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/init.h>
19 #include <linux/serio.h>
20 #include <linux/delay.h>
24 #define PS2_STATUS (1)
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)
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)
46 static int pcips2_write(struct serio
*io
, unsigned char val
)
48 struct pcips2_data
*ps2if
= io
->port_data
;
52 stat
= inb(ps2if
->base
+ PS2_STATUS
);
54 } while (!(stat
& PS2_STAT_TXEMPTY
));
56 outb(val
, ps2if
->base
+ PS2_DATA
);
61 static irqreturn_t
pcips2_interrupt(int irq
, void *devid
, struct pt_regs
*regs
)
63 struct pcips2_data
*ps2if
= devid
;
64 unsigned char status
, scancode
;
70 status
= inb(ps2if
->base
+ PS2_STATUS
);
71 if (!(status
& PS2_STAT_RXFULL
))
74 scancode
= inb(ps2if
->base
+ PS2_DATA
);
75 if (status
== 0xff && scancode
== 0xff)
78 flag
= (status
& PS2_STAT_PARITY
) ? 0 : SERIO_PARITY
;
80 if (hweight8(scancode
) & 1)
83 serio_interrupt(ps2if
->io
, scancode
, flag
, regs
);
85 return IRQ_RETVAL(handled
);
88 static void pcips2_flush_input(struct pcips2_data
*ps2if
)
90 unsigned char status
, scancode
;
93 status
= inb(ps2if
->base
+ PS2_STATUS
);
94 if (!(status
& PS2_STAT_RXFULL
))
96 scancode
= inb(ps2if
->base
+ PS2_DATA
);
97 if (status
== 0xff && scancode
== 0xff)
102 static int pcips2_open(struct serio
*io
)
104 struct pcips2_data
*ps2if
= io
->port_data
;
107 outb(PS2_CTRL_ENABLE
, ps2if
->base
);
108 pcips2_flush_input(ps2if
);
110 ret
= request_irq(ps2if
->dev
->irq
, pcips2_interrupt
, IRQF_SHARED
,
113 val
= PS2_CTRL_ENABLE
| PS2_CTRL_RXIRQ
;
115 outb(val
, ps2if
->base
);
120 static void pcips2_close(struct serio
*io
)
122 struct pcips2_data
*ps2if
= io
->port_data
;
124 outb(0, ps2if
->base
);
126 free_irq(ps2if
->dev
->irq
, ps2if
);
129 static int __devinit
pcips2_probe(struct pci_dev
*dev
, const struct pci_device_id
*id
)
131 struct pcips2_data
*ps2if
;
135 ret
= pci_enable_device(dev
);
139 ret
= pci_request_regions(dev
, "pcips2");
143 ps2if
= kmalloc(sizeof(struct pcips2_data
), GFP_KERNEL
);
144 serio
= kmalloc(sizeof(struct serio
), GFP_KERNEL
);
145 if (!ps2if
|| !serio
) {
150 memset(ps2if
, 0, sizeof(struct pcips2_data
));
151 memset(serio
, 0, sizeof(struct serio
));
153 serio
->id
.type
= SERIO_8042
;
154 serio
->write
= pcips2_write
;
155 serio
->open
= pcips2_open
;
156 serio
->close
= pcips2_close
;
157 strlcpy(serio
->name
, pci_name(dev
), sizeof(serio
->name
));
158 strlcpy(serio
->phys
, dev
->dev
.bus_id
, sizeof(serio
->phys
));
159 serio
->port_data
= ps2if
;
160 serio
->dev
.parent
= &dev
->dev
;
163 ps2if
->base
= pci_resource_start(dev
, 0);
165 pci_set_drvdata(dev
, ps2if
);
167 serio_register_port(ps2if
->io
);
173 pci_release_regions(dev
);
175 pci_disable_device(dev
);
180 static void __devexit
pcips2_remove(struct pci_dev
*dev
)
182 struct pcips2_data
*ps2if
= pci_get_drvdata(dev
);
184 serio_unregister_port(ps2if
->io
);
185 pci_set_drvdata(dev
, NULL
);
187 pci_release_regions(dev
);
188 pci_disable_device(dev
);
191 static struct pci_device_id pcips2_ids
[] = {
193 .vendor
= 0x14f2, /* MOBILITY */
194 .device
= 0x0123, /* Keyboard */
195 .subvendor
= PCI_ANY_ID
,
196 .subdevice
= PCI_ANY_ID
,
197 .class = PCI_CLASS_INPUT_KEYBOARD
<< 8,
198 .class_mask
= 0xffff00,
201 .vendor
= 0x14f2, /* MOBILITY */
202 .device
= 0x0124, /* Mouse */
203 .subvendor
= PCI_ANY_ID
,
204 .subdevice
= PCI_ANY_ID
,
205 .class = PCI_CLASS_INPUT_MOUSE
<< 8,
206 .class_mask
= 0xffff00,
211 static struct pci_driver pcips2_driver
= {
213 .id_table
= pcips2_ids
,
214 .probe
= pcips2_probe
,
215 .remove
= __devexit_p(pcips2_remove
),
218 static int __init
pcips2_init(void)
220 return pci_register_driver(&pcips2_driver
);
223 static void __exit
pcips2_exit(void)
225 pci_unregister_driver(&pcips2_driver
);
228 module_init(pcips2_init
);
229 module_exit(pcips2_exit
);
231 MODULE_LICENSE("GPL");
232 MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
233 MODULE_DESCRIPTION("PCI PS/2 keyboard/mouse driver");
234 MODULE_DEVICE_TABLE(pci
, pcips2_ids
);