Version:  2.0.40 2.2.26 2.4.37 2.6.39 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15

Linux/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/slab.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 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 pcips2_remove(struct pci_dev *dev)
179 {
180         struct pcips2_data *ps2if = pci_get_drvdata(dev);
181 
182         serio_unregister_port(ps2if->io);
183         kfree(ps2if);
184         pci_release_regions(dev);
185         pci_disable_device(dev);
186 }
187 
188 static const struct pci_device_id pcips2_ids[] = {
189         {
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,
196         },
197         {
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,
204         },
205         { 0, }
206 };
207 MODULE_DEVICE_TABLE(pci, pcips2_ids);
208 
209 static struct pci_driver pcips2_driver = {
210         .name                   = "pcips2",
211         .id_table               = pcips2_ids,
212         .probe                  = pcips2_probe,
213         .remove                 = pcips2_remove,
214 };
215 
216 module_pci_driver(pcips2_driver);
217 
218 MODULE_LICENSE("GPL");
219 MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
220 MODULE_DESCRIPTION("PCI PS/2 keyboard/mouse driver");
221 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us