diff options
| author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
|---|---|---|
| committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
| commit | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch) | |
| tree | a57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/input/misc | |
| parent | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff) | |
Diffstat (limited to 'drivers/input/misc')
| -rw-r--r-- | drivers/input/misc/alps_gpio_scrollwheel.c | 428 | ||||
| -rw-r--r-- | drivers/input/misc/ati_remote.c | 867 | ||||
| -rw-r--r-- | drivers/input/misc/cm3217.c | 1081 | ||||
| -rw-r--r-- | drivers/input/misc/gpio_axis.c | 192 | ||||
| -rw-r--r-- | drivers/input/misc/gpio_event.c | 260 | ||||
| -rw-r--r-- | drivers/input/misc/gpio_input.c | 376 | ||||
| -rw-r--r-- | drivers/input/misc/gpio_matrix.c | 441 | ||||
| -rw-r--r-- | drivers/input/misc/gpio_output.c | 97 | ||||
| -rw-r--r-- | drivers/input/misc/keychord.c | 387 |
9 files changed, 4129 insertions, 0 deletions
diff --git a/drivers/input/misc/alps_gpio_scrollwheel.c b/drivers/input/misc/alps_gpio_scrollwheel.c new file mode 100644 index 00000000000..4a789267c47 --- /dev/null +++ b/drivers/input/misc/alps_gpio_scrollwheel.c | |||
| @@ -0,0 +1,428 @@ | |||
| 1 | /* | ||
| 2 | * kernel/drivers/input/misc/alps_gpio_scrollwheel.c | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010, NVIDIA Corporation. | ||
| 5 | * | ||
| 6 | * Driver for ScrollWheel on GPIO lines capable of generating interrupts. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
| 14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 16 | * more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License along | ||
| 19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
| 20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
| 21 | */ | ||
| 22 | |||
| 23 | |||
| 24 | #include <linux/module.h> | ||
| 25 | #include <linux/init.h> | ||
| 26 | #include <linux/fs.h> | ||
| 27 | #include <linux/interrupt.h> | ||
| 28 | #include <linux/irq.h> | ||
| 29 | #include <linux/sched.h> | ||
| 30 | #include <linux/pm.h> | ||
| 31 | #include <linux/slab.h> | ||
| 32 | #include <linux/sysctl.h> | ||
| 33 | #include <linux/proc_fs.h> | ||
| 34 | #include <linux/delay.h> | ||
| 35 | #include <linux/platform_device.h> | ||
| 36 | #include <linux/input.h> | ||
| 37 | #include <linux/gpio_scrollwheel.h> | ||
| 38 | #include <linux/workqueue.h> | ||
| 39 | #include <linux/gpio.h> | ||
| 40 | |||
| 41 | struct scrollwheel_button_data { | ||
| 42 | struct gpio_scrollwheel_button *button; | ||
| 43 | struct input_dev *input; | ||
| 44 | struct timer_list timer; | ||
| 45 | struct work_struct work; | ||
| 46 | int timer_debounce; /* in msecs */ | ||
| 47 | int rotgpio; | ||
| 48 | bool disabled; | ||
| 49 | }; | ||
| 50 | |||
| 51 | struct gpio_scrollwheel_drvdata { | ||
| 52 | struct input_dev *input; | ||
| 53 | struct mutex disable_lock; | ||
| 54 | unsigned int n_buttons; | ||
| 55 | int (*enable)(struct device *dev); | ||
| 56 | void (*disable)(struct device *dev); | ||
| 57 | struct scrollwheel_button_data data[0]; | ||
| 58 | }; | ||
| 59 | |||
| 60 | static void scrollwheel_report_key(struct scrollwheel_button_data *bdata) | ||
| 61 | { | ||
| 62 | struct gpio_scrollwheel_button *button = bdata->button; | ||
| 63 | struct input_dev *input = bdata->input; | ||
| 64 | int state = (gpio_get_value(button->gpio) ? 1 : 0) ^ \ | ||
| 65 | button->active_low; | ||
| 66 | int state2 = 0; | ||
| 67 | |||
| 68 | switch (button->pinaction) { | ||
| 69 | case GPIO_SCROLLWHEEL_PIN_PRESS: | ||
| 70 | input_report_key(input, KEY_ENTER, 1); | ||
| 71 | input_report_key(input, KEY_ENTER, 0); | ||
| 72 | input_sync(input); | ||
| 73 | break; | ||
| 74 | |||
| 75 | case GPIO_SCROLLWHEEL_PIN_ROT1: | ||
| 76 | case GPIO_SCROLLWHEEL_PIN_ROT2: | ||
| 77 | state2 = (gpio_get_value(bdata->rotgpio) ? 1 : 0) \ | ||
| 78 | ^ button->active_low; | ||
| 79 | if (state != state2) { | ||
| 80 | input_report_key(input, KEY_DOWN, 1); | ||
| 81 | input_report_key(input, KEY_DOWN, 0); | ||
| 82 | } else { | ||
| 83 | input_report_key(input, KEY_UP, 1); | ||
| 84 | input_report_key(input, KEY_UP, 0); | ||
| 85 | } | ||
| 86 | input_sync(input); | ||
| 87 | break; | ||
| 88 | |||
| 89 | default: | ||
| 90 | pr_err("%s:Line=%d, Invalid Pinaction\n", __func__, __LINE__); | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | static void scrollwheel_work_func(struct work_struct *work) | ||
| 95 | { | ||
| 96 | struct scrollwheel_button_data *bdata = | ||
| 97 | container_of(work, struct scrollwheel_button_data, work); | ||
| 98 | |||
| 99 | scrollwheel_report_key(bdata); | ||
| 100 | } | ||
| 101 | |||
| 102 | static void scrollwheel_timer(unsigned long _data) | ||
| 103 | { | ||
| 104 | struct scrollwheel_button_data *data = \ | ||
| 105 | (struct scrollwheel_button_data *)_data; | ||
| 106 | |||
| 107 | schedule_work(&data->work); | ||
| 108 | } | ||
| 109 | |||
| 110 | static irqreturn_t scrollwheel_isr(int irq, void *dev_id) | ||
| 111 | { | ||
| 112 | struct scrollwheel_button_data *bdata = dev_id; | ||
| 113 | struct gpio_scrollwheel_button *button = bdata->button; | ||
| 114 | |||
| 115 | BUG_ON(irq != gpio_to_irq(button->gpio)); | ||
| 116 | |||
| 117 | if (bdata->timer_debounce) | ||
| 118 | mod_timer(&bdata->timer, | ||
| 119 | jiffies + msecs_to_jiffies(bdata->timer_debounce)); | ||
| 120 | else | ||
| 121 | schedule_work(&bdata->work); | ||
| 122 | |||
| 123 | return IRQ_HANDLED; | ||
| 124 | } | ||
| 125 | |||
| 126 | static int __devinit gpio_scrollwheel_setup_key(struct platform_device *pdev, | ||
| 127 | struct scrollwheel_button_data *bdata, | ||
| 128 | struct gpio_scrollwheel_button *button) | ||
| 129 | { | ||
| 130 | char *desc = button->desc ? button->desc : "gpio_scrollwheel"; | ||
| 131 | struct device *dev = &pdev->dev; | ||
| 132 | unsigned long irqflags; | ||
| 133 | int irq, error; | ||
| 134 | |||
| 135 | setup_timer(&bdata->timer, scrollwheel_timer, (unsigned long)bdata); | ||
| 136 | INIT_WORK(&bdata->work, scrollwheel_work_func); | ||
| 137 | |||
| 138 | error = gpio_request(button->gpio, desc); | ||
| 139 | if (error < 0) { | ||
| 140 | dev_err(dev, "failed to request GPIO %d, error %d\n", | ||
| 141 | button->gpio, error); | ||
| 142 | return error; | ||
| 143 | } | ||
| 144 | |||
| 145 | error = gpio_direction_input(button->gpio); | ||
| 146 | if (error < 0) { | ||
| 147 | dev_err(dev, "failed to configure" | ||
| 148 | " direction for GPIO %d, error %d\n", | ||
| 149 | button->gpio, error); | ||
| 150 | goto fail; | ||
| 151 | } | ||
| 152 | |||
| 153 | if (button->debounce_interval) { | ||
| 154 | error = gpio_set_debounce(button->gpio, | ||
| 155 | button->debounce_interval * 1000); | ||
| 156 | /* use timer if gpiolib doesn't provide debounce */ | ||
| 157 | if (error < 0) | ||
| 158 | bdata->timer_debounce = button->debounce_interval; | ||
| 159 | } | ||
| 160 | |||
| 161 | irq = gpio_to_irq(button->gpio); | ||
| 162 | if (irq < 0) { | ||
| 163 | error = irq; | ||
| 164 | dev_err(dev, "Unable to get irq no for GPIO %d, error %d\n", | ||
| 165 | button->gpio, error); | ||
| 166 | goto fail; | ||
| 167 | } | ||
| 168 | |||
| 169 | irqflags = IRQF_TRIGGER_FALLING; | ||
| 170 | |||
| 171 | error = request_irq(irq, scrollwheel_isr, irqflags, desc, bdata); | ||
| 172 | if (error) { | ||
| 173 | dev_err(dev, "Unable to claim irq %d; error %d\n", | ||
| 174 | irq, error); | ||
| 175 | goto fail; | ||
| 176 | } | ||
| 177 | |||
| 178 | return 0; | ||
| 179 | |||
| 180 | fail: | ||
| 181 | return error; | ||
| 182 | } | ||
| 183 | |||
| 184 | static int gpio_scrollwheel_open(struct input_dev *input) | ||
| 185 | { | ||
| 186 | struct gpio_scrollwheel_drvdata *ddata = input_get_drvdata(input); | ||
| 187 | |||
| 188 | return ddata->enable ? ddata->enable(input->dev.parent) : 0; | ||
| 189 | } | ||
| 190 | |||
| 191 | static void gpio_scrollwheel_close(struct input_dev *input) | ||
| 192 | { | ||
| 193 | struct gpio_scrollwheel_drvdata *ddata = input_get_drvdata(input); | ||
| 194 | |||
| 195 | if (ddata->disable) | ||
| 196 | ddata->disable(input->dev.parent); | ||
| 197 | } | ||
| 198 | |||
| 199 | static int __devinit gpio_scrollwheel_probe(struct platform_device *pdev) | ||
| 200 | { | ||
| 201 | struct gpio_scrollwheel_platform_data *pdata = pdev->dev.platform_data; | ||
| 202 | struct gpio_scrollwheel_drvdata *ddata; | ||
| 203 | struct device *dev = &pdev->dev; | ||
| 204 | struct input_dev *input; | ||
| 205 | int i, error; | ||
| 206 | |||
| 207 | ddata = kzalloc(sizeof(struct gpio_scrollwheel_drvdata) + | ||
| 208 | pdata->nbuttons * sizeof(struct scrollwheel_button_data), | ||
| 209 | GFP_KERNEL); | ||
| 210 | if (ddata == NULL) { | ||
| 211 | dev_err(dev, "failed to allocate memory\n"); | ||
| 212 | error = -ENOMEM; | ||
| 213 | return error; | ||
| 214 | } | ||
| 215 | |||
| 216 | input = input_allocate_device(); | ||
| 217 | if (input == NULL) { | ||
| 218 | dev_err(dev, "failed to allocate input device\n"); | ||
| 219 | error = -ENOMEM; | ||
| 220 | kfree(ddata); | ||
| 221 | return error; | ||
| 222 | } | ||
| 223 | |||
| 224 | ddata->input = input; | ||
| 225 | ddata->n_buttons = pdata->nbuttons; | ||
| 226 | ddata->enable = pdata->enable; | ||
| 227 | ddata->disable = pdata->disable; | ||
| 228 | mutex_init(&ddata->disable_lock); | ||
| 229 | |||
| 230 | platform_set_drvdata(pdev, ddata); | ||
| 231 | input_set_drvdata(input, ddata); | ||
| 232 | |||
| 233 | input->name = pdev->name; | ||
| 234 | input->phys = "gpio-scrollwheel/input0"; | ||
| 235 | input->dev.parent = &pdev->dev; | ||
| 236 | input->open = gpio_scrollwheel_open; | ||
| 237 | input->close = gpio_scrollwheel_close; | ||
| 238 | |||
| 239 | input->id.bustype = BUS_HOST; | ||
| 240 | input->id.vendor = 0x0001; | ||
| 241 | input->id.product = 0x0001; | ||
| 242 | input->id.version = 0x0100; | ||
| 243 | |||
| 244 | /* Enable auto repeat feature of Linux input subsystem */ | ||
| 245 | if (pdata->rep) | ||
| 246 | __set_bit(EV_REP, input->evbit); | ||
| 247 | |||
| 248 | for (i = 0; i < pdata->nbuttons; i++) { | ||
| 249 | struct gpio_scrollwheel_button *button = &pdata->buttons[i]; | ||
| 250 | struct scrollwheel_button_data *bdata = &ddata->data[i]; | ||
| 251 | |||
| 252 | bdata->input = input; | ||
| 253 | bdata->button = button; | ||
| 254 | |||
| 255 | if (button->pinaction == GPIO_SCROLLWHEEL_PIN_PRESS || | ||
| 256 | button->pinaction == GPIO_SCROLLWHEEL_PIN_ROT1) { | ||
| 257 | error = gpio_scrollwheel_setup_key(pdev, bdata, button); | ||
| 258 | if (error) | ||
| 259 | goto fail; | ||
| 260 | } else { | ||
| 261 | if (button->pinaction == GPIO_SCROLLWHEEL_PIN_ONOFF) { | ||
| 262 | gpio_request(button->gpio, button->desc); | ||
| 263 | gpio_direction_output(button->gpio, 0); | ||
| 264 | } | ||
| 265 | |||
| 266 | if (button->pinaction == GPIO_SCROLLWHEEL_PIN_ROT2) { | ||
| 267 | gpio_request(button->gpio, button->desc); | ||
| 268 | gpio_direction_input(button->gpio); | ||
| 269 | /* Save rot2 gpio number in rot1 context */ | ||
| 270 | ddata->data[2].rotgpio = button->gpio; | ||
| 271 | } | ||
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 275 | /* set input capability */ | ||
| 276 | __set_bit(EV_KEY, input->evbit); | ||
| 277 | __set_bit(KEY_ENTER, input->keybit); | ||
| 278 | __set_bit(KEY_UP, input->keybit); | ||
| 279 | __set_bit(KEY_DOWN, input->keybit); | ||
| 280 | |||
| 281 | error = input_register_device(input); | ||
| 282 | if (error) { | ||
| 283 | dev_err(dev, "Unable to register input device, error: %d\n", | ||
| 284 | error); | ||
| 285 | goto fail; | ||
| 286 | } | ||
| 287 | |||
| 288 | input_sync(input); | ||
| 289 | |||
| 290 | return 0; | ||
| 291 | |||
| 292 | fail: | ||
| 293 | while (--i >= 0) { | ||
| 294 | if (pdata->buttons[i].pinaction == GPIO_SCROLLWHEEL_PIN_PRESS || | ||
| 295 | pdata->buttons[i].pinaction == GPIO_SCROLLWHEEL_PIN_ROT1) { | ||
| 296 | free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]); | ||
| 297 | if (ddata->data[i].timer_debounce) | ||
| 298 | del_timer_sync(&ddata->data[i].timer); | ||
| 299 | cancel_work_sync(&ddata->data[i].work); | ||
| 300 | } | ||
| 301 | gpio_free(pdata->buttons[i].gpio); | ||
| 302 | } | ||
| 303 | |||
| 304 | platform_set_drvdata(pdev, NULL); | ||
| 305 | input_free_device(input); | ||
| 306 | kfree(ddata); | ||
| 307 | return error; | ||
| 308 | } | ||
| 309 | |||
| 310 | static int __devexit gpio_scrollwheel_remove(struct platform_device *pdev) | ||
| 311 | { | ||
| 312 | struct gpio_scrollwheel_platform_data *pdata = pdev->dev.platform_data; | ||
| 313 | struct gpio_scrollwheel_drvdata *ddata = platform_get_drvdata(pdev); | ||
| 314 | struct input_dev *input = ddata->input; | ||
| 315 | int i; | ||
| 316 | |||
| 317 | for (i = 0; i < pdata->nbuttons; i++) { | ||
| 318 | if (pdata->buttons[i].pinaction == GPIO_SCROLLWHEEL_PIN_PRESS || | ||
| 319 | pdata->buttons[i].pinaction == GPIO_SCROLLWHEEL_PIN_ROT1) { | ||
| 320 | int irq = gpio_to_irq(pdata->buttons[i].gpio); | ||
| 321 | free_irq(irq, &ddata->data[i]); | ||
| 322 | if (ddata->data[i].timer_debounce) | ||
| 323 | del_timer_sync(&ddata->data[i].timer); | ||
| 324 | cancel_work_sync(&ddata->data[i].work); | ||
| 325 | } | ||
| 326 | gpio_free(pdata->buttons[i].gpio); | ||
| 327 | } | ||
| 328 | |||
| 329 | input_unregister_device(input); | ||
| 330 | |||
| 331 | return 0; | ||
| 332 | } | ||
| 333 | |||
| 334 | |||
| 335 | #ifdef CONFIG_PM | ||
| 336 | static int gpio_scrollwheel_suspend(struct device *dev) | ||
| 337 | { | ||
| 338 | struct platform_device *pdev = to_platform_device(dev); | ||
| 339 | struct gpio_scrollwheel_platform_data *pdata = pdev->dev.platform_data; | ||
| 340 | struct gpio_scrollwheel_drvdata *ddata = platform_get_drvdata(pdev); | ||
| 341 | int i, irq; | ||
| 342 | |||
| 343 | for (i = 0; i < pdata->nbuttons; i++) { | ||
| 344 | if (pdata->buttons[i].pinaction == GPIO_SCROLLWHEEL_PIN_PRESS || | ||
| 345 | pdata->buttons[i].pinaction == GPIO_SCROLLWHEEL_PIN_ROT1) { | ||
| 346 | irq = gpio_to_irq(pdata->buttons[i].gpio); | ||
| 347 | disable_irq(irq); | ||
| 348 | if (ddata->data[i].timer_debounce) | ||
| 349 | del_timer_sync(&ddata->data[i].timer); | ||
| 350 | cancel_work_sync(&ddata->data[i].work); | ||
| 351 | } else { | ||
| 352 | if (pdata->buttons[i].pinaction == GPIO_SCROLLWHEEL_PIN_ONOFF) | ||
| 353 | gpio_direction_output(pdata->buttons[i].gpio, 1); | ||
| 354 | else { | ||
| 355 | irq = gpio_to_irq(pdata->buttons[i].gpio); | ||
| 356 | disable_irq(irq); | ||
| 357 | } | ||
| 358 | } | ||
| 359 | } | ||
| 360 | return 0; | ||
| 361 | } | ||
| 362 | |||
| 363 | static int gpio_scrollwheel_resume(struct device *dev) | ||
| 364 | { | ||
| 365 | struct platform_device *pdev = to_platform_device(dev); | ||
| 366 | struct gpio_scrollwheel_platform_data *pdata = pdev->dev.platform_data; | ||
| 367 | struct gpio_scrollwheel_drvdata *ddata = platform_get_drvdata(pdev); | ||
| 368 | int i, irq; | ||
| 369 | |||
| 370 | for (i = 0; i < pdata->nbuttons; i++) { | ||
| 371 | if (pdata->buttons[i].pinaction == GPIO_SCROLLWHEEL_PIN_PRESS || | ||
| 372 | pdata->buttons[i].pinaction == GPIO_SCROLLWHEEL_PIN_ROT1) { | ||
| 373 | irq = gpio_to_irq(pdata->buttons[i].gpio); | ||
| 374 | enable_irq(irq); | ||
| 375 | if (ddata->data[i].timer_debounce) | ||
| 376 | setup_timer(&ddata->data[i].timer,\ | ||
| 377 | scrollwheel_timer, (unsigned long)&ddata->data[i]); | ||
| 378 | |||
| 379 | INIT_WORK(&ddata->data[i].work, scrollwheel_work_func); | ||
| 380 | } else { | ||
| 381 | if (pdata->buttons[i].pinaction == GPIO_SCROLLWHEEL_PIN_ONOFF) | ||
| 382 | gpio_direction_output(pdata->buttons[i].gpio, 0); | ||
| 383 | else { | ||
| 384 | irq = gpio_to_irq(pdata->buttons[i].gpio); | ||
| 385 | enable_irq(irq); | ||
| 386 | } | ||
| 387 | } | ||
| 388 | } | ||
| 389 | |||
| 390 | return 0; | ||
| 391 | } | ||
| 392 | |||
| 393 | static const struct dev_pm_ops gpio_scrollwheel_pm_ops = { | ||
| 394 | .suspend = gpio_scrollwheel_suspend, | ||
| 395 | .resume = gpio_scrollwheel_resume, | ||
| 396 | }; | ||
| 397 | #endif | ||
| 398 | |||
| 399 | static struct platform_driver gpio_scrollwheel_device_driver = { | ||
| 400 | .probe = gpio_scrollwheel_probe, | ||
| 401 | .remove = __devexit_p(gpio_scrollwheel_remove), | ||
| 402 | .driver = { | ||
| 403 | .name = "alps-gpio-scrollwheel", | ||
| 404 | .owner = THIS_MODULE, | ||
| 405 | #ifdef CONFIG_PM | ||
| 406 | .pm = &gpio_scrollwheel_pm_ops, | ||
| 407 | #endif | ||
| 408 | } | ||
| 409 | }; | ||
| 410 | |||
| 411 | static int __init gpio_scrollwheel_init(void) | ||
| 412 | { | ||
| 413 | return platform_driver_register(&gpio_scrollwheel_device_driver); | ||
| 414 | } | ||
| 415 | |||
| 416 | static void __exit gpio_scrollwheel_exit(void) | ||
| 417 | { | ||
| 418 | platform_driver_unregister(&gpio_scrollwheel_device_driver); | ||
| 419 | } | ||
| 420 | |||
| 421 | module_init(gpio_scrollwheel_init); | ||
| 422 | module_exit(gpio_scrollwheel_exit); | ||
| 423 | |||
| 424 | MODULE_LICENSE("GPL"); | ||
| 425 | MODULE_AUTHOR("NVIDIA Corporation"); | ||
| 426 | MODULE_DESCRIPTION("Alps SRBE ScrollWheel driver"); | ||
| 427 | |||
| 428 | MODULE_ALIAS("platform:alps-gpio-scrollwheel"); | ||
diff --git a/drivers/input/misc/ati_remote.c b/drivers/input/misc/ati_remote.c new file mode 100644 index 00000000000..bce57129afb --- /dev/null +++ b/drivers/input/misc/ati_remote.c | |||
| @@ -0,0 +1,867 @@ | |||
| 1 | /* | ||
| 2 | * USB ATI Remote support | ||
| 3 | * | ||
| 4 | * Version 2.2.0 Copyright (c) 2004 Torrey Hoffman <thoffman@arnor.net> | ||
| 5 | * Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev | ||
| 6 | * | ||
| 7 | * This 2.2.0 version is a rewrite / cleanup of the 2.1.1 driver, including | ||
| 8 | * porting to the 2.6 kernel interfaces, along with other modification | ||
| 9 | * to better match the style of the existing usb/input drivers. However, the | ||
| 10 | * protocol and hardware handling is essentially unchanged from 2.1.1. | ||
| 11 | * | ||
| 12 | * The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by | ||
| 13 | * Vojtech Pavlik. | ||
| 14 | * | ||
| 15 | * Changes: | ||
| 16 | * | ||
| 17 | * Feb 2004: Torrey Hoffman <thoffman@arnor.net> | ||
| 18 | * Version 2.2.0 | ||
| 19 | * Jun 2004: Torrey Hoffman <thoffman@arnor.net> | ||
| 20 | * Version 2.2.1 | ||
| 21 | * Added key repeat support contributed by: | ||
| 22 | * Vincent Vanackere <vanackere@lif.univ-mrs.fr> | ||
| 23 | * Added support for the "Lola" remote contributed by: | ||
| 24 | * Seth Cohn <sethcohn@yahoo.com> | ||
| 25 | * | ||
| 26 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 27 | * | ||
| 28 | * This program is free software; you can redistribute it and/or modify | ||
| 29 | * it under the terms of the GNU General Public License as published by | ||
| 30 | * the Free Software Foundation; either version 2 of the License, or | ||
| 31 | * (at your option) any later version. | ||
| 32 | * | ||
| 33 | * This program is distributed in the hope that it will be useful, | ||
| 34 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 35 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 36 | * GNU General Public License for more details. | ||
| 37 | * | ||
| 38 | * You should have received a copy of the GNU General Public License | ||
| 39 | * along with this program; if not, write to the Free Software | ||
| 40 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 41 | * | ||
| 42 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 43 | * | ||
| 44 | * Hardware & software notes | ||
| 45 | * | ||
| 46 | * These remote controls are distributed by ATI as part of their | ||
| 47 | * "All-In-Wonder" video card packages. The receiver self-identifies as a | ||
| 48 | * "USB Receiver" with manufacturer "X10 Wireless Technology Inc". | ||
| 49 | * | ||
| 50 | * The "Lola" remote is available from X10. See: | ||
| 51 | * http://www.x10.com/products/lola_sg1.htm | ||
| 52 | * The Lola is similar to the ATI remote but has no mouse support, and slightly | ||
| 53 | * different keys. | ||
| 54 | * | ||
| 55 | * It is possible to use multiple receivers and remotes on multiple computers | ||
| 56 | * simultaneously by configuring them to use specific channels. | ||
| 57 | * | ||
| 58 | * The RF protocol used by the remote supports 16 distinct channels, 1 to 16. | ||
| 59 | * Actually, it may even support more, at least in some revisions of the | ||
| 60 | * hardware. | ||
| 61 | * | ||
| 62 | * Each remote can be configured to transmit on one channel as follows: | ||
| 63 | * - Press and hold the "hand icon" button. | ||
| 64 | * - When the red LED starts to blink, let go of the "hand icon" button. | ||
| 65 | * - When it stops blinking, input the channel code as two digits, from 01 | ||
| 66 | * to 16, and press the hand icon again. | ||
| 67 | * | ||
| 68 | * The timing can be a little tricky. Try loading the module with debug=1 | ||
| 69 | * to have the kernel print out messages about the remote control number | ||
| 70 | * and mask. Note: debugging prints remote numbers as zero-based hexadecimal. | ||
| 71 | * | ||
| 72 | * The driver has a "channel_mask" parameter. This bitmask specifies which | ||
| 73 | * channels will be ignored by the module. To mask out channels, just add | ||
| 74 | * all the 2^channel_number values together. | ||
| 75 | * | ||
| 76 | * For instance, set channel_mask = 2^4 = 16 (binary 10000) to make ati_remote | ||
| 77 | * ignore signals coming from remote controls transmitting on channel 4, but | ||
| 78 | * accept all other channels. | ||
| 79 | * | ||
| 80 | * Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be | ||
| 81 | * ignored. | ||
| 82 | * | ||
| 83 | * The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this | ||
| 84 | * parameter are unused. | ||
| 85 | * | ||
| 86 | */ | ||
| 87 | |||
| 88 | #include <linux/kernel.h> | ||
| 89 | #include <linux/errno.h> | ||
| 90 | #include <linux/init.h> | ||
| 91 | #include <linux/slab.h> | ||
| 92 | #include <linux/module.h> | ||
| 93 | #include <linux/usb/input.h> | ||
| 94 | #include <linux/wait.h> | ||
| 95 | #include <linux/jiffies.h> | ||
| 96 | |||
| 97 | /* | ||
| 98 | * Module and Version Information, Module Parameters | ||
| 99 | */ | ||
| 100 | |||
| 101 | #define ATI_REMOTE_VENDOR_ID 0x0bc7 | ||
| 102 | #define LOLA_REMOTE_PRODUCT_ID 0x0002 | ||
| 103 | #define LOLA2_REMOTE_PRODUCT_ID 0x0003 | ||
| 104 | #define ATI_REMOTE_PRODUCT_ID 0x0004 | ||
| 105 | #define NVIDIA_REMOTE_PRODUCT_ID 0x0005 | ||
| 106 | #define MEDION_REMOTE_PRODUCT_ID 0x0006 | ||
| 107 | |||
| 108 | #define DRIVER_VERSION "2.2.1" | ||
| 109 | #define DRIVER_AUTHOR "Torrey Hoffman <thoffman@arnor.net>" | ||
| 110 | #define DRIVER_DESC "ATI/X10 RF USB Remote Control" | ||
| 111 | |||
| 112 | #define NAME_BUFSIZE 80 /* size of product name, path buffers */ | ||
| 113 | #define DATA_BUFSIZE 63 /* size of URB data buffers */ | ||
| 114 | |||
| 115 | /* | ||
| 116 | * Duplicate event filtering time. | ||
| 117 | * Sequential, identical KIND_FILTERED inputs with less than | ||
| 118 | * FILTER_TIME milliseconds between them are considered as repeat | ||
| 119 | * events. The hardware generates 5 events for the first keypress | ||
| 120 | * and we have to take this into account for an accurate repeat | ||
| 121 | * behaviour. | ||
| 122 | */ | ||
| 123 | #define FILTER_TIME 60 /* msec */ | ||
| 124 | #define REPEAT_DELAY 500 /* msec */ | ||
| 125 | |||
| 126 | static unsigned long channel_mask; | ||
| 127 | module_param(channel_mask, ulong, 0644); | ||
| 128 | MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore"); | ||
| 129 | |||
| 130 | static int debug; | ||
| 131 | module_param(debug, int, 0644); | ||
| 132 | MODULE_PARM_DESC(debug, "Enable extra debug messages and information"); | ||
| 133 | |||
| 134 | static int repeat_filter = FILTER_TIME; | ||
| 135 | module_param(repeat_filter, int, 0644); | ||
| 136 | MODULE_PARM_DESC(repeat_filter, "Repeat filter time, default = 60 msec"); | ||
| 137 | |||
| 138 | static int repeat_delay = REPEAT_DELAY; | ||
| 139 | module_param(repeat_delay, int, 0644); | ||
| 140 | MODULE_PARM_DESC(repeat_delay, "Delay before sending repeats, default = 500 msec"); | ||
| 141 | |||
| 142 | #define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0) | ||
| 143 | #undef err | ||
| 144 | #define err(format, arg...) printk(KERN_ERR format , ## arg) | ||
| 145 | |||
| 146 | static struct usb_device_id ati_remote_table[] = { | ||
| 147 | { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID) }, | ||
| 148 | { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA2_REMOTE_PRODUCT_ID) }, | ||
| 149 | { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) }, | ||
| 150 | { USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID) }, | ||
| 151 | { USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID) }, | ||
| 152 | {} /* Terminating entry */ | ||
| 153 | }; | ||
| 154 | |||
| 155 | MODULE_DEVICE_TABLE(usb, ati_remote_table); | ||
| 156 | |||
| 157 | /* Get hi and low bytes of a 16-bits int */ | ||
| 158 | #define HI(a) ((unsigned char)((a) >> 8)) | ||
| 159 | #define LO(a) ((unsigned char)((a) & 0xff)) | ||
| 160 | |||
| 161 | #define SEND_FLAG_IN_PROGRESS 1 | ||
| 162 | #define SEND_FLAG_COMPLETE 2 | ||
| 163 | |||
| 164 | /* Device initialization strings */ | ||
| 165 | static char init1[] = { 0x01, 0x00, 0x20, 0x14 }; | ||
| 166 | static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 }; | ||
| 167 | |||
| 168 | struct ati_remote { | ||
| 169 | struct input_dev *idev; | ||
| 170 | struct usb_device *udev; | ||
| 171 | struct usb_interface *interface; | ||
| 172 | |||
| 173 | struct urb *irq_urb; | ||
| 174 | struct urb *out_urb; | ||
| 175 | struct usb_endpoint_descriptor *endpoint_in; | ||
| 176 | struct usb_endpoint_descriptor *endpoint_out; | ||
| 177 | unsigned char *inbuf; | ||
| 178 | unsigned char *outbuf; | ||
| 179 | dma_addr_t inbuf_dma; | ||
| 180 | dma_addr_t outbuf_dma; | ||
| 181 | |||
| 182 | unsigned char old_data[2]; /* Detect duplicate events */ | ||
| 183 | unsigned long old_jiffies; | ||
| 184 | unsigned long acc_jiffies; /* handle acceleration */ | ||
| 185 | unsigned long first_jiffies; | ||
| 186 | |||
| 187 | unsigned int repeat_count; | ||
| 188 | |||
| 189 | char name[NAME_BUFSIZE]; | ||
| 190 | char phys[NAME_BUFSIZE]; | ||
| 191 | |||
| 192 | wait_queue_head_t wait; | ||
| 193 | int send_flags; | ||
| 194 | }; | ||
| 195 | |||
| 196 | /* "Kinds" of messages sent from the hardware to the driver. */ | ||
| 197 | #define KIND_END 0 | ||
| 198 | #define KIND_LITERAL 1 /* Simply pass to input system */ | ||
| 199 | #define KIND_FILTERED 2 /* Add artificial key-up events, drop keyrepeats */ | ||
| 200 | #define KIND_LU 3 /* Directional keypad diagonals - left up, */ | ||
| 201 | #define KIND_RU 4 /* right up, */ | ||
| 202 | #define KIND_LD 5 /* left down, */ | ||
| 203 | #define KIND_RD 6 /* right down */ | ||
| 204 | #define KIND_ACCEL 7 /* Directional keypad - left, right, up, down.*/ | ||
| 205 | |||
| 206 | /* Translation table from hardware messages to input events. */ | ||
| 207 | static const struct { | ||
| 208 | short kind; | ||
| 209 | unsigned char data1, data2; | ||
| 210 | int type; | ||
| 211 | unsigned int code; | ||
| 212 | int value; | ||
| 213 | } ati_remote_tbl[] = { | ||
| 214 | /* Directional control pad axes */ | ||
| 215 | {KIND_ACCEL, 0x35, 0x70, EV_REL, REL_X, -1}, /* left */ | ||
| 216 | {KIND_ACCEL, 0x36, 0x71, EV_REL, REL_X, 1}, /* right */ | ||
| 217 | {KIND_ACCEL, 0x37, 0x72, EV_REL, REL_Y, -1}, /* up */ | ||
| 218 | {KIND_ACCEL, 0x38, 0x73, EV_REL, REL_Y, 1}, /* down */ | ||
| 219 | /* Directional control pad diagonals */ | ||
| 220 | {KIND_LU, 0x39, 0x74, EV_REL, 0, 0}, /* left up */ | ||
| 221 | {KIND_RU, 0x3a, 0x75, EV_REL, 0, 0}, /* right up */ | ||
| 222 | {KIND_LD, 0x3c, 0x77, EV_REL, 0, 0}, /* left down */ | ||
| 223 | {KIND_RD, 0x3b, 0x76, EV_REL, 0, 0}, /* right down */ | ||
| 224 | |||
| 225 | /* "Mouse button" buttons */ | ||
| 226 | {KIND_LITERAL, 0x3d, 0x78, EV_KEY, BTN_LEFT, 1}, /* left btn down */ | ||
| 227 | {KIND_LITERAL, 0x3e, 0x79, EV_KEY, BTN_LEFT, 0}, /* left btn up */ | ||
| 228 | {KIND_LITERAL, 0x41, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */ | ||
| 229 | {KIND_LITERAL, 0x42, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */ | ||
| 230 | |||
| 231 | /* Artificial "doubleclick" events are generated by the hardware. | ||
| 232 | * They are mapped to the "side" and "extra" mouse buttons here. */ | ||
| 233 | {KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */ | ||
| 234 | {KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */ | ||
| 235 | |||
| 236 | /* keyboard. */ | ||
| 237 | {KIND_FILTERED, 0xd2, 0x0d, EV_KEY, KEY_1, 1}, | ||
| 238 | {KIND_FILTERED, 0xd3, 0x0e, EV_KEY, KEY_2, 1}, | ||
| 239 | {KIND_FILTERED, 0xd4, 0x0f, EV_KEY, KEY_3, 1}, | ||
| 240 | {KIND_FILTERED, 0xd5, 0x10, EV_KEY, KEY_4, 1}, | ||
| 241 | {KIND_FILTERED, 0xd6, 0x11, EV_KEY, KEY_5, 1}, | ||
| 242 | {KIND_FILTERED, 0xd7, 0x12, EV_KEY, KEY_6, 1}, | ||
| 243 | {KIND_FILTERED, 0xd8, 0x13, EV_KEY, KEY_7, 1}, | ||
| 244 | {KIND_FILTERED, 0xd9, 0x14, EV_KEY, KEY_8, 1}, | ||
| 245 | {KIND_FILTERED, 0xda, 0x15, EV_KEY, KEY_9, 1}, | ||
| 246 | {KIND_FILTERED, 0xdc, 0x17, EV_KEY, KEY_0, 1}, | ||
| 247 | {KIND_FILTERED, 0xc5, 0x00, EV_KEY, KEY_A, 1}, | ||
| 248 | {KIND_FILTERED, 0xc6, 0x01, EV_KEY, KEY_B, 1}, | ||
| 249 | {KIND_FILTERED, 0xde, 0x19, EV_KEY, KEY_C, 1}, | ||
| 250 | {KIND_FILTERED, 0xe0, 0x1b, EV_KEY, KEY_D, 1}, | ||
| 251 | {KIND_FILTERED, 0xe6, 0x21, EV_KEY, KEY_E, 1}, | ||
| 252 | {KIND_FILTERED, 0xe8, 0x23, EV_KEY, KEY_F, 1}, | ||
| 253 | |||
| 254 | /* "special" keys */ | ||
| 255 | {KIND_FILTERED, 0xdd, 0x18, EV_KEY, KEY_KPENTER, 1}, /* "check" */ | ||
| 256 | {KIND_FILTERED, 0xdb, 0x16, EV_KEY, KEY_MENU, 1}, /* "menu" */ | ||
| 257 | {KIND_FILTERED, 0xc7, 0x02, EV_KEY, KEY_POWER, 1}, /* Power */ | ||
| 258 | {KIND_FILTERED, 0xc8, 0x03, EV_KEY, KEY_TV, 1}, /* TV */ | ||
| 259 | {KIND_FILTERED, 0xc9, 0x04, EV_KEY, KEY_DVD, 1}, /* DVD */ | ||
| 260 | {KIND_FILTERED, 0xca, 0x05, EV_KEY, KEY_WWW, 1}, /* WEB */ | ||
| 261 | {KIND_FILTERED, 0xcb, 0x06, EV_KEY, KEY_BOOKMARKS, 1}, /* "book" */ | ||
| 262 | {KIND_FILTERED, 0xcc, 0x07, EV_KEY, KEY_EDIT, 1}, /* "hand" */ | ||
| 263 | {KIND_FILTERED, 0xe1, 0x1c, EV_KEY, KEY_COFFEE, 1}, /* "timer" */ | ||
| 264 | {KIND_FILTERED, 0xe5, 0x20, EV_KEY, KEY_FRONT, 1}, /* "max" */ | ||
| 265 | {KIND_FILTERED, 0xe2, 0x1d, EV_KEY, KEY_LEFT, 1}, /* left */ | ||
| 266 | {KIND_FILTERED, 0xe4, 0x1f, EV_KEY, KEY_RIGHT, 1}, /* right */ | ||
| 267 | {KIND_FILTERED, 0xe7, 0x22, EV_KEY, KEY_DOWN, 1}, /* down */ | ||
| 268 | {KIND_FILTERED, 0xdf, 0x1a, EV_KEY, KEY_UP, 1}, /* up */ | ||
| 269 | {KIND_FILTERED, 0xe3, 0x1e, EV_KEY, KEY_OK, 1}, /* "OK" */ | ||
| 270 | {KIND_FILTERED, 0xce, 0x09, EV_KEY, KEY_VOLUMEDOWN, 1}, /* VOL + */ | ||
| 271 | {KIND_FILTERED, 0xcd, 0x08, EV_KEY, KEY_VOLUMEUP, 1}, /* VOL - */ | ||
| 272 | {KIND_FILTERED, 0xcf, 0x0a, EV_KEY, KEY_MUTE, 1}, /* MUTE */ | ||
| 273 | {KIND_FILTERED, 0xd0, 0x0b, EV_KEY, KEY_CHANNELUP, 1}, /* CH + */ | ||
| 274 | {KIND_FILTERED, 0xd1, 0x0c, EV_KEY, KEY_CHANNELDOWN, 1},/* CH - */ | ||
| 275 | {KIND_FILTERED, 0xec, 0x27, EV_KEY, KEY_RECORD, 1}, /* ( o) red */ | ||
| 276 | {KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAY, 1}, /* ( >) */ | ||
| 277 | {KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1}, /* (<<) */ | ||
| 278 | {KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1}, /* (>>) */ | ||
| 279 | {KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1}, /* ([]) */ | ||
| 280 | {KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_PAUSE, 1}, /* ('') */ | ||
| 281 | {KIND_FILTERED, 0xf0, 0x2b, EV_KEY, KEY_PREVIOUS, 1}, /* (<-) */ | ||
| 282 | {KIND_FILTERED, 0xef, 0x2a, EV_KEY, KEY_NEXT, 1}, /* (>+) */ | ||
| 283 | {KIND_FILTERED, 0xf2, 0x2D, EV_KEY, KEY_INFO, 1}, /* PLAYING */ | ||
| 284 | {KIND_FILTERED, 0xf3, 0x2E, EV_KEY, KEY_HOME, 1}, /* TOP */ | ||
| 285 | {KIND_FILTERED, 0xf4, 0x2F, EV_KEY, KEY_END, 1}, /* END */ | ||
| 286 | {KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_SELECT, 1}, /* SELECT */ | ||
| 287 | |||
| 288 | {KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0} | ||
| 289 | }; | ||
| 290 | |||
| 291 | /* Local function prototypes */ | ||
| 292 | static int ati_remote_open (struct input_dev *inputdev); | ||
| 293 | static void ati_remote_close (struct input_dev *inputdev); | ||
| 294 | static int ati_remote_sendpacket (struct ati_remote *ati_remote, u16 cmd, unsigned char *data); | ||
| 295 | static void ati_remote_irq_out (struct urb *urb); | ||
| 296 | static void ati_remote_irq_in (struct urb *urb); | ||
| 297 | static void ati_remote_input_report (struct urb *urb); | ||
| 298 | static int ati_remote_initialize (struct ati_remote *ati_remote); | ||
| 299 | static int ati_remote_probe (struct usb_interface *interface, const struct usb_device_id *id); | ||
| 300 | static void ati_remote_disconnect (struct usb_interface *interface); | ||
| 301 | |||
| 302 | /* usb specific object to register with the usb subsystem */ | ||
| 303 | static struct usb_driver ati_remote_driver = { | ||
| 304 | .name = "ati_remote", | ||
| 305 | .probe = ati_remote_probe, | ||
| 306 | .disconnect = ati_remote_disconnect, | ||
| 307 | .id_table = ati_remote_table, | ||
| 308 | }; | ||
| 309 | |||
| 310 | /* | ||
| 311 | * ati_remote_dump_input | ||
| 312 | */ | ||
| 313 | static void ati_remote_dump(struct device *dev, unsigned char *data, | ||
| 314 | unsigned int len) | ||
| 315 | { | ||
| 316 | if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00)) | ||
| 317 | dev_warn(dev, "Weird byte 0x%02x\n", data[0]); | ||
| 318 | else if (len == 4) | ||
| 319 | dev_warn(dev, "Weird key %02x %02x %02x %02x\n", | ||
| 320 | data[0], data[1], data[2], data[3]); | ||
| 321 | else | ||
| 322 | dev_warn(dev, "Weird data, len=%d %02x %02x %02x %02x %02x %02x ...\n", | ||
| 323 | len, data[0], data[1], data[2], data[3], data[4], data[5]); | ||
| 324 | } | ||
| 325 | |||
| 326 | /* | ||
| 327 | * ati_remote_open | ||
| 328 | */ | ||
| 329 | static int ati_remote_open(struct input_dev *inputdev) | ||
| 330 | { | ||
| 331 | struct ati_remote *ati_remote = input_get_drvdata(inputdev); | ||
| 332 | |||
| 333 | /* On first open, submit the read urb which was set up previously. */ | ||
| 334 | ati_remote->irq_urb->dev = ati_remote->udev; | ||
| 335 | if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) { | ||
| 336 | dev_err(&ati_remote->interface->dev, | ||
| 337 | "%s: usb_submit_urb failed!\n", __func__); | ||
| 338 | return -EIO; | ||
| 339 | } | ||
| 340 | |||
| 341 | return 0; | ||
| 342 | } | ||
| 343 | |||
| 344 | /* | ||
| 345 | * ati_remote_close | ||
| 346 | */ | ||
| 347 | static void ati_remote_close(struct input_dev *inputdev) | ||
| 348 | { | ||
| 349 | struct ati_remote *ati_remote = input_get_drvdata(inputdev); | ||
| 350 | |||
| 351 | usb_kill_urb(ati_remote->irq_urb); | ||
| 352 | } | ||
| 353 | |||
| 354 | /* | ||
| 355 | * ati_remote_irq_out | ||
| 356 | */ | ||
| 357 | static void ati_remote_irq_out(struct urb *urb) | ||
| 358 | { | ||
| 359 | struct ati_remote *ati_remote = urb->context; | ||
| 360 | |||
| 361 | if (urb->status) { | ||
| 362 | dev_dbg(&ati_remote->interface->dev, "%s: status %d\n", | ||
| 363 | __func__, urb->status); | ||
| 364 | return; | ||
| 365 | } | ||
| 366 | |||
| 367 | ati_remote->send_flags |= SEND_FLAG_COMPLETE; | ||
| 368 | wmb(); | ||
| 369 | wake_up(&ati_remote->wait); | ||
| 370 | } | ||
| 371 | |||
| 372 | /* | ||
| 373 | * ati_remote_sendpacket | ||
| 374 | * | ||
| 375 | * Used to send device initialization strings | ||
| 376 | */ | ||
| 377 | static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigned char *data) | ||
| 378 | { | ||
| 379 | int retval = 0; | ||
| 380 | |||
| 381 | /* Set up out_urb */ | ||
| 382 | memcpy(ati_remote->out_urb->transfer_buffer + 1, data, LO(cmd)); | ||
| 383 | ((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd); | ||
| 384 | |||
| 385 | ati_remote->out_urb->transfer_buffer_length = LO(cmd) + 1; | ||
| 386 | ati_remote->out_urb->dev = ati_remote->udev; | ||
| 387 | ati_remote->send_flags = SEND_FLAG_IN_PROGRESS; | ||
| 388 | |||
| 389 | retval = usb_submit_urb(ati_remote->out_urb, GFP_ATOMIC); | ||
| 390 | if (retval) { | ||
| 391 | dev_dbg(&ati_remote->interface->dev, | ||
| 392 | "sendpacket: usb_submit_urb failed: %d\n", retval); | ||
| 393 | return retval; | ||
| 394 | } | ||
| 395 | |||
| 396 | wait_event_timeout(ati_remote->wait, | ||
| 397 | ((ati_remote->out_urb->status != -EINPROGRESS) || | ||
| 398 | (ati_remote->send_flags & SEND_FLAG_COMPLETE)), | ||
| 399 | HZ); | ||
| 400 | usb_kill_urb(ati_remote->out_urb); | ||
| 401 | |||
| 402 | return retval; | ||
| 403 | } | ||
| 404 | |||
| 405 | /* | ||
| 406 | * ati_remote_event_lookup | ||
| 407 | */ | ||
| 408 | static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2) | ||
| 409 | { | ||
| 410 | int i; | ||
| 411 | |||
| 412 | for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) { | ||
| 413 | /* | ||
| 414 | * Decide if the table entry matches the remote input. | ||
| 415 | */ | ||
| 416 | if ((((ati_remote_tbl[i].data1 & 0x0f) == (d1 & 0x0f))) && | ||
| 417 | ((((ati_remote_tbl[i].data1 >> 4) - | ||
| 418 | (d1 >> 4) + rem) & 0x0f) == 0x0f) && | ||
| 419 | (ati_remote_tbl[i].data2 == d2)) | ||
| 420 | return i; | ||
| 421 | |||
| 422 | } | ||
| 423 | return -1; | ||
| 424 | } | ||
| 425 | |||
| 426 | /* | ||
| 427 | * ati_remote_compute_accel | ||
| 428 | * | ||
| 429 | * Implements acceleration curve for directional control pad | ||
| 430 | * If elapsed time since last event is > 1/4 second, user "stopped", | ||
| 431 | * so reset acceleration. Otherwise, user is probably holding the control | ||
| 432 | * pad down, so we increase acceleration, ramping up over two seconds to | ||
| 433 | * a maximum speed. | ||
| 434 | */ | ||
| 435 | static int ati_remote_compute_accel(struct ati_remote *ati_remote) | ||
| 436 | { | ||
| 437 | static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 }; | ||
| 438 | unsigned long now = jiffies; | ||
| 439 | int acc; | ||
| 440 | |||
| 441 | if (time_after(now, ati_remote->old_jiffies + msecs_to_jiffies(250))) { | ||
| 442 | acc = 1; | ||
| 443 | ati_remote->acc_jiffies = now; | ||
| 444 | } | ||
| 445 | else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(125))) | ||
| 446 | acc = accel[0]; | ||
| 447 | else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(250))) | ||
| 448 | acc = accel[1]; | ||
| 449 | else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(500))) | ||
| 450 | acc = accel[2]; | ||
| 451 | else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1000))) | ||
| 452 | acc = accel[3]; | ||
| 453 | else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1500))) | ||
| 454 | acc = accel[4]; | ||
| 455 | else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(2000))) | ||
| 456 | acc = accel[5]; | ||
| 457 | else | ||
| 458 | acc = accel[6]; | ||
| 459 | |||
| 460 | return acc; | ||
| 461 | } | ||
| 462 | |||
| 463 | /* | ||
| 464 | * ati_remote_report_input | ||
| 465 | */ | ||
| 466 | static void ati_remote_input_report(struct urb *urb) | ||
| 467 | { | ||
| 468 | struct ati_remote *ati_remote = urb->context; | ||
| 469 | unsigned char *data= ati_remote->inbuf; | ||
| 470 | struct input_dev *dev = ati_remote->idev; | ||
| 471 | int index, acc; | ||
| 472 | int remote_num; | ||
| 473 | |||
| 474 | /* Deal with strange looking inputs */ | ||
| 475 | if ( (urb->actual_length != 4) || (data[0] != 0x14) || | ||
| 476 | ((data[3] & 0x0f) != 0x00) ) { | ||
| 477 | ati_remote_dump(&urb->dev->dev, data, urb->actual_length); | ||
| 478 | return; | ||
| 479 | } | ||
| 480 | |||
| 481 | /* Mask unwanted remote channels. */ | ||
| 482 | /* note: remote_num is 0-based, channel 1 on remote == 0 here */ | ||
| 483 | remote_num = (data[3] >> 4) & 0x0f; | ||
| 484 | if (channel_mask & (1 << (remote_num + 1))) { | ||
| 485 | dbginfo(&ati_remote->interface->dev, | ||
| 486 | "Masked input from channel 0x%02x: data %02x,%02x, mask= 0x%02lx\n", | ||
| 487 | remote_num, data[1], data[2], channel_mask); | ||
| 488 | return; | ||
| 489 | } | ||
| 490 | |||
| 491 | /* Look up event code index in translation table */ | ||
| 492 | index = ati_remote_event_lookup(remote_num, data[1], data[2]); | ||
| 493 | if (index < 0) { | ||
| 494 | dev_warn(&ati_remote->interface->dev, | ||
| 495 | "Unknown input from channel 0x%02x: data %02x,%02x\n", | ||
| 496 | remote_num, data[1], data[2]); | ||
| 497 | return; | ||
| 498 | } | ||
| 499 | dbginfo(&ati_remote->interface->dev, | ||
| 500 | "channel 0x%02x; data %02x,%02x; index %d; keycode %d\n", | ||
| 501 | remote_num, data[1], data[2], index, ati_remote_tbl[index].code); | ||
| 502 | |||
| 503 | if (ati_remote_tbl[index].kind == KIND_LITERAL) { | ||
| 504 | input_event(dev, ati_remote_tbl[index].type, | ||
| 505 | ati_remote_tbl[index].code, | ||
| 506 | ati_remote_tbl[index].value); | ||
| 507 | input_sync(dev); | ||
| 508 | |||
| 509 | ati_remote->old_jiffies = jiffies; | ||
| 510 | return; | ||
| 511 | } | ||
| 512 | |||
| 513 | if (ati_remote_tbl[index].kind == KIND_FILTERED) { | ||
| 514 | unsigned long now = jiffies; | ||
| 515 | |||
| 516 | /* Filter duplicate events which happen "too close" together. */ | ||
| 517 | if (ati_remote->old_data[0] == data[1] && | ||
| 518 | ati_remote->old_data[1] == data[2] && | ||
| 519 | time_before(now, ati_remote->old_jiffies + | ||
| 520 | msecs_to_jiffies(repeat_filter))) { | ||
| 521 | ati_remote->repeat_count++; | ||
| 522 | } else { | ||
| 523 | ati_remote->repeat_count = 0; | ||
| 524 | ati_remote->first_jiffies = now; | ||
| 525 | } | ||
| 526 | |||
| 527 | ati_remote->old_data[0] = data[1]; | ||
| 528 | ati_remote->old_data[1] = data[2]; | ||
| 529 | ati_remote->old_jiffies = now; | ||
| 530 | |||
| 531 | /* Ensure we skip at least the 4 first duplicate events (generated | ||
| 532 | * by a single keypress), and continue skipping until repeat_delay | ||
| 533 | * msecs have passed | ||
| 534 | */ | ||
| 535 | if (ati_remote->repeat_count > 0 && | ||
| 536 | (ati_remote->repeat_count < 5 || | ||
| 537 | time_before(now, ati_remote->first_jiffies + | ||
| 538 | msecs_to_jiffies(repeat_delay)))) | ||
| 539 | return; | ||
| 540 | |||
| 541 | |||
| 542 | input_event(dev, ati_remote_tbl[index].type, | ||
| 543 | ati_remote_tbl[index].code, 1); | ||
| 544 | input_sync(dev); | ||
| 545 | input_event(dev, ati_remote_tbl[index].type, | ||
| 546 | ati_remote_tbl[index].code, 0); | ||
| 547 | input_sync(dev); | ||
| 548 | |||
| 549 | } else { | ||
| 550 | |||
| 551 | /* | ||
| 552 | * Other event kinds are from the directional control pad, and have an | ||
| 553 | * acceleration factor applied to them. Without this acceleration, the | ||
| 554 | * control pad is mostly unusable. | ||
| 555 | */ | ||
| 556 | acc = ati_remote_compute_accel(ati_remote); | ||
| 557 | |||
| 558 | switch (ati_remote_tbl[index].kind) { | ||
| 559 | case KIND_ACCEL: | ||
| 560 | input_event(dev, ati_remote_tbl[index].type, | ||
| 561 | ati_remote_tbl[index].code, | ||
| 562 | ati_remote_tbl[index].value * acc); | ||
| 563 | break; | ||
| 564 | case KIND_LU: | ||
| 565 | input_report_rel(dev, REL_X, -acc); | ||
| 566 | input_report_rel(dev, REL_Y, -acc); | ||
| 567 | break; | ||
| 568 | case KIND_RU: | ||
| 569 | input_report_rel(dev, REL_X, acc); | ||
| 570 | input_report_rel(dev, REL_Y, -acc); | ||
| 571 | break; | ||
| 572 | case KIND_LD: | ||
| 573 | input_report_rel(dev, REL_X, -acc); | ||
| 574 | input_report_rel(dev, REL_Y, acc); | ||
| 575 | break; | ||
| 576 | case KIND_RD: | ||
| 577 | input_report_rel(dev, REL_X, acc); | ||
| 578 | input_report_rel(dev, REL_Y, acc); | ||
| 579 | break; | ||
| 580 | default: | ||
| 581 | dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n", | ||
| 582 | ati_remote_tbl[index].kind); | ||
| 583 | } | ||
| 584 | input_sync(dev); | ||
| 585 | |||
| 586 | ati_remote->old_jiffies = jiffies; | ||
| 587 | ati_remote->old_data[0] = data[1]; | ||
| 588 | ati_remote->old_data[1] = data[2]; | ||
| 589 | } | ||
| 590 | } | ||
| 591 | |||
| 592 | /* | ||
| 593 | * ati_remote_irq_in | ||
| 594 | */ | ||
| 595 | static void ati_remote_irq_in(struct urb *urb) | ||
| 596 | { | ||
| 597 | struct ati_remote *ati_remote = urb->context; | ||
| 598 | int retval; | ||
| 599 | |||
| 600 | switch (urb->status) { | ||
| 601 | case 0: /* success */ | ||
| 602 | ati_remote_input_report(urb); | ||
| 603 | break; | ||
| 604 | case -ECONNRESET: /* unlink */ | ||
| 605 | case -ENOENT: | ||
| 606 | case -ESHUTDOWN: | ||
| 607 | dev_dbg(&ati_remote->interface->dev, "%s: urb error status, unlink? \n", | ||
| 608 | __func__); | ||
| 609 | return; | ||
| 610 | default: /* error */ | ||
| 611 | dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n", | ||
| 612 | __func__, urb->status); | ||
| 613 | } | ||
| 614 | |||
| 615 | retval = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 616 | if (retval) | ||
| 617 | dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n", | ||
| 618 | __func__, retval); | ||
| 619 | } | ||
| 620 | |||
| 621 | /* | ||
| 622 | * ati_remote_alloc_buffers | ||
| 623 | */ | ||
| 624 | static int ati_remote_alloc_buffers(struct usb_device *udev, | ||
| 625 | struct ati_remote *ati_remote) | ||
| 626 | { | ||
| 627 | ati_remote->inbuf = usb_alloc_coherent(udev, DATA_BUFSIZE, GFP_ATOMIC, | ||
| 628 | &ati_remote->inbuf_dma); | ||
| 629 | if (!ati_remote->inbuf) | ||
| 630 | return -1; | ||
| 631 | |||
| 632 | ati_remote->outbuf = usb_alloc_coherent(udev, DATA_BUFSIZE, GFP_ATOMIC, | ||
| 633 | &ati_remote->outbuf_dma); | ||
| 634 | if (!ati_remote->outbuf) | ||
| 635 | return -1; | ||
| 636 | |||
| 637 | ati_remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
| 638 | if (!ati_remote->irq_urb) | ||
| 639 | return -1; | ||
| 640 | |||
| 641 | ati_remote->out_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
| 642 | if (!ati_remote->out_urb) | ||
| 643 | return -1; | ||
| 644 | |||
| 645 | return 0; | ||
| 646 | } | ||
| 647 | |||
| 648 | /* | ||
| 649 | * ati_remote_free_buffers | ||
| 650 | */ | ||
| 651 | static void ati_remote_free_buffers(struct ati_remote *ati_remote) | ||
| 652 | { | ||
| 653 | usb_free_urb(ati_remote->irq_urb); | ||
| 654 | usb_free_urb(ati_remote->out_urb); | ||
| 655 | |||
| 656 | usb_free_coherent(ati_remote->udev, DATA_BUFSIZE, | ||
| 657 | ati_remote->inbuf, ati_remote->inbuf_dma); | ||
| 658 | |||
| 659 | usb_free_coherent(ati_remote->udev, DATA_BUFSIZE, | ||
| 660 | ati_remote->outbuf, ati_remote->outbuf_dma); | ||
| 661 | } | ||
| 662 | |||
| 663 | static void ati_remote_input_init(struct ati_remote *ati_remote) | ||
| 664 | { | ||
| 665 | struct input_dev *idev = ati_remote->idev; | ||
| 666 | int i; | ||
| 667 | |||
| 668 | idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); | ||
| 669 | idev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) | | ||
| 670 | BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA); | ||
| 671 | idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); | ||
| 672 | for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) | ||
| 673 | if (ati_remote_tbl[i].type == EV_KEY) | ||
| 674 | set_bit(ati_remote_tbl[i].code, idev->keybit); | ||
| 675 | |||
| 676 | input_set_drvdata(idev, ati_remote); | ||
| 677 | |||
| 678 | idev->open = ati_remote_open; | ||
| 679 | idev->close = ati_remote_close; | ||
| 680 | |||
| 681 | idev->name = ati_remote->name; | ||
| 682 | idev->phys = ati_remote->phys; | ||
| 683 | |||
| 684 | usb_to_input_id(ati_remote->udev, &idev->id); | ||
| 685 | idev->dev.parent = &ati_remote->udev->dev; | ||
| 686 | } | ||
| 687 | |||
| 688 | static int ati_remote_initialize(struct ati_remote *ati_remote) | ||
| 689 | { | ||
| 690 | struct usb_device *udev = ati_remote->udev; | ||
| 691 | int pipe, maxp; | ||
| 692 | |||
| 693 | init_waitqueue_head(&ati_remote->wait); | ||
| 694 | |||
| 695 | /* Set up irq_urb */ | ||
| 696 | pipe = usb_rcvintpipe(udev, ati_remote->endpoint_in->bEndpointAddress); | ||
| 697 | maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); | ||
| 698 | maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp; | ||
| 699 | |||
| 700 | usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf, | ||
| 701 | maxp, ati_remote_irq_in, ati_remote, | ||
| 702 | ati_remote->endpoint_in->bInterval); | ||
| 703 | ati_remote->irq_urb->transfer_dma = ati_remote->inbuf_dma; | ||
| 704 | ati_remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
| 705 | |||
| 706 | /* Set up out_urb */ | ||
| 707 | pipe = usb_sndintpipe(udev, ati_remote->endpoint_out->bEndpointAddress); | ||
| 708 | maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); | ||
| 709 | maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp; | ||
| 710 | |||
| 711 | usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf, | ||
| 712 | maxp, ati_remote_irq_out, ati_remote, | ||
| 713 | ati_remote->endpoint_out->bInterval); | ||
| 714 | ati_remote->out_urb->transfer_dma = ati_remote->outbuf_dma; | ||
| 715 | ati_remote->out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
| 716 | |||
| 717 | /* send initialization strings */ | ||
| 718 | if ((ati_remote_sendpacket(ati_remote, 0x8004, init1)) || | ||
| 719 | (ati_remote_sendpacket(ati_remote, 0x8007, init2))) { | ||
| 720 | dev_err(&ati_remote->interface->dev, | ||
| 721 | "Initializing ati_remote hardware failed.\n"); | ||
| 722 | return -EIO; | ||
| 723 | } | ||
| 724 | |||
| 725 | return 0; | ||
| 726 | } | ||
| 727 | |||
| 728 | /* | ||
| 729 | * ati_remote_probe | ||
| 730 | */ | ||
| 731 | static int ati_remote_probe(struct usb_interface *interface, const struct usb_device_id *id) | ||
| 732 | { | ||
| 733 | struct usb_device *udev = interface_to_usbdev(interface); | ||
| 734 | struct usb_host_interface *iface_host = interface->cur_altsetting; | ||
| 735 | struct usb_endpoint_descriptor *endpoint_in, *endpoint_out; | ||
| 736 | struct ati_remote *ati_remote; | ||
| 737 | struct input_dev *input_dev; | ||
| 738 | int err = -ENOMEM; | ||
| 739 | |||
| 740 | if (iface_host->desc.bNumEndpoints != 2) { | ||
| 741 | err("%s: Unexpected desc.bNumEndpoints\n", __func__); | ||
| 742 | return -ENODEV; | ||
| 743 | } | ||
| 744 | |||
| 745 | endpoint_in = &iface_host->endpoint[0].desc; | ||
| 746 | endpoint_out = &iface_host->endpoint[1].desc; | ||
| 747 | |||
| 748 | if (!usb_endpoint_is_int_in(endpoint_in)) { | ||
| 749 | err("%s: Unexpected endpoint_in\n", __func__); | ||
| 750 | return -ENODEV; | ||
| 751 | } | ||
| 752 | if (le16_to_cpu(endpoint_in->wMaxPacketSize) == 0) { | ||
| 753 | err("%s: endpoint_in message size==0? \n", __func__); | ||
| 754 | return -ENODEV; | ||
| 755 | } | ||
| 756 | |||
| 757 | ati_remote = kzalloc(sizeof (struct ati_remote), GFP_KERNEL); | ||
| 758 | input_dev = input_allocate_device(); | ||
| 759 | if (!ati_remote || !input_dev) | ||
| 760 | goto fail1; | ||
| 761 | |||
| 762 | /* Allocate URB buffers, URBs */ | ||
| 763 | if (ati_remote_alloc_buffers(udev, ati_remote)) | ||
| 764 | goto fail2; | ||
| 765 | |||
| 766 | ati_remote->endpoint_in = endpoint_in; | ||
| 767 | ati_remote->endpoint_out = endpoint_out; | ||
| 768 | ati_remote->udev = udev; | ||
| 769 | ati_remote->idev = input_dev; | ||
| 770 | ati_remote->interface = interface; | ||
| 771 | |||
| 772 | usb_make_path(udev, ati_remote->phys, sizeof(ati_remote->phys)); | ||
| 773 | strlcat(ati_remote->phys, "/input0", sizeof(ati_remote->phys)); | ||
| 774 | |||
| 775 | if (udev->manufacturer) | ||
| 776 | strlcpy(ati_remote->name, udev->manufacturer, sizeof(ati_remote->name)); | ||
| 777 | |||
| 778 | if (udev->product) | ||
| 779 | snprintf(ati_remote->name, sizeof(ati_remote->name), | ||
| 780 | "%s %s", ati_remote->name, udev->product); | ||
| 781 | |||
| 782 | if (!strlen(ati_remote->name)) | ||
| 783 | snprintf(ati_remote->name, sizeof(ati_remote->name), | ||
| 784 | DRIVER_DESC "(%04x,%04x)", | ||
| 785 | le16_to_cpu(ati_remote->udev->descriptor.idVendor), | ||
| 786 | le16_to_cpu(ati_remote->udev->descriptor.idProduct)); | ||
| 787 | |||
| 788 | ati_remote_input_init(ati_remote); | ||
| 789 | |||
| 790 | /* Device Hardware Initialization - fills in ati_remote->idev from udev. */ | ||
| 791 | err = ati_remote_initialize(ati_remote); | ||
| 792 | if (err) | ||
| 793 | goto fail3; | ||
| 794 | |||
| 795 | /* Set up and register input device */ | ||
| 796 | err = input_register_device(ati_remote->idev); | ||
| 797 | if (err) | ||
| 798 | goto fail3; | ||
| 799 | |||
| 800 | usb_set_intfdata(interface, ati_remote); | ||
| 801 | return 0; | ||
| 802 | |||
| 803 | fail3: usb_kill_urb(ati_remote->irq_urb); | ||
| 804 | usb_kill_urb(ati_remote->out_urb); | ||
| 805 | fail2: ati_remote_free_buffers(ati_remote); | ||
| 806 | fail1: input_free_device(input_dev); | ||
| 807 | kfree(ati_remote); | ||
| 808 | return err; | ||
| 809 | } | ||
| 810 | |||
| 811 | /* | ||
| 812 | * ati_remote_disconnect | ||
| 813 | */ | ||
| 814 | static void ati_remote_disconnect(struct usb_interface *interface) | ||
| 815 | { | ||
| 816 | struct ati_remote *ati_remote; | ||
| 817 | |||
| 818 | ati_remote = usb_get_intfdata(interface); | ||
| 819 | usb_set_intfdata(interface, NULL); | ||
| 820 | if (!ati_remote) { | ||
| 821 | dev_warn(&interface->dev, "%s - null device?\n", __func__); | ||
| 822 | return; | ||
| 823 | } | ||
| 824 | |||
| 825 | usb_kill_urb(ati_remote->irq_urb); | ||
| 826 | usb_kill_urb(ati_remote->out_urb); | ||
| 827 | input_unregister_device(ati_remote->idev); | ||
| 828 | ati_remote_free_buffers(ati_remote); | ||
| 829 | kfree(ati_remote); | ||
| 830 | } | ||
| 831 | |||
| 832 | /* | ||
| 833 | * ati_remote_init | ||
| 834 | */ | ||
| 835 | static int __init ati_remote_init(void) | ||
| 836 | { | ||
| 837 | int result; | ||
| 838 | |||
| 839 | result = usb_register(&ati_remote_driver); | ||
| 840 | if (result) | ||
| 841 | printk(KERN_ERR KBUILD_MODNAME | ||
| 842 | ": usb_register error #%d\n", result); | ||
| 843 | else | ||
| 844 | printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" | ||
| 845 | DRIVER_DESC "\n"); | ||
| 846 | |||
| 847 | return result; | ||
| 848 | } | ||
| 849 | |||
| 850 | /* | ||
| 851 | * ati_remote_exit | ||
| 852 | */ | ||
| 853 | static void __exit ati_remote_exit(void) | ||
| 854 | { | ||
| 855 | usb_deregister(&ati_remote_driver); | ||
| 856 | } | ||
| 857 | |||
| 858 | /* | ||
| 859 | * module specification | ||
| 860 | */ | ||
| 861 | |||
| 862 | module_init(ati_remote_init); | ||
| 863 | module_exit(ati_remote_exit); | ||
| 864 | |||
| 865 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
| 866 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 867 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/misc/cm3217.c b/drivers/input/misc/cm3217.c new file mode 100644 index 00000000000..9c9b60d6961 --- /dev/null +++ b/drivers/input/misc/cm3217.c | |||
| @@ -0,0 +1,1081 @@ | |||
| 1 | /* drivers/input/misc/cm3217.c - cm3217 optical sensors driver | ||
| 2 | * | ||
| 3 | * Copyright (C) 2011 Capella Microsystems Inc. | ||
| 4 | * Author: Frank Hsieh <pengyueh@gmail.com> | ||
| 5 | * | ||
| 6 | * This software is licensed under the terms of the GNU General Public | ||
| 7 | * License version 2, as published by the Free Software Foundation, and | ||
| 8 | * may be copied, distributed, and modified under those terms. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/delay.h> | ||
| 18 | #include <linux/earlysuspend.h> | ||
| 19 | #include <linux/i2c.h> | ||
| 20 | #include <linux/input.h> | ||
| 21 | #include <linux/interrupt.h> | ||
| 22 | #include <linux/module.h> | ||
| 23 | #include <linux/platform_device.h> | ||
| 24 | #include <linux/workqueue.h> | ||
| 25 | #include <linux/irq.h> | ||
| 26 | #include <linux/errno.h> | ||
| 27 | #include <linux/err.h> | ||
| 28 | #include <linux/gpio.h> | ||
| 29 | #include <linux/miscdevice.h> | ||
| 30 | #include <linux/lightsensor.h> | ||
| 31 | #include <linux/slab.h> | ||
| 32 | #include <linux/uaccess.h> | ||
| 33 | #include <linux/cm3217.h> | ||
| 34 | #include <linux/wakelock.h> | ||
| 35 | #include <linux/jiffies.h> | ||
| 36 | #include <asm/mach-types.h> | ||
| 37 | #include <asm/setup.h> | ||
| 38 | |||
| 39 | #define D(x...) pr_info(x) | ||
| 40 | |||
| 41 | #define I2C_RETRY_COUNT 10 | ||
| 42 | |||
| 43 | #define LS_POLLING_DELAY 500 | ||
| 44 | |||
| 45 | static void report_do_work(struct work_struct *w); | ||
| 46 | static DECLARE_DELAYED_WORK(report_work, report_do_work); | ||
| 47 | |||
| 48 | struct cm3217_info { | ||
| 49 | struct class *cm3217_class; | ||
| 50 | struct device *ls_dev; | ||
| 51 | struct input_dev *ls_input_dev; | ||
| 52 | |||
| 53 | struct early_suspend early_suspend; | ||
| 54 | struct i2c_client *i2c_client; | ||
| 55 | struct workqueue_struct *lp_wq; | ||
| 56 | |||
| 57 | int als_enable; | ||
| 58 | int als_enabled_before_suspend; | ||
| 59 | uint16_t *adc_table; | ||
| 60 | uint16_t cali_table[10]; | ||
| 61 | int irq; | ||
| 62 | int ls_calibrate; | ||
| 63 | int (*power) (int, uint8_t); /* power to the chip */ | ||
| 64 | |||
| 65 | uint32_t als_kadc; | ||
| 66 | uint32_t als_gadc; | ||
| 67 | uint16_t golden_adc; | ||
| 68 | |||
| 69 | int lightsensor_opened; | ||
| 70 | int current_level; | ||
| 71 | uint16_t current_adc; | ||
| 72 | int polling_delay; | ||
| 73 | }; | ||
| 74 | |||
| 75 | struct cm3217_info *lp_info; | ||
| 76 | |||
| 77 | int enable_log; | ||
| 78 | int fLevel = -1; | ||
| 79 | |||
| 80 | static struct mutex als_enable_mutex, als_disable_mutex, als_get_adc_mutex; | ||
| 81 | |||
| 82 | static int lightsensor_enable(struct cm3217_info *lpi); | ||
| 83 | static int lightsensor_disable(struct cm3217_info *lpi); | ||
| 84 | |||
| 85 | int32_t als_kadc; | ||
| 86 | |||
| 87 | static int I2C_RxData(uint16_t slaveAddr, uint8_t *rxData, int length) | ||
| 88 | { | ||
| 89 | uint8_t loop_i; | ||
| 90 | |||
| 91 | struct i2c_msg msgs[] = { | ||
| 92 | { | ||
| 93 | .addr = slaveAddr, | ||
| 94 | .flags = I2C_M_RD, | ||
| 95 | .len = length, | ||
| 96 | .buf = rxData, | ||
| 97 | }, | ||
| 98 | }; | ||
| 99 | |||
| 100 | for (loop_i = 0; loop_i < I2C_RETRY_COUNT; loop_i++) { | ||
| 101 | if (i2c_transfer(lp_info->i2c_client->adapter, msgs, 1) > 0) | ||
| 102 | break; | ||
| 103 | msleep(10); | ||
| 104 | } | ||
| 105 | |||
| 106 | if (loop_i >= I2C_RETRY_COUNT) { | ||
| 107 | printk(KERN_ERR "[ERR][CM3217 error] %s retry over %d\n", | ||
| 108 | __func__, I2C_RETRY_COUNT); | ||
| 109 | return -EIO; | ||
| 110 | } | ||
| 111 | |||
| 112 | return 0; | ||
| 113 | } | ||
| 114 | |||
| 115 | static int I2C_TxData(uint16_t slaveAddr, uint8_t *txData, int length) | ||
| 116 | { | ||
| 117 | uint8_t loop_i; | ||
| 118 | |||
| 119 | struct i2c_msg msg[] = { | ||
| 120 | { | ||
| 121 | .addr = slaveAddr, | ||
| 122 | .flags = 0, | ||
| 123 | .len = length, | ||
| 124 | .buf = txData, | ||
| 125 | }, | ||
| 126 | }; | ||
| 127 | |||
| 128 | for (loop_i = 0; loop_i < I2C_RETRY_COUNT; loop_i++) { | ||
| 129 | if (i2c_transfer(lp_info->i2c_client->adapter, msg, 1) > 0) | ||
| 130 | break; | ||
| 131 | msleep(10); | ||
| 132 | } | ||
| 133 | |||
| 134 | if (loop_i >= I2C_RETRY_COUNT) { | ||
| 135 | printk(KERN_ERR "[ERR][CM3217 error] %s retry over %d\n", | ||
| 136 | __func__, I2C_RETRY_COUNT); | ||
| 137 | return -EIO; | ||
| 138 | } | ||
| 139 | |||
| 140 | return 0; | ||
| 141 | } | ||
| 142 | |||
| 143 | static int _cm3217_I2C_Read_Byte(uint16_t slaveAddr, uint8_t *pdata) | ||
| 144 | { | ||
| 145 | uint8_t buffer = 0; | ||
| 146 | int ret = 0; | ||
| 147 | |||
| 148 | if (pdata == NULL) | ||
| 149 | return -EFAULT; | ||
| 150 | |||
| 151 | ret = I2C_RxData(slaveAddr, &buffer, 1); | ||
| 152 | if (ret < 0) { | ||
| 153 | pr_err("[ERR][CM3217 error]%s: I2C_RxData fail, slave addr: 0x%x\n", | ||
| 154 | __func__, slaveAddr); | ||
| 155 | return ret; | ||
| 156 | } | ||
| 157 | |||
| 158 | *pdata = buffer; | ||
| 159 | |||
| 160 | #if 0 | ||
| 161 | /* Debug use */ | ||
| 162 | printk(KERN_DEBUG "[CM3217] %s: I2C_RxData[0x%x] = 0x%x\n", | ||
| 163 | __func__, slaveAddr, buffer); | ||
| 164 | #endif | ||
| 165 | |||
| 166 | return ret; | ||
| 167 | } | ||
| 168 | |||
| 169 | static int _cm3217_I2C_Write_Byte(uint16_t SlaveAddress, uint8_t data) | ||
| 170 | { | ||
| 171 | char buffer[2]; | ||
| 172 | int ret = 0; | ||
| 173 | |||
| 174 | #if 0 | ||
| 175 | /* Debug use */ | ||
| 176 | printk(KERN_DEBUG | ||
| 177 | "[CM3217] %s: _cm3217_I2C_Write_Byte[0x%x, 0x%x, 0x%x]\n", | ||
| 178 | __func__, SlaveAddress, cmd, data); | ||
| 179 | #endif | ||
| 180 | |||
| 181 | buffer[0] = data; | ||
| 182 | |||
| 183 | ret = I2C_TxData(SlaveAddress, buffer, 1); | ||
| 184 | if (ret < 0) { | ||
| 185 | pr_err("[ERR][CM3217 error]%s: I2C_TxData fail\n", __func__); | ||
| 186 | return -EIO; | ||
| 187 | } | ||
| 188 | |||
| 189 | return ret; | ||
| 190 | } | ||
| 191 | |||
| 192 | static int get_ls_adc_value(uint16_t *als_step, bool resume) | ||
| 193 | { | ||
| 194 | uint8_t lsb, msb; | ||
| 195 | int ret = 0; | ||
| 196 | struct cm3217_info *lpi = lp_info; | ||
| 197 | |||
| 198 | if (als_step == NULL) | ||
| 199 | return -EFAULT; | ||
| 200 | |||
| 201 | /* Read ALS data: LSB */ | ||
| 202 | ret = _cm3217_I2C_Read_Byte(ALS_R_LSB_addr, &lsb); | ||
| 203 | if (ret < 0) { | ||
| 204 | pr_err("[LS][CM3217 error]%s: _cm3217_I2C_Read_Byte LSB fail\n", | ||
| 205 | __func__); | ||
| 206 | return -EIO; | ||
| 207 | } | ||
| 208 | |||
| 209 | /* Read ALS data: MSB */ | ||
| 210 | ret = _cm3217_I2C_Read_Byte(ALS_R_MSB_addr, &msb); | ||
| 211 | if (ret < 0) { | ||
| 212 | pr_err("[LS][CM3217 error]%s: _cm3217_I2C_Read_Byte MSB fail\n", | ||
| 213 | __func__); | ||
| 214 | return -EIO; | ||
| 215 | } | ||
| 216 | |||
| 217 | *als_step = (uint16_t) msb; | ||
| 218 | *als_step <<= 8; | ||
| 219 | *als_step |= (uint16_t) lsb; | ||
| 220 | |||
| 221 | D("[LS][CM3217] %s: raw adc = 0x%X\n", __func__, *als_step); | ||
| 222 | |||
| 223 | if (!lpi->ls_calibrate) { | ||
| 224 | *als_step = (*als_step) * lpi->als_gadc / lpi->als_kadc; | ||
| 225 | if (*als_step > 0xFFFF) | ||
| 226 | *als_step = 0xFFFF; | ||
| 227 | } | ||
| 228 | |||
| 229 | return ret; | ||
| 230 | } | ||
| 231 | |||
| 232 | static void report_lsensor_input_event(struct cm3217_info *lpi, bool resume) | ||
| 233 | { | ||
| 234 | uint16_t adc_value = 0; | ||
| 235 | int level = 0, i, ret = 0; | ||
| 236 | |||
| 237 | mutex_lock(&als_get_adc_mutex); | ||
| 238 | |||
| 239 | ret = get_ls_adc_value(&adc_value, resume); | ||
| 240 | |||
| 241 | if (lpi->ls_calibrate) { | ||
| 242 | for (i = 0; i < 10; i++) { | ||
| 243 | if (adc_value <= (*(lpi->cali_table + i))) { | ||
| 244 | level = i; | ||
| 245 | if (*(lpi->cali_table + i)) | ||
| 246 | break; | ||
| 247 | } | ||
| 248 | /* avoid i = 10, because 'cali_table' of size is 10 */ | ||
| 249 | if (i == 9) { | ||
| 250 | level = i; | ||
| 251 | break; | ||
| 252 | } | ||
| 253 | } | ||
| 254 | } else { | ||
| 255 | for (i = 0; i < 10; i++) { | ||
| 256 | if (adc_value <= (*(lpi->adc_table + i))) { | ||
| 257 | level = i; | ||
| 258 | if (*(lpi->adc_table + i)) | ||
| 259 | break; | ||
| 260 | } | ||
| 261 | /* avoid i = 10, because 'cali_table' of size is 10 */ | ||
| 262 | if (i == 9) { | ||
| 263 | level = i; | ||
| 264 | break; | ||
| 265 | } | ||
| 266 | } | ||
| 267 | } | ||
| 268 | |||
| 269 | if ((i == 0) || (adc_value == 0)) | ||
| 270 | D("[LS][CM3217] %s: ADC=0x%03X, Level=%d, l_thd equal 0, " | ||
| 271 | "h_thd = 0x%x\n", __func__, adc_value, level, | ||
| 272 | *(lpi->cali_table + i)); | ||
| 273 | else | ||
| 274 | D("[LS][CM3217] %s: ADC=0x%03X, Level=%d, l_thd = 0x%x, " | ||
| 275 | "h_thd = 0x%x\n", __func__, adc_value, level, | ||
| 276 | *(lpi->cali_table + (i - 1)) + 1, *(lpi->cali_table + i)); | ||
| 277 | |||
| 278 | lpi->current_level = level; | ||
| 279 | lpi->current_adc = adc_value; | ||
| 280 | |||
| 281 | /* | ||
| 282 | D("[CM3217] %s: *(lpi->cali_table + (i - 1)) + 1 = 0x%X, " | ||
| 283 | "*(lpi->cali_table + i) = 0x%x\n", __func__, | ||
| 284 | *(lpi->cali_table + (i - 1)) + 1, *(lpi->cali_table + i)); | ||
| 285 | */ | ||
| 286 | |||
| 287 | if (fLevel >= 0) { | ||
| 288 | D("[LS][CM3217] L-sensor force level enable level=%d " | ||
| 289 | "fLevel=%d\n", level, fLevel); | ||
| 290 | level = fLevel; | ||
| 291 | } | ||
| 292 | |||
| 293 | input_report_abs(lpi->ls_input_dev, ABS_MISC, level); | ||
| 294 | input_sync(lpi->ls_input_dev); | ||
| 295 | |||
| 296 | mutex_unlock(&als_get_adc_mutex); | ||
| 297 | } | ||
| 298 | |||
| 299 | static void report_do_work(struct work_struct *work) | ||
| 300 | { | ||
| 301 | struct cm3217_info *lpi = lp_info; | ||
| 302 | |||
| 303 | if (enable_log) | ||
| 304 | D("[CM3217] %s\n", __func__); | ||
| 305 | |||
| 306 | report_lsensor_input_event(lpi, 0); | ||
| 307 | |||
| 308 | queue_delayed_work(lpi->lp_wq, &report_work, lpi->polling_delay); | ||
| 309 | } | ||
| 310 | |||
| 311 | static int als_power(int enable) | ||
| 312 | { | ||
| 313 | struct cm3217_info *lpi = lp_info; | ||
| 314 | |||
| 315 | if (lpi->power) | ||
| 316 | lpi->power(LS_PWR_ON, 1); | ||
| 317 | |||
| 318 | return 0; | ||
| 319 | } | ||
| 320 | |||
| 321 | void lightsensor_set_kvalue(struct cm3217_info *lpi) | ||
| 322 | { | ||
| 323 | if (!lpi) { | ||
| 324 | pr_err("[LS][CM3217 error]%s: ls_info is empty\n", __func__); | ||
| 325 | return; | ||
| 326 | } | ||
| 327 | |||
| 328 | D("[LS][CM3217] %s: ALS calibrated als_kadc=0x%x\n", | ||
| 329 | __func__, als_kadc); | ||
| 330 | |||
| 331 | if (als_kadc >> 16 == ALS_CALIBRATED) | ||
| 332 | lpi->als_kadc = als_kadc & 0xFFFF; | ||
| 333 | else { | ||
| 334 | lpi->als_kadc = 0; | ||
| 335 | D("[LS][CM3217] %s: no ALS calibrated\n", __func__); | ||
| 336 | } | ||
| 337 | |||
| 338 | if (lpi->als_kadc && lpi->golden_adc > 0) { | ||
| 339 | lpi->als_kadc = (lpi->als_kadc > 0 && lpi->als_kadc < 0x1000) ? | ||
| 340 | lpi->als_kadc : lpi->golden_adc; | ||
| 341 | lpi->als_gadc = lpi->golden_adc; | ||
| 342 | } else { | ||
| 343 | lpi->als_kadc = 1; | ||
| 344 | lpi->als_gadc = 1; | ||
| 345 | } | ||
| 346 | |||
| 347 | D("[LS][CM3217] %s: als_kadc=0x%x, als_gadc=0x%x\n", | ||
| 348 | __func__, lpi->als_kadc, lpi->als_gadc); | ||
| 349 | } | ||
| 350 | |||
| 351 | static int lightsensor_update_table(struct cm3217_info *lpi) | ||
| 352 | { | ||
| 353 | uint32_t tmpData[10]; | ||
| 354 | int i; | ||
| 355 | |||
| 356 | for (i = 0; i < 10; i++) { | ||
| 357 | tmpData[i] = (uint32_t) (*(lpi->adc_table + i)) | ||
| 358 | * lpi->als_kadc / lpi->als_gadc; | ||
| 359 | if (tmpData[i] <= 0xFFFF) | ||
| 360 | lpi->cali_table[i] = (uint16_t) tmpData[i]; | ||
| 361 | else | ||
| 362 | lpi->cali_table[i] = 0xFFFF; | ||
| 363 | D("[LS][CM3217] %s: Calibrated adc_table: data[%d], %x\n", | ||
| 364 | __func__, i, lpi->cali_table[i]); | ||
| 365 | } | ||
| 366 | |||
| 367 | return 0; | ||
| 368 | } | ||
| 369 | |||
| 370 | static int lightsensor_enable(struct cm3217_info *lpi) | ||
| 371 | { | ||
| 372 | int ret = 0; | ||
| 373 | uint8_t cmd = 0; | ||
| 374 | |||
| 375 | mutex_lock(&als_enable_mutex); | ||
| 376 | |||
| 377 | D("[LS][CM3217] %s\n", __func__); | ||
| 378 | |||
| 379 | cmd = (CM3217_ALS_IT_2_T | CM3217_ALS_BIT5_Default_1 | | ||
| 380 | CM3217_ALS_WDM_DEFAULT_1); | ||
| 381 | ret = _cm3217_I2C_Write_Byte(ALS_W_CMD1_addr, cmd); | ||
| 382 | if (ret < 0) | ||
| 383 | pr_err("[LS][CM3217 error]%s: set auto light sensor fail\n", | ||
| 384 | __func__); | ||
| 385 | else { | ||
| 386 | msleep(50); /* wait for 50 ms for the first report adc */ | ||
| 387 | |||
| 388 | /* report an invalid value first to ensure we | ||
| 389 | * trigger an event when adc_level is zero. | ||
| 390 | */ | ||
| 391 | input_report_abs(lpi->ls_input_dev, ABS_MISC, -1); | ||
| 392 | input_sync(lpi->ls_input_dev); | ||
| 393 | /* resume, IOCTL and DEVICE_ATTR */ | ||
| 394 | report_lsensor_input_event(lpi, 1); | ||
| 395 | lpi->als_enable = 1; | ||
| 396 | } | ||
| 397 | |||
| 398 | queue_delayed_work(lpi->lp_wq, &report_work, lpi->polling_delay); | ||
| 399 | lpi->als_enable = 1; | ||
| 400 | |||
| 401 | mutex_unlock(&als_enable_mutex); | ||
| 402 | |||
| 403 | return ret; | ||
| 404 | } | ||
| 405 | |||
| 406 | static int lightsensor_disable(struct cm3217_info *lpi) | ||
| 407 | { | ||
| 408 | int ret = 0; | ||
| 409 | char cmd = 0; | ||
| 410 | |||
| 411 | mutex_lock(&als_disable_mutex); | ||
| 412 | |||
| 413 | D("[LS][CM3217] %s\n", __func__); | ||
| 414 | |||
| 415 | cmd = (CM3217_ALS_IT_2_T | CM3217_ALS_BIT5_Default_1 | | ||
| 416 | CM3217_ALS_WDM_DEFAULT_1 | CM3217_ALS_SD); | ||
| 417 | ret = _cm3217_I2C_Write_Byte(ALS_W_CMD1_addr, cmd); | ||
| 418 | if (ret < 0) | ||
| 419 | pr_err("[LS][CM3217 error]%s: disable auto light sensor fail\n", | ||
| 420 | __func__); | ||
| 421 | else { | ||
| 422 | lpi->als_enable = 0; | ||
| 423 | } | ||
| 424 | |||
| 425 | cancel_delayed_work(&report_work); | ||
| 426 | lpi->als_enable = 0; | ||
| 427 | |||
| 428 | mutex_unlock(&als_disable_mutex); | ||
| 429 | |||
| 430 | return ret; | ||
| 431 | } | ||
| 432 | |||
| 433 | static int lightsensor_open(struct inode *inode, struct file *file) | ||
| 434 | { | ||
| 435 | struct cm3217_info *lpi = lp_info; | ||
| 436 | int rc = 0; | ||
| 437 | |||
| 438 | D("[LS][CM3217] %s\n", __func__); | ||
| 439 | if (lpi->lightsensor_opened) { | ||
| 440 | pr_err("[LS][CM3217 error]%s: already opened\n", __func__); | ||
| 441 | rc = -EBUSY; | ||
| 442 | } | ||
| 443 | lpi->lightsensor_opened = 1; | ||
| 444 | |||
| 445 | return rc; | ||
| 446 | } | ||
| 447 | |||
| 448 | static int lightsensor_release(struct inode *inode, struct file *file) | ||
| 449 | { | ||
| 450 | struct cm3217_info *lpi = lp_info; | ||
| 451 | |||
| 452 | D("[LS][CM3217] %s\n", __func__); | ||
| 453 | lpi->lightsensor_opened = 0; | ||
| 454 | |||
| 455 | return 0; | ||
| 456 | } | ||
| 457 | |||
| 458 | static long lightsensor_ioctl(struct file *file, unsigned int cmd, | ||
| 459 | unsigned long arg) | ||
| 460 | { | ||
| 461 | int rc, val; | ||
| 462 | struct cm3217_info *lpi = lp_info; | ||
| 463 | |||
| 464 | /* D("[CM3217] %s cmd %d\n", __func__, _IOC_NR(cmd)); */ | ||
| 465 | |||
| 466 | switch (cmd) { | ||
| 467 | case LIGHTSENSOR_IOCTL_ENABLE: | ||
| 468 | if (get_user(val, (unsigned long __user *)arg)) { | ||
| 469 | rc = -EFAULT; | ||
| 470 | break; | ||
| 471 | } | ||
| 472 | D("[LS][CM3217] %s LIGHTSENSOR_IOCTL_ENABLE, value = %d\n", | ||
| 473 | __func__, val); | ||
| 474 | rc = val ? lightsensor_enable(lpi) : lightsensor_disable(lpi); | ||
| 475 | break; | ||
| 476 | |||
| 477 | case LIGHTSENSOR_IOCTL_GET_ENABLED: | ||
| 478 | val = lpi->als_enable; | ||
| 479 | D("[LS][CM3217] %s LIGHTSENSOR_IOCTL_GET_ENABLED, enabled %d\n", | ||
| 480 | __func__, val); | ||
| 481 | rc = put_user(val, (unsigned long __user *)arg); | ||
| 482 | break; | ||
| 483 | |||
| 484 | default: | ||
| 485 | pr_err("[LS][CM3217 error]%s: invalid cmd %d\n", | ||
| 486 | __func__, _IOC_NR(cmd)); | ||
| 487 | rc = -EINVAL; | ||
| 488 | } | ||
| 489 | |||
| 490 | return rc; | ||
| 491 | } | ||
| 492 | |||
| 493 | static const struct file_operations lightsensor_fops = { | ||
| 494 | .owner = THIS_MODULE, | ||
| 495 | .open = lightsensor_open, | ||
| 496 | .release = lightsensor_release, | ||
| 497 | .unlocked_ioctl = lightsensor_ioctl | ||
| 498 | }; | ||
| 499 | |||
| 500 | static struct miscdevice lightsensor_misc = { | ||
| 501 | .minor = MISC_DYNAMIC_MINOR, | ||
| 502 | .name = "lightsensor", | ||
| 503 | .fops = &lightsensor_fops | ||
| 504 | }; | ||
| 505 | |||
| 506 | static ssize_t ls_adc_show(struct device *dev, | ||
| 507 | struct device_attribute *attr, char *buf) | ||
| 508 | { | ||
| 509 | int ret; | ||
| 510 | struct cm3217_info *lpi = lp_info; | ||
| 511 | |||
| 512 | D("[LS][CM3217] %s: ADC = 0x%04X, Level = %d\n", | ||
| 513 | __func__, lpi->current_adc, lpi->current_level); | ||
| 514 | |||
| 515 | ret = sprintf(buf, "ADC[0x%04X] => level %d\n", | ||
| 516 | lpi->current_adc, lpi->current_level); | ||
| 517 | |||
| 518 | return ret; | ||
| 519 | } | ||
| 520 | |||
| 521 | static DEVICE_ATTR(ls_adc, 0664, ls_adc_show, NULL); | ||
| 522 | |||
| 523 | static ssize_t ls_enable_show(struct device *dev, | ||
| 524 | struct device_attribute *attr, char *buf) | ||
| 525 | { | ||
| 526 | int ret = 0; | ||
| 527 | struct cm3217_info *lpi = lp_info; | ||
| 528 | |||
| 529 | ret = sprintf(buf, "Light sensor Auto Enable = %d\n", lpi->als_enable); | ||
| 530 | |||
| 531 | return ret; | ||
| 532 | } | ||
| 533 | |||
| 534 | static ssize_t ls_enable_store(struct device *dev, | ||
| 535 | struct device_attribute *attr, | ||
| 536 | const char *buf, size_t count) | ||
| 537 | { | ||
| 538 | int ret = 0; | ||
| 539 | int ls_auto; | ||
| 540 | struct cm3217_info *lpi = lp_info; | ||
| 541 | |||
| 542 | ls_auto = -1; | ||
| 543 | sscanf(buf, "%d", &ls_auto); | ||
| 544 | |||
| 545 | if (ls_auto != 0 && ls_auto != 1) | ||
| 546 | return -EINVAL; | ||
| 547 | |||
| 548 | if (ls_auto) | ||
| 549 | ret = lightsensor_enable(lpi); | ||
| 550 | else | ||
| 551 | ret = lightsensor_disable(lpi); | ||
| 552 | |||
| 553 | D("[LS][CM3217] %s: lpi->als_enable = %d, lpi->ls_calibrate = %d, " | ||
| 554 | "ls_auto=%d\n", __func__, lpi->als_enable, lpi->ls_calibrate, | ||
| 555 | ls_auto); | ||
| 556 | |||
| 557 | if (ret < 0) | ||
| 558 | pr_err("[LS][CM3217 error]%s: set auto light sensor fail\n", | ||
| 559 | __func__); | ||
| 560 | |||
| 561 | return count; | ||
| 562 | } | ||
| 563 | |||
| 564 | static DEVICE_ATTR(ls_auto, 0664, ls_enable_show, ls_enable_store); | ||
| 565 | |||
| 566 | static ssize_t ls_kadc_show(struct device *dev, | ||
| 567 | struct device_attribute *attr, char *buf) | ||
| 568 | { | ||
| 569 | struct cm3217_info *lpi = lp_info; | ||
| 570 | int ret; | ||
| 571 | |||
| 572 | ret = sprintf(buf, "kadc = 0x%x", lpi->als_kadc); | ||
| 573 | |||
| 574 | return ret; | ||
| 575 | } | ||
| 576 | |||
| 577 | static ssize_t ls_kadc_store(struct device *dev, | ||
| 578 | struct device_attribute *attr, | ||
| 579 | const char *buf, size_t count) | ||
| 580 | { | ||
| 581 | struct cm3217_info *lpi = lp_info; | ||
| 582 | int kadc_temp = 0; | ||
| 583 | |||
| 584 | sscanf(buf, "%d", &kadc_temp); | ||
| 585 | |||
| 586 | /* if (kadc_temp <= 0 || lpi->golden_adc <= 0) { | ||
| 587 | printk(KERN_ERR "[LS][CM3217 error] %s: kadc_temp=0x%x, " | ||
| 588 | "als_gadc=0x%x\n", __func__, kadc_temp, | ||
| 589 | lpi->golden_adc); | ||
| 590 | return -EINVAL; | ||
| 591 | } */ | ||
| 592 | |||
| 593 | mutex_lock(&als_get_adc_mutex); | ||
| 594 | |||
| 595 | if (kadc_temp != 0) { | ||
| 596 | lpi->als_kadc = kadc_temp; | ||
| 597 | if (lpi->als_gadc != 0) { | ||
| 598 | if (lightsensor_update_table(lpi) < 0) | ||
| 599 | printk(KERN_ERR | ||
| 600 | "[LS][CM3217 error] %s: " | ||
| 601 | "update ls table fail\n", __func__); | ||
| 602 | } else { | ||
| 603 | printk(KERN_INFO | ||
| 604 | "[LS]%s: als_gadc =0x%x wait to be set\n", | ||
| 605 | __func__, lpi->als_gadc); | ||
| 606 | } | ||
| 607 | } else { | ||
| 608 | printk(KERN_INFO "[LS]%s: als_kadc can't be set to zero\n", | ||
| 609 | __func__); | ||
| 610 | } | ||
| 611 | |||
| 612 | mutex_unlock(&als_get_adc_mutex); | ||
| 613 | |||
| 614 | return count; | ||
| 615 | } | ||
| 616 | |||
| 617 | static DEVICE_ATTR(ls_kadc, 0664, ls_kadc_show, ls_kadc_store); | ||
| 618 | |||
| 619 | static ssize_t ls_gadc_show(struct device *dev, | ||
| 620 | struct device_attribute *attr, char *buf) | ||
| 621 | { | ||
| 622 | struct cm3217_info *lpi = lp_info; | ||
| 623 | int ret; | ||
| 624 | |||
| 625 | ret = sprintf(buf, "gadc = 0x%x\n", lpi->als_gadc); | ||
| 626 | |||
| 627 | return ret; | ||
| 628 | } | ||
| 629 | |||
| 630 | static ssize_t ls_gadc_store(struct device *dev, | ||
| 631 | struct device_attribute *attr, | ||
| 632 | const char *buf, size_t count) | ||
| 633 | { | ||
| 634 | struct cm3217_info *lpi = lp_info; | ||
| 635 | int gadc_temp = 0; | ||
| 636 | |||
| 637 | sscanf(buf, "%d", &gadc_temp); | ||
| 638 | |||
| 639 | /* if (gadc_temp <= 0 || lpi->golden_adc <= 0) { | ||
| 640 | printk(KERN_ERR "[LS][CM3217 error] %s: kadc_temp=0x%x, " | ||
| 641 | "als_gadc=0x%x\n", __func__, kadc_temp, | ||
| 642 | lpi->golden_adc); | ||
| 643 | return -EINVAL; | ||
| 644 | } */ | ||
| 645 | |||
| 646 | mutex_lock(&als_get_adc_mutex); | ||
| 647 | |||
| 648 | if (gadc_temp != 0) { | ||
| 649 | lpi->als_gadc = gadc_temp; | ||
| 650 | if (lpi->als_kadc != 0) { | ||
| 651 | if (lightsensor_update_table(lpi) < 0) | ||
| 652 | printk(KERN_ERR | ||
| 653 | "[LS][CM3217 error] %s: " | ||
| 654 | "update ls table fail\n", __func__); | ||
| 655 | } else { | ||
| 656 | printk(KERN_INFO | ||
| 657 | "[LS]%s: als_kadc =0x%x wait to be set\n", | ||
| 658 | __func__, lpi->als_kadc); | ||
| 659 | } | ||
| 660 | } else { | ||
| 661 | printk(KERN_INFO "[LS]%s: als_gadc can't be set to zero\n", | ||
| 662 | __func__); | ||
| 663 | } | ||
| 664 | |||
| 665 | mutex_unlock(&als_get_adc_mutex); | ||
| 666 | |||
| 667 | return count; | ||
| 668 | } | ||
| 669 | |||
| 670 | static DEVICE_ATTR(ls_gadc, 0664, ls_gadc_show, ls_gadc_store); | ||
| 671 | |||
| 672 | static ssize_t ls_adc_table_show(struct device *dev, | ||
| 673 | struct device_attribute *attr, char *buf) | ||
| 674 | { | ||
| 675 | unsigned length = 0; | ||
| 676 | int i; | ||
| 677 | |||
| 678 | for (i = 0; i < 10; i++) { | ||
| 679 | length += sprintf(buf + length, | ||
| 680 | "[CM3217]Get adc_table[%d] = 0x%x ; %d, " | ||
| 681 | "Get cali_table[%d] = 0x%x ; %d,\n", | ||
| 682 | i, *(lp_info->adc_table + i), | ||
| 683 | *(lp_info->adc_table + i), | ||
| 684 | i, *(lp_info->cali_table + i), | ||
| 685 | *(lp_info->cali_table + i)); | ||
| 686 | } | ||
| 687 | |||
| 688 | return length; | ||
| 689 | } | ||
| 690 | |||
| 691 | static ssize_t ls_adc_table_store(struct device *dev, | ||
| 692 | struct device_attribute *attr, | ||
| 693 | const char *buf, size_t count) | ||
| 694 | { | ||
| 695 | struct cm3217_info *lpi = lp_info; | ||
| 696 | char *token[10]; | ||
| 697 | unsigned long tempdata[10]; | ||
| 698 | int i, r; | ||
| 699 | |||
| 700 | printk(KERN_INFO "[LS][CM3217]%s\n", buf); | ||
| 701 | for (i = 0; i < 10; i++) { | ||
| 702 | token[i] = strsep((char **)&buf, " "); | ||
| 703 | r = kstrtoul(token[i], 16, &tempdata[i]); | ||
| 704 | if (tempdata[i] < 1 || tempdata[i] > 0xffff || r) { | ||
| 705 | printk(KERN_ERR | ||
| 706 | "[LS][CM3217 error] adc_table[%d] = " | ||
| 707 | "0x%lx Err\n", i, tempdata[i]); | ||
| 708 | return count; | ||
| 709 | } | ||
| 710 | } | ||
| 711 | |||
| 712 | mutex_lock(&als_get_adc_mutex); | ||
| 713 | |||
| 714 | for (i = 0; i < 10; i++) { | ||
| 715 | lpi->adc_table[i] = tempdata[i]; | ||
| 716 | printk(KERN_INFO | ||
| 717 | "[LS][CM3217]Set lpi->adc_table[%d] = 0x%x\n", | ||
| 718 | i, *(lp_info->adc_table + i)); | ||
| 719 | } | ||
| 720 | if (lightsensor_update_table(lpi) < 0) | ||
| 721 | printk(KERN_ERR "[LS][CM3217 error] %s: update ls table fail\n", | ||
| 722 | __func__); | ||
| 723 | |||
| 724 | mutex_unlock(&als_get_adc_mutex); | ||
| 725 | |||
| 726 | D("[LS][CM3217] %s\n", __func__); | ||
| 727 | |||
| 728 | return count; | ||
| 729 | } | ||
| 730 | |||
| 731 | static DEVICE_ATTR(ls_adc_table, 0664, ls_adc_table_show, ls_adc_table_store); | ||
| 732 | |||
| 733 | static uint8_t ALS_CONF1; | ||
| 734 | |||
| 735 | static ssize_t ls_conf1_show(struct device *dev, | ||
| 736 | struct device_attribute *attr, char *buf) | ||
| 737 | { | ||
| 738 | return sprintf(buf, "ALS_CONF1 = %x\n", ALS_CONF1); | ||
| 739 | } | ||
| 740 | |||
| 741 | static ssize_t ls_conf1_store(struct device *dev, | ||
| 742 | struct device_attribute *attr, | ||
| 743 | const char *buf, size_t count) | ||
| 744 | { | ||
| 745 | int value = 0; | ||
| 746 | |||
| 747 | sscanf(buf, "0x%x", &value); | ||
| 748 | |||
| 749 | ALS_CONF1 = value; | ||
| 750 | printk(KERN_INFO "[LS]set ALS_CONF1 = %x\n", ALS_CONF1); | ||
| 751 | _cm3217_I2C_Write_Byte(ALS_W_CMD1_addr, ALS_CONF1); | ||
| 752 | |||
| 753 | return count; | ||
| 754 | } | ||
| 755 | |||
| 756 | static DEVICE_ATTR(ls_conf1, 0664, ls_conf1_show, ls_conf1_store); | ||
| 757 | |||
| 758 | static uint8_t ALS_CONF2; | ||
| 759 | static ssize_t ls_conf2_show(struct device *dev, | ||
| 760 | struct device_attribute *attr, char *buf) | ||
| 761 | { | ||
| 762 | return sprintf(buf, "ALS_CONF2 = %x\n", ALS_CONF2); | ||
| 763 | } | ||
| 764 | |||
| 765 | static ssize_t ls_conf2_store(struct device *dev, | ||
| 766 | struct device_attribute *attr, | ||
| 767 | const char *buf, size_t count) | ||
| 768 | { | ||
| 769 | int value = 0; | ||
| 770 | |||
| 771 | sscanf(buf, "0x%x", &value); | ||
| 772 | |||
| 773 | ALS_CONF2 = value; | ||
| 774 | printk(KERN_INFO "[LS]set ALS_CONF2 = %x\n", ALS_CONF2); | ||
| 775 | _cm3217_I2C_Write_Byte(ALS_W_CMD2_addr, ALS_CONF2); | ||
| 776 | |||
| 777 | return count; | ||
| 778 | } | ||
| 779 | |||
| 780 | static DEVICE_ATTR(ls_conf2, 0664, ls_conf2_show, ls_conf2_store); | ||
| 781 | |||
| 782 | static ssize_t ls_fLevel_show(struct device *dev, | ||
| 783 | struct device_attribute *attr, char *buf) | ||
| 784 | { | ||
| 785 | return sprintf(buf, "fLevel = %d\n", fLevel); | ||
| 786 | } | ||
| 787 | |||
| 788 | static ssize_t ls_fLevel_store(struct device *dev, | ||
| 789 | struct device_attribute *attr, | ||
| 790 | const char *buf, size_t count) | ||
| 791 | { | ||
| 792 | struct cm3217_info *lpi = lp_info; | ||
| 793 | int value = 0; | ||
| 794 | |||
| 795 | sscanf(buf, "%d", &value); | ||
| 796 | (value >= 0) ? (value = min(value, 10)) : (value = max(value, -1)); | ||
| 797 | fLevel = value; | ||
| 798 | |||
| 799 | input_report_abs(lpi->ls_input_dev, ABS_MISC, fLevel); | ||
| 800 | input_sync(lpi->ls_input_dev); | ||
| 801 | |||
| 802 | printk(KERN_INFO "[LS]set fLevel = %d\n", fLevel); | ||
| 803 | |||
| 804 | msleep(1000); | ||
| 805 | fLevel = -1; | ||
| 806 | |||
| 807 | return count; | ||
| 808 | } | ||
| 809 | |||
| 810 | static DEVICE_ATTR(ls_flevel, 0664, ls_fLevel_show, ls_fLevel_store); | ||
| 811 | |||
| 812 | static int lightsensor_setup(struct cm3217_info *lpi) | ||
| 813 | { | ||
| 814 | int ret; | ||
| 815 | |||
| 816 | lpi->ls_input_dev = input_allocate_device(); | ||
| 817 | if (!lpi->ls_input_dev) { | ||
| 818 | pr_err("[LS][CM3217 error]%s: " | ||
| 819 | "could not allocate ls input device\n", __func__); | ||
| 820 | return -ENOMEM; | ||
| 821 | } | ||
| 822 | lpi->ls_input_dev->name = "cm3217-ls"; | ||
| 823 | set_bit(EV_ABS, lpi->ls_input_dev->evbit); | ||
| 824 | input_set_abs_params(lpi->ls_input_dev, ABS_MISC, 0, 9, 0, 0); | ||
| 825 | |||
| 826 | ret = input_register_device(lpi->ls_input_dev); | ||
| 827 | if (ret < 0) { | ||
| 828 | pr_err("[LS][CM3217 error]%s: " | ||
| 829 | "can not register ls input device\n", __func__); | ||
| 830 | goto err_free_ls_input_device; | ||
| 831 | } | ||
| 832 | |||
| 833 | ret = misc_register(&lightsensor_misc); | ||
| 834 | if (ret < 0) { | ||
| 835 | pr_err("[LS][CM3217 error]%s: " | ||
| 836 | "can not register ls misc device\n", __func__); | ||
| 837 | goto err_unregister_ls_input_device; | ||
| 838 | } | ||
| 839 | |||
| 840 | return ret; | ||
| 841 | |||
| 842 | err_unregister_ls_input_device: | ||
| 843 | input_unregister_device(lpi->ls_input_dev); | ||
| 844 | err_free_ls_input_device: | ||
| 845 | input_free_device(lpi->ls_input_dev); | ||
| 846 | return ret; | ||
| 847 | } | ||
| 848 | |||
| 849 | static int cm3217_setup(struct cm3217_info *lpi) | ||
| 850 | { | ||
| 851 | int ret = 0; | ||
| 852 | |||
| 853 | als_power(1); | ||
| 854 | msleep(5); | ||
| 855 | |||
| 856 | ret = _cm3217_I2C_Write_Byte(ALS_W_CMD2_addr, | ||
| 857 | CM3217_ALS_WDM_DEFAULT_1 | ||
| 858 | | CM3217_ALS_IT_2_T | ||
| 859 | | CM3217_ALS_BIT5_Default_1); | ||
| 860 | if (ret < 0) | ||
| 861 | return ret; | ||
| 862 | |||
| 863 | ret = _cm3217_I2C_Write_Byte(ALS_W_CMD2_addr, CM3217_ALS_IT_100ms); | ||
| 864 | msleep(10); | ||
| 865 | |||
| 866 | return ret; | ||
| 867 | } | ||
| 868 | |||
| 869 | static void cm3217_early_suspend(struct early_suspend *h) | ||
| 870 | { | ||
| 871 | struct cm3217_info *lpi = lp_info; | ||
| 872 | |||
| 873 | D("[LS][CM3217] %s\n", __func__); | ||
| 874 | |||
| 875 | lpi->als_enabled_before_suspend = lpi->als_enable; | ||
| 876 | if (lpi->als_enable) | ||
| 877 | lightsensor_disable(lpi); | ||
| 878 | } | ||
| 879 | |||
| 880 | static void cm3217_late_resume(struct early_suspend *h) | ||
| 881 | { | ||
| 882 | struct cm3217_info *lpi = lp_info; | ||
| 883 | |||
| 884 | D("[LS][CM3217] %s\n", __func__); | ||
| 885 | |||
| 886 | if (lpi->als_enabled_before_suspend) | ||
| 887 | lightsensor_enable(lpi); | ||
| 888 | } | ||
| 889 | |||
| 890 | static int cm3217_probe(struct i2c_client *client, | ||
| 891 | const struct i2c_device_id *id) | ||
| 892 | { | ||
| 893 | int ret = 0; | ||
| 894 | struct cm3217_info *lpi; | ||
| 895 | struct cm3217_platform_data *pdata; | ||
| 896 | |||
| 897 | D("[CM3217] %s\n", __func__); | ||
| 898 | |||
| 899 | lpi = kzalloc(sizeof(struct cm3217_info), GFP_KERNEL); | ||
| 900 | if (!lpi) | ||
| 901 | return -ENOMEM; | ||
| 902 | |||
| 903 | /* D("[CM3217] %s: client->irq = %d\n", __func__, client->irq); */ | ||
| 904 | |||
| 905 | lpi->i2c_client = client; | ||
| 906 | pdata = client->dev.platform_data; | ||
| 907 | if (!pdata) { | ||
| 908 | pr_err("[CM3217 error]%s: Assign platform_data error!!\n", | ||
| 909 | __func__); | ||
| 910 | ret = -EBUSY; | ||
| 911 | goto err_platform_data_null; | ||
| 912 | } | ||
| 913 | |||
| 914 | lpi->irq = client->irq; | ||
| 915 | |||
| 916 | i2c_set_clientdata(client, lpi); | ||
| 917 | lpi->adc_table = pdata->levels; | ||
| 918 | lpi->golden_adc = pdata->golden_adc; | ||
| 919 | lpi->power = pdata->power; | ||
| 920 | |||
| 921 | lpi->polling_delay = msecs_to_jiffies(LS_POLLING_DELAY); | ||
| 922 | |||
| 923 | lp_info = lpi; | ||
| 924 | |||
| 925 | mutex_init(&als_enable_mutex); | ||
| 926 | mutex_init(&als_disable_mutex); | ||
| 927 | mutex_init(&als_get_adc_mutex); | ||
| 928 | |||
| 929 | ret = lightsensor_setup(lpi); | ||
| 930 | if (ret < 0) { | ||
| 931 | pr_err("[LS][CM3217 error]%s: lightsensor_setup error!!\n", | ||
| 932 | __func__); | ||
| 933 | goto err_lightsensor_setup; | ||
| 934 | } | ||
| 935 | |||
| 936 | /* SET LUX STEP FACTOR HERE | ||
| 937 | * if adc raw value one step = 0.3 lux | ||
| 938 | * the following will set the factor 0.3 = 3/10 | ||
| 939 | * and lpi->golden_adc = 3; | ||
| 940 | * set als_kadc = (ALS_CALIBRATED <<16) | 10; */ | ||
| 941 | |||
| 942 | als_kadc = (ALS_CALIBRATED << 16) | 10; | ||
| 943 | lpi->golden_adc = 3; | ||
| 944 | |||
| 945 | /* ls calibrate always set to 1 */ | ||
| 946 | lpi->ls_calibrate = 1; | ||
| 947 | |||
| 948 | lightsensor_set_kvalue(lpi); | ||
| 949 | ret = lightsensor_update_table(lpi); | ||
| 950 | if (ret < 0) { | ||
| 951 | pr_err("[LS][CM3217 error]%s: update ls table fail\n", | ||
| 952 | __func__); | ||
| 953 | goto err_lightsensor_update_table; | ||
| 954 | } | ||
| 955 | |||
| 956 | lpi->lp_wq = create_singlethread_workqueue("cm3217_wq"); | ||
| 957 | if (!lpi->lp_wq) { | ||
| 958 | pr_err("[CM3217 error]%s: can't create workqueue\n", __func__); | ||
| 959 | ret = -ENOMEM; | ||
| 960 | goto err_create_singlethread_workqueue; | ||
| 961 | } | ||
| 962 | |||
| 963 | ret = cm3217_setup(lpi); | ||
| 964 | if (ret < 0) { | ||
| 965 | pr_err("[ERR][CM3217 error]%s: cm3217_setup error!\n", | ||
| 966 | __func__); | ||
| 967 | goto err_cm3217_setup; | ||
| 968 | } | ||
| 969 | |||
| 970 | lpi->cm3217_class = class_create(THIS_MODULE, "optical_sensors"); | ||
| 971 | if (IS_ERR(lpi->cm3217_class)) { | ||
| 972 | ret = PTR_ERR(lpi->cm3217_class); | ||
| 973 | lpi->cm3217_class = NULL; | ||
| 974 | goto err_create_class; | ||
| 975 | } | ||
| 976 | |||
| 977 | lpi->ls_dev = device_create(lpi->cm3217_class, | ||
| 978 | NULL, 0, "%s", "lightsensor"); | ||
| 979 | if (unlikely(IS_ERR(lpi->ls_dev))) { | ||
| 980 | ret = PTR_ERR(lpi->ls_dev); | ||
| 981 | lpi->ls_dev = NULL; | ||
| 982 | goto err_create_ls_device; | ||
| 983 | } | ||
| 984 | |||
| 985 | /* register the attributes */ | ||
| 986 | ret = device_create_file(lpi->ls_dev, &dev_attr_ls_adc); | ||
| 987 | if (ret) | ||
| 988 | goto err_create_ls_device_file; | ||
| 989 | |||
| 990 | /* register the attributes */ | ||
| 991 | ret = device_create_file(lpi->ls_dev, &dev_attr_ls_auto); | ||
| 992 | if (ret) | ||
| 993 | goto err_create_ls_device_file; | ||
| 994 | |||
| 995 | /* register the attributes */ | ||
| 996 | ret = device_create_file(lpi->ls_dev, &dev_attr_ls_kadc); | ||
| 997 | if (ret) | ||
| 998 | goto err_create_ls_device_file; | ||
| 999 | |||
| 1000 | ret = device_create_file(lpi->ls_dev, &dev_attr_ls_gadc); | ||
| 1001 | if (ret) | ||
| 1002 | goto err_create_ls_device_file; | ||
| 1003 | |||
| 1004 | ret = device_create_file(lpi->ls_dev, &dev_attr_ls_adc_table); | ||
| 1005 | if (ret) | ||
| 1006 | goto err_create_ls_device_file; | ||
| 1007 | |||
| 1008 | ret = device_create_file(lpi->ls_dev, &dev_attr_ls_conf1); | ||
| 1009 | if (ret) | ||
| 1010 | goto err_create_ls_device_file; | ||
| 1011 | |||
| 1012 | ret = device_create_file(lpi->ls_dev, &dev_attr_ls_conf2); | ||
| 1013 | if (ret) | ||
| 1014 | goto err_create_ls_device_file; | ||
| 1015 | |||
| 1016 | ret = device_create_file(lpi->ls_dev, &dev_attr_ls_flevel); | ||
| 1017 | if (ret) | ||
| 1018 | goto err_create_ls_device_file; | ||
| 1019 | |||
| 1020 | lpi->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; | ||
| 1021 | lpi->early_suspend.suspend = cm3217_early_suspend; | ||
| 1022 | lpi->early_suspend.resume = cm3217_late_resume; | ||
| 1023 | register_early_suspend(&lpi->early_suspend); | ||
| 1024 | |||
| 1025 | lpi->als_enable = 0; | ||
| 1026 | lpi->als_enabled_before_suspend = 0; | ||
| 1027 | D("[CM3217] %s: Probe success!\n", __func__); | ||
| 1028 | |||
| 1029 | return ret; | ||
| 1030 | |||
| 1031 | err_create_ls_device_file: | ||
| 1032 | device_unregister(lpi->ls_dev); | ||
| 1033 | err_create_ls_device: | ||
| 1034 | class_destroy(lpi->cm3217_class); | ||
| 1035 | err_create_class: | ||
| 1036 | err_cm3217_setup: | ||
| 1037 | destroy_workqueue(lpi->lp_wq); | ||
| 1038 | mutex_destroy(&als_enable_mutex); | ||
| 1039 | mutex_destroy(&als_disable_mutex); | ||
| 1040 | mutex_destroy(&als_get_adc_mutex); | ||
| 1041 | input_unregister_device(lpi->ls_input_dev); | ||
| 1042 | input_free_device(lpi->ls_input_dev); | ||
| 1043 | err_create_singlethread_workqueue: | ||
| 1044 | err_lightsensor_update_table: | ||
| 1045 | misc_deregister(&lightsensor_misc); | ||
| 1046 | err_lightsensor_setup: | ||
| 1047 | err_platform_data_null: | ||
| 1048 | kfree(lpi); | ||
| 1049 | return ret; | ||
| 1050 | } | ||
| 1051 | |||
| 1052 | static const struct i2c_device_id cm3217_i2c_id[] = { | ||
| 1053 | {CM3217_I2C_NAME, 0}, | ||
| 1054 | {} | ||
| 1055 | }; | ||
| 1056 | |||
| 1057 | static struct i2c_driver cm3217_driver = { | ||
| 1058 | .id_table = cm3217_i2c_id, | ||
| 1059 | .probe = cm3217_probe, | ||
| 1060 | .driver = { | ||
| 1061 | .name = CM3217_I2C_NAME, | ||
| 1062 | .owner = THIS_MODULE, | ||
| 1063 | }, | ||
| 1064 | }; | ||
| 1065 | |||
| 1066 | static int __init cm3217_init(void) | ||
| 1067 | { | ||
| 1068 | return i2c_add_driver(&cm3217_driver); | ||
| 1069 | } | ||
| 1070 | |||
| 1071 | static void __exit cm3217_exit(void) | ||
| 1072 | { | ||
| 1073 | i2c_del_driver(&cm3217_driver); | ||
| 1074 | } | ||
| 1075 | |||
| 1076 | module_init(cm3217_init); | ||
| 1077 | module_exit(cm3217_exit); | ||
| 1078 | |||
| 1079 | MODULE_LICENSE("GPL"); | ||
| 1080 | MODULE_DESCRIPTION("CM3217 Driver"); | ||
| 1081 | MODULE_AUTHOR("Frank Hsieh <pengyueh@gmail.com>"); | ||
diff --git a/drivers/input/misc/gpio_axis.c b/drivers/input/misc/gpio_axis.c new file mode 100644 index 00000000000..0acf4a576f5 --- /dev/null +++ b/drivers/input/misc/gpio_axis.c | |||
| @@ -0,0 +1,192 @@ | |||
| 1 | /* drivers/input/misc/gpio_axis.c | ||
| 2 | * | ||
| 3 | * Copyright (C) 2007 Google, Inc. | ||
| 4 | * | ||
| 5 | * This software is licensed under the terms of the GNU General Public | ||
| 6 | * License version 2, as published by the Free Software Foundation, and | ||
| 7 | * may be copied, distributed, and modified under those terms. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/kernel.h> | ||
| 17 | #include <linux/gpio.h> | ||
| 18 | #include <linux/gpio_event.h> | ||
| 19 | #include <linux/interrupt.h> | ||
| 20 | #include <linux/slab.h> | ||
| 21 | |||
| 22 | struct gpio_axis_state { | ||
| 23 | struct gpio_event_input_devs *input_devs; | ||
| 24 | struct gpio_event_axis_info *info; | ||
| 25 | uint32_t pos; | ||
| 26 | }; | ||
| 27 | |||
| 28 | uint16_t gpio_axis_4bit_gray_map_table[] = { | ||
| 29 | [0x0] = 0x0, [0x1] = 0x1, /* 0000 0001 */ | ||
| 30 | [0x3] = 0x2, [0x2] = 0x3, /* 0011 0010 */ | ||
| 31 | [0x6] = 0x4, [0x7] = 0x5, /* 0110 0111 */ | ||
| 32 | [0x5] = 0x6, [0x4] = 0x7, /* 0101 0100 */ | ||
| 33 | [0xc] = 0x8, [0xd] = 0x9, /* 1100 1101 */ | ||
| 34 | [0xf] = 0xa, [0xe] = 0xb, /* 1111 1110 */ | ||
| 35 | [0xa] = 0xc, [0xb] = 0xd, /* 1010 1011 */ | ||
| 36 | [0x9] = 0xe, [0x8] = 0xf, /* 1001 1000 */ | ||
| 37 | }; | ||
| 38 | uint16_t gpio_axis_4bit_gray_map(struct gpio_event_axis_info *info, uint16_t in) | ||
| 39 | { | ||
| 40 | return gpio_axis_4bit_gray_map_table[in]; | ||
| 41 | } | ||
| 42 | |||
| 43 | uint16_t gpio_axis_5bit_singletrack_map_table[] = { | ||
| 44 | [0x10] = 0x00, [0x14] = 0x01, [0x1c] = 0x02, /* 10000 10100 11100 */ | ||
| 45 | [0x1e] = 0x03, [0x1a] = 0x04, [0x18] = 0x05, /* 11110 11010 11000 */ | ||
| 46 | [0x08] = 0x06, [0x0a] = 0x07, [0x0e] = 0x08, /* 01000 01010 01110 */ | ||
| 47 | [0x0f] = 0x09, [0x0d] = 0x0a, [0x0c] = 0x0b, /* 01111 01101 01100 */ | ||
| 48 | [0x04] = 0x0c, [0x05] = 0x0d, [0x07] = 0x0e, /* 00100 00101 00111 */ | ||
| 49 | [0x17] = 0x0f, [0x16] = 0x10, [0x06] = 0x11, /* 10111 10110 00110 */ | ||
| 50 | [0x02] = 0x12, [0x12] = 0x13, [0x13] = 0x14, /* 00010 10010 10011 */ | ||
| 51 | [0x1b] = 0x15, [0x0b] = 0x16, [0x03] = 0x17, /* 11011 01011 00011 */ | ||
| 52 | [0x01] = 0x18, [0x09] = 0x19, [0x19] = 0x1a, /* 00001 01001 11001 */ | ||
| 53 | [0x1d] = 0x1b, [0x15] = 0x1c, [0x11] = 0x1d, /* 11101 10101 10001 */ | ||
| 54 | }; | ||
| 55 | uint16_t gpio_axis_5bit_singletrack_map( | ||
| 56 | struct gpio_event_axis_info *info, uint16_t in) | ||
| 57 | { | ||
| 58 | return gpio_axis_5bit_singletrack_map_table[in]; | ||
| 59 | } | ||
| 60 | |||
| 61 | static void gpio_event_update_axis(struct gpio_axis_state *as, int report) | ||
| 62 | { | ||
| 63 | struct gpio_event_axis_info *ai = as->info; | ||
| 64 | int i; | ||
| 65 | int change; | ||
| 66 | uint16_t state = 0; | ||
| 67 | uint16_t pos; | ||
| 68 | uint16_t old_pos = as->pos; | ||
| 69 | for (i = ai->count - 1; i >= 0; i--) | ||
| 70 | state = (state << 1) | gpio_get_value(ai->gpio[i]); | ||
| 71 | pos = ai->map(ai, state); | ||
| 72 | if (ai->flags & GPIOEAF_PRINT_RAW) | ||
| 73 | pr_info("axis %d-%d raw %x, pos %d -> %d\n", | ||
| 74 | ai->type, ai->code, state, old_pos, pos); | ||
| 75 | if (report && pos != old_pos) { | ||
| 76 | if (ai->type == EV_REL) { | ||
| 77 | change = (ai->decoded_size + pos - old_pos) % | ||
| 78 | ai->decoded_size; | ||
| 79 | if (change > ai->decoded_size / 2) | ||
| 80 | change -= ai->decoded_size; | ||
| 81 | if (change == ai->decoded_size / 2) { | ||
| 82 | if (ai->flags & GPIOEAF_PRINT_EVENT) | ||
| 83 | pr_info("axis %d-%d unknown direction, " | ||
| 84 | "pos %d -> %d\n", ai->type, | ||
| 85 | ai->code, old_pos, pos); | ||
| 86 | change = 0; /* no closest direction */ | ||
| 87 | } | ||
| 88 | if (ai->flags & GPIOEAF_PRINT_EVENT) | ||
| 89 | pr_info("axis %d-%d change %d\n", | ||
| 90 | ai->type, ai->code, change); | ||
| 91 | input_report_rel(as->input_devs->dev[ai->dev], | ||
| 92 | ai->code, change); | ||
| 93 | } else { | ||
| 94 | if (ai->flags & GPIOEAF_PRINT_EVENT) | ||
| 95 | pr_info("axis %d-%d now %d\n", | ||
| 96 | ai->type, ai->code, pos); | ||
| 97 | input_event(as->input_devs->dev[ai->dev], | ||
| 98 | ai->type, ai->code, pos); | ||
| 99 | } | ||
| 100 | input_sync(as->input_devs->dev[ai->dev]); | ||
| 101 | } | ||
| 102 | as->pos = pos; | ||
| 103 | } | ||
| 104 | |||
| 105 | static irqreturn_t gpio_axis_irq_handler(int irq, void *dev_id) | ||
| 106 | { | ||
| 107 | struct gpio_axis_state *as = dev_id; | ||
| 108 | gpio_event_update_axis(as, 1); | ||
| 109 | return IRQ_HANDLED; | ||
| 110 | } | ||
| 111 | |||
| 112 | int gpio_event_axis_func(struct gpio_event_input_devs *input_devs, | ||
| 113 | struct gpio_event_info *info, void **data, int func) | ||
| 114 | { | ||
| 115 | int ret; | ||
| 116 | int i; | ||
| 117 | int irq; | ||
| 118 | struct gpio_event_axis_info *ai; | ||
| 119 | struct gpio_axis_state *as; | ||
| 120 | |||
| 121 | ai = container_of(info, struct gpio_event_axis_info, info); | ||
| 122 | if (func == GPIO_EVENT_FUNC_SUSPEND) { | ||
| 123 | for (i = 0; i < ai->count; i++) | ||
| 124 | disable_irq(gpio_to_irq(ai->gpio[i])); | ||
| 125 | return 0; | ||
| 126 | } | ||
| 127 | if (func == GPIO_EVENT_FUNC_RESUME) { | ||
| 128 | for (i = 0; i < ai->count; i++) | ||
| 129 | enable_irq(gpio_to_irq(ai->gpio[i])); | ||
| 130 | return 0; | ||
| 131 | } | ||
| 132 | |||
| 133 | if (func == GPIO_EVENT_FUNC_INIT) { | ||
| 134 | *data = as = kmalloc(sizeof(*as), GFP_KERNEL); | ||
| 135 | if (as == NULL) { | ||
| 136 | ret = -ENOMEM; | ||
| 137 | goto err_alloc_axis_state_failed; | ||
| 138 | } | ||
| 139 | as->input_devs = input_devs; | ||
| 140 | as->info = ai; | ||
| 141 | if (ai->dev >= input_devs->count) { | ||
| 142 | pr_err("gpio_event_axis: bad device index %d >= %d " | ||
| 143 | "for %d:%d\n", ai->dev, input_devs->count, | ||
| 144 | ai->type, ai->code); | ||
| 145 | ret = -EINVAL; | ||
| 146 | goto err_bad_device_index; | ||
| 147 | } | ||
| 148 | |||
| 149 | input_set_capability(input_devs->dev[ai->dev], | ||
| 150 | ai->type, ai->code); | ||
| 151 | if (ai->type == EV_ABS) { | ||
| 152 | input_set_abs_params(input_devs->dev[ai->dev], ai->code, | ||
| 153 | 0, ai->decoded_size - 1, 0, 0); | ||
| 154 | } | ||
| 155 | for (i = 0; i < ai->count; i++) { | ||
| 156 | ret = gpio_request(ai->gpio[i], "gpio_event_axis"); | ||
| 157 | if (ret < 0) | ||
| 158 | goto err_request_gpio_failed; | ||
| 159 | ret = gpio_direction_input(ai->gpio[i]); | ||
| 160 | if (ret < 0) | ||
| 161 | goto err_gpio_direction_input_failed; | ||
| 162 | ret = irq = gpio_to_irq(ai->gpio[i]); | ||
| 163 | if (ret < 0) | ||
| 164 | goto err_get_irq_num_failed; | ||
| 165 | ret = request_irq(irq, gpio_axis_irq_handler, | ||
| 166 | IRQF_TRIGGER_RISING | | ||
| 167 | IRQF_TRIGGER_FALLING, | ||
| 168 | "gpio_event_axis", as); | ||
| 169 | if (ret < 0) | ||
| 170 | goto err_request_irq_failed; | ||
| 171 | } | ||
| 172 | gpio_event_update_axis(as, 0); | ||
| 173 | return 0; | ||
| 174 | } | ||
| 175 | |||
| 176 | ret = 0; | ||
| 177 | as = *data; | ||
| 178 | for (i = ai->count - 1; i >= 0; i--) { | ||
| 179 | free_irq(gpio_to_irq(ai->gpio[i]), as); | ||
| 180 | err_request_irq_failed: | ||
| 181 | err_get_irq_num_failed: | ||
| 182 | err_gpio_direction_input_failed: | ||
| 183 | gpio_free(ai->gpio[i]); | ||
| 184 | err_request_gpio_failed: | ||
| 185 | ; | ||
| 186 | } | ||
| 187 | err_bad_device_index: | ||
| 188 | kfree(as); | ||
| 189 | *data = NULL; | ||
| 190 | err_alloc_axis_state_failed: | ||
| 191 | return ret; | ||
| 192 | } | ||
diff --git a/drivers/input/misc/gpio_event.c b/drivers/input/misc/gpio_event.c new file mode 100644 index 00000000000..a98be67d1ab --- /dev/null +++ b/drivers/input/misc/gpio_event.c | |||
| @@ -0,0 +1,260 @@ | |||
| 1 | /* drivers/input/misc/gpio_event.c | ||
| 2 | * | ||
| 3 | * Copyright (C) 2007 Google, Inc. | ||
| 4 | * | ||
| 5 | * This software is licensed under the terms of the GNU General Public | ||
| 6 | * License version 2, as published by the Free Software Foundation, and | ||
| 7 | * may be copied, distributed, and modified under those terms. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/earlysuspend.h> | ||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/input.h> | ||
| 19 | #include <linux/gpio_event.h> | ||
| 20 | #include <linux/hrtimer.h> | ||
| 21 | #include <linux/platform_device.h> | ||
| 22 | #include <linux/slab.h> | ||
| 23 | |||
| 24 | struct gpio_event { | ||
| 25 | struct gpio_event_input_devs *input_devs; | ||
| 26 | const struct gpio_event_platform_data *info; | ||
| 27 | struct early_suspend early_suspend; | ||
| 28 | void *state[0]; | ||
| 29 | }; | ||
| 30 | |||
| 31 | static int gpio_input_event( | ||
| 32 | struct input_dev *dev, unsigned int type, unsigned int code, int value) | ||
| 33 | { | ||
| 34 | int i; | ||
| 35 | int devnr; | ||
| 36 | int ret = 0; | ||
| 37 | int tmp_ret; | ||
| 38 | struct gpio_event_info **ii; | ||
| 39 | struct gpio_event *ip = input_get_drvdata(dev); | ||
| 40 | |||
| 41 | for (devnr = 0; devnr < ip->input_devs->count; devnr++) | ||
| 42 | if (ip->input_devs->dev[devnr] == dev) | ||
| 43 | break; | ||
| 44 | if (devnr == ip->input_devs->count) { | ||
| 45 | pr_err("gpio_input_event: unknown device %p\n", dev); | ||
| 46 | return -EIO; | ||
| 47 | } | ||
| 48 | |||
| 49 | for (i = 0, ii = ip->info->info; i < ip->info->info_count; i++, ii++) { | ||
| 50 | if ((*ii)->event) { | ||
| 51 | tmp_ret = (*ii)->event(ip->input_devs, *ii, | ||
| 52 | &ip->state[i], | ||
| 53 | devnr, type, code, value); | ||
| 54 | if (tmp_ret) | ||
| 55 | ret = tmp_ret; | ||
| 56 | } | ||
| 57 | } | ||
| 58 | return ret; | ||
| 59 | } | ||
| 60 | |||
| 61 | static int gpio_event_call_all_func(struct gpio_event *ip, int func) | ||
| 62 | { | ||
| 63 | int i; | ||
| 64 | int ret; | ||
| 65 | struct gpio_event_info **ii; | ||
| 66 | |||
| 67 | if (func == GPIO_EVENT_FUNC_INIT || func == GPIO_EVENT_FUNC_RESUME) { | ||
| 68 | ii = ip->info->info; | ||
| 69 | for (i = 0; i < ip->info->info_count; i++, ii++) { | ||
| 70 | if ((*ii)->func == NULL) { | ||
| 71 | ret = -ENODEV; | ||
| 72 | pr_err("gpio_event_probe: Incomplete pdata, " | ||
| 73 | "no function\n"); | ||
| 74 | goto err_no_func; | ||
| 75 | } | ||
| 76 | if (func == GPIO_EVENT_FUNC_RESUME && (*ii)->no_suspend) | ||
| 77 | continue; | ||
| 78 | ret = (*ii)->func(ip->input_devs, *ii, &ip->state[i], | ||
| 79 | func); | ||
| 80 | if (ret) { | ||
| 81 | pr_err("gpio_event_probe: function failed\n"); | ||
| 82 | goto err_func_failed; | ||
| 83 | } | ||
| 84 | } | ||
| 85 | return 0; | ||
| 86 | } | ||
| 87 | |||
| 88 | ret = 0; | ||
| 89 | i = ip->info->info_count; | ||
| 90 | ii = ip->info->info + i; | ||
| 91 | while (i > 0) { | ||
| 92 | i--; | ||
| 93 | ii--; | ||
| 94 | if ((func & ~1) == GPIO_EVENT_FUNC_SUSPEND && (*ii)->no_suspend) | ||
| 95 | continue; | ||
| 96 | (*ii)->func(ip->input_devs, *ii, &ip->state[i], func & ~1); | ||
| 97 | err_func_failed: | ||
| 98 | err_no_func: | ||
| 99 | ; | ||
| 100 | } | ||
| 101 | return ret; | ||
| 102 | } | ||
| 103 | |||
| 104 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
| 105 | void gpio_event_suspend(struct early_suspend *h) | ||
| 106 | { | ||
| 107 | struct gpio_event *ip; | ||
| 108 | ip = container_of(h, struct gpio_event, early_suspend); | ||
| 109 | gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_SUSPEND); | ||
| 110 | ip->info->power(ip->info, 0); | ||
| 111 | } | ||
| 112 | |||
| 113 | void gpio_event_resume(struct early_suspend *h) | ||
| 114 | { | ||
| 115 | struct gpio_event *ip; | ||
| 116 | ip = container_of(h, struct gpio_event, early_suspend); | ||
| 117 | ip->info->power(ip->info, 1); | ||
| 118 | gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_RESUME); | ||
| 119 | } | ||
| 120 | #endif | ||
| 121 | |||
| 122 | static int gpio_event_probe(struct platform_device *pdev) | ||
| 123 | { | ||
| 124 | int err; | ||
| 125 | struct gpio_event *ip; | ||
| 126 | struct gpio_event_platform_data *event_info; | ||
| 127 | int dev_count = 1; | ||
| 128 | int i; | ||
| 129 | int registered = 0; | ||
| 130 | |||
| 131 | event_info = pdev->dev.platform_data; | ||
| 132 | if (event_info == NULL) { | ||
| 133 | pr_err("gpio_event_probe: No pdata\n"); | ||
| 134 | return -ENODEV; | ||
| 135 | } | ||
| 136 | if ((!event_info->name && !event_info->names[0]) || | ||
| 137 | !event_info->info || !event_info->info_count) { | ||
| 138 | pr_err("gpio_event_probe: Incomplete pdata\n"); | ||
| 139 | return -ENODEV; | ||
| 140 | } | ||
| 141 | if (!event_info->name) | ||
| 142 | while (event_info->names[dev_count]) | ||
| 143 | dev_count++; | ||
| 144 | ip = kzalloc(sizeof(*ip) + | ||
| 145 | sizeof(ip->state[0]) * event_info->info_count + | ||
| 146 | sizeof(*ip->input_devs) + | ||
| 147 | sizeof(ip->input_devs->dev[0]) * dev_count, GFP_KERNEL); | ||
| 148 | if (ip == NULL) { | ||
| 149 | err = -ENOMEM; | ||
| 150 | pr_err("gpio_event_probe: Failed to allocate private data\n"); | ||
| 151 | goto err_kp_alloc_failed; | ||
| 152 | } | ||
| 153 | ip->input_devs = (void*)&ip->state[event_info->info_count]; | ||
| 154 | platform_set_drvdata(pdev, ip); | ||
| 155 | |||
| 156 | for (i = 0; i < dev_count; i++) { | ||
| 157 | struct input_dev *input_dev = input_allocate_device(); | ||
| 158 | if (input_dev == NULL) { | ||
| 159 | err = -ENOMEM; | ||
| 160 | pr_err("gpio_event_probe: " | ||
| 161 | "Failed to allocate input device\n"); | ||
| 162 | goto err_input_dev_alloc_failed; | ||
| 163 | } | ||
| 164 | input_set_drvdata(input_dev, ip); | ||
| 165 | input_dev->name = event_info->name ? | ||
| 166 | event_info->name : event_info->names[i]; | ||
| 167 | input_dev->event = gpio_input_event; | ||
| 168 | ip->input_devs->dev[i] = input_dev; | ||
| 169 | } | ||
| 170 | ip->input_devs->count = dev_count; | ||
| 171 | ip->info = event_info; | ||
| 172 | if (event_info->power) { | ||
| 173 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
| 174 | ip->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; | ||
| 175 | ip->early_suspend.suspend = gpio_event_suspend; | ||
| 176 | ip->early_suspend.resume = gpio_event_resume; | ||
| 177 | register_early_suspend(&ip->early_suspend); | ||
| 178 | #endif | ||
| 179 | ip->info->power(ip->info, 1); | ||
| 180 | } | ||
| 181 | |||
| 182 | err = gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_INIT); | ||
| 183 | if (err) | ||
| 184 | goto err_call_all_func_failed; | ||
| 185 | |||
| 186 | for (i = 0; i < dev_count; i++) { | ||
| 187 | err = input_register_device(ip->input_devs->dev[i]); | ||
| 188 | if (err) { | ||
| 189 | pr_err("gpio_event_probe: Unable to register %s " | ||
| 190 | "input device\n", ip->input_devs->dev[i]->name); | ||
| 191 | goto err_input_register_device_failed; | ||
| 192 | } | ||
| 193 | registered++; | ||
| 194 | } | ||
| 195 | |||
| 196 | return 0; | ||
| 197 | |||
| 198 | err_input_register_device_failed: | ||
| 199 | gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_UNINIT); | ||
| 200 | err_call_all_func_failed: | ||
| 201 | if (event_info->power) { | ||
| 202 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
| 203 | unregister_early_suspend(&ip->early_suspend); | ||
| 204 | #endif | ||
| 205 | ip->info->power(ip->info, 0); | ||
| 206 | } | ||
| 207 | for (i = 0; i < registered; i++) | ||
| 208 | input_unregister_device(ip->input_devs->dev[i]); | ||
| 209 | for (i = dev_count - 1; i >= registered; i--) { | ||
| 210 | input_free_device(ip->input_devs->dev[i]); | ||
| 211 | err_input_dev_alloc_failed: | ||
| 212 | ; | ||
| 213 | } | ||
| 214 | kfree(ip); | ||
| 215 | err_kp_alloc_failed: | ||
| 216 | return err; | ||
| 217 | } | ||
| 218 | |||
| 219 | static int gpio_event_remove(struct platform_device *pdev) | ||
| 220 | { | ||
| 221 | struct gpio_event *ip = platform_get_drvdata(pdev); | ||
| 222 | int i; | ||
| 223 | |||
| 224 | gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_UNINIT); | ||
| 225 | if (ip->info->power) { | ||
| 226 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
| 227 | unregister_early_suspend(&ip->early_suspend); | ||
| 228 | #endif | ||
| 229 | ip->info->power(ip->info, 0); | ||
| 230 | } | ||
| 231 | for (i = 0; i < ip->input_devs->count; i++) | ||
| 232 | input_unregister_device(ip->input_devs->dev[i]); | ||
| 233 | kfree(ip); | ||
| 234 | return 0; | ||
| 235 | } | ||
| 236 | |||
| 237 | static struct platform_driver gpio_event_driver = { | ||
| 238 | .probe = gpio_event_probe, | ||
| 239 | .remove = gpio_event_remove, | ||
| 240 | .driver = { | ||
| 241 | .name = GPIO_EVENT_DEV_NAME, | ||
| 242 | }, | ||
| 243 | }; | ||
| 244 | |||
| 245 | static int __devinit gpio_event_init(void) | ||
| 246 | { | ||
| 247 | return platform_driver_register(&gpio_event_driver); | ||
| 248 | } | ||
| 249 | |||
| 250 | static void __exit gpio_event_exit(void) | ||
| 251 | { | ||
| 252 | platform_driver_unregister(&gpio_event_driver); | ||
| 253 | } | ||
| 254 | |||
| 255 | module_init(gpio_event_init); | ||
| 256 | module_exit(gpio_event_exit); | ||
| 257 | |||
| 258 | MODULE_DESCRIPTION("GPIO Event Driver"); | ||
| 259 | MODULE_LICENSE("GPL"); | ||
| 260 | |||
diff --git a/drivers/input/misc/gpio_input.c b/drivers/input/misc/gpio_input.c new file mode 100644 index 00000000000..6a0c3151096 --- /dev/null +++ b/drivers/input/misc/gpio_input.c | |||
| @@ -0,0 +1,376 @@ | |||
| 1 | /* drivers/input/misc/gpio_input.c | ||
| 2 | * | ||
| 3 | * Copyright (C) 2007 Google, Inc. | ||
| 4 | * | ||
| 5 | * This software is licensed under the terms of the GNU General Public | ||
| 6 | * License version 2, as published by the Free Software Foundation, and | ||
| 7 | * may be copied, distributed, and modified under those terms. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/kernel.h> | ||
| 17 | #include <linux/gpio.h> | ||
| 18 | #include <linux/gpio_event.h> | ||
| 19 | #include <linux/hrtimer.h> | ||
| 20 | #include <linux/input.h> | ||
| 21 | #include <linux/interrupt.h> | ||
| 22 | #include <linux/slab.h> | ||
| 23 | #include <linux/wakelock.h> | ||
| 24 | |||
| 25 | enum { | ||
| 26 | DEBOUNCE_UNSTABLE = BIT(0), /* Got irq, while debouncing */ | ||
| 27 | DEBOUNCE_PRESSED = BIT(1), | ||
| 28 | DEBOUNCE_NOTPRESSED = BIT(2), | ||
| 29 | DEBOUNCE_WAIT_IRQ = BIT(3), /* Stable irq state */ | ||
| 30 | DEBOUNCE_POLL = BIT(4), /* Stable polling state */ | ||
| 31 | |||
| 32 | DEBOUNCE_UNKNOWN = | ||
| 33 | DEBOUNCE_PRESSED | DEBOUNCE_NOTPRESSED, | ||
| 34 | }; | ||
| 35 | |||
| 36 | struct gpio_key_state { | ||
| 37 | struct gpio_input_state *ds; | ||
| 38 | uint8_t debounce; | ||
| 39 | }; | ||
| 40 | |||
| 41 | struct gpio_input_state { | ||
| 42 | struct gpio_event_input_devs *input_devs; | ||
| 43 | const struct gpio_event_input_info *info; | ||
| 44 | struct hrtimer timer; | ||
| 45 | int use_irq; | ||
| 46 | int debounce_count; | ||
| 47 | spinlock_t irq_lock; | ||
| 48 | struct wake_lock wake_lock; | ||
| 49 | struct gpio_key_state key_state[0]; | ||
| 50 | }; | ||
| 51 | |||
| 52 | static enum hrtimer_restart gpio_event_input_timer_func(struct hrtimer *timer) | ||
| 53 | { | ||
| 54 | int i; | ||
| 55 | int pressed; | ||
| 56 | struct gpio_input_state *ds = | ||
| 57 | container_of(timer, struct gpio_input_state, timer); | ||
| 58 | unsigned gpio_flags = ds->info->flags; | ||
| 59 | unsigned npolarity; | ||
| 60 | int nkeys = ds->info->keymap_size; | ||
| 61 | const struct gpio_event_direct_entry *key_entry; | ||
| 62 | struct gpio_key_state *key_state; | ||
| 63 | unsigned long irqflags; | ||
| 64 | uint8_t debounce; | ||
| 65 | bool sync_needed; | ||
| 66 | |||
| 67 | #if 0 | ||
| 68 | key_entry = kp->keys_info->keymap; | ||
| 69 | key_state = kp->key_state; | ||
| 70 | for (i = 0; i < nkeys; i++, key_entry++, key_state++) | ||
| 71 | pr_info("gpio_read_detect_status %d %d\n", key_entry->gpio, | ||
| 72 | gpio_read_detect_status(key_entry->gpio)); | ||
| 73 | #endif | ||
| 74 | key_entry = ds->info->keymap; | ||
| 75 | key_state = ds->key_state; | ||
| 76 | sync_needed = false; | ||
| 77 | spin_lock_irqsave(&ds->irq_lock, irqflags); | ||
| 78 | for (i = 0; i < nkeys; i++, key_entry++, key_state++) { | ||
| 79 | debounce = key_state->debounce; | ||
| 80 | if (debounce & DEBOUNCE_WAIT_IRQ) | ||
| 81 | continue; | ||
| 82 | if (key_state->debounce & DEBOUNCE_UNSTABLE) { | ||
| 83 | debounce = key_state->debounce = DEBOUNCE_UNKNOWN; | ||
| 84 | enable_irq(gpio_to_irq(key_entry->gpio)); | ||
| 85 | if (gpio_flags & GPIOEDF_PRINT_KEY_UNSTABLE) | ||
| 86 | pr_info("gpio_keys_scan_keys: key %x-%x, %d " | ||
| 87 | "(%d) continue debounce\n", | ||
| 88 | ds->info->type, key_entry->code, | ||
| 89 | i, key_entry->gpio); | ||
| 90 | } | ||
| 91 | npolarity = !(gpio_flags & GPIOEDF_ACTIVE_HIGH); | ||
| 92 | pressed = gpio_get_value(key_entry->gpio) ^ npolarity; | ||
| 93 | if (debounce & DEBOUNCE_POLL) { | ||
| 94 | if (pressed == !(debounce & DEBOUNCE_PRESSED)) { | ||
| 95 | ds->debounce_count++; | ||
| 96 | key_state->debounce = DEBOUNCE_UNKNOWN; | ||
| 97 | if (gpio_flags & GPIOEDF_PRINT_KEY_DEBOUNCE) | ||
| 98 | pr_info("gpio_keys_scan_keys: key %x-" | ||
| 99 | "%x, %d (%d) start debounce\n", | ||
| 100 | ds->info->type, key_entry->code, | ||
| 101 | i, key_entry->gpio); | ||
| 102 | } | ||
| 103 | continue; | ||
| 104 | } | ||
| 105 | if (pressed && (debounce & DEBOUNCE_NOTPRESSED)) { | ||
| 106 | if (gpio_flags & GPIOEDF_PRINT_KEY_DEBOUNCE) | ||
| 107 | pr_info("gpio_keys_scan_keys: key %x-%x, %d " | ||
| 108 | "(%d) debounce pressed 1\n", | ||
| 109 | ds->info->type, key_entry->code, | ||
| 110 | i, key_entry->gpio); | ||
| 111 | key_state->debounce = DEBOUNCE_PRESSED; | ||
| 112 | continue; | ||
| 113 | } | ||
| 114 | if (!pressed && (debounce & DEBOUNCE_PRESSED)) { | ||
| 115 | if (gpio_flags & GPIOEDF_PRINT_KEY_DEBOUNCE) | ||
| 116 | pr_info("gpio_keys_scan_keys: key %x-%x, %d " | ||
| 117 | "(%d) debounce pressed 0\n", | ||
| 118 | ds->info->type, key_entry->code, | ||
| 119 | i, key_entry->gpio); | ||
| 120 | key_state->debounce = DEBOUNCE_NOTPRESSED; | ||
| 121 | continue; | ||
| 122 | } | ||
| 123 | /* key is stable */ | ||
| 124 | ds->debounce_count--; | ||
| 125 | if (ds->use_irq) | ||
| 126 | key_state->debounce |= DEBOUNCE_WAIT_IRQ; | ||
| 127 | else | ||
| 128 | key_state->debounce |= DEBOUNCE_POLL; | ||
| 129 | if (gpio_flags & GPIOEDF_PRINT_KEYS) | ||
| 130 | pr_info("gpio_keys_scan_keys: key %x-%x, %d (%d) " | ||
| 131 | "changed to %d\n", ds->info->type, | ||
| 132 | key_entry->code, i, key_entry->gpio, pressed); | ||
| 133 | input_event(ds->input_devs->dev[key_entry->dev], ds->info->type, | ||
| 134 | key_entry->code, pressed); | ||
| 135 | sync_needed = true; | ||
| 136 | } | ||
| 137 | if (sync_needed) { | ||
| 138 | for (i = 0; i < ds->input_devs->count; i++) | ||
| 139 | input_sync(ds->input_devs->dev[i]); | ||
| 140 | } | ||
| 141 | |||
| 142 | #if 0 | ||
| 143 | key_entry = kp->keys_info->keymap; | ||
| 144 | key_state = kp->key_state; | ||
| 145 | for (i = 0; i < nkeys; i++, key_entry++, key_state++) { | ||
| 146 | pr_info("gpio_read_detect_status %d %d\n", key_entry->gpio, | ||
| 147 | gpio_read_detect_status(key_entry->gpio)); | ||
| 148 | } | ||
| 149 | #endif | ||
| 150 | |||
| 151 | if (ds->debounce_count) | ||
| 152 | hrtimer_start(timer, ds->info->debounce_time, HRTIMER_MODE_REL); | ||
| 153 | else if (!ds->use_irq) | ||
| 154 | hrtimer_start(timer, ds->info->poll_time, HRTIMER_MODE_REL); | ||
| 155 | else | ||
| 156 | wake_unlock(&ds->wake_lock); | ||
| 157 | |||
| 158 | spin_unlock_irqrestore(&ds->irq_lock, irqflags); | ||
| 159 | |||
| 160 | return HRTIMER_NORESTART; | ||
| 161 | } | ||
| 162 | |||
| 163 | static irqreturn_t gpio_event_input_irq_handler(int irq, void *dev_id) | ||
| 164 | { | ||
| 165 | struct gpio_key_state *ks = dev_id; | ||
| 166 | struct gpio_input_state *ds = ks->ds; | ||
| 167 | int keymap_index = ks - ds->key_state; | ||
| 168 | const struct gpio_event_direct_entry *key_entry; | ||
| 169 | unsigned long irqflags; | ||
| 170 | int pressed; | ||
| 171 | |||
| 172 | if (!ds->use_irq) | ||
| 173 | return IRQ_HANDLED; | ||
| 174 | |||
| 175 | key_entry = &ds->info->keymap[keymap_index]; | ||
| 176 | |||
| 177 | if (ds->info->debounce_time.tv64) { | ||
| 178 | spin_lock_irqsave(&ds->irq_lock, irqflags); | ||
| 179 | if (ks->debounce & DEBOUNCE_WAIT_IRQ) { | ||
| 180 | ks->debounce = DEBOUNCE_UNKNOWN; | ||
| 181 | if (ds->debounce_count++ == 0) { | ||
| 182 | wake_lock(&ds->wake_lock); | ||
| 183 | hrtimer_start( | ||
| 184 | &ds->timer, ds->info->debounce_time, | ||
| 185 | HRTIMER_MODE_REL); | ||
| 186 | } | ||
| 187 | if (ds->info->flags & GPIOEDF_PRINT_KEY_DEBOUNCE) | ||
| 188 | pr_info("gpio_event_input_irq_handler: " | ||
| 189 | "key %x-%x, %d (%d) start debounce\n", | ||
| 190 | ds->info->type, key_entry->code, | ||
| 191 | keymap_index, key_entry->gpio); | ||
| 192 | } else { | ||
| 193 | disable_irq_nosync(irq); | ||
| 194 | ks->debounce = DEBOUNCE_UNSTABLE; | ||
| 195 | } | ||
| 196 | spin_unlock_irqrestore(&ds->irq_lock, irqflags); | ||
| 197 | } else { | ||
| 198 | pressed = gpio_get_value(key_entry->gpio) ^ | ||
| 199 | !(ds->info->flags & GPIOEDF_ACTIVE_HIGH); | ||
| 200 | if (ds->info->flags & GPIOEDF_PRINT_KEYS) | ||
| 201 | pr_info("gpio_event_input_irq_handler: key %x-%x, %d " | ||
| 202 | "(%d) changed to %d\n", | ||
| 203 | ds->info->type, key_entry->code, keymap_index, | ||
| 204 | key_entry->gpio, pressed); | ||
| 205 | input_event(ds->input_devs->dev[key_entry->dev], ds->info->type, | ||
| 206 | key_entry->code, pressed); | ||
| 207 | input_sync(ds->input_devs->dev[key_entry->dev]); | ||
| 208 | } | ||
| 209 | return IRQ_HANDLED; | ||
| 210 | } | ||
| 211 | |||
| 212 | static int gpio_event_input_request_irqs(struct gpio_input_state *ds) | ||
| 213 | { | ||
| 214 | int i; | ||
| 215 | int err; | ||
| 216 | unsigned int irq; | ||
| 217 | unsigned long req_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; | ||
| 218 | |||
| 219 | for (i = 0; i < ds->info->keymap_size; i++) { | ||
| 220 | err = irq = gpio_to_irq(ds->info->keymap[i].gpio); | ||
| 221 | if (err < 0) | ||
| 222 | goto err_gpio_get_irq_num_failed; | ||
| 223 | err = request_irq(irq, gpio_event_input_irq_handler, | ||
| 224 | req_flags, "gpio_keys", &ds->key_state[i]); | ||
| 225 | if (err) { | ||
| 226 | pr_err("gpio_event_input_request_irqs: request_irq " | ||
| 227 | "failed for input %d, irq %d\n", | ||
| 228 | ds->info->keymap[i].gpio, irq); | ||
| 229 | goto err_request_irq_failed; | ||
| 230 | } | ||
| 231 | if (ds->info->info.no_suspend) { | ||
| 232 | err = enable_irq_wake(irq); | ||
| 233 | if (err) { | ||
| 234 | pr_err("gpio_event_input_request_irqs: " | ||
| 235 | "enable_irq_wake failed for input %d, " | ||
| 236 | "irq %d\n", | ||
| 237 | ds->info->keymap[i].gpio, irq); | ||
| 238 | goto err_enable_irq_wake_failed; | ||
| 239 | } | ||
| 240 | } | ||
| 241 | } | ||
| 242 | return 0; | ||
| 243 | |||
| 244 | for (i = ds->info->keymap_size - 1; i >= 0; i--) { | ||
| 245 | irq = gpio_to_irq(ds->info->keymap[i].gpio); | ||
| 246 | if (ds->info->info.no_suspend) | ||
| 247 | disable_irq_wake(irq); | ||
| 248 | err_enable_irq_wake_failed: | ||
| 249 | free_irq(irq, &ds->key_state[i]); | ||
| 250 | err_request_irq_failed: | ||
| 251 | err_gpio_get_irq_num_failed: | ||
| 252 | ; | ||
| 253 | } | ||
| 254 | return err; | ||
| 255 | } | ||
| 256 | |||
| 257 | int gpio_event_input_func(struct gpio_event_input_devs *input_devs, | ||
| 258 | struct gpio_event_info *info, void **data, int func) | ||
| 259 | { | ||
| 260 | int ret; | ||
| 261 | int i; | ||
| 262 | unsigned long irqflags; | ||
| 263 | struct gpio_event_input_info *di; | ||
| 264 | struct gpio_input_state *ds = *data; | ||
| 265 | |||
| 266 | di = container_of(info, struct gpio_event_input_info, info); | ||
| 267 | |||
| 268 | if (func == GPIO_EVENT_FUNC_SUSPEND) { | ||
| 269 | if (ds->use_irq) | ||
| 270 | for (i = 0; i < di->keymap_size; i++) | ||
| 271 | disable_irq(gpio_to_irq(di->keymap[i].gpio)); | ||
| 272 | hrtimer_cancel(&ds->timer); | ||
| 273 | return 0; | ||
| 274 | } | ||
| 275 | if (func == GPIO_EVENT_FUNC_RESUME) { | ||
| 276 | spin_lock_irqsave(&ds->irq_lock, irqflags); | ||
| 277 | if (ds->use_irq) | ||
| 278 | for (i = 0; i < di->keymap_size; i++) | ||
| 279 | enable_irq(gpio_to_irq(di->keymap[i].gpio)); | ||
| 280 | hrtimer_start(&ds->timer, ktime_set(0, 0), HRTIMER_MODE_REL); | ||
| 281 | spin_unlock_irqrestore(&ds->irq_lock, irqflags); | ||
| 282 | return 0; | ||
| 283 | } | ||
| 284 | |||
| 285 | if (func == GPIO_EVENT_FUNC_INIT) { | ||
| 286 | if (ktime_to_ns(di->poll_time) <= 0) | ||
| 287 | di->poll_time = ktime_set(0, 20 * NSEC_PER_MSEC); | ||
| 288 | |||
| 289 | *data = ds = kzalloc(sizeof(*ds) + sizeof(ds->key_state[0]) * | ||
| 290 | di->keymap_size, GFP_KERNEL); | ||
| 291 | if (ds == NULL) { | ||
| 292 | ret = -ENOMEM; | ||
| 293 | pr_err("gpio_event_input_func: " | ||
| 294 | "Failed to allocate private data\n"); | ||
| 295 | goto err_ds_alloc_failed; | ||
| 296 | } | ||
| 297 | ds->debounce_count = di->keymap_size; | ||
| 298 | ds->input_devs = input_devs; | ||
| 299 | ds->info = di; | ||
| 300 | wake_lock_init(&ds->wake_lock, WAKE_LOCK_SUSPEND, "gpio_input"); | ||
| 301 | spin_lock_init(&ds->irq_lock); | ||
| 302 | |||
| 303 | for (i = 0; i < di->keymap_size; i++) { | ||
| 304 | int dev = di->keymap[i].dev; | ||
| 305 | if (dev >= input_devs->count) { | ||
| 306 | pr_err("gpio_event_input_func: bad device " | ||
| 307 | "index %d >= %d for key code %d\n", | ||
| 308 | dev, input_devs->count, | ||
| 309 | di->keymap[i].code); | ||
| 310 | ret = -EINVAL; | ||
| 311 | goto err_bad_keymap; | ||
| 312 | } | ||
| 313 | input_set_capability(input_devs->dev[dev], di->type, | ||
| 314 | di->keymap[i].code); | ||
| 315 | ds->key_state[i].ds = ds; | ||
| 316 | ds->key_state[i].debounce = DEBOUNCE_UNKNOWN; | ||
| 317 | } | ||
| 318 | |||
| 319 | for (i = 0; i < di->keymap_size; i++) { | ||
| 320 | ret = gpio_request(di->keymap[i].gpio, "gpio_kp_in"); | ||
| 321 | if (ret) { | ||
| 322 | pr_err("gpio_event_input_func: gpio_request " | ||
| 323 | "failed for %d\n", di->keymap[i].gpio); | ||
| 324 | goto err_gpio_request_failed; | ||
| 325 | } | ||
| 326 | ret = gpio_direction_input(di->keymap[i].gpio); | ||
| 327 | if (ret) { | ||
| 328 | pr_err("gpio_event_input_func: " | ||
| 329 | "gpio_direction_input failed for %d\n", | ||
| 330 | di->keymap[i].gpio); | ||
| 331 | goto err_gpio_configure_failed; | ||
| 332 | } | ||
| 333 | } | ||
| 334 | |||
| 335 | ret = gpio_event_input_request_irqs(ds); | ||
| 336 | |||
| 337 | spin_lock_irqsave(&ds->irq_lock, irqflags); | ||
| 338 | ds->use_irq = ret == 0; | ||
| 339 | |||
| 340 | pr_info("GPIO Input Driver: Start gpio inputs for %s%s in %s " | ||
| 341 | "mode\n", input_devs->dev[0]->name, | ||
| 342 | (input_devs->count > 1) ? "..." : "", | ||
| 343 | ret == 0 ? "interrupt" : "polling"); | ||
| 344 | |||
| 345 | hrtimer_init(&ds->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
| 346 | ds->timer.function = gpio_event_input_timer_func; | ||
| 347 | hrtimer_start(&ds->timer, ktime_set(0, 0), HRTIMER_MODE_REL); | ||
| 348 | spin_unlock_irqrestore(&ds->irq_lock, irqflags); | ||
| 349 | return 0; | ||
| 350 | } | ||
| 351 | |||
| 352 | ret = 0; | ||
| 353 | spin_lock_irqsave(&ds->irq_lock, irqflags); | ||
| 354 | hrtimer_cancel(&ds->timer); | ||
| 355 | if (ds->use_irq) { | ||
| 356 | for (i = di->keymap_size - 1; i >= 0; i--) { | ||
| 357 | int irq = gpio_to_irq(di->keymap[i].gpio); | ||
| 358 | if (ds->info->info.no_suspend) | ||
| 359 | disable_irq_wake(irq); | ||
| 360 | free_irq(irq, &ds->key_state[i]); | ||
| 361 | } | ||
| 362 | } | ||
| 363 | spin_unlock_irqrestore(&ds->irq_lock, irqflags); | ||
| 364 | |||
| 365 | for (i = di->keymap_size - 1; i >= 0; i--) { | ||
| 366 | err_gpio_configure_failed: | ||
| 367 | gpio_free(di->keymap[i].gpio); | ||
| 368 | err_gpio_request_failed: | ||
| 369 | ; | ||
| 370 | } | ||
| 371 | err_bad_keymap: | ||
| 372 | wake_lock_destroy(&ds->wake_lock); | ||
| 373 | kfree(ds); | ||
| 374 | err_ds_alloc_failed: | ||
| 375 | return ret; | ||
| 376 | } | ||
diff --git a/drivers/input/misc/gpio_matrix.c b/drivers/input/misc/gpio_matrix.c new file mode 100644 index 00000000000..eaa9e89d473 --- /dev/null +++ b/drivers/input/misc/gpio_matrix.c | |||
| @@ -0,0 +1,441 @@ | |||
| 1 | /* drivers/input/misc/gpio_matrix.c | ||
| 2 | * | ||
| 3 | * Copyright (C) 2007 Google, Inc. | ||
| 4 | * | ||
| 5 | * This software is licensed under the terms of the GNU General Public | ||
| 6 | * License version 2, as published by the Free Software Foundation, and | ||
| 7 | * may be copied, distributed, and modified under those terms. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/kernel.h> | ||
| 17 | #include <linux/gpio.h> | ||
| 18 | #include <linux/gpio_event.h> | ||
| 19 | #include <linux/hrtimer.h> | ||
| 20 | #include <linux/interrupt.h> | ||
| 21 | #include <linux/slab.h> | ||
| 22 | #include <linux/wakelock.h> | ||
| 23 | |||
| 24 | struct gpio_kp { | ||
| 25 | struct gpio_event_input_devs *input_devs; | ||
| 26 | struct gpio_event_matrix_info *keypad_info; | ||
| 27 | struct hrtimer timer; | ||
| 28 | struct wake_lock wake_lock; | ||
| 29 | int current_output; | ||
| 30 | unsigned int use_irq:1; | ||
| 31 | unsigned int key_state_changed:1; | ||
| 32 | unsigned int last_key_state_changed:1; | ||
| 33 | unsigned int some_keys_pressed:2; | ||
| 34 | unsigned int disabled_irq:1; | ||
| 35 | unsigned long keys_pressed[0]; | ||
| 36 | }; | ||
| 37 | |||
| 38 | static void clear_phantom_key(struct gpio_kp *kp, int out, int in) | ||
| 39 | { | ||
| 40 | struct gpio_event_matrix_info *mi = kp->keypad_info; | ||
| 41 | int key_index = out * mi->ninputs + in; | ||
| 42 | unsigned short keyentry = mi->keymap[key_index]; | ||
| 43 | unsigned short keycode = keyentry & MATRIX_KEY_MASK; | ||
| 44 | unsigned short dev = keyentry >> MATRIX_CODE_BITS; | ||
| 45 | |||
| 46 | if (!test_bit(keycode, kp->input_devs->dev[dev]->key)) { | ||
| 47 | if (mi->flags & GPIOKPF_PRINT_PHANTOM_KEYS) | ||
| 48 | pr_info("gpiomatrix: phantom key %x, %d-%d (%d-%d) " | ||
| 49 | "cleared\n", keycode, out, in, | ||
| 50 | mi->output_gpios[out], mi->input_gpios[in]); | ||
| 51 | __clear_bit(key_index, kp->keys_pressed); | ||
| 52 | } else { | ||
| 53 | if (mi->flags & GPIOKPF_PRINT_PHANTOM_KEYS) | ||
| 54 | pr_info("gpiomatrix: phantom key %x, %d-%d (%d-%d) " | ||
| 55 | "not cleared\n", keycode, out, in, | ||
| 56 | mi->output_gpios[out], mi->input_gpios[in]); | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | static int restore_keys_for_input(struct gpio_kp *kp, int out, int in) | ||
| 61 | { | ||
| 62 | int rv = 0; | ||
| 63 | int key_index; | ||
| 64 | |||
| 65 | key_index = out * kp->keypad_info->ninputs + in; | ||
| 66 | while (out < kp->keypad_info->noutputs) { | ||
| 67 | if (test_bit(key_index, kp->keys_pressed)) { | ||
| 68 | rv = 1; | ||
| 69 | clear_phantom_key(kp, out, in); | ||
| 70 | } | ||
| 71 | key_index += kp->keypad_info->ninputs; | ||
| 72 | out++; | ||
| 73 | } | ||
| 74 | return rv; | ||
| 75 | } | ||
| 76 | |||
| 77 | static void remove_phantom_keys(struct gpio_kp *kp) | ||
| 78 | { | ||
| 79 | int out, in, inp; | ||
| 80 | int key_index; | ||
| 81 | |||
| 82 | if (kp->some_keys_pressed < 3) | ||
| 83 | return; | ||
| 84 | |||
| 85 | for (out = 0; out < kp->keypad_info->noutputs; out++) { | ||
| 86 | inp = -1; | ||
| 87 | key_index = out * kp->keypad_info->ninputs; | ||
| 88 | for (in = 0; in < kp->keypad_info->ninputs; in++, key_index++) { | ||
| 89 | if (test_bit(key_index, kp->keys_pressed)) { | ||
| 90 | if (inp == -1) { | ||
| 91 | inp = in; | ||
| 92 | continue; | ||
| 93 | } | ||
| 94 | if (inp >= 0) { | ||
| 95 | if (!restore_keys_for_input(kp, out + 1, | ||
| 96 | inp)) | ||
| 97 | break; | ||
| 98 | clear_phantom_key(kp, out, inp); | ||
| 99 | inp = -2; | ||
| 100 | } | ||
| 101 | restore_keys_for_input(kp, out, in); | ||
| 102 | } | ||
| 103 | } | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 107 | static void report_key(struct gpio_kp *kp, int key_index, int out, int in) | ||
| 108 | { | ||
| 109 | struct gpio_event_matrix_info *mi = kp->keypad_info; | ||
| 110 | int pressed = test_bit(key_index, kp->keys_pressed); | ||
| 111 | unsigned short keyentry = mi->keymap[key_index]; | ||
| 112 | unsigned short keycode = keyentry & MATRIX_KEY_MASK; | ||
| 113 | unsigned short dev = keyentry >> MATRIX_CODE_BITS; | ||
| 114 | |||
| 115 | if (pressed != test_bit(keycode, kp->input_devs->dev[dev]->key)) { | ||
| 116 | if (keycode == KEY_RESERVED) { | ||
| 117 | if (mi->flags & GPIOKPF_PRINT_UNMAPPED_KEYS) | ||
| 118 | pr_info("gpiomatrix: unmapped key, %d-%d " | ||
| 119 | "(%d-%d) changed to %d\n", | ||
| 120 | out, in, mi->output_gpios[out], | ||
| 121 | mi->input_gpios[in], pressed); | ||
| 122 | } else { | ||
| 123 | if (mi->flags & GPIOKPF_PRINT_MAPPED_KEYS) | ||
| 124 | pr_info("gpiomatrix: key %x, %d-%d (%d-%d) " | ||
| 125 | "changed to %d\n", keycode, | ||
| 126 | out, in, mi->output_gpios[out], | ||
| 127 | mi->input_gpios[in], pressed); | ||
| 128 | input_report_key(kp->input_devs->dev[dev], keycode, pressed); | ||
| 129 | } | ||
| 130 | } | ||
| 131 | } | ||
| 132 | |||
| 133 | static void report_sync(struct gpio_kp *kp) | ||
| 134 | { | ||
| 135 | int i; | ||
| 136 | |||
| 137 | for (i = 0; i < kp->input_devs->count; i++) | ||
| 138 | input_sync(kp->input_devs->dev[i]); | ||
| 139 | } | ||
| 140 | |||
| 141 | static enum hrtimer_restart gpio_keypad_timer_func(struct hrtimer *timer) | ||
| 142 | { | ||
| 143 | int out, in; | ||
| 144 | int key_index; | ||
| 145 | int gpio; | ||
| 146 | struct gpio_kp *kp = container_of(timer, struct gpio_kp, timer); | ||
| 147 | struct gpio_event_matrix_info *mi = kp->keypad_info; | ||
| 148 | unsigned gpio_keypad_flags = mi->flags; | ||
| 149 | unsigned polarity = !!(gpio_keypad_flags & GPIOKPF_ACTIVE_HIGH); | ||
| 150 | |||
| 151 | out = kp->current_output; | ||
| 152 | if (out == mi->noutputs) { | ||
| 153 | out = 0; | ||
| 154 | kp->last_key_state_changed = kp->key_state_changed; | ||
| 155 | kp->key_state_changed = 0; | ||
| 156 | kp->some_keys_pressed = 0; | ||
| 157 | } else { | ||
| 158 | key_index = out * mi->ninputs; | ||
| 159 | for (in = 0; in < mi->ninputs; in++, key_index++) { | ||
| 160 | gpio = mi->input_gpios[in]; | ||
| 161 | if (gpio_get_value(gpio) ^ !polarity) { | ||
| 162 | if (kp->some_keys_pressed < 3) | ||
| 163 | kp->some_keys_pressed++; | ||
| 164 | kp->key_state_changed |= !__test_and_set_bit( | ||
| 165 | key_index, kp->keys_pressed); | ||
| 166 | } else | ||
| 167 | kp->key_state_changed |= __test_and_clear_bit( | ||
| 168 | key_index, kp->keys_pressed); | ||
| 169 | } | ||
| 170 | gpio = mi->output_gpios[out]; | ||
| 171 | if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE) | ||
| 172 | gpio_set_value(gpio, !polarity); | ||
| 173 | else | ||
| 174 | gpio_direction_input(gpio); | ||
| 175 | out++; | ||
| 176 | } | ||
| 177 | kp->current_output = out; | ||
| 178 | if (out < mi->noutputs) { | ||
| 179 | gpio = mi->output_gpios[out]; | ||
| 180 | if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE) | ||
| 181 | gpio_set_value(gpio, polarity); | ||
| 182 | else | ||
| 183 | gpio_direction_output(gpio, polarity); | ||
| 184 | hrtimer_start(timer, mi->settle_time, HRTIMER_MODE_REL); | ||
| 185 | return HRTIMER_NORESTART; | ||
| 186 | } | ||
| 187 | if (gpio_keypad_flags & GPIOKPF_DEBOUNCE) { | ||
| 188 | if (kp->key_state_changed) { | ||
| 189 | hrtimer_start(&kp->timer, mi->debounce_delay, | ||
| 190 | HRTIMER_MODE_REL); | ||
| 191 | return HRTIMER_NORESTART; | ||
| 192 | } | ||
| 193 | kp->key_state_changed = kp->last_key_state_changed; | ||
| 194 | } | ||
| 195 | if (kp->key_state_changed) { | ||
| 196 | if (gpio_keypad_flags & GPIOKPF_REMOVE_SOME_PHANTOM_KEYS) | ||
| 197 | remove_phantom_keys(kp); | ||
| 198 | key_index = 0; | ||
| 199 | for (out = 0; out < mi->noutputs; out++) | ||
| 200 | for (in = 0; in < mi->ninputs; in++, key_index++) | ||
| 201 | report_key(kp, key_index, out, in); | ||
| 202 | report_sync(kp); | ||
| 203 | } | ||
| 204 | if (!kp->use_irq || kp->some_keys_pressed) { | ||
| 205 | hrtimer_start(timer, mi->poll_time, HRTIMER_MODE_REL); | ||
| 206 | return HRTIMER_NORESTART; | ||
| 207 | } | ||
| 208 | |||
| 209 | /* No keys are pressed, reenable interrupt */ | ||
| 210 | for (out = 0; out < mi->noutputs; out++) { | ||
| 211 | if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE) | ||
| 212 | gpio_set_value(mi->output_gpios[out], polarity); | ||
| 213 | else | ||
| 214 | gpio_direction_output(mi->output_gpios[out], polarity); | ||
| 215 | } | ||
| 216 | for (in = 0; in < mi->ninputs; in++) | ||
| 217 | enable_irq(gpio_to_irq(mi->input_gpios[in])); | ||
| 218 | wake_unlock(&kp->wake_lock); | ||
| 219 | return HRTIMER_NORESTART; | ||
| 220 | } | ||
| 221 | |||
| 222 | static irqreturn_t gpio_keypad_irq_handler(int irq_in, void *dev_id) | ||
| 223 | { | ||
| 224 | int i; | ||
| 225 | struct gpio_kp *kp = dev_id; | ||
| 226 | struct gpio_event_matrix_info *mi = kp->keypad_info; | ||
| 227 | unsigned gpio_keypad_flags = mi->flags; | ||
| 228 | |||
| 229 | if (!kp->use_irq) { | ||
| 230 | /* ignore interrupt while registering the handler */ | ||
| 231 | kp->disabled_irq = 1; | ||
| 232 | disable_irq_nosync(irq_in); | ||
| 233 | return IRQ_HANDLED; | ||
| 234 | } | ||
| 235 | |||
| 236 | for (i = 0; i < mi->ninputs; i++) | ||
| 237 | disable_irq_nosync(gpio_to_irq(mi->input_gpios[i])); | ||
| 238 | for (i = 0; i < mi->noutputs; i++) { | ||
| 239 | if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE) | ||
| 240 | gpio_set_value(mi->output_gpios[i], | ||
| 241 | !(gpio_keypad_flags & GPIOKPF_ACTIVE_HIGH)); | ||
| 242 | else | ||
| 243 | gpio_direction_input(mi->output_gpios[i]); | ||
| 244 | } | ||
| 245 | wake_lock(&kp->wake_lock); | ||
| 246 | hrtimer_start(&kp->timer, ktime_set(0, 0), HRTIMER_MODE_REL); | ||
| 247 | return IRQ_HANDLED; | ||
| 248 | } | ||
| 249 | |||
| 250 | static int gpio_keypad_request_irqs(struct gpio_kp *kp) | ||
| 251 | { | ||
| 252 | int i; | ||
| 253 | int err; | ||
| 254 | unsigned int irq; | ||
| 255 | unsigned long request_flags; | ||
| 256 | struct gpio_event_matrix_info *mi = kp->keypad_info; | ||
| 257 | |||
| 258 | switch (mi->flags & (GPIOKPF_ACTIVE_HIGH|GPIOKPF_LEVEL_TRIGGERED_IRQ)) { | ||
| 259 | default: | ||
| 260 | request_flags = IRQF_TRIGGER_FALLING; | ||
| 261 | break; | ||
| 262 | case GPIOKPF_ACTIVE_HIGH: | ||
| 263 | request_flags = IRQF_TRIGGER_RISING; | ||
| 264 | break; | ||
| 265 | case GPIOKPF_LEVEL_TRIGGERED_IRQ: | ||
| 266 | request_flags = IRQF_TRIGGER_LOW; | ||
| 267 | break; | ||
| 268 | case GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_ACTIVE_HIGH: | ||
| 269 | request_flags = IRQF_TRIGGER_HIGH; | ||
| 270 | break; | ||
| 271 | } | ||
| 272 | |||
| 273 | for (i = 0; i < mi->ninputs; i++) { | ||
| 274 | err = irq = gpio_to_irq(mi->input_gpios[i]); | ||
| 275 | if (err < 0) | ||
| 276 | goto err_gpio_get_irq_num_failed; | ||
| 277 | err = request_irq(irq, gpio_keypad_irq_handler, request_flags, | ||
| 278 | "gpio_kp", kp); | ||
| 279 | if (err) { | ||
| 280 | pr_err("gpiomatrix: request_irq failed for input %d, " | ||
| 281 | "irq %d\n", mi->input_gpios[i], irq); | ||
| 282 | goto err_request_irq_failed; | ||
| 283 | } | ||
| 284 | err = enable_irq_wake(irq); | ||
| 285 | if (err) { | ||
| 286 | pr_err("gpiomatrix: set_irq_wake failed for input %d, " | ||
| 287 | "irq %d\n", mi->input_gpios[i], irq); | ||
| 288 | } | ||
| 289 | disable_irq(irq); | ||
| 290 | if (kp->disabled_irq) { | ||
| 291 | kp->disabled_irq = 0; | ||
| 292 | enable_irq(irq); | ||
| 293 | } | ||
| 294 | } | ||
| 295 | return 0; | ||
| 296 | |||
| 297 | for (i = mi->noutputs - 1; i >= 0; i--) { | ||
| 298 | free_irq(gpio_to_irq(mi->input_gpios[i]), kp); | ||
| 299 | err_request_irq_failed: | ||
| 300 | err_gpio_get_irq_num_failed: | ||
| 301 | ; | ||
| 302 | } | ||
| 303 | return err; | ||
| 304 | } | ||
| 305 | |||
| 306 | int gpio_event_matrix_func(struct gpio_event_input_devs *input_devs, | ||
| 307 | struct gpio_event_info *info, void **data, int func) | ||
| 308 | { | ||
| 309 | int i; | ||
| 310 | int err; | ||
| 311 | int key_count; | ||
| 312 | struct gpio_kp *kp; | ||
| 313 | struct gpio_event_matrix_info *mi; | ||
| 314 | |||
| 315 | mi = container_of(info, struct gpio_event_matrix_info, info); | ||
| 316 | if (func == GPIO_EVENT_FUNC_SUSPEND || func == GPIO_EVENT_FUNC_RESUME) { | ||
| 317 | /* TODO: disable scanning */ | ||
| 318 | return 0; | ||
| 319 | } | ||
| 320 | |||
| 321 | if (func == GPIO_EVENT_FUNC_INIT) { | ||
| 322 | if (mi->keymap == NULL || | ||
| 323 | mi->input_gpios == NULL || | ||
| 324 | mi->output_gpios == NULL) { | ||
| 325 | err = -ENODEV; | ||
| 326 | pr_err("gpiomatrix: Incomplete pdata\n"); | ||
| 327 | goto err_invalid_platform_data; | ||
| 328 | } | ||
| 329 | key_count = mi->ninputs * mi->noutputs; | ||
| 330 | |||
| 331 | *data = kp = kzalloc(sizeof(*kp) + sizeof(kp->keys_pressed[0]) * | ||
| 332 | BITS_TO_LONGS(key_count), GFP_KERNEL); | ||
| 333 | if (kp == NULL) { | ||
| 334 | err = -ENOMEM; | ||
| 335 | pr_err("gpiomatrix: Failed to allocate private data\n"); | ||
| 336 | goto err_kp_alloc_failed; | ||
| 337 | } | ||
| 338 | kp->input_devs = input_devs; | ||
| 339 | kp->keypad_info = mi; | ||
| 340 | for (i = 0; i < key_count; i++) { | ||
| 341 | unsigned short keyentry = mi->keymap[i]; | ||
| 342 | unsigned short keycode = keyentry & MATRIX_KEY_MASK; | ||
| 343 | unsigned short dev = keyentry >> MATRIX_CODE_BITS; | ||
| 344 | if (dev >= input_devs->count) { | ||
| 345 | pr_err("gpiomatrix: bad device index %d >= " | ||
| 346 | "%d for key code %d\n", | ||
| 347 | dev, input_devs->count, keycode); | ||
| 348 | err = -EINVAL; | ||
| 349 | goto err_bad_keymap; | ||
| 350 | } | ||
| 351 | if (keycode && keycode <= KEY_MAX) | ||
| 352 | input_set_capability(input_devs->dev[dev], | ||
| 353 | EV_KEY, keycode); | ||
| 354 | } | ||
| 355 | |||
| 356 | for (i = 0; i < mi->noutputs; i++) { | ||
| 357 | err = gpio_request(mi->output_gpios[i], "gpio_kp_out"); | ||
| 358 | if (err) { | ||
| 359 | pr_err("gpiomatrix: gpio_request failed for " | ||
| 360 | "output %d\n", mi->output_gpios[i]); | ||
| 361 | goto err_request_output_gpio_failed; | ||
| 362 | } | ||
| 363 | if (gpio_cansleep(mi->output_gpios[i])) { | ||
| 364 | pr_err("gpiomatrix: unsupported output gpio %d," | ||
| 365 | " can sleep\n", mi->output_gpios[i]); | ||
| 366 | err = -EINVAL; | ||
| 367 | goto err_output_gpio_configure_failed; | ||
| 368 | } | ||
| 369 | if (mi->flags & GPIOKPF_DRIVE_INACTIVE) | ||
| 370 | err = gpio_direction_output(mi->output_gpios[i], | ||
| 371 | !(mi->flags & GPIOKPF_ACTIVE_HIGH)); | ||
| 372 | else | ||
| 373 | err = gpio_direction_input(mi->output_gpios[i]); | ||
| 374 | if (err) { | ||
| 375 | pr_err("gpiomatrix: gpio_configure failed for " | ||
| 376 | "output %d\n", mi->output_gpios[i]); | ||
| 377 | goto err_output_gpio_configure_failed; | ||
| 378 | } | ||
| 379 | } | ||
| 380 | for (i = 0; i < mi->ninputs; i++) { | ||
| 381 | err = gpio_request(mi->input_gpios[i], "gpio_kp_in"); | ||
| 382 | if (err) { | ||
| 383 | pr_err("gpiomatrix: gpio_request failed for " | ||
| 384 | "input %d\n", mi->input_gpios[i]); | ||
| 385 | goto err_request_input_gpio_failed; | ||
| 386 | } | ||
| 387 | err = gpio_direction_input(mi->input_gpios[i]); | ||
| 388 | if (err) { | ||
| 389 | pr_err("gpiomatrix: gpio_direction_input failed" | ||
| 390 | " for input %d\n", mi->input_gpios[i]); | ||
| 391 | goto err_gpio_direction_input_failed; | ||
| 392 | } | ||
| 393 | } | ||
| 394 | kp->current_output = mi->noutputs; | ||
| 395 | kp->key_state_changed = 1; | ||
| 396 | |||
| 397 | hrtimer_init(&kp->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
| 398 | kp->timer.function = gpio_keypad_timer_func; | ||
| 399 | wake_lock_init(&kp->wake_lock, WAKE_LOCK_SUSPEND, "gpio_kp"); | ||
| 400 | err = gpio_keypad_request_irqs(kp); | ||
| 401 | kp->use_irq = err == 0; | ||
| 402 | |||
| 403 | pr_info("GPIO Matrix Keypad Driver: Start keypad matrix for " | ||
| 404 | "%s%s in %s mode\n", input_devs->dev[0]->name, | ||
| 405 | (input_devs->count > 1) ? "..." : "", | ||
| 406 | kp->use_irq ? "interrupt" : "polling"); | ||
| 407 | |||
| 408 | if (kp->use_irq) | ||
| 409 | wake_lock(&kp->wake_lock); | ||
| 410 | hrtimer_start(&kp->timer, ktime_set(0, 0), HRTIMER_MODE_REL); | ||
| 411 | |||
| 412 | return 0; | ||
| 413 | } | ||
| 414 | |||
| 415 | err = 0; | ||
| 416 | kp = *data; | ||
| 417 | |||
| 418 | if (kp->use_irq) | ||
| 419 | for (i = mi->noutputs - 1; i >= 0; i--) | ||
| 420 | free_irq(gpio_to_irq(mi->input_gpios[i]), kp); | ||
| 421 | |||
| 422 | hrtimer_cancel(&kp->timer); | ||
| 423 | wake_lock_destroy(&kp->wake_lock); | ||
| 424 | for (i = mi->noutputs - 1; i >= 0; i--) { | ||
| 425 | err_gpio_direction_input_failed: | ||
| 426 | gpio_free(mi->input_gpios[i]); | ||
| 427 | err_request_input_gpio_failed: | ||
| 428 | ; | ||
| 429 | } | ||
| 430 | for (i = mi->noutputs - 1; i >= 0; i--) { | ||
| 431 | err_output_gpio_configure_failed: | ||
| 432 | gpio_free(mi->output_gpios[i]); | ||
| 433 | err_request_output_gpio_failed: | ||
| 434 | ; | ||
| 435 | } | ||
| 436 | err_bad_keymap: | ||
| 437 | kfree(kp); | ||
| 438 | err_kp_alloc_failed: | ||
| 439 | err_invalid_platform_data: | ||
| 440 | return err; | ||
| 441 | } | ||
diff --git a/drivers/input/misc/gpio_output.c b/drivers/input/misc/gpio_output.c new file mode 100644 index 00000000000..2aac2fad0a1 --- /dev/null +++ b/drivers/input/misc/gpio_output.c | |||
| @@ -0,0 +1,97 @@ | |||
| 1 | /* drivers/input/misc/gpio_output.c | ||
| 2 | * | ||
| 3 | * Copyright (C) 2007 Google, Inc. | ||
| 4 | * | ||
| 5 | * This software is licensed under the terms of the GNU General Public | ||
| 6 | * License version 2, as published by the Free Software Foundation, and | ||
| 7 | * may be copied, distributed, and modified under those terms. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/kernel.h> | ||
| 17 | #include <linux/gpio.h> | ||
| 18 | #include <linux/gpio_event.h> | ||
| 19 | |||
| 20 | int gpio_event_output_event( | ||
| 21 | struct gpio_event_input_devs *input_devs, struct gpio_event_info *info, | ||
| 22 | void **data, unsigned int dev, unsigned int type, | ||
| 23 | unsigned int code, int value) | ||
| 24 | { | ||
| 25 | int i; | ||
| 26 | struct gpio_event_output_info *oi; | ||
| 27 | oi = container_of(info, struct gpio_event_output_info, info); | ||
| 28 | if (type != oi->type) | ||
| 29 | return 0; | ||
| 30 | if (!(oi->flags & GPIOEDF_ACTIVE_HIGH)) | ||
| 31 | value = !value; | ||
| 32 | for (i = 0; i < oi->keymap_size; i++) | ||
| 33 | if (dev == oi->keymap[i].dev && code == oi->keymap[i].code) | ||
| 34 | gpio_set_value(oi->keymap[i].gpio, value); | ||
| 35 | return 0; | ||
| 36 | } | ||
| 37 | |||
| 38 | int gpio_event_output_func( | ||
| 39 | struct gpio_event_input_devs *input_devs, struct gpio_event_info *info, | ||
| 40 | void **data, int func) | ||
| 41 | { | ||
| 42 | int ret; | ||
| 43 | int i; | ||
| 44 | struct gpio_event_output_info *oi; | ||
| 45 | oi = container_of(info, struct gpio_event_output_info, info); | ||
| 46 | |||
| 47 | if (func == GPIO_EVENT_FUNC_SUSPEND || func == GPIO_EVENT_FUNC_RESUME) | ||
| 48 | return 0; | ||
| 49 | |||
| 50 | if (func == GPIO_EVENT_FUNC_INIT) { | ||
| 51 | int output_level = !(oi->flags & GPIOEDF_ACTIVE_HIGH); | ||
| 52 | |||
| 53 | for (i = 0; i < oi->keymap_size; i++) { | ||
| 54 | int dev = oi->keymap[i].dev; | ||
| 55 | if (dev >= input_devs->count) { | ||
| 56 | pr_err("gpio_event_output_func: bad device " | ||
| 57 | "index %d >= %d for key code %d\n", | ||
| 58 | dev, input_devs->count, | ||
| 59 | oi->keymap[i].code); | ||
| 60 | ret = -EINVAL; | ||
| 61 | goto err_bad_keymap; | ||
| 62 | } | ||
| 63 | input_set_capability(input_devs->dev[dev], oi->type, | ||
| 64 | oi->keymap[i].code); | ||
| 65 | } | ||
| 66 | |||
| 67 | for (i = 0; i < oi->keymap_size; i++) { | ||
| 68 | ret = gpio_request(oi->keymap[i].gpio, | ||
| 69 | "gpio_event_output"); | ||
| 70 | if (ret) { | ||
| 71 | pr_err("gpio_event_output_func: gpio_request " | ||
| 72 | "failed for %d\n", oi->keymap[i].gpio); | ||
| 73 | goto err_gpio_request_failed; | ||
| 74 | } | ||
| 75 | ret = gpio_direction_output(oi->keymap[i].gpio, | ||
| 76 | output_level); | ||
| 77 | if (ret) { | ||
| 78 | pr_err("gpio_event_output_func: " | ||
| 79 | "gpio_direction_output failed for %d\n", | ||
| 80 | oi->keymap[i].gpio); | ||
| 81 | goto err_gpio_direction_output_failed; | ||
| 82 | } | ||
| 83 | } | ||
| 84 | return 0; | ||
| 85 | } | ||
| 86 | |||
| 87 | ret = 0; | ||
| 88 | for (i = oi->keymap_size - 1; i >= 0; i--) { | ||
| 89 | err_gpio_direction_output_failed: | ||
| 90 | gpio_free(oi->keymap[i].gpio); | ||
| 91 | err_gpio_request_failed: | ||
| 92 | ; | ||
| 93 | } | ||
| 94 | err_bad_keymap: | ||
| 95 | return ret; | ||
| 96 | } | ||
| 97 | |||
diff --git a/drivers/input/misc/keychord.c b/drivers/input/misc/keychord.c new file mode 100644 index 00000000000..3ffab6da411 --- /dev/null +++ b/drivers/input/misc/keychord.c | |||
| @@ -0,0 +1,387 @@ | |||
| 1 | /* | ||
| 2 | * drivers/input/misc/keychord.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008 Google, Inc. | ||
| 5 | * Author: Mike Lockwood <lockwood@android.com> | ||
| 6 | * | ||
| 7 | * This software is licensed under the terms of the GNU General Public | ||
| 8 | * License version 2, as published by the Free Software Foundation, and | ||
| 9 | * may be copied, distributed, and modified under those terms. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include <linux/poll.h> | ||
| 19 | #include <linux/slab.h> | ||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/init.h> | ||
| 22 | #include <linux/spinlock.h> | ||
| 23 | #include <linux/fs.h> | ||
| 24 | #include <linux/miscdevice.h> | ||
| 25 | #include <linux/keychord.h> | ||
| 26 | #include <linux/sched.h> | ||
| 27 | |||
| 28 | #define KEYCHORD_NAME "keychord" | ||
| 29 | #define BUFFER_SIZE 16 | ||
| 30 | |||
| 31 | MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>"); | ||
| 32 | MODULE_DESCRIPTION("Key chord input driver"); | ||
| 33 | MODULE_SUPPORTED_DEVICE("keychord"); | ||
| 34 | MODULE_LICENSE("GPL"); | ||
| 35 | |||
| 36 | #define NEXT_KEYCHORD(kc) ((struct input_keychord *) \ | ||
| 37 | ((char *)kc + sizeof(struct input_keychord) + \ | ||
| 38 | kc->count * sizeof(kc->keycodes[0]))) | ||
| 39 | |||
| 40 | struct keychord_device { | ||
| 41 | struct input_handler input_handler; | ||
| 42 | int registered; | ||
| 43 | |||
| 44 | /* list of keychords to monitor */ | ||
| 45 | struct input_keychord *keychords; | ||
| 46 | int keychord_count; | ||
| 47 | |||
| 48 | /* bitmask of keys contained in our keychords */ | ||
| 49 | unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; | ||
| 50 | /* current state of the keys */ | ||
| 51 | unsigned long keystate[BITS_TO_LONGS(KEY_CNT)]; | ||
| 52 | /* number of keys that are currently pressed */ | ||
| 53 | int key_down; | ||
| 54 | |||
| 55 | /* second input_device_id is needed for null termination */ | ||
| 56 | struct input_device_id device_ids[2]; | ||
| 57 | |||
| 58 | spinlock_t lock; | ||
| 59 | wait_queue_head_t waitq; | ||
| 60 | unsigned char head; | ||
| 61 | unsigned char tail; | ||
| 62 | __u16 buff[BUFFER_SIZE]; | ||
| 63 | }; | ||
| 64 | |||
| 65 | static int check_keychord(struct keychord_device *kdev, | ||
| 66 | struct input_keychord *keychord) | ||
| 67 | { | ||
| 68 | int i; | ||
| 69 | |||
| 70 | if (keychord->count != kdev->key_down) | ||
| 71 | return 0; | ||
| 72 | |||
| 73 | for (i = 0; i < keychord->count; i++) { | ||
| 74 | if (!test_bit(keychord->keycodes[i], kdev->keystate)) | ||
| 75 | return 0; | ||
| 76 | } | ||
| 77 | |||
| 78 | /* we have a match */ | ||
| 79 | return 1; | ||
| 80 | } | ||
| 81 | |||
| 82 | static void keychord_event(struct input_handle *handle, unsigned int type, | ||
| 83 | unsigned int code, int value) | ||
| 84 | { | ||
| 85 | struct keychord_device *kdev = handle->private; | ||
| 86 | struct input_keychord *keychord; | ||
| 87 | unsigned long flags; | ||
| 88 | int i, got_chord = 0; | ||
| 89 | |||
| 90 | if (type != EV_KEY || code >= KEY_MAX) | ||
| 91 | return; | ||
| 92 | |||
| 93 | spin_lock_irqsave(&kdev->lock, flags); | ||
| 94 | /* do nothing if key state did not change */ | ||
| 95 | if (!test_bit(code, kdev->keystate) == !value) | ||
| 96 | goto done; | ||
| 97 | __change_bit(code, kdev->keystate); | ||
| 98 | if (value) | ||
| 99 | kdev->key_down++; | ||
| 100 | else | ||
| 101 | kdev->key_down--; | ||
| 102 | |||
| 103 | /* don't notify on key up */ | ||
| 104 | if (!value) | ||
| 105 | goto done; | ||
| 106 | /* ignore this event if it is not one of the keys we are monitoring */ | ||
| 107 | if (!test_bit(code, kdev->keybit)) | ||
| 108 | goto done; | ||
| 109 | |||
| 110 | keychord = kdev->keychords; | ||
| 111 | if (!keychord) | ||
| 112 | goto done; | ||
| 113 | |||
| 114 | /* check to see if the keyboard state matches any keychords */ | ||
| 115 | for (i = 0; i < kdev->keychord_count; i++) { | ||
| 116 | if (check_keychord(kdev, keychord)) { | ||
| 117 | kdev->buff[kdev->head] = keychord->id; | ||
| 118 | kdev->head = (kdev->head + 1) % BUFFER_SIZE; | ||
| 119 | got_chord = 1; | ||
| 120 | break; | ||
| 121 | } | ||
| 122 | /* skip to next keychord */ | ||
| 123 | keychord = NEXT_KEYCHORD(keychord); | ||
| 124 | } | ||
| 125 | |||
| 126 | done: | ||
| 127 | spin_unlock_irqrestore(&kdev->lock, flags); | ||
| 128 | |||
| 129 | if (got_chord) | ||
| 130 | wake_up_interruptible(&kdev->waitq); | ||
| 131 | } | ||
| 132 | |||
| 133 | static int keychord_connect(struct input_handler *handler, | ||
| 134 | struct input_dev *dev, | ||
| 135 | const struct input_device_id *id) | ||
| 136 | { | ||
| 137 | int i, ret; | ||
| 138 | struct input_handle *handle; | ||
| 139 | struct keychord_device *kdev = | ||
| 140 | container_of(handler, struct keychord_device, input_handler); | ||
| 141 | |||
| 142 | /* | ||
| 143 | * ignore this input device if it does not contain any keycodes | ||
| 144 | * that we are monitoring | ||
| 145 | */ | ||
| 146 | for (i = 0; i < KEY_MAX; i++) { | ||
| 147 | if (test_bit(i, kdev->keybit) && test_bit(i, dev->keybit)) | ||
| 148 | break; | ||
| 149 | } | ||
| 150 | if (i == KEY_MAX) | ||
| 151 | return -ENODEV; | ||
| 152 | |||
| 153 | handle = kzalloc(sizeof(*handle), GFP_KERNEL); | ||
| 154 | if (!handle) | ||
| 155 | return -ENOMEM; | ||
| 156 | |||
| 157 | handle->dev = dev; | ||
| 158 | handle->handler = handler; | ||
| 159 | handle->name = KEYCHORD_NAME; | ||
| 160 | handle->private = kdev; | ||
| 161 | |||
| 162 | ret = input_register_handle(handle); | ||
| 163 | if (ret) | ||
| 164 | goto err_input_register_handle; | ||
| 165 | |||
| 166 | ret = input_open_device(handle); | ||
| 167 | if (ret) | ||
| 168 | goto err_input_open_device; | ||
| 169 | |||
| 170 | pr_info("keychord: using input dev %s for fevent\n", dev->name); | ||
| 171 | |||
| 172 | return 0; | ||
| 173 | |||
| 174 | err_input_open_device: | ||
| 175 | input_unregister_handle(handle); | ||
| 176 | err_input_register_handle: | ||
| 177 | kfree(handle); | ||
| 178 | return ret; | ||
| 179 | } | ||
| 180 | |||
| 181 | static void keychord_disconnect(struct input_handle *handle) | ||
| 182 | { | ||
| 183 | input_close_device(handle); | ||
| 184 | input_unregister_handle(handle); | ||
| 185 | kfree(handle); | ||
| 186 | } | ||
| 187 | |||
| 188 | /* | ||
| 189 | * keychord_read is used to read keychord events from the driver | ||
| 190 | */ | ||
| 191 | static ssize_t keychord_read(struct file *file, char __user *buffer, | ||
| 192 | size_t count, loff_t *ppos) | ||
| 193 | { | ||
| 194 | struct keychord_device *kdev = file->private_data; | ||
| 195 | __u16 id; | ||
| 196 | int retval; | ||
| 197 | unsigned long flags; | ||
| 198 | |||
| 199 | if (count < sizeof(id)) | ||
| 200 | return -EINVAL; | ||
| 201 | count = sizeof(id); | ||
| 202 | |||
| 203 | if (kdev->head == kdev->tail && (file->f_flags & O_NONBLOCK)) | ||
| 204 | return -EAGAIN; | ||
| 205 | |||
| 206 | retval = wait_event_interruptible(kdev->waitq, | ||
| 207 | kdev->head != kdev->tail); | ||
| 208 | if (retval) | ||
| 209 | return retval; | ||
| 210 | |||
| 211 | spin_lock_irqsave(&kdev->lock, flags); | ||
| 212 | /* pop a keychord ID off the queue */ | ||
| 213 | id = kdev->buff[kdev->tail]; | ||
| 214 | kdev->tail = (kdev->tail + 1) % BUFFER_SIZE; | ||
| 215 | spin_unlock_irqrestore(&kdev->lock, flags); | ||
| 216 | |||
| 217 | if (copy_to_user(buffer, &id, count)) | ||
| 218 | return -EFAULT; | ||
| 219 | |||
| 220 | return count; | ||
| 221 | } | ||
| 222 | |||
| 223 | /* | ||
| 224 | * keychord_write is used to configure the driver | ||
| 225 | */ | ||
| 226 | static ssize_t keychord_write(struct file *file, const char __user *buffer, | ||
| 227 | size_t count, loff_t *ppos) | ||
| 228 | { | ||
| 229 | struct keychord_device *kdev = file->private_data; | ||
| 230 | struct input_keychord *keychords = 0; | ||
| 231 | struct input_keychord *keychord, *next, *end; | ||
| 232 | int ret, i, key; | ||
| 233 | unsigned long flags; | ||
| 234 | |||
| 235 | if (count < sizeof(struct input_keychord)) | ||
| 236 | return -EINVAL; | ||
| 237 | keychords = kzalloc(count, GFP_KERNEL); | ||
| 238 | if (!keychords) | ||
| 239 | return -ENOMEM; | ||
| 240 | |||
| 241 | /* read list of keychords from userspace */ | ||
| 242 | if (copy_from_user(keychords, buffer, count)) { | ||
| 243 | kfree(keychords); | ||
| 244 | return -EFAULT; | ||
| 245 | } | ||
| 246 | |||
| 247 | /* unregister handler before changing configuration */ | ||
| 248 | if (kdev->registered) { | ||
| 249 | input_unregister_handler(&kdev->input_handler); | ||
| 250 | kdev->registered = 0; | ||
| 251 | } | ||
| 252 | |||
| 253 | spin_lock_irqsave(&kdev->lock, flags); | ||
| 254 | /* clear any existing configuration */ | ||
| 255 | kfree(kdev->keychords); | ||
| 256 | kdev->keychords = 0; | ||
| 257 | kdev->keychord_count = 0; | ||
| 258 | kdev->key_down = 0; | ||
| 259 | memset(kdev->keybit, 0, sizeof(kdev->keybit)); | ||
| 260 | memset(kdev->keystate, 0, sizeof(kdev->keystate)); | ||
| 261 | kdev->head = kdev->tail = 0; | ||
| 262 | |||
| 263 | keychord = keychords; | ||
| 264 | end = (struct input_keychord *)((char *)keychord + count); | ||
| 265 | |||
| 266 | while (keychord < end) { | ||
| 267 | next = NEXT_KEYCHORD(keychord); | ||
| 268 | if (keychord->count <= 0 || next > end) { | ||
| 269 | pr_err("keychord: invalid keycode count %d\n", | ||
| 270 | keychord->count); | ||
| 271 | goto err_unlock_return; | ||
| 272 | } | ||
| 273 | if (keychord->version != KEYCHORD_VERSION) { | ||
| 274 | pr_err("keychord: unsupported version %d\n", | ||
| 275 | keychord->version); | ||
| 276 | goto err_unlock_return; | ||
| 277 | } | ||
| 278 | |||
| 279 | /* keep track of the keys we are monitoring in keybit */ | ||
| 280 | for (i = 0; i < keychord->count; i++) { | ||
| 281 | key = keychord->keycodes[i]; | ||
| 282 | if (key < 0 || key >= KEY_CNT) { | ||
| 283 | pr_err("keychord: keycode %d out of range\n", | ||
| 284 | key); | ||
| 285 | goto err_unlock_return; | ||
| 286 | } | ||
| 287 | __set_bit(key, kdev->keybit); | ||
| 288 | } | ||
| 289 | |||
| 290 | kdev->keychord_count++; | ||
| 291 | keychord = next; | ||
| 292 | } | ||
| 293 | |||
| 294 | kdev->keychords = keychords; | ||
| 295 | spin_unlock_irqrestore(&kdev->lock, flags); | ||
| 296 | |||
| 297 | ret = input_register_handler(&kdev->input_handler); | ||
| 298 | if (ret) { | ||
| 299 | kfree(keychords); | ||
| 300 | kdev->keychords = 0; | ||
| 301 | return ret; | ||
| 302 | } | ||
| 303 | kdev->registered = 1; | ||
| 304 | |||
| 305 | return count; | ||
| 306 | |||
| 307 | err_unlock_return: | ||
| 308 | spin_unlock_irqrestore(&kdev->lock, flags); | ||
| 309 | kfree(keychords); | ||
| 310 | return -EINVAL; | ||
| 311 | } | ||
| 312 | |||
| 313 | static unsigned int keychord_poll(struct file *file, poll_table *wait) | ||
| 314 | { | ||
| 315 | struct keychord_device *kdev = file->private_data; | ||
| 316 | |||
| 317 | poll_wait(file, &kdev->waitq, wait); | ||
| 318 | |||
| 319 | if (kdev->head != kdev->tail) | ||
| 320 | return POLLIN | POLLRDNORM; | ||
| 321 | |||
| 322 | return 0; | ||
| 323 | } | ||
| 324 | |||
| 325 | static int keychord_open(struct inode *inode, struct file *file) | ||
| 326 | { | ||
| 327 | struct keychord_device *kdev; | ||
| 328 | |||
| 329 | kdev = kzalloc(sizeof(struct keychord_device), GFP_KERNEL); | ||
| 330 | if (!kdev) | ||
| 331 | return -ENOMEM; | ||
| 332 | |||
| 333 | spin_lock_init(&kdev->lock); | ||
| 334 | init_waitqueue_head(&kdev->waitq); | ||
| 335 | |||
| 336 | kdev->input_handler.event = keychord_event; | ||
| 337 | kdev->input_handler.connect = keychord_connect; | ||
| 338 | kdev->input_handler.disconnect = keychord_disconnect; | ||
| 339 | kdev->input_handler.name = KEYCHORD_NAME; | ||
| 340 | kdev->input_handler.id_table = kdev->device_ids; | ||
| 341 | |||
| 342 | kdev->device_ids[0].flags = INPUT_DEVICE_ID_MATCH_EVBIT; | ||
| 343 | __set_bit(EV_KEY, kdev->device_ids[0].evbit); | ||
| 344 | |||
| 345 | file->private_data = kdev; | ||
| 346 | |||
| 347 | return 0; | ||
| 348 | } | ||
| 349 | |||
| 350 | static int keychord_release(struct inode *inode, struct file *file) | ||
| 351 | { | ||
| 352 | struct keychord_device *kdev = file->private_data; | ||
| 353 | |||
| 354 | if (kdev->registered) | ||
| 355 | input_unregister_handler(&kdev->input_handler); | ||
| 356 | kfree(kdev); | ||
| 357 | |||
| 358 | return 0; | ||
| 359 | } | ||
| 360 | |||
| 361 | static const struct file_operations keychord_fops = { | ||
| 362 | .owner = THIS_MODULE, | ||
| 363 | .open = keychord_open, | ||
| 364 | .release = keychord_release, | ||
| 365 | .read = keychord_read, | ||
| 366 | .write = keychord_write, | ||
| 367 | .poll = keychord_poll, | ||
| 368 | }; | ||
| 369 | |||
| 370 | static struct miscdevice keychord_misc = { | ||
| 371 | .fops = &keychord_fops, | ||
| 372 | .name = KEYCHORD_NAME, | ||
| 373 | .minor = MISC_DYNAMIC_MINOR, | ||
| 374 | }; | ||
| 375 | |||
| 376 | static int __init keychord_init(void) | ||
| 377 | { | ||
| 378 | return misc_register(&keychord_misc); | ||
| 379 | } | ||
| 380 | |||
| 381 | static void __exit keychord_exit(void) | ||
| 382 | { | ||
| 383 | misc_deregister(&keychord_misc); | ||
| 384 | } | ||
| 385 | |||
| 386 | module_init(keychord_init); | ||
| 387 | module_exit(keychord_exit); | ||
