mirror of
https://github.com/torvalds/linux.git
synced 2024-12-22 02:52:56 +00:00
3e0a4e8580
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>
227 lines
5.1 KiB
C
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;
|
|
}
|