linux/drivers/media/usb/as102/as102_fw.c
Thomas Gleixner 3e0a4e8580 treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 118
Based on 1 normalized pattern(s):

  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

extracted by the scancode license scanner the SPDX license identifier

  GPL-2.0-or-later

has been chosen to replace the boilerplate/reference in 44 file(s).

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Richard Fontana <rfontana@redhat.com>
Reviewed-by: Allison Randal <allison@lohutok.net>
Cc: linux-spdx@vger.kernel.org
Link: https://lkml.kernel.org/r/20190523091651.032047323@linutronix.de
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-05-24 17:39:02 +02:00

227 lines
5.1 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Abilis Systems Single DVB-T Receiver
* Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
* Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
*/
#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);
firmware = NULL;
/* 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;
}