// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2006,2007 Daniel Mack, Tim Ruetz
*/
#include <linux/device.h>
#include <linux/gfp.h>
#include <linux/init.h>
#include <linux/usb.h>
#include <linux/usb/input.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include "device.h"
#include "input.h"
static const unsigned short keycode_ak1[] = { KEY_C, KEY_B, KEY_A };
static const unsigned short keycode_rk2[] = { KEY_1, KEY_2, KEY_3, KEY_4,
KEY_5, KEY_6, KEY_7 };
static const unsigned short keycode_rk3[] = { KEY_1, KEY_2, KEY_3, KEY_4,
KEY_5, KEY_6, KEY_7, KEY_8, KEY_9 };
static const unsigned short keycode_kore[] = {
KEY_FN_F1, /* "menu" */
KEY_FN_F7, /* "lcd backlight */
KEY_FN_F2, /* "control" */
KEY_FN_F3, /* "enter" */
KEY_FN_F4, /* "view" */
KEY_FN_F5, /* "esc" */
KEY_FN_F6, /* "sound" */
KEY_FN_F8, /* array spacer, never triggered. */
KEY_RIGHT,
KEY_DOWN,
KEY_UP,
KEY_LEFT,
KEY_SOUND, /* "listen" */
KEY_RECORD,
KEY_PLAYPAUSE,
KEY_STOP,
BTN_4, /* 8 softkeys */
BTN_3,
BTN_2,
BTN_1,
BTN_8,
BTN_7,
BTN_6,
BTN_5,
KEY_BRL_DOT4, /* touch sensitive knobs */
KEY_BRL_DOT3,
KEY_BRL_DOT2,
KEY_BRL_DOT1,
KEY_BRL_DOT8,
KEY_BRL_DOT7,
KEY_BRL_DOT6,
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 const 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 )
#define KONTROLS4_BUTTON(X) ((X) + BTN_MISC)
#define KONTROLS4_ABS(X) ((X) + ABS_HAT0X)
#define DEG90 (range / 2 )
#define DEG180 (range)
#define DEG270 (DEG90 + DEG180)
#define DEG360 (DEG180 * 2 )
#define HIGH_PEAK (268 )
#define LOW_PEAK (-7 )
/* some of these devices have endless rotation potentiometers
* built in which use two tapers, 90 degrees phase shifted.
* this algorithm decodes them to one single value, ranging
* from 0 to 999 */
static unsigned int decode_erp(unsigned char a, unsigned char b)
{
int weight_a, weight_b;
int pos_a, pos_b;
int ret;
int range = HIGH_PEAK - LOW_PEAK;
int mid_value = (HIGH_PEAK + LOW_PEAK) / 2 ;
weight_b = abs(mid_value - a) - (range / 2 - 100 ) / 2 ;
if (weight_b < 0 )
weight_b = 0 ;
if (weight_b > 100 )
weight_b = 100 ;
weight_a = 100 - weight_b;
if (a < mid_value) {
/* 0..90 and 270..360 degrees */
pos_b = b - LOW_PEAK + DEG270;
if (pos_b >= DEG360)
pos_b -= DEG360;
} else
/* 90..270 degrees */
pos_b = HIGH_PEAK - b + DEG90;
if (b > mid_value)
/* 0..180 degrees */
pos_a = a - LOW_PEAK;
else
/* 180..360 degrees */
pos_a = HIGH_PEAK - a + DEG180;
/* interpolate both slider values, depending on weight factors */
/* 0..99 x DEG360 */
ret = pos_a * weight_a + pos_b * weight_b;
/* normalize to 0..999 */
ret *= 10 ;
ret /= DEG360;
if (ret < 0 )
ret += 1000 ;
if (ret >= 1000 )
ret -= 1000 ;
return ret;
}
#undef DEG90
#undef DEG180
#undef DEG270
#undef DEG360
#undef HIGH_PEAK
#undef LOW_PEAK
static inline void snd_caiaq_input_report_abs(struct snd_usb_caiaqdev *cdev,
int axis, const unsigned char *buf,
int offset)
{
input_report_abs(cdev->input_dev, axis,
(buf[offset * 2 ] << 8 ) | buf[offset * 2 + 1 ]);
}
static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *cdev,
const unsigned char *buf,
unsigned int len)
{
struct input_dev *input_dev = cdev->input_dev;
switch (cdev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2):
snd_caiaq_input_report_abs(cdev, ABS_X, buf, 2 );
snd_caiaq_input_report_abs(cdev, ABS_Y, buf, 0 );
snd_caiaq_input_report_abs(cdev, ABS_Z, buf, 1 );
break ;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
snd_caiaq_input_report_abs(cdev, ABS_X, buf, 0 );
snd_caiaq_input_report_abs(cdev, ABS_Y, buf, 1 );
snd_caiaq_input_report_abs(cdev, ABS_Z, buf, 2 );
break ;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
snd_caiaq_input_report_abs(cdev, ABS_HAT0X, buf, 4 );
snd_caiaq_input_report_abs(cdev, ABS_HAT0Y, buf, 2 );
snd_caiaq_input_report_abs(cdev, ABS_HAT1X, buf, 6 );
snd_caiaq_input_report_abs(cdev, ABS_HAT1Y, buf, 1 );
snd_caiaq_input_report_abs(cdev, ABS_HAT2X, buf, 7 );
snd_caiaq_input_report_abs(cdev, ABS_HAT2Y, buf, 0 );
snd_caiaq_input_report_abs(cdev, ABS_HAT3X, buf, 5 );
snd_caiaq_input_report_abs(cdev, ABS_HAT3Y, buf, 3 );
break ;
}
input_sync(input_dev);
}
static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *cdev,
const char *buf, unsigned int len)
{
struct input_dev *input_dev = cdev->input_dev;
int i;
switch (cdev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):
i = decode_erp(buf[0 ], buf[1 ]);
input_report_abs(input_dev, ABS_X, i);
input_sync(input_dev);
break ;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
i = decode_erp(buf[7 ], buf[5 ]);
input_report_abs(input_dev, ABS_HAT0X, i);
i = decode_erp(buf[12 ], buf[14 ]);
input_report_abs(input_dev, ABS_HAT0Y, i);
i = decode_erp(buf[15 ], buf[13 ]);
input_report_abs(input_dev, ABS_HAT1X, i);
i = decode_erp(buf[0 ], buf[2 ]);
input_report_abs(input_dev, ABS_HAT1Y, i);
i = decode_erp(buf[3 ], buf[1 ]);
input_report_abs(input_dev, ABS_HAT2X, i);
i = decode_erp(buf[8 ], buf[10 ]);
input_report_abs(input_dev, ABS_HAT2Y, i);
i = decode_erp(buf[11 ], buf[9 ]);
input_report_abs(input_dev, ABS_HAT3X, i);
i = decode_erp(buf[4 ], buf[6 ]);
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 ;
}
}
static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *cdev,
unsigned char *buf, unsigned int len)
{
struct input_dev *input_dev = cdev->input_dev;
unsigned short *keycode = input_dev->keycode;
int i;
if (!keycode)
return ;
if (input_dev->id.product == USB_PID_RIGKONTROL2)
for (i = 0 ; i < len; i++)
buf[i] = ~buf[i];
for (i = 0 ; i < input_dev->keycodemax && i < len * 8 ; i++)
input_report_key(input_dev, keycode[i],
buf[i / 8 ] & (1 << (i % 8 )));
switch (cdev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
input_report_abs(cdev->input_dev, ABS_MISC, 255 - buf[4 ]);
break ;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
/* rotary encoders */
input_report_abs(cdev->input_dev, ABS_X, buf[5 ] & 0 xf);
input_report_abs(cdev->input_dev, ABS_Y, buf[5 ] >> 4 );
input_report_abs(cdev->input_dev, ABS_Z, buf[6 ] & 0 xf);
input_report_abs(cdev->input_dev, ABS_MISC, buf[6 ] >> 4 );
break ;
}
input_sync(input_dev);
}
#define TKS4_MSGBLOCK_SIZE 16
static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *cdev,
const unsigned char *buf,
unsigned int len)
{
struct device *dev = caiaqdev_to_dev(cdev);
while (len) {
unsigned int i, block_id = (buf[0 ] << 8 ) | buf[1 ];
switch (block_id) {
case 0 :
/* buttons */
for (i = 0 ; i < KONTROLS4_BUTTONS; i++)
input_report_key(cdev->input_dev, KONTROLS4_BUTTON(i),
(buf[4 + (i / 8 )] >> (i % 8 )) & 1 );
break ;
case 1 :
/* left wheel */
input_report_abs(cdev->input_dev, KONTROLS4_ABS(36 ), buf[9 ] | ((buf[8 ] & 0 x3) << 8 ));
/* right wheel */
input_report_abs(cdev->input_dev, KONTROLS4_ABS(37 ), buf[13 ] | ((buf[12 ] & 0 x3) << 8 ));
/* rotary encoders */
input_report_abs(cdev->input_dev, KONTROLS4_ABS(38 ), buf[3 ] & 0 xf);
input_report_abs(cdev->input_dev, KONTROLS4_ABS(39 ), buf[4 ] >> 4 );
input_report_abs(cdev->input_dev, KONTROLS4_ABS(40 ), buf[4 ] & 0 xf);
input_report_abs(cdev->input_dev, KONTROLS4_ABS(41 ), buf[5 ] >> 4 );
input_report_abs(cdev->input_dev, KONTROLS4_ABS(42 ), buf[5 ] & 0 xf);
input_report_abs(cdev->input_dev, KONTROLS4_ABS(43 ), buf[6 ] >> 4 );
input_report_abs(cdev->input_dev, KONTROLS4_ABS(44 ), buf[6 ] & 0 xf);
input_report_abs(cdev->input_dev, KONTROLS4_ABS(45 ), buf[7 ] >> 4 );
input_report_abs(cdev->input_dev, KONTROLS4_ABS(46 ), buf[7 ] & 0 xf);
break ;
case 2 :
/* Volume Fader Channel D */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(0 ), buf, 1 );
/* Volume Fader Channel B */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(1 ), buf, 2 );
/* Volume Fader Channel A */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(2 ), buf, 3 );
/* Volume Fader Channel C */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(3 ), buf, 4 );
/* Loop Volume */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(4 ), buf, 6 );
/* Crossfader */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(7 ), buf, 7 );
break ;
case 3 :
/* Tempo Fader R */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(6 ), buf, 3 );
/* Tempo Fader L */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(5 ), buf, 4 );
/* Mic Volume */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(8 ), buf, 6 );
/* Cue Mix */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(9 ), buf, 7 );
break ;
case 4 :
/* Wheel distance sensor L */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(10 ), buf, 1 );
/* Wheel distance sensor R */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(11 ), buf, 2 );
/* Channel D EQ - Filter */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(12 ), buf, 3 );
/* Channel D EQ - Low */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(13 ), buf, 4 );
/* Channel D EQ - Mid */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(14 ), buf, 5 );
/* Channel D EQ - Hi */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(15 ), buf, 6 );
/* FX2 - dry/wet */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(16 ), buf, 7 );
break ;
case 5 :
/* FX2 - 1 */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(17 ), buf, 1 );
/* FX2 - 2 */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(18 ), buf, 2 );
/* FX2 - 3 */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(19 ), buf, 3 );
/* Channel B EQ - Filter */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(20 ), buf, 4 );
/* Channel B EQ - Low */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(21 ), buf, 5 );
/* Channel B EQ - Mid */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(22 ), buf, 6 );
/* Channel B EQ - Hi */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(23 ), buf, 7 );
break ;
case 6 :
/* Channel A EQ - Filter */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(24 ), buf, 1 );
/* Channel A EQ - Low */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(25 ), buf, 2 );
/* Channel A EQ - Mid */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(26 ), buf, 3 );
/* Channel A EQ - Hi */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(27 ), buf, 4 );
/* Channel C EQ - Filter */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(28 ), buf, 5 );
/* Channel C EQ - Low */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(29 ), buf, 6 );
/* Channel C EQ - Mid */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(30 ), buf, 7 );
break ;
case 7 :
/* Channel C EQ - Hi */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(31 ), buf, 1 );
/* FX1 - wet/dry */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(32 ), buf, 2 );
/* FX1 - 1 */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(33 ), buf, 3 );
/* FX1 - 2 */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(34 ), buf, 4 );
/* FX1 - 3 */
snd_caiaq_input_report_abs(cdev, KONTROLS4_ABS(35 ), buf, 5 );
break ;
default :
dev_dbg(dev, "%s(): bogus block (id %d)\n" ,
__func__, block_id);
return ;
}
len -= TKS4_MSGBLOCK_SIZE;
buf += TKS4_MSGBLOCK_SIZE;
}
input_sync(cdev->input_dev);
}
#define MASCHINE_MSGBLOCK_SIZE 2
static void snd_usb_caiaq_maschine_dispatch(struct snd_usb_caiaqdev *cdev,
const unsigned char *buf,
unsigned int len)
{
unsigned int i, pad_id;
__le16 *pressure = (__le16 *) buf;
for (i = 0 ; i < MASCHINE_PADS; i++) {
pad_id = le16_to_cpu(*pressure) >> 12 ;
input_report_abs(cdev->input_dev, MASCHINE_PAD(pad_id),
le16_to_cpu(*pressure) & 0 xfff);
pressure++;
}
input_sync(cdev->input_dev);
}
static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb)
{
struct snd_usb_caiaqdev *cdev = urb->context;
unsigned char *buf = urb->transfer_buffer;
struct device *dev = &urb->dev->dev;
int ret;
if (urb->status || !cdev || urb != cdev->ep4_in_urb)
return ;
switch (cdev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
if (urb->actual_length < 24 )
goto requeue;
if (buf[0 ] & 0 x3)
snd_caiaq_input_read_io(cdev, buf + 1 , 7 );
if (buf[0 ] & 0 x4)
snd_caiaq_input_read_analog(cdev, buf + 8 , 16 );
break ;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
snd_usb_caiaq_tks4_dispatch(cdev, 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(cdev, buf, urb->actual_length);
break ;
}
requeue:
cdev->ep4_in_urb->actual_length = 0 ;
ret = usb_submit_urb(cdev->ep4_in_urb, GFP_ATOMIC);
if (ret < 0 )
dev_err(dev, "unable to submit urb. OOM!?\n" );
}
static int snd_usb_caiaq_input_open(struct input_dev *idev)
{
struct snd_usb_caiaqdev *cdev = input_get_drvdata(idev);
if (!cdev)
return -EINVAL;
switch (cdev->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(cdev->ep4_in_urb, GFP_KERNEL) != 0 )
return -EIO;
break ;
}
return 0 ;
}
static void snd_usb_caiaq_input_close(struct input_dev *idev)
{
struct snd_usb_caiaqdev *cdev = input_get_drvdata(idev);
if (!cdev)
return ;
switch (cdev->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(cdev->ep4_in_urb);
break ;
}
}
void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *cdev,
char *buf,
unsigned int len)
{
if (!cdev->input_dev || len < 1 )
return ;
switch (buf[0 ]) {
case EP1_CMD_READ_ANALOG:
snd_caiaq_input_read_analog(cdev, buf + 1 , len - 1 );
break ;
case EP1_CMD_READ_ERP:
snd_caiaq_input_read_erp(cdev, buf + 1 , len - 1 );
break ;
case EP1_CMD_READ_IO:
snd_caiaq_input_read_io(cdev, buf + 1 , len - 1 );
break ;
}
}
int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *cdev)
{
struct usb_device *usb_dev = cdev->chip.dev;
struct input_dev *input;
int i, ret = 0 ;
input = input_allocate_device();
if (!input)
return -ENOMEM;
usb_make_path(usb_dev, cdev->phys, sizeof (cdev->phys));
strlcat(cdev->phys, "/input0" , sizeof (cdev->phys));
input->name = cdev->product_name;
input->phys = cdev->phys;
usb_to_input_id(usb_dev, &input->id);
input->dev.parent = &usb_dev->dev;
input_set_drvdata(input, cdev);
switch (cdev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2):
input->evbit[0 ] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input->absbit[0 ] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |
BIT_MASK(ABS_Z);
BUILD_BUG_ON(sizeof (cdev->keycode) < sizeof (keycode_rk2));
memcpy(cdev->keycode, keycode_rk2, sizeof (keycode_rk2));
input->keycodemax = ARRAY_SIZE(keycode_rk2);
input_set_abs_params(input, ABS_X, 0 , 4096 , 0 , 10 );
input_set_abs_params(input, ABS_Y, 0 , 4096 , 0 , 10 );
input_set_abs_params(input, ABS_Z, 0 , 4096 , 0 , 10 );
snd_usb_caiaq_set_auto_msg(cdev, 1 , 10 , 0 );
break ;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):
input->evbit[0 ] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input->absbit[0 ] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |
BIT_MASK(ABS_Z);
BUILD_BUG_ON(sizeof (cdev->keycode) < sizeof (keycode_rk3));
memcpy(cdev->keycode, keycode_rk3, sizeof (keycode_rk3));
input->keycodemax = ARRAY_SIZE(keycode_rk3);
input_set_abs_params(input, ABS_X, 0 , 1024 , 0 , 10 );
input_set_abs_params(input, ABS_Y, 0 , 1024 , 0 , 10 );
input_set_abs_params(input, ABS_Z, 0 , 1024 , 0 , 10 );
snd_usb_caiaq_set_auto_msg(cdev, 1 , 10 , 0 );
break ;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):
input->evbit[0 ] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input->absbit[0 ] = BIT_MASK(ABS_X);
BUILD_BUG_ON(sizeof (cdev->keycode) < sizeof (keycode_ak1));
memcpy(cdev->keycode, keycode_ak1, sizeof (keycode_ak1));
input->keycodemax = ARRAY_SIZE(keycode_ak1);
input_set_abs_params(input, ABS_X, 0 , 999 , 0 , 10 );
snd_usb_caiaq_set_auto_msg(cdev, 1 , 0 , 5 );
break ;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
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_X) | BIT_MASK(ABS_Y) |
BIT_MASK(ABS_Z);
input->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC);
BUILD_BUG_ON(sizeof (cdev->keycode) < sizeof (keycode_kore));
memcpy(cdev->keycode, keycode_kore, sizeof (keycode_kore));
input->keycodemax = ARRAY_SIZE(keycode_kore);
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_X, 0 , 4096 , 0 , 10 );
input_set_abs_params(input, ABS_Y, 0 , 4096 , 0 , 10 );
input_set_abs_params(input, ABS_Z, 0 , 4096 , 0 , 10 );
input_set_abs_params(input, ABS_MISC, 0 , 255 , 0 , 1 );
snd_usb_caiaq_set_auto_msg(cdev, 1 , 10 , 5 );
break ;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
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_X) | BIT_MASK(ABS_Y) |
BIT_MASK(ABS_Z);
input->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC);
BUILD_BUG_ON(sizeof (cdev->keycode) < KONTROLX1_INPUTS);
for (i = 0 ; i < KONTROLX1_INPUTS; i++)
cdev->keycode[i] = BTN_MISC + i;
input->keycodemax = KONTROLX1_INPUTS;
/* analog potentiometers */
input_set_abs_params(input, ABS_HAT0X, 0 , 4096 , 0 , 10 );
input_set_abs_params(input, ABS_HAT0Y, 0 , 4096 , 0 , 10 );
input_set_abs_params(input, ABS_HAT1X, 0 , 4096 , 0 , 10 );
input_set_abs_params(input, ABS_HAT1Y, 0 , 4096 , 0 , 10 );
input_set_abs_params(input, ABS_HAT2X, 0 , 4096 , 0 , 10 );
input_set_abs_params(input, ABS_HAT2Y, 0 , 4096 , 0 , 10 );
input_set_abs_params(input, ABS_HAT3X, 0 , 4096 , 0 , 10 );
input_set_abs_params(input, ABS_HAT3Y, 0 , 4096 , 0 , 10 );
/* rotary encoders */
input_set_abs_params(input, ABS_X, 0 , 0 xf, 0 , 1 );
input_set_abs_params(input, ABS_Y, 0 , 0 xf, 0 , 1 );
input_set_abs_params(input, ABS_Z, 0 , 0 xf, 0 , 1 );
input_set_abs_params(input, ABS_MISC, 0 , 0 xf, 0 , 1 );
cdev->ep4_in_urb = usb_alloc_urb(0 , GFP_KERNEL);
if (!cdev->ep4_in_urb) {
ret = -ENOMEM;
goto exit_free_idev;
}
usb_fill_bulk_urb(cdev->ep4_in_urb, usb_dev,
usb_rcvbulkpipe(usb_dev, 0 x4),
cdev->ep4_in_buf, EP4_BUFSIZE,
snd_usb_caiaq_ep4_reply_dispatch, cdev);
ret = usb_urb_ep_type_check(cdev->ep4_in_urb);
if (ret < 0 )
goto exit_free_idev;
snd_usb_caiaq_set_auto_msg(cdev, 1 , 10 , 5 );
break ;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
input->evbit[0 ] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
BUILD_BUG_ON(sizeof (cdev->keycode) < KONTROLS4_BUTTONS);
for (i = 0 ; i < KONTROLS4_BUTTONS; i++)
cdev->keycode[i] = KONTROLS4_BUTTON(i);
input->keycodemax = KONTROLS4_BUTTONS;
for (i = 0 ; i < KONTROLS4_AXIS; i++) {
int axis = KONTROLS4_ABS(i);
input->absbit[BIT_WORD(axis)] |= BIT_MASK(axis);
}
/* 36 analog potentiometers and faders */
for (i = 0 ; i < 36 ; i++)
input_set_abs_params(input, KONTROLS4_ABS(i), 0 , 0 xfff, 0 , 10 );
/* 2 encoder wheels */
input_set_abs_params(input, KONTROLS4_ABS(36 ), 0 , 0 x3ff, 0 , 1 );
input_set_abs_params(input, KONTROLS4_ABS(37 ), 0 , 0 x3ff, 0 , 1 );
/* 9 rotary encoders */
for (i = 0 ; i < 9 ; i++)
input_set_abs_params(input, KONTROLS4_ABS(38 +i), 0 , 0 xf, 0 , 1 );
cdev->ep4_in_urb = usb_alloc_urb(0 , GFP_KERNEL);
if (!cdev->ep4_in_urb) {
ret = -ENOMEM;
goto exit_free_idev;
}
usb_fill_bulk_urb(cdev->ep4_in_urb, usb_dev,
usb_rcvbulkpipe(usb_dev, 0 x4),
cdev->ep4_in_buf, EP4_BUFSIZE,
snd_usb_caiaq_ep4_reply_dispatch, cdev);
ret = usb_urb_ep_type_check(cdev->ep4_in_urb);
if (ret < 0 )
goto exit_free_idev;
snd_usb_caiaq_set_auto_msg(cdev, 1 , 10 , 5 );
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 (cdev->keycode) < sizeof (keycode_maschine));
memcpy(cdev->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 , 0 xfff, 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 );
cdev->ep4_in_urb = usb_alloc_urb(0 , GFP_KERNEL);
if (!cdev->ep4_in_urb) {
ret = -ENOMEM;
goto exit_free_idev;
}
usb_fill_bulk_urb(cdev->ep4_in_urb, usb_dev,
usb_rcvbulkpipe(usb_dev, 0 x4),
cdev->ep4_in_buf, EP4_BUFSIZE,
snd_usb_caiaq_ep4_reply_dispatch, cdev);
ret = usb_urb_ep_type_check(cdev->ep4_in_urb);
if (ret < 0 )
goto exit_free_idev;
snd_usb_caiaq_set_auto_msg(cdev, 1 , 10 , 5 );
break ;
default :
/* no input methods supported on this device */
ret = -EINVAL;
goto exit_free_idev;
}
input->open = snd_usb_caiaq_input_open;
input->close = snd_usb_caiaq_input_close;
input->keycode = cdev->keycode;
input->keycodesize = sizeof (unsigned short );
for (i = 0 ; i < input->keycodemax; i++)
__set_bit(cdev->keycode[i], input->keybit);
cdev->input_dev = input;
ret = input_register_device(input);
if (ret < 0 )
goto exit_free_idev;
return 0 ;
exit_free_idev:
input_free_device(input);
cdev->input_dev = NULL;
return ret;
}
void snd_usb_caiaq_input_disconnect(struct snd_usb_caiaqdev *cdev)
{
if (!cdev || !cdev->input_dev)
return ;
usb_kill_urb(cdev->ep4_in_urb);
input_unregister_device(cdev->input_dev);
}
void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *cdev)
{
if (!cdev || !cdev->input_dev)
return ;
usb_free_urb(cdev->ep4_in_urb);
cdev->ep4_in_urb = NULL;
cdev->input_dev = NULL;
}
Messung V0.5 in Prozent C=95 H=92 G=93
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet am 2026-06-08)
¤
*© Formatika GbR, Deutschland