root/drivers/input/touchscreen/htcpen.c

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

DEFINITIONS

This source file includes following definitions.
  1. htcpen_interrupt
  2. htcpen_open
  3. htcpen_close
  4. htcpen_isa_probe
  5. htcpen_isa_remove
  6. htcpen_isa_suspend
  7. htcpen_isa_resume
  8. htcpen_isa_init
  9. htcpen_isa_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * HTC Shift touchscreen driver
   4  *
   5  * Copyright (C) 2008 Pau Oliva Fora <pof@eslack.org>
   6  */
   7 
   8 #include <linux/errno.h>
   9 #include <linux/kernel.h>
  10 #include <linux/module.h>
  11 #include <linux/input.h>
  12 #include <linux/interrupt.h>
  13 #include <linux/io.h>
  14 #include <linux/init.h>
  15 #include <linux/irq.h>
  16 #include <linux/isa.h>
  17 #include <linux/ioport.h>
  18 #include <linux/dmi.h>
  19 
  20 MODULE_AUTHOR("Pau Oliva Fora <pau@eslack.org>");
  21 MODULE_DESCRIPTION("HTC Shift touchscreen driver");
  22 MODULE_LICENSE("GPL");
  23 
  24 #define HTCPEN_PORT_IRQ_CLEAR   0x068
  25 #define HTCPEN_PORT_INIT        0x06c
  26 #define HTCPEN_PORT_INDEX       0x0250
  27 #define HTCPEN_PORT_DATA        0x0251
  28 #define HTCPEN_IRQ              3
  29 
  30 #define DEVICE_ENABLE           0xa2
  31 #define DEVICE_DISABLE          0xa3
  32 
  33 #define X_INDEX                 3
  34 #define Y_INDEX                 5
  35 #define TOUCH_INDEX             0xb
  36 #define LSB_XY_INDEX            0xc
  37 #define X_AXIS_MAX              2040
  38 #define Y_AXIS_MAX              2040
  39 
  40 static bool invert_x;
  41 module_param(invert_x, bool, 0644);
  42 MODULE_PARM_DESC(invert_x, "If set, X axis is inverted");
  43 static bool invert_y;
  44 module_param(invert_y, bool, 0644);
  45 MODULE_PARM_DESC(invert_y, "If set, Y axis is inverted");
  46 
  47 static irqreturn_t htcpen_interrupt(int irq, void *handle)
  48 {
  49         struct input_dev *htcpen_dev = handle;
  50         unsigned short x, y, xy;
  51 
  52         /* 0 = press; 1 = release */
  53         outb_p(TOUCH_INDEX, HTCPEN_PORT_INDEX);
  54 
  55         if (inb_p(HTCPEN_PORT_DATA)) {
  56                 input_report_key(htcpen_dev, BTN_TOUCH, 0);
  57         } else {
  58                 outb_p(X_INDEX, HTCPEN_PORT_INDEX);
  59                 x = inb_p(HTCPEN_PORT_DATA);
  60 
  61                 outb_p(Y_INDEX, HTCPEN_PORT_INDEX);
  62                 y = inb_p(HTCPEN_PORT_DATA);
  63 
  64                 outb_p(LSB_XY_INDEX, HTCPEN_PORT_INDEX);
  65                 xy = inb_p(HTCPEN_PORT_DATA);
  66 
  67                 /* get high resolution value of X and Y using LSB */
  68                 x = X_AXIS_MAX - ((x * 8) + ((xy >> 4) & 0xf));
  69                 y = (y * 8) + (xy & 0xf);
  70                 if (invert_x)
  71                         x = X_AXIS_MAX - x;
  72                 if (invert_y)
  73                         y = Y_AXIS_MAX - y;
  74 
  75                 if (x != X_AXIS_MAX && x != 0) {
  76                         input_report_key(htcpen_dev, BTN_TOUCH, 1);
  77                         input_report_abs(htcpen_dev, ABS_X, x);
  78                         input_report_abs(htcpen_dev, ABS_Y, y);
  79                 }
  80         }
  81 
  82         input_sync(htcpen_dev);
  83 
  84         inb_p(HTCPEN_PORT_IRQ_CLEAR);
  85 
  86         return IRQ_HANDLED;
  87 }
  88 
  89 static int htcpen_open(struct input_dev *dev)
  90 {
  91         outb_p(DEVICE_ENABLE, HTCPEN_PORT_INIT);
  92 
  93         return 0;
  94 }
  95 
  96 static void htcpen_close(struct input_dev *dev)
  97 {
  98         outb_p(DEVICE_DISABLE, HTCPEN_PORT_INIT);
  99         synchronize_irq(HTCPEN_IRQ);
 100 }
 101 
 102 static int htcpen_isa_probe(struct device *dev, unsigned int id)
 103 {
 104         struct input_dev *htcpen_dev;
 105         int err = -EBUSY;
 106 
 107         if (!request_region(HTCPEN_PORT_IRQ_CLEAR, 1, "htcpen")) {
 108                 printk(KERN_ERR "htcpen: unable to get IO region 0x%x\n",
 109                         HTCPEN_PORT_IRQ_CLEAR);
 110                 goto request_region1_failed;
 111         }
 112 
 113         if (!request_region(HTCPEN_PORT_INIT, 1, "htcpen")) {
 114                 printk(KERN_ERR "htcpen: unable to get IO region 0x%x\n",
 115                         HTCPEN_PORT_INIT);
 116                 goto request_region2_failed;
 117         }
 118 
 119         if (!request_region(HTCPEN_PORT_INDEX, 2, "htcpen")) {
 120                 printk(KERN_ERR "htcpen: unable to get IO region 0x%x\n",
 121                         HTCPEN_PORT_INDEX);
 122                 goto request_region3_failed;
 123         }
 124 
 125         htcpen_dev = input_allocate_device();
 126         if (!htcpen_dev) {
 127                 printk(KERN_ERR "htcpen: can't allocate device\n");
 128                 err = -ENOMEM;
 129                 goto input_alloc_failed;
 130         }
 131 
 132         htcpen_dev->name = "HTC Shift EC TouchScreen";
 133         htcpen_dev->id.bustype = BUS_ISA;
 134 
 135         htcpen_dev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
 136         htcpen_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
 137         input_set_abs_params(htcpen_dev, ABS_X, 0, X_AXIS_MAX, 0, 0);
 138         input_set_abs_params(htcpen_dev, ABS_Y, 0, Y_AXIS_MAX, 0, 0);
 139 
 140         htcpen_dev->open = htcpen_open;
 141         htcpen_dev->close = htcpen_close;
 142 
 143         err = request_irq(HTCPEN_IRQ, htcpen_interrupt, 0, "htcpen",
 144                         htcpen_dev);
 145         if (err) {
 146                 printk(KERN_ERR "htcpen: irq busy\n");
 147                 goto request_irq_failed;
 148         }
 149 
 150         inb_p(HTCPEN_PORT_IRQ_CLEAR);
 151 
 152         err = input_register_device(htcpen_dev);
 153         if (err)
 154                 goto input_register_failed;
 155 
 156         dev_set_drvdata(dev, htcpen_dev);
 157 
 158         return 0;
 159 
 160  input_register_failed:
 161         free_irq(HTCPEN_IRQ, htcpen_dev);
 162  request_irq_failed:
 163         input_free_device(htcpen_dev);
 164  input_alloc_failed:
 165         release_region(HTCPEN_PORT_INDEX, 2);
 166  request_region3_failed:
 167         release_region(HTCPEN_PORT_INIT, 1);
 168  request_region2_failed:
 169         release_region(HTCPEN_PORT_IRQ_CLEAR, 1);
 170  request_region1_failed:
 171         return err;
 172 }
 173 
 174 static int htcpen_isa_remove(struct device *dev, unsigned int id)
 175 {
 176         struct input_dev *htcpen_dev = dev_get_drvdata(dev);
 177 
 178         input_unregister_device(htcpen_dev);
 179 
 180         free_irq(HTCPEN_IRQ, htcpen_dev);
 181 
 182         release_region(HTCPEN_PORT_INDEX, 2);
 183         release_region(HTCPEN_PORT_INIT, 1);
 184         release_region(HTCPEN_PORT_IRQ_CLEAR, 1);
 185 
 186         return 0;
 187 }
 188 
 189 #ifdef CONFIG_PM
 190 static int htcpen_isa_suspend(struct device *dev, unsigned int n,
 191                                 pm_message_t state)
 192 {
 193         outb_p(DEVICE_DISABLE, HTCPEN_PORT_INIT);
 194 
 195         return 0;
 196 }
 197 
 198 static int htcpen_isa_resume(struct device *dev, unsigned int n)
 199 {
 200         outb_p(DEVICE_ENABLE, HTCPEN_PORT_INIT);
 201 
 202         return 0;
 203 }
 204 #endif
 205 
 206 static struct isa_driver htcpen_isa_driver = {
 207         .probe          = htcpen_isa_probe,
 208         .remove         = htcpen_isa_remove,
 209 #ifdef CONFIG_PM
 210         .suspend        = htcpen_isa_suspend,
 211         .resume         = htcpen_isa_resume,
 212 #endif
 213         .driver = {
 214                 .owner  = THIS_MODULE,
 215                 .name   = "htcpen",
 216         }
 217 };
 218 
 219 static const struct dmi_system_id htcshift_dmi_table[] __initconst = {
 220         {
 221                 .ident = "Shift",
 222                 .matches = {
 223                         DMI_MATCH(DMI_SYS_VENDOR, "High Tech Computer Corp"),
 224                         DMI_MATCH(DMI_PRODUCT_NAME, "Shift"),
 225                 },
 226         },
 227         { }
 228 };
 229 MODULE_DEVICE_TABLE(dmi, htcshift_dmi_table);
 230 
 231 static int __init htcpen_isa_init(void)
 232 {
 233         if (!dmi_check_system(htcshift_dmi_table))
 234                 return -ENODEV;
 235 
 236         return isa_register_driver(&htcpen_isa_driver, 1);
 237 }
 238 
 239 static void __exit htcpen_isa_exit(void)
 240 {
 241         isa_unregister_driver(&htcpen_isa_driver);
 242 }
 243 
 244 module_init(htcpen_isa_init);
 245 module_exit(htcpen_isa_exit);

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