root/drivers/input/tablet/pegasus_notetaker.c

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

DEFINITIONS

This source file includes following definitions.
  1. pegasus_control_msg
  2. pegasus_set_mode
  3. pegasus_parse_packet
  4. pegasus_irq
  5. pegasus_init
  6. pegasus_open
  7. pegasus_close
  8. pegasus_probe
  9. pegasus_disconnect
  10. pegasus_suspend
  11. pegasus_resume
  12. pegasus_reset_resume

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Pegasus Mobile Notetaker Pen input tablet driver
   4  *
   5  * Copyright (c) 2016 Martin Kepplinger <martink@posteo.de>
   6  */
   7 
   8 /*
   9  * request packet (control endpoint):
  10  * |-------------------------------------|
  11  * | Report ID | Nr of bytes | command   |
  12  * | (1 byte)  | (1 byte)    | (n bytes) |
  13  * |-------------------------------------|
  14  * | 0x02      | n           |           |
  15  * |-------------------------------------|
  16  *
  17  * data packet after set xy mode command, 0x80 0xb5 0x02 0x01
  18  * and pen is in range:
  19  *
  20  * byte byte name               value (bits)
  21  * --------------------------------------------
  22  * 0    status                  0 1 0 0 0 0 X X
  23  * 1    color                   0 0 0 0 H 0 S T
  24  * 2    X low
  25  * 3    X high
  26  * 4    Y low
  27  * 5    Y high
  28  *
  29  * X X  battery state:
  30  *      no state reported       0x00
  31  *      battery low             0x01
  32  *      battery good            0x02
  33  *
  34  * H    Hovering
  35  * S    Switch 1 (pen button)
  36  * T    Tip
  37  */
  38 
  39 #include <linux/kernel.h>
  40 #include <linux/module.h>
  41 #include <linux/input.h>
  42 #include <linux/usb/input.h>
  43 #include <linux/slab.h>
  44 #include <linux/workqueue.h>
  45 #include <linux/mutex.h>
  46 
  47 /* USB HID defines */
  48 #define USB_REQ_GET_REPORT              0x01
  49 #define USB_REQ_SET_REPORT              0x09
  50 
  51 #define USB_VENDOR_ID_PEGASUSTECH       0x0e20
  52 #define USB_DEVICE_ID_PEGASUS_NOTETAKER_EN100   0x0101
  53 
  54 /* device specific defines */
  55 #define NOTETAKER_REPORT_ID             0x02
  56 #define NOTETAKER_SET_CMD               0x80
  57 #define NOTETAKER_SET_MODE              0xb5
  58 
  59 #define NOTETAKER_LED_MOUSE             0x02
  60 #define PEN_MODE_XY                     0x01
  61 
  62 #define SPECIAL_COMMAND                 0x80
  63 #define BUTTON_PRESSED                  0xb5
  64 #define COMMAND_VERSION                 0xa9
  65 
  66 /* in xy data packet */
  67 #define BATTERY_NO_REPORT               0x40
  68 #define BATTERY_LOW                     0x41
  69 #define BATTERY_GOOD                    0x42
  70 #define PEN_BUTTON_PRESSED              BIT(1)
  71 #define PEN_TIP                         BIT(0)
  72 
  73 struct pegasus {
  74         unsigned char *data;
  75         u8 data_len;
  76         dma_addr_t data_dma;
  77         struct input_dev *dev;
  78         struct usb_device *usbdev;
  79         struct usb_interface *intf;
  80         struct urb *irq;
  81 
  82         /* serialize access to open/suspend */
  83         struct mutex pm_mutex;
  84         bool is_open;
  85 
  86         char name[128];
  87         char phys[64];
  88         struct work_struct init;
  89 };
  90 
  91 static int pegasus_control_msg(struct pegasus *pegasus, u8 *data, int len)
  92 {
  93         const int sizeof_buf = len + 2;
  94         int result;
  95         int error;
  96         u8 *cmd_buf;
  97 
  98         cmd_buf = kmalloc(sizeof_buf, GFP_KERNEL);
  99         if (!cmd_buf)
 100                 return -ENOMEM;
 101 
 102         cmd_buf[0] = NOTETAKER_REPORT_ID;
 103         cmd_buf[1] = len;
 104         memcpy(cmd_buf + 2, data, len);
 105 
 106         result = usb_control_msg(pegasus->usbdev,
 107                                  usb_sndctrlpipe(pegasus->usbdev, 0),
 108                                  USB_REQ_SET_REPORT,
 109                                  USB_TYPE_VENDOR | USB_DIR_OUT,
 110                                  0, 0, cmd_buf, sizeof_buf,
 111                                  USB_CTRL_SET_TIMEOUT);
 112 
 113         kfree(cmd_buf);
 114 
 115         if (unlikely(result != sizeof_buf)) {
 116                 error = result < 0 ? result : -EIO;
 117                 dev_err(&pegasus->usbdev->dev, "control msg error: %d\n",
 118                         error);
 119                 return error;
 120         }
 121 
 122         return 0;
 123 }
 124 
 125 static int pegasus_set_mode(struct pegasus *pegasus, u8 mode, u8 led)
 126 {
 127         u8 cmd[] = { NOTETAKER_SET_CMD, NOTETAKER_SET_MODE, led, mode };
 128 
 129         return pegasus_control_msg(pegasus, cmd, sizeof(cmd));
 130 }
 131 
 132 static void pegasus_parse_packet(struct pegasus *pegasus)
 133 {
 134         unsigned char *data = pegasus->data;
 135         struct input_dev *dev = pegasus->dev;
 136         u16 x, y;
 137 
 138         switch (data[0]) {
 139         case SPECIAL_COMMAND:
 140                 /* device button pressed */
 141                 if (data[1] == BUTTON_PRESSED)
 142                         schedule_work(&pegasus->init);
 143 
 144                 break;
 145 
 146         /* xy data */
 147         case BATTERY_LOW:
 148                 dev_warn_once(&dev->dev, "Pen battery low\n");
 149                 /* fall through */
 150 
 151         case BATTERY_NO_REPORT:
 152         case BATTERY_GOOD:
 153                 x = le16_to_cpup((__le16 *)&data[2]);
 154                 y = le16_to_cpup((__le16 *)&data[4]);
 155 
 156                 /* pen-up event */
 157                 if (x == 0 && y == 0)
 158                         break;
 159 
 160                 input_report_key(dev, BTN_TOUCH, data[1] & PEN_TIP);
 161                 input_report_key(dev, BTN_RIGHT, data[1] & PEN_BUTTON_PRESSED);
 162                 input_report_key(dev, BTN_TOOL_PEN, 1);
 163                 input_report_abs(dev, ABS_X, (s16)x);
 164                 input_report_abs(dev, ABS_Y, y);
 165 
 166                 input_sync(dev);
 167                 break;
 168 
 169         default:
 170                 dev_warn_once(&pegasus->usbdev->dev,
 171                               "unknown answer from device\n");
 172         }
 173 }
 174 
 175 static void pegasus_irq(struct urb *urb)
 176 {
 177         struct pegasus *pegasus = urb->context;
 178         struct usb_device *dev = pegasus->usbdev;
 179         int retval;
 180 
 181         switch (urb->status) {
 182         case 0:
 183                 pegasus_parse_packet(pegasus);
 184                 usb_mark_last_busy(pegasus->usbdev);
 185                 break;
 186 
 187         case -ECONNRESET:
 188         case -ENOENT:
 189         case -ESHUTDOWN:
 190                 dev_err(&dev->dev, "%s - urb shutting down with status: %d",
 191                         __func__, urb->status);
 192                 return;
 193 
 194         default:
 195                 dev_err(&dev->dev, "%s - nonzero urb status received: %d",
 196                         __func__, urb->status);
 197                 break;
 198         }
 199 
 200         retval = usb_submit_urb(urb, GFP_ATOMIC);
 201         if (retval)
 202                 dev_err(&dev->dev, "%s - usb_submit_urb failed with result %d",
 203                         __func__, retval);
 204 }
 205 
 206 static void pegasus_init(struct work_struct *work)
 207 {
 208         struct pegasus *pegasus = container_of(work, struct pegasus, init);
 209         int error;
 210 
 211         error = pegasus_set_mode(pegasus, PEN_MODE_XY, NOTETAKER_LED_MOUSE);
 212         if (error)
 213                 dev_err(&pegasus->usbdev->dev, "pegasus_set_mode error: %d\n",
 214                         error);
 215 }
 216 
 217 static int pegasus_open(struct input_dev *dev)
 218 {
 219         struct pegasus *pegasus = input_get_drvdata(dev);
 220         int error;
 221 
 222         error = usb_autopm_get_interface(pegasus->intf);
 223         if (error)
 224                 return error;
 225 
 226         mutex_lock(&pegasus->pm_mutex);
 227         pegasus->irq->dev = pegasus->usbdev;
 228         if (usb_submit_urb(pegasus->irq, GFP_KERNEL)) {
 229                 error = -EIO;
 230                 goto err_autopm_put;
 231         }
 232 
 233         error = pegasus_set_mode(pegasus, PEN_MODE_XY, NOTETAKER_LED_MOUSE);
 234         if (error)
 235                 goto err_kill_urb;
 236 
 237         pegasus->is_open = true;
 238         mutex_unlock(&pegasus->pm_mutex);
 239         return 0;
 240 
 241 err_kill_urb:
 242         usb_kill_urb(pegasus->irq);
 243         cancel_work_sync(&pegasus->init);
 244 err_autopm_put:
 245         mutex_unlock(&pegasus->pm_mutex);
 246         usb_autopm_put_interface(pegasus->intf);
 247         return error;
 248 }
 249 
 250 static void pegasus_close(struct input_dev *dev)
 251 {
 252         struct pegasus *pegasus = input_get_drvdata(dev);
 253 
 254         mutex_lock(&pegasus->pm_mutex);
 255         usb_kill_urb(pegasus->irq);
 256         cancel_work_sync(&pegasus->init);
 257         pegasus->is_open = false;
 258         mutex_unlock(&pegasus->pm_mutex);
 259 
 260         usb_autopm_put_interface(pegasus->intf);
 261 }
 262 
 263 static int pegasus_probe(struct usb_interface *intf,
 264                          const struct usb_device_id *id)
 265 {
 266         struct usb_device *dev = interface_to_usbdev(intf);
 267         struct usb_endpoint_descriptor *endpoint;
 268         struct pegasus *pegasus;
 269         struct input_dev *input_dev;
 270         int error;
 271         int pipe;
 272 
 273         /* We control interface 0 */
 274         if (intf->cur_altsetting->desc.bInterfaceNumber >= 1)
 275                 return -ENODEV;
 276 
 277         /* Sanity check that the device has an endpoint */
 278         if (intf->cur_altsetting->desc.bNumEndpoints < 1) {
 279                 dev_err(&intf->dev, "Invalid number of endpoints\n");
 280                 return -EINVAL;
 281         }
 282 
 283         endpoint = &intf->cur_altsetting->endpoint[0].desc;
 284 
 285         pegasus = kzalloc(sizeof(*pegasus), GFP_KERNEL);
 286         input_dev = input_allocate_device();
 287         if (!pegasus || !input_dev) {
 288                 error = -ENOMEM;
 289                 goto err_free_mem;
 290         }
 291 
 292         mutex_init(&pegasus->pm_mutex);
 293 
 294         pegasus->usbdev = dev;
 295         pegasus->dev = input_dev;
 296         pegasus->intf = intf;
 297 
 298         pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
 299         pegasus->data_len = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
 300 
 301         pegasus->data = usb_alloc_coherent(dev, pegasus->data_len, GFP_KERNEL,
 302                                            &pegasus->data_dma);
 303         if (!pegasus->data) {
 304                 error = -ENOMEM;
 305                 goto err_free_mem;
 306         }
 307 
 308         pegasus->irq = usb_alloc_urb(0, GFP_KERNEL);
 309         if (!pegasus->irq) {
 310                 error = -ENOMEM;
 311                 goto err_free_dma;
 312         }
 313 
 314         usb_fill_int_urb(pegasus->irq, dev, pipe,
 315                          pegasus->data, pegasus->data_len,
 316                          pegasus_irq, pegasus, endpoint->bInterval);
 317 
 318         pegasus->irq->transfer_dma = pegasus->data_dma;
 319         pegasus->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 320 
 321         if (dev->manufacturer)
 322                 strlcpy(pegasus->name, dev->manufacturer,
 323                         sizeof(pegasus->name));
 324 
 325         if (dev->product) {
 326                 if (dev->manufacturer)
 327                         strlcat(pegasus->name, " ", sizeof(pegasus->name));
 328                 strlcat(pegasus->name, dev->product, sizeof(pegasus->name));
 329         }
 330 
 331         if (!strlen(pegasus->name))
 332                 snprintf(pegasus->name, sizeof(pegasus->name),
 333                          "USB Pegasus Device %04x:%04x",
 334                          le16_to_cpu(dev->descriptor.idVendor),
 335                          le16_to_cpu(dev->descriptor.idProduct));
 336 
 337         usb_make_path(dev, pegasus->phys, sizeof(pegasus->phys));
 338         strlcat(pegasus->phys, "/input0", sizeof(pegasus->phys));
 339 
 340         INIT_WORK(&pegasus->init, pegasus_init);
 341 
 342         usb_set_intfdata(intf, pegasus);
 343 
 344         input_dev->name = pegasus->name;
 345         input_dev->phys = pegasus->phys;
 346         usb_to_input_id(dev, &input_dev->id);
 347         input_dev->dev.parent = &intf->dev;
 348 
 349         input_set_drvdata(input_dev, pegasus);
 350 
 351         input_dev->open = pegasus_open;
 352         input_dev->close = pegasus_close;
 353 
 354         __set_bit(EV_ABS, input_dev->evbit);
 355         __set_bit(EV_KEY, input_dev->evbit);
 356 
 357         __set_bit(ABS_X, input_dev->absbit);
 358         __set_bit(ABS_Y, input_dev->absbit);
 359 
 360         __set_bit(BTN_TOUCH, input_dev->keybit);
 361         __set_bit(BTN_RIGHT, input_dev->keybit);
 362         __set_bit(BTN_TOOL_PEN, input_dev->keybit);
 363 
 364         __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
 365         __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
 366 
 367         input_set_abs_params(input_dev, ABS_X, -1500, 1500, 8, 0);
 368         input_set_abs_params(input_dev, ABS_Y, 1600, 3000, 8, 0);
 369 
 370         error = input_register_device(pegasus->dev);
 371         if (error)
 372                 goto err_free_urb;
 373 
 374         return 0;
 375 
 376 err_free_urb:
 377         usb_free_urb(pegasus->irq);
 378 err_free_dma:
 379         usb_free_coherent(dev, pegasus->data_len,
 380                           pegasus->data, pegasus->data_dma);
 381 err_free_mem:
 382         input_free_device(input_dev);
 383         kfree(pegasus);
 384         usb_set_intfdata(intf, NULL);
 385 
 386         return error;
 387 }
 388 
 389 static void pegasus_disconnect(struct usb_interface *intf)
 390 {
 391         struct pegasus *pegasus = usb_get_intfdata(intf);
 392 
 393         input_unregister_device(pegasus->dev);
 394 
 395         usb_free_urb(pegasus->irq);
 396         usb_free_coherent(interface_to_usbdev(intf),
 397                           pegasus->data_len, pegasus->data,
 398                           pegasus->data_dma);
 399 
 400         kfree(pegasus);
 401         usb_set_intfdata(intf, NULL);
 402 }
 403 
 404 static int pegasus_suspend(struct usb_interface *intf, pm_message_t message)
 405 {
 406         struct pegasus *pegasus = usb_get_intfdata(intf);
 407 
 408         mutex_lock(&pegasus->pm_mutex);
 409         usb_kill_urb(pegasus->irq);
 410         cancel_work_sync(&pegasus->init);
 411         mutex_unlock(&pegasus->pm_mutex);
 412 
 413         return 0;
 414 }
 415 
 416 static int pegasus_resume(struct usb_interface *intf)
 417 {
 418         struct pegasus *pegasus = usb_get_intfdata(intf);
 419         int retval = 0;
 420 
 421         mutex_lock(&pegasus->pm_mutex);
 422         if (pegasus->is_open && usb_submit_urb(pegasus->irq, GFP_NOIO) < 0)
 423                 retval = -EIO;
 424         mutex_unlock(&pegasus->pm_mutex);
 425 
 426         return retval;
 427 }
 428 
 429 static int pegasus_reset_resume(struct usb_interface *intf)
 430 {
 431         struct pegasus *pegasus = usb_get_intfdata(intf);
 432         int retval = 0;
 433 
 434         mutex_lock(&pegasus->pm_mutex);
 435         if (pegasus->is_open) {
 436                 retval = pegasus_set_mode(pegasus, PEN_MODE_XY,
 437                                           NOTETAKER_LED_MOUSE);
 438                 if (!retval && usb_submit_urb(pegasus->irq, GFP_NOIO) < 0)
 439                         retval = -EIO;
 440         }
 441         mutex_unlock(&pegasus->pm_mutex);
 442 
 443         return retval;
 444 }
 445 
 446 static const struct usb_device_id pegasus_ids[] = {
 447         { USB_DEVICE(USB_VENDOR_ID_PEGASUSTECH,
 448                      USB_DEVICE_ID_PEGASUS_NOTETAKER_EN100) },
 449         { }
 450 };
 451 MODULE_DEVICE_TABLE(usb, pegasus_ids);
 452 
 453 static struct usb_driver pegasus_driver = {
 454         .name           = "pegasus_notetaker",
 455         .probe          = pegasus_probe,
 456         .disconnect     = pegasus_disconnect,
 457         .suspend        = pegasus_suspend,
 458         .resume         = pegasus_resume,
 459         .reset_resume   = pegasus_reset_resume,
 460         .id_table       = pegasus_ids,
 461         .supports_autosuspend = 1,
 462 };
 463 
 464 module_usb_driver(pegasus_driver);
 465 
 466 MODULE_AUTHOR("Martin Kepplinger <martink@posteo.de>");
 467 MODULE_DESCRIPTION("Pegasus Mobile Notetaker Pen tablet driver");
 468 MODULE_LICENSE("GPL");

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