root/drivers/input/serio/ct82c710.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ct82c710_interrupt
  2. ct82c170_wait
  3. ct82c710_close
  4. ct82c710_open
  5. ct82c710_write
  6. ct82c710_detect
  7. ct82c710_probe
  8. ct82c710_remove
  9. ct82c710_init
  10. ct82c710_exit

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  Copyright (c) 1999-2001 Vojtech Pavlik
   4  */
   5 
   6 /*
   7  *  82C710 C&T mouse port chip driver for Linux
   8  */
   9 
  10 /*
  11  */
  12 
  13 #include <linux/delay.h>
  14 #include <linux/module.h>
  15 #include <linux/ioport.h>
  16 #include <linux/init.h>
  17 #include <linux/interrupt.h>
  18 #include <linux/serio.h>
  19 #include <linux/errno.h>
  20 #include <linux/err.h>
  21 #include <linux/platform_device.h>
  22 #include <linux/slab.h>
  23 
  24 #include <asm/io.h>
  25 
  26 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
  27 MODULE_DESCRIPTION("82C710 C&T mouse port chip driver");
  28 MODULE_LICENSE("GPL");
  29 
  30 /*
  31  * ct82c710 interface
  32  */
  33 
  34 #define CT82C710_DEV_IDLE     0x01              /* Device Idle */
  35 #define CT82C710_RX_FULL      0x02              /* Device Char received */
  36 #define CT82C710_TX_IDLE      0x04              /* Device XMIT Idle */
  37 #define CT82C710_RESET        0x08              /* Device Reset */
  38 #define CT82C710_INTS_ON      0x10              /* Device Interrupt On */
  39 #define CT82C710_ERROR_FLAG   0x20              /* Device Error */
  40 #define CT82C710_CLEAR        0x40              /* Device Clear */
  41 #define CT82C710_ENABLE       0x80              /* Device Enable */
  42 
  43 #define CT82C710_IRQ          12
  44 
  45 #define CT82C710_DATA         ct82c710_iores.start
  46 #define CT82C710_STATUS       (ct82c710_iores.start + 1)
  47 
  48 static struct serio *ct82c710_port;
  49 static struct platform_device *ct82c710_device;
  50 static struct resource ct82c710_iores;
  51 
  52 /*
  53  * Interrupt handler for the 82C710 mouse port. A character
  54  * is waiting in the 82C710.
  55  */
  56 
  57 static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id)
  58 {
  59         return serio_interrupt(ct82c710_port, inb(CT82C710_DATA), 0);
  60 }
  61 
  62 /*
  63  * Wait for device to send output char and flush any input char.
  64  */
  65 
  66 static int ct82c170_wait(void)
  67 {
  68         int timeout = 60000;
  69 
  70         while ((inb(CT82C710_STATUS) & (CT82C710_RX_FULL | CT82C710_TX_IDLE | CT82C710_DEV_IDLE))
  71                        != (CT82C710_DEV_IDLE | CT82C710_TX_IDLE) && timeout) {
  72 
  73                 if (inb_p(CT82C710_STATUS) & CT82C710_RX_FULL) inb_p(CT82C710_DATA);
  74 
  75                 udelay(1);
  76                 timeout--;
  77         }
  78 
  79         return !timeout;
  80 }
  81 
  82 static void ct82c710_close(struct serio *serio)
  83 {
  84         if (ct82c170_wait())
  85                 printk(KERN_WARNING "ct82c710.c: Device busy in close()\n");
  86 
  87         outb_p(inb_p(CT82C710_STATUS) & ~(CT82C710_ENABLE | CT82C710_INTS_ON), CT82C710_STATUS);
  88 
  89         if (ct82c170_wait())
  90                 printk(KERN_WARNING "ct82c710.c: Device busy in close()\n");
  91 
  92         free_irq(CT82C710_IRQ, NULL);
  93 }
  94 
  95 static int ct82c710_open(struct serio *serio)
  96 {
  97         unsigned char status;
  98         int err;
  99 
 100         err = request_irq(CT82C710_IRQ, ct82c710_interrupt, 0, "ct82c710", NULL);
 101         if (err)
 102                 return err;
 103 
 104         status = inb_p(CT82C710_STATUS);
 105 
 106         status |= (CT82C710_ENABLE | CT82C710_RESET);
 107         outb_p(status, CT82C710_STATUS);
 108 
 109         status &= ~(CT82C710_RESET);
 110         outb_p(status, CT82C710_STATUS);
 111 
 112         status |= CT82C710_INTS_ON;
 113         outb_p(status, CT82C710_STATUS);        /* Enable interrupts */
 114 
 115         while (ct82c170_wait()) {
 116                 printk(KERN_ERR "ct82c710: Device busy in open()\n");
 117                 status &= ~(CT82C710_ENABLE | CT82C710_INTS_ON);
 118                 outb_p(status, CT82C710_STATUS);
 119                 free_irq(CT82C710_IRQ, NULL);
 120                 return -EBUSY;
 121         }
 122 
 123         return 0;
 124 }
 125 
 126 /*
 127  * Write to the 82C710 mouse device.
 128  */
 129 
 130 static int ct82c710_write(struct serio *port, unsigned char c)
 131 {
 132         if (ct82c170_wait()) return -1;
 133         outb_p(c, CT82C710_DATA);
 134         return 0;
 135 }
 136 
 137 /*
 138  * See if we can find a 82C710 device. Read mouse address.
 139  */
 140 
 141 static int __init ct82c710_detect(void)
 142 {
 143         outb_p(0x55, 0x2fa);                            /* Any value except 9, ff or 36 */
 144         outb_p(0xaa, 0x3fa);                            /* Inverse of 55 */
 145         outb_p(0x36, 0x3fa);                            /* Address the chip */
 146         outb_p(0xe4, 0x3fa);                            /* 390/4; 390 = config address */
 147         outb_p(0x1b, 0x2fa);                            /* Inverse of e4 */
 148         outb_p(0x0f, 0x390);                            /* Write index */
 149         if (inb_p(0x391) != 0xe4)                       /* Config address found? */
 150                 return -ENODEV;                         /* No: no 82C710 here */
 151 
 152         outb_p(0x0d, 0x390);                            /* Write index */
 153         ct82c710_iores.start = inb_p(0x391) << 2;       /* Get mouse I/O address */
 154         ct82c710_iores.end = ct82c710_iores.start + 1;
 155         ct82c710_iores.flags = IORESOURCE_IO;
 156         outb_p(0x0f, 0x390);
 157         outb_p(0x0f, 0x391);                            /* Close config mode */
 158 
 159         return 0;
 160 }
 161 
 162 static int ct82c710_probe(struct platform_device *dev)
 163 {
 164         ct82c710_port = kzalloc(sizeof(struct serio), GFP_KERNEL);
 165         if (!ct82c710_port)
 166                 return -ENOMEM;
 167 
 168         ct82c710_port->id.type = SERIO_8042;
 169         ct82c710_port->dev.parent = &dev->dev;
 170         ct82c710_port->open = ct82c710_open;
 171         ct82c710_port->close = ct82c710_close;
 172         ct82c710_port->write = ct82c710_write;
 173         strlcpy(ct82c710_port->name, "C&T 82c710 mouse port",
 174                 sizeof(ct82c710_port->name));
 175         snprintf(ct82c710_port->phys, sizeof(ct82c710_port->phys),
 176                  "isa%16llx/serio0", (unsigned long long)CT82C710_DATA);
 177 
 178         serio_register_port(ct82c710_port);
 179 
 180         printk(KERN_INFO "serio: C&T 82c710 mouse port at %#llx irq %d\n",
 181                 (unsigned long long)CT82C710_DATA, CT82C710_IRQ);
 182 
 183         return 0;
 184 }
 185 
 186 static int ct82c710_remove(struct platform_device *dev)
 187 {
 188         serio_unregister_port(ct82c710_port);
 189 
 190         return 0;
 191 }
 192 
 193 static struct platform_driver ct82c710_driver = {
 194         .driver         = {
 195                 .name   = "ct82c710",
 196         },
 197         .probe          = ct82c710_probe,
 198         .remove         = ct82c710_remove,
 199 };
 200 
 201 
 202 static int __init ct82c710_init(void)
 203 {
 204         int error;
 205 
 206         error = ct82c710_detect();
 207         if (error)
 208                 return error;
 209 
 210         error = platform_driver_register(&ct82c710_driver);
 211         if (error)
 212                 return error;
 213 
 214         ct82c710_device = platform_device_alloc("ct82c710", -1);
 215         if (!ct82c710_device) {
 216                 error = -ENOMEM;
 217                 goto err_unregister_driver;
 218         }
 219 
 220         error = platform_device_add_resources(ct82c710_device, &ct82c710_iores, 1);
 221         if (error)
 222                 goto err_free_device;
 223 
 224         error = platform_device_add(ct82c710_device);
 225         if (error)
 226                 goto err_free_device;
 227 
 228         return 0;
 229 
 230  err_free_device:
 231         platform_device_put(ct82c710_device);
 232  err_unregister_driver:
 233         platform_driver_unregister(&ct82c710_driver);
 234         return error;
 235 }
 236 
 237 static void __exit ct82c710_exit(void)
 238 {
 239         platform_device_unregister(ct82c710_device);
 240         platform_driver_unregister(&ct82c710_driver);
 241 }
 242 
 243 module_init(ct82c710_init);
 244 module_exit(ct82c710_exit);

/* [<][>][^][v][top][bottom][index][help] */