Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pcips2.c
Go to the documentation of this file.
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/slab.h>
19 #include <linux/init.h>
20 #include <linux/serio.h>
21 #include <linux/delay.h>
22 #include <asm/io.h>
23 
24 #define PS2_CTRL (0)
25 #define PS2_STATUS (1)
26 #define PS2_DATA (2)
27 
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)
33 
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)
40 
41 struct pcips2_data {
42  struct serio *io;
43  unsigned int base;
44  struct pci_dev *dev;
45 };
46 
47 static int pcips2_write(struct serio *io, unsigned char val)
48 {
49  struct pcips2_data *ps2if = io->port_data;
50  unsigned int stat;
51 
52  do {
53  stat = inb(ps2if->base + PS2_STATUS);
54  cpu_relax();
55  } while (!(stat & PS2_STAT_TXEMPTY));
56 
57  outb(val, ps2if->base + PS2_DATA);
58 
59  return 0;
60 }
61 
62 static irqreturn_t pcips2_interrupt(int irq, void *devid)
63 {
64  struct pcips2_data *ps2if = devid;
65  unsigned char status, scancode;
66  int handled = 0;
67 
68  do {
69  unsigned int flag;
70 
71  status = inb(ps2if->base + PS2_STATUS);
72  if (!(status & PS2_STAT_RXFULL))
73  break;
74  handled = 1;
75  scancode = inb(ps2if->base + PS2_DATA);
76  if (status == 0xff && scancode == 0xff)
77  break;
78 
79  flag = (status & PS2_STAT_PARITY) ? 0 : SERIO_PARITY;
80 
81  if (hweight8(scancode) & 1)
82  flag ^= SERIO_PARITY;
83 
84  serio_interrupt(ps2if->io, scancode, flag);
85  } while (1);
86  return IRQ_RETVAL(handled);
87 }
88 
89 static void pcips2_flush_input(struct pcips2_data *ps2if)
90 {
91  unsigned char status, scancode;
92 
93  do {
94  status = inb(ps2if->base + PS2_STATUS);
95  if (!(status & PS2_STAT_RXFULL))
96  break;
97  scancode = inb(ps2if->base + PS2_DATA);
98  if (status == 0xff && scancode == 0xff)
99  break;
100  } while (1);
101 }
102 
103 static int pcips2_open(struct serio *io)
104 {
105  struct pcips2_data *ps2if = io->port_data;
106  int ret, val = 0;
107 
108  outb(PS2_CTRL_ENABLE, ps2if->base);
109  pcips2_flush_input(ps2if);
110 
111  ret = request_irq(ps2if->dev->irq, pcips2_interrupt, IRQF_SHARED,
112  "pcips2", ps2if);
113  if (ret == 0)
115 
116  outb(val, ps2if->base);
117 
118  return ret;
119 }
120 
121 static void pcips2_close(struct serio *io)
122 {
123  struct pcips2_data *ps2if = io->port_data;
124 
125  outb(0, ps2if->base);
126 
127  free_irq(ps2if->dev->irq, ps2if);
128 }
129 
130 static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_id *id)
131 {
132  struct pcips2_data *ps2if;
133  struct serio *serio;
134  int ret;
135 
136  ret = pci_enable_device(dev);
137  if (ret)
138  goto out;
139 
140  ret = pci_request_regions(dev, "pcips2");
141  if (ret)
142  goto disable;
143 
144  ps2if = kzalloc(sizeof(struct pcips2_data), GFP_KERNEL);
145  serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
146  if (!ps2if || !serio) {
147  ret = -ENOMEM;
148  goto release;
149  }
150 
151 
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;
160  ps2if->io = serio;
161  ps2if->dev = dev;
162  ps2if->base = pci_resource_start(dev, 0);
163 
164  pci_set_drvdata(dev, ps2if);
165 
166  serio_register_port(ps2if->io);
167  return 0;
168 
169  release:
170  kfree(ps2if);
171  kfree(serio);
172  pci_release_regions(dev);
173  disable:
174  pci_disable_device(dev);
175  out:
176  return ret;
177 }
178 
179 static void __devexit pcips2_remove(struct pci_dev *dev)
180 {
181  struct pcips2_data *ps2if = pci_get_drvdata(dev);
182 
183  serio_unregister_port(ps2if->io);
184  pci_set_drvdata(dev, NULL);
185  kfree(ps2if);
186  pci_release_regions(dev);
187  pci_disable_device(dev);
188 }
189 
190 static const struct pci_device_id pcips2_ids[] = {
191  {
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,
198  },
199  {
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,
206  },
207  { 0, }
208 };
209 MODULE_DEVICE_TABLE(pci, pcips2_ids);
210 
211 static struct pci_driver pcips2_driver = {
212  .name = "pcips2",
213  .id_table = pcips2_ids,
214  .probe = pcips2_probe,
215  .remove = __devexit_p(pcips2_remove),
216 };
217 
218 module_pci_driver(pcips2_driver);
219 
220 MODULE_LICENSE("GPL");
221 MODULE_AUTHOR("Russell King <[email protected]>");
222 MODULE_DESCRIPTION("PCI PS/2 keyboard/mouse driver");