root/drivers/hid/hid-picolcd_core.c

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

DEFINITIONS

This source file includes following definitions.
  1. picolcd_report
  2. picolcd_send_and_wait
  3. picolcd_raw_keypad
  4. picolcd_check_version
  5. picolcd_reset
  6. picolcd_operation_mode_show
  7. picolcd_operation_mode_store
  8. picolcd_operation_mode_delay_show
  9. picolcd_operation_mode_delay_store
  10. picolcd_raw_event
  11. picolcd_suspend
  12. picolcd_resume
  13. picolcd_reset_resume
  14. picolcd_init_keys
  15. picolcd_exit_keys
  16. picolcd_probe_lcd
  17. picolcd_probe_bootloader
  18. picolcd_probe
  19. picolcd_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /***************************************************************************
   3  *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
   4  *                                                                         *
   5  *   Based on Logitech G13 driver (v0.4)                                   *
   6  *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
   7  *                                                                         *
   8  ***************************************************************************/
   9 
  10 #include <linux/hid.h>
  11 #include <linux/hid-debug.h>
  12 #include <linux/input.h>
  13 #include "hid-ids.h"
  14 
  15 #include <linux/fb.h>
  16 #include <linux/vmalloc.h>
  17 
  18 #include <linux/completion.h>
  19 #include <linux/uaccess.h>
  20 #include <linux/module.h>
  21 #include <linux/string.h>
  22 
  23 #include "hid-picolcd.h"
  24 
  25 
  26 /* Input device
  27  *
  28  * The PicoLCD has an IR receiver header, a built-in keypad with 5 keys
  29  * and header for 4x4 key matrix. The built-in keys are part of the matrix.
  30  */
  31 static const unsigned short def_keymap[PICOLCD_KEYS] = {
  32         KEY_RESERVED,   /* none */
  33         KEY_BACK,       /* col 4 + row 1 */
  34         KEY_HOMEPAGE,   /* col 3 + row 1 */
  35         KEY_RESERVED,   /* col 2 + row 1 */
  36         KEY_RESERVED,   /* col 1 + row 1 */
  37         KEY_SCROLLUP,   /* col 4 + row 2 */
  38         KEY_OK,         /* col 3 + row 2 */
  39         KEY_SCROLLDOWN, /* col 2 + row 2 */
  40         KEY_RESERVED,   /* col 1 + row 2 */
  41         KEY_RESERVED,   /* col 4 + row 3 */
  42         KEY_RESERVED,   /* col 3 + row 3 */
  43         KEY_RESERVED,   /* col 2 + row 3 */
  44         KEY_RESERVED,   /* col 1 + row 3 */
  45         KEY_RESERVED,   /* col 4 + row 4 */
  46         KEY_RESERVED,   /* col 3 + row 4 */
  47         KEY_RESERVED,   /* col 2 + row 4 */
  48         KEY_RESERVED,   /* col 1 + row 4 */
  49 };
  50 
  51 
  52 /* Find a given report */
  53 struct hid_report *picolcd_report(int id, struct hid_device *hdev, int dir)
  54 {
  55         struct list_head *feature_report_list = &hdev->report_enum[dir].report_list;
  56         struct hid_report *report = NULL;
  57 
  58         list_for_each_entry(report, feature_report_list, list) {
  59                 if (report->id == id)
  60                         return report;
  61         }
  62         hid_warn(hdev, "No report with id 0x%x found\n", id);
  63         return NULL;
  64 }
  65 
  66 /* Submit a report and wait for a reply from device - if device fades away
  67  * or does not respond in time, return NULL */
  68 struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev,
  69                 int report_id, const u8 *raw_data, int size)
  70 {
  71         struct picolcd_data *data = hid_get_drvdata(hdev);
  72         struct picolcd_pending *work;
  73         struct hid_report *report = picolcd_out_report(report_id, hdev);
  74         unsigned long flags;
  75         int i, j, k;
  76 
  77         if (!report || !data)
  78                 return NULL;
  79         if (data->status & PICOLCD_FAILED)
  80                 return NULL;
  81         work = kzalloc(sizeof(*work), GFP_KERNEL);
  82         if (!work)
  83                 return NULL;
  84 
  85         init_completion(&work->ready);
  86         work->out_report = report;
  87         work->in_report  = NULL;
  88         work->raw_size   = 0;
  89 
  90         mutex_lock(&data->mutex);
  91         spin_lock_irqsave(&data->lock, flags);
  92         for (i = k = 0; i < report->maxfield; i++)
  93                 for (j = 0; j < report->field[i]->report_count; j++) {
  94                         hid_set_field(report->field[i], j, k < size ? raw_data[k] : 0);
  95                         k++;
  96                 }
  97         if (data->status & PICOLCD_FAILED) {
  98                 kfree(work);
  99                 work = NULL;
 100         } else {
 101                 data->pending = work;
 102                 hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT);
 103                 spin_unlock_irqrestore(&data->lock, flags);
 104                 wait_for_completion_interruptible_timeout(&work->ready, HZ*2);
 105                 spin_lock_irqsave(&data->lock, flags);
 106                 data->pending = NULL;
 107         }
 108         spin_unlock_irqrestore(&data->lock, flags);
 109         mutex_unlock(&data->mutex);
 110         return work;
 111 }
 112 
 113 /*
 114  * input class device
 115  */
 116 static int picolcd_raw_keypad(struct picolcd_data *data,
 117                 struct hid_report *report, u8 *raw_data, int size)
 118 {
 119         /*
 120          * Keypad event
 121          * First and second data bytes list currently pressed keys,
 122          * 0x00 means no key and at most 2 keys may be pressed at same time
 123          */
 124         int i, j;
 125 
 126         /* determine newly pressed keys */
 127         for (i = 0; i < size; i++) {
 128                 unsigned int key_code;
 129                 if (raw_data[i] == 0)
 130                         continue;
 131                 for (j = 0; j < sizeof(data->pressed_keys); j++)
 132                         if (data->pressed_keys[j] == raw_data[i])
 133                                 goto key_already_down;
 134                 for (j = 0; j < sizeof(data->pressed_keys); j++)
 135                         if (data->pressed_keys[j] == 0) {
 136                                 data->pressed_keys[j] = raw_data[i];
 137                                 break;
 138                         }
 139                 input_event(data->input_keys, EV_MSC, MSC_SCAN, raw_data[i]);
 140                 if (raw_data[i] < PICOLCD_KEYS)
 141                         key_code = data->keycode[raw_data[i]];
 142                 else
 143                         key_code = KEY_UNKNOWN;
 144                 if (key_code != KEY_UNKNOWN) {
 145                         dbg_hid(PICOLCD_NAME " got key press for %u:%d",
 146                                         raw_data[i], key_code);
 147                         input_report_key(data->input_keys, key_code, 1);
 148                 }
 149                 input_sync(data->input_keys);
 150 key_already_down:
 151                 continue;
 152         }
 153 
 154         /* determine newly released keys */
 155         for (j = 0; j < sizeof(data->pressed_keys); j++) {
 156                 unsigned int key_code;
 157                 if (data->pressed_keys[j] == 0)
 158                         continue;
 159                 for (i = 0; i < size; i++)
 160                         if (data->pressed_keys[j] == raw_data[i])
 161                                 goto key_still_down;
 162                 input_event(data->input_keys, EV_MSC, MSC_SCAN, data->pressed_keys[j]);
 163                 if (data->pressed_keys[j] < PICOLCD_KEYS)
 164                         key_code = data->keycode[data->pressed_keys[j]];
 165                 else
 166                         key_code = KEY_UNKNOWN;
 167                 if (key_code != KEY_UNKNOWN) {
 168                         dbg_hid(PICOLCD_NAME " got key release for %u:%d",
 169                                         data->pressed_keys[j], key_code);
 170                         input_report_key(data->input_keys, key_code, 0);
 171                 }
 172                 input_sync(data->input_keys);
 173                 data->pressed_keys[j] = 0;
 174 key_still_down:
 175                 continue;
 176         }
 177         return 1;
 178 }
 179 
 180 static int picolcd_check_version(struct hid_device *hdev)
 181 {
 182         struct picolcd_data *data = hid_get_drvdata(hdev);
 183         struct picolcd_pending *verinfo;
 184         int ret = 0;
 185 
 186         if (!data)
 187                 return -ENODEV;
 188 
 189         verinfo = picolcd_send_and_wait(hdev, REPORT_VERSION, NULL, 0);
 190         if (!verinfo) {
 191                 hid_err(hdev, "no version response from PicoLCD\n");
 192                 return -ENODEV;
 193         }
 194 
 195         if (verinfo->raw_size == 2) {
 196                 data->version[0] = verinfo->raw_data[1];
 197                 data->version[1] = verinfo->raw_data[0];
 198                 if (data->status & PICOLCD_BOOTLOADER) {
 199                         hid_info(hdev, "PicoLCD, bootloader version %d.%d\n",
 200                                  verinfo->raw_data[1], verinfo->raw_data[0]);
 201                 } else {
 202                         hid_info(hdev, "PicoLCD, firmware version %d.%d\n",
 203                                  verinfo->raw_data[1], verinfo->raw_data[0]);
 204                 }
 205         } else {
 206                 hid_err(hdev, "confused, got unexpected version response from PicoLCD\n");
 207                 ret = -EINVAL;
 208         }
 209         kfree(verinfo);
 210         return ret;
 211 }
 212 
 213 /*
 214  * Reset our device and wait for answer to VERSION request
 215  */
 216 int picolcd_reset(struct hid_device *hdev)
 217 {
 218         struct picolcd_data *data = hid_get_drvdata(hdev);
 219         struct hid_report *report = picolcd_out_report(REPORT_RESET, hdev);
 220         unsigned long flags;
 221         int error;
 222 
 223         if (!data || !report || report->maxfield != 1)
 224                 return -ENODEV;
 225 
 226         spin_lock_irqsave(&data->lock, flags);
 227         if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER)
 228                 data->status |= PICOLCD_BOOTLOADER;
 229 
 230         /* perform the reset */
 231         hid_set_field(report->field[0], 0, 1);
 232         if (data->status & PICOLCD_FAILED) {
 233                 spin_unlock_irqrestore(&data->lock, flags);
 234                 return -ENODEV;
 235         }
 236         hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
 237         spin_unlock_irqrestore(&data->lock, flags);
 238 
 239         error = picolcd_check_version(hdev);
 240         if (error)
 241                 return error;
 242 
 243         picolcd_resume_lcd(data);
 244         picolcd_resume_backlight(data);
 245         picolcd_fb_refresh(data);
 246         picolcd_leds_set(data);
 247         return 0;
 248 }
 249 
 250 /*
 251  * The "operation_mode" sysfs attribute
 252  */
 253 static ssize_t picolcd_operation_mode_show(struct device *dev,
 254                 struct device_attribute *attr, char *buf)
 255 {
 256         struct picolcd_data *data = dev_get_drvdata(dev);
 257 
 258         if (data->status & PICOLCD_BOOTLOADER)
 259                 return snprintf(buf, PAGE_SIZE, "[bootloader] lcd\n");
 260         else
 261                 return snprintf(buf, PAGE_SIZE, "bootloader [lcd]\n");
 262 }
 263 
 264 static ssize_t picolcd_operation_mode_store(struct device *dev,
 265                 struct device_attribute *attr, const char *buf, size_t count)
 266 {
 267         struct picolcd_data *data = dev_get_drvdata(dev);
 268         struct hid_report *report = NULL;
 269         int timeout = data->opmode_delay;
 270         unsigned long flags;
 271 
 272         if (sysfs_streq(buf, "lcd")) {
 273                 if (data->status & PICOLCD_BOOTLOADER)
 274                         report = picolcd_out_report(REPORT_EXIT_FLASHER, data->hdev);
 275         } else if (sysfs_streq(buf, "bootloader")) {
 276                 if (!(data->status & PICOLCD_BOOTLOADER))
 277                         report = picolcd_out_report(REPORT_EXIT_KEYBOARD, data->hdev);
 278         } else {
 279                 return -EINVAL;
 280         }
 281 
 282         if (!report || report->maxfield != 1)
 283                 return -EINVAL;
 284 
 285         spin_lock_irqsave(&data->lock, flags);
 286         hid_set_field(report->field[0], 0, timeout & 0xff);
 287         hid_set_field(report->field[0], 1, (timeout >> 8) & 0xff);
 288         hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT);
 289         spin_unlock_irqrestore(&data->lock, flags);
 290         return count;
 291 }
 292 
 293 static DEVICE_ATTR(operation_mode, 0644, picolcd_operation_mode_show,
 294                 picolcd_operation_mode_store);
 295 
 296 /*
 297  * The "operation_mode_delay" sysfs attribute
 298  */
 299 static ssize_t picolcd_operation_mode_delay_show(struct device *dev,
 300                 struct device_attribute *attr, char *buf)
 301 {
 302         struct picolcd_data *data = dev_get_drvdata(dev);
 303 
 304         return snprintf(buf, PAGE_SIZE, "%hu\n", data->opmode_delay);
 305 }
 306 
 307 static ssize_t picolcd_operation_mode_delay_store(struct device *dev,
 308                 struct device_attribute *attr, const char *buf, size_t count)
 309 {
 310         struct picolcd_data *data = dev_get_drvdata(dev);
 311         unsigned u;
 312         if (sscanf(buf, "%u", &u) != 1)
 313                 return -EINVAL;
 314         if (u > 30000)
 315                 return -EINVAL;
 316         else
 317                 data->opmode_delay = u;
 318         return count;
 319 }
 320 
 321 static DEVICE_ATTR(operation_mode_delay, 0644, picolcd_operation_mode_delay_show,
 322                 picolcd_operation_mode_delay_store);
 323 
 324 /*
 325  * Handle raw report as sent by device
 326  */
 327 static int picolcd_raw_event(struct hid_device *hdev,
 328                 struct hid_report *report, u8 *raw_data, int size)
 329 {
 330         struct picolcd_data *data = hid_get_drvdata(hdev);
 331         unsigned long flags;
 332         int ret = 0;
 333 
 334         if (!data)
 335                 return 1;
 336 
 337         if (size > 64) {
 338                 hid_warn(hdev, "invalid size value (%d) for picolcd raw event (%d)\n",
 339                                 size, report->id);
 340                 return 0;
 341         }
 342 
 343         if (report->id == REPORT_KEY_STATE) {
 344                 if (data->input_keys)
 345                         ret = picolcd_raw_keypad(data, report, raw_data+1, size-1);
 346         } else if (report->id == REPORT_IR_DATA) {
 347                 ret = picolcd_raw_cir(data, report, raw_data+1, size-1);
 348         } else {
 349                 spin_lock_irqsave(&data->lock, flags);
 350                 /*
 351                  * We let the caller of picolcd_send_and_wait() check if the
 352                  * report we got is one of the expected ones or not.
 353                  */
 354                 if (data->pending) {
 355                         memcpy(data->pending->raw_data, raw_data+1, size-1);
 356                         data->pending->raw_size  = size-1;
 357                         data->pending->in_report = report;
 358                         complete(&data->pending->ready);
 359                 }
 360                 spin_unlock_irqrestore(&data->lock, flags);
 361         }
 362 
 363         picolcd_debug_raw_event(data, hdev, report, raw_data, size);
 364         return 1;
 365 }
 366 
 367 #ifdef CONFIG_PM
 368 static int picolcd_suspend(struct hid_device *hdev, pm_message_t message)
 369 {
 370         if (PMSG_IS_AUTO(message))
 371                 return 0;
 372 
 373         picolcd_suspend_backlight(hid_get_drvdata(hdev));
 374         dbg_hid(PICOLCD_NAME " device ready for suspend\n");
 375         return 0;
 376 }
 377 
 378 static int picolcd_resume(struct hid_device *hdev)
 379 {
 380         int ret;
 381         ret = picolcd_resume_backlight(hid_get_drvdata(hdev));
 382         if (ret)
 383                 dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret);
 384         return 0;
 385 }
 386 
 387 static int picolcd_reset_resume(struct hid_device *hdev)
 388 {
 389         int ret;
 390         ret = picolcd_reset(hdev);
 391         if (ret)
 392                 dbg_hid(PICOLCD_NAME " resetting our device failed: %d\n", ret);
 393         ret = picolcd_fb_reset(hid_get_drvdata(hdev), 0);
 394         if (ret)
 395                 dbg_hid(PICOLCD_NAME " restoring framebuffer content failed: %d\n", ret);
 396         ret = picolcd_resume_lcd(hid_get_drvdata(hdev));
 397         if (ret)
 398                 dbg_hid(PICOLCD_NAME " restoring lcd failed: %d\n", ret);
 399         ret = picolcd_resume_backlight(hid_get_drvdata(hdev));
 400         if (ret)
 401                 dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret);
 402         picolcd_leds_set(hid_get_drvdata(hdev));
 403         return 0;
 404 }
 405 #endif
 406 
 407 /* initialize keypad input device */
 408 static int picolcd_init_keys(struct picolcd_data *data,
 409                 struct hid_report *report)
 410 {
 411         struct hid_device *hdev = data->hdev;
 412         struct input_dev *idev;
 413         int error, i;
 414 
 415         if (!report)
 416                 return -ENODEV;
 417         if (report->maxfield != 1 || report->field[0]->report_count != 2 ||
 418                         report->field[0]->report_size != 8) {
 419                 hid_err(hdev, "unsupported KEY_STATE report\n");
 420                 return -EINVAL;
 421         }
 422 
 423         idev = input_allocate_device();
 424         if (idev == NULL) {
 425                 hid_err(hdev, "failed to allocate input device\n");
 426                 return -ENOMEM;
 427         }
 428         input_set_drvdata(idev, hdev);
 429         memcpy(data->keycode, def_keymap, sizeof(def_keymap));
 430         idev->name = hdev->name;
 431         idev->phys = hdev->phys;
 432         idev->uniq = hdev->uniq;
 433         idev->id.bustype = hdev->bus;
 434         idev->id.vendor  = hdev->vendor;
 435         idev->id.product = hdev->product;
 436         idev->id.version = hdev->version;
 437         idev->dev.parent = &hdev->dev;
 438         idev->keycode     = &data->keycode;
 439         idev->keycodemax  = PICOLCD_KEYS;
 440         idev->keycodesize = sizeof(data->keycode[0]);
 441         input_set_capability(idev, EV_MSC, MSC_SCAN);
 442         set_bit(EV_REP, idev->evbit);
 443         for (i = 0; i < PICOLCD_KEYS; i++)
 444                 input_set_capability(idev, EV_KEY, data->keycode[i]);
 445         error = input_register_device(idev);
 446         if (error) {
 447                 hid_err(hdev, "error registering the input device\n");
 448                 input_free_device(idev);
 449                 return error;
 450         }
 451         data->input_keys = idev;
 452         return 0;
 453 }
 454 
 455 static void picolcd_exit_keys(struct picolcd_data *data)
 456 {
 457         struct input_dev *idev = data->input_keys;
 458 
 459         data->input_keys = NULL;
 460         if (idev)
 461                 input_unregister_device(idev);
 462 }
 463 
 464 static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data)
 465 {
 466         int error;
 467 
 468         /* Setup keypad input device */
 469         error = picolcd_init_keys(data, picolcd_in_report(REPORT_KEY_STATE, hdev));
 470         if (error)
 471                 goto err;
 472 
 473         /* Setup CIR input device */
 474         error = picolcd_init_cir(data, picolcd_in_report(REPORT_IR_DATA, hdev));
 475         if (error)
 476                 goto err;
 477 
 478         /* Set up the framebuffer device */
 479         error = picolcd_init_framebuffer(data);
 480         if (error)
 481                 goto err;
 482 
 483         /* Setup lcd class device */
 484         error = picolcd_init_lcd(data, picolcd_out_report(REPORT_CONTRAST, hdev));
 485         if (error)
 486                 goto err;
 487 
 488         /* Setup backlight class device */
 489         error = picolcd_init_backlight(data, picolcd_out_report(REPORT_BRIGHTNESS, hdev));
 490         if (error)
 491                 goto err;
 492 
 493         /* Setup the LED class devices */
 494         error = picolcd_init_leds(data, picolcd_out_report(REPORT_LED_STATE, hdev));
 495         if (error)
 496                 goto err;
 497 
 498         picolcd_init_devfs(data, picolcd_out_report(REPORT_EE_READ, hdev),
 499                         picolcd_out_report(REPORT_EE_WRITE, hdev),
 500                         picolcd_out_report(REPORT_READ_MEMORY, hdev),
 501                         picolcd_out_report(REPORT_WRITE_MEMORY, hdev),
 502                         picolcd_out_report(REPORT_RESET, hdev));
 503         return 0;
 504 err:
 505         picolcd_exit_leds(data);
 506         picolcd_exit_backlight(data);
 507         picolcd_exit_lcd(data);
 508         picolcd_exit_framebuffer(data);
 509         picolcd_exit_cir(data);
 510         picolcd_exit_keys(data);
 511         return error;
 512 }
 513 
 514 static int picolcd_probe_bootloader(struct hid_device *hdev, struct picolcd_data *data)
 515 {
 516         picolcd_init_devfs(data, NULL, NULL,
 517                         picolcd_out_report(REPORT_BL_READ_MEMORY, hdev),
 518                         picolcd_out_report(REPORT_BL_WRITE_MEMORY, hdev), NULL);
 519         return 0;
 520 }
 521 
 522 static int picolcd_probe(struct hid_device *hdev,
 523                      const struct hid_device_id *id)
 524 {
 525         struct picolcd_data *data;
 526         int error = -ENOMEM;
 527 
 528         dbg_hid(PICOLCD_NAME " hardware probe...\n");
 529 
 530         /*
 531          * Let's allocate the picolcd data structure, set some reasonable
 532          * defaults, and associate it with the device
 533          */
 534         data = kzalloc(sizeof(struct picolcd_data), GFP_KERNEL);
 535         if (data == NULL) {
 536                 hid_err(hdev, "can't allocate space for Minibox PicoLCD device data\n");
 537                 return -ENOMEM;
 538         }
 539 
 540         spin_lock_init(&data->lock);
 541         mutex_init(&data->mutex);
 542         data->hdev = hdev;
 543         data->opmode_delay = 5000;
 544         if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER)
 545                 data->status |= PICOLCD_BOOTLOADER;
 546         hid_set_drvdata(hdev, data);
 547 
 548         /* Parse the device reports and start it up */
 549         error = hid_parse(hdev);
 550         if (error) {
 551                 hid_err(hdev, "device report parse failed\n");
 552                 goto err_cleanup_data;
 553         }
 554 
 555         error = hid_hw_start(hdev, 0);
 556         if (error) {
 557                 hid_err(hdev, "hardware start failed\n");
 558                 goto err_cleanup_data;
 559         }
 560 
 561         error = hid_hw_open(hdev);
 562         if (error) {
 563                 hid_err(hdev, "failed to open input interrupt pipe for key and IR events\n");
 564                 goto err_cleanup_hid_hw;
 565         }
 566 
 567         error = device_create_file(&hdev->dev, &dev_attr_operation_mode_delay);
 568         if (error) {
 569                 hid_err(hdev, "failed to create sysfs attributes\n");
 570                 goto err_cleanup_hid_ll;
 571         }
 572 
 573         error = device_create_file(&hdev->dev, &dev_attr_operation_mode);
 574         if (error) {
 575                 hid_err(hdev, "failed to create sysfs attributes\n");
 576                 goto err_cleanup_sysfs1;
 577         }
 578 
 579         if (data->status & PICOLCD_BOOTLOADER)
 580                 error = picolcd_probe_bootloader(hdev, data);
 581         else
 582                 error = picolcd_probe_lcd(hdev, data);
 583         if (error)
 584                 goto err_cleanup_sysfs2;
 585 
 586         dbg_hid(PICOLCD_NAME " activated and initialized\n");
 587         return 0;
 588 
 589 err_cleanup_sysfs2:
 590         device_remove_file(&hdev->dev, &dev_attr_operation_mode);
 591 err_cleanup_sysfs1:
 592         device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay);
 593 err_cleanup_hid_ll:
 594         hid_hw_close(hdev);
 595 err_cleanup_hid_hw:
 596         hid_hw_stop(hdev);
 597 err_cleanup_data:
 598         kfree(data);
 599         return error;
 600 }
 601 
 602 static void picolcd_remove(struct hid_device *hdev)
 603 {
 604         struct picolcd_data *data = hid_get_drvdata(hdev);
 605         unsigned long flags;
 606 
 607         dbg_hid(PICOLCD_NAME " hardware remove...\n");
 608         spin_lock_irqsave(&data->lock, flags);
 609         data->status |= PICOLCD_FAILED;
 610         spin_unlock_irqrestore(&data->lock, flags);
 611 
 612         picolcd_exit_devfs(data);
 613         device_remove_file(&hdev->dev, &dev_attr_operation_mode);
 614         device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay);
 615         hid_hw_close(hdev);
 616         hid_hw_stop(hdev);
 617 
 618         /* Shortcut potential pending reply that will never arrive */
 619         spin_lock_irqsave(&data->lock, flags);
 620         if (data->pending)
 621                 complete(&data->pending->ready);
 622         spin_unlock_irqrestore(&data->lock, flags);
 623 
 624         /* Cleanup LED */
 625         picolcd_exit_leds(data);
 626         /* Clean up the framebuffer */
 627         picolcd_exit_backlight(data);
 628         picolcd_exit_lcd(data);
 629         picolcd_exit_framebuffer(data);
 630         /* Cleanup input */
 631         picolcd_exit_cir(data);
 632         picolcd_exit_keys(data);
 633 
 634         mutex_destroy(&data->mutex);
 635         /* Finally, clean up the picolcd data itself */
 636         kfree(data);
 637 }
 638 
 639 static const struct hid_device_id picolcd_devices[] = {
 640         { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) },
 641         { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) },
 642         { }
 643 };
 644 MODULE_DEVICE_TABLE(hid, picolcd_devices);
 645 
 646 static struct hid_driver picolcd_driver = {
 647         .name =          "hid-picolcd",
 648         .id_table =      picolcd_devices,
 649         .probe =         picolcd_probe,
 650         .remove =        picolcd_remove,
 651         .raw_event =     picolcd_raw_event,
 652 #ifdef CONFIG_PM
 653         .suspend =       picolcd_suspend,
 654         .resume =        picolcd_resume,
 655         .reset_resume =  picolcd_reset_resume,
 656 #endif
 657 };
 658 module_hid_driver(picolcd_driver);
 659 
 660 MODULE_DESCRIPTION("Minibox graphics PicoLCD Driver");
 661 MODULE_LICENSE("GPL v2");

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