linux/drivers/media/usb/as102/as102_fw.c
<<
>>
Prefs
   1/*
   2 * Abilis Systems Single DVB-T Receiver
   3 * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
   4 * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2, or (at your option)
   9 * any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 */
  16#include <linux/kernel.h>
  17#include <linux/errno.h>
  18#include <linux/ctype.h>
  19#include <linux/delay.h>
  20#include <linux/firmware.h>
  21
  22#include "as102_drv.h"
  23#include "as102_fw.h"
  24
  25static const char as102_st_fw1[] = "as102_data1_st.hex";
  26static const char as102_st_fw2[] = "as102_data2_st.hex";
  27static const char as102_dt_fw1[] = "as102_data1_dt.hex";
  28static const char as102_dt_fw2[] = "as102_data2_dt.hex";
  29
  30static unsigned char atohx(unsigned char *dst, char *src)
  31{
  32        unsigned char value = 0;
  33
  34        char msb = tolower(*src) - '0';
  35        char lsb = tolower(*(src + 1)) - '0';
  36
  37        if (msb > 9)
  38                msb -= 7;
  39        if (lsb > 9)
  40                lsb -= 7;
  41
  42        *dst = value = ((msb & 0xF) << 4) | (lsb & 0xF);
  43        return value;
  44}
  45
  46/*
  47 * Parse INTEL HEX firmware file to extract address and data.
  48 */
  49static int parse_hex_line(unsigned char *fw_data, unsigned char *addr,
  50                          unsigned char *data, int *dataLength,
  51                          unsigned char *addr_has_changed) {
  52
  53        int count = 0;
  54        unsigned char *src, dst;
  55
  56        if (*fw_data++ != ':') {
  57                pr_err("invalid firmware file\n");
  58                return -EFAULT;
  59        }
  60
  61        /* locate end of line */
  62        for (src = fw_data; *src != '\n'; src += 2) {
  63                atohx(&dst, src);
  64                /* parse line to split addr / data */
  65                switch (count) {
  66                case 0:
  67                        *dataLength = dst;
  68                        break;
  69                case 1:
  70                        addr[2] = dst;
  71                        break;
  72                case 2:
  73                        addr[3] = dst;
  74                        break;
  75                case 3:
  76                        /* check if data is an address */
  77                        if (dst == 0x04)
  78                                *addr_has_changed = 1;
  79                        else
  80                                *addr_has_changed = 0;
  81                        break;
  82                case  4:
  83                case  5:
  84                        if (*addr_has_changed)
  85                                addr[(count - 4)] = dst;
  86                        else
  87                                data[(count - 4)] = dst;
  88                        break;
  89                default:
  90                        data[(count - 4)] = dst;
  91                        break;
  92                }
  93                count++;
  94        }
  95
  96        /* return read value + ':' + '\n' */
  97        return (count * 2) + 2;
  98}
  99
 100static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap,
 101                                 unsigned char *cmd,
 102                                 const struct firmware *firmware) {
 103
 104        struct as10x_fw_pkt_t *fw_pkt;
 105        int total_read_bytes = 0, errno = 0;
 106        unsigned char addr_has_changed = 0;
 107
 108        fw_pkt = kmalloc(sizeof(*fw_pkt), GFP_KERNEL);
 109        if (!fw_pkt)
 110                return -ENOMEM;
 111
 112
 113        for (total_read_bytes = 0; total_read_bytes < firmware->size; ) {
 114                int read_bytes = 0, data_len = 0;
 115
 116                /* parse intel hex line */
 117                read_bytes = parse_hex_line(
 118                                (u8 *) (firmware->data + total_read_bytes),
 119                                fw_pkt->raw.address,
 120                                fw_pkt->raw.data,
 121                                &data_len,
 122                                &addr_has_changed);
 123
 124                if (read_bytes <= 0)
 125                        goto error;
 126
 127                /* detect the end of file */
 128                total_read_bytes += read_bytes;
 129                if (total_read_bytes == firmware->size) {
 130                        fw_pkt->u.request[0] = 0x00;
 131                        fw_pkt->u.request[1] = 0x03;
 132
 133                        /* send EOF command */
 134                        errno = bus_adap->ops->upload_fw_pkt(bus_adap,
 135                                                             (uint8_t *)
 136                                                             fw_pkt, 2, 0);
 137                        if (errno < 0)
 138                                goto error;
 139                } else {
 140                        if (!addr_has_changed) {
 141                                /* prepare command to send */
 142                                fw_pkt->u.request[0] = 0x00;
 143                                fw_pkt->u.request[1] = 0x01;
 144
 145                                data_len += sizeof(fw_pkt->u.request);
 146                                data_len += sizeof(fw_pkt->raw.address);
 147
 148                                /* send cmd to device */
 149                                errno = bus_adap->ops->upload_fw_pkt(bus_adap,
 150                                                                     (uint8_t *)
 151                                                                     fw_pkt,
 152                                                                     data_len,
 153                                                                     0);
 154                                if (errno < 0)
 155                                        goto error;
 156                        }
 157                }
 158        }
 159error:
 160        kfree(fw_pkt);
 161        return (errno == 0) ? total_read_bytes : errno;
 162}
 163
 164int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap)
 165{
 166        int errno = -EFAULT;
 167        const struct firmware *firmware = NULL;
 168        unsigned char *cmd_buf = NULL;
 169        const char *fw1, *fw2;
 170        struct usb_device *dev = bus_adap->usb_dev;
 171
 172        /* select fw file to upload */
 173        if (dual_tuner) {
 174                fw1 = as102_dt_fw1;
 175                fw2 = as102_dt_fw2;
 176        } else {
 177                fw1 = as102_st_fw1;
 178                fw2 = as102_st_fw2;
 179        }
 180
 181        /* allocate buffer to store firmware upload command and data */
 182        cmd_buf = kzalloc(MAX_FW_PKT_SIZE, GFP_KERNEL);
 183        if (cmd_buf == NULL) {
 184                errno = -ENOMEM;
 185                goto error;
 186        }
 187
 188        /* request kernel to locate firmware file: part1 */
 189        errno = request_firmware(&firmware, fw1, &dev->dev);
 190        if (errno < 0) {
 191                pr_err("%s: unable to locate firmware file: %s\n",
 192                       DRIVER_NAME, fw1);
 193                goto error;
 194        }
 195
 196        /* initiate firmware upload */
 197        errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
 198        if (errno < 0) {
 199                pr_err("%s: error during firmware upload part1\n",
 200                       DRIVER_NAME);
 201                goto error;
 202        }
 203
 204        pr_info("%s: firmware: %s loaded with success\n",
 205                DRIVER_NAME, fw1);
 206        release_firmware(firmware);
 207        firmware = NULL;
 208
 209        /* wait for boot to complete */
 210        mdelay(100);
 211
 212        /* request kernel to locate firmware file: part2 */
 213        errno = request_firmware(&firmware, fw2, &dev->dev);
 214        if (errno < 0) {
 215                pr_err("%s: unable to locate firmware file: %s\n",
 216                       DRIVER_NAME, fw2);
 217                goto error;
 218        }
 219
 220        /* initiate firmware upload */
 221        errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
 222        if (errno < 0) {
 223                pr_err("%s: error during firmware upload part2\n",
 224                       DRIVER_NAME);
 225                goto error;
 226        }
 227
 228        pr_info("%s: firmware: %s loaded with success\n",
 229                DRIVER_NAME, fw2);
 230error:
 231        kfree(cmd_buf);
 232        release_firmware(firmware);
 233
 234        return errno;
 235}
 236