/*
* drivers/input/tablet/wacom_sys.c
*
* USB Wacom tablet support - system specific code
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include "wacom_wac.h"
#include "wacom.h"
/* defines to get HID report descriptor */
#define HID_DEVICET_HID (USB_TYPE_CLASS | 0x01)
#define HID_DEVICET_REPORT (USB_TYPE_CLASS | 0x02)
#define HID_USAGE_UNDEFINED 0x00
#define HID_USAGE_PAGE 0x05
#define HID_USAGE_PAGE_DIGITIZER 0x0d
#define HID_USAGE_PAGE_DESKTOP 0x01
#define HID_USAGE 0x09
#define HID_USAGE_X 0x30
#define HID_USAGE_Y 0x31
#define HID_USAGE_X_TILT 0x3d
#define HID_USAGE_Y_TILT 0x3e
#define HID_USAGE_FINGER 0x22
#define HID_USAGE_STYLUS 0x20
#define HID_COLLECTION 0xc0
enum {
WCM_UNDEFINED = 0,
WCM_DESKTOP,
WCM_DIGITIZER,
};
struct hid_descriptor {
struct usb_descriptor_header header;
__le16 bcdHID;
u8 bCountryCode;
u8 bNumDescriptors;
u8 bDescriptorType;
__le16 wDescriptorLength;
} __attribute__ ((packed));
/* defines to get/set USB message */
#define USB_REQ_GET_REPORT 0x01
#define USB_REQ_SET_REPORT 0x09
#define WAC_HID_FEATURE_REPORT 0x03
#define WAC_MSG_RETRIES 5
#define WAC_CMD_LED_CONTROL 0x20
#define WAC_CMD_ICON_START 0x21
#define WAC_CMD_ICON_XFER 0x23
#define WAC_CMD_RETRIES 10
static int wacom_get_report(struct usb_interface *intf, u8 type, u8 id,
void *buf, size_t size, unsigned int retries)
{
struct usb_device *dev = interface_to_usbdev(intf);
int retval;
do {
retval = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_REPORT,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
(type << 8) + id,
intf->altsetting[0].desc.bInterfaceNumber,
buf, size, 100);
} while ((retval == -ETIMEDOUT || retval == -EPIPE) && --retries);
return retval;
}
static int wacom_set_report(struct usb_interface *intf, u8 type, u8 id,
void *buf, size_t size, unsigned int retries)
{
struct usb_device *dev = interface_to_usbdev(intf);
int retval;
do {
retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_SET_REPORT,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
(type << 8) + id,
intf->altsetting[0].desc.bInterfaceNumber,
buf, size, 1000);
} while ((retval == -ETIMEDOUT || retval == -EPIPE) && --retries);
return retval;
}
static void wacom_sys_irq(struct urb *urb)
{
struct wacom *wacom = urb->context;
int retval;
switch (urb->status) {
case 0:
/* success */
break;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d", __func__, urb->status);
return;
default:
dbg("%s - nonzero urb status received: %d", __func__, urb->status);
goto exit;
}
wacom_wac_irq(&wacom->wacom_wac, urb->actual_length);
exit:
usb_mark_last_busy(wacom->usbdev);
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
err ("%s - usb_submit_urb failed with result %d",
__func__, retval);
}
static int wacom_open(struct input_dev *dev)
{
struct wacom *wacom = input_get_drvdata(dev);
int retval = 0;
if (usb_autopm_get_interface(wacom->intf) < 0)
return -EIO;
mutex_lock(&wacom->lock);
if (usb_submit_urb(wacom->irq, GFP_KERNEL)) {
retval = -EIO;
goto out;
}
wacom->open = true;
wacom->intf->needs_remote_wakeup = 1;
out:
mutex_unlock(&wacom->lock);
usb_autopm_put_interface(wacom->intf);
return retval;
}
static void wacom_close(struct input_dev *dev)
{
struct wacom *wacom = input_get_drvdata(dev);
int autopm_error;
autopm_error = usb_autopm_get_interface(wacom->intf);
mutex_lock(&wacom->lock);
usb_kill_urb(wacom->irq);
wacom->open = false;
wacom->intf->needs_remote_wakeup = 0;
mutex_unlock(&wacom->lock);
if (!autopm_error)
usb_autopm_put_interface(wacom->intf);
}
static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hid_desc,
struct wacom_features *features)
{
struct usb_device *dev = interface_to_usbdev(intf);
char limit = 0;
/* result has to be defined as int for some devices */
int result = 0;
int i