linux/drivers/staging/line6/variax.c
<<
>>
Prefs
   1/*
   2 * Line6 Linux USB driver - 0.8.0
   3 *
   4 * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
   5 *
   6 *      This program is free software; you can redistribute it and/or
   7 *      modify it under the terms of the GNU General Public License as
   8 *      published by the Free Software Foundation, version 2.
   9 *
  10 */
  11
  12#include "driver.h"
  13
  14#include "audio.h"
  15#include "control.h"
  16#include "variax.h"
  17
  18
  19#define VARIAX_SYSEX_CODE 7
  20#define VARIAX_SYSEX_PARAM 0x3b
  21#define VARIAX_SYSEX_ACTIVATE 0x2a
  22#define VARIAX_MODEL_HEADER_LENGTH 7
  23#define VARIAX_MODEL_MESSAGE_LENGTH 199
  24#define VARIAX_OFFSET_ACTIVATE 7
  25
  26
  27static const char variax_activate[] = {
  28        0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01,
  29        0xf7
  30};
  31static const char variax_request_bank[] = {
  32        0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6d, 0xf7
  33};
  34static const char variax_request_model1[] = {
  35        0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x3c, 0x00,
  36        0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x05, 0x03,
  37        0x00, 0x00, 0x00, 0xf7
  38};
  39static const char variax_request_model2[] = {
  40        0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x3c, 0x00,
  41        0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x03,
  42        0x00, 0x00, 0x00, 0xf7
  43};
  44
  45
  46/*
  47        Decode data transmitted by workbench.
  48*/
  49static void variax_decode(const unsigned char *raw_data, unsigned char *data,
  50                          int raw_size)
  51{
  52        for (; raw_size > 0; raw_size -= 6) {
  53                data[2] = raw_data[0] | (raw_data[1] << 4);
  54                data[1] = raw_data[2] | (raw_data[3] << 4);
  55                data[0] = raw_data[4] | (raw_data[5] << 4);
  56                raw_data += 6;
  57                data += 3;
  58        }
  59}
  60
  61static void variax_activate_timeout(unsigned long arg)
  62{
  63        struct usb_line6_variax *variax = (struct usb_line6_variax *)arg;
  64        variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = 1;
  65        line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
  66                                     sizeof(variax_activate));
  67}
  68
  69/*
  70        Send an asynchronous activation request after a given interval.
  71*/
  72static void variax_activate_delayed(struct usb_line6_variax *variax,
  73                                    int seconds)
  74{
  75        variax->activate_timer.expires = jiffies + seconds * HZ;
  76        variax->activate_timer.function = variax_activate_timeout;
  77        variax->activate_timer.data = (unsigned long)variax;
  78        add_timer(&variax->activate_timer);
  79}
  80
  81static void variax_startup_timeout(unsigned long arg)
  82{
  83        struct usb_line6_variax *variax = (struct usb_line6_variax *)arg;
  84
  85        if (variax->dumpreq.ok)
  86                return;
  87
  88        line6_dump_request_async(&variax->dumpreq, &variax->line6, 0);
  89        line6_startup_delayed(&variax->dumpreq, 1, variax_startup_timeout,
  90                              variax);
  91}
  92
  93/*
  94        Process a completely received message.
  95*/
  96void variax_process_message(struct usb_line6_variax *variax)
  97{
  98        const unsigned char *buf = variax->line6.buffer_message;
  99
 100        switch (buf[0]) {
 101        case LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST:
 102                switch (buf[1]) {
 103                case VARIAXMIDI_volume:
 104                        variax->volume = buf[2];
 105                        break;
 106
 107                case VARIAXMIDI_tone:
 108                        variax->tone = buf[2];
 109                }
 110
 111                break;
 112
 113        case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_DEVICE:
 114        case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST:
 115                variax->model = buf[1];
 116                line6_dump_request_async(&variax->dumpreq, &variax->line6, 0);
 117                break;
 118
 119        case LINE6_RESET:
 120                dev_info(variax->line6.ifcdev, "VARIAX reset\n");
 121                variax_activate_delayed(variax, VARIAX_ACTIVATE_DELAY);
 122                break;
 123
 124        case LINE6_SYSEX_BEGIN:
 125                if (memcmp(buf + 1, variax_request_model1 + 1,
 126                           VARIAX_MODEL_HEADER_LENGTH - 1) == 0) {
 127                        if (variax->line6.message_length ==
 128                            VARIAX_MODEL_MESSAGE_LENGTH) {
 129                                switch (variax->dumpreq.in_progress) {
 130                                case VARIAX_DUMP_PASS1:
 131                                        variax_decode(buf + VARIAX_MODEL_HEADER_LENGTH, (unsigned char *)&variax->model_data,
 132                                                                                                (sizeof(variax->model_data.name) + sizeof(variax->model_data.control) / 2) * 2);
 133                                        line6_dump_request_async(&variax->dumpreq, &variax->line6, 1);
 134                                        line6_dump_started(&variax->dumpreq, VARIAX_DUMP_PASS2);
 135                                        break;
 136
 137                                case VARIAX_DUMP_PASS2:
 138                                        /* model name is transmitted twice, so skip it here: */
 139                                        variax_decode(buf + VARIAX_MODEL_HEADER_LENGTH,
 140                                                      (unsigned char *)&variax->model_data.control + sizeof(variax->model_data.control) / 2,
 141                                                      sizeof(variax->model_data.control) / 2 * 2);
 142                                        variax->dumpreq.ok = 1;
 143                                        line6_dump_request_async(&variax->dumpreq, &variax->line6, 2);
 144                                        line6_dump_started(&variax->dumpreq, VARIAX_DUMP_PASS3);
 145                                }
 146                        } else {
 147                                DEBUG_MESSAGES(dev_err(variax->line6.ifcdev, "illegal length %d of model data\n", variax->line6.message_length));
 148                                line6_dump_finished(&variax->dumpreq);
 149                        }
 150                } else if (memcmp(buf + 1, variax_request_bank + 1,
 151                                sizeof(variax_request_bank) - 2) == 0) {
 152                        memcpy(variax->bank,
 153                               buf + sizeof(variax_request_bank) - 1,
 154                               sizeof(variax->bank));
 155                        variax->dumpreq.ok = 1;
 156                        line6_dump_finished(&variax->dumpreq);
 157                }
 158
 159                break;
 160
 161        case LINE6_SYSEX_END:
 162                break;
 163
 164        default:
 165                DEBUG_MESSAGES(dev_err(variax->line6.ifcdev, "Variax: unknown message %02X\n", buf[0]));
 166        }
 167}
 168
 169/*
 170        "read" request on "volume" special file.
 171*/
 172static ssize_t variax_get_volume(struct device *dev,
 173                                 struct device_attribute *attr, char *buf)
 174{
 175        struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
 176        return sprintf(buf, "%d\n", variax->volume);
 177}
 178
 179/*
 180        "write" request on "volume" special file.
 181*/
 182static ssize_t variax_set_volume(struct device *dev,
 183                                 struct device_attribute *attr,
 184                                 const char *buf, size_t count)
 185{
 186        struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
 187        int value = simple_strtoul(buf, NULL, 10);
 188
 189        if (line6_transmit_parameter(&variax->line6, VARIAXMIDI_volume,
 190                                     value) == 0)
 191                variax->volume = value;
 192
 193        return count;
 194}
 195
 196/*
 197        "read" request on "model" special file.
 198*/
 199static ssize_t variax_get_model(struct device *dev,
 200                                struct device_attribute *attr, char *buf)
 201{
 202        struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
 203        return sprintf(buf, "%d\n", variax->model);
 204}
 205
 206/*
 207        "write" request on "model" special file.
 208*/
 209static ssize_t variax_set_model(struct device *dev,
 210                                struct device_attribute *attr,
 211                                const char *buf, size_t count)
 212{
 213        struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
 214        int value = simple_strtoul(buf, NULL, 10);
 215
 216        if (line6_send_program(&variax->line6, value) == 0)
 217                variax->model = value;
 218
 219        return count;
 220}
 221
 222/*
 223        "read" request on "active" special file.
 224*/
 225static ssize_t variax_get_active(struct device *dev,
 226                                 struct device_attribute *attr, char *buf)
 227{
 228        struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
 229        return sprintf(buf, "%d\n", variax->buffer_activate[VARIAX_OFFSET_ACTIVATE]);
 230}
 231
 232/*
 233        "write" request on "active" special file.
 234*/
 235static ssize_t variax_set_active(struct device *dev,
 236                                 struct device_attribute *attr,
 237                                 const char *buf, size_t count)
 238{
 239        struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
 240        int value = simple_strtoul(buf, NULL, 10) ? 1 : 0;
 241        variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = value;
 242        line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
 243                                     sizeof(variax_activate));
 244        return count;
 245}
 246
 247/*
 248        "read" request on "tone" special file.
 249*/
 250static ssize_t variax_get_tone(struct device *dev,
 251                               struct device_attribute *attr, char *buf)
 252{
 253        struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
 254        return sprintf(buf, "%d\n", variax->tone);
 255}
 256
 257/*
 258        "write" request on "tone" special file.
 259*/
 260static ssize_t variax_set_tone(struct device *dev,
 261                               struct device_attribute *attr,
 262                               const char *buf, size_t count)
 263{
 264        struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
 265        int value = simple_strtoul(buf, NULL, 10);
 266
 267        if (line6_transmit_parameter(&variax->line6, VARIAXMIDI_tone,
 268                                     value) == 0)
 269                variax->tone = value;
 270
 271        return count;
 272}
 273
 274static ssize_t get_string(char *buf, const char *data, int length)
 275{
 276        int i;
 277        memcpy(buf, data, length);
 278
 279        for (i = length; i--;) {
 280                char c = buf[i];
 281
 282                if ((c != 0) && (c != ' '))
 283                        break;
 284        }
 285
 286        buf[i + 1] = '\n';
 287        return i + 2;
 288}
 289
 290/*
 291        "read" request on "name" special file.
 292*/
 293static ssize_t variax_get_name(struct device *dev,
 294                               struct device_attribute *attr, char *buf)
 295{
 296        struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
 297        line6_wait_dump(&variax->dumpreq, 0);
 298        return get_string(buf, variax->model_data.name,
 299                          sizeof(variax->model_data.name));
 300}
 301
 302/*
 303        "read" request on "bank" special file.
 304*/
 305static ssize_t variax_get_bank(struct device *dev,
 306                               struct device_attribute *attr, char *buf)
 307{
 308        struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
 309        line6_wait_dump(&variax->dumpreq, 0);
 310        return get_string(buf, variax->bank, sizeof(variax->bank));
 311}
 312
 313/*
 314        "read" request on "dump" special file.
 315*/
 316static ssize_t variax_get_dump(struct device *dev,
 317                               struct device_attribute *attr, char *buf)
 318{
 319        struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
 320        int retval;
 321        retval = line6_wait_dump(&variax->dumpreq, 0);
 322        if (retval < 0)
 323                return retval;
 324        memcpy(buf, &variax->model_data.control,
 325               sizeof(variax->model_data.control));
 326        return sizeof(variax->model_data.control);
 327}
 328
 329#if CREATE_RAW_FILE
 330
 331/*
 332        "write" request on "raw" special file.
 333*/
 334static ssize_t variax_set_raw2(struct device *dev,
 335                               struct device_attribute *attr,
 336                               const char *buf, size_t count)
 337{
 338        struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
 339        int size;
 340        int i;
 341        char *sysex;
 342
 343        count -= count % 3;
 344        size = count * 2;
 345        sysex = variax_alloc_sysex_buffer(variax, VARIAX_SYSEX_PARAM, size);
 346
 347        if (!sysex)
 348                return 0;
 349
 350        for (i = 0; i < count; i += 3) {
 351                const unsigned char *p1 = buf + i;
 352                char *p2 = sysex + SYSEX_DATA_OFS + i * 2;
 353                p2[0] = p1[2] & 0x0f;
 354                p2[1] = p1[2] >> 4;
 355                p2[2] = p1[1] & 0x0f;
 356                p2[3] = p1[1] >> 4;
 357                p2[4] = p1[0] & 0x0f;
 358                p2[5] = p1[0] >> 4;
 359        }
 360
 361        line6_send_sysex_message(&variax->line6, sysex, size);
 362        kfree(sysex);
 363        return count;
 364}
 365
 366#endif
 367
 368/* Variax workbench special files: */
 369static DEVICE_ATTR(model, S_IWUGO | S_IRUGO, variax_get_model, variax_set_model);
 370static DEVICE_ATTR(volume, S_IWUGO | S_IRUGO, variax_get_volume, variax_set_volume);
 371static DEVICE_ATTR(tone, S_IWUGO | S_IRUGO, variax_get_tone, variax_set_tone);
 372static DEVICE_ATTR(name, S_IRUGO, variax_get_name, line6_nop_write);
 373static DEVICE_ATTR(bank, S_IRUGO, variax_get_bank, line6_nop_write);
 374static DEVICE_ATTR(dump, S_IRUGO, variax_get_dump, line6_nop_write);
 375static DEVICE_ATTR(active, S_IWUGO | S_IRUGO, variax_get_active, variax_set_active);
 376
 377#if CREATE_RAW_FILE
 378static DEVICE_ATTR(raw, S_IWUGO, line6_nop_read, line6_set_raw);
 379static DEVICE_ATTR(raw2, S_IWUGO, line6_nop_read, variax_set_raw2);
 380#endif
 381
 382
 383/*
 384        Variax destructor.
 385*/
 386static void variax_destruct(struct usb_interface *interface)
 387{
 388        struct usb_line6_variax *variax = usb_get_intfdata(interface);
 389        struct usb_line6 *line6;
 390
 391        if (variax == NULL)
 392                return;
 393        line6 = &variax->line6;
 394        if (line6 == NULL)
 395                return;
 396        line6_cleanup_audio(line6);
 397
 398        /* free dump request data: */
 399        line6_dumpreq_destructbuf(&variax->dumpreq, 2);
 400        line6_dumpreq_destructbuf(&variax->dumpreq, 1);
 401        line6_dumpreq_destruct(&variax->dumpreq);
 402
 403        kfree(variax->buffer_activate);
 404        del_timer_sync(&variax->activate_timer);
 405}
 406
 407/*
 408        Create sysfs entries.
 409*/
 410static int variax_create_files2(struct device *dev)
 411{
 412        int err;
 413        CHECK_RETURN(device_create_file(dev, &dev_attr_model));
 414        CHECK_RETURN(device_create_file(dev, &dev_attr_volume));
 415        CHECK_RETURN(device_create_file(dev, &dev_attr_tone));
 416        CHECK_RETURN(device_create_file(dev, &dev_attr_name));
 417        CHECK_RETURN(device_create_file(dev, &dev_attr_bank));
 418        CHECK_RETURN(device_create_file(dev, &dev_attr_dump));
 419        CHECK_RETURN(device_create_file(dev, &dev_attr_active));
 420#if CREATE_RAW_FILE
 421        CHECK_RETURN(device_create_file(dev, &dev_attr_raw));
 422        CHECK_RETURN(device_create_file(dev, &dev_attr_raw2));
 423#endif
 424        return 0;
 425}
 426
 427/*
 428         Init workbench device.
 429*/
 430int variax_init(struct usb_interface *interface,
 431                struct usb_line6_variax *variax)
 432{
 433        int err;
 434
 435        if ((interface == NULL) || (variax == NULL))
 436                return -ENODEV;
 437
 438        /* initialize USB buffers: */
 439        err = line6_dumpreq_init(&variax->dumpreq, variax_request_model1,
 440                                 sizeof(variax_request_model1));
 441
 442        if (err < 0) {
 443                dev_err(&interface->dev, "Out of memory\n");
 444                variax_destruct(interface);
 445                return err;
 446        }
 447
 448        err = line6_dumpreq_initbuf(&variax->dumpreq, variax_request_model2,
 449                                    sizeof(variax_request_model2), 1);
 450
 451        if (err < 0) {
 452                dev_err(&interface->dev, "Out of memory\n");
 453                variax_destruct(interface);
 454                return err;
 455        }
 456
 457        err = line6_dumpreq_initbuf(&variax->dumpreq, variax_request_bank,
 458                                    sizeof(variax_request_bank), 2);
 459
 460        if (err < 0) {
 461                dev_err(&interface->dev, "Out of memory\n");
 462                variax_destruct(interface);
 463                return err;
 464        }
 465
 466        variax->buffer_activate = kmalloc(sizeof(variax_activate), GFP_KERNEL);
 467
 468        if (variax->buffer_activate == NULL) {
 469                dev_err(&interface->dev, "Out of memory\n");
 470                variax_destruct(interface);
 471                return -ENOMEM;
 472        }
 473
 474        memcpy(variax->buffer_activate, variax_activate,
 475               sizeof(variax_activate));
 476        init_timer(&variax->activate_timer);
 477
 478        /* create sysfs entries: */
 479        err = variax_create_files(0, 0, &interface->dev);
 480        if (err < 0) {
 481                variax_destruct(interface);
 482                return err;
 483        }
 484
 485        err = variax_create_files2(&interface->dev);
 486        if (err < 0) {
 487                variax_destruct(interface);
 488                return err;
 489        }
 490
 491        /* initialize audio system: */
 492        err = line6_init_audio(&variax->line6);
 493        if (err < 0) {
 494                variax_destruct(interface);
 495                return err;
 496        }
 497
 498        /* initialize MIDI subsystem: */
 499        err = line6_init_midi(&variax->line6);
 500        if (err < 0) {
 501                variax_destruct(interface);
 502                return err;
 503        }
 504
 505        /* register audio system: */
 506        err = line6_register_audio(&variax->line6);
 507        if (err < 0) {
 508                variax_destruct(interface);
 509                return err;
 510        }
 511
 512        variax_activate_delayed(variax, VARIAX_ACTIVATE_DELAY);
 513        line6_startup_delayed(&variax->dumpreq, VARIAX_STARTUP_DELAY,
 514                              variax_startup_timeout, variax);
 515        return 0;
 516}
 517
 518/*
 519        Workbench device disconnected.
 520*/
 521void variax_disconnect(struct usb_interface *interface)
 522{
 523        struct device *dev;
 524
 525        if (interface == NULL)
 526                return;
 527        dev = &interface->dev;
 528
 529        if (dev != NULL) {
 530                /* remove sysfs entries: */
 531                variax_remove_files(0, 0, dev);
 532                device_remove_file(dev, &dev_attr_model);
 533                device_remove_file(dev, &dev_attr_volume);
 534                device_remove_file(dev, &dev_attr_tone);
 535                device_remove_file(dev, &dev_attr_name);
 536                device_remove_file(dev, &dev_attr_bank);
 537                device_remove_file(dev, &dev_attr_dump);
 538                device_remove_file(dev, &dev_attr_active);
 539#if CREATE_RAW_FILE
 540                device_remove_file(dev, &dev_attr_raw);
 541                device_remove_file(dev, &dev_attr_raw2);
 542#endif
 543        }
 544
 545        variax_destruct(interface);
 546}
 547