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                dev_err(&intf->dev,
 223                        "error requesting ezusb 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                dev_err(&intf->dev,
 231                        "error validating ezusb 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                dev_err(&intf->dev,
 241                        "unable to upload ezusb firmware %s: begin message.\n",
 242                        fwname);
 243                return ret;
 244        }
 245
 246        while (usb6fire_fw_ihex_next_record(rec)) { /* write firmware */
 247                ret = usb6fire_fw_ezusb_write(device, 0xa0, rec->address,
 248                                rec->data, rec->len);
 249                if (ret < 0) {
 250                        kfree(rec);
 251                        release_firmware(fw);
 252                        dev_err(&intf->dev,
 253                                "unable to upload ezusb firmware %s: data urb.\n",
 254                                fwname);
 255                        return ret;
 256                }
 257        }
 258
 259        release_firmware(fw);
 260        kfree(rec);
 261        if (postdata) { /* write data after firmware has been uploaded */
 262                ret = usb6fire_fw_ezusb_write(device, 0xa0, postaddr,
 263                                postdata, postlen);
 264                if (ret < 0) {
 265                        dev_err(&intf->dev,
 266                                "unable to upload ezusb firmware %s: post urb.\n",
 267                                fwname);
 268                        return ret;
 269                }
 270        }
 271
 272        data = 0x00; /* resume ezusb cpu */
 273        ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1);
 274        if (ret < 0) {
 275                dev_err(&intf->dev,
 276                        "unable to upload ezusb firmware %s: end message.\n",
 277                        fwname);
 278                return ret;
 279        }
 280        return 0;
 281}
 282
 283static int usb6fire_fw_fpga_upload(
 284                struct usb_interface *intf, const char *fwname)
 285{
 286        int ret;
 287        int i;
 288        struct usb_device *device = interface_to_usbdev(intf);
 289        u8 *buffer = kmalloc(FPGA_BUFSIZE, GFP_KERNEL);
 290        const char *c;
 291        const char *end;
 292        const struct firmware *fw;
 293
 294        if (!buffer)
 295                return -ENOMEM;
 296
 297        ret = request_firmware(&fw, fwname, &device->dev);
 298        if (ret < 0) {
 299                dev_err(&intf->dev, "unable to get fpga firmware %s.\n",
 300                                fwname);
 301                kfree(buffer);
 302                return -EIO;
 303        }
 304
 305        c = fw->data;
 306        end = fw->data + fw->size;
 307
 308        ret = usb6fire_fw_ezusb_write(device, 8, 0, NULL, 0);
 309        if (ret < 0) {
 310                kfree(buffer);
 311                release_firmware(fw);
 312                dev_err(&intf->dev,
 313                        "unable to upload fpga firmware: begin urb.\n");
 314                return ret;
 315        }
 316
 317        while (c != end) {
 318                for (i = 0; c != end && i < FPGA_BUFSIZE; i++, c++)
 319                        buffer[i] = bitrev8((u8)*c);
 320
 321                ret = usb6fire_fw_fpga_write(device, buffer, i);
 322                if (ret < 0) {
 323                        release_firmware(fw);
 324                        kfree(buffer);
 325                        dev_err(&intf->dev,
 326                                "unable to upload fpga firmware: fw urb.\n");
 327                        return ret;
 328                }
 329        }
 330        release_firmware(fw);
 331        kfree(buffer);
 332
 333        ret = usb6fire_fw_ezusb_write(device, 9, 0, NULL, 0);
 334        if (ret < 0) {
 335                dev_err(&intf->dev,
 336                        "unable to upload fpga firmware: end urb.\n");
 337                return ret;
 338        }
 339        return 0;
 340}
 341
 342/* check, if the firmware version the devices has currently loaded
 343 * is known by this driver. 'version' needs to have 4 bytes version
 344 * info data. */
 345static int usb6fire_fw_check(struct usb_interface *intf, const u8 *version)
 346{
 347        int i;
 348
 349        for (i = 0; i < ARRAY_SIZE(known_fw_versions); i++)
 350                if (!memcmp(version, known_fw_versions + i, 2))
 351                        return 0;
 352
 353        dev_err(&intf->dev, "invalid fimware version in device: %4ph. "
 354                        "please reconnect to power. if this failure "
 355                        "still happens, check your firmware installation.",
 356                        version);
 357        return -EINVAL;
 358}
 359
 360int usb6fire_fw_init(struct usb_interface *intf)
 361{
 362        int i;
 363        int ret;
 364        struct usb_device *device = interface_to_usbdev(intf);
 365        /* buffer: 8 receiving bytes from device and
 366         * sizeof(EP_W_MAX_PACKET_SIZE) bytes for non-const copy */
 367        u8 buffer[12];
 368
 369        ret = usb6fire_fw_ezusb_read(device, 1, 0, buffer, 8);
 370        if (ret < 0) {
 371                dev_err(&intf->dev,
 372                        "unable to receive device firmware state.\n");
 373                return ret;
 374        }
 375        if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55) {
 376                dev_err(&intf->dev,
 377                        "unknown device firmware state received from device:");
 378                for (i = 0; i < 8; i++)
 379                        printk(KERN_CONT "%02x ", buffer[i]);
 380                printk(KERN_CONT "\n");
 381                return -EIO;
 382        }
 383        /* do we need fpga loader ezusb firmware? */
 384        if (buffer[3] == 0x01) {
 385                ret = usb6fire_fw_ezusb_upload(intf,
 386                                "6fire/dmx6firel2.ihx", 0, NULL, 0);
 387                if (ret < 0)
 388                        return ret;
 389                return FW_NOT_READY;
 390        }
 391        /* do we need fpga firmware and application ezusb firmware? */
 392        else if (buffer[3] == 0x02) {
 393                ret = usb6fire_fw_check(intf, buffer + 4);
 394                if (ret < 0)
 395                        return ret;
 396                ret = usb6fire_fw_fpga_upload(intf, "6fire/dmx6firecf.bin");
 397                if (ret < 0)
 398                        return ret;
 399                memcpy(buffer, ep_w_max_packet_size,
 400                                sizeof(ep_w_max_packet_size));
 401                ret = usb6fire_fw_ezusb_upload(intf, "6fire/dmx6fireap.ihx",
 402                                0x0003, buffer, sizeof(ep_w_max_packet_size));
 403                if (ret < 0)
 404                        return ret;
 405                return FW_NOT_READY;
 406        }
 407        /* all fw loaded? */
 408        else if (buffer[3] == 0x03)
 409                return usb6fire_fw_check(intf, buffer + 4);
 410        /* unknown data? */
 411        else {
 412                dev_err(&intf->dev,
 413                        "unknown device firmware state received from device: ");
 414                for (i = 0; i < 8; i++)
 415                        printk(KERN_CONT "%02x ", buffer[i]);
 416                printk(KERN_CONT "\n");
 417                return -EIO;
 418        }
 419        return 0;
 420}
 421
 422