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        return usb_control_msg_send(device, 0, type,
 162                                    USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 163                                    value, 0, data, len, HZ, GFP_KERNEL);
 164}
 165
 166static int usb6fire_fw_ezusb_read(struct usb_device *device,
 167                int type, int value, char *data, int len)
 168{
 169        return usb_control_msg_recv(device, 0, type,
 170                                    USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 171                                    value, 0, data, len, HZ, GFP_KERNEL);
 172}
 173
 174static int usb6fire_fw_fpga_write(struct usb_device *device,
 175                char *data, int len)
 176{
 177        int actual_len;
 178        int ret;
 179
 180        ret = usb_bulk_msg(device, usb_sndbulkpipe(device, FPGA_EP), data, len,
 181                        &actual_len, HZ);
 182        if (ret < 0)
 183                return ret;
 184        else if (actual_len != len)
 185                return -EIO;
 186        return 0;
 187}
 188
 189static int usb6fire_fw_ezusb_upload(
 190                struct usb_interface *intf, const char *fwname,
 191                unsigned int postaddr, u8 *postdata, unsigned int postlen)
 192{
 193        int ret;
 194        u8 data;
 195        struct usb_device *device = interface_to_usbdev(intf);
 196        const struct firmware *fw = NULL;
 197        struct ihex_record *rec = kmalloc(sizeof(struct ihex_record),
 198                        GFP_KERNEL);
 199
 200        if (!rec)
 201                return -ENOMEM;
 202
 203        ret = request_firmware(&fw, fwname, &device->dev);
 204        if (ret < 0) {
 205                kfree(rec);
 206                dev_err(&intf->dev,
 207                        "error requesting ezusb firmware %s.\n", fwname);
 208                return ret;
 209        }
 210        ret = usb6fire_fw_ihex_init(fw, rec);
 211        if (ret < 0) {
 212                kfree(rec);
 213                release_firmware(fw);
 214                dev_err(&intf->dev,
 215                        "error validating ezusb firmware %s.\n", fwname);
 216                return ret;
 217        }
 218        /* upload firmware image */
 219        data = 0x01; /* stop ezusb cpu */
 220        ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1);
 221        if (ret) {
 222                kfree(rec);
 223                release_firmware(fw);
 224                dev_err(&intf->dev,
 225                        "unable to upload ezusb firmware %s: begin message.\n",
 226                        fwname);
 227                return ret;
 228        }
 229
 230        while (usb6fire_fw_ihex_next_record(rec)) { /* write firmware */
 231                ret = usb6fire_fw_ezusb_write(device, 0xa0, rec->address,
 232                                rec->data, rec->len);
 233                if (ret) {
 234                        kfree(rec);
 235                        release_firmware(fw);
 236                        dev_err(&intf->dev,
 237                                "unable to upload ezusb firmware %s: data urb.\n",
 238                                fwname);
 239                        return ret;
 240                }
 241        }
 242
 243        release_firmware(fw);
 244        kfree(rec);
 245        if (postdata) { /* write data after firmware has been uploaded */
 246                ret = usb6fire_fw_ezusb_write(device, 0xa0, postaddr,
 247                                postdata, postlen);
 248                if (ret) {
 249                        dev_err(&intf->dev,
 250                                "unable to upload ezusb firmware %s: post urb.\n",
 251                                fwname);
 252                        return ret;
 253                }
 254        }
 255
 256        data = 0x00; /* resume ezusb cpu */
 257        ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1);
 258        if (ret) {
 259                dev_err(&intf->dev,
 260                        "unable to upload ezusb firmware %s: end message.\n",
 261                        fwname);
 262                return ret;
 263        }
 264        return 0;
 265}
 266
 267static int usb6fire_fw_fpga_upload(
 268                struct usb_interface *intf, const char *fwname)
 269{
 270        int ret;
 271        int i;
 272        struct usb_device *device = interface_to_usbdev(intf);
 273        u8 *buffer = kmalloc(FPGA_BUFSIZE, GFP_KERNEL);
 274        const char *c;
 275        const char *end;
 276        const struct firmware *fw;
 277
 278        if (!buffer)
 279                return -ENOMEM;
 280
 281        ret = request_firmware(&fw, fwname, &device->dev);
 282        if (ret < 0) {
 283                dev_err(&intf->dev, "unable to get fpga firmware %s.\n",
 284                                fwname);
 285                kfree(buffer);
 286                return -EIO;
 287        }
 288
 289        c = fw->data;
 290        end = fw->data + fw->size;
 291
 292        ret = usb6fire_fw_ezusb_write(device, 8, 0, NULL, 0);
 293        if (ret) {
 294                kfree(buffer);
 295                release_firmware(fw);
 296                dev_err(&intf->dev,
 297                        "unable to upload fpga firmware: begin urb.\n");
 298                return ret;
 299        }
 300
 301        while (c != end) {
 302                for (i = 0; c != end && i < FPGA_BUFSIZE; i++, c++)
 303                        buffer[i] = bitrev8((u8)*c);
 304
 305                ret = usb6fire_fw_fpga_write(device, buffer, i);
 306                if (ret < 0) {
 307                        release_firmware(fw);
 308                        kfree(buffer);
 309                        dev_err(&intf->dev,
 310                                "unable to upload fpga firmware: fw urb.\n");
 311                        return ret;
 312                }
 313        }
 314        release_firmware(fw);
 315        kfree(buffer);
 316
 317        ret = usb6fire_fw_ezusb_write(device, 9, 0, NULL, 0);
 318        if (ret) {
 319                dev_err(&intf->dev,
 320                        "unable to upload fpga firmware: end urb.\n");
 321                return ret;
 322        }
 323        return 0;
 324}
 325
 326/* check, if the firmware version the devices has currently loaded
 327 * is known by this driver. 'version' needs to have 4 bytes version
 328 * info data. */
 329static int usb6fire_fw_check(struct usb_interface *intf, const u8 *version)
 330{
 331        int i;
 332
 333        for (i = 0; i < ARRAY_SIZE(known_fw_versions); i++)
 334                if (!memcmp(version, known_fw_versions + i, 2))
 335                        return 0;
 336
 337        dev_err(&intf->dev, "invalid firmware version in device: %4ph. "
 338                        "please reconnect to power. if this failure "
 339                        "still happens, check your firmware installation.",
 340                        version);
 341        return -EINVAL;
 342}
 343
 344int usb6fire_fw_init(struct usb_interface *intf)
 345{
 346        int i;
 347        int ret;
 348        struct usb_device *device = interface_to_usbdev(intf);
 349        /* buffer: 8 receiving bytes from device and
 350         * sizeof(EP_W_MAX_PACKET_SIZE) bytes for non-const copy */
 351        u8 buffer[12];
 352
 353        ret = usb6fire_fw_ezusb_read(device, 1, 0, buffer, 8);
 354        if (ret) {
 355                dev_err(&intf->dev,
 356                        "unable to receive device firmware state.\n");
 357                return ret;
 358        }
 359        if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55) {
 360                dev_err(&intf->dev,
 361                        "unknown device firmware state received from device:");
 362                for (i = 0; i < 8; i++)
 363                        printk(KERN_CONT "%02x ", buffer[i]);
 364                printk(KERN_CONT "\n");
 365                return -EIO;
 366        }
 367        /* do we need fpga loader ezusb firmware? */
 368        if (buffer[3] == 0x01) {
 369                ret = usb6fire_fw_ezusb_upload(intf,
 370                                "6fire/dmx6firel2.ihx", 0, NULL, 0);
 371                if (ret < 0)
 372                        return ret;
 373                return FW_NOT_READY;
 374        }
 375        /* do we need fpga firmware and application ezusb firmware? */
 376        else if (buffer[3] == 0x02) {
 377                ret = usb6fire_fw_check(intf, buffer + 4);
 378                if (ret < 0)
 379                        return ret;
 380                ret = usb6fire_fw_fpga_upload(intf, "6fire/dmx6firecf.bin");
 381                if (ret < 0)
 382                        return ret;
 383                memcpy(buffer, ep_w_max_packet_size,
 384                                sizeof(ep_w_max_packet_size));
 385                ret = usb6fire_fw_ezusb_upload(intf, "6fire/dmx6fireap.ihx",
 386                                0x0003, buffer, sizeof(ep_w_max_packet_size));
 387                if (ret < 0)
 388                        return ret;
 389                return FW_NOT_READY;
 390        }
 391        /* all fw loaded? */
 392        else if (buffer[3] == 0x03)
 393                return usb6fire_fw_check(intf, buffer + 4);
 394        /* unknown data? */
 395        else {
 396                dev_err(&intf->dev,
 397                        "unknown device firmware state received from device: ");
 398                for (i = 0; i < 8; i++)
 399                        printk(KERN_CONT "%02x ", buffer[i]);
 400                printk(KERN_CONT "\n");
 401                return -EIO;
 402        }
 403        return 0;
 404}
 405
 406