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