2 * mediactrl.c -- Jog Shuttle device support
3 * Copyright (C) 2001-2007 Dan Dennedy <dan@dennedy.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 #include <sys/ioctl.h>
22 #include <sys/types.h>
25 #include <asm/types.h>
32 #include <linux/input.h>
33 #include "mediactrl.h"
36 static char *_shuttle_name = "Shuttle";
37 static char *_jog_name = "Jog";
42 static struct media_ctrl_key mc_shuttle_pro_keys[] = {
43 { 0x100, "Button 1", MEDIA_CTRL_F1 },
44 { 0x101, "Button 2", MEDIA_CTRL_F2 },
45 { 0x102, "Button 3", MEDIA_CTRL_F3 },
46 { 0x103, "Button 4", MEDIA_CTRL_F4 },
47 { 0x104, "Button 5", MEDIA_CTRL_B4 },
48 { 0x105, "Button 6", MEDIA_CTRL_B2 },
49 { 0x106, "Button 7", MEDIA_CTRL_B1 },
50 { 0x107, "Button 8", MEDIA_CTRL_B3 },
51 { 0x108, "Button 9", MEDIA_CTRL_B5 },
52 { 0x109, "Button 10", MEDIA_CTRL_B6 },
53 { 0x10a, "Button 11", MEDIA_CTRL_B7 },
54 { 0x10b, "Button 12", MEDIA_CTRL_B8 },
55 { 0x10c, "Button 13", MEDIA_CTRL_B9 },
63 static struct media_ctrl_key _mc_shuttle_xpress_keys[] = {
64 { 0x104, "Button B4", MEDIA_CTRL_B4 },
65 { 0x105, "Button B2", MEDIA_CTRL_B2 },
66 { 0x106, "Button B1", MEDIA_CTRL_B1 },
67 { 0x107, "Button B3", MEDIA_CTRL_B3 },
68 { 0x108, "Button B5", MEDIA_CTRL_B5 },
72 static struct media_ctrl_key mc_shuttle_xpress_keys[] = {
73 { 0x104, "Button B1", MEDIA_CTRL_B1},
74 { 0x105, "Button B2", MEDIA_CTRL_B2 },
75 { 0x106, "Button B3", MEDIA_CTRL_B3 },
76 { 0x107, "Button B4", MEDIA_CTRL_B4 },
77 { 0x108, "Button B5", MEDIA_CTRL_B5 },
86 static struct media_ctrl_key mc_jlcooper_mcs3_keys[] = {
87 { 0x107, "F1", MEDIA_CTRL_F1 },
88 { 0x101, "F2", MEDIA_CTRL_F2 },
89 { 0x105, "F3", MEDIA_CTRL_F3 },
90 { 0x102, "F4", MEDIA_CTRL_F4 },
91 { 0x103, "F5", MEDIA_CTRL_F5 },
92 { 0x104, "F6", MEDIA_CTRL_F6 },
93 { 0x10d, "W1", MEDIA_CTRL_B6 },
94 { 0x10e, "W2", MEDIA_CTRL_B4 },
95 { 0x100, "W3", MEDIA_CTRL_B2 },
96 { 0x106, "W4", MEDIA_CTRL_B1 },
97 { 0x110, "W5", MEDIA_CTRL_B3 },
98 { 0x111, "W6", MEDIA_CTRL_B5 },
99 { 0x115, "W7", MEDIA_CTRL_B7 },
100 { 0x116, "STICK_LEFT", MEDIA_CTRL_STICK_LEFT },
101 { 0x113, "STICK_RIGHT", MEDIA_CTRL_STICK_RIGHT },
102 { 0x114, "STICK_UP", MEDIA_CTRL_STICK_UP },
103 { 0x112, "STICK_DOWN", MEDIA_CTRL_STICK_DOWN },
104 { 0x10f, "Rewind", MEDIA_CTRL_REWIND },
105 { 0x108, "Fast Forward", MEDIA_CTRL_FAST_FORWARD },
106 { 0x109, "Stop", MEDIA_CTRL_STOP },
107 { 0x10a, "Play", MEDIA_CTRL_PLAY },
108 { 0x10b, "Record", MEDIA_CTRL_RECORD },
116 static struct media_ctrl_key mc_powermate_keys[] = {
117 { BTN_0, "Button", MEDIA_CTRL_B1 },
125 static struct media_ctrl_key mc_x_keys[] = {
126 { 0x102, "Button L1", MEDIA_CTRL_F1 },
127 { 0x103, "Button L2", MEDIA_CTRL_F9 },
128 { 0x104, "Button L3", MEDIA_CTRL_B1 },
129 { 0x105, "Button L4", MEDIA_CTRL_B3 },
130 { 0x106, "Button L5", MEDIA_CTRL_B5 },
131 { 0x10a, "Button L6", MEDIA_CTRL_F2 },
132 { 0x10b, "Button L7", MEDIA_CTRL_F10 },
133 { 0x10c, "Button L8", MEDIA_CTRL_B2 },
134 { 0x10d, "Button L9", MEDIA_CTRL_B4 },
135 { 0x10e, "Button L10", MEDIA_CTRL_B6 },
136 { 0x112, "Button C1", MEDIA_CTRL_F3 },
137 { 0x11a, "Button C2", MEDIA_CTRL_F4 },
138 { 0x122, "Button C3", MEDIA_CTRL_F5 },
139 { 0x12a, "Button C4", MEDIA_CTRL_F6 },
140 { 0x113, "Button C5", MEDIA_CTRL_F11 },
141 { 0x11b, "Button C6", MEDIA_CTRL_F12 },
142 { 0x123, "Button C7", MEDIA_CTRL_F13 },
143 { 0x12b, "Button C8", MEDIA_CTRL_F14 },
144 { 0x132, "Button R1", MEDIA_CTRL_F7 },
145 { 0x133, "Button R2", MEDIA_CTRL_F15 },
146 { 0x134, "Button R3", MEDIA_CTRL_B7 },
147 { 0x135, "Button R4", MEDIA_CTRL_B9 },
148 { 0x136, "Button R5", MEDIA_CTRL_B11 },
149 { 0x13a, "Button R6", MEDIA_CTRL_F8 },
150 { 0x13b, "Button R7", MEDIA_CTRL_F16 },
151 { 0x13c, "Button R8", MEDIA_CTRL_B8 },
152 { 0x13d, "Button R9", MEDIA_CTRL_B10 },
153 { 0x13e, "Button R10", MEDIA_CTRL_B12 },
157 struct media_ctrl_key *media_ctrl_get_key(struct media_ctrl *ctrl, int code, int *index)
160 struct media_ctrl_key *keys = ctrl->device->keys;
162 while ( keys[i].key != 0 ) {
163 if (keys[i].key == code) {
174 int media_ctrl_get_keys_count(struct media_ctrl *ctrl)
177 struct media_ctrl_key *keys = ctrl->device->keys;
179 while ( keys[i].key != 0 ) {
186 void translate_contour_hid_event(struct media_ctrl *ctrl, struct input_event *ev, struct media_ctrl_event *me)
193 if (ev->type == EV_REL) {
194 /* First check the outer dial */
195 if (ev->code == REL_WHEEL) {
197 cv = (signed int)ev->value;
198 if (cv == 1 || cv == -1 ) cv = 0;
201 if ( cv == ctrl->lastshu ) return;
204 if ( cv > 0 ) cv -= 1;
205 if ( cv < 0) cv += 1;
207 //printf("Shuttle: %d\n", cv);
208 me->type = MEDIA_CTRL_EVENT_SHUTTLE;
210 me->name = _shuttle_name;
212 } else if (ev->code == REL_DIAL) {
214 if ( ctrl->lastval == -1 ) ctrl->lastval = ev->value;
218 if ( lv == cv ) return;
222 if (cv < 10 && lv > 0xF0) cv +=0x100;
223 if (lv < 10 && cv > 0xF0) lv +=0x100;
225 me->type = MEDIA_CTRL_EVENT_JOG;
227 me->name = _jog_name;
229 ctrl->jogpos += me->value;
230 //printf("Jog: %06ld (%d)\n", ctrl->jogpos, me->value);
233 } else if (ev->type == EV_KEY) {
235 struct media_ctrl_key *key = media_ctrl_get_key(ctrl, ev->code, &index);
236 if ( key == NULL ) return;
238 me->type = MEDIA_CTRL_EVENT_KEY;
239 me->code = key->code;
240 me->value = ev->value;
241 me->name = ( char* )key->name;
244 //printf("Key: %04x %02x: %s\n", ev->code, ev->value, key->name);
250 void translate_compliant(struct media_ctrl *ctrl, struct input_event *ev, struct media_ctrl_event *me)
254 // printf("Translate %02x %02x\n", ev->type, ev->code );
256 if (ev->type == EV_REL) {
257 if (ev->code == REL_DIAL) {
259 me->type = MEDIA_CTRL_EVENT_JOG;
260 me->value = (signed int)ev->value;
261 me->name = _jog_name;
263 ctrl->jogpos += me->value;
264 //printf("Jog: %06ld (%d)\n", ctrl->jogpos, me->value);
267 } else if (ev->type == EV_ABS) {
269 if ( ev->code == 0x1c || ev->code == ABS_THROTTLE ) {
270 //printf("ABS_MISC\n" );
271 me->type = MEDIA_CTRL_EVENT_SHUTTLE;
272 me->value = (signed int)ev->value;
273 me->name = _shuttle_name;
275 ctrl->shuttlepos = me->value;
276 //printf("Shuttle: %06d (%d)\n", ctrl->shuttlepos, me->value);
278 } else if (ev->type == EV_KEY) {
280 struct media_ctrl_key *key = media_ctrl_get_key(ctrl, ev->code, &index);
281 if ( key == NULL ) return;
283 me->type = MEDIA_CTRL_EVENT_KEY;
284 me->code = key->code;
285 me->value = ev->value;
286 me->name = ( char* )key->name;
289 //printf("Key: %04x %02x: %s\n", ev->code, ev->value, key->name);
294 struct media_ctrl_device supported_devices[] = {
295 { 0x0b33, 0x0030, "Contour ShuttlePRO v2", mc_shuttle_pro_keys, translate_contour_hid_event },
296 { 0x0b33, 0x0020, "Contour Design ShuttleXpress", mc_shuttle_xpress_keys, translate_contour_hid_event },
297 { 0x0b33, 0x0010, "Contour ShuttlePro", mc_shuttle_pro_keys, translate_contour_hid_event },
298 { 0x0b33, 0x0011, "Contour ShuttlePro", mc_shuttle_pro_keys, translate_contour_hid_event }, /* Hercules OEM */
299 { 0x05f3, 0x0240, "Contour ShuttlePro", mc_shuttle_pro_keys, translate_contour_hid_event },
300 { 0x0760, 0x0001, "JLCooper MCS3", mc_jlcooper_mcs3_keys, translate_compliant },
301 { 0x077d, 0x0410, "Griffin PowerMate", mc_powermate_keys, translate_compliant },
302 { 0x05f3, 0x0241, "X-Keys Editor", mc_x_keys, translate_contour_hid_event },
307 void media_ctrl_translate(struct media_ctrl *ctrl, struct input_event *ev, struct media_ctrl_event *me)
309 if ( ctrl->device ) ctrl->device->translate(ctrl, ev, me);
313 void media_ctrl_read_event(struct media_ctrl *ctrl, struct media_ctrl_event *me)
316 struct input_event ev;
318 // struct media_ctrl_event me;
320 if ( ctrl->fd > 0 ) {
321 n = read(ctrl->fd, &ev, sizeof(ev));
326 if (n != sizeof(ev)) {
327 //printf("JogShuttle::inputCallback: read: (%d) %s\n", errno, strerror(errno));
333 if ( ctrl->device && ctrl->device->translate)
334 ctrl->device->translate(ctrl, &ev, me);
338 if ( me->type == MEDIA_CTRL_EVENT_JOG ) {
339 struct timeval timev;
340 gettimeofday(&timev, NULL);
341 unsigned long now = (unsigned long)timev.tv_usec + (1000000*(unsigned long)timev.tv_sec);
342 if ( now < ctrl->last_jog_time + 40000 ) {
343 //printf("*** Fast Jog %02d %05d ***\n", me->value, now - ctrl->last_jog_time);
344 ctrl->jogrel = me->value;
345 me->type = MEDIA_CTRL_EVENT_NONE;
347 me->value += ctrl->jogrel;
349 ctrl->last_jog_time = now;
350 // printf("*** Jog %02d ***\n", me->value);
359 int probe_device(struct media_ctrl *mc)
364 if ( ioctl(mc->fd, EVIOCGID, &devinfo) ) {
365 perror("evdev ioctl");
370 if ( supported_devices[i].vendor == devinfo[1]
371 && supported_devices[i].product == devinfo[2] ) {
373 mc->device = &supported_devices[i];
374 //printf("Success on /dev/input/event%d: %s\n", mc->eventno, mc->device->name);
376 // mc->translate = mc->device.translate_function;
377 // mc = malloc(sizeof(struct media_ctrl));
380 mc->last_jog_time = 0;
386 } while ( supported_devices[++i].vendor != 0 );
392 void media_ctrl_get_device_list()
399 void find_first_device(struct media_ctrl *mc)
404 for ( i = 0; i < 32; i++ ) {
405 sprintf(buf, "/dev/input/event%d", i);
406 fd = open( buf, O_RDONLY );
412 if( probe_device(mc) ) {
424 void media_ctrl_close(struct media_ctrl *mc)
428 memset( mc, 0, sizeof( struct media_ctrl ) );
432 void media_ctrl_open(struct media_ctrl *mc)
434 find_first_device(mc);
437 void media_ctrl_open2(struct media_ctrl *mc, const char *devname)
441 fd = open( devname, O_RDONLY );
448 if( probe_device(mc) ) {