123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- /*
- * Abilis Systems Single DVB-T Receiver
- * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
- * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
- #include <linux/kernel.h>
- #include <linux/errno.h>
- #include <linux/ctype.h>
- #include <linux/delay.h>
- #include <linux/firmware.h>
- #include "as102_drv.h"
- #include "as102_fw.h"
- static const char as102_st_fw1[] = "as102_data1_st.hex";
- static const char as102_st_fw2[] = "as102_data2_st.hex";
- static const char as102_dt_fw1[] = "as102_data1_dt.hex";
- static const char as102_dt_fw2[] = "as102_data2_dt.hex";
- static unsigned char atohx(unsigned char *dst, char *src)
- {
- unsigned char value = 0;
- char msb = tolower(*src) - '0';
- char lsb = tolower(*(src + 1)) - '0';
- if (msb > 9)
- msb -= 7;
- if (lsb > 9)
- lsb -= 7;
- *dst = value = ((msb & 0xF) << 4) | (lsb & 0xF);
- return value;
- }
- /*
- * Parse INTEL HEX firmware file to extract address and data.
- */
- static int parse_hex_line(unsigned char *fw_data, unsigned char *addr,
- unsigned char *data, int *dataLength,
- unsigned char *addr_has_changed) {
- int count = 0;
- unsigned char *src, dst;
- if (*fw_data++ != ':') {
- pr_err("invalid firmware file\n");
- return -EFAULT;
- }
- /* locate end of line */
- for (src = fw_data; *src != '\n'; src += 2) {
- atohx(&dst, src);
- /* parse line to split addr / data */
- switch (count) {
- case 0:
- *dataLength = dst;
- break;
- case 1:
- addr[2] = dst;
- break;
- case 2:
- addr[3] = dst;
- break;
- case 3:
- /* check if data is an address */
- if (dst == 0x04)
- *addr_has_changed = 1;
- else
- *addr_has_changed = 0;
- break;
- case 4:
- case 5:
- if (*addr_has_changed)
- addr[(count - 4)] = dst;
- else
- data[(count - 4)] = dst;
- break;
- default:
- data[(count - 4)] = dst;
- break;
- }
- count++;
- }
- /* return read value + ':' + '\n' */
- return (count * 2) + 2;
- }
- static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap,
- unsigned char *cmd,
- const struct firmware *firmware) {
- struct as10x_fw_pkt_t *fw_pkt;
- int total_read_bytes = 0, errno = 0;
- unsigned char addr_has_changed = 0;
- fw_pkt = kmalloc(sizeof(*fw_pkt), GFP_KERNEL);
- if (!fw_pkt)
- return -ENOMEM;
- for (total_read_bytes = 0; total_read_bytes < firmware->size; ) {
- int read_bytes = 0, data_len = 0;
- /* parse intel hex line */
- read_bytes = parse_hex_line(
- (u8 *) (firmware->data + total_read_bytes),
- fw_pkt->raw.address,
- fw_pkt->raw.data,
- &data_len,
- &addr_has_changed);
- if (read_bytes <= 0)
- goto error;
- /* detect the end of file */
- total_read_bytes += read_bytes;
- if (total_read_bytes == firmware->size) {
- fw_pkt->u.request[0] = 0x00;
- fw_pkt->u.request[1] = 0x03;
- /* send EOF command */
- errno = bus_adap->ops->upload_fw_pkt(bus_adap,
- (uint8_t *)
- fw_pkt, 2, 0);
- if (errno < 0)
- goto error;
- } else {
- if (!addr_has_changed) {
- /* prepare command to send */
- fw_pkt->u.request[0] = 0x00;
- fw_pkt->u.request[1] = 0x01;
- data_len += sizeof(fw_pkt->u.request);
- data_len += sizeof(fw_pkt->raw.address);
- /* send cmd to device */
- errno = bus_adap->ops->upload_fw_pkt(bus_adap,
- (uint8_t *)
- fw_pkt,
- data_len,
- 0);
- if (errno < 0)
- goto error;
- }
- }
- }
- error:
- kfree(fw_pkt);
- return (errno == 0) ? total_read_bytes : errno;
- }
- int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap)
- {
- int errno = -EFAULT;
- const struct firmware *firmware = NULL;
- unsigned char *cmd_buf = NULL;
- const char *fw1, *fw2;
- struct usb_device *dev = bus_adap->usb_dev;
- /* select fw file to upload */
- if (dual_tuner) {
- fw1 = as102_dt_fw1;
- fw2 = as102_dt_fw2;
- } else {
- fw1 = as102_st_fw1;
- fw2 = as102_st_fw2;
- }
- /* allocate buffer to store firmware upload command and data */
- cmd_buf = kzalloc(MAX_FW_PKT_SIZE, GFP_KERNEL);
- if (cmd_buf == NULL) {
- errno = -ENOMEM;
- goto error;
- }
- /* request kernel to locate firmware file: part1 */
- errno = request_firmware(&firmware, fw1, &dev->dev);
- if (errno < 0) {
- pr_err("%s: unable to locate firmware file: %s\n",
- DRIVER_NAME, fw1);
- goto error;
- }
- /* initiate firmware upload */
- errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
- if (errno < 0) {
- pr_err("%s: error during firmware upload part1\n",
- DRIVER_NAME);
- goto error;
- }
- pr_info("%s: firmware: %s loaded with success\n",
- DRIVER_NAME, fw1);
- release_firmware(firmware);
- /* wait for boot to complete */
- mdelay(100);
- /* request kernel to locate firmware file: part2 */
- errno = request_firmware(&firmware, fw2, &dev->dev);
- if (errno < 0) {
- pr_err("%s: unable to locate firmware file: %s\n",
- DRIVER_NAME, fw2);
- goto error;
- }
- /* initiate firmware upload */
- errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
- if (errno < 0) {
- pr_err("%s: error during firmware upload part2\n",
- DRIVER_NAME);
- goto error;
- }
- pr_info("%s: firmware: %s loaded with success\n",
- DRIVER_NAME, fw2);
- error:
- kfree(cmd_buf);
- release_firmware(firmware);
- return errno;
- }
|