summaryrefslogtreecommitdiff
path: root/drivers/staging/media/as102/as102_fw.c
diff options
context:
space:
mode:
authorPierrick Hascoet <pierrick.hascoet@abilis.com>2011-10-31 12:24:39 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-11-03 07:42:49 -0200
commit41b44e0418112e694f9b7beb8088efbb8c9c0053 (patch)
treec12811c8a738b48f75d8b9a9eeb7e7d1cad68a54 /drivers/staging/media/as102/as102_fw.c
parent539b469518b45c0b5915bec3e258e21e03667084 (diff)
[media] staging: as102: Initial import from Abilis
Changes by Devin Heitmueller: Import the original Abilis Systems as102 driver. The source is unmodified, with the only changes I've made so far were that I created a Kconfig and Makefile so that the code builds in a standard v4l-dvb tree. This driver requires firmware (which Abilis has provided with redistribution terms which will allow it to be bundled in the Linux distributions). The firmware can be downloaded from here: Thanks to Rainer Miethling from PCTV Systems for working to get the driver released (for use with the PCTV 74e) and Pierrick Hascoet from Abilis for authoring the driver. Changes by Piotr Chmura: - moved the driver from media/dvb to staging/media - removed Makefile/Kconfig - compilation fails in current tree [snjw23@gmail.com: edited changelog] Signed-off-by: Pierrick Hascoet <pierrick.hascoet@abilis.com> Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com> Signed-off-by: Piotr Chmura <chmooreck@poczta.onet.pl> Signed-off-by: Sylwester Nawrocki <snjw23@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/staging/media/as102/as102_fw.c')
-rw-r--r--drivers/staging/media/as102/as102_fw.c236
1 files changed, 236 insertions, 0 deletions
diff --git a/drivers/staging/media/as102/as102_fw.c b/drivers/staging/media/as102/as102_fw.c
new file mode 100644
index 000000000000..d921a6fd6953
--- /dev/null
+++ b/drivers/staging/media/as102/as102_fw.c
@@ -0,0 +1,236 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#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"
+
+#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
+char as102_st_fw1[] = "as102_data1_st.hex";
+char as102_st_fw2[] = "as102_data2_st.hex";
+char as102_dt_fw1[] = "as102_data1_dt.hex";
+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++ != ':') {
+ printk(KERN_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 as102_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;
+
+ ENTER();
+
+ 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 */
+ if ((total_read_bytes += read_bytes) == firmware->size) {
+ fw_pkt.u.request[0] = 0x00;
+ fw_pkt.u.request[1] = 0x03;
+
+ /* send EOF command */
+ if ((errno = bus_adap->ops->upload_fw_pkt(bus_adap,(uint8_t *) &fw_pkt, 2, 0)) < 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 */
+ if ((errno = bus_adap->ops->upload_fw_pkt(bus_adap, (uint8_t *) &fw_pkt, data_len, 0)) < 0)
+ goto error;
+ }
+ }
+ }
+error:
+ LEAVE();
+ return (errno == 0) ? total_read_bytes : errno;
+}
+
+int as102_fw_upload(struct as102_bus_adapter_t *bus_adap) {
+ int errno = -EFAULT;
+ const struct firmware *firmware;
+ unsigned char *cmd_buf = NULL;
+ char *fw1, *fw2;
+
+#if defined(CONFIG_AS102_USB)
+ struct usb_device *dev = bus_adap->usb_dev;
+#endif
+#if defined(CONFIG_AS102_SPI)
+ struct spi_device *dev = bus_adap->spi_dev;
+#endif
+ ENTER();
+
+ /* 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;
+ }
+
+#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
+ /* allocate buffer to store firmware upload command and data */
+ if ((cmd_buf = kzalloc(MAX_FW_PKT_SIZE, GFP_KERNEL)) == NULL) {
+ errno = -ENOMEM;
+ goto error;
+ }
+
+ /* request kernel to locate firmware file: part1 */
+ if ((errno = request_firmware(&firmware, fw1, &dev->dev)) < 0) {
+ printk(KERN_ERR "%s: unable to locate firmware file: %s\n",
+ DRIVER_NAME, fw1);
+ goto error;
+ }
+
+ /* initiate firmware upload */
+ if ((errno = as102_firmware_upload(bus_adap, cmd_buf, firmware)) < 0) {
+ printk(KERN_ERR "%s: error during firmware upload part1\n",
+ DRIVER_NAME);
+ goto error;
+ }
+
+ printk(KERN_INFO "%s: fimrware: %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 */
+ if ((errno = request_firmware(&firmware, fw2, &dev->dev)) < 0) {
+ printk(KERN_ERR "%s: unable to locate firmware file: %s\n",
+ DRIVER_NAME, fw2);
+ goto error;
+ }
+
+ /* initiate firmware upload */
+ if ((errno = as102_firmware_upload(bus_adap, cmd_buf, firmware)) < 0) {
+ printk(KERN_ERR "%s: error during firmware upload part2\n",
+ DRIVER_NAME);
+ goto error;
+ }
+
+ printk(KERN_INFO "%s: fimrware: %s loaded with success\n",
+ DRIVER_NAME, fw2);
+error:
+ /* free data buffer */
+ kfree(cmd_buf);
+ /* release firmware if needed */
+ if (firmware != NULL)
+ release_firmware(firmware);
+#endif
+ LEAVE();
+ return errno;
+}
+#endif
+
+/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */