Mailing List archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[linux-dvb] [patch-rfc] frontend firmware
This patch implements firmware loading for frontends through a callback to the
adapter. It probably is easier to just stuff the struct device into
dvb_frontend, but I wanted to see the connection between the frontends and
their adapters, so I did it this way. I've only modified the fw loading for
the Microtune 7202D (sp887x) frontend, and it's untested as I do not have
this frontend let alone DVB-T :)
Comments?
Kenneth
Index: linux/drivers/media/dvb/ttpci/av7110.c
===================================================================
RCS file: /cvs/linuxtv/dvb-kernel/linux/drivers/media/dvb/ttpci/av7110.c,v
retrieving revision 1.126
diff -u -r1.126 av7110.c
--- linux/drivers/media/dvb/ttpci/av7110.c 21 Jun 2004 14:21:19 -0000 1.126
+++ linux/drivers/media/dvb/ttpci/av7110.c 21 Jun 2004 18:15:44 -0000
@@ -1091,6 +1091,13 @@
up(&av7110->pid_mutex);
}
+static int av7110_firmware_request(const struct firmware **fw,
+ const char *name, void *data)
+{
+ struct av7110 *av7110 = data;
+ return request_firmware(fw, name, &av7110->dev->pci->dev);
+}
+
static int av7110_register(struct av7110 *av7110)
{
@@ -1106,6 +1113,8 @@
dvb_add_frontend_notifier (av7110->dvb_adapter,
av7110_before_after_tune, av7110);
+ dvb_add_frontend_firmware (av7110->dvb_adapter,
+ av7110_firmware_request, av7110);
/**
* init DiSEqC stuff
@@ -1188,6 +1197,8 @@
dvb_remove_frontend_notifier (av7110->dvb_adapter,
av7110_before_after_tune);
+ dvb_remove_frontend_firmware (av7110->dvb_adapter,
+ av7110_firmware_request);
dvb_remove_frontend_ioctls (av7110->dvb_adapter,
av7110_diseqc_ioctl, NULL);
Index: linux/drivers/media/dvb/dvb-core/dvb_frontend.h
===================================================================
RCS file: /cvs/linuxtv/dvb-kernel/linux/drivers/media/dvb/dvb-core/dvb_frontend.h,v
retrieving revision 1.11
diff -u -r1.11 dvb_frontend.h
--- linux/drivers/media/dvb/dvb-core/dvb_frontend.h 3 May 2004 11:15:31 -0000 1.11
+++ linux/drivers/media/dvb/dvb-core/dvb_frontend.h 21 Jun 2004 18:16:44 -0000
@@ -34,6 +34,7 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/errno.h>
+#include <linux/firmware.h>
#include <linux/dvb/frontend.h>
@@ -50,9 +51,13 @@
int (*ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg);
int (*after_ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg);
void (*notifier_callback) (fe_status_t s, void *data);
+ int (*firmware_callback) (const struct firmware **fw,
+ const char *name, void *data);
+
struct dvb_adapter *dvb_adapter;
void *before_after_data; /* can be used by hardware module... */
void *notifier_data; /* can be used by hardware module... */
+ void *firmware_data; // XXX These should be combined, no?
void *data; /* can be used by hardware module... */
struct dvb_i2c_bus *i2c; /* legacy cruft, currently fe drivers depend on this */
@@ -138,5 +143,22 @@
dvb_remove_frontend_notifier (struct dvb_adapter *adapter,
void (*callback) (fe_status_t s, void *data));
+/**
+ * Add firmware loading capabilities for the frontends through it's
+ * adapter.
+ */
+
+extern int
+dvb_add_frontend_firmware (struct dvb_adapter *adapter,
+ int (*callback) (const struct firmware **fw,
+ const char *name, void *data),
+ void *data);
+extern void
+dvb_remove_frontend_firmware (struct dvb_adapter *adapter,
+ int (*callback) (const struct firmware **fw,
+ const char *name, void *data));
+
+
+
#endif
Index: linux/drivers/media/dvb/dvb-core/dvb_frontend.c
===================================================================
RCS file: /cvs/linuxtv/dvb-kernel/linux/drivers/media/dvb/dvb-core/dvb_frontend.c,v
retrieving revision 1.80
diff -u -r1.80 dvb_frontend.c
--- linux/drivers/media/dvb/dvb-core/dvb_frontend.c 14 May 2004 09:55:27 -0000 1.80
+++ linux/drivers/media/dvb/dvb-core/dvb_frontend.c 21 Jun 2004 18:16:57 -0000
@@ -134,10 +134,19 @@
void *data;
};
+struct dvb_frontend_firmware_data {
+ struct list_head list_head;
+ struct dvb_adapter *adapter;
+ int (*callback) (const struct firmware **fw,
+ const char *name, void *data);
+ void *data;
+};
+
static LIST_HEAD(frontend_list);
static LIST_HEAD(frontend_ioctl_list);
static LIST_HEAD(frontend_notifier_list);
+static LIST_HEAD(frontend_firmware_list);
static DECLARE_MUTEX(frontend_mutex);
@@ -1039,6 +1048,57 @@
up (&frontend_mutex);
}
+int
+dvb_add_frontend_firmware (struct dvb_adapter *adapter,
+ int (*callback) (const struct firmware **fw,
+ const char *name, void *data),
+ void *data)
+{
+ struct dvb_frontend_firmware_data *firmware;
+ struct list_head *entry;
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ if (down_interruptible (&frontend_mutex))
+ return -ERESTARTSYS;
+
+ firmware = kmalloc (sizeof(struct dvb_frontend_firmware_data), GFP_KERNEL);
+
+ if (!firmware) {
+ up (&frontend_mutex);
+ return -ENOMEM;
+ }
+
+ firmware->adapter = adapter;
+ firmware->callback = callback;
+ firmware->data = data;
+
+ list_add_tail (&firmware->list_head, &frontend_firmware_list);
+
+ list_for_each (entry, &frontend_list) {
+ struct dvb_frontend_data *fe;
+
+ fe = list_entry (entry, struct dvb_frontend_data, list_head);
+
+ if (fe->frontend.dvb_adapter == adapter &&
+ fe->frontend.firmware_callback == NULL)
+ {
+ fe->frontend.firmware_callback = callback;
+ fe->frontend.firmware_data = data;
+ }
+ }
+
+ up (&frontend_mutex);
+
+ return 0;
+}
+
+void
+dvb_remove_frontend_firmware (struct dvb_adapter *adapter,
+ int (*callback) (const struct firmware **fw,
+ const char *name, void *data))
+{
+}
static struct file_operations dvb_frontend_fops = {
.owner = THIS_MODULE,
Index: linux/drivers/media/dvb/frontends/sp887x.c
===================================================================
RCS file: /cvs/linuxtv/dvb-kernel/linux/drivers/media/dvb/frontends/sp887x.c,v
retrieving revision 1.11
diff -u -r1.11 sp887x.c
--- linux/drivers/media/dvb/frontends/sp887x.c 11 Mar 2004 18:40:44 -0000 1.11
+++ linux/drivers/media/dvb/frontends/sp887x.c 21 Jun 2004 18:17:25 -0000
@@ -24,17 +24,12 @@
#include <linux/fcntl.h>
#include <linux/errno.h>
#include <linux/i2c.h>
+#include <linux/firmware.h>
#include "dvb_frontend.h"
#include "dvb_functions.h"
-#ifndef DVB_SP887X_FIRMWARE_FILE
-#define DVB_SP887X_FIRMWARE_FILE "/usr/lib/hotplug/firmware/sc_main.mc"
-#endif
-
-static char *sp887x_firmware = DVB_SP887X_FIRMWARE_FILE;
-
#if 0
#define dprintk(x...) printk(x)
#else
@@ -193,12 +188,8 @@
int sp887x_initial_setup (struct dvb_frontend *fe)
{
u8 buf [BLOCKSIZE+2];
- unsigned char *firmware = NULL;
+ const struct firmware *fw;
int i;
- int fd;
- int filesize;
- int fw_size;
- mm_segment_t fs;
dprintk("%s\n", __FUNCTION__);
@@ -207,47 +198,21 @@
sp887x_microcontroller_stop (fe);
- fs = get_fs();
+ if (!fe->firmware_callback) {
+ printk(KERN_ERR "sp887x: Unable to request firmware.\n");
+ return -ENOSYS;
+ }
+
+ int ret = fe->firmware_callback(&fw, "dvb-frontend-sp887x.fw", fe->firmware_data);
+ if (ret) {
+ printk(KERN_ERR "sp887x: Unable to get firmware.\n");
+ return -EINVAL;
+ }
- // Load the firmware
- set_fs(get_ds());
- fd = open(sp887x_firmware, 0, 0);
- if (fd < 0) {
- printk(KERN_WARNING "%s: Unable to open firmware %s\n", __FUNCTION__,
- sp887x_firmware);
- return -EIO;
- }
- filesize = lseek(fd, 0L, 2);
- if (filesize <= 0) {
- printk(KERN_WARNING "%s: Firmware %s is empty\n", __FUNCTION__,
- sp887x_firmware);
- sys_close(fd);
- return -EIO;
- }
-
- fw_size = 0x4000;
-
- // allocate buffer for it
- firmware = vmalloc(fw_size);
- if (firmware == NULL) {
- printk(KERN_WARNING "%s: Out of memory loading firmware\n",
- __FUNCTION__);
- sys_close(fd);
- return -EIO;
- }
-
- // read it!
- // read the first 16384 bytes from the file
- // ignore the first 10 bytes
- lseek(fd, 10, 0);
- if (read(fd, firmware, fw_size) != fw_size) {
- printk(KERN_WARNING "%s: Failed to read firmware\n", __FUNCTION__);
- vfree(firmware);
- sys_close(fd);
- return -EIO;
+ if (fw->size != 0x4000) {
+ printk(KERN_ERR "sp887x: Invalid firmware size.\n");
+ return -EINVAL;
}
- sys_close(fd);
- set_fs(fs);
printk ("%s: firmware upload... ", __FUNCTION__);
@@ -258,12 +223,12 @@
/* dummy write (wrap around to start of memory) */
sp887x_writereg(fe, 0x8f0a, 0x0000);
- for (i=0; i<fw_size; i+=BLOCKSIZE) {
+ for (i=10; i<fw->size; i+=BLOCKSIZE) {
int c = BLOCKSIZE;
int err;
- if (i+c > fw_size)
- c = fw_size - i;
+ if (i+c > fw->size)
+ c = fw->size - i;
/* bit 0x8000 in address is set to enable 13bit mode */
/* bit 0x4000 enables multibyte read/write transfers */
@@ -271,17 +236,17 @@
buf[0] = 0xcf;
buf[1] = 0x0a;
- memcpy(&buf[2], firmware + i, c);
+ memcpy(&buf[2], fw->data + i, c);
if ((err = i2c_writebytes (fe, 0x70, buf, c+2)) < 0) {
printk ("failed.\n");
printk ("%s: i2c error (err == %i)\n", __FUNCTION__, err);
- vfree(firmware);
+ release_firmware(fw);
return err;
}
}
- vfree(firmware);
+ release_firmware(fw);
/* don't write RS bytes between packets */
sp887x_writereg(fe, 0xc13, 0x001);
Home |
Main Index |
Thread Index