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