linux/sound/usb/6fire/firmware.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Linux driver for TerraTec DMX 6Fire USB
   4 *
   5 * Firmware loader
   6 *
   7 * Author:      Torsten Schenk <torsten.schenk@zoho.com>
   8 * Created:     Jan 01, 2011
   9 * Copyright:   (C) Torsten Schenk
  10 */
  11
  12#include <linux/firmware.h>
  13#include <linux/module.h>
  14#include <linux/bitrev.h>
  15#include <linux/kernel.h>
  16
  17#include "firmware.h"
  18#include "chip.h"
  19
  20MODULE_FIRMWARE("6fire/dmx6firel2.ihx");
  21MODULE_FIRMWARE("6fire/dmx6fireap.ihx");
  22MODULE_FIRMWARE("6fire/dmx6firecf.bin");
  23
  24enum {
  25        FPGA_BUFSIZE = 512, FPGA_EP = 2
  26};
  27
  28/*
  29 * wMaxPacketSize of pcm endpoints.
  30 * keep synced with rates_in_packet_size and rates_out_packet_size in pcm.c
  31 * fpp: frames per isopacket
  32 *
  33 * CAUTION: keep sizeof <= buffer[] in usb6fire_fw_init
  34 */
  35static const u8 ep_w_max_packet_size[] = {
  36        0xe4, 0x00, 0xe4, 0x00, /* alt 1: 228 EP2 and EP6 (7 fpp) */
  37        0xa4, 0x01, 0xa4, 0x01, /* alt 2: 420 EP2 and EP6 (13 fpp)*/
  38        0x94, 0x01, 0x5c, 0x02  /* alt 3: 404 EP2 and 604 EP6 (25 fpp) */
  39};
  40
  41static const u8 known_fw_versions[][2] = {
  42        { 0x03, 0x01 }
  43};
  44
  45struct ihex_record {
  46        u16 address;
  47        u8 len;
  48        u8 data[256];
  49        char error; /* true if an error occurred parsing this record */
  50
  51        u8 max_len; /* maximum record length in whole ihex */
  52
  53        /* private */
  54        const char *txt_data;
  55        unsigned int txt_length;
  56        unsigned int txt_offset; /* current position in txt_data */
  57};
  58
  59static u8 usb6fire_fw_ihex_hex(const u8 *data, u8 *crc)
  60{
  61        u8 val = 0;
  62        int hval;
  63
  64        hval = hex_to_bin(data[0]);
  65        if (hval >= 0)
  66                val |= (hval << 4);
  67
  68        hval = hex_to_bin(data[1]);
  69        if (hval >= 0)
  70                val |= hval;
  71
  72        *crc += val;
  73        return val;
  74}
  75
  76/*
  77 * returns true if record is available, false otherwise.
  78 * iff an error occurred, false will be returned and record->error will be true.
  79 */
  80static bool usb6fire_fw_ihex_next_record(struct ihex_record *record)
  81{
  82        u8 crc = 0;
  83        u8 type;
  84        int i;
  85
  86        record->error = false;
  87
  88        /* find begin of record (marked by a colon) */
  89        while (record->txt_offset < record->txt_length
  90                        && record->txt_data[record->txt_offset] != ':')
  91                record->txt_offset++;
  92        if (record->txt_offset == record->txt_length)
  93                return false;
  94
  95        /* number of characters needed for len, addr and type entries */
  96        record->txt_offset++;
  97        if (record->txt_offset + 8 > record->txt_length) {
  98                record->error = true;
  99                return false;
 100        }
 101
 102        record->len = usb6fire_fw_ihex_hex(record->txt_data +
 103                        record->txt_offset, &crc);
 104        record->txt_offset += 2;
 105        record->address = usb6fire_fw_ihex_hex(record->txt_data +
 106                        record->txt_offset, &crc) << 8;
 107        record->txt_offset += 2;
 108        record->address |= usb6fire_fw_ihex_hex(record->txt_data +
 109                        record->txt_offset, &crc);
 110        record->txt_offset += 2;
 111        type = usb6fire_fw_ihex_hex(record->txt_data +
 112                        record->txt_offset, &crc);
 113        record->txt_offset += 2;
 114
 115        /* number of characters needed for data and crc entries */
 116        if (record->txt_offset + 2 * (record->len + 1) > record->txt_length) {
 117                record->error = true;
 118                return false;
 119        }
 120        for (i = 0; i < record->len; i++) {
 121                record->data[i] = usb6fire_fw_ihex_hex(record->txt_data
 122                                + record->txt_offset, &crc);
 123                record->txt_offset += 2;
 124        }
 125        usb6fire_fw_ihex_hex(record->txt_data + record->txt_offset, &crc);
 126        if (crc) {
 127                record->error = true;
 128                return false;
 129        }
 130
 131        if (type == 1 || !record->len) /* eof */
 132                return false;
 133        else if (type == 0)
 134                return true;
 135        else {
 136                record->error = true;
 137                return false;
 138        }
 139}
 140
 141static int usb6fire_fw_ihex_init(const struct firmware *fw,
 142                struct ihex_record *record)
 143{
 144        record->txt_data = fw->data;
 145        record->txt_length = fw->size;
 146        record->txt_offset = 0;
 147        record->max_len = 0;
 148        /* read all records, if loop ends, record->error indicates,
 149         * whether ihex is valid. */
 150        while (usb6fire_fw_ihex_next_record(record))
 151                record->max_len = max(record->len, record->max_len);
 152        if (record->error)
 153                return -EINVAL;
 154        record->txt_offset = 0;
 155        return 0;
 156}
 157
 158static int usb6fire_fw_ezusb_write(struct usb_device *device,
 159                int type, int value, char *data, int len)
 160{
 161        int ret;
 162
 163        ret = usb_control_msg(device, usb_sndctrlpipe(device, 0), type,
 164                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 165                        value, 0, data, len, HZ);
 166        if (ret < 0)
 167                return ret;
 168        else if (ret != len)
 169                return -EIO;
 170        return 0;
 171}
 172
 173static int usb6fire_fw_ezusb_read(struct usb_device *device,
 174                int type, int value, char *data, int len)
 175{
 176        int ret = usb_control_msg(device, usb_rcvctrlpipe(device, 0), type,
 177                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value,
 178                        0, data, len, HZ);
 179        if (ret < 0)
 180                return ret;
 181        else if (ret != len)
 182                return -EIO;
 183        return 0;
 184}
 185
 186static int usb6fire_fw_fpga_write(struct usb_device *device,
 187                char *data, int len)
 188{
 189        int actual_len;
 190        int ret;
 191
 192        ret = usb_bulk_msg(device, usb_sndbulkpipe(device, FPGA_EP), data, len,
 193                        &actual_len, HZ);
 194        if (ret < 0)
 195                return ret;
 196        else if (actual_len != len)
 197                return -EIO;
 198        return 0;
 199}
 200
 201static int usb6fire_fw_ezusb_upload(
 202                struct usb_interface *intf, const char *fwname,
 203                unsigned int postaddr, u8 *postdata, unsigned int postlen)
 204{
 205        int ret;
 206        u8 data;
 207        struct usb_device *device = interface_to_usbdev(intf);
 208        const struct firmware *fw = NULL;
 209        struct ihex_record *rec = kmalloc(sizeof(struct ihex_record),
 210                        GFP_KERNEL);
 211
 212        if (!rec)
 213                return -ENOMEM;
 214
 215        ret = request_firmware(&fw, fwname, &device->dev);
 216        if (ret < 0) {
 217                kfree(rec);
 218                dev_err(&intf->dev,
 219                        "error requesting ezusb firmware %s.\n", fwname);
 220                return ret;
 221        }
 222        ret = usb6fire_fw_ihex_init(fw, rec);
 223        if (ret < 0) {
 224                kfree(rec);
 225                release_firmware(fw);
 226                dev_err(&intf->dev,
 227                        "error validating ezusb firmware %s.\n", fwname);
 228                return ret;
 229        }
 230        /* upload firmware image */
 231        data = 0x01; /* stop ezusb cpu */
 232        ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1);
 233        if (ret < 0) {
 234                kfree(rec);
 235                release_firmware(fw);
 236                dev_err(&intf->dev,
 237                        "unable to upload ezusb firmware %s: begin message.\n",
 238                        fwname);
 239                return ret;
 240        }
 241
 242        while (usb6fire_fw_ihex_next_record(rec)) { /* write firmware */
 243                ret = usb6fire_fw_ezusb_write(device, 0xa0, rec->address,
 244                                rec->data, rec->len);
 245                if (ret < 0) {
 246                        kfree(rec);
 247                        release_firmware(fw);
 248                        dev_err(&intf->dev,
 249                                "unable to upload ezusb firmware %s: data urb.\n",
 250                                fwname);
 251                        return ret;
 252                }
 253        }
 254
 255        release_firmware(fw);
 256        kfree(rec);
 257        if (postdata) { /* write data after firmware has been uploaded */
 258                ret = usb6fire_fw_ezusb_write(device, 0xa0, postaddr,
 259                                postdata, postlen);
 260                if (ret < 0) {
 261                        dev_err(&intf->dev,
 262                                "unable to upload ezusb firmware %s: post urb.\n",
 263                                fwname);
 264                        return ret;
 265                }
 266        }
 267
 268        data = 0x00; /* resume ezusb cpu */
 269        ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1);
 270        if (ret < 0) {
 271                dev_err(&intf->dev,
 272                        "unable to upload ezusb firmware %s: end message.\n",
 273                        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                dev_err(&intf->dev, "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                dev_err(&intf->dev,
 309                        "unable to upload fpga firmware: 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] = bitrev8((u8)*c);
 316
 317                ret = usb6fire_fw_fpga_write(device, buffer, i);
 318                if (ret < 0) {
 319                        release_firmware(fw);
 320                        kfree(buffer);
 321                        dev_err(&intf->dev,
 322                                "unable to upload fpga 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                dev_err(&intf->dev,
 332                        "unable to upload fpga firmware: 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(struct usb_interface *intf, const 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        dev_err(&intf->dev, "invalid firmware 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                dev_err(&intf->dev,
 368                        "unable to receive device firmware state.\n");
 369                return ret;
 370        }
 371        if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55) {
 372                dev_err(&intf->dev,
 373                        "unknown device firmware state received from device:");
 374                for (i = 0; i < 8; i++)
 375                        printk(KERN_CONT "%02x ", buffer[i]);
 376                printk(KERN_CONT "\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(intf, 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(intf, buffer + 4);
 406        /* unknown data? */
 407        else {
 408                dev_err(&intf->dev,
 409                        "unknown device firmware state received from device: ");
 410                for (i = 0; i < 8; i++)
 411                        printk(KERN_CONT "%02x ", buffer[i]);
 412                printk(KERN_CONT "\n");
 413                return -EIO;
 414        }
 415        return 0;
 416}
 417
 418