aboutsummaryrefslogtreecommitdiff
path: root/sound/usb/caiaq/input.c
diff options
context:
space:
mode:
authorWilliam Light <wrl@illest.net>2011-10-10 15:54:23 +0000
committerTakashi Iwai <tiwai@suse.de>2011-10-13 08:16:46 +0200
commite653510a27e63b41a5bae3c46eb093375e17ca2d (patch)
treef4fd7eed75963295c074ff08e517e90b19db5287 /sound/usb/caiaq/input.c
parent3d37fbe44112b06279efa04ad91a0e4b7a0c600c (diff)
ALSA: snd-usb-caiaq: Add support for Maschine
This adds partial support for the Maschine controller by Native Instruments. Supported now are the 1x1 MIDI interface and the 41 buttons, 11 endless rotary encoders, and 16 pressure-sensitive drum pads. Still to work on are the dimmable LEDs and the two monochrome screens. Signed-off-by: William Light <wrl@illest.net> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb/caiaq/input.c')
-rw-r--r--sound/usb/caiaq/input.c151
1 files changed, 150 insertions, 1 deletions
diff --git a/sound/usb/caiaq/input.c b/sound/usb/caiaq/input.c
index 9efb92e4090..26a121b42c3 100644
--- a/sound/usb/caiaq/input.c
+++ b/sound/usb/caiaq/input.c
@@ -67,6 +67,61 @@ static unsigned short keycode_kore[] = {
KEY_BRL_DOT5
};
+#define MASCHINE_BUTTONS (42)
+#define MASCHINE_BUTTON(X) ((X) + BTN_MISC)
+#define MASCHINE_PADS (16)
+#define MASCHINE_PAD(X) ((X) + ABS_PRESSURE)
+
+static unsigned short keycode_maschine[] = {
+ MASCHINE_BUTTON(40), /* mute */
+ MASCHINE_BUTTON(39), /* solo */
+ MASCHINE_BUTTON(38), /* select */
+ MASCHINE_BUTTON(37), /* duplicate */
+ MASCHINE_BUTTON(36), /* navigate */
+ MASCHINE_BUTTON(35), /* pad mode */
+ MASCHINE_BUTTON(34), /* pattern */
+ MASCHINE_BUTTON(33), /* scene */
+ KEY_RESERVED, /* spacer */
+
+ MASCHINE_BUTTON(30), /* rec */
+ MASCHINE_BUTTON(31), /* erase */
+ MASCHINE_BUTTON(32), /* shift */
+ MASCHINE_BUTTON(28), /* grid */
+ MASCHINE_BUTTON(27), /* > */
+ MASCHINE_BUTTON(26), /* < */
+ MASCHINE_BUTTON(25), /* restart */
+
+ MASCHINE_BUTTON(21), /* E */
+ MASCHINE_BUTTON(22), /* F */
+ MASCHINE_BUTTON(23), /* G */
+ MASCHINE_BUTTON(24), /* H */
+ MASCHINE_BUTTON(20), /* D */
+ MASCHINE_BUTTON(19), /* C */
+ MASCHINE_BUTTON(18), /* B */
+ MASCHINE_BUTTON(17), /* A */
+
+ MASCHINE_BUTTON(0), /* control */
+ MASCHINE_BUTTON(2), /* browse */
+ MASCHINE_BUTTON(4), /* < */
+ MASCHINE_BUTTON(6), /* snap */
+ MASCHINE_BUTTON(7), /* autowrite */
+ MASCHINE_BUTTON(5), /* > */
+ MASCHINE_BUTTON(3), /* sampling */
+ MASCHINE_BUTTON(1), /* step */
+
+ MASCHINE_BUTTON(15), /* 8 softkeys */
+ MASCHINE_BUTTON(14),
+ MASCHINE_BUTTON(13),
+ MASCHINE_BUTTON(12),
+ MASCHINE_BUTTON(11),
+ MASCHINE_BUTTON(10),
+ MASCHINE_BUTTON(9),
+ MASCHINE_BUTTON(8),
+
+ MASCHINE_BUTTON(16), /* note repeat */
+ MASCHINE_BUTTON(29) /* play */
+};
+
#define KONTROLX1_INPUTS (40)
#define KONTROLS4_BUTTONS (12 * 8)
#define KONTROLS4_AXIS (46)
@@ -218,6 +273,29 @@ static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev,
input_report_abs(input_dev, ABS_HAT3Y, i);
input_sync(input_dev);
break;
+
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER):
+ /* 4 under the left screen */
+ input_report_abs(input_dev, ABS_HAT0X, decode_erp(buf[21], buf[20]));
+ input_report_abs(input_dev, ABS_HAT0Y, decode_erp(buf[15], buf[14]));
+ input_report_abs(input_dev, ABS_HAT1X, decode_erp(buf[9], buf[8]));
+ input_report_abs(input_dev, ABS_HAT1Y, decode_erp(buf[3], buf[2]));
+
+ /* 4 under the right screen */
+ input_report_abs(input_dev, ABS_HAT2X, decode_erp(buf[19], buf[18]));
+ input_report_abs(input_dev, ABS_HAT2Y, decode_erp(buf[13], buf[12]));
+ input_report_abs(input_dev, ABS_HAT3X, decode_erp(buf[7], buf[6]));
+ input_report_abs(input_dev, ABS_HAT3Y, decode_erp(buf[1], buf[0]));
+
+ /* volume */
+ input_report_abs(input_dev, ABS_RX, decode_erp(buf[17], buf[16]));
+ /* tempo */
+ input_report_abs(input_dev, ABS_RY, decode_erp(buf[11], buf[10]));
+ /* swing */
+ input_report_abs(input_dev, ABS_RZ, decode_erp(buf[5], buf[4]));
+
+ input_sync(input_dev);
+ break;
}
}
@@ -400,6 +478,25 @@ static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *dev,
input_sync(dev->input_dev);
}
+#define MASCHINE_MSGBLOCK_SIZE 2
+
+static void snd_usb_caiaq_maschine_dispatch(struct snd_usb_caiaqdev *dev,
+ const unsigned char *buf,
+ unsigned int len)
+{
+ unsigned int i, pad_id;
+ uint16_t pressure;
+
+ for (i = 0; i < MASCHINE_PADS; i++) {
+ pressure = be16_to_cpu(buf[i * 2] << 8 | buf[(i * 2) + 1]);
+ pad_id = pressure >> 12;
+
+ input_report_abs(dev->input_dev, MASCHINE_PAD(pad_id), pressure & 0xfff);
+ }
+
+ input_sync(dev->input_dev);
+}
+
static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb)
{
struct snd_usb_caiaqdev *dev = urb->context;
@@ -425,6 +522,13 @@ static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb)
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
snd_usb_caiaq_tks4_dispatch(dev, buf, urb->actual_length);
break;
+
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER):
+ if (urb->actual_length < (MASCHINE_PADS * MASCHINE_MSGBLOCK_SIZE))
+ goto requeue;
+
+ snd_usb_caiaq_maschine_dispatch(dev, buf, urb->actual_length);
+ break;
}
requeue:
@@ -444,6 +548,7 @@ static int snd_usb_caiaq_input_open(struct input_dev *idev)
switch (dev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER):
if (usb_submit_urb(dev->ep4_in_urb, GFP_KERNEL) != 0)
return -EIO;
break;
@@ -462,6 +567,7 @@ static void snd_usb_caiaq_input_close(struct input_dev *idev)
switch (dev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER):
usb_kill_urb(dev->ep4_in_urb);
break;
}
@@ -652,6 +758,50 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
break;
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER):
+ input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ input->absbit[0] = BIT_MASK(ABS_HAT0X) | BIT_MASK(ABS_HAT0Y) |
+ BIT_MASK(ABS_HAT1X) | BIT_MASK(ABS_HAT1Y) |
+ BIT_MASK(ABS_HAT2X) | BIT_MASK(ABS_HAT2Y) |
+ BIT_MASK(ABS_HAT3X) | BIT_MASK(ABS_HAT3Y) |
+ BIT_MASK(ABS_RX) | BIT_MASK(ABS_RY) |
+ BIT_MASK(ABS_RZ);
+
+ BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_maschine));
+ memcpy(dev->keycode, keycode_maschine, sizeof(keycode_maschine));
+ input->keycodemax = ARRAY_SIZE(keycode_maschine);
+
+ for (i = 0; i < MASCHINE_PADS; i++) {
+ input->absbit[0] |= MASCHINE_PAD(i);
+ input_set_abs_params(input, MASCHINE_PAD(i), 0, 0xfff, 5, 10);
+ }
+
+ input_set_abs_params(input, ABS_HAT0X, 0, 999, 0, 10);
+ input_set_abs_params(input, ABS_HAT0Y, 0, 999, 0, 10);
+ input_set_abs_params(input, ABS_HAT1X, 0, 999, 0, 10);
+ input_set_abs_params(input, ABS_HAT1Y, 0, 999, 0, 10);
+ input_set_abs_params(input, ABS_HAT2X, 0, 999, 0, 10);
+ input_set_abs_params(input, ABS_HAT2Y, 0, 999, 0, 10);
+ input_set_abs_params(input, ABS_HAT3X, 0, 999, 0, 10);
+ input_set_abs_params(input, ABS_HAT3Y, 0, 999, 0, 10);
+ input_set_abs_params(input, ABS_RX, 0, 999, 0, 10);
+ input_set_abs_params(input, ABS_RY, 0, 999, 0, 10);
+ input_set_abs_params(input, ABS_RZ, 0, 999, 0, 10);
+
+ dev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->ep4_in_urb) {
+ ret = -ENOMEM;
+ goto exit_free_idev;
+ }
+
+ usb_fill_bulk_urb(dev->ep4_in_urb, usb_dev,
+ usb_rcvbulkpipe(usb_dev, 0x4),
+ dev->ep4_in_buf, EP4_BUFSIZE,
+ snd_usb_caiaq_ep4_reply_dispatch, dev);
+
+ snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5);
+ break;
+
default:
/* no input methods supported on this device */
goto exit_free_idev;
@@ -690,4 +840,3 @@ void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev)
input_unregister_device(dev->input_dev);
dev->input_dev = NULL;
}
-