2 * linux/drivers/input/serio/pcips2.c
4 * Copyright (C) 2003 Russell King, All Rights Reserved.
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.
10 * I'm not sure if this is a generic PS/2 PCI interface or specific to
11 * the Mobility Electronics docking station.
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/slab.h>
19 #include <linux/init.h>
20 #include <linux/serio.h>
21 #include <linux/delay.h>
25 #define PS2_STATUS (1)
28 #define PS2_CTRL_CLK (1<<0)
29 #define PS2_CTRL_DAT (1<<1)
30 #define PS2_CTRL_TXIRQ (1<<2)
31 #define PS2_CTRL_ENABLE (1<<3)
32 #define PS2_CTRL_RXIRQ (1<<4)
34 #define PS2_STAT_CLK (1<<0)
35 #define PS2_STAT_DAT (1<<1)
36 #define PS2_STAT_PARITY (1<<2)
37 #define PS2_STAT_RXFULL (1<<5)
38 #define PS2_STAT_TXBUSY (1<<6)
39 #define PS2_STAT_TXEMPTY (1<<7)
47 static int pcips2_write(struct serio
*io
, unsigned char val
)
49 struct pcips2_data
*ps2if
= io
->port_data
;
53 stat
= inb(ps2if
->base
+ PS2_STATUS
);
55 } while (!(stat
& PS2_STAT_TXEMPTY
));
57 outb(val
, ps2if
->base
+ PS2_DATA
);
62 static irqreturn_t
pcips2_interrupt(int irq
, void *devid
)
64 struct pcips2_data
*ps2if
= devid
;
65 unsigned char status
, scancode
;
71 status
= inb(ps2if
->base
+ PS2_STATUS
);
72 if (!(status
& PS2_STAT_RXFULL
))
75 scancode
= inb(ps2if
->base
+ PS2_DATA
);
76 if (status
== 0xff && scancode
== 0xff)
79 flag
= (status
& PS2_STAT_PARITY
) ? 0 : SERIO_PARITY
;
81 if (hweight8(scancode
) & 1)
84 serio_interrupt(ps2if
->io
, scancode
, flag
);
86 return IRQ_RETVAL(handled
);
89 static void pcips2_flush_input(struct pcips2_data
*ps2if
)
91 unsigned char status
, scancode
;
94 status
= inb(ps2if
->base
+ PS2_STATUS
);
95 if (!(status
& PS2_STAT_RXFULL
))
97 scancode
= inb(ps2if
->base
+ PS2_DATA
);
98 if (status
== 0xff && scancode
== 0xff)
103 static int pcips2_open(struct serio
*io
)
105 struct pcips2_data
*ps2if
= io
->port_data
;
108 outb(PS2_CTRL_ENABLE
, ps2if
->base
);
109 pcips2_flush_input(ps2if
);
111 ret
= request_irq(ps2if
->dev
->irq
, pcips2_interrupt
, IRQF_SHARED
,
114 val
= PS2_CTRL_ENABLE
| PS2_CTRL_RXIRQ
;
116 outb(val
, ps2if
->base
);
121 static void pcips2_close(struct serio
*io
)
123 struct pcips2_data
*ps2if
= io
->port_data
;
125 outb(0, ps2if
->base
);
127 free_irq(ps2if
->dev
->irq
, ps2if
);
130 static int __devinit
pcips2_probe(struct pci_dev
*dev
, const struct pci_device_id
*id
)
132 struct pcips2_data
*ps2if
;
136 ret
= pci_enable_device(dev
);
140 ret
= pci_request_regions(dev
, "pcips2");
144 ps2if
= kzalloc(sizeof(struct pcips2_data
), GFP_KERNEL
);
145 serio
= kzalloc(sizeof(struct serio
), GFP_KERNEL
);
146 if (!ps2if
|| !serio
) {
152 serio
->id
.type
= SERIO_8042
;
153 serio
->write
= pcips2_write
;
154 serio
->open
= pcips2_open
;
155 serio
->close
= pcips2_close
;
156 strlcpy(serio
->name
, pci_name(dev
), sizeof(serio
->name
));
157 strlcpy(serio
->phys
, dev_name(&dev
->dev
), sizeof(serio
->phys
));
158 serio
->port_data
= ps2if
;
159 serio
->dev
.parent
= &dev
->dev
;
162 ps2if
->base
= pci_resource_start(dev
, 0);
164 pci_set_drvdata(dev
, ps2if
);
166 serio_register_port(ps2if
->io
);
172 pci_release_regions(dev
);
174 pci_disable_device(dev
);
179 static void __devexit
pcips2_remove(struct pci_dev
*dev
)
181 struct pcips2_data
*ps2if
= pci_get_drvdata(dev
);
183 serio_unregister_port(ps2if
->io
);
184 pci_set_drvdata(dev
, NULL
);
186 pci_release_regions(dev
);
187 pci_disable_device(dev
);
190 static const struct pci_device_id pcips2_ids
[] = {
192 .vendor
= 0x14f2, /* MOBILITY */
193 .device
= 0x0123, /* Keyboard */
194 .subvendor
= PCI_ANY_ID
,
195 .subdevice
= PCI_ANY_ID
,
196 .class = PCI_CLASS_INPUT_KEYBOARD
<< 8,
197 .class_mask
= 0xffff00,
200 .vendor
= 0x14f2, /* MOBILITY */
201 .device
= 0x0124, /* Mouse */
202 .subvendor
= PCI_ANY_ID
,
203 .subdevice
= PCI_ANY_ID
,
204 .class = PCI_CLASS_INPUT_MOUSE
<< 8,
205 .class_mask
= 0xffff00,
210 static struct pci_driver pcips2_driver
= {
212 .id_table
= pcips2_ids
,
213 .probe
= pcips2_probe
,
214 .remove
= __devexit_p(pcips2_remove
),
217 static int __init
pcips2_init(void)
219 return pci_register_driver(&pcips2_driver
);
222 static void __exit
pcips2_exit(void)
224 pci_unregister_driver(&pcips2_driver
);
227 module_init(pcips2_init
);
228 module_exit(pcips2_exit
);
230 MODULE_LICENSE("GPL");
231 MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
232 MODULE_DESCRIPTION("PCI PS/2 keyboard/mouse driver");
233 MODULE_DEVICE_TABLE(pci
, pcips2_ids
);