Mailing List archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[linux-dvb] Re: [patch-rfc] frontend firmware
Hi Michael!
On Monday 21 June 2004 20:44, Michael Hunold wrote:
> It's inevitable to switch over to kernel-i2c for the saa7146 based cards
> and let dvb-i2c vanish.
>
> For the stv0299 and the tda1004x drivers, I already did these changes,
> ie. they use the kernel-i2c interface and the kernel-i2c adapters
> registered by av7110 and budget.
>
> The big plus is, that kernel-i2c automatically does all the sysfs and
> kobject foo. In addition, it's very easy to use the firmware-loading
> facilities in conjunction with kernel-i2c.
>
> Please have a look at the tda1004x driver, where firmware loading is
> implemented through the device member of the i2c client object.
Ahh, I see clearly now. Didn't notice what was what earlier, but...
> In the short term, we should at least convert all drivers that need
> firmware to kernel-i2c.
Please check the attached patch very thoroughly, as I most certainly broke
something :) It's only the sp887x, but at least it's something. I belive you
asked kindly for patches like this a couple of months ago..
> Michael.
Regards,
Kenneth
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 20:35:47 -0000
@@ -22,18 +22,13 @@
#include <linux/fs.h>
#include <linux/unistd.h>
#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;
+#define I2C_DRIVERID_SP887X I2C_DRIVERID_EXP2
#if 0
#define dprintk(x...) printk(x)
@@ -68,18 +63,21 @@
FE_CAN_RECOVER
};
-static int errno;
+struct sp887x_state {
+ u8 initialized;
+ struct i2c_adapter *i2c;
+ struct dvb_adapter *dvb;
+};
static
-int i2c_writebytes (struct dvb_frontend *fe, u8 addr, u8 *buf, u8 len)
+int i2c_writebytes (struct i2c_adapter *i2c, u8 addr, u8 *buf, u8 len)
{
- struct dvb_i2c_bus *i2c = fe->i2c;
struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = len };
int err;
LOG("i2c_writebytes", msg.addr, msg.buf, msg.len);
- if ((err = i2c->xfer (i2c, &msg, 1)) != 1) {
+ if ((err = i2c_transfer(i2c, &msg, 1)) != 1) {
printk ("%s: i2c write error (addr %02x, err == %i)\n",
__FUNCTION__, addr, err);
return -EREMOTEIO;
@@ -91,16 +89,15 @@
static
-int sp887x_writereg (struct dvb_frontend *fe, u16 reg, u16 data)
+int sp887x_writereg (struct i2c_adapter *i2c, u16 reg, u16 data)
{
- struct dvb_i2c_bus *i2c = fe->i2c;
u8 b0 [] = { reg >> 8 , reg & 0xff, data >> 8, data & 0xff };
struct i2c_msg msg = { .addr = 0x70, .flags = 0, .buf = b0, .len = 4 };
int ret;
LOG("sp887x_writereg", msg.addr, msg.buf, msg.len);
- if ((ret = i2c->xfer(i2c, &msg, 1)) != 1) {
+ if ((ret = i2c_transfer(i2c, &msg, 1)) != 1) {
/**
* in case of soft reset we ignore ACK errors...
*/
@@ -119,9 +116,8 @@
static
-u16 sp887x_readreg (struct dvb_frontend *fe, u16 reg)
+u16 sp887x_readreg (struct i2c_adapter *i2c, u16 reg)
{
- struct dvb_i2c_bus *i2c = fe->i2c;
u8 b0 [] = { reg >> 8 , reg & 0xff };
u8 b1 [2];
int ret;
@@ -131,7 +127,7 @@
LOG("sp887x_readreg (w)", msg[0].addr, msg[0].buf, msg[0].len);
LOG("sp887x_readreg (r)", msg[1].addr, msg[1].buf, msg[1].len);
- if ((ret = i2c->xfer(i2c, msg, 2)) != 2)
+ if ((ret = i2c_transfer(i2c, msg, 2)) != 2)
printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
return (((b1[0] << 8) | b1[1]) & 0xfff);
@@ -139,182 +135,56 @@
static
-void sp887x_microcontroller_stop (struct dvb_frontend *fe)
+void sp887x_microcontroller_stop (struct i2c_adapter *i2c)
{
dprintk("%s\n", __FUNCTION__);
- sp887x_writereg(fe, 0xf08, 0x000);
- sp887x_writereg(fe, 0xf09, 0x000);
+ sp887x_writereg(i2c, 0xf08, 0x000);
+ sp887x_writereg(i2c, 0xf09, 0x000);
/* microcontroller STOP */
- sp887x_writereg(fe, 0xf00, 0x000);
+ sp887x_writereg(i2c, 0xf00, 0x000);
}
static
-void sp887x_microcontroller_start (struct dvb_frontend *fe)
+void sp887x_microcontroller_start (struct i2c_adapter *i2c)
{
dprintk("%s\n", __FUNCTION__);
- sp887x_writereg(fe, 0xf08, 0x000);
- sp887x_writereg(fe, 0xf09, 0x000);
+ sp887x_writereg(i2c, 0xf08, 0x000);
+ sp887x_writereg(i2c, 0xf09, 0x000);
/* microcontroller START */
- sp887x_writereg(fe, 0xf00, 0x001);
+ sp887x_writereg(i2c, 0xf00, 0x001);
}
static
-void sp887x_setup_agc (struct dvb_frontend *fe)
+void sp887x_setup_agc (struct i2c_adapter *i2c)
{
/* setup AGC parameters */
dprintk("%s\n", __FUNCTION__);
- sp887x_writereg(fe, 0x33c, 0x054);
- sp887x_writereg(fe, 0x33b, 0x04c);
- sp887x_writereg(fe, 0x328, 0x000);
- sp887x_writereg(fe, 0x327, 0x005);
- sp887x_writereg(fe, 0x326, 0x001);
- sp887x_writereg(fe, 0x325, 0x001);
- sp887x_writereg(fe, 0x324, 0x001);
- sp887x_writereg(fe, 0x318, 0x050);
- sp887x_writereg(fe, 0x317, 0x3fe);
- sp887x_writereg(fe, 0x316, 0x001);
- sp887x_writereg(fe, 0x313, 0x005);
- sp887x_writereg(fe, 0x312, 0x002);
- sp887x_writereg(fe, 0x306, 0x000);
- sp887x_writereg(fe, 0x303, 0x000);
+ sp887x_writereg(i2c, 0x33c, 0x054);
+ sp887x_writereg(i2c, 0x33b, 0x04c);
+ sp887x_writereg(i2c, 0x328, 0x000);
+ sp887x_writereg(i2c, 0x327, 0x005);
+ sp887x_writereg(i2c, 0x326, 0x001);
+ sp887x_writereg(i2c, 0x325, 0x001);
+ sp887x_writereg(i2c, 0x324, 0x001);
+ sp887x_writereg(i2c, 0x318, 0x050);
+ sp887x_writereg(i2c, 0x317, 0x3fe);
+ sp887x_writereg(i2c, 0x316, 0x001);
+ sp887x_writereg(i2c, 0x313, 0x005);
+ sp887x_writereg(i2c, 0x312, 0x002);
+ sp887x_writereg(i2c, 0x306, 0x000);
+ sp887x_writereg(i2c, 0x303, 0x000);
}
-
-#define BLOCKSIZE 30
-
-/**
- * load firmware and setup MPEG interface...
- */
-static
-int sp887x_initial_setup (struct dvb_frontend *fe)
-{
- u8 buf [BLOCKSIZE+2];
- unsigned char *firmware = NULL;
- int i;
- int fd;
- int filesize;
- int fw_size;
- mm_segment_t fs;
-
- dprintk("%s\n", __FUNCTION__);
-
- /* soft reset */
- sp887x_writereg(fe, 0xf1a, 0x000);
-
- sp887x_microcontroller_stop (fe);
-
- fs = get_fs();
-
- // 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;
- }
- sys_close(fd);
- set_fs(fs);
-
- printk ("%s: firmware upload... ", __FUNCTION__);
-
- /* setup write pointer to -1 (end of memory) */
- /* bit 0x8000 in address is set to enable 13bit mode */
- sp887x_writereg(fe, 0x8f08, 0x1fff);
-
- /* dummy write (wrap around to start of memory) */
- sp887x_writereg(fe, 0x8f0a, 0x0000);
-
- for (i=0; i<fw_size; i+=BLOCKSIZE) {
- int c = BLOCKSIZE;
- int err;
-
- 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 */
- /* write register is 0xf0a */
- buf[0] = 0xcf;
- buf[1] = 0x0a;
-
- memcpy(&buf[2], firmware + 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);
- return err;
- }
- }
-
- vfree(firmware);
-
- /* don't write RS bytes between packets */
- sp887x_writereg(fe, 0xc13, 0x001);
-
- /* suppress clock if (!data_valid) */
- sp887x_writereg(fe, 0xc14, 0x000);
-
- /* setup MPEG interface... */
- sp887x_writereg(fe, 0xc1a, 0x872);
- sp887x_writereg(fe, 0xc1b, 0x001);
- sp887x_writereg(fe, 0xc1c, 0x000); /* parallel mode (serial mode == 1) */
- sp887x_writereg(fe, 0xc1a, 0x871);
-
- /* ADC mode, 2 for MT8872, 3 for SP8870/SP8871 */
- sp887x_writereg(fe, 0x301, 0x002);
-
- sp887x_setup_agc(fe);
-
- /* bit 0x010: enable data valid signal */
- sp887x_writereg(fe, 0xd00, 0x010);
- sp887x_writereg(fe, 0x0d1, 0x000);
-
- printk ("done.\n");
- return 0;
-};
-
-
/**
* returns the actual tuned center frequency which can be used
* to initialise the AFC registers
*/
static
-int tsa5060_setup_pll (struct dvb_frontend *fe, int freq)
+int tsa5060_setup_pll (struct i2c_adapter *i2c, int freq)
{
u8 cfg, cpump, band_select;
u8 buf [4];
@@ -334,9 +204,9 @@
buf [3] = cpump | band_select;
/* open i2c gate for PLL message transmission... */
- sp887x_writereg(fe, 0x206, 0x001);
- i2c_writebytes(fe, 0x60, buf, 4);
- sp887x_writereg(fe, 0x206, 0x000);
+ sp887x_writereg(i2c, 0x206, 0x001);
+ i2c_writebytes(i2c, 0x60, buf, 4);
+ sp887x_writereg(i2c, 0x206, 0x000);
return (div * 166666 - 36000000);
}
@@ -441,7 +311,7 @@
static
-void sp887x_correct_offsets (struct dvb_frontend *fe,
+void sp887x_correct_offsets (struct i2c_adapter *i2c,
struct dvb_frontend_parameters *p,
int actual_freq)
{
@@ -464,17 +334,17 @@
frequency_shift = -frequency_shift;
/* sample rate correction */
- sp887x_writereg(fe, 0x319, srate_correction[bw_index] >> 12);
- sp887x_writereg(fe, 0x31a, srate_correction[bw_index] & 0xfff);
+ sp887x_writereg(i2c, 0x319, srate_correction[bw_index] >> 12);
+ sp887x_writereg(i2c, 0x31a, srate_correction[bw_index] & 0xfff);
/* carrier offset correction */
- sp887x_writereg(fe, 0x309, frequency_shift >> 12);
- sp887x_writereg(fe, 0x30a, frequency_shift & 0xfff);
+ sp887x_writereg(i2c, 0x309, frequency_shift >> 12);
+ sp887x_writereg(i2c, 0x30a, frequency_shift & 0xfff);
}
static
-int sp887x_setup_frontend_parameters (struct dvb_frontend *fe,
+int sp887x_setup_frontend_parameters (struct i2c_adapter *i2c,
struct dvb_frontend_parameters *p)
{
int actual_freq, err;
@@ -488,14 +358,14 @@
if ((err = configure_reg0xc05(p, ®0xc05)))
return err;
- sp887x_microcontroller_stop(fe);
+ sp887x_microcontroller_stop(i2c);
- actual_freq = tsa5060_setup_pll(fe, p->frequency);
+ actual_freq = tsa5060_setup_pll(i2c, p->frequency);
/* read status reg in order to clear pending irqs */
- sp887x_readreg(fe, 0x200);
+ sp887x_readreg(i2c, 0x200);
- sp887x_correct_offsets(fe, p, actual_freq);
+ sp887x_correct_offsets(i2c, p, actual_freq);
/* filter for 6/7/8 Mhz channel */
if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
@@ -505,15 +375,15 @@
else
val = 0;
- sp887x_writereg(fe, 0x311, val);
+ sp887x_writereg(i2c, 0x311, val);
/* scan order: 2k first = 0, 8k first = 1 */
if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K)
- sp887x_writereg(fe, 0x338, 0x000);
+ sp887x_writereg(i2c, 0x338, 0x000);
else
- sp887x_writereg(fe, 0x338, 0x001);
+ sp887x_writereg(i2c, 0x338, 0x001);
- sp887x_writereg(fe, 0xc05, reg0xc05);
+ sp887x_writereg(i2c, 0xc05, reg0xc05);
if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
val = 2 << 3;
@@ -525,17 +395,48 @@
/* enable OFDM and SAW bits as lock indicators in sync register 0xf17,
* optimize algorithm for given bandwidth...
*/
- sp887x_writereg(fe, 0xf14, 0x160 | val);
- sp887x_writereg(fe, 0xf15, 0x000);
+ sp887x_writereg(i2c, 0xf14, 0x160 | val);
+ sp887x_writereg(i2c, 0xf15, 0x000);
- sp887x_microcontroller_start(fe);
+ sp887x_microcontroller_start(i2c);
return 0;
}
+static int sp887x_init (struct i2c_adapter *i2c)
+{
+ /* don't write RS bytes between packets */
+ sp887x_writereg(i2c, 0xc13, 0x001);
+
+ /* suppress clock if (!data_valid) */
+ sp887x_writereg(i2c, 0xc14, 0x000);
+
+ /* setup MPEG interface... */
+ sp887x_writereg(i2c, 0xc1a, 0x872);
+ sp887x_writereg(i2c, 0xc1b, 0x001);
+ sp887x_writereg(i2c, 0xc1c, 0x000); /* parallel mode (serial mode == 1) */
+ sp887x_writereg(i2c, 0xc1a, 0x871);
+
+ /* ADC mode, 2 for MT8872, 3 for SP8870/SP8871 */
+ sp887x_writereg(i2c, 0x301, 0x002);
+
+ sp887x_setup_agc(i2c);
+
+ /* bit 0x010: enable data valid signal */
+ sp887x_writereg(i2c, 0xd00, 0x010);
+ sp887x_writereg(i2c, 0x0d1, 0x000);
+
+ /* enable TS output and interface pins */
+ sp887x_writereg(i2c, 0xc18, 0x00d);
+
+ return 0;
+};
static
int sp887x_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
{
+ struct sp887x_state *state = (struct sp887x_state *) fe->data;
+ struct i2c_adapter *i2c = state->i2c;
+
switch (cmd) {
case FE_GET_INFO:
memcpy (arg, &sp887x_info, sizeof(struct dvb_frontend_info));
@@ -543,9 +444,9 @@
case FE_READ_STATUS:
{
- u16 snr12 = sp887x_readreg(fe, 0xf16);
- u16 sync0x200 = sp887x_readreg(fe, 0x200);
- u16 sync0xf17 = sp887x_readreg(fe, 0xf17);
+ u16 snr12 = sp887x_readreg(i2c, 0xf16);
+ u16 sync0x200 = sp887x_readreg(i2c, 0x200);
+ u16 sync0xf17 = sp887x_readreg(i2c, 0xf17);
fe_status_t *status = arg;
*status = 0;
@@ -579,10 +480,10 @@
case FE_READ_BER:
{
u32* ber = arg;
- *ber = (sp887x_readreg(fe, 0xc08) & 0x3f) |
- (sp887x_readreg(fe, 0xc07) << 6);
- sp887x_writereg(fe, 0xc08, 0x000);
- sp887x_writereg(fe, 0xc07, 0x000);
+ *ber = (sp887x_readreg(i2c, 0xc08) & 0x3f) |
+ (sp887x_readreg(i2c, 0xc07) << 6);
+ sp887x_writereg(i2c, 0xc08, 0x000);
+ sp887x_writereg(i2c, 0xc07, 0x000);
if (*ber >= 0x3fff0)
*ber = ~0;
break;
@@ -591,7 +492,7 @@
case FE_READ_SIGNAL_STRENGTH: // FIXME: correct registers ?
{
- u16 snr12 = sp887x_readreg(fe, 0xf16);
+ u16 snr12 = sp887x_readreg(i2c, 0xf16);
u32 signal = 3 * (snr12 << 4);
*((u16*) arg) = (signal < 0xffff) ? signal : 0xffff;
break;
@@ -599,7 +500,7 @@
case FE_READ_SNR:
{
- u16 snr12 = sp887x_readreg(fe, 0xf16);
+ u16 snr12 = sp887x_readreg(i2c, 0xf16);
*(u16*) arg = (snr12 << 4) | (snr12 >> 8);
break;
}
@@ -607,30 +508,30 @@
case FE_READ_UNCORRECTED_BLOCKS:
{
u32 *ublocks = (u32 *) arg;
- *ublocks = sp887x_readreg(fe, 0xc0c);
+ *ublocks = sp887x_readreg(i2c, 0xc0c);
if (*ublocks == 0xfff)
*ublocks = ~0;
break;
}
case FE_SET_FRONTEND:
- return sp887x_setup_frontend_parameters(fe, arg);
+ return sp887x_setup_frontend_parameters(i2c, arg);
case FE_GET_FRONTEND: // FIXME: read known values back from Hardware...
- break;
+ return -EOPNOTSUPP;
case FE_SLEEP:
/* tristate TS output and disable interface pins */
- sp887x_writereg(fe, 0xc18, 0x000);
+ sp887x_writereg(i2c, 0xc18, 0x000);
break;
case FE_INIT:
- if (fe->data == NULL) { /* first time initialisation... */
- fe->data = (void*) ~0;
- sp887x_initial_setup (fe);
- }
- /* enable TS output and interface pins */
- sp887x_writereg(fe, 0xc18, 0x00d);
+ if (state->initialized)
+ return 0;
+
+ sp887x_init(i2c);
+
+ state->initialized = 1;
break;
case FE_GET_TUNE_SETTINGS:
@@ -649,51 +550,193 @@
return 0;
}
+#define BLOCKSIZE 30
+int sp887x_load_firmware(struct i2c_adapter *i2c,
+ struct firmware *fw)
+{
+ u8 buf [BLOCKSIZE+2];
+ int i;
+ dprintk("%s\n", __FUNCTION__);
-static
-int sp887x_attach (struct dvb_i2c_bus *i2c, void **data)
+ /* soft reset */
+ sp887x_writereg(i2c, 0xf1a, 0x000);
+
+ sp887x_microcontroller_stop (i2c);
+
+ if (fw->size != 0x4000) {
+ printk(KERN_ERR "sp887x: Invalid firmware size.\n");
+ return -EINVAL;
+ }
+
+ printk ("%s: firmware upload... ", __FUNCTION__);
+
+ /* setup write pointer to -1 (end of memory) */
+ /* bit 0x8000 in address is set to enable 13bit mode */
+ sp887x_writereg(i2c, 0x8f08, 0x1fff);
+
+ /* dummy write (wrap around to start of memory) */
+ sp887x_writereg(i2c, 0x8f0a, 0x0000);
+
+ for (i=10; i<fw->size; i+=BLOCKSIZE) {
+ int c = BLOCKSIZE;
+ int err;
+
+ 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 */
+ /* write register is 0xf0a */
+ buf[0] = 0xcf;
+ buf[1] = 0x0a;
+
+ memcpy(&buf[2], fw->data + i, c);
+
+ if ((err = i2c_writebytes (i2c, 0x70, buf, c+2)) < 0) {
+ printk ("failed.\n");
+ printk ("%s: i2c error (err == %i)\n", __FUNCTION__, err);
+ release_firmware(fw);
+ return err;
+ }
+ }
+
+ release_firmware(fw);
+ return 0;
+}
+
+static struct i2c_client client_template;
+
+static int attach_adapter (struct i2c_adapter *adapter)
{
+ struct sp887x_state *state;
+ struct i2c_client *client;
+ const struct firmware *fw;
+ int ret;
+
struct i2c_msg msg = {.addr = 0x70, .flags = 0, .buf = NULL, .len = 0 };
dprintk ("%s\n", __FUNCTION__);
- if (i2c->xfer (i2c, &msg, 1) != 1)
+ if (i2c_transfer(adapter, &msg, 1) != 1)
return -ENODEV;
- return dvb_register_frontend (sp887x_ioctl, i2c, NULL, &sp887x_info);
-}
+ if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)))
+ return -ENOMEM;
+
+ if (NULL == (state = kmalloc(sizeof(struct sp887x_state), GFP_KERNEL))) {
+ kfree(client);
+ return -ENOMEM;
+ }
+ state->i2c = adapter;
+ state->dvb = NULL;
+ state->initialized = 0;
-static
-void sp887x_detach (struct dvb_i2c_bus *i2c, void *data)
+ memcpy(client, &client_template, sizeof(struct i2c_client));
+ client->adapter = adapter;
+ client->addr = 0x70;
+ i2c_set_clientdata(client, state);
+
+ ret = i2c_attach_client(client);
+ if (ret) {
+ kfree(state);
+ kfree(client);
+ return ret;
+ }
+
+ BUG_ON(!state->dvb);
+
+ printk(KERN_INFO "sp887x: waiting for firmware..\n");
+ ret = request_firmware(&fw, "dvb-fe-sp887x.fw", &client->dev);
+ if (ret) {
+ printk(KERN_ERR "sp887x: unable to load firmware.\n");
+ goto out;
+ }
+
+ ret = dvb_register_frontend_new(sp887x_ioctl, state->dvb,
+ state, &sp887x_info);
+ if (ret) {
+ printk(KERN_ERR "sp887x: unable to register frontend.\n");
+ goto out;
+ }
+
+ return 0;
+out:
+ i2c_detach_client(client);
+ kfree(client);
+ kfree(state);
+ return ret;
+}
+
+static int detach_client (struct i2c_client *client)
{
+ struct sp887x_state *state = i2c_get_clientdata(client);
+
dprintk ("%s\n", __FUNCTION__);
- dvb_unregister_frontend (sp887x_ioctl, i2c);
-}
+
+ dvb_unregister_frontend_new (sp887x_ioctl, state->dvb);
+ i2c_detach_client(client);
+ BUG_ON(state->dvb);
+ kfree(client);
+ kfree(state);
+ return 0;
+}
-static
-int __init init_sp887x (void)
+static int command (struct i2c_client *client, unsigned int cmd, void *arg)
{
+ struct sp887x_state *state = (struct sp887x_state*)i2c_get_clientdata(client);
+
dprintk ("%s\n", __FUNCTION__);
- return dvb_register_i2c_device (NULL, sp887x_attach, sp887x_detach);
+
+ switch (cmd) {
+ case FE_REGISTER:
+ state->dvb = (struct dvb_adapter*)arg;
+ break;
+
+ case FE_UNREGISTER:
+ state->dvb = NULL;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
}
+static struct i2c_driver driver = {
+ .owner = THIS_MODULE,
+ .name = "sp887x",
+ .id = I2C_DRIVERID_SP887X,
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = attach_adapter,
+ .detach_client = detach_client,
+ .command = command,
+};
-static
-void __exit exit_sp887x (void)
+static struct i2c_client client_template = {
+ I2C_DEVNAME("sp887x"),
+ .flags = I2C_CLIENT_ALLOW_USE,
+ .driver = &driver,
+};
+
+static int __init init_sp887x (void)
{
dprintk ("%s\n", __FUNCTION__);
- dvb_unregister_i2c_device (sp887x_attach);
+ return i2c_add_driver (&driver);
}
+static void __exit exit_sp887x (void)
+{
+ dprintk ("%s\n", __FUNCTION__);
+ if (i2c_del_driver (&driver))
+ printk(KERN_ERR "sp887x: driver deregistration failed.\n");
+}
module_init(init_sp887x);
module_exit(exit_sp887x);
-
MODULE_DESCRIPTION("sp887x DVB-T demodulator driver");
MODULE_LICENSE("GPL");
-
Home |
Main Index |
Thread Index