Merge branch 'proc-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/adobriyan...
[linux-2.6] / drivers / input / serio / pcips2.c
1 /*
2  * linux/drivers/input/serio/pcips2.c
3  *
4  *  Copyright (C) 2003 Russell King, All Rights Reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License.
9  *
10  *  I'm not sure if this is a generic PS/2 PCI interface or specific to
11  *  the Mobility Electronics docking station.
12  */
13 #include <linux/module.h>
14 #include <linux/interrupt.h>
15 #include <linux/ioport.h>
16 #include <linux/input.h>
17 #include <linux/pci.h>
18 #include <linux/init.h>
19 #include <linux/serio.h>
20 #include <linux/delay.h>
21 #include <asm/io.h>
22
23 #define PS2_CTRL                (0)
24 #define PS2_STATUS              (1)
25 #define PS2_DATA                (2)
26
27 #define PS2_CTRL_CLK            (1<<0)
28 #define PS2_CTRL_DAT            (1<<1)
29 #define PS2_CTRL_TXIRQ          (1<<2)
30 #define PS2_CTRL_ENABLE         (1<<3)
31 #define PS2_CTRL_RXIRQ          (1<<4)
32
33 #define PS2_STAT_CLK            (1<<0)
34 #define PS2_STAT_DAT            (1<<1)
35 #define PS2_STAT_PARITY         (1<<2)
36 #define PS2_STAT_RXFULL         (1<<5)
37 #define PS2_STAT_TXBUSY         (1<<6)
38 #define PS2_STAT_TXEMPTY        (1<<7)
39
40 struct pcips2_data {
41         struct serio    *io;
42         unsigned int    base;
43         struct pci_dev  *dev;
44 };
45
46 static int pcips2_write(struct serio *io, unsigned char val)
47 {
48         struct pcips2_data *ps2if = io->port_data;
49         unsigned int stat;
50
51         do {
52                 stat = inb(ps2if->base + PS2_STATUS);
53                 cpu_relax();
54         } while (!(stat & PS2_STAT_TXEMPTY));
55
56         outb(val, ps2if->base + PS2_DATA);
57
58         return 0;
59 }
60
61 static irqreturn_t pcips2_interrupt(int irq, void *devid)
62 {
63         struct pcips2_data *ps2if = devid;
64         unsigned char status, scancode;
65         int handled = 0;
66
67         do {
68                 unsigned int flag;
69
70                 status = inb(ps2if->base + PS2_STATUS);
71                 if (!(status & PS2_STAT_RXFULL))
72                         break;
73                 handled = 1;
74                 scancode = inb(ps2if->base + PS2_DATA);
75                 if (status == 0xff && scancode == 0xff)
76                         break;
77
78                 flag = (status & PS2_STAT_PARITY) ? 0 : SERIO_PARITY;
79
80                 if (hweight8(scancode) & 1)
81                         flag ^= SERIO_PARITY;
82
83                 serio_interrupt(ps2if->io, scancode, flag);
84         } while (1);
85         return IRQ_RETVAL(handled);
86 }
87
88 static void pcips2_flush_input(struct pcips2_data *ps2if)
89 {
90         unsigned char status, scancode;
91
92         do {
93                 status = inb(ps2if->base + PS2_STATUS);
94                 if (!(status & PS2_STAT_RXFULL))
95                         break;
96                 scancode = inb(ps2if->base + PS2_DATA);
97                 if (status == 0xff && scancode == 0xff)
98                         break;
99         } while (1);
100 }
101
102 static int pcips2_open(struct serio *io)
103 {
104         struct pcips2_data *ps2if = io->port_data;
105         int ret, val = 0;
106
107         outb(PS2_CTRL_ENABLE, ps2if->base);
108         pcips2_flush_input(ps2if);
109
110         ret = request_irq(ps2if->dev->irq, pcips2_interrupt, IRQF_SHARED,
111                           "pcips2", ps2if);
112         if (ret == 0)
113                 val = PS2_CTRL_ENABLE | PS2_CTRL_RXIRQ;
114
115         outb(val, ps2if->base);
116
117         return ret;
118 }
119
120 static void pcips2_close(struct serio *io)
121 {
122         struct pcips2_data *ps2if = io->port_data;
123
124         outb(0, ps2if->base);
125
126         free_irq(ps2if->dev->irq, ps2if);
127 }
128
129 static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_id *id)
130 {
131         struct pcips2_data *ps2if;
132         struct serio *serio;
133         int ret;
134
135         ret = pci_enable_device(dev);
136         if (ret)
137                 goto out;
138
139         ret = pci_request_regions(dev, "pcips2");
140         if (ret)
141                 goto disable;
142
143         ps2if = kzalloc(sizeof(struct pcips2_data), GFP_KERNEL);
144         serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
145         if (!ps2if || !serio) {
146                 ret = -ENOMEM;
147                 goto release;
148         }
149
150
151         serio->id.type          = SERIO_8042;
152         serio->write            = pcips2_write;
153         serio->open             = pcips2_open;
154         serio->close            = pcips2_close;
155         strlcpy(serio->name, pci_name(dev), sizeof(serio->name));
156         strlcpy(serio->phys, dev_name(&dev->dev), sizeof(serio->phys));
157         serio->port_data        = ps2if;
158         serio->dev.parent       = &dev->dev;
159         ps2if->io               = serio;
160         ps2if->dev              = dev;
161         ps2if->base             = pci_resource_start(dev, 0);
162
163         pci_set_drvdata(dev, ps2if);
164
165         serio_register_port(ps2if->io);
166         return 0;
167
168  release:
169         kfree(ps2if);
170         kfree(serio);
171         pci_release_regions(dev);
172  disable:
173         pci_disable_device(dev);
174  out:
175         return ret;
176 }
177
178 static void __devexit pcips2_remove(struct pci_dev *dev)
179 {
180         struct pcips2_data *ps2if = pci_get_drvdata(dev);
181
182         serio_unregister_port(ps2if->io);
183         pci_set_drvdata(dev, NULL);
184         kfree(ps2if);
185         pci_release_regions(dev);
186         pci_disable_device(dev);
187 }
188
189 static struct pci_device_id pcips2_ids[] = {
190         {
191                 .vendor         = 0x14f2,       /* MOBILITY */
192                 .device         = 0x0123,       /* Keyboard */
193                 .subvendor      = PCI_ANY_ID,
194                 .subdevice      = PCI_ANY_ID,
195                 .class          = PCI_CLASS_INPUT_KEYBOARD << 8,
196                 .class_mask     = 0xffff00,
197         },
198         {
199                 .vendor         = 0x14f2,       /* MOBILITY */
200                 .device         = 0x0124,       /* Mouse */
201                 .subvendor      = PCI_ANY_ID,
202                 .subdevice      = PCI_ANY_ID,
203                 .class          = PCI_CLASS_INPUT_MOUSE << 8,
204                 .class_mask     = 0xffff00,
205         },
206         { 0, }
207 };
208
209 static struct pci_driver pcips2_driver = {
210         .name                   = "pcips2",
211         .id_table               = pcips2_ids,
212         .probe                  = pcips2_probe,
213         .remove                 = __devexit_p(pcips2_remove),
214 };
215
216 static int __init pcips2_init(void)
217 {
218         return pci_register_driver(&pcips2_driver);
219 }
220
221 static void __exit pcips2_exit(void)
222 {
223         pci_unregister_driver(&pcips2_driver);
224 }
225
226 module_init(pcips2_init);
227 module_exit(pcips2_exit);
228
229 MODULE_LICENSE("GPL");
230 MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
231 MODULE_DESCRIPTION("PCI PS/2 keyboard/mouse driver");
232 MODULE_DEVICE_TABLE(pci, pcips2_ids);