linux/sound/usb/6fire/firmware.c
<<
>>
Prefs
   1/*
   2 * Linux driver for TerraTec DMX 6Fire USB
   3 *
   4 * Firmware loader
   5 *
   6 * Author:      Torsten Schenk <torsten.schenk@zoho.com>
   7 * Created:     Jan 01, 2011
   8 * Copyright:   (C) Torsten Schenk
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License as published by
  12 * the Free Software Foundation; either version 2 of the License, or
  13 * (at your option) any later version.
  14 */
  15
  16#include <linux/firmware.h>
  17#include <linux/module.h>
  18#include <linux/bitrev.h>
  19#include <linux/kernel.h>
  20
  21#include "firmware.h"
  22#include "chip.h"
  23
  24MODULE_FIRMWARE("6fire/dmx6firel2.ihx");
  25MODULE_FIRMWARE("6fire/dmx6fireap.ihx");
  26MODULE_FIRMWARE("6fire/dmx6firecf.bin");
  27
  28enum {
  29        FPGA_BUFSIZE = 512, FPGA_EP = 2
  30};
  31
  32/*
  33 * wMaxPacketSize of pcm endpoints.
  34 * keep synced with rates_in_packet_size and rates_out_packet_size in pcm.c
  35 * fpp: frames per isopacket
  36 *
  37 * CAUTION: keep sizeof <= buffer[] in usb6fire_fw_init
  38 */
  39static const u8 ep_w_max_packet_size[] = {
  40        0xe4, 0x00, 0xe4, 0x00, /* alt 1: 228 EP2 and EP6 (7 fpp) */
  41        0xa4, 0x01, 0xa4, 0x01, /* alt 2: 420 EP2 and EP6 (13 fpp)*/
  42        0x94, 0x01, 0x5c, 0x02  /* alt 3: 404 EP2 and 604 EP6 (25 fpp) */
  43};
  44
  45static const u8 known_fw_versions[][2] = {
  46        { 0x03, 0x01 }
  47};
  48
  49struct ihex_record {
  50        u16 address;
  51        u8 len;
  52        u8 data[256];
  53        char error; /* true if an error occurred parsing this record */
  54
  55        u8 max_len; /* maximum record length in whole ihex */
  56
  57        /* private */
  58        const char *txt_data;
  59        unsigned int txt_length;
  60        unsigned int txt_offset; /* current position in txt_data */
  61};
  62
  63static u8 usb6fire_fw_ihex_hex(const u8 *data, u8 *crc)
  64{
  65        u8 val = 0;
  66        int hval;
  67
  68        hval = hex_to_bin(data[0]);
  69        if (hval >= 0)
  70                val |= (hval << 4);
  71
  72        hval = hex_to_bin(data[1]);
  73        if (hval >= 0)
  74                val |= hval;
  75
  76        *crc += val;
  77        return val;
  78}
  79
  80/*
  81 * returns true if record is available, false otherwise.
  82 * iff an error occurred, false will be returned and record->error will be true.
  83 */
  84static bool usb6fire_fw_ihex_next_record(struct ihex_record *record)
  85{
  86        u8 crc = 0;
  87        u8 type;
  88        int i;
  89
  90        record->error = false;
  91
  92        /* find begin of record (marked by a colon) */
  93        while (record->txt_offset < record->txt_length
  94                        && record->txt_data[record->txt_offset] != ':')
  95                record->txt_offset++;
  96        if (record->txt_offset == record->txt_length)
  97                return false;
  98
  99        /* number of characters needed for len, addr and type entries */
 100        record->txt_offset++;
 101        if (record->txt_offset + 8 > record->txt_length) {
 102                record->error = true;
 103                return false;
 104        }
 105
 106        record->len = usb6fire_fw_ihex_hex(record->txt_data +
 107                        record->txt_offset, &crc);
 108        record->txt_offset += 2;
 109        record->address = usb6fire_fw_ihex_hex(record->txt_data +
 110                        record->txt_offset, &crc) << 8;
 111        record->txt_offset += 2;
 112        record->address |= usb6fire_fw_ihex_hex(record->txt_data +
 113                        record->txt_offset, &crc);
 114        record->txt_offset += 2;
 115        type = usb6fire_fw_ihex_hex(record->txt_data +
 116                        record->txt_offset, &crc);
 117        record->txt_offset += 2;
 118
 119        /* number of characters needed for data and crc entries */
 120        if (record->txt_offset + 2 * (record->len + 1) > record->txt_length) {
 121                record->error = true;
 122                return false;
 123        }
 124        for (i = 0; i < record->len; i++) {
 125                record->data[i] = usb6fire_fw_ihex_hex(record->txt_data
 126                                + record->txt_offset, &crc);
 127                record->txt_offset += 2;
 128        }
 129        usb6fire_fw_ihex_hex(record->txt_data + record->txt_offset, &crc);
 130        if (crc) {
 131                record->error = true;
 132                return false;
 133        }
 134
 135        if (type == 1 || !record->len) /* eof */
 136                return false;
 137        else if (type == 0)
 138                return true;
 139        else {
 140                record->error = true;
 141                return false;
 142        }
 143}
 144
 145static int usb6fire_fw_ihex_init(const struct firmware *fw,
 146                struct ihex_record *record)
 147{
 148        record->txt_data = fw->data;
 149        record->txt_length = fw->size;
 150        record->txt_offset = 0;
 151        record->max_len = 0;
 152        /* read all records, if loop ends, record->error indicates,
 153         * whether ihex is valid. */
 154        while (usb6fire_fw_ihex_next_record(record))
 155                record->max_len = max(record->len, record->max_len);
 156        if (record->error)
 157                return -EINVAL;
 158        record->txt_offset = 0;
 159        return 0;
 160}
 161
 162static int usb6fire_fw_ezusb_write(struct usb_device *device,
 163                int type, int value, char *data, int len)
 164{
 165        int ret;
 166
 167        ret = usb_control_msg(device, usb_sndctrlpipe(device, 0), type,
 168                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 169                        value, 0, data, len, HZ);
 170        if (ret < 0)
 171                return ret;
 172        else if (ret != len)
 173                return -EIO;
 174        return 0;
 175}
 176
 177static int usb6fire_fw_ezusb_read(struct usb_device *device,
 178                int type, int value, char *data, int len)
 179{
 180        int ret = usb_control_msg(device, usb_rcvctrlpipe(device, 0), type,
 181                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value,
 182                        0, data, len, HZ);
 183        if (ret < 0)
 184                return ret;
 185        else if (ret != len)
 186                return -EIO;
 187        return 0;
 188}
 189
 190static int usb6fire_fw_fpga_write(struct usb_device *device,
 191                char *data, int len)
 192{
 193        int actual_len;
 194        int ret;
 195
 196        ret = usb_bulk_msg(device, usb_sndbulkpipe(device, FPGA_EP), data, len,
 197                        &actual_len, HZ);
 198        if (ret < 0)
 199                return ret;
 200        else if (actual_len != len)
 201                return -EIO;
 202        return 0;
 203}
 204
 205static int usb6fire_fw_ezusb_upload(
 206                struct usb_interface *intf, const char *fwname,
 207                unsigned int postaddr, u8 *postdata, unsigned int postlen)
 208{
 209        int ret;
 210        u8 data;
 211        struct usb_device *device = interface_to_usbdev(intf);
 212        const struct firmware *fw = NULL;
 213        struct ihex_record *rec = kmalloc(sizeof(struct ihex_record),
 214                        GFP_KERNEL);
 215
 216        if (!rec)
 217                return -ENOMEM;
 218
 219        ret = request_firmware(&fw, fwname, &device->dev);
 220        if (ret < 0) {
 221                kfree(rec);
 222                snd_printk(KERN_ERR PREFIX "error requesting ezusb "
 223                                "firmware %s.\n", fwname);
 224                return ret;
 225        }
 226        ret = usb6fire_fw_ihex_init(fw, rec);
 227        if (ret < 0) {
 228                kfree(rec);
 229                release_firmware(fw);
 230                snd_printk(KERN_ERR PREFIX "error validating ezusb "
 231                                "firmware %s.\n", fwname);
 232                return ret;
 233        }
 234        /* upload firmware image */
 235        data = 0x01; /* stop ezusb cpu */
 236        ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1);
 237        if (ret < 0) {
 238                kfree(rec);
 239                release_firmware(fw);
 240                snd_printk(KERN_ERR PREFIX "unable to upload ezusb "
 241                                "firmware %s: begin message.\n", fwname);
 242                return ret;
 243        }
 244
 245        while (usb6fire_fw_ihex_next_record(rec)) { /* write firmware */
 246                ret = usb6fire_fw_ezusb_write(device, 0xa0, rec->address,
 247                                rec->data, rec->len);
 248                if (ret < 0) {
 249                        kfree(rec);
 250                        release_firmware(fw);
 251                        snd_printk(KERN_ERR PREFIX "unable to upload ezusb "
 252                                        "firmware %s: data urb.\n", fwname);
 253                        return ret;
 254                }
 255        }
 256
 257        release_firmware(fw);
 258        kfree(rec);
 259        if (postdata) { /* write data after firmware has been uploaded */
 260                ret = usb6fire_fw_ezusb_write(device, 0xa0, postaddr,
 261                                postdata, postlen);
 262                if (ret < 0) {
 263                        snd_printk(KERN_ERR PREFIX "unable to upload ezusb "
 264                                        "firmware %s: post urb.\n", fwname);
 265                        return ret;
 266                }
 267        }
 268
 269        data = 0x00; /* resume ezusb cpu */
 270        ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1);
 271        if (ret < 0) {
 272                snd_printk(KERN_ERR PREFIX "unable to upload ezusb "
 273                                "firmware %s: end message.\n", fwname);
 274                return ret;
 275        }
 276        return 0;
 277}
 278
 279static int usb6fire_fw_fpga_upload(
 280                struct usb_interface *intf, const char *fwname)
 281{
 282        int ret;
 283        int i;
 284        struct usb_device *device = interface_to_usbdev(intf);
 285        u8 *buffer = kmalloc(FPGA_BUFSIZE, GFP_KERNEL);
 286        const char *c;
 287        const char *end;
 288        const struct firmware *fw;
 289
 290        if (!buffer)
 291                return -ENOMEM;
 292
 293        ret = request_firmware(&fw, fwname, &device->dev);
 294        if (ret < 0) {
 295                snd_printk(KERN_ERR PREFIX "unable to get fpga firmware %s.\n",
 296                                fwname);
 297                kfree(buffer);
 298                return -EIO;
 299        }
 300
 301        c = fw->data;
 302        end = fw->data + fw->size;
 303
 304        ret = usb6fire_fw_ezusb_write(device, 8, 0, NULL, 0);
 305        if (ret < 0) {
 306                kfree(buffer);
 307                release_firmware(fw);
 308                snd_printk(KERN_ERR PREFIX "unable to upload fpga firmware: "
 309                                "begin urb.\n");
 310                return ret;
 311        }
 312
 313        while (c != end) {
 314                for (i = 0; c != end && i < FPGA_BUFSIZE; i++, c++)
 315                        buffer[i] = byte_rev_table[(u8) *c];
 316
 317                ret = usb6fire_fw_fpga_write(device, buffer, i);
 318                if (ret < 0) {
 319                        release_firmware(fw);
 320                        kfree(buffer);
 321                        snd_printk(KERN_ERR PREFIX "unable to upload fpga "
 322                                        "firmware: fw urb.\n");
 323                        return ret;
 324                }
 325        }
 326        release_firmware(fw);
 327        kfree(buffer);
 328
 329        ret = usb6fire_fw_ezusb_write(device, 9, 0, NULL, 0);
 330        if (ret < 0) {
 331                snd_printk(KERN_ERR PREFIX "unable to upload fpga firmware: "
 332                                "end urb.\n");
 333                return ret;
 334        }
 335        return 0;
 336}
 337
 338/* check, if the firmware version the devices has currently loaded
 339 * is known by this driver. 'version' needs to have 4 bytes version
 340 * info data. */
 341static int usb6fire_fw_check(u8 *version)
 342{
 343        int i;
 344
 345        for (i = 0; i < ARRAY_SIZE(known_fw_versions); i++)
 346                if (!memcmp(version, known_fw_versions + i, 2))
 347                        return 0;
 348
 349        snd_printk(KERN_ERR PREFIX "invalid fimware version in device: %4ph. "
 350                        "please reconnect to power. if this failure "
 351                        "still happens, check your firmware installation.",
 352                        version);
 353        return -EINVAL;
 354}
 355
 356int usb6fire_fw_init(struct usb_interface *intf)
 357{
 358        int i;
 359        int ret;
 360        struct usb_device *device = interface_to_usbdev(intf);
 361        /* buffer: 8 receiving bytes from device and
 362         * sizeof(EP_W_MAX_PACKET_SIZE) bytes for non-const copy */
 363        u8 buffer[12];
 364
 365        ret = usb6fire_fw_ezusb_read(device, 1, 0, buffer, 8);
 366        if (ret < 0) {
 367                snd_printk(KERN_ERR PREFIX "unable to receive device "
 368                                "firmware state.\n");
 369                return ret;
 370        }
 371        if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55) {
 372                snd_printk(KERN_ERR PREFIX "unknown device firmware state "
 373                                "received from device: ");
 374                for (i = 0; i < 8; i++)
 375                        snd_printk("%02x ", buffer[i]);
 376                snd_printk("\n");
 377                return -EIO;
 378        }
 379        /* do we need fpga loader ezusb firmware? */
 380        if (buffer[3] == 0x01) {
 381                ret = usb6fire_fw_ezusb_upload(intf,
 382                                "6fire/dmx6firel2.ihx", 0, NULL, 0);
 383                if (ret < 0)
 384                        return ret;
 385                return FW_NOT_READY;
 386        }
 387        /* do we need fpga firmware and application ezusb firmware? */
 388        else if (buffer[3] == 0x02) {
 389                ret = usb6fire_fw_check(buffer + 4);
 390                if (ret < 0)
 391                        return ret;
 392                ret = usb6fire_fw_fpga_upload(intf, "6fire/dmx6firecf.bin");
 393                if (ret < 0)
 394                        return ret;
 395                memcpy(buffer, ep_w_max_packet_size,
 396                                sizeof(ep_w_max_packet_size));
 397                ret = usb6fire_fw_ezusb_upload(intf, "6fire/dmx6fireap.ihx",
 398                                0x0003, buffer, sizeof(ep_w_max_packet_size));
 399                if (ret < 0)
 400                        return ret;
 401                return FW_NOT_READY;
 402        }
 403        /* all fw loaded? */
 404        else if (buffer[3] == 0x03)
 405                return usb6fire_fw_check(buffer + 4);
 406        /* unknown data? */
 407        else {
 408                snd_printk(KERN_ERR PREFIX "unknown device firmware state "
 409                                "received from device: ");
 410                for (i = 0; i < 8; i++)
 411                        snd_printk("%02x ", buffer[i]);
 412                snd_printk("\n");
 413                return -EIO;
 414        }
 415        return 0;
 416}
 417
 418