linux/sound/firewire/scs1x.c
<<
>>
Prefs
   1/*
   2 * Stanton Control System 1 MIDI driver
   3 *
   4 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
   5 * Licensed under the terms of the GNU General Public License, version 2.
   6 */
   7
   8#include <linux/device.h>
   9#include <linux/firewire.h>
  10#include <linux/firewire-constants.h>
  11#include <linux/interrupt.h>
  12#include <linux/module.h>
  13#include <linux/mod_devicetable.h>
  14#include <linux/slab.h>
  15#include <linux/string.h>
  16#include <linux/wait.h>
  17#include <sound/core.h>
  18#include <sound/initval.h>
  19#include <sound/rawmidi.h>
  20#include "lib.h"
  21
  22#define OUI_STANTON     0x001260
  23#define MODEL_SCS_1M    0x001000
  24#define MODEL_SCS_1D    0x002000
  25
  26#define HSS1394_ADDRESS                 0xc007dedadadaULL
  27#define HSS1394_MAX_PACKET_SIZE         64
  28
  29#define HSS1394_TAG_USER_DATA           0x00
  30#define HSS1394_TAG_CHANGE_ADDRESS      0xf1
  31
  32struct scs {
  33        struct snd_card *card;
  34        struct fw_unit *unit;
  35        struct fw_address_handler hss_handler;
  36        struct fw_transaction transaction;
  37        bool transaction_running;
  38        bool output_idle;
  39        u8 output_status;
  40        u8 output_bytes;
  41        bool output_escaped;
  42        bool output_escape_high_nibble;
  43        u8 input_escape_count;
  44        struct snd_rawmidi_substream *output;
  45        struct snd_rawmidi_substream *input;
  46        struct tasklet_struct tasklet;
  47        wait_queue_head_t idle_wait;
  48        u8 *buffer;
  49};
  50
  51static const u8 sysex_escape_prefix[] = {
  52        0xf0,                   /* SysEx begin */
  53        0x00, 0x01, 0x60,       /* Stanton DJ */
  54        0x48, 0x53, 0x53,       /* "HSS" */
  55};
  56
  57static int scs_output_open(struct snd_rawmidi_substream *stream)
  58{
  59        struct scs *scs = stream->rmidi->private_data;
  60
  61        scs->output_status = 0;
  62        scs->output_bytes = 1;
  63        scs->output_escaped = false;
  64
  65        return 0;
  66}
  67
  68static int scs_output_close(struct snd_rawmidi_substream *stream)
  69{
  70        return 0;
  71}
  72
  73static void scs_output_trigger(struct snd_rawmidi_substream *stream, int up)
  74{
  75        struct scs *scs = stream->rmidi->private_data;
  76
  77        ACCESS_ONCE(scs->output) = up ? stream : NULL;
  78        if (up) {
  79                scs->output_idle = false;
  80                tasklet_schedule(&scs->tasklet);
  81        }
  82}
  83
  84static void scs_write_callback(struct fw_card *card, int rcode,
  85                               void *data, size_t length, void *callback_data)
  86{
  87        struct scs *scs = callback_data;
  88
  89        if (rcode == RCODE_GENERATION) {
  90                /* TODO: retry this packet */
  91        }
  92
  93        scs->transaction_running = false;
  94        tasklet_schedule(&scs->tasklet);
  95}
  96
  97static bool is_valid_running_status(u8 status)
  98{
  99        return status >= 0x80 && status <= 0xef;
 100}
 101
 102static bool is_one_byte_cmd(u8 status)
 103{
 104        return status == 0xf6 ||
 105               status >= 0xf8;
 106}
 107
 108static bool is_two_bytes_cmd(u8 status)
 109{
 110        return (status >= 0xc0 && status <= 0xdf) ||
 111               status == 0xf1 ||
 112               status == 0xf3;
 113}
 114
 115static bool is_three_bytes_cmd(u8 status)
 116{
 117        return (status >= 0x80 && status <= 0xbf) ||
 118               (status >= 0xe0 && status <= 0xef) ||
 119               status == 0xf2;
 120}
 121
 122static bool is_invalid_cmd(u8 status)
 123{
 124        return status == 0xf4 ||
 125               status == 0xf5 ||
 126               status == 0xf9 ||
 127               status == 0xfd;
 128}
 129
 130static void scs_output_tasklet(unsigned long data)
 131{
 132        struct scs *scs = (void *)data;
 133        struct snd_rawmidi_substream *stream;
 134        unsigned int i;
 135        u8 byte;
 136        struct fw_device *dev;
 137        int generation;
 138
 139        if (scs->transaction_running)
 140                return;
 141
 142        stream = ACCESS_ONCE(scs->output);
 143        if (!stream) {
 144                scs->output_idle = true;
 145                wake_up(&scs->idle_wait);
 146                return;
 147        }
 148
 149        i = scs->output_bytes;
 150        for (;;) {
 151                if (snd_rawmidi_transmit(stream, &byte, 1) != 1) {
 152                        scs->output_bytes = i;
 153                        scs->output_idle = true;
 154                        wake_up(&scs->idle_wait);
 155                        return;
 156                }
 157                /*
 158                 * Convert from real MIDI to what I think the device expects (no
 159                 * running status, one command per packet, unescaped SysExs).
 160                 */
 161                if (scs->output_escaped && byte < 0x80) {
 162                        if (scs->output_escape_high_nibble) {
 163                                if (i < HSS1394_MAX_PACKET_SIZE) {
 164                                        scs->buffer[i] = byte << 4;
 165                                        scs->output_escape_high_nibble = false;
 166                                }
 167                        } else {
 168                                scs->buffer[i++] |= byte & 0x0f;
 169                                scs->output_escape_high_nibble = true;
 170                        }
 171                } else if (byte < 0x80) {
 172                        if (i == 1) {
 173                                if (!is_valid_running_status(scs->output_status))
 174                                        continue;
 175                                scs->buffer[0] = HSS1394_TAG_USER_DATA;
 176                                scs->buffer[i++] = scs->output_status;
 177                        }
 178                        scs->buffer[i++] = byte;
 179                        if ((i == 3 && is_two_bytes_cmd(scs->output_status)) ||
 180                            (i == 4 && is_three_bytes_cmd(scs->output_status)))
 181                                break;
 182                        if (i == 1 + ARRAY_SIZE(sysex_escape_prefix) &&
 183                            !memcmp(scs->buffer + 1, sysex_escape_prefix,
 184                                    ARRAY_SIZE(sysex_escape_prefix))) {
 185                                scs->output_escaped = true;
 186                                scs->output_escape_high_nibble = true;
 187                                i = 0;
 188                        }
 189                        if (i >= HSS1394_MAX_PACKET_SIZE)
 190                                i = 1;
 191                } else if (byte == 0xf7) {
 192                        if (scs->output_escaped) {
 193                                if (i >= 1 && scs->output_escape_high_nibble &&
 194                                    scs->buffer[0] != HSS1394_TAG_CHANGE_ADDRESS)
 195                                        break;
 196                        } else {
 197                                if (i > 1 && scs->output_status == 0xf0) {
 198                                        scs->buffer[i++] = 0xf7;
 199                                        break;
 200                                }
 201                        }
 202                        i = 1;
 203                        scs->output_escaped = false;
 204                } else if (!is_invalid_cmd(byte) &&
 205                           byte < 0xf8) {
 206                        i = 1;
 207                        scs->buffer[0] = HSS1394_TAG_USER_DATA;
 208                        scs->buffer[i++] = byte;
 209                        scs->output_status = byte;
 210                        scs->output_escaped = false;
 211                        if (is_one_byte_cmd(byte))
 212                                break;
 213                }
 214        }
 215        scs->output_bytes = 1;
 216        scs->output_escaped = false;
 217
 218        scs->transaction_running = true;
 219        dev = fw_parent_device(scs->unit);
 220        generation = dev->generation;
 221        smp_rmb(); /* node_id vs. generation */
 222        fw_send_request(dev->card, &scs->transaction, TCODE_WRITE_BLOCK_REQUEST,
 223                        dev->node_id, generation, dev->max_speed,
 224                        HSS1394_ADDRESS, scs->buffer, i,
 225                        scs_write_callback, scs);
 226}
 227
 228static void scs_output_drain(struct snd_rawmidi_substream *stream)
 229{
 230        struct scs *scs = stream->rmidi->private_data;
 231
 232        wait_event(scs->idle_wait, scs->output_idle);
 233}
 234
 235static struct snd_rawmidi_ops output_ops = {
 236        .open    = scs_output_open,
 237        .close   = scs_output_close,
 238        .trigger = scs_output_trigger,
 239        .drain   = scs_output_drain,
 240};
 241
 242static int scs_input_open(struct snd_rawmidi_substream *stream)
 243{
 244        struct scs *scs = stream->rmidi->private_data;
 245
 246        scs->input_escape_count = 0;
 247
 248        return 0;
 249}
 250
 251static int scs_input_close(struct snd_rawmidi_substream *stream)
 252{
 253        return 0;
 254}
 255
 256static void scs_input_trigger(struct snd_rawmidi_substream *stream, int up)
 257{
 258        struct scs *scs = stream->rmidi->private_data;
 259
 260        ACCESS_ONCE(scs->input) = up ? stream : NULL;
 261}
 262
 263static void scs_input_escaped_byte(struct snd_rawmidi_substream *stream,
 264                                   u8 byte)
 265{
 266        u8 nibbles[2];
 267
 268        nibbles[0] = byte >> 4;
 269        nibbles[1] = byte & 0x0f;
 270        snd_rawmidi_receive(stream, nibbles, 2);
 271}
 272
 273static void scs_input_midi_byte(struct scs *scs,
 274                                struct snd_rawmidi_substream *stream,
 275                                u8 byte)
 276{
 277        if (scs->input_escape_count > 0) {
 278                scs_input_escaped_byte(stream, byte);
 279                scs->input_escape_count--;
 280                if (scs->input_escape_count == 0)
 281                        snd_rawmidi_receive(stream, (const u8[]) { 0xf7 }, 1);
 282        } else if (byte == 0xf9) {
 283                snd_rawmidi_receive(stream, sysex_escape_prefix,
 284                                    ARRAY_SIZE(sysex_escape_prefix));
 285                scs_input_escaped_byte(stream, 0x00);
 286                scs_input_escaped_byte(stream, 0xf9);
 287                scs->input_escape_count = 3;
 288        } else {
 289                snd_rawmidi_receive(stream, &byte, 1);
 290        }
 291}
 292
 293static void scs_input_packet(struct scs *scs,
 294                             struct snd_rawmidi_substream *stream,
 295                             const u8 *data, unsigned int bytes)
 296{
 297        unsigned int i;
 298
 299        if (data[0] == HSS1394_TAG_USER_DATA) {
 300                for (i = 1; i < bytes; ++i)
 301                        scs_input_midi_byte(scs, stream, data[i]);
 302        } else {
 303                snd_rawmidi_receive(stream, sysex_escape_prefix,
 304                                    ARRAY_SIZE(sysex_escape_prefix));
 305                for (i = 0; i < bytes; ++i)
 306                        scs_input_escaped_byte(stream, data[i]);
 307                snd_rawmidi_receive(stream, (const u8[]) { 0xf7 }, 1);
 308        }
 309}
 310
 311static struct snd_rawmidi_ops input_ops = {
 312        .open    = scs_input_open,
 313        .close   = scs_input_close,
 314        .trigger = scs_input_trigger,
 315};
 316
 317static int scs_create_midi(struct scs *scs)
 318{
 319        struct snd_rawmidi *rmidi;
 320        int err;
 321
 322        err = snd_rawmidi_new(scs->card, "SCS.1x", 0, 1, 1, &rmidi);
 323        if (err < 0)
 324                return err;
 325        snprintf(rmidi->name, sizeof(rmidi->name),
 326                 "%s MIDI", scs->card->shortname);
 327        rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
 328                            SNDRV_RAWMIDI_INFO_INPUT |
 329                            SNDRV_RAWMIDI_INFO_DUPLEX;
 330        rmidi->private_data = scs;
 331        snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &output_ops);
 332        snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &input_ops);
 333
 334        return 0;
 335}
 336
 337static void handle_hss(struct fw_card *card, struct fw_request *request,
 338                       int tcode, int destination, int source, int generation,
 339                       unsigned long long offset, void *data, size_t length,
 340                       void *callback_data)
 341{
 342        struct scs *scs = callback_data;
 343        struct snd_rawmidi_substream *stream;
 344
 345        if (offset != scs->hss_handler.offset) {
 346                fw_send_response(card, request, RCODE_ADDRESS_ERROR);
 347                return;
 348        }
 349        if (tcode != TCODE_WRITE_QUADLET_REQUEST &&
 350            tcode != TCODE_WRITE_BLOCK_REQUEST) {
 351                fw_send_response(card, request, RCODE_TYPE_ERROR);
 352                return;
 353        }
 354
 355        if (length >= 1) {
 356                stream = ACCESS_ONCE(scs->input);
 357                if (stream)
 358                        scs_input_packet(scs, stream, data, length);
 359        }
 360
 361        fw_send_response(card, request, RCODE_COMPLETE);
 362}
 363
 364static int scs_init_hss_address(struct scs *scs)
 365{
 366        __be64 data;
 367        int err;
 368
 369        data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) |
 370                           scs->hss_handler.offset);
 371        err = snd_fw_transaction(scs->unit, TCODE_WRITE_BLOCK_REQUEST,
 372                                 HSS1394_ADDRESS, &data, 8);
 373        if (err < 0)
 374                dev_err(&scs->unit->device, "HSS1394 communication failed\n");
 375
 376        return err;
 377}
 378
 379static void scs_card_free(struct snd_card *card)
 380{
 381        struct scs *scs = card->private_data;
 382
 383        fw_core_remove_address_handler(&scs->hss_handler);
 384        kfree(scs->buffer);
 385}
 386
 387static int scs_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
 388{
 389        struct fw_device *fw_dev = fw_parent_device(unit);
 390        struct snd_card *card;
 391        struct scs *scs;
 392        int err;
 393
 394        err = snd_card_create(-16, NULL, THIS_MODULE, sizeof(*scs), &card);
 395        if (err < 0)
 396                return err;
 397        snd_card_set_dev(card, &unit->device);
 398
 399        scs = card->private_data;
 400        scs->card = card;
 401        scs->unit = unit;
 402        tasklet_init(&scs->tasklet, scs_output_tasklet, (unsigned long)scs);
 403        init_waitqueue_head(&scs->idle_wait);
 404        scs->output_idle = true;
 405
 406        scs->buffer = kmalloc(HSS1394_MAX_PACKET_SIZE, GFP_KERNEL);
 407        if (!scs->buffer) {
 408                err = -ENOMEM;
 409                goto err_card;
 410        }
 411
 412        scs->hss_handler.length = HSS1394_MAX_PACKET_SIZE;
 413        scs->hss_handler.address_callback = handle_hss;
 414        scs->hss_handler.callback_data = scs;
 415        err = fw_core_add_address_handler(&scs->hss_handler,
 416                                          &fw_high_memory_region);
 417        if (err < 0)
 418                goto err_buffer;
 419
 420        card->private_free = scs_card_free;
 421
 422        strcpy(card->driver, "SCS.1x");
 423        strcpy(card->shortname, "SCS.1x");
 424        fw_csr_string(unit->directory, CSR_MODEL,
 425                      card->shortname, sizeof(card->shortname));
 426        snprintf(card->longname, sizeof(card->longname),
 427                 "Stanton DJ %s (GUID %08x%08x) at %s, S%d",
 428                 card->shortname, fw_dev->config_rom[3], fw_dev->config_rom[4],
 429                 dev_name(&unit->device), 100 << fw_dev->max_speed);
 430        strcpy(card->mixername, card->shortname);
 431
 432        err = scs_init_hss_address(scs);
 433        if (err < 0)
 434                goto err_card;
 435
 436        err = scs_create_midi(scs);
 437        if (err < 0)
 438                goto err_card;
 439
 440        err = snd_card_register(card);
 441        if (err < 0)
 442                goto err_card;
 443
 444        dev_set_drvdata(&unit->device, scs);
 445
 446        return 0;
 447
 448err_buffer:
 449        kfree(scs->buffer);
 450err_card:
 451        snd_card_free(card);
 452        return err;
 453}
 454
 455static void scs_update(struct fw_unit *unit)
 456{
 457        struct scs *scs = dev_get_drvdata(&unit->device);
 458        __be64 data;
 459
 460        data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) |
 461                           scs->hss_handler.offset);
 462        snd_fw_transaction(scs->unit, TCODE_WRITE_BLOCK_REQUEST,
 463                           HSS1394_ADDRESS, &data, 8);
 464}
 465
 466static void scs_remove(struct fw_unit *unit)
 467{
 468        struct scs *scs = dev_get_drvdata(&unit->device);
 469
 470        snd_card_disconnect(scs->card);
 471
 472        ACCESS_ONCE(scs->output) = NULL;
 473        ACCESS_ONCE(scs->input) = NULL;
 474
 475        wait_event(scs->idle_wait, scs->output_idle);
 476
 477        tasklet_kill(&scs->tasklet);
 478
 479        snd_card_free_when_closed(scs->card);
 480}
 481
 482static const struct ieee1394_device_id scs_id_table[] = {
 483        {
 484                .match_flags = IEEE1394_MATCH_VENDOR_ID |
 485                               IEEE1394_MATCH_MODEL_ID,
 486                .vendor_id   = OUI_STANTON,
 487                .model_id    = MODEL_SCS_1M,
 488        },
 489        {
 490                .match_flags = IEEE1394_MATCH_VENDOR_ID |
 491                               IEEE1394_MATCH_MODEL_ID,
 492                .vendor_id   = OUI_STANTON,
 493                .model_id    = MODEL_SCS_1D,
 494        },
 495        {}
 496};
 497MODULE_DEVICE_TABLE(ieee1394, scs_id_table);
 498
 499MODULE_DESCRIPTION("SCS.1x MIDI driver");
 500MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 501MODULE_LICENSE("GPL v2");
 502
 503static struct fw_driver scs_driver = {
 504        .driver = {
 505                .owner  = THIS_MODULE,
 506                .name   = KBUILD_MODNAME,
 507                .bus    = &fw_bus_type,
 508        },
 509        .probe    = scs_probe,
 510        .update   = scs_update,
 511        .remove   = scs_remove,
 512        .id_table = scs_id_table,
 513};
 514
 515static int __init alsa_scs1x_init(void)
 516{
 517        return driver_register(&scs_driver.driver);
 518}
 519
 520static void __exit alsa_scs1x_exit(void)
 521{
 522        driver_unregister(&scs_driver.driver);
 523}
 524
 525module_init(alsa_scs1x_init);
 526module_exit(alsa_scs1x_exit);
 527