diff options
| -rw-r--r-- | sound/usb/midi.c | 110 | ||||
| -rw-r--r-- | sound/usb/midi.h | 2 | ||||
| -rw-r--r-- | sound/usb/quirks-table.h | 11 | ||||
| -rw-r--r-- | sound/usb/quirks.c | 1 | ||||
| -rw-r--r-- | sound/usb/usbaudio.h | 1 |
5 files changed, 125 insertions, 0 deletions
diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 2c1558c327bb..9c23d89066e4 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c | |||
| @@ -645,6 +645,105 @@ static struct usb_protocol_ops snd_usbmidi_cme_ops = { | |||
| 645 | }; | 645 | }; |
| 646 | 646 | ||
| 647 | /* | 647 | /* |
| 648 | * AKAI MPD16 protocol: | ||
| 649 | * | ||
| 650 | * For control port (endpoint 1): | ||
| 651 | * ============================== | ||
| 652 | * One or more chunks consisting of first byte of (0x10 | msg_len) and then a | ||
| 653 | * SysEx message (msg_len=9 bytes long). | ||
| 654 | * | ||
| 655 | * For data port (endpoint 2): | ||
| 656 | * =========================== | ||
| 657 | * One or more chunks consisting of first byte of (0x20 | msg_len) and then a | ||
| 658 | * MIDI message (msg_len bytes long) | ||
| 659 | * | ||
| 660 | * Messages sent: Active Sense, Note On, Poly Pressure, Control Change. | ||
| 661 | */ | ||
| 662 | static void snd_usbmidi_akai_input(struct snd_usb_midi_in_endpoint *ep, | ||
| 663 | uint8_t *buffer, int buffer_length) | ||
| 664 | { | ||
| 665 | unsigned int pos = 0; | ||
| 666 | unsigned int len = (unsigned int)buffer_length; | ||
| 667 | while (pos < len) { | ||
| 668 | unsigned int port = (buffer[pos] >> 4) - 1; | ||
| 669 | unsigned int msg_len = buffer[pos] & 0x0f; | ||
| 670 | pos++; | ||
| 671 | if (pos + msg_len <= len && port < 2) | ||
| 672 | snd_usbmidi_input_data(ep, 0, &buffer[pos], msg_len); | ||
| 673 | pos += msg_len; | ||
| 674 | } | ||
| 675 | } | ||
| 676 | |||
| 677 | #define MAX_AKAI_SYSEX_LEN 9 | ||
| 678 | |||
| 679 | static void snd_usbmidi_akai_output(struct snd_usb_midi_out_endpoint *ep, | ||
| 680 | struct urb *urb) | ||
| 681 | { | ||
| 682 | uint8_t *msg; | ||
| 683 | int pos, end, count, buf_end; | ||
| 684 | uint8_t tmp[MAX_AKAI_SYSEX_LEN]; | ||
| 685 | struct snd_rawmidi_substream *substream = ep->ports[0].substream; | ||
| 686 | |||
| 687 | if (!ep->ports[0].active) | ||
| 688 | return; | ||
| 689 | |||
| 690 | msg = urb->transfer_buffer + urb->transfer_buffer_length; | ||
| 691 | buf_end = ep->max_transfer - MAX_AKAI_SYSEX_LEN - 1; | ||
| 692 | |||
| 693 | /* only try adding more data when there's space for at least 1 SysEx */ | ||
| 694 | while (urb->transfer_buffer_length < buf_end) { | ||
| 695 | count = snd_rawmidi_transmit_peek(substream, | ||
| 696 | tmp, MAX_AKAI_SYSEX_LEN); | ||
| 697 | if (!count) { | ||
| 698 | ep->ports[0].active = 0; | ||
| 699 | return; | ||
| 700 | } | ||
| 701 | /* try to skip non-SysEx data */ | ||
| 702 | for (pos = 0; pos < count && tmp[pos] != 0xF0; pos++) | ||
| 703 | ; | ||
| 704 | |||
| 705 | if (pos > 0) { | ||
| 706 | snd_rawmidi_transmit_ack(substream, pos); | ||
| 707 | continue; | ||
| 708 | } | ||
| 709 | |||
| 710 | /* look for the start or end marker */ | ||
| 711 | for (end = 1; end < count && tmp[end] < 0xF0; end++) | ||
| 712 | ; | ||
| 713 | |||
| 714 | /* next SysEx started before the end of current one */ | ||
| 715 | if (end < count && tmp[end] == 0xF0) { | ||
| 716 | /* it's incomplete - drop it */ | ||
| 717 | snd_rawmidi_transmit_ack(substream, end); | ||
| 718 | continue; | ||
| 719 | } | ||
| 720 | /* SysEx complete */ | ||
| 721 | if (end < count && tmp[end] == 0xF7) { | ||
| 722 | /* queue it, ack it, and get the next one */ | ||
| 723 | count = end + 1; | ||
| 724 | msg[0] = 0x10 | count; | ||
| 725 | memcpy(&msg[1], tmp, count); | ||
| 726 | snd_rawmidi_transmit_ack(substream, count); | ||
| 727 | urb->transfer_buffer_length += count + 1; | ||
| 728 | msg += count + 1; | ||
| 729 | continue; | ||
| 730 | } | ||
| 731 | /* less than 9 bytes and no end byte - wait for more */ | ||
| 732 | if (count < MAX_AKAI_SYSEX_LEN) { | ||
| 733 | ep->ports[0].active = 0; | ||
| 734 | return; | ||
| 735 | } | ||
| 736 | /* 9 bytes and no end marker in sight - malformed, skip it */ | ||
| 737 | snd_rawmidi_transmit_ack(substream, count); | ||
| 738 | } | ||
| 739 | } | ||
| 740 | |||
| 741 | static struct usb_protocol_ops snd_usbmidi_akai_ops = { | ||
| 742 | .input = snd_usbmidi_akai_input, | ||
| 743 | .output = snd_usbmidi_akai_output, | ||
| 744 | }; | ||
| 745 | |||
| 746 | /* | ||
| 648 | * Novation USB MIDI protocol: number of data bytes is in the first byte | 747 | * Novation USB MIDI protocol: number of data bytes is in the first byte |
| 649 | * (when receiving) (+1!) or in the second byte (when sending); data begins | 748 | * (when receiving) (+1!) or in the second byte (when sending); data begins |
| 650 | * at the third byte. | 749 | * at the third byte. |
| @@ -1434,6 +1533,11 @@ static struct port_info { | |||
| 1434 | EXTERNAL_PORT(0x086a, 0x0001, 8, "%s Broadcast"), | 1533 | EXTERNAL_PORT(0x086a, 0x0001, 8, "%s Broadcast"), |
| 1435 | EXTERNAL_PORT(0x086a, 0x0002, 8, "%s Broadcast"), | 1534 | EXTERNAL_PORT(0x086a, 0x0002, 8, "%s Broadcast"), |
| 1436 | EXTERNAL_PORT(0x086a, 0x0003, 4, "%s Broadcast"), | 1535 | EXTERNAL_PORT(0x086a, 0x0003, 4, "%s Broadcast"), |
| 1536 | /* Akai MPD16 */ | ||
| 1537 | CONTROL_PORT(0x09e8, 0x0062, 0, "%s Control"), | ||
| 1538 | PORT_INFO(0x09e8, 0x0062, 1, "%s MIDI", 0, | ||
| 1539 | SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | | ||
| 1540 | SNDRV_SEQ_PORT_TYPE_HARDWARE), | ||
| 1437 | /* Access Music Virus TI */ | 1541 | /* Access Music Virus TI */ |
| 1438 | EXTERNAL_PORT(0x133e, 0x0815, 0, "%s MIDI"), | 1542 | EXTERNAL_PORT(0x133e, 0x0815, 0, "%s MIDI"), |
| 1439 | PORT_INFO(0x133e, 0x0815, 1, "%s Synth", 0, | 1543 | PORT_INFO(0x133e, 0x0815, 1, "%s Synth", 0, |
| @@ -2035,6 +2139,12 @@ int snd_usbmidi_create(struct snd_card *card, | |||
| 2035 | umidi->usb_protocol_ops = &snd_usbmidi_cme_ops; | 2139 | umidi->usb_protocol_ops = &snd_usbmidi_cme_ops; |
| 2036 | err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); | 2140 | err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); |
| 2037 | break; | 2141 | break; |
| 2142 | case QUIRK_MIDI_AKAI: | ||
| 2143 | umidi->usb_protocol_ops = &snd_usbmidi_akai_ops; | ||
| 2144 | err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); | ||
| 2145 | /* endpoint 1 is input-only */ | ||
| 2146 | endpoints[1].out_cables = 0; | ||
| 2147 | break; | ||
| 2038 | default: | 2148 | default: |
| 2039 | snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type); | 2149 | snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type); |
| 2040 | err = -ENXIO; | 2150 | err = -ENXIO; |
diff --git a/sound/usb/midi.h b/sound/usb/midi.h index 2089ec987c66..2fca80b744c0 100644 --- a/sound/usb/midi.h +++ b/sound/usb/midi.h | |||
| @@ -37,6 +37,8 @@ struct snd_usb_midi_endpoint_info { | |||
| 37 | 37 | ||
| 38 | /* for QUIRK_MIDI_CME, data is NULL */ | 38 | /* for QUIRK_MIDI_CME, data is NULL */ |
| 39 | 39 | ||
| 40 | /* for QUIRK_MIDI_AKAI, data is NULL */ | ||
| 41 | |||
| 40 | int snd_usbmidi_create(struct snd_card *card, | 42 | int snd_usbmidi_create(struct snd_card *card, |
| 41 | struct usb_interface *iface, | 43 | struct usb_interface *iface, |
| 42 | struct list_head *midi_list, | 44 | struct list_head *midi_list, |
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 91ddef31bcbd..f8797f61a24b 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h | |||
| @@ -1973,6 +1973,17 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
| 1973 | } | 1973 | } |
| 1974 | }, | 1974 | }, |
| 1975 | 1975 | ||
| 1976 | /* AKAI devices */ | ||
| 1977 | { | ||
| 1978 | USB_DEVICE(0x09e8, 0x0062), | ||
| 1979 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | ||
| 1980 | .vendor_name = "AKAI", | ||
| 1981 | .product_name = "MPD16", | ||
| 1982 | .ifnum = 0, | ||
| 1983 | .type = QUIRK_MIDI_AKAI, | ||
| 1984 | } | ||
| 1985 | }, | ||
| 1986 | |||
| 1976 | /* TerraTec devices */ | 1987 | /* TerraTec devices */ |
| 1977 | { | 1988 | { |
| 1978 | USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0012), | 1989 | USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0012), |
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 136e5b4cf6de..b45e54c09ba2 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c | |||
| @@ -289,6 +289,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip, | |||
| 289 | [QUIRK_MIDI_FASTLANE] = create_any_midi_quirk, | 289 | [QUIRK_MIDI_FASTLANE] = create_any_midi_quirk, |
| 290 | [QUIRK_MIDI_EMAGIC] = create_any_midi_quirk, | 290 | [QUIRK_MIDI_EMAGIC] = create_any_midi_quirk, |
| 291 | [QUIRK_MIDI_CME] = create_any_midi_quirk, | 291 | [QUIRK_MIDI_CME] = create_any_midi_quirk, |
| 292 | [QUIRK_MIDI_AKAI] = create_any_midi_quirk, | ||
| 292 | [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, | 293 | [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, |
| 293 | [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, | 294 | [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, |
| 294 | [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk, | 295 | [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk, |
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index d679e72a3e5c..06ebf24d3a4d 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h | |||
| @@ -74,6 +74,7 @@ enum quirk_type { | |||
| 74 | QUIRK_MIDI_FASTLANE, | 74 | QUIRK_MIDI_FASTLANE, |
| 75 | QUIRK_MIDI_EMAGIC, | 75 | QUIRK_MIDI_EMAGIC, |
| 76 | QUIRK_MIDI_CME, | 76 | QUIRK_MIDI_CME, |
| 77 | QUIRK_MIDI_AKAI, | ||
| 77 | QUIRK_MIDI_US122L, | 78 | QUIRK_MIDI_US122L, |
| 78 | QUIRK_AUDIO_STANDARD_INTERFACE, | 79 | QUIRK_AUDIO_STANDARD_INTERFACE, |
| 79 | QUIRK_AUDIO_FIXED_ENDPOINT, | 80 | QUIRK_AUDIO_FIXED_ENDPOINT, |
