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/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
)
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
);
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 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
= kzalloc(sizeof(struct pcips2_data
), GFP_KERNEL
);
144 serio
= kzalloc(sizeof(struct serio
), GFP_KERNEL
);
145 if (!ps2if
|| !serio
) {
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
;
161 ps2if
->base
= pci_resource_start(dev
, 0);
163 pci_set_drvdata(dev
, ps2if
);
165 serio_register_port(ps2if
->io
);
171 pci_release_regions(dev
);
173 pci_disable_device(dev
);
178 static void pcips2_remove(struct pci_dev
*dev
)
180 struct pcips2_data
*ps2if
= pci_get_drvdata(dev
);
182 serio_unregister_port(ps2if
->io
);
184 pci_release_regions(dev
);
185 pci_disable_device(dev
);
188 static const struct pci_device_id pcips2_ids
[] = {
190 .vendor
= 0x14f2, /* MOBILITY */
191 .device
= 0x0123, /* Keyboard */
192 .subvendor
= PCI_ANY_ID
,
193 .subdevice
= PCI_ANY_ID
,
194 .class = PCI_CLASS_INPUT_KEYBOARD
<< 8,
195 .class_mask
= 0xffff00,
198 .vendor
= 0x14f2, /* MOBILITY */
199 .device
= 0x0124, /* Mouse */
200 .subvendor
= PCI_ANY_ID
,
201 .subdevice
= PCI_ANY_ID
,
202 .class = PCI_CLASS_INPUT_MOUSE
<< 8,
203 .class_mask
= 0xffff00,
207 MODULE_DEVICE_TABLE(pci
, pcips2_ids
);
209 static struct pci_driver pcips2_driver
= {
211 .id_table
= pcips2_ids
,
212 .probe
= pcips2_probe
,
213 .remove
= pcips2_remove
,
216 module_pci_driver(pcips2_driver
);
218 MODULE_LICENSE("GPL");
219 MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
220 MODULE_DESCRIPTION("PCI PS/2 keyboard/mouse driver");