162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * A driver for the Griffin Technology, Inc. "PowerMate" USB controller dial. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * v1.1, (c)2002 William R Sowerbutts <will@sowerbutts.com> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This device is a anodised aluminium knob which connects over USB. It can measure 862306a36Sopenharmony_ci * clockwise and anticlockwise rotation. The dial also acts as a pushbutton with 962306a36Sopenharmony_ci * a spring for automatic release. The base contains a pair of LEDs which illuminate 1062306a36Sopenharmony_ci * the translucent base. It rotates without limit and reports its relative rotation 1162306a36Sopenharmony_ci * back to the host when polled by the USB controller. 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Testing with the knob I have has shown that it measures approximately 94 "clicks" 1462306a36Sopenharmony_ci * for one full rotation. Testing with my High Speed Rotation Actuator (ok, it was 1562306a36Sopenharmony_ci * a variable speed cordless electric drill) has shown that the device can measure 1662306a36Sopenharmony_ci * speeds of up to 7 clicks either clockwise or anticlockwise between pollings from 1762306a36Sopenharmony_ci * the host. If it counts more than 7 clicks before it is polled, it will wrap back 1862306a36Sopenharmony_ci * to zero and start counting again. This was at quite high speed, however, almost 1962306a36Sopenharmony_ci * certainly faster than the human hand could turn it. Griffin say that it loses a 2062306a36Sopenharmony_ci * pulse or two on a direction change; the granularity is so fine that I never 2162306a36Sopenharmony_ci * noticed this in practice. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * The device's microcontroller can be programmed to set the LED to either a constant 2462306a36Sopenharmony_ci * intensity, or to a rhythmic pulsing. Several patterns and speeds are available. 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * Griffin were very happy to provide documentation and free hardware for development. 2762306a36Sopenharmony_ci * 2862306a36Sopenharmony_ci * Some userspace tools are available on the web: http://sowerbutts.com/powermate/ 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci */ 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include <linux/kernel.h> 3362306a36Sopenharmony_ci#include <linux/slab.h> 3462306a36Sopenharmony_ci#include <linux/module.h> 3562306a36Sopenharmony_ci#include <linux/spinlock.h> 3662306a36Sopenharmony_ci#include <linux/usb/input.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define POWERMATE_VENDOR 0x077d /* Griffin Technology, Inc. */ 3962306a36Sopenharmony_ci#define POWERMATE_PRODUCT_NEW 0x0410 /* Griffin PowerMate */ 4062306a36Sopenharmony_ci#define POWERMATE_PRODUCT_OLD 0x04AA /* Griffin soundKnob */ 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define CONTOUR_VENDOR 0x05f3 /* Contour Design, Inc. */ 4362306a36Sopenharmony_ci#define CONTOUR_JOG 0x0240 /* Jog and Shuttle */ 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* these are the command codes we send to the device */ 4662306a36Sopenharmony_ci#define SET_STATIC_BRIGHTNESS 0x01 4762306a36Sopenharmony_ci#define SET_PULSE_ASLEEP 0x02 4862306a36Sopenharmony_ci#define SET_PULSE_AWAKE 0x03 4962306a36Sopenharmony_ci#define SET_PULSE_MODE 0x04 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/* these refer to bits in the powermate_device's requires_update field. */ 5262306a36Sopenharmony_ci#define UPDATE_STATIC_BRIGHTNESS (1<<0) 5362306a36Sopenharmony_ci#define UPDATE_PULSE_ASLEEP (1<<1) 5462306a36Sopenharmony_ci#define UPDATE_PULSE_AWAKE (1<<2) 5562306a36Sopenharmony_ci#define UPDATE_PULSE_MODE (1<<3) 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* at least two versions of the hardware exist, with differing payload 5862306a36Sopenharmony_ci sizes. the first three bytes always contain the "interesting" data in 5962306a36Sopenharmony_ci the relevant format. */ 6062306a36Sopenharmony_ci#define POWERMATE_PAYLOAD_SIZE_MAX 6 6162306a36Sopenharmony_ci#define POWERMATE_PAYLOAD_SIZE_MIN 3 6262306a36Sopenharmony_cistruct powermate_device { 6362306a36Sopenharmony_ci signed char *data; 6462306a36Sopenharmony_ci dma_addr_t data_dma; 6562306a36Sopenharmony_ci struct urb *irq, *config; 6662306a36Sopenharmony_ci struct usb_ctrlrequest *configcr; 6762306a36Sopenharmony_ci struct usb_device *udev; 6862306a36Sopenharmony_ci struct usb_interface *intf; 6962306a36Sopenharmony_ci struct input_dev *input; 7062306a36Sopenharmony_ci spinlock_t lock; 7162306a36Sopenharmony_ci int static_brightness; 7262306a36Sopenharmony_ci int pulse_speed; 7362306a36Sopenharmony_ci int pulse_table; 7462306a36Sopenharmony_ci int pulse_asleep; 7562306a36Sopenharmony_ci int pulse_awake; 7662306a36Sopenharmony_ci int requires_update; // physical settings which are out of sync 7762306a36Sopenharmony_ci char phys[64]; 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic char pm_name_powermate[] = "Griffin PowerMate"; 8162306a36Sopenharmony_cistatic char pm_name_soundknob[] = "Griffin SoundKnob"; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic void powermate_config_complete(struct urb *urb); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* Callback for data arriving from the PowerMate over the USB interrupt pipe */ 8662306a36Sopenharmony_cistatic void powermate_irq(struct urb *urb) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci struct powermate_device *pm = urb->context; 8962306a36Sopenharmony_ci struct device *dev = &pm->intf->dev; 9062306a36Sopenharmony_ci int retval; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci switch (urb->status) { 9362306a36Sopenharmony_ci case 0: 9462306a36Sopenharmony_ci /* success */ 9562306a36Sopenharmony_ci break; 9662306a36Sopenharmony_ci case -ECONNRESET: 9762306a36Sopenharmony_ci case -ENOENT: 9862306a36Sopenharmony_ci case -ESHUTDOWN: 9962306a36Sopenharmony_ci /* this urb is terminated, clean up */ 10062306a36Sopenharmony_ci dev_dbg(dev, "%s - urb shutting down with status: %d\n", 10162306a36Sopenharmony_ci __func__, urb->status); 10262306a36Sopenharmony_ci return; 10362306a36Sopenharmony_ci default: 10462306a36Sopenharmony_ci dev_dbg(dev, "%s - nonzero urb status received: %d\n", 10562306a36Sopenharmony_ci __func__, urb->status); 10662306a36Sopenharmony_ci goto exit; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* handle updates to device state */ 11062306a36Sopenharmony_ci input_report_key(pm->input, BTN_0, pm->data[0] & 0x01); 11162306a36Sopenharmony_ci input_report_rel(pm->input, REL_DIAL, pm->data[1]); 11262306a36Sopenharmony_ci input_sync(pm->input); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ciexit: 11562306a36Sopenharmony_ci retval = usb_submit_urb (urb, GFP_ATOMIC); 11662306a36Sopenharmony_ci if (retval) 11762306a36Sopenharmony_ci dev_err(dev, "%s - usb_submit_urb failed with result: %d\n", 11862306a36Sopenharmony_ci __func__, retval); 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/* Decide if we need to issue a control message and do so. Must be called with pm->lock taken */ 12262306a36Sopenharmony_cistatic void powermate_sync_state(struct powermate_device *pm) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci if (pm->requires_update == 0) 12562306a36Sopenharmony_ci return; /* no updates are required */ 12662306a36Sopenharmony_ci if (pm->config->status == -EINPROGRESS) 12762306a36Sopenharmony_ci return; /* an update is already in progress; it'll issue this update when it completes */ 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci if (pm->requires_update & UPDATE_PULSE_ASLEEP){ 13062306a36Sopenharmony_ci pm->configcr->wValue = cpu_to_le16( SET_PULSE_ASLEEP ); 13162306a36Sopenharmony_ci pm->configcr->wIndex = cpu_to_le16( pm->pulse_asleep ? 1 : 0 ); 13262306a36Sopenharmony_ci pm->requires_update &= ~UPDATE_PULSE_ASLEEP; 13362306a36Sopenharmony_ci }else if (pm->requires_update & UPDATE_PULSE_AWAKE){ 13462306a36Sopenharmony_ci pm->configcr->wValue = cpu_to_le16( SET_PULSE_AWAKE ); 13562306a36Sopenharmony_ci pm->configcr->wIndex = cpu_to_le16( pm->pulse_awake ? 1 : 0 ); 13662306a36Sopenharmony_ci pm->requires_update &= ~UPDATE_PULSE_AWAKE; 13762306a36Sopenharmony_ci }else if (pm->requires_update & UPDATE_PULSE_MODE){ 13862306a36Sopenharmony_ci int op, arg; 13962306a36Sopenharmony_ci /* the powermate takes an operation and an argument for its pulse algorithm. 14062306a36Sopenharmony_ci the operation can be: 14162306a36Sopenharmony_ci 0: divide the speed 14262306a36Sopenharmony_ci 1: pulse at normal speed 14362306a36Sopenharmony_ci 2: multiply the speed 14462306a36Sopenharmony_ci the argument only has an effect for operations 0 and 2, and ranges between 14562306a36Sopenharmony_ci 1 (least effect) to 255 (maximum effect). 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci thus, several states are equivalent and are coalesced into one state. 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci we map this onto a range from 0 to 510, with: 15062306a36Sopenharmony_ci 0 -- 254 -- use divide (0 = slowest) 15162306a36Sopenharmony_ci 255 -- use normal speed 15262306a36Sopenharmony_ci 256 -- 510 -- use multiple (510 = fastest). 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci Only values of 'arg' quite close to 255 are particularly useful/spectacular. 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_ci if (pm->pulse_speed < 255) { 15762306a36Sopenharmony_ci op = 0; // divide 15862306a36Sopenharmony_ci arg = 255 - pm->pulse_speed; 15962306a36Sopenharmony_ci } else if (pm->pulse_speed > 255) { 16062306a36Sopenharmony_ci op = 2; // multiply 16162306a36Sopenharmony_ci arg = pm->pulse_speed - 255; 16262306a36Sopenharmony_ci } else { 16362306a36Sopenharmony_ci op = 1; // normal speed 16462306a36Sopenharmony_ci arg = 0; // can be any value 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci pm->configcr->wValue = cpu_to_le16( (pm->pulse_table << 8) | SET_PULSE_MODE ); 16762306a36Sopenharmony_ci pm->configcr->wIndex = cpu_to_le16( (arg << 8) | op ); 16862306a36Sopenharmony_ci pm->requires_update &= ~UPDATE_PULSE_MODE; 16962306a36Sopenharmony_ci } else if (pm->requires_update & UPDATE_STATIC_BRIGHTNESS) { 17062306a36Sopenharmony_ci pm->configcr->wValue = cpu_to_le16( SET_STATIC_BRIGHTNESS ); 17162306a36Sopenharmony_ci pm->configcr->wIndex = cpu_to_le16( pm->static_brightness ); 17262306a36Sopenharmony_ci pm->requires_update &= ~UPDATE_STATIC_BRIGHTNESS; 17362306a36Sopenharmony_ci } else { 17462306a36Sopenharmony_ci printk(KERN_ERR "powermate: unknown update required"); 17562306a36Sopenharmony_ci pm->requires_update = 0; /* fudge the bug */ 17662306a36Sopenharmony_ci return; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/* printk("powermate: %04x %04x\n", pm->configcr->wValue, pm->configcr->wIndex); */ 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci pm->configcr->bRequestType = 0x41; /* vendor request */ 18262306a36Sopenharmony_ci pm->configcr->bRequest = 0x01; 18362306a36Sopenharmony_ci pm->configcr->wLength = 0; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci usb_fill_control_urb(pm->config, pm->udev, usb_sndctrlpipe(pm->udev, 0), 18662306a36Sopenharmony_ci (void *) pm->configcr, NULL, 0, 18762306a36Sopenharmony_ci powermate_config_complete, pm); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (usb_submit_urb(pm->config, GFP_ATOMIC)) 19062306a36Sopenharmony_ci printk(KERN_ERR "powermate: usb_submit_urb(config) failed"); 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci/* Called when our asynchronous control message completes. We may need to issue another immediately */ 19462306a36Sopenharmony_cistatic void powermate_config_complete(struct urb *urb) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci struct powermate_device *pm = urb->context; 19762306a36Sopenharmony_ci unsigned long flags; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (urb->status) 20062306a36Sopenharmony_ci printk(KERN_ERR "powermate: config urb returned %d\n", urb->status); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci spin_lock_irqsave(&pm->lock, flags); 20362306a36Sopenharmony_ci powermate_sync_state(pm); 20462306a36Sopenharmony_ci spin_unlock_irqrestore(&pm->lock, flags); 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci/* Set the LED up as described and begin the sync with the hardware if required */ 20862306a36Sopenharmony_cistatic void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed, 20962306a36Sopenharmony_ci int pulse_table, int pulse_asleep, int pulse_awake) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci unsigned long flags; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (pulse_speed < 0) 21462306a36Sopenharmony_ci pulse_speed = 0; 21562306a36Sopenharmony_ci if (pulse_table < 0) 21662306a36Sopenharmony_ci pulse_table = 0; 21762306a36Sopenharmony_ci if (pulse_speed > 510) 21862306a36Sopenharmony_ci pulse_speed = 510; 21962306a36Sopenharmony_ci if (pulse_table > 2) 22062306a36Sopenharmony_ci pulse_table = 2; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci pulse_asleep = !!pulse_asleep; 22362306a36Sopenharmony_ci pulse_awake = !!pulse_awake; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci spin_lock_irqsave(&pm->lock, flags); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci /* mark state updates which are required */ 22962306a36Sopenharmony_ci if (static_brightness != pm->static_brightness) { 23062306a36Sopenharmony_ci pm->static_brightness = static_brightness; 23162306a36Sopenharmony_ci pm->requires_update |= UPDATE_STATIC_BRIGHTNESS; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci if (pulse_asleep != pm->pulse_asleep) { 23462306a36Sopenharmony_ci pm->pulse_asleep = pulse_asleep; 23562306a36Sopenharmony_ci pm->requires_update |= (UPDATE_PULSE_ASLEEP | UPDATE_STATIC_BRIGHTNESS); 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci if (pulse_awake != pm->pulse_awake) { 23862306a36Sopenharmony_ci pm->pulse_awake = pulse_awake; 23962306a36Sopenharmony_ci pm->requires_update |= (UPDATE_PULSE_AWAKE | UPDATE_STATIC_BRIGHTNESS); 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci if (pulse_speed != pm->pulse_speed || pulse_table != pm->pulse_table) { 24262306a36Sopenharmony_ci pm->pulse_speed = pulse_speed; 24362306a36Sopenharmony_ci pm->pulse_table = pulse_table; 24462306a36Sopenharmony_ci pm->requires_update |= UPDATE_PULSE_MODE; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci powermate_sync_state(pm); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci spin_unlock_irqrestore(&pm->lock, flags); 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci/* Callback from the Input layer when an event arrives from userspace to configure the LED */ 25362306a36Sopenharmony_cistatic int powermate_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int _value) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci unsigned int command = (unsigned int)_value; 25662306a36Sopenharmony_ci struct powermate_device *pm = input_get_drvdata(dev); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (type == EV_MSC && code == MSC_PULSELED){ 25962306a36Sopenharmony_ci /* 26062306a36Sopenharmony_ci bits 0- 7: 8 bits: LED brightness 26162306a36Sopenharmony_ci bits 8-16: 9 bits: pulsing speed modifier (0 ... 510); 0-254 = slower, 255 = standard, 256-510 = faster. 26262306a36Sopenharmony_ci bits 17-18: 2 bits: pulse table (0, 1, 2 valid) 26362306a36Sopenharmony_ci bit 19: 1 bit : pulse whilst asleep? 26462306a36Sopenharmony_ci bit 20: 1 bit : pulse constantly? 26562306a36Sopenharmony_ci */ 26662306a36Sopenharmony_ci int static_brightness = command & 0xFF; // bits 0-7 26762306a36Sopenharmony_ci int pulse_speed = (command >> 8) & 0x1FF; // bits 8-16 26862306a36Sopenharmony_ci int pulse_table = (command >> 17) & 0x3; // bits 17-18 26962306a36Sopenharmony_ci int pulse_asleep = (command >> 19) & 0x1; // bit 19 27062306a36Sopenharmony_ci int pulse_awake = (command >> 20) & 0x1; // bit 20 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci powermate_pulse_led(pm, static_brightness, pulse_speed, pulse_table, pulse_asleep, pulse_awake); 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci return 0; 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic int powermate_alloc_buffers(struct usb_device *udev, struct powermate_device *pm) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci pm->data = usb_alloc_coherent(udev, POWERMATE_PAYLOAD_SIZE_MAX, 28162306a36Sopenharmony_ci GFP_KERNEL, &pm->data_dma); 28262306a36Sopenharmony_ci if (!pm->data) 28362306a36Sopenharmony_ci return -1; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci pm->configcr = kmalloc(sizeof(*(pm->configcr)), GFP_KERNEL); 28662306a36Sopenharmony_ci if (!pm->configcr) 28762306a36Sopenharmony_ci return -ENOMEM; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci return 0; 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cistatic void powermate_free_buffers(struct usb_device *udev, struct powermate_device *pm) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci usb_free_coherent(udev, POWERMATE_PAYLOAD_SIZE_MAX, 29562306a36Sopenharmony_ci pm->data, pm->data_dma); 29662306a36Sopenharmony_ci kfree(pm->configcr); 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci/* Called whenever a USB device matching one in our supported devices table is connected */ 30062306a36Sopenharmony_cistatic int powermate_probe(struct usb_interface *intf, const struct usb_device_id *id) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci struct usb_device *udev = interface_to_usbdev (intf); 30362306a36Sopenharmony_ci struct usb_host_interface *interface; 30462306a36Sopenharmony_ci struct usb_endpoint_descriptor *endpoint; 30562306a36Sopenharmony_ci struct powermate_device *pm; 30662306a36Sopenharmony_ci struct input_dev *input_dev; 30762306a36Sopenharmony_ci int pipe, maxp; 30862306a36Sopenharmony_ci int error = -ENOMEM; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci interface = intf->cur_altsetting; 31162306a36Sopenharmony_ci if (interface->desc.bNumEndpoints < 1) 31262306a36Sopenharmony_ci return -EINVAL; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci endpoint = &interface->endpoint[0].desc; 31562306a36Sopenharmony_ci if (!usb_endpoint_is_int_in(endpoint)) 31662306a36Sopenharmony_ci return -EIO; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 31962306a36Sopenharmony_ci 0x0a, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 32062306a36Sopenharmony_ci 0, interface->desc.bInterfaceNumber, NULL, 0, 32162306a36Sopenharmony_ci USB_CTRL_SET_TIMEOUT); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci pm = kzalloc(sizeof(struct powermate_device), GFP_KERNEL); 32462306a36Sopenharmony_ci input_dev = input_allocate_device(); 32562306a36Sopenharmony_ci if (!pm || !input_dev) 32662306a36Sopenharmony_ci goto fail1; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci if (powermate_alloc_buffers(udev, pm)) 32962306a36Sopenharmony_ci goto fail2; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci pm->irq = usb_alloc_urb(0, GFP_KERNEL); 33262306a36Sopenharmony_ci if (!pm->irq) 33362306a36Sopenharmony_ci goto fail2; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci pm->config = usb_alloc_urb(0, GFP_KERNEL); 33662306a36Sopenharmony_ci if (!pm->config) 33762306a36Sopenharmony_ci goto fail3; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci pm->udev = udev; 34062306a36Sopenharmony_ci pm->intf = intf; 34162306a36Sopenharmony_ci pm->input = input_dev; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci usb_make_path(udev, pm->phys, sizeof(pm->phys)); 34462306a36Sopenharmony_ci strlcat(pm->phys, "/input0", sizeof(pm->phys)); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci spin_lock_init(&pm->lock); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci switch (le16_to_cpu(udev->descriptor.idProduct)) { 34962306a36Sopenharmony_ci case POWERMATE_PRODUCT_NEW: 35062306a36Sopenharmony_ci input_dev->name = pm_name_powermate; 35162306a36Sopenharmony_ci break; 35262306a36Sopenharmony_ci case POWERMATE_PRODUCT_OLD: 35362306a36Sopenharmony_ci input_dev->name = pm_name_soundknob; 35462306a36Sopenharmony_ci break; 35562306a36Sopenharmony_ci default: 35662306a36Sopenharmony_ci input_dev->name = pm_name_soundknob; 35762306a36Sopenharmony_ci printk(KERN_WARNING "powermate: unknown product id %04x\n", 35862306a36Sopenharmony_ci le16_to_cpu(udev->descriptor.idProduct)); 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci input_dev->phys = pm->phys; 36262306a36Sopenharmony_ci usb_to_input_id(udev, &input_dev->id); 36362306a36Sopenharmony_ci input_dev->dev.parent = &intf->dev; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci input_set_drvdata(input_dev, pm); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci input_dev->event = powermate_input_event; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) | 37062306a36Sopenharmony_ci BIT_MASK(EV_MSC); 37162306a36Sopenharmony_ci input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0); 37262306a36Sopenharmony_ci input_dev->relbit[BIT_WORD(REL_DIAL)] = BIT_MASK(REL_DIAL); 37362306a36Sopenharmony_ci input_dev->mscbit[BIT_WORD(MSC_PULSELED)] = BIT_MASK(MSC_PULSELED); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* get a handle to the interrupt data pipe */ 37662306a36Sopenharmony_ci pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress); 37762306a36Sopenharmony_ci maxp = usb_maxpacket(udev, pipe); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci if (maxp < POWERMATE_PAYLOAD_SIZE_MIN || maxp > POWERMATE_PAYLOAD_SIZE_MAX) { 38062306a36Sopenharmony_ci printk(KERN_WARNING "powermate: Expected payload of %d--%d bytes, found %d bytes!\n", 38162306a36Sopenharmony_ci POWERMATE_PAYLOAD_SIZE_MIN, POWERMATE_PAYLOAD_SIZE_MAX, maxp); 38262306a36Sopenharmony_ci maxp = POWERMATE_PAYLOAD_SIZE_MAX; 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci usb_fill_int_urb(pm->irq, udev, pipe, pm->data, 38662306a36Sopenharmony_ci maxp, powermate_irq, 38762306a36Sopenharmony_ci pm, endpoint->bInterval); 38862306a36Sopenharmony_ci pm->irq->transfer_dma = pm->data_dma; 38962306a36Sopenharmony_ci pm->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci /* register our interrupt URB with the USB system */ 39262306a36Sopenharmony_ci if (usb_submit_urb(pm->irq, GFP_KERNEL)) { 39362306a36Sopenharmony_ci error = -EIO; 39462306a36Sopenharmony_ci goto fail4; 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci error = input_register_device(pm->input); 39862306a36Sopenharmony_ci if (error) 39962306a36Sopenharmony_ci goto fail5; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci /* force an update of everything */ 40362306a36Sopenharmony_ci pm->requires_update = UPDATE_PULSE_ASLEEP | UPDATE_PULSE_AWAKE | UPDATE_PULSE_MODE | UPDATE_STATIC_BRIGHTNESS; 40462306a36Sopenharmony_ci powermate_pulse_led(pm, 0x80, 255, 0, 1, 0); // set default pulse parameters 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci usb_set_intfdata(intf, pm); 40762306a36Sopenharmony_ci return 0; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci fail5: usb_kill_urb(pm->irq); 41062306a36Sopenharmony_ci fail4: usb_free_urb(pm->config); 41162306a36Sopenharmony_ci fail3: usb_free_urb(pm->irq); 41262306a36Sopenharmony_ci fail2: powermate_free_buffers(udev, pm); 41362306a36Sopenharmony_ci fail1: input_free_device(input_dev); 41462306a36Sopenharmony_ci kfree(pm); 41562306a36Sopenharmony_ci return error; 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci/* Called when a USB device we've accepted ownership of is removed */ 41962306a36Sopenharmony_cistatic void powermate_disconnect(struct usb_interface *intf) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci struct powermate_device *pm = usb_get_intfdata (intf); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci usb_set_intfdata(intf, NULL); 42462306a36Sopenharmony_ci if (pm) { 42562306a36Sopenharmony_ci pm->requires_update = 0; 42662306a36Sopenharmony_ci usb_kill_urb(pm->irq); 42762306a36Sopenharmony_ci input_unregister_device(pm->input); 42862306a36Sopenharmony_ci usb_kill_urb(pm->config); 42962306a36Sopenharmony_ci usb_free_urb(pm->irq); 43062306a36Sopenharmony_ci usb_free_urb(pm->config); 43162306a36Sopenharmony_ci powermate_free_buffers(interface_to_usbdev(intf), pm); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci kfree(pm); 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic const struct usb_device_id powermate_devices[] = { 43862306a36Sopenharmony_ci { USB_DEVICE(POWERMATE_VENDOR, POWERMATE_PRODUCT_NEW) }, 43962306a36Sopenharmony_ci { USB_DEVICE(POWERMATE_VENDOR, POWERMATE_PRODUCT_OLD) }, 44062306a36Sopenharmony_ci { USB_DEVICE(CONTOUR_VENDOR, CONTOUR_JOG) }, 44162306a36Sopenharmony_ci { } /* Terminating entry */ 44262306a36Sopenharmony_ci}; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ciMODULE_DEVICE_TABLE (usb, powermate_devices); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic struct usb_driver powermate_driver = { 44762306a36Sopenharmony_ci .name = "powermate", 44862306a36Sopenharmony_ci .probe = powermate_probe, 44962306a36Sopenharmony_ci .disconnect = powermate_disconnect, 45062306a36Sopenharmony_ci .id_table = powermate_devices, 45162306a36Sopenharmony_ci}; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cimodule_usb_driver(powermate_driver); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ciMODULE_AUTHOR( "William R Sowerbutts" ); 45662306a36Sopenharmony_ciMODULE_DESCRIPTION( "Griffin Technology, Inc PowerMate driver" ); 45762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 458