* Re: Help requested: new HSS1394 MIDI back-end [not found] <94aa86f3-5257-402a-a094-f58fccdeb846@email.android.com> @ 2012-05-30 4:51 ` Clemens Ladisch 2012-05-30 5:12 ` [alsa-devel] " Sean M. Pappalardo - D.J. Pegasus 0 siblings, 1 reply; 25+ messages in thread From: Clemens Ladisch @ 2012-05-30 4:51 UTC (permalink / raw) To: Sean M. Pappalardo - D.J. Pegasus; +Cc: alsa-devel, linux1394-devel Sean M. Pappalardo - D.J. Pegasus wrote: >It works perfectly with the SCS.1m!! The .1d works, but some of >the non-standard data it sends appears to be getting corrupted. In >particular, the device sends four-byte platter messages that start with >0xF9 and the remaining three can range from 0x00 to 0xFF. This is not MIDI. Into what MIDI messages should the driver convert this? Is this documented anywhere? Regards, Clemens ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [alsa-devel] Help requested: new HSS1394 MIDI back-end 2012-05-30 4:51 ` Help requested: new HSS1394 MIDI back-end Clemens Ladisch @ 2012-05-30 5:12 ` Sean M. Pappalardo - D.J. Pegasus 2012-05-30 7:18 ` Clemens Ladisch 0 siblings, 1 reply; 25+ messages in thread From: Sean M. Pappalardo - D.J. Pegasus @ 2012-05-30 5:12 UTC (permalink / raw) To: Clemens Ladisch; +Cc: alsa-devel, linux1394-devel [-- Attachment #1.1.1: Type: text/plain, Size: 1393 bytes --] On 05/30/2012 06:51 AM, Clemens Ladisch wrote: > Sean M. Pappalardo - D.J. Pegasus wrote: >> It works perfectly with the SCS.1m!! The .1d works, but some of >> the non-standard data it sends appears to be getting corrupted. In >> particular, the device sends four-byte platter messages that start with >> 0xF9 and the remaining three can range from 0x00 to 0xFF. > > This is not MIDI. Into what MIDI messages should > the driver convert this? It shouldn't convert it at all. Just deliver it as-is in a single four-byte message, if possible. (0xF9 is a valid, if undefined, MIDI status. They're using it kind of like SYSEX only without the terminating byte, likely for efficiency on the wire.) > Is this documented anywhere? It's documented in the SCS.1 MIDI spec which is attached. (See the record encoder doc.) In looking at that again, I will also need the ability to use the HSS1394 SendUserControl function to set the device's timers, and that is definitely not MIDI at all. (Sorry, I forgot about that since I wrote Mixxx's HSS1394 code awhile ago.) I wonder if it would be a good idea to define a special SYSEX message that the SCS1x driver would interpret and convert to a call to that function? That wouldn't be future-proof but it is MIDI-compatible. Sincerely, Sean M. Pappalardo "D.J. Pegasus" Mixxx Developer - Controller Specialist [-- Attachment #1.1.2: scs1_docs.zip --] [-- Type: application/zip, Size: 330272 bytes --] [-- Attachment #1.2: S/MIME Cryptographic Signature --] [-- Type: application/pkcs7-signature, Size: 4545 bytes --] [-- Attachment #2: Type: text/plain, Size: 395 bytes --] ------------------------------------------------------------------------------ Live Security Virtual Conference Exclusive live event will cover all the ways today's security and threat landscape has changed and how IT managers can respond. Discussions will include endpoint security, mobile security and the latest in malware threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/ [-- Attachment #3: Type: text/plain, Size: 0 bytes --] ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Help requested: new HSS1394 MIDI back-end 2012-05-30 5:12 ` [alsa-devel] " Sean M. Pappalardo - D.J. Pegasus @ 2012-05-30 7:18 ` Clemens Ladisch 2012-05-31 20:00 ` Clemens Ladisch 2012-05-31 22:04 ` Sean M. Pappalardo - D.J. Pegasus 0 siblings, 2 replies; 25+ messages in thread From: Clemens Ladisch @ 2012-05-30 7:18 UTC (permalink / raw) To: Sean M. Pappalardo - D.J. Pegasus; +Cc: alsa-devel, linux1394-devel Sean M. Pappalardo - D.J. Pegasus wrote: > On 05/30/2012 06:51 AM, Clemens Ladisch wrote: >> Sean M. Pappalardo - D.J. Pegasus wrote: >>> four-byte platter messages that start with >>> 0xF9 and the remaining three can range from 0x00 to 0xFF. >> >> This is not MIDI. Into what MIDI messages should >> the driver convert this? > > It shouldn't convert it at all. Just deliver it as-is in a single > four-byte message, if possible. The problem is the communication between the driver and userspace; _that_ must be valid MIDI. > 0xF9 is a valid, if undefined, MIDI status. Undefined means invalid. Furthermore, data bytes must not have the eighth bit set. > I will also need the ability to use the HSS1394 SendUserControl > function to set the device's timers, and that is definitely not MIDI > at all. > I wonder if it would be a good idea to define a special SYSEX message > that the SCS1x driver would interpret and convert to a call to that > function? As it happens, the actual SysEx commands use the wrong manufacturer ID ("00 01 02" is Crystal Semiconductor); I could just use the real ID (Stanton is "00 01 60") to escape non-MIDI HSS1394 messages. Let's add "HSS" to identify this, and to allow the full byte range, each HSS1394 byte is split into two nibbles. So: 00 F9 xx yy zz -> F0 00 01 60 48 53 53 00 00 0F 09 0x 0x 0y 0y 0z 0z F7 13 xx yy zz <- F0 00 01 60 48 53 53 01 03 0x 0x 0y 0y 0z 0z F7 14 xx yy zz <- F0 00 01 60 48 53 53 01 04 0x 0x 0y 0y 0z 0z F7 (0x13 = 0x10 + 3 = kUserTagBase + uUserTag) Regards, Clemens ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Help requested: new HSS1394 MIDI back-end 2012-05-30 7:18 ` Clemens Ladisch @ 2012-05-31 20:00 ` Clemens Ladisch 2012-06-09 6:54 ` Sean M. Pappalardo - D.J. Pegasus ` (2 more replies) 2012-05-31 22:04 ` Sean M. Pappalardo - D.J. Pegasus 1 sibling, 3 replies; 25+ messages in thread From: Clemens Ladisch @ 2012-05-31 20:00 UTC (permalink / raw) To: Sean M. Pappalardo - D.J. Pegasus; +Cc: alsa-devel, linux1394-devel I wrote: > 00 F9 xx yy zz -> F0 00 01 60 48 53 53 00 00 0F 09 0x 0x 0y 0y 0z 0z F7 > 13 xx yy zz <- F0 00 01 60 48 53 53 01 03 0x 0x 0y 0y 0z 0z F7 > 14 xx yy zz <- F0 00 01 60 48 53 53 01 04 0x 0x 0y 0y 0z 0z F7 New patch below. Regards, Clemens --- a/sound/firewire/Kconfig +++ b/sound/firewire/Kconfig @@ -33,4 +33,17 @@ config SND_ISIGHT To compile this driver as a module, choose M here: the module will be called snd-isight. +config SND_SCS1X + tristate "Stanton Control System 1 MIDI" + select SND_PCM + select SND_RAWMIDI + select SND_FIREWIRE_LIB + help + Say Y here to include support for the MIDI ports of the Stanton + SCS.1d/SCS.1m DJ controllers. (SCS.1m audio is still handled + by FFADO.) + + To compile this driver as a module, choose M here: the module + will be called snd-scs1x. + endif # SND_FIREWIRE --- a/sound/firewire/Makefile +++ b/sound/firewire/Makefile @@ -2,7 +2,9 @@ snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \ fcp.o cmp.o amdtp.o snd-firewire-speakers-objs := speakers.o snd-isight-objs := isight.o +snd-scs1x-objs := scs1x.o obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o obj-$(CONFIG_SND_FIREWIRE_SPEAKERS) += snd-firewire-speakers.o obj-$(CONFIG_SND_ISIGHT) += snd-isight.o +obj-$(CONFIG_SND_SCS1X) += snd-scs1x.o --- /dev/null +++ b/sound/firewire/scs1x.c @@ -0,0 +1,498 @@ +/* + * Stanton Control System 1 MIDI driver + * + * Copyright (c) Clemens Ladisch <clemens@ladisch.de> + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#include <linux/device.h> +#include <linux/firewire.h> +#include <linux/firewire-constants.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/wait.h> +#include <sound/core.h> +#include <sound/initval.h> +#include <sound/rawmidi.h> +#include "lib.h" + +#define OUI_STANTON 0x001260 +#define MODEL_SCS_1M 0x001000 +#define MODEL_SCS_1D 0x002000 + +#define HSS1394_ADDRESS 0xc007dedadadaULL +#define HSS1394_MAX_PACKET_SIZE 64 + +#define HSS1394_TAG_USER_DATA 0x00 +#define HSS1394_TAG_CHANGE_ADDRESS 0xf1 + +struct scs { + struct snd_card *card; + struct fw_unit *unit; + struct fw_address_handler hss_handler; + struct fw_transaction transaction; + bool transaction_running; + bool output_idle; + u8 midi_status; + u8 midi_bytes; + bool output_escaped; + bool escape_high_nibble; + struct snd_rawmidi_substream *output; + struct snd_rawmidi_substream *input; + struct tasklet_struct tasklet; + wait_queue_head_t idle_wait; + u8 *buffer; +}; + +static const u8 sysex_escape_prefix[] = { + 0xf0, /* SysEx begin */ + 0x00, 0x01, 0x60, /* Stanton DJ */ + 0x48, 0x53, 0x53, /* "HSS" */ +}; + +static int scs_output_open(struct snd_rawmidi_substream *stream) +{ + struct scs *scs = stream->rmidi->private_data; + + scs->midi_status = 0; + scs->midi_bytes = 1; + scs->output_escaped = false; + + return 0; +} + +static int scs_output_close(struct snd_rawmidi_substream *stream) +{ + return 0; +} + +static void scs_output_trigger(struct snd_rawmidi_substream *stream, int up) +{ + struct scs *scs = stream->rmidi->private_data; + + ACCESS_ONCE(scs->output) = up ? stream : NULL; + if (up) { + scs->output_idle = false; + tasklet_schedule(&scs->tasklet); + } +} + +static void scs_write_callback(struct fw_card *card, int rcode, + void *data, size_t length, void *callback_data) +{ + struct scs *scs = callback_data; + + if (rcode == RCODE_GENERATION) { + /* TODO: retry this packet */ + } + + scs->transaction_running = false; + tasklet_schedule(&scs->tasklet); +} + +static bool is_valid_running_status(u8 status) +{ + return status >= 0x80 && status <= 0xef; +} + +static bool is_one_byte_cmd(u8 status) +{ + return status == 0xf6 || + status >= 0xf8; +} + +static bool is_two_bytes_cmd(u8 status) +{ + return (status >= 0xc0 && status <= 0xdf) || + status == 0xf1 || + status == 0xf3; +} + +static bool is_three_bytes_cmd(u8 status) +{ + return (status >= 0x80 && status <= 0xbf) || + (status >= 0xe0 && status <= 0xef) || + status == 0xf2; +} + +static bool is_invalid_cmd(u8 status) +{ + return status == 0xf4 || + status == 0xf5 || + status == 0xf9 || + status == 0xfd; +} + +static void scs_output_tasklet(unsigned long data) +{ + struct scs *scs = (void *)data; + struct snd_rawmidi_substream *stream; + unsigned int i; + u8 byte; + struct fw_device *dev; + int generation; + + if (scs->transaction_running) + return; + + stream = ACCESS_ONCE(scs->output); + if (!stream) { + scs->output_idle = true; + wake_up(&scs->idle_wait); + return; + } + + i = scs->midi_bytes; + for (;;) { + if (snd_rawmidi_transmit(stream, &byte, 1) != 1) { + scs->midi_bytes = i; + scs->output_idle = true; + wake_up(&scs->idle_wait); + return; + } + /* + * Convert from real MIDI to what the device expects (no + * running status, one command per packet, unescaped SysExs). + */ + if (scs->output_escaped && byte < 0x80) { + if (scs->escape_high_nibble) { + if (i < HSS1394_MAX_PACKET_SIZE) { + scs->buffer[i] = byte << 4; + scs->escape_high_nibble = false; + } + } else { + scs->buffer[i++] |= byte & 0x0f; + scs->escape_high_nibble = true; + } + } else if (byte < 0x80) { + if (i == 1) { + if (!is_valid_running_status(scs->midi_status)) + continue; + scs->buffer[0] = HSS1394_TAG_USER_DATA; + scs->buffer[i++] = scs->midi_status; + } + scs->buffer[i++] = byte; + if ((i == 3 && is_two_bytes_cmd(scs->midi_status)) || + (i == 4 && is_three_bytes_cmd(scs->midi_status))) + break; + if (i == 1 + ARRAY_SIZE(sysex_escape_prefix) && + !memcmp(scs->buffer + 1, sysex_escape_prefix, + ARRAY_SIZE(sysex_escape_prefix))) { + scs->output_escaped = true; + scs->escape_high_nibble = true; + i = 0; + } + if (i >= HSS1394_MAX_PACKET_SIZE) + i = 1; + } else if (byte == 0xf7) { + if (scs->output_escaped) { + if (i >= 1 && scs->escape_high_nibble && + scs->buffer[0] != HSS1394_TAG_CHANGE_ADDRESS) + break; + } else { + if (i > 1 && scs->midi_status == 0xf0) { + scs->buffer[i++] = 0xf7; + break; + } + } + i = 1; + scs->output_escaped = false; + } else if (!is_invalid_cmd(byte) && + byte < 0xf8) { + i = 1; + scs->buffer[0] = HSS1394_TAG_USER_DATA; + scs->buffer[i++] = byte; + scs->midi_status = byte; + scs->output_escaped = false; + if (is_one_byte_cmd(byte)) + break; + } + } + scs->midi_bytes = 1; + scs->output_escaped = false; + + scs->transaction_running = true; + dev = fw_parent_device(scs->unit); + generation = dev->generation; + smp_rmb(); /* node_id vs. generation */ + fw_send_request(dev->card, &scs->transaction, TCODE_WRITE_BLOCK_REQUEST, + dev->node_id, generation, dev->max_speed, + HSS1394_ADDRESS, scs->buffer, i, + scs_write_callback, scs); +} + +static void scs_output_drain(struct snd_rawmidi_substream *stream) +{ + struct scs *scs = stream->rmidi->private_data; + + wait_event(scs->idle_wait, scs->output_idle); +} + +static struct snd_rawmidi_ops output_ops = { + .open = scs_output_open, + .close = scs_output_close, + .trigger = scs_output_trigger, + .drain = scs_output_drain, +}; + +static int scs_input_open(struct snd_rawmidi_substream *stream) +{ + return 0; +} + +static int scs_input_close(struct snd_rawmidi_substream *stream) +{ + return 0; +} + +static void scs_input_trigger(struct snd_rawmidi_substream *stream, int up) +{ + struct scs *scs = stream->rmidi->private_data; + + ACCESS_ONCE(scs->input) = up ? stream : NULL; +} + +static void scs_input_packet(struct snd_rawmidi_substream *stream, + const u8 *data, unsigned int bytes) +{ + unsigned int i; + u8 nibbles[2]; + + if (data[0] == HSS1394_TAG_USER_DATA && bytes >= 2 && + data[1] >= 0x80 && !is_invalid_cmd(data[1])) { + snd_rawmidi_receive(stream, data + 1, bytes - 1); + } else { + snd_rawmidi_receive(stream, sysex_escape_prefix, + ARRAY_SIZE(sysex_escape_prefix)); + for (i = 0; i < bytes; ++i) { + nibbles[0] = data[i] >> 4; + nibbles[1] = data[i] & 0x0f; + snd_rawmidi_receive(stream, nibbles, 2); + } + snd_rawmidi_receive(stream, (const u8[]) { 0xf7 }, 1); + } +} + +static struct snd_rawmidi_ops input_ops = { + .open = scs_input_open, + .close = scs_input_close, + .trigger = scs_input_trigger, +}; + +static int scs_create_midi(struct scs *scs) +{ + struct snd_rawmidi *rmidi; + int err; + + err = snd_rawmidi_new(scs->card, "SCS.1x", 0, 1, 1, &rmidi); + if (err < 0) + return err; + snprintf(rmidi->name, sizeof(rmidi->name), + "%s MIDI", scs->card->shortname); + rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | + SNDRV_RAWMIDI_INFO_INPUT | + SNDRV_RAWMIDI_INFO_DUPLEX; + rmidi->private_data = scs; + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &output_ops); + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &input_ops); + + return 0; +} + +static void handle_hss(struct fw_card *card, struct fw_request *request, + int tcode, int destination, int source, int generation, + unsigned long long offset, void *data, size_t length, + void *callback_data) +{ + struct scs *scs = callback_data; + struct snd_rawmidi_substream *stream; + + if (offset != scs->hss_handler.offset) { + fw_send_response(card, request, RCODE_ADDRESS_ERROR); + return; + } + if (tcode != TCODE_WRITE_QUADLET_REQUEST && + tcode != TCODE_WRITE_BLOCK_REQUEST) { + fw_send_response(card, request, RCODE_TYPE_ERROR); + return; + } + + if (length >= 1) { + stream = ACCESS_ONCE(scs->input); + if (stream) + scs_input_packet(stream, data, length); + } + + fw_send_response(card, request, RCODE_COMPLETE); +} + +static int scs_init_hss_address(struct scs *scs) +{ + u8 data[8]; + int err; + + *(__be64 *)data = cpu_to_be64(scs->hss_handler.offset); + data[0] = HSS1394_TAG_CHANGE_ADDRESS; + err = snd_fw_transaction(scs->unit, TCODE_WRITE_BLOCK_REQUEST, + HSS1394_ADDRESS, data, 8); + if (err < 0) + dev_err(&scs->unit->device, "HSS1394 communication failed\n"); + + return err; +} + +static void scs_card_free(struct snd_card *card) +{ + struct scs *scs = card->private_data; + + fw_core_remove_address_handler(&scs->hss_handler); + kfree(scs->buffer); +} + +static int scs_probe(struct device *unit_dev) +{ + struct fw_unit *unit = fw_unit(unit_dev); + struct fw_device *fw_dev = fw_parent_device(unit); + struct snd_card *card; + struct scs *scs; + int err; + + err = snd_card_create(-16, NULL, THIS_MODULE, sizeof(*scs), &card); + if (err < 0) + return err; + snd_card_set_dev(card, unit_dev); + + scs = card->private_data; + scs->card = card; + scs->unit = unit; + tasklet_init(&scs->tasklet, scs_output_tasklet, (unsigned long)scs); + init_waitqueue_head(&scs->idle_wait); + scs->output_idle = true; + + scs->buffer = kmalloc(HSS1394_MAX_PACKET_SIZE, GFP_KERNEL); + if (!scs->buffer) + goto err_card; + + scs->hss_handler.length = HSS1394_MAX_PACKET_SIZE; + scs->hss_handler.address_callback = handle_hss; + scs->hss_handler.callback_data = scs; + err = fw_core_add_address_handler(&scs->hss_handler, + &fw_high_memory_region); + if (err < 0) + goto err_buffer; + + card->private_free = scs_card_free; + + strcpy(card->driver, "SCS.1x"); + strcpy(card->shortname, "SCS.1x"); + fw_csr_string(unit->directory, CSR_MODEL, + card->shortname, sizeof(card->shortname)); + snprintf(card->longname, sizeof(card->longname), + "Stanton DJ %s (GUID %08x%08x) at %s, S%d", + card->shortname, fw_dev->config_rom[3], fw_dev->config_rom[4], + dev_name(&unit->device), 100 << fw_dev->max_speed); + strcpy(card->mixername, card->shortname); + + err = scs_init_hss_address(scs); + if (err < 0) + goto err_card; + + err = scs_create_midi(scs); + if (err < 0) + goto err_card; + + err = snd_card_register(card); + if (err < 0) + goto err_card; + + dev_set_drvdata(unit_dev, scs); + + return 0; + +err_buffer: + kfree(scs->buffer); +err_card: + snd_card_free(card); + return err; +} + +static int scs_remove(struct device *dev) +{ + struct scs *scs = dev_get_drvdata(dev); + + snd_card_disconnect(scs->card); + + ACCESS_ONCE(scs->output) = NULL; + ACCESS_ONCE(scs->input) = NULL; + + wait_event(scs->idle_wait, scs->output_idle); + + tasklet_kill(&scs->tasklet); + + snd_card_free_when_closed(scs->card); + + return 0; +} + +static void scs_update(struct fw_unit *unit) +{ + struct scs *scs = dev_get_drvdata(&unit->device); + int generation; + u8 data[8]; + + *(__be64 *)data = cpu_to_be64(scs->hss_handler.offset); + data[0] = HSS1394_TAG_CHANGE_ADDRESS; + generation = fw_parent_device(unit)->generation; + smp_rmb(); /* node_id vs. generation */ + snd_fw_transaction(scs->unit, TCODE_WRITE_BLOCK_REQUEST, + HSS1394_ADDRESS, data, 8); +} + +static const struct ieee1394_device_id scs_id_table[] = { + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | + IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_STANTON, + .model_id = MODEL_SCS_1M, + }, + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | + IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_STANTON, + .model_id = MODEL_SCS_1D, + }, + {} +}; +MODULE_DEVICE_TABLE(ieee1394, scs_id_table); + +MODULE_DESCRIPTION("SCS.1x MIDI driver"); +MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); +MODULE_LICENSE("GPL v2"); + +static struct fw_driver scs_driver = { + .driver = { + .owner = THIS_MODULE, + .name = KBUILD_MODNAME, + .bus = &fw_bus_type, + .probe = scs_probe, + .remove = scs_remove, + }, + .update = scs_update, + .id_table = scs_id_table, +}; + +static int __init alsa_scs1x_init(void) +{ + return driver_register(&scs_driver.driver); +} + +static void __exit alsa_scs1x_exit(void) +{ + driver_unregister(&scs_driver.driver); +} + +module_init(alsa_scs1x_init); +module_exit(alsa_scs1x_exit); ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Help requested: new HSS1394 MIDI back-end 2012-05-31 20:00 ` Clemens Ladisch @ 2012-06-09 6:54 ` Sean M. Pappalardo - D.J. Pegasus 2012-06-09 11:07 ` Clemens Ladisch 2012-06-09 8:42 ` Sean M. Pappalardo - D.J. Pegasus 2012-06-09 10:12 ` Sean M. Pappalardo - D.J. Pegasus 2 siblings, 1 reply; 25+ messages in thread From: Sean M. Pappalardo - D.J. Pegasus @ 2012-06-09 6:54 UTC (permalink / raw) To: Clemens Ladisch; +Cc: alsa-devel, linux1394-devel [-- Attachment #1.1: Type: text/plain, Size: 1165 bytes --] Hello again. Sorry for the delay. I've been quite busy in the last week. On 05/31/2012 10:00 PM, Clemens Ladisch wrote: > I wrote: >> 00 F9 xx yy zz -> F0 00 01 60 48 53 53 00 00 0F 09 0x 0x 0y 0y 0z 0z F7 This appears to work fine. But where did you get the leading 00 from? libhss1394 just sends F9 xx yy zz. >> 13 xx yy zz<- F0 00 01 60 48 53 53 01 03 0x 0x 0y 0y 0z 0z F7 >> 14 xx yy zz<- F0 00 01 60 48 53 53 01 04 0x 0x 0y 0y 0z 0z F7 >> (0x13 = 0x10 + 3 = kUserTagBase + uUserTag) I'm not clear on how you arrived at that formula. HSS1394.h shows: //! Send a user control message via the channel to the target //! node. Returns the number of bytes sent on success, zero on //! failure. uUserTag is valid in the range 0x00 - 0xDF. All other //! tag values will be rejected (0 return). virtual uint SendUserControl(uint8 uUserTag, const uint8 *pUserData, uint uDataBytes) = 0; It appears to work with arbitrary-length user data strings, though the Stanton docs only specify 3-byte ones at this time. Sincerely, Sean M. Pappalardo "D.J. Pegasus" Mixxx Developer - Controller Specialist [-- Attachment #1.2: S/MIME Cryptographic Signature --] [-- Type: application/pkcs7-signature, Size: 4558 bytes --] [-- Attachment #2: Type: text/plain, Size: 0 bytes --] ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Help requested: new HSS1394 MIDI back-end 2012-06-09 6:54 ` Sean M. Pappalardo - D.J. Pegasus @ 2012-06-09 11:07 ` Clemens Ladisch 2012-06-09 12:41 ` Sean M. Pappalardo - D.J. Pegasus 2012-06-10 13:00 ` Clemens Ladisch 0 siblings, 2 replies; 25+ messages in thread From: Clemens Ladisch @ 2012-06-09 11:07 UTC (permalink / raw) To: Sean M. Pappalardo - D.J. Pegasus; +Cc: alsa-devel, linux1394-devel Sean M. Pappalardo - D.J. Pegasus wrote: > On 05/31/2012 10:00 PM, Clemens Ladisch wrote: >> I wrote: >>> 00 F9 xx yy zz -> F0 00 01 60 48 53 53 00 00 0F 09 0x 0x 0y 0y 0z 0z F7 > > This appears to work fine. But where did you get the leading 00 from? This is how the FireWire packets are constructed. The first byte is a tag; 00 means that the rest of the packet contains MIDI data, ... >>> 13 xx yy zz<- F0 00 01 60 48 53 53 01 03 0x 0x 0y 0y 0z 0z F7 >>> 14 xx yy zz<- F0 00 01 60 48 53 53 01 04 0x 0x 0y 0y 0z 0z F7 >>> (0x13 = 0x10 + 3 = kUserTagBase + uUserTag) ... while tags in the range 10..EF are "user tags". When you use this function: > // uUserTag is valid in the range 0x00 - 0xDF. > virtual uint SendUserControl(uint8 uUserTag, const uint8 *pUserData, > uint uDataBytes) = 0; libhss1394 will add 0x10 to the tag. > I just modified Mixxx's SCS.1d script to work with your custom sysex > messages and tested with your latest patch. The .1d doesn't actually > work 100% with this since Mixxx never receives some of the standard > MIDI messages amid all of the sysex ones, and it's much worse when the > platter is spinning and sending the tons of messages it does. This > could be due to PortMIDI's lack of a callback mechanism, forcing Mixxx > to poll it every 1ms because it's much more difficult to reproduce the > problem using amidi -d. That's possible. However, at 4 KB, ALSA's buffer should be big enough for those messages. > I also see an F9 message slip through once in awhile according to amidi -d: > F9 > 55 > 91 > C4 The driver currently assumes that there is exactly one MIDI message per packet. It appears that this is not true, and if F9 and real MIDI commands are mixed in one packet, the result is not correct. > As soon as I start the JACK server to handle the audio interface on > the SCS.1m, the ALSA driver stops sending MIDI for that device unless > I stop JACK and power-cycle the device. Its last words are: > F0 00 01 60 48 53 53 0F 03 00 03 00 00 0B 01 F7 This is a ping response (tag F3). Apparently, Jack's FFADO driver reinitializes the device and registers its own address for received packets. Since it does _not_ handle MIDI messages, it really should not do this. Regards, Clemens ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Help requested: new HSS1394 MIDI back-end 2012-06-09 11:07 ` Clemens Ladisch @ 2012-06-09 12:41 ` Sean M. Pappalardo - D.J. Pegasus 2012-06-10 13:00 ` Clemens Ladisch 1 sibling, 0 replies; 25+ messages in thread From: Sean M. Pappalardo - D.J. Pegasus @ 2012-06-09 12:41 UTC (permalink / raw) To: Clemens Ladisch; +Cc: alsa-devel, linux1394-devel, ffado-devel [-- Attachment #1.1: Type: text/plain, Size: 1645 bytes --] On 06/09/2012 01:07 PM, Clemens Ladisch wrote: >> I just modified Mixxx's SCS.1d script to work with your custom sysex >> messages and tested with your latest patch. The .1d doesn't actually >> work 100% with this since Mixxx never receives some of the standard >> MIDI messages amid all of the sysex ones, and it's much worse when the >> platter is spinning and sending the tons of messages it does. This >> could be due to PortMIDI's lack of a callback mechanism, forcing Mixxx >> to poll it every 1ms because it's much more difficult to reproduce the >> problem using amidi -d. > > That's possible. However, at 4 KB, ALSA's buffer should be big enough > for those messages. Yes, I subsequently found out that it was a bug in Mixxx's PortMIDI code. I've corrected that and it works much better now. (Nothing like a demanding device to ferret out bugs, eh?) >> As soon as I start the JACK server to handle the audio interface on >> the SCS.1m, the ALSA driver stops sending MIDI for that device unless >> I stop JACK and power-cycle the device. Its last words are: >> F0 00 01 60 48 53 53 0F 03 00 03 00 00 0B 01 F7 > > This is a ping response (tag F3). Apparently, Jack's FFADO driver > reinitializes the device and registers its own address for received > packets. Since it does _not_ handle MIDI messages, it really should > not do this. I think the test-scs program uses JACK-MIDI, so that might be why. But test-scs is obsoleted by your driver. I'm CC'ing the FFADO-devel list so they can take a look. Sincerely, Sean M. Pappalardo "D.J. Pegasus" Mixxx Developer - Controller Specialist [-- Attachment #1.2: S/MIME Cryptographic Signature --] [-- Type: application/pkcs7-signature, Size: 4558 bytes --] [-- Attachment #2: Type: text/plain, Size: 0 bytes --] ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Help requested: new HSS1394 MIDI back-end 2012-06-09 11:07 ` Clemens Ladisch 2012-06-09 12:41 ` Sean M. Pappalardo - D.J. Pegasus @ 2012-06-10 13:00 ` Clemens Ladisch 2012-10-24 11:49 ` Sean M. Pappalardo - D.J. Pegasus 1 sibling, 1 reply; 25+ messages in thread From: Clemens Ladisch @ 2012-06-10 13:00 UTC (permalink / raw) To: Sean M. Pappalardo - D.J. Pegasus; +Cc: alsa-devel, linux1394-devel I wrote: > Sean M. Pappalardo - D.J. Pegasus wrote: >> I also see an F9 message slip through once in awhile according to amidi -d: > > The driver currently assumes that there is exactly one MIDI message per > packet. It appears that this is not true, and if F9 and real MIDI > commands are mixed in one packet, the result is not correct. New patch below. Regards, Clemens --- a/sound/firewire/Kconfig +++ b/sound/firewire/Kconfig @@ -33,4 +33,17 @@ config SND_ISIGHT To compile this driver as a module, choose M here: the module will be called snd-isight. +config SND_SCS1X + tristate "Stanton Control System 1 MIDI" + select SND_PCM + select SND_RAWMIDI + select SND_FIREWIRE_LIB + help + Say Y here to include support for the MIDI ports of the Stanton + SCS.1d/SCS.1m DJ controllers. (SCS.1m audio is still handled + by FFADO.) + + To compile this driver as a module, choose M here: the module + will be called snd-scs1x. + endif # SND_FIREWIRE --- a/sound/firewire/Makefile +++ b/sound/firewire/Makefile @@ -2,7 +2,9 @@ snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \ fcp.o cmp.o amdtp.o snd-firewire-speakers-objs := speakers.o snd-isight-objs := isight.o +snd-scs1x-objs := scs1x.o obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o obj-$(CONFIG_SND_FIREWIRE_SPEAKERS) += snd-firewire-speakers.o obj-$(CONFIG_SND_ISIGHT) += snd-isight.o +obj-$(CONFIG_SND_SCS1X) += snd-scs1x.o --- /dev/null +++ b/sound/firewire/scs1x.c @@ -0,0 +1,527 @@ +/* + * Stanton Control System 1 MIDI driver + * + * Copyright (c) Clemens Ladisch <clemens@ladisch.de> + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#include <linux/device.h> +#include <linux/firewire.h> +#include <linux/firewire-constants.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/wait.h> +#include <sound/core.h> +#include <sound/initval.h> +#include <sound/rawmidi.h> +#include "lib.h" + +#define OUI_STANTON 0x001260 +#define MODEL_SCS_1M 0x001000 +#define MODEL_SCS_1D 0x002000 + +#define HSS1394_ADDRESS 0xc007dedadadaULL +#define HSS1394_MAX_PACKET_SIZE 64 + +#define HSS1394_TAG_USER_DATA 0x00 +#define HSS1394_TAG_CHANGE_ADDRESS 0xf1 + +struct scs { + struct snd_card *card; + struct fw_unit *unit; + struct fw_address_handler hss_handler; + struct fw_transaction transaction; + bool transaction_running; + bool output_idle; + u8 output_status; + u8 output_bytes; + bool output_escaped; + bool output_escape_high_nibble; + u8 input_escape_count; + struct snd_rawmidi_substream *output; + struct snd_rawmidi_substream *input; + struct tasklet_struct tasklet; + wait_queue_head_t idle_wait; + u8 *buffer; +}; + +static const u8 sysex_escape_prefix[] = { + 0xf0, /* SysEx begin */ + 0x00, 0x01, 0x60, /* Stanton DJ */ + 0x48, 0x53, 0x53, /* "HSS" */ +}; + +static int scs_output_open(struct snd_rawmidi_substream *stream) +{ + struct scs *scs = stream->rmidi->private_data; + + scs->output_status = 0; + scs->output_bytes = 1; + scs->output_escaped = false; + + return 0; +} + +static int scs_output_close(struct snd_rawmidi_substream *stream) +{ + return 0; +} + +static void scs_output_trigger(struct snd_rawmidi_substream *stream, int up) +{ + struct scs *scs = stream->rmidi->private_data; + + ACCESS_ONCE(scs->output) = up ? stream : NULL; + if (up) { + scs->output_idle = false; + tasklet_schedule(&scs->tasklet); + } +} + +static void scs_write_callback(struct fw_card *card, int rcode, + void *data, size_t length, void *callback_data) +{ + struct scs *scs = callback_data; + + if (rcode == RCODE_GENERATION) { + /* TODO: retry this packet */ + } + + scs->transaction_running = false; + tasklet_schedule(&scs->tasklet); +} + +static bool is_valid_running_status(u8 status) +{ + return status >= 0x80 && status <= 0xef; +} + +static bool is_one_byte_cmd(u8 status) +{ + return status == 0xf6 || + status >= 0xf8; +} + +static bool is_two_bytes_cmd(u8 status) +{ + return (status >= 0xc0 && status <= 0xdf) || + status == 0xf1 || + status == 0xf3; +} + +static bool is_three_bytes_cmd(u8 status) +{ + return (status >= 0x80 && status <= 0xbf) || + (status >= 0xe0 && status <= 0xef) || + status == 0xf2; +} + +static bool is_invalid_cmd(u8 status) +{ + return status == 0xf4 || + status == 0xf5 || + status == 0xf9 || + status == 0xfd; +} + +static void scs_output_tasklet(unsigned long data) +{ + struct scs *scs = (void *)data; + struct snd_rawmidi_substream *stream; + unsigned int i; + u8 byte; + struct fw_device *dev; + int generation; + + if (scs->transaction_running) + return; + + stream = ACCESS_ONCE(scs->output); + if (!stream) { + scs->output_idle = true; + wake_up(&scs->idle_wait); + return; + } + + i = scs->output_bytes; + for (;;) { + if (snd_rawmidi_transmit(stream, &byte, 1) != 1) { + scs->output_bytes = i; + scs->output_idle = true; + wake_up(&scs->idle_wait); + return; + } + /* + * Convert from real MIDI to what I think the device expects (no + * running status, one command per packet, unescaped SysExs). + */ + if (scs->output_escaped && byte < 0x80) { + if (scs->output_escape_high_nibble) { + if (i < HSS1394_MAX_PACKET_SIZE) { + scs->buffer[i] = byte << 4; + scs->output_escape_high_nibble = false; + } + } else { + scs->buffer[i++] |= byte & 0x0f; + scs->output_escape_high_nibble = true; + } + } else if (byte < 0x80) { + if (i == 1) { + if (!is_valid_running_status(scs->output_status)) + continue; + scs->buffer[0] = HSS1394_TAG_USER_DATA; + scs->buffer[i++] = scs->output_status; + } + scs->buffer[i++] = byte; + if ((i == 3 && is_two_bytes_cmd(scs->output_status)) || + (i == 4 && is_three_bytes_cmd(scs->output_status))) + break; + if (i == 1 + ARRAY_SIZE(sysex_escape_prefix) && + !memcmp(scs->buffer + 1, sysex_escape_prefix, + ARRAY_SIZE(sysex_escape_prefix))) { + scs->output_escaped = true; + scs->output_escape_high_nibble = true; + i = 0; + } + if (i >= HSS1394_MAX_PACKET_SIZE) + i = 1; + } else if (byte == 0xf7) { + if (scs->output_escaped) { + if (i >= 1 && scs->output_escape_high_nibble && + scs->buffer[0] != HSS1394_TAG_CHANGE_ADDRESS) + break; + } else { + if (i > 1 && scs->output_status == 0xf0) { + scs->buffer[i++] = 0xf7; + break; + } + } + i = 1; + scs->output_escaped = false; + } else if (!is_invalid_cmd(byte) && + byte < 0xf8) { + i = 1; + scs->buffer[0] = HSS1394_TAG_USER_DATA; + scs->buffer[i++] = byte; + scs->output_status = byte; + scs->output_escaped = false; + if (is_one_byte_cmd(byte)) + break; + } + } + scs->output_bytes = 1; + scs->output_escaped = false; + + scs->transaction_running = true; + dev = fw_parent_device(scs->unit); + generation = dev->generation; + smp_rmb(); /* node_id vs. generation */ + fw_send_request(dev->card, &scs->transaction, TCODE_WRITE_BLOCK_REQUEST, + dev->node_id, generation, dev->max_speed, + HSS1394_ADDRESS, scs->buffer, i, + scs_write_callback, scs); +} + +static void scs_output_drain(struct snd_rawmidi_substream *stream) +{ + struct scs *scs = stream->rmidi->private_data; + + wait_event(scs->idle_wait, scs->output_idle); +} + +static struct snd_rawmidi_ops output_ops = { + .open = scs_output_open, + .close = scs_output_close, + .trigger = scs_output_trigger, + .drain = scs_output_drain, +}; + +static int scs_input_open(struct snd_rawmidi_substream *stream) +{ + struct scs *scs = stream->rmidi->private_data; + + scs->input_escape_count = 0; + + return 0; +} + +static int scs_input_close(struct snd_rawmidi_substream *stream) +{ + return 0; +} + +static void scs_input_trigger(struct snd_rawmidi_substream *stream, int up) +{ + struct scs *scs = stream->rmidi->private_data; + + ACCESS_ONCE(scs->input) = up ? stream : NULL; +} + +static void scs_input_escaped_byte(struct snd_rawmidi_substream *stream, + u8 byte) +{ + u8 nibbles[2]; + + nibbles[0] = byte >> 4; + nibbles[1] = byte & 0x0f; + snd_rawmidi_receive(stream, nibbles, 2); +} + +static void scs_input_midi_byte(struct scs *scs, + struct snd_rawmidi_substream *stream, + u8 byte) +{ + if (scs->input_escape_count > 0) { + scs_input_escaped_byte(stream, byte); + scs->input_escape_count--; + if (scs->input_escape_count == 0) + snd_rawmidi_receive(stream, (const u8[]) { 0xf7 }, 1); + } else if (byte == 0xf9) { + snd_rawmidi_receive(stream, sysex_escape_prefix, + ARRAY_SIZE(sysex_escape_prefix)); + scs_input_escaped_byte(stream, 0x00); + scs_input_escaped_byte(stream, 0xf9); + scs->input_escape_count = 3; + } else { + snd_rawmidi_receive(stream, &byte, 1); + } +} + +static void scs_input_packet(struct scs *scs, + struct snd_rawmidi_substream *stream, + const u8 *data, unsigned int bytes) +{ + unsigned int i; + + if (data[0] == HSS1394_TAG_USER_DATA) { + for (i = 0; i < bytes; ++i) + scs_input_midi_byte(scs, stream, data[i]); + } else { + snd_rawmidi_receive(stream, sysex_escape_prefix, + ARRAY_SIZE(sysex_escape_prefix)); + for (i = 0; i < bytes; ++i) + scs_input_escaped_byte(stream, data[i]); + snd_rawmidi_receive(stream, (const u8[]) { 0xf7 }, 1); + } +} + +static struct snd_rawmidi_ops input_ops = { + .open = scs_input_open, + .close = scs_input_close, + .trigger = scs_input_trigger, +}; + +static int scs_create_midi(struct scs *scs) +{ + struct snd_rawmidi *rmidi; + int err; + + err = snd_rawmidi_new(scs->card, "SCS.1x", 0, 1, 1, &rmidi); + if (err < 0) + return err; + snprintf(rmidi->name, sizeof(rmidi->name), + "%s MIDI", scs->card->shortname); + rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | + SNDRV_RAWMIDI_INFO_INPUT | + SNDRV_RAWMIDI_INFO_DUPLEX; + rmidi->private_data = scs; + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &output_ops); + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &input_ops); + + return 0; +} + +static void handle_hss(struct fw_card *card, struct fw_request *request, + int tcode, int destination, int source, int generation, + unsigned long long offset, void *data, size_t length, + void *callback_data) +{ + struct scs *scs = callback_data; + struct snd_rawmidi_substream *stream; + + if (offset != scs->hss_handler.offset) { + fw_send_response(card, request, RCODE_ADDRESS_ERROR); + return; + } + if (tcode != TCODE_WRITE_QUADLET_REQUEST && + tcode != TCODE_WRITE_BLOCK_REQUEST) { + fw_send_response(card, request, RCODE_TYPE_ERROR); + return; + } + + if (length >= 1) { + stream = ACCESS_ONCE(scs->input); + if (stream) + scs_input_packet(scs, stream, data, length); + } + + fw_send_response(card, request, RCODE_COMPLETE); +} + +static int scs_init_hss_address(struct scs *scs) +{ + u8 data[8]; + int err; + + *(__be64 *)data = cpu_to_be64(scs->hss_handler.offset); + data[0] = HSS1394_TAG_CHANGE_ADDRESS; + err = snd_fw_transaction(scs->unit, TCODE_WRITE_BLOCK_REQUEST, + HSS1394_ADDRESS, data, 8); + if (err < 0) + dev_err(&scs->unit->device, "HSS1394 communication failed\n"); + + return err; +} + +static void scs_card_free(struct snd_card *card) +{ + struct scs *scs = card->private_data; + + fw_core_remove_address_handler(&scs->hss_handler); + kfree(scs->buffer); +} + +static int scs_probe(struct device *unit_dev) +{ + struct fw_unit *unit = fw_unit(unit_dev); + struct fw_device *fw_dev = fw_parent_device(unit); + struct snd_card *card; + struct scs *scs; + int err; + + err = snd_card_create(-16, NULL, THIS_MODULE, sizeof(*scs), &card); + if (err < 0) + return err; + snd_card_set_dev(card, unit_dev); + + scs = card->private_data; + scs->card = card; + scs->unit = unit; + tasklet_init(&scs->tasklet, scs_output_tasklet, (unsigned long)scs); + init_waitqueue_head(&scs->idle_wait); + scs->output_idle = true; + + scs->buffer = kmalloc(HSS1394_MAX_PACKET_SIZE, GFP_KERNEL); + if (!scs->buffer) + goto err_card; + + scs->hss_handler.length = HSS1394_MAX_PACKET_SIZE; + scs->hss_handler.address_callback = handle_hss; + scs->hss_handler.callback_data = scs; + err = fw_core_add_address_handler(&scs->hss_handler, + &fw_high_memory_region); + if (err < 0) + goto err_buffer; + + card->private_free = scs_card_free; + + strcpy(card->driver, "SCS.1x"); + strcpy(card->shortname, "SCS.1x"); + fw_csr_string(unit->directory, CSR_MODEL, + card->shortname, sizeof(card->shortname)); + snprintf(card->longname, sizeof(card->longname), + "Stanton DJ %s (GUID %08x%08x) at %s, S%d", + card->shortname, fw_dev->config_rom[3], fw_dev->config_rom[4], + dev_name(&unit->device), 100 << fw_dev->max_speed); + strcpy(card->mixername, card->shortname); + + err = scs_init_hss_address(scs); + if (err < 0) + goto err_card; + + err = scs_create_midi(scs); + if (err < 0) + goto err_card; + + err = snd_card_register(card); + if (err < 0) + goto err_card; + + dev_set_drvdata(unit_dev, scs); + + return 0; + +err_buffer: + kfree(scs->buffer); +err_card: + snd_card_free(card); + return err; +} + +static int scs_remove(struct device *dev) +{ + struct scs *scs = dev_get_drvdata(dev); + + snd_card_disconnect(scs->card); + + ACCESS_ONCE(scs->output) = NULL; + ACCESS_ONCE(scs->input) = NULL; + + wait_event(scs->idle_wait, scs->output_idle); + + tasklet_kill(&scs->tasklet); + + snd_card_free_when_closed(scs->card); + + return 0; +} + +static void scs_update(struct fw_unit *unit) +{ + struct scs *scs = dev_get_drvdata(&unit->device); + u8 data[8]; + + *(__be64 *)data = cpu_to_be64(scs->hss_handler.offset); + data[0] = HSS1394_TAG_CHANGE_ADDRESS; + snd_fw_transaction(scs->unit, TCODE_WRITE_BLOCK_REQUEST, + HSS1394_ADDRESS, data, 8); +} + +static const struct ieee1394_device_id scs_id_table[] = { + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | + IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_STANTON, + .model_id = MODEL_SCS_1M, + }, + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | + IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_STANTON, + .model_id = MODEL_SCS_1D, + }, + {} +}; +MODULE_DEVICE_TABLE(ieee1394, scs_id_table); + +MODULE_DESCRIPTION("SCS.1x MIDI driver"); +MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); +MODULE_LICENSE("GPL v2"); + +static struct fw_driver scs_driver = { + .driver = { + .owner = THIS_MODULE, + .name = KBUILD_MODNAME, + .bus = &fw_bus_type, + .probe = scs_probe, + .remove = scs_remove, + }, + .update = scs_update, + .id_table = scs_id_table, +}; + +static int __init alsa_scs1x_init(void) +{ + return driver_register(&scs_driver.driver); +} + +static void __exit alsa_scs1x_exit(void) +{ + driver_unregister(&scs_driver.driver); +} + +module_init(alsa_scs1x_init); +module_exit(alsa_scs1x_exit); ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Help requested: new HSS1394 MIDI back-end 2012-06-10 13:00 ` Clemens Ladisch @ 2012-10-24 11:49 ` Sean M. Pappalardo - D.J. Pegasus 2012-10-25 19:23 ` Clemens Ladisch 0 siblings, 1 reply; 25+ messages in thread From: Sean M. Pappalardo - D.J. Pegasus @ 2012-10-24 11:49 UTC (permalink / raw) To: Clemens Ladisch; +Cc: alsa-devel, linux1394-devel [-- Attachment #1.1: Type: text/plain, Size: 1053 bytes --] Hello again. I'm very sorry for my absence. As usual with works of passion, life has gotten in the way the past few months. On 06/10/2012 03:00 PM, Clemens Ladisch wrote: > New patch below. This one seems to work perfectly with Mixxx! However, the amidi dump still shows an extra 00 byte after every message: F0 00 01 60 48 53 53 00 00 0F 09 02 0C 09 0A 05 0C F7 00 F0 00 01 60 48 53 53 00 00 0F 09 03 00 08 03 05 0C F7 00 F0 00 01 60 48 53 53 00 00 0F 09 03 04 06 0D 05 0C F7 00 80 20 00 00 F0 00 01 60 48 53 53 00 00 0F 09 03 08 05 06 05 0C F7 00 F0 00 01 60 48 53 53 00 00 0F 09 03 0C 03 0F 05 0C F7 00 90 20 0D 00 F0 00 01 60 48 53 53 00 00 0F 09 04 00 02 09 05 0C F7 00 F0 00 01 60 48 53 53 00 00 0F 09 04 04 01 02 05 0C F7 00 F0 00 01 60 48 53 53 00 00 0F 09 04 07 0F 0B 05 0C F7 00 We should probably fix that. BTW, which ALSA version (and Linux kernel version) did the last patch go into, if any? Sincerely, Sean M. Pappalardo "D.J. Pegasus" Mixxx Developer - Controller Specialist [-- Attachment #1.2: S/MIME Cryptographic Signature --] [-- Type: application/pkcs7-signature, Size: 4558 bytes --] [-- Attachment #2: Type: text/plain, Size: 0 bytes --] ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Help requested: new HSS1394 MIDI back-end 2012-10-24 11:49 ` Sean M. Pappalardo - D.J. Pegasus @ 2012-10-25 19:23 ` Clemens Ladisch 2012-10-25 20:26 ` Sean M. Pappalardo - D.J. Pegasus ` (3 more replies) 0 siblings, 4 replies; 25+ messages in thread From: Clemens Ladisch @ 2012-10-25 19:23 UTC (permalink / raw) To: Sean M. Pappalardo - D.J. Pegasus; +Cc: alsa-devel, linux1394-devel Sean M. Pappalardo - D.J. Pegasus wrote: > the amidi dump still shows an extra 00 byte after every message Silly off-by-one error. New patch below. > BTW, which ALSA version (and Linux kernel version) did the last patch > go into, if any? I was waiting for your Tested-by ... Regards, Clemens sound/firewire/Kconfig | 13 ++ sound/firewire/Makefile | 2 + sound/firewire/scs1x.c | 531 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 546 insertions(+), 0 deletions(-) create mode 100644 sound/firewire/scs1x.c diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig index 2607148..ea063e1 100644 --- a/sound/firewire/Kconfig +++ b/sound/firewire/Kconfig @@ -33,4 +33,17 @@ config SND_ISIGHT To compile this driver as a module, choose M here: the module will be called snd-isight. +config SND_SCS1X + tristate "Stanton Control System 1 MIDI" + select SND_PCM + select SND_RAWMIDI + select SND_FIREWIRE_LIB + help + Say Y here to include support for the MIDI ports of the Stanton + SCS.1d/SCS.1m DJ controllers. (SCS.1m audio is still handled + by FFADO.) + + To compile this driver as a module, choose M here: the module + will be called snd-scs1x. + endif # SND_FIREWIRE diff --git a/sound/firewire/Makefile b/sound/firewire/Makefile index d71ed89..460179d 100644 --- a/sound/firewire/Makefile +++ b/sound/firewire/Makefile @@ -2,7 +2,9 @@ snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \ fcp.o cmp.o amdtp.o snd-firewire-speakers-objs := speakers.o snd-isight-objs := isight.o +snd-scs1x-objs := scs1x.o obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o obj-$(CONFIG_SND_FIREWIRE_SPEAKERS) += snd-firewire-speakers.o obj-$(CONFIG_SND_ISIGHT) += snd-isight.o +obj-$(CONFIG_SND_SCS1X) += snd-scs1x.o diff --git a/sound/firewire/scs1x.c b/sound/firewire/scs1x.c new file mode 100644 index 0000000..40b4798 --- /dev/null +++ b/sound/firewire/scs1x.c @@ -0,0 +1,531 @@ +/* + * Stanton Control System 1 MIDI driver + * + * Copyright (c) Clemens Ladisch <clemens@ladisch.de> + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#include <linux/device.h> +#include <linux/firewire.h> +#include <linux/firewire-constants.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/wait.h> +#include <sound/core.h> +#include <sound/initval.h> +#include <sound/rawmidi.h> +#include "lib.h" + +#define OUI_STANTON 0x001260 +#define MODEL_SCS_1M 0x001000 +#define MODEL_SCS_1D 0x002000 + +#define HSS1394_ADDRESS 0xc007dedadadaULL +#define HSS1394_MAX_PACKET_SIZE 64 + +#define HSS1394_TAG_USER_DATA 0x00 +#define HSS1394_TAG_CHANGE_ADDRESS 0xf1 + +struct scs { + struct snd_card *card; + struct fw_unit *unit; + struct fw_address_handler hss_handler; + struct fw_transaction transaction; + bool transaction_running; + bool output_idle; + u8 output_status; + u8 output_bytes; + bool output_escaped; + bool output_escape_high_nibble; + u8 input_escape_count; + struct snd_rawmidi_substream *output; + struct snd_rawmidi_substream *input; + struct tasklet_struct tasklet; + wait_queue_head_t idle_wait; + u8 *buffer; +}; + +static const u8 sysex_escape_prefix[] = { + 0xf0, /* SysEx begin */ + 0x00, 0x01, 0x60, /* Stanton DJ */ + 0x48, 0x53, 0x53, /* "HSS" */ +}; + +static int scs_output_open(struct snd_rawmidi_substream *stream) +{ + struct scs *scs = stream->rmidi->private_data; + + scs->output_status = 0; + scs->output_bytes = 1; + scs->output_escaped = false; + + return 0; +} + +static int scs_output_close(struct snd_rawmidi_substream *stream) +{ + return 0; +} + +static void scs_output_trigger(struct snd_rawmidi_substream *stream, int up) +{ + struct scs *scs = stream->rmidi->private_data; + + ACCESS_ONCE(scs->output) = up ? stream : NULL; + if (up) { + scs->output_idle = false; + tasklet_schedule(&scs->tasklet); + } +} + +static void scs_write_callback(struct fw_card *card, int rcode, + void *data, size_t length, void *callback_data) +{ + struct scs *scs = callback_data; + + if (rcode == RCODE_GENERATION) { + /* TODO: retry this packet */ + } + + scs->transaction_running = false; + tasklet_schedule(&scs->tasklet); +} + +static bool is_valid_running_status(u8 status) +{ + return status >= 0x80 && status <= 0xef; +} + +static bool is_one_byte_cmd(u8 status) +{ + return status == 0xf6 || + status >= 0xf8; +} + +static bool is_two_bytes_cmd(u8 status) +{ + return (status >= 0xc0 && status <= 0xdf) || + status == 0xf1 || + status == 0xf3; +} + +static bool is_three_bytes_cmd(u8 status) +{ + return (status >= 0x80 && status <= 0xbf) || + (status >= 0xe0 && status <= 0xef) || + status == 0xf2; +} + +static bool is_invalid_cmd(u8 status) +{ + return status == 0xf4 || + status == 0xf5 || + status == 0xf9 || + status == 0xfd; +} + +static void scs_output_tasklet(unsigned long data) +{ + struct scs *scs = (void *)data; + struct snd_rawmidi_substream *stream; + unsigned int i; + u8 byte; + struct fw_device *dev; + int generation; + + if (scs->transaction_running) + return; + + stream = ACCESS_ONCE(scs->output); + if (!stream) { + scs->output_idle = true; + wake_up(&scs->idle_wait); + return; + } + + i = scs->output_bytes; + for (;;) { + if (snd_rawmidi_transmit(stream, &byte, 1) != 1) { + scs->output_bytes = i; + scs->output_idle = true; + wake_up(&scs->idle_wait); + return; + } + /* + * Convert from real MIDI to what I think the device expects (no + * running status, one command per packet, unescaped SysExs). + */ + if (scs->output_escaped && byte < 0x80) { + if (scs->output_escape_high_nibble) { + if (i < HSS1394_MAX_PACKET_SIZE) { + scs->buffer[i] = byte << 4; + scs->output_escape_high_nibble = false; + } + } else { + scs->buffer[i++] |= byte & 0x0f; + scs->output_escape_high_nibble = true; + } + } else if (byte < 0x80) { + if (i == 1) { + if (!is_valid_running_status(scs->output_status)) + continue; + scs->buffer[0] = HSS1394_TAG_USER_DATA; + scs->buffer[i++] = scs->output_status; + } + scs->buffer[i++] = byte; + if ((i == 3 && is_two_bytes_cmd(scs->output_status)) || + (i == 4 && is_three_bytes_cmd(scs->output_status))) + break; + if (i == 1 + ARRAY_SIZE(sysex_escape_prefix) && + !memcmp(scs->buffer + 1, sysex_escape_prefix, + ARRAY_SIZE(sysex_escape_prefix))) { + scs->output_escaped = true; + scs->output_escape_high_nibble = true; + i = 0; + } + if (i >= HSS1394_MAX_PACKET_SIZE) + i = 1; + } else if (byte == 0xf7) { + if (scs->output_escaped) { + if (i >= 1 && scs->output_escape_high_nibble && + scs->buffer[0] != HSS1394_TAG_CHANGE_ADDRESS) + break; + } else { + if (i > 1 && scs->output_status == 0xf0) { + scs->buffer[i++] = 0xf7; + break; + } + } + i = 1; + scs->output_escaped = false; + } else if (!is_invalid_cmd(byte) && + byte < 0xf8) { + i = 1; + scs->buffer[0] = HSS1394_TAG_USER_DATA; + scs->buffer[i++] = byte; + scs->output_status = byte; + scs->output_escaped = false; + if (is_one_byte_cmd(byte)) + break; + } + } + scs->output_bytes = 1; + scs->output_escaped = false; + + scs->transaction_running = true; + dev = fw_parent_device(scs->unit); + generation = dev->generation; + smp_rmb(); /* node_id vs. generation */ + fw_send_request(dev->card, &scs->transaction, TCODE_WRITE_BLOCK_REQUEST, + dev->node_id, generation, dev->max_speed, + HSS1394_ADDRESS, scs->buffer, i, + scs_write_callback, scs); +} + +static void scs_output_drain(struct snd_rawmidi_substream *stream) +{ + struct scs *scs = stream->rmidi->private_data; + + wait_event(scs->idle_wait, scs->output_idle); +} + +static struct snd_rawmidi_ops output_ops = { + .open = scs_output_open, + .close = scs_output_close, + .trigger = scs_output_trigger, + .drain = scs_output_drain, +}; + +static int scs_input_open(struct snd_rawmidi_substream *stream) +{ + struct scs *scs = stream->rmidi->private_data; + + scs->input_escape_count = 0; + + return 0; +} + +static int scs_input_close(struct snd_rawmidi_substream *stream) +{ + return 0; +} + +static void scs_input_trigger(struct snd_rawmidi_substream *stream, int up) +{ + struct scs *scs = stream->rmidi->private_data; + + ACCESS_ONCE(scs->input) = up ? stream : NULL; +} + +static void scs_input_escaped_byte(struct snd_rawmidi_substream *stream, + u8 byte) +{ + u8 nibbles[2]; + + nibbles[0] = byte >> 4; + nibbles[1] = byte & 0x0f; + snd_rawmidi_receive(stream, nibbles, 2); +} + +static void scs_input_midi_byte(struct scs *scs, + struct snd_rawmidi_substream *stream, + u8 byte) +{ + if (scs->input_escape_count > 0) { + scs_input_escaped_byte(stream, byte); + scs->input_escape_count--; + if (scs->input_escape_count == 0) + snd_rawmidi_receive(stream, (const u8[]) { 0xf7 }, 1); + } else if (byte == 0xf9) { + snd_rawmidi_receive(stream, sysex_escape_prefix, + ARRAY_SIZE(sysex_escape_prefix)); + scs_input_escaped_byte(stream, 0x00); + scs_input_escaped_byte(stream, 0xf9); + scs->input_escape_count = 3; + } else { + snd_rawmidi_receive(stream, &byte, 1); + } +} + +static void scs_input_packet(struct scs *scs, + struct snd_rawmidi_substream *stream, + const u8 *data, unsigned int bytes) +{ + unsigned int i; + + if (data[0] == HSS1394_TAG_USER_DATA) { + for (i = 1; i < bytes; ++i) + scs_input_midi_byte(scs, stream, data[i]); + } else { + snd_rawmidi_receive(stream, sysex_escape_prefix, + ARRAY_SIZE(sysex_escape_prefix)); + for (i = 0; i < bytes; ++i) + scs_input_escaped_byte(stream, data[i]); + snd_rawmidi_receive(stream, (const u8[]) { 0xf7 }, 1); + } +} + +static struct snd_rawmidi_ops input_ops = { + .open = scs_input_open, + .close = scs_input_close, + .trigger = scs_input_trigger, +}; + +static int scs_create_midi(struct scs *scs) +{ + struct snd_rawmidi *rmidi; + int err; + + err = snd_rawmidi_new(scs->card, "SCS.1x", 0, 1, 1, &rmidi); + if (err < 0) + return err; + snprintf(rmidi->name, sizeof(rmidi->name), + "%s MIDI", scs->card->shortname); + rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | + SNDRV_RAWMIDI_INFO_INPUT | + SNDRV_RAWMIDI_INFO_DUPLEX; + rmidi->private_data = scs; + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &output_ops); + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &input_ops); + + return 0; +} + +static void handle_hss(struct fw_card *card, struct fw_request *request, + int tcode, int destination, int source, int generation, + unsigned long long offset, void *data, size_t length, + void *callback_data) +{ + struct scs *scs = callback_data; + struct snd_rawmidi_substream *stream; + + if (offset != scs->hss_handler.offset) { + fw_send_response(card, request, RCODE_ADDRESS_ERROR); + return; + } + if (tcode != TCODE_WRITE_QUADLET_REQUEST && + tcode != TCODE_WRITE_BLOCK_REQUEST) { + fw_send_response(card, request, RCODE_TYPE_ERROR); + return; + } + + if (length >= 1) { + stream = ACCESS_ONCE(scs->input); + if (stream) + scs_input_packet(scs, stream, data, length); + } + + fw_send_response(card, request, RCODE_COMPLETE); +} + +static int scs_init_hss_address(struct scs *scs) +{ + u8 data[8]; + int err; + + *(__be64 *)data = cpu_to_be64(scs->hss_handler.offset); + data[0] = HSS1394_TAG_CHANGE_ADDRESS; + err = snd_fw_transaction(scs->unit, TCODE_WRITE_BLOCK_REQUEST, + HSS1394_ADDRESS, data, 8, 0); + if (err < 0) + dev_err(&scs->unit->device, "HSS1394 communication failed\n"); + + return err; +} + +static void scs_card_free(struct snd_card *card) +{ + struct scs *scs = card->private_data; + + fw_core_remove_address_handler(&scs->hss_handler); + kfree(scs->buffer); +} + +static int scs_probe(struct device *unit_dev) +{ + struct fw_unit *unit = fw_unit(unit_dev); + struct fw_device *fw_dev = fw_parent_device(unit); + struct snd_card *card; + struct scs *scs; + int err; + + err = snd_card_create(-16, NULL, THIS_MODULE, sizeof(*scs), &card); + if (err < 0) + return err; + snd_card_set_dev(card, unit_dev); + + scs = card->private_data; + scs->card = card; + scs->unit = unit; + tasklet_init(&scs->tasklet, scs_output_tasklet, (unsigned long)scs); + init_waitqueue_head(&scs->idle_wait); + scs->output_idle = true; + + scs->buffer = kmalloc(HSS1394_MAX_PACKET_SIZE, GFP_KERNEL); + if (!scs->buffer) + goto err_card; + + scs->hss_handler.length = HSS1394_MAX_PACKET_SIZE; + scs->hss_handler.address_callback = handle_hss; + scs->hss_handler.callback_data = scs; + err = fw_core_add_address_handler(&scs->hss_handler, + &fw_high_memory_region); + if (err < 0) + goto err_buffer; + + card->private_free = scs_card_free; + + strcpy(card->driver, "SCS.1x"); + strcpy(card->shortname, "SCS.1x"); + fw_csr_string(unit->directory, CSR_MODEL, + card->shortname, sizeof(card->shortname)); + snprintf(card->longname, sizeof(card->longname), + "Stanton DJ %s (GUID %08x%08x) at %s, S%d", + card->shortname, fw_dev->config_rom[3], fw_dev->config_rom[4], + dev_name(&unit->device), 100 << fw_dev->max_speed); + strcpy(card->mixername, card->shortname); + + err = scs_init_hss_address(scs); + if (err < 0) + goto err_card; + + err = scs_create_midi(scs); + if (err < 0) + goto err_card; + + err = snd_card_register(card); + if (err < 0) + goto err_card; + + dev_set_drvdata(unit_dev, scs); + + return 0; + +err_buffer: + kfree(scs->buffer); +err_card: + snd_card_free(card); + return err; +} + +static int scs_remove(struct device *dev) +{ + struct scs *scs = dev_get_drvdata(dev); + + snd_card_disconnect(scs->card); + + ACCESS_ONCE(scs->output) = NULL; + ACCESS_ONCE(scs->input) = NULL; + + wait_event(scs->idle_wait, scs->output_idle); + + tasklet_kill(&scs->tasklet); + + snd_card_free_when_closed(scs->card); + + return 0; +} + +static void scs_update(struct fw_unit *unit) +{ + struct scs *scs = dev_get_drvdata(&unit->device); + int generation; + u8 data[8]; + + *(__be64 *)data = cpu_to_be64(scs->hss_handler.offset); + data[0] = HSS1394_TAG_CHANGE_ADDRESS; + generation = fw_parent_device(unit)->generation; + smp_rmb(); /* node_id vs. generation */ + snd_fw_transaction(scs->unit, TCODE_WRITE_BLOCK_REQUEST, + HSS1394_ADDRESS, data, 8, + FW_FIXED_GENERATION | generation); +} + +static const struct ieee1394_device_id scs_id_table[] = { + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | + IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_STANTON, + .model_id = MODEL_SCS_1M, + }, + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | + IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_STANTON, + .model_id = MODEL_SCS_1D, + }, + {} +}; +MODULE_DEVICE_TABLE(ieee1394, scs_id_table); + +MODULE_DESCRIPTION("SCS.1x MIDI driver"); +MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); +MODULE_LICENSE("GPL v2"); + +static struct fw_driver scs_driver = { + .driver = { + .owner = THIS_MODULE, + .name = KBUILD_MODNAME, + .bus = &fw_bus_type, + .probe = scs_probe, + .remove = scs_remove, + }, + .update = scs_update, + .id_table = scs_id_table, +}; + +static int __init alsa_scs1x_init(void) +{ + return driver_register(&scs_driver.driver); +} + +static void __exit alsa_scs1x_exit(void) +{ + driver_unregister(&scs_driver.driver); +} + +module_init(alsa_scs1x_init); +module_exit(alsa_scs1x_exit); ^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: Help requested: new HSS1394 MIDI back-end 2012-10-25 19:23 ` Clemens Ladisch @ 2012-10-25 20:26 ` Sean M. Pappalardo - D.J. Pegasus 2012-10-26 7:48 ` Clemens Ladisch 2012-10-31 10:00 ` Sean M. Pappalardo - D.J. Pegasus ` (2 subsequent siblings) 3 siblings, 1 reply; 25+ messages in thread From: Sean M. Pappalardo - D.J. Pegasus @ 2012-10-25 20:26 UTC (permalink / raw) To: Clemens Ladisch; +Cc: alsa-devel, linux1394-devel [-- Attachment #1.1: Type: text/plain, Size: 377 bytes --] On 10/25/2012 09:23 PM, Clemens Ladisch wrote: > I was waiting for your Tested-by ... Oopsie... I thought I replied saying that Tested-by: Sean M. Pappalardo - D.J. Pegasus <spappalardo@mixxx.org> ...was fine. Ah well. Thanks again for all your hard work on this! Sincerely, Sean M. Pappalardo "D.J. Pegasus" Mixxx Developer - Controller Specialist [-- Attachment #1.2: S/MIME Cryptographic Signature --] [-- Type: application/pkcs7-signature, Size: 4558 bytes --] [-- Attachment #2: Type: text/plain, Size: 0 bytes --] ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Help requested: new HSS1394 MIDI back-end 2012-10-25 20:26 ` Sean M. Pappalardo - D.J. Pegasus @ 2012-10-26 7:48 ` Clemens Ladisch 0 siblings, 0 replies; 25+ messages in thread From: Clemens Ladisch @ 2012-10-26 7:48 UTC (permalink / raw) To: Sean M. Pappalardo - D.J. Pegasus; +Cc: alsa-devel, linux1394-devel Sean M. Pappalardo - D.J. Pegasus wrote: > On 10/25/2012 09:23 PM, Clemens Ladisch wrote: >> I was waiting for your Tested-by ... > > Oopsie... I thought I replied saying that > > Tested-by: Sean M. Pappalardo - D.J. Pegasus <spappalardo@mixxx.org> > > ...was fine. Sorry, you did; what I meant to say was that I was waiting for the test *result*. (Which turned out to be negative after all.) Regards, Clemens ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Help requested: new HSS1394 MIDI back-end 2012-10-25 19:23 ` Clemens Ladisch 2012-10-25 20:26 ` Sean M. Pappalardo - D.J. Pegasus @ 2012-10-31 10:00 ` Sean M. Pappalardo - D.J. Pegasus 2012-11-11 21:34 ` [git pull] " Clemens Ladisch 2012-11-09 6:41 ` Help requested: " Sean M. Pappalardo - D.J. Pegasus 2012-11-12 9:45 ` Takashi Iwai 3 siblings, 1 reply; 25+ messages in thread From: Sean M. Pappalardo - D.J. Pegasus @ 2012-10-31 10:00 UTC (permalink / raw) To: Clemens Ladisch; +Cc: alsa-devel, linux1394-devel [-- Attachment #1.1: Type: text/plain, Size: 394 bytes --] On 10/25/2012 09:23 PM, Clemens Ladisch wrote: > Silly off-by-one error. New patch below. Okay! That looks and works great! (I had to remove the extra parameter on the snd_fw_transaction calls since I'm still using kernel 3.2.18.) Thank you very much for all your time and work on this! Sincerely, Sean M. Pappalardo "D.J. Pegasus" Mixxx Developer - Controller Specialist [-- Attachment #1.2: S/MIME Cryptographic Signature --] [-- Type: application/pkcs7-signature, Size: 4558 bytes --] [-- Attachment #2: Type: text/plain, Size: 0 bytes --] ^ permalink raw reply [flat|nested] 25+ messages in thread
* [git pull] new HSS1394 MIDI back-end 2012-10-31 10:00 ` Sean M. Pappalardo - D.J. Pegasus @ 2012-11-11 21:34 ` Clemens Ladisch 0 siblings, 0 replies; 25+ messages in thread From: Clemens Ladisch @ 2012-11-11 21:34 UTC (permalink / raw) To: Takashi Iwai; +Cc: alsa-devel Takashi, please pull the following change since commit a0d271cbfed1dd50278c6b06bead3d00ba0a88f9: Linux 3.6 (2012-09-30 16:47:46 -0700) which is available in the git repository at: git://git.alsa-project.org/alsa-kprivate.git stanton-cs1-driver Clemens Ladisch (1): ALSA: firewire: add Stanton SCS.1d/1m driver sound/firewire/Kconfig | 13 ++ sound/firewire/Makefile | 2 + sound/firewire/scs1x.c | 527 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 542 insertions(+), 0 deletions(-) create mode 100644 sound/firewire/scs1x.c ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Help requested: new HSS1394 MIDI back-end 2012-10-25 19:23 ` Clemens Ladisch 2012-10-25 20:26 ` Sean M. Pappalardo - D.J. Pegasus 2012-10-31 10:00 ` Sean M. Pappalardo - D.J. Pegasus @ 2012-11-09 6:41 ` Sean M. Pappalardo - D.J. Pegasus 2012-11-12 9:45 ` Takashi Iwai 3 siblings, 0 replies; 25+ messages in thread From: Sean M. Pappalardo - D.J. Pegasus @ 2012-11-09 6:41 UTC (permalink / raw) To: Clemens Ladisch; +Cc: alsa-devel, linux1394-devel [-- Attachment #1.1: Type: text/plain, Size: 290 bytes --] Hello again. Since your patch works fine, I just wanted to know in which ALSA and kernel version it will appear, so I can tell end users what they need. Thank you very much for your time. Sincerely, Sean M. Pappalardo "D.J. Pegasus" Mixxx Developer - Controller Specialist [-- Attachment #1.2: S/MIME Cryptographic Signature --] [-- Type: application/pkcs7-signature, Size: 4558 bytes --] [-- Attachment #2: Type: text/plain, Size: 0 bytes --] ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Help requested: new HSS1394 MIDI back-end 2012-10-25 19:23 ` Clemens Ladisch ` (2 preceding siblings ...) 2012-11-09 6:41 ` Help requested: " Sean M. Pappalardo - D.J. Pegasus @ 2012-11-12 9:45 ` Takashi Iwai 2012-11-12 11:33 ` Clemens Ladisch 3 siblings, 1 reply; 25+ messages in thread From: Takashi Iwai @ 2012-11-12 9:45 UTC (permalink / raw) To: Clemens Ladisch Cc: Sean M. Pappalardo - D.J. Pegasus, alsa-devel, linux1394-devel At Thu, 25 Oct 2012 21:23:41 +0200, Clemens Ladisch wrote: > > +static int scs_init_hss_address(struct scs *scs) > +{ > + u8 data[8]; > + int err; > + > + *(__be64 *)data = cpu_to_be64(scs->hss_handler.offset); Wouldn't it be safer to use unaligned access or a union? > +static void scs_update(struct fw_unit *unit) > +{ > + struct scs *scs = dev_get_drvdata(&unit->device); > + int generation; > + u8 data[8]; > + > + *(__be64 *)data = cpu_to_be64(scs->hss_handler.offset); Ditto. Takashi ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Help requested: new HSS1394 MIDI back-end 2012-11-12 9:45 ` Takashi Iwai @ 2012-11-12 11:33 ` Clemens Ladisch 2012-11-12 11:40 ` Takashi Iwai 0 siblings, 1 reply; 25+ messages in thread From: Clemens Ladisch @ 2012-11-12 11:33 UTC (permalink / raw) To: Takashi Iwai Cc: Sean M. Pappalardo - D.J. Pegasus, alsa-devel, linux1394-devel Takashi Iwai wrote: > Clemens Ladisch wrote: >> >> +static int scs_init_hss_address(struct scs *scs) >> +{ >> + u8 data[8]; >> + int err; >> + >> + *(__be64 *)data = cpu_to_be64(scs->hss_handler.offset); > > Wouldn't it be safer to use unaligned access or a union? Oops, indeed. But safest would be to avoid playing byte-array games: __be64 data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) | scs->hss_handler.offset); Now fixed in the same branch. Regards, Clemens ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Help requested: new HSS1394 MIDI back-end 2012-11-12 11:33 ` Clemens Ladisch @ 2012-11-12 11:40 ` Takashi Iwai 2012-11-12 11:45 ` [alsa-devel] " Clemens Ladisch 0 siblings, 1 reply; 25+ messages in thread From: Takashi Iwai @ 2012-11-12 11:40 UTC (permalink / raw) To: Clemens Ladisch Cc: Sean M. Pappalardo - D.J. Pegasus, alsa-devel, linux1394-devel At Mon, 12 Nov 2012 12:33:47 +0100, Clemens Ladisch wrote: > > Takashi Iwai wrote: > > Clemens Ladisch wrote: > >> > >> +static int scs_init_hss_address(struct scs *scs) > >> +{ > >> + u8 data[8]; > >> + int err; > >> + > >> + *(__be64 *)data = cpu_to_be64(scs->hss_handler.offset); > > > > Wouldn't it be safer to use unaligned access or a union? > > Oops, indeed. But safest would be to avoid playing byte-array games: > > __be64 data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) | > scs->hss_handler.offset); > > Now fixed in the same branch. OK, let me know when you push out the changes, so that I'll pull it. thanks, Takashi ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [alsa-devel] Help requested: new HSS1394 MIDI back-end 2012-11-12 11:40 ` Takashi Iwai @ 2012-11-12 11:45 ` Clemens Ladisch 2012-11-12 14:26 ` Takashi Iwai 0 siblings, 1 reply; 25+ messages in thread From: Clemens Ladisch @ 2012-11-12 11:45 UTC (permalink / raw) To: Takashi Iwai Cc: Sean M. Pappalardo - D.J. Pegasus, alsa-devel, linux1394-devel Takashi Iwai wrote: > Clemens Ladisch wrote: >> Now fixed in the same branch. > > OK, let me know when you push out the changes, so that I'll pull it. Pushed (as amended commit). Regards, Clemens ------------------------------------------------------------------------------ Everyone hates slow websites. So do we. Make your web apps faster with AppDynamics Download AppDynamics Lite for free today: http://p.sf.net/sfu/appdyn_d2d_nov ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [alsa-devel] Help requested: new HSS1394 MIDI back-end 2012-11-12 11:45 ` [alsa-devel] " Clemens Ladisch @ 2012-11-12 14:26 ` Takashi Iwai 0 siblings, 0 replies; 25+ messages in thread From: Takashi Iwai @ 2012-11-12 14:26 UTC (permalink / raw) To: Clemens Ladisch Cc: Sean M. Pappalardo - D.J. Pegasus, alsa-devel, linux1394-devel At Mon, 12 Nov 2012 12:45:50 +0100, Clemens Ladisch wrote: > > Takashi Iwai wrote: > > Clemens Ladisch wrote: > >> Now fixed in the same branch. > > > > OK, let me know when you push out the changes, so that I'll pull it. > > Pushed (as amended commit). Thanks, pulled now. Takashi ------------------------------------------------------------------------------ Everyone hates slow websites. So do we. Make your web apps faster with AppDynamics Download AppDynamics Lite for free today: http://p.sf.net/sfu/appdyn_d2d_nov ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Help requested: new HSS1394 MIDI back-end 2012-05-31 20:00 ` Clemens Ladisch 2012-06-09 6:54 ` Sean M. Pappalardo - D.J. Pegasus @ 2012-06-09 8:42 ` Sean M. Pappalardo - D.J. Pegasus 2012-06-09 10:12 ` Sean M. Pappalardo - D.J. Pegasus 2 siblings, 0 replies; 25+ messages in thread From: Sean M. Pappalardo - D.J. Pegasus @ 2012-06-09 8:42 UTC (permalink / raw) To: Clemens Ladisch; +Cc: alsa-devel, linux1394-devel [-- Attachment #1.1: Type: text/plain, Size: 1338 bytes --] Hello again. I just modified Mixxx's SCS.1d script to work with your custom sysex messages and tested with your latest patch. The .1d doesn't actually work 100% with this since Mixxx never receives some of the standard MIDI messages amid all of the sysex ones, and it's much worse when the platter is spinning and sending the tons of messages it does. This could be due to PortMIDI's lack of a callback mechanism, forcing Mixxx to poll it every 1ms because it's much more difficult to reproduce the problem using amidi -d. (Of course, amidi isn't sending data to the controller at the same time like Mixxx does.) That said, the scratching works better in Linux that it does on Windows via libhss1394! (Not really a surprise since Windows has issues anyway.) I also see an F9 message slip through once in awhile according to amidi -d: F9 55 91 C4 That's most likely to happen if the unit is sending alot of standard MIDI messages (such as when I quickly move a slider that sends a CC) since the device is always sending F9 messages as timestamps. More F9 messages slip through when the platter is spinning because then they come more frequently. Thank you again very much for your time and work! Sincerely, Sean M. Pappalardo "D.J. Pegasus" Mixxx Developer - Controller Specialist [-- Attachment #1.2: S/MIME Cryptographic Signature --] [-- Type: application/pkcs7-signature, Size: 4558 bytes --] [-- Attachment #2: Type: text/plain, Size: 0 bytes --] ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Help requested: new HSS1394 MIDI back-end 2012-05-31 20:00 ` Clemens Ladisch 2012-06-09 6:54 ` Sean M. Pappalardo - D.J. Pegasus 2012-06-09 8:42 ` Sean M. Pappalardo - D.J. Pegasus @ 2012-06-09 10:12 ` Sean M. Pappalardo - D.J. Pegasus 2 siblings, 0 replies; 25+ messages in thread From: Sean M. Pappalardo - D.J. Pegasus @ 2012-06-09 10:12 UTC (permalink / raw) To: Clemens Ladisch; +Cc: alsa-devel, linux1394-devel [-- Attachment #1.1: Type: text/plain, Size: 661 bytes --] Oh one more thing, sorry for the multiple messages. As soon as I start the JACK server to handle the audio interface on the SCS.1m, the ALSA driver stops sending MIDI for that device unless I stop JACK and power-cycle the device. Its last words are: F0 00 01 60 48 53 53 0F 03 00 03 00 00 0B 01 F7 It does, however, continue to respond to MIDI messages send to it. The SCS.1d (connected through the SCS.1m) continues as before. (On Windows via libhss1394, it's possible to use the audio interface and HSS1394 control on both devices simultaneously.) Sincerely, Sean M. Pappalardo "D.J. Pegasus" Mixxx Developer - Controller Specialist [-- Attachment #1.2: S/MIME Cryptographic Signature --] [-- Type: application/pkcs7-signature, Size: 4558 bytes --] [-- Attachment #2: Type: text/plain, Size: 0 bytes --] ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Help requested: new HSS1394 MIDI back-end 2012-05-30 7:18 ` Clemens Ladisch 2012-05-31 20:00 ` Clemens Ladisch @ 2012-05-31 22:04 ` Sean M. Pappalardo - D.J. Pegasus 2012-06-01 8:22 ` Clemens Ladisch 1 sibling, 1 reply; 25+ messages in thread From: Sean M. Pappalardo - D.J. Pegasus @ 2012-05-31 22:04 UTC (permalink / raw) To: Clemens Ladisch; +Cc: alsa-devel, linux1394-devel [-- Attachment #1.1: Type: text/plain, Size: 828 bytes --] On 05/30/2012 09:18 AM, Clemens Ladisch wrote: > As it happens, the actual SysEx commands use the wrong manufacturer ID > ("00 01 02" is Crystal Semiconductor); I could just use the real ID > (Stanton is "00 01 60") to escape non-MIDI HSS1394 messages. Let's add > "HSS" to identify this, and to allow the full byte range, each HSS1394 > byte is split into two nibbles. That all sounds good, but that now means that applications that want to use these device features must have different code for Linux than they do for Windows or OSX. In the case of Mixxx, that also means a different controller preset. But I guess that's not the end of the world if it's a choice between this and no support at all. Sigh... Sincerely, Sean M. Pappalardo "D.J. Pegasus" Mixxx Developer - Controller Specialist [-- Attachment #1.2: S/MIME Cryptographic Signature --] [-- Type: application/pkcs7-signature, Size: 4545 bytes --] [-- Attachment #2: Type: text/plain, Size: 0 bytes --] ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Help requested: new HSS1394 MIDI back-end 2012-05-31 22:04 ` Sean M. Pappalardo - D.J. Pegasus @ 2012-06-01 8:22 ` Clemens Ladisch 2012-06-01 13:40 ` [alsa-devel] " Stefan Richter 0 siblings, 1 reply; 25+ messages in thread From: Clemens Ladisch @ 2012-06-01 8:22 UTC (permalink / raw) To: Sean M. Pappalardo - D.J. Pegasus; +Cc: alsa-devel, linux1394-devel Sean M. Pappalardo - D.J. Pegasus wrote: > On 05/30/2012 09:18 AM, Clemens Ladisch wrote: >> As it happens, the actual SysEx commands use the wrong manufacturer ID >> ("00 01 02" is Crystal Semiconductor); I could just use the real ID >> (Stanton is "00 01 60") to escape non-MIDI HSS1394 messages. Let's add >> "HSS" to identify this, and to allow the full byte range, each HSS1394 >> byte is split into two nibbles. > > That all sounds good, but that now means that applications that want > to use these device features must have different code for Linux than > they do for Windows or OSX. IIRC it was decided to use a MIDI driver in order to allow other applications to access these devices with standard MIDI APIs. (Does this imply that on Windows and OS X, it is not possible to access them without using the HSS1394 library?) You could still port the HSS1394 library so that it sits on top of the MIDI driver. (In other words, the Linux MIDI backend would be the equivalent of the Windows and OS X FireWire backends.) Regards, Clemens ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [alsa-devel] Help requested: new HSS1394 MIDI back-end 2012-06-01 8:22 ` Clemens Ladisch @ 2012-06-01 13:40 ` Stefan Richter 0 siblings, 0 replies; 25+ messages in thread From: Stefan Richter @ 2012-06-01 13:40 UTC (permalink / raw) To: Clemens Ladisch Cc: Sean M. Pappalardo - D.J. Pegasus, alsa-devel, linux1394-devel On Jun 01 Clemens Ladisch wrote: > Sean M. Pappalardo - D.J. Pegasus wrote: > > On 05/30/2012 09:18 AM, Clemens Ladisch wrote: > >> As it happens, the actual SysEx commands use the wrong manufacturer ID > >> ("00 01 02" is Crystal Semiconductor); I could just use the real ID > >> (Stanton is "00 01 60") to escape non-MIDI HSS1394 messages. Let's add > >> "HSS" to identify this, and to allow the full byte range, each HSS1394 > >> byte is split into two nibbles. It wasn't quite clear (to me) from the start that HSS1394 is not actually "MIDI encapsulated in a vendor-defined 1394 transport protocol" but more like "a vendor-defined events-and-commands protocol which borrows much from MIDI, encapsulated in a vendor-defined 1394 transport protocol". > > That all sounds good, but that now means that applications that want > > to use these device features must have different code for Linux than > > they do for Windows or OSX. On the other hand, there is the benefit that applications (multi-platform or single-platform, HSS1394 aware or unaware) just have to cope with generic ALSA-based MIDI programming when on Linux. > IIRC it was decided to use a MIDI driver in order to allow other > applications to access these devices with standard MIDI APIs. > (Does this imply that on Windows and OS X, it is not possible to > access them without using the HSS1394 library?) I guess while a HSS1394-to-MIDI driver, sitting between the native 1394 stack and the native audio and music API, would be just as feasible on these two other platforms, only the libhss1394 way was implemented. Seeing how small Clemens' driver is, and speculating that a similar OS X driver would be about the same amount of code while a Windows driver may or may not be bigger, I suspect that the overall code size of such three platform specific drivers would actually be less than - the platform independent part of libhss1394, - plus OS X, Windows, and Linux backends in libhss1394, - plus the Thesycon driver which is required by libhss1394 on Windows. And then there is the need of applications (on whatever platform) to interface with libhss1394 in addition to native MIDI interfaces if these applications want to support other MIDI devices too. Granted, if nobody is there to implement the small kernelspace solution but somebody is there to implement the bigger userspace solution, then the latter is what gets done, for better or worse. > You could still port the HSS1394 library so that it sits on top of the > MIDI driver. (In other words, the Linux MIDI backend would be the > equivalent of the Windows and OS X FireWire backends.) The current interface between the platform-independent and platform-specific parts of libhss1394 resides on a level of abstraction similar to the raw1394 interface. It deals with 1394 node IDs, 1394 bus generation, 1394 block transactions and the likes. (But also with interfaces to the platforms' threading APIs etc.) So, either the Linux backend would have to be hooked into libhss1394 somewhere higher than that, or it would have to be written as a raw-I/O backend and to ignore Clemens' nice ALSA driver. -- Stefan Richter -=====-===-- -==- ----= http://arcgraph.de/sr/ ------------------------------------------------------------------------------ Live Security Virtual Conference Exclusive live event will cover all the ways today's security and threat landscape has changed and how IT managers can respond. Discussions will include endpoint security, mobile security and the latest in malware threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/ ^ permalink raw reply [flat|nested] 25+ messages in thread
end of thread, other threads:[~2012-11-12 14:26 UTC | newest]
Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <94aa86f3-5257-402a-a094-f58fccdeb846@email.android.com>
2012-05-30 4:51 ` Help requested: new HSS1394 MIDI back-end Clemens Ladisch
2012-05-30 5:12 ` [alsa-devel] " Sean M. Pappalardo - D.J. Pegasus
2012-05-30 7:18 ` Clemens Ladisch
2012-05-31 20:00 ` Clemens Ladisch
2012-06-09 6:54 ` Sean M. Pappalardo - D.J. Pegasus
2012-06-09 11:07 ` Clemens Ladisch
2012-06-09 12:41 ` Sean M. Pappalardo - D.J. Pegasus
2012-06-10 13:00 ` Clemens Ladisch
2012-10-24 11:49 ` Sean M. Pappalardo - D.J. Pegasus
2012-10-25 19:23 ` Clemens Ladisch
2012-10-25 20:26 ` Sean M. Pappalardo - D.J. Pegasus
2012-10-26 7:48 ` Clemens Ladisch
2012-10-31 10:00 ` Sean M. Pappalardo - D.J. Pegasus
2012-11-11 21:34 ` [git pull] " Clemens Ladisch
2012-11-09 6:41 ` Help requested: " Sean M. Pappalardo - D.J. Pegasus
2012-11-12 9:45 ` Takashi Iwai
2012-11-12 11:33 ` Clemens Ladisch
2012-11-12 11:40 ` Takashi Iwai
2012-11-12 11:45 ` [alsa-devel] " Clemens Ladisch
2012-11-12 14:26 ` Takashi Iwai
2012-06-09 8:42 ` Sean M. Pappalardo - D.J. Pegasus
2012-06-09 10:12 ` Sean M. Pappalardo - D.J. Pegasus
2012-05-31 22:04 ` Sean M. Pappalardo - D.J. Pegasus
2012-06-01 8:22 ` Clemens Ladisch
2012-06-01 13:40 ` [alsa-devel] " Stefan Richter
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.