2 * A driver for the Griffin Technology, Inc. "PowerMate" USB controller dial.
4 * v1.1, (c)2002 William R Sowerbutts <will@sowerbutts.com>
6 * This device is an anodized aluminium knob which connects over USB. It can measure
7 * clockwise and anticlockwise rotation. The dial also acts as a pushbutton with
8 * a spring for automatic release. The base contains a pair of LEDs which illuminate
9 * the translucent base. It rotates without limit and reports its relative rotation
10 * back to the host when polled by the USB controller.
12 * Testing with the knob I have has shown that it measures approximately 96 "clicks"
13 * for one full rotation. Testing with my High Speed Rotation Actuator (ok, it was
14 * a variable speed cordless electric drill) has shown that the device can measure
15 * speeds of up to 7 clicks either clockwise or anticlockwise between pollings from
16 * the host. If it counts more than 7 clicks before it is polled, it will wrap back
17 * to zero and start counting again. This was at quite high speed, however, almost
18 * certainly faster than the human hand could turn it. Griffin say that it loses a
19 * pulse or two on a direction change; the granularity is so fine that I never
20 * noticed this in practice.
22 * The device's microcontroller can be programmed to set the LED to either a constant
23 * intensity, or to a rhythmic pulsing. Several patterns and speeds are available.
25 * Griffin were very happy to provide documentation and free hardware for development.
29 #include <linux/kernel.h>
30 #include <linux/slab.h>
31 #include <linux/input.h>
32 #include <linux/module.h>
33 #include <linux/init.h>
34 #include <linux/usb.h>
36 #define POWERMATE_VENDOR 0x077d /* Griffin Technology, Inc. */
37 #define POWERMATE_PRODUCT_NEW 0x0410 /* Griffin PowerMate */
38 #define POWERMATE_PRODUCT_OLD 0x04AA /* Griffin soundKnob */
40 /* these are the command codes we send to the device */
41 #define SET_STATIC_BRIGHTNESS 0x01
42 #define SET_PULSE_ASLEEP 0x02
43 #define SET_PULSE_AWAKE 0x03
44 #define SET_PULSE_MODE 0x04
46 /* these refer to bits in the powermate_device's requires_update field. */
47 #define UPDATE_STATIC_BRIGHTNESS (1<<0)
48 #define UPDATE_PULSE_ASLEEP (1<<1)
49 #define UPDATE_PULSE_AWAKE (1<<2)
50 #define UPDATE_PULSE_MODE (1<<3)
52 /* at least two versions of the hardware exist, with differing payload
53 sizes. the first three bytes always contain the "interesting" data in
54 the relevant format. */
55 #define POWERMATE_PAYLOAD_SIZE_MAX 6
56 #define POWERMATE_PAYLOAD_SIZE_MIN 3
57 struct powermate_device {
58 signed char data[POWERMATE_PAYLOAD_SIZE_MAX];
59 struct urb irq, config;
60 struct usb_ctrlrequest configdr;
61 struct usb_device *udev;
62 struct input_dev input;
63 struct semaphore lock;
64 int static_brightness;
69 int requires_update; // physical settings which are out of sync
73 static char pm_name_powermate[] = "Griffin PowerMate";
74 static char pm_name_soundknob[] = "Griffin SoundKnob";
76 static void powermate_config_complete(struct urb *urb); /* forward declararation of callback */
78 /* Callback for data arriving from the PowerMate over the USB interrupt pipe */
79 static void powermate_irq(struct urb *urb)
81 struct powermate_device *pm = urb->context;
86 /* handle updates to device state */
87 input_report_key(&pm->input, BTN_0, pm->data[0] & 0x01);
88 input_report_rel(&pm->input, REL_DIAL, pm->data[1]);
91 /* Decide if we need to issue a control message and do so. Must be called with pm->lock down */
92 static void powermate_sync_state(struct powermate_device *pm)
94 if(pm->requires_update == 0)
95 return; /* no updates are required */
96 if(pm->config.status == -EINPROGRESS)
97 return; /* an update is already in progress; it'll issue this update when it completes */
99 if(pm->requires_update & UPDATE_PULSE_ASLEEP){
100 pm->configdr.wValue = cpu_to_le16( SET_PULSE_ASLEEP );
101 pm->configdr.wIndex = cpu_to_le16( pm->pulse_asleep ? 1 : 0 );
102 pm->requires_update &= ~UPDATE_PULSE_ASLEEP;
103 }else if(pm->requires_update & UPDATE_PULSE_AWAKE){
104 pm->configdr.wValue = cpu_to_le16( SET_PULSE_AWAKE );
105 pm->configdr.wIndex = cpu_to_le16( pm->pulse_awake ? 1 : 0 );
106 pm->requires_update &= ~UPDATE_PULSE_AWAKE;
107 }else if(pm->requires_update & UPDATE_PULSE_MODE){
109 /* the powermate takes an operation and an argument for its pulse algorithm.
110 the operation can be:
112 1: pulse at normal speed
113 2: multiply the speed
114 the argument only has an effect for operations 0 and 2, and ranges between
115 1 (least effect) to 255 (maximum effect).
117 thus, several states are equivalent and are coalesced into one state.
119 we map this onto a range from 0 to 510, with:
120 0 -- 254 -- use divide (0 = slowest)
121 255 -- use normal speed
122 256 -- 510 -- use multiple (510 = fastest).
124 Only values of 'arg' quite close to 255 are particularly useful/spectacular.
126 if(pm->pulse_speed < 255){
128 arg = 255 - pm->pulse_speed;
129 }else if(pm->pulse_speed > 255){
131 arg = pm->pulse_speed - 255;
133 op = 1; // normal speed
134 arg = 0; // can be any value
136 pm->configdr.wValue = cpu_to_le16( (pm->pulse_table << 8) | SET_PULSE_MODE );
137 pm->configdr.wIndex = cpu_to_le16( (arg << 8) | op );
138 pm->requires_update &= ~UPDATE_PULSE_MODE;
139 }else if(pm->requires_update & UPDATE_STATIC_BRIGHTNESS){
140 pm->configdr.wValue = cpu_to_le16( SET_STATIC_BRIGHTNESS );
141 pm->configdr.wIndex = cpu_to_le16( pm->static_brightness );
142 pm->requires_update &= ~UPDATE_STATIC_BRIGHTNESS;
144 printk(KERN_ERR "powermate: unknown update required");
145 pm->requires_update = 0; /* fudge the bug */
149 pm->config.dev = pm->udev; /* is this necessary? */
150 pm->configdr.bRequestType = 0x41; /* vendor request */
151 pm->configdr.bRequest = 0x01;
152 pm->configdr.wLength = 0;
154 FILL_CONTROL_URB(&pm->config, pm->udev, usb_sndctrlpipe(pm->udev, 0),
155 (void*)&pm->configdr, 0, 0, powermate_config_complete, pm);
157 if(usb_submit_urb(&pm->config))
158 printk(KERN_ERR "powermate: usb_submit_urb(config) failed");
161 /* Called when our asynchronous control message completes. We may need to issue another immediately */
162 static void powermate_config_complete(struct urb *urb)
164 struct powermate_device *pm = urb->context;
167 printk(KERN_ERR "powermate: config urb returned %d\n", urb->status);
170 powermate_sync_state(pm);
174 /* Set the LED up as described and begin the sync with the hardware if required */
175 static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed,
176 int pulse_table, int pulse_asleep, int pulse_awake)
182 if(pulse_speed > 510)
187 pulse_asleep = !!pulse_asleep;
188 pulse_awake = !!pulse_awake;
192 /* mark state updates which are required */
193 /* we update the static brightness if we've changed pulse mode,
194 because the hardware seems to stick at an arbitrary value rather
195 than jumping back to the static brightness we requested */
196 if(static_brightness != pm->static_brightness){
197 pm->static_brightness = static_brightness;
198 pm->requires_update |= UPDATE_STATIC_BRIGHTNESS;
200 if(pulse_asleep != pm->pulse_asleep){
201 pm->pulse_asleep = pulse_asleep;
202 pm->requires_update |= (UPDATE_PULSE_ASLEEP | UPDATE_STATIC_BRIGHTNESS);
204 if(pulse_awake != pm->pulse_awake){
205 pm->pulse_awake = pulse_awake;
206 pm->requires_update |= (UPDATE_PULSE_AWAKE | UPDATE_STATIC_BRIGHTNESS);
208 if(pulse_speed != pm->pulse_speed || pulse_table != pm->pulse_table){
209 pm->pulse_speed = pulse_speed;
210 pm->pulse_table = pulse_table;
211 pm->requires_update |= UPDATE_PULSE_MODE;
214 powermate_sync_state(pm);
219 /* Callback from the Input layer when an event arrives from userspace to configure the LED */
220 static int powermate_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int _value)
222 unsigned int command = (unsigned int)_value;
223 struct powermate_device *pm = dev->private;
225 if(type == EV_MSC && code == MSC_PULSELED){
227 bits 0- 7: 8 bits: LED brightness
228 bits 8-16: 9 bits: pulsing speed modifier (0 ... 510); 0-254 = slower, 255 = standard, 256-510 = faster.
229 bits 17-18: 2 bits: pulse table (0, 1, 2 valid)
230 bit 19: 1 bit : pulse whilst asleep?
231 bit 20: 1 bit : pulse constantly?
233 int static_brightness = command & 0xFF; // bits 0-7
234 int pulse_speed = (command >> 8) & 0x1FF; // bits 8-16
235 int pulse_table = (command >> 17) & 0x3; // bits 17-18
236 int pulse_asleep = (command >> 19) & 0x1; // bit 19
237 int pulse_awake = (command >> 20) & 0x1; // bit 20
239 powermate_pulse_led(pm, static_brightness, pulse_speed, pulse_table, pulse_asleep, pulse_awake);
245 /* Called whenever a USB device matching one in our supported devices table is connected */
246 static void *powermate_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
248 struct usb_interface_descriptor *interface;
249 struct usb_endpoint_descriptor *endpoint;
250 struct powermate_device *pm;
253 interface = udev->config[0].interface[ifnum].altsetting + 0;
254 endpoint = interface->endpoint + 0;
255 if (!(endpoint->bEndpointAddress & 0x80)) return NULL;
256 if ((endpoint->bmAttributes & 3) != 3) return NULL;
258 usb_set_protocol(udev, interface->bInterfaceNumber, 0);
259 usb_set_idle(udev, interface->bInterfaceNumber, 0, 0);
261 if (!(pm = kmalloc(sizeof(struct powermate_device), GFP_KERNEL)))
264 memset(pm, 0, sizeof(struct powermate_device));
267 init_MUTEX(&pm->lock);
269 /* get a handle to the interrupt data pipe */
270 pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
271 maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
273 if(maxp < POWERMATE_PAYLOAD_SIZE_MIN || maxp > POWERMATE_PAYLOAD_SIZE_MAX){
274 printk("powermate: Expected payload of %d--%d bytes, found %d bytes!\n",
275 POWERMATE_PAYLOAD_SIZE_MIN, POWERMATE_PAYLOAD_SIZE_MAX, maxp);
276 maxp = POWERMATE_PAYLOAD_SIZE_MAX;
280 FILL_INT_URB(&pm->irq, udev, pipe, pm->data, maxp, powermate_irq, pm, endpoint->bInterval);
282 /* register our interrupt URB with the USB system */
283 if(usb_submit_urb(&pm->irq)) {
285 return NULL; /* failure */
288 switch (udev->descriptor.idProduct) {
289 case POWERMATE_PRODUCT_NEW: pm->input.name = pm_name_powermate; break;
290 case POWERMATE_PRODUCT_OLD: pm->input.name = pm_name_soundknob; break;
292 pm->input.name = pm_name_soundknob;
293 printk(KERN_WARNING "powermate: unknown product id %04x\n", udev->descriptor.idProduct);
296 pm->input.private = pm;
297 pm->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_MSC);
298 pm->input.keybit[LONG(BTN_0)] = BIT(BTN_0);
299 pm->input.relbit[LONG(REL_DIAL)] = BIT(REL_DIAL);
300 pm->input.mscbit[LONG(MSC_PULSELED)] = BIT(MSC_PULSELED);
301 pm->input.idbus = BUS_USB;
302 pm->input.idvendor = udev->descriptor.idVendor;
303 pm->input.idproduct = udev->descriptor.idProduct;
304 pm->input.idversion = udev->descriptor.bcdDevice;
305 pm->input.event = powermate_input_event;
307 input_register_device(&pm->input);
309 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) /* Vojtech -- is this the correct version? */
312 usb_make_path(udev, path, 64);
313 snprintf(pm->phys, 64, "%s/input0", path);
314 printk(KERN_INFO "input: %s on %s\n", pm->input.name, pm->input.path);
317 printk(KERN_INFO "input: %s on input%d\n", pm->input.name, pm->input.number);
320 /* force an update of everything */
321 pm->requires_update = UPDATE_PULSE_ASLEEP | UPDATE_PULSE_AWAKE | UPDATE_PULSE_MODE | UPDATE_STATIC_BRIGHTNESS;
322 powermate_pulse_led(pm, 0x80, 255, 0, 1, 0); // set default pulse parameters
327 /* Called when a USB device we've accepted ownership of is removed */
328 static void powermate_disconnect(struct usb_device *dev, void *ptr)
330 struct powermate_device *pm = ptr;
332 pm->requires_update = 0;
333 usb_unlink_urb(&pm->irq);
334 input_unregister_device(&pm->input);
339 static struct usb_device_id powermate_devices [] = {
340 { USB_DEVICE(POWERMATE_VENDOR, POWERMATE_PRODUCT_NEW) },
341 { USB_DEVICE(POWERMATE_VENDOR, POWERMATE_PRODUCT_OLD) },
342 { } /* Terminating entry */
345 MODULE_DEVICE_TABLE (usb, powermate_devices);
347 static struct usb_driver powermate_driver = {
349 probe: powermate_probe,
350 disconnect: powermate_disconnect,
351 id_table: powermate_devices,
354 int powermate_init(void)
356 if (usb_register(&powermate_driver) < 0)
361 void powermate_cleanup(void)
363 usb_deregister(&powermate_driver);
366 module_init(powermate_init);
367 module_exit(powermate_cleanup);
369 MODULE_AUTHOR( "William R Sowerbutts" );
370 MODULE_DESCRIPTION( "Griffin Technology, Inc PowerMate driver" );
371 MODULE_LICENSE("GPL");