From f9ada374f07fa8c09c15262ffd26371beacb1e98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Andr=C3=A9n?= Date: Wed, 27 Jul 2011 17:18:44 -0300 Subject: [media] gspca-stv06xx: Simplify register writes by avoiding special data structures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Erik Andrén Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.h b/drivers/media/video/gspca/stv06xx/stv06xx.h index e0f63c5..d270a59 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx.h +++ b/drivers/media/video/gspca/stv06xx/stv06xx.h @@ -37,6 +37,8 @@ #define STV_ISOC_ENDPOINT_ADDR 0x81 +#define STV_R 0x0509 + #define STV_REG23 0x0423 /* Control registers of the STV0600 ASIC */ @@ -61,7 +63,9 @@ /* Refers to the CIF 352x288 and QCIF 176x144 */ /* 1: 288 lines, 2: 144 lines */ -#define STV_Y_CTRL 0x15c3 +#define STV_Y_CTRL 0x15c3 + +#define STV_RESET 0x1620 /* 0xa: 352 columns, 0x6: 176 columns */ #define STV_X_CTRL 0x1680 diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h index 7fe3587..c7615c2 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h +++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h @@ -216,22 +216,23 @@ struct stv_init { u8 len; }; -static const u8 x1500[] = { /* 0x1500 - 0x150f */ - 0x0b, 0xa7, 0xb7, 0x00, 0x00 -}; - -static const u8 x1536[] = { /* 0x1536 - 0x153b */ - 0x02, 0x00, 0x60, 0x01, 0x20, 0x01 -}; - static const struct stv_init stv_bridge_init[] = { /* This reg is written twice. Some kind of reset? */ - {NULL, 0x1620, 0x80}, - {NULL, 0x1620, 0x00}, - {NULL, 0x1443, 0x00}, - {NULL, 0x1423, 0x04}, - {x1500, 0x1500, ARRAY_SIZE(x1500)}, - {x1536, 0x1536, ARRAY_SIZE(x1536)}, + {NULL, STV_RESET, 0x80}, + {NULL, STV_RESET, 0x00}, + {NULL, STV_SCAN_RATE, 0x00}, + {NULL, STV_I2C_FLUSH, 0x04}, + {NULL, STV_REG00, 0x0b}, + {NULL, STV_REG01, 0xa7}, + {NULL, STV_REG02, 0xb7}, + {NULL, STV_REG03, 0x00}, + {NULL, STV_REG04, 0x00}, + {NULL, 0x1536, 0x02}, + {NULL, 0x1537, 0x00}, + {NULL, 0x1538, 0x60}, + {NULL, 0x1539, 0x01}, + {NULL, 0x153a, 0x20}, + {NULL, 0x153b, 0x01}, }; static const u8 vv6410_sensor_init[][2] = { @@ -240,7 +241,7 @@ static const u8 vv6410_sensor_init[][2] = { {VV6410_SETUP0, VV6410_LOW_POWER_MODE}, /* Use shuffled read-out mode */ {VV6410_SETUP1, BIT(6)}, - /* All modes to 1 */ + /* All modes to 1, FST, Fast QCK, Free running QCK, Free running LST, FST will qualify visible pixels */ {VV6410_FGMODES, BIT(6) | BIT(4) | BIT(2) | BIT(0)}, {VV6410_PINMAPPING, 0x00}, /* Pre-clock generator divide off */ -- cgit v0.10.2 From 46fecfaf786a35ce6dc024a70ae1e768ee44e803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Andr=C3=A9n?= Date: Wed, 27 Jul 2011 17:19:58 -0300 Subject: [media] gspca-stv06xx: Simplify stv_init struct and vv6410 bridge init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Erik Andrén Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c index f839843..51b6659 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c @@ -138,18 +138,7 @@ static int vv6410_init(struct sd *sd) s32 *sensor_settings = sd->sensor_priv; for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++) { - /* if NULL then len contains single value */ - if (stv_bridge_init[i].data == NULL) { - err = stv06xx_write_bridge(sd, - stv_bridge_init[i].start, - stv_bridge_init[i].len); - } else { - int j; - for (j = 0; j < stv_bridge_init[i].len; j++) - err = stv06xx_write_bridge(sd, - stv_bridge_init[i].start + j, - stv_bridge_init[i].data[j]); - } + stv06xx_write_bridge(sd, stv_bridge_init[i].addr, stv_bridge_init[i].data); } if (err < 0) diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h index c7615c2..f75c336 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h +++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h @@ -211,28 +211,27 @@ const struct stv06xx_sensor stv06xx_sensor_vv6410 = { /* If NULL, only single value to write, stored in len */ struct stv_init { - const u8 *data; - u16 start; - u8 len; + u16 addr; + u8 data; }; static const struct stv_init stv_bridge_init[] = { /* This reg is written twice. Some kind of reset? */ - {NULL, STV_RESET, 0x80}, - {NULL, STV_RESET, 0x00}, - {NULL, STV_SCAN_RATE, 0x00}, - {NULL, STV_I2C_FLUSH, 0x04}, - {NULL, STV_REG00, 0x0b}, - {NULL, STV_REG01, 0xa7}, - {NULL, STV_REG02, 0xb7}, - {NULL, STV_REG03, 0x00}, - {NULL, STV_REG04, 0x00}, - {NULL, 0x1536, 0x02}, - {NULL, 0x1537, 0x00}, - {NULL, 0x1538, 0x60}, - {NULL, 0x1539, 0x01}, - {NULL, 0x153a, 0x20}, - {NULL, 0x153b, 0x01}, + {STV_RESET, 0x80}, + {STV_RESET, 0x00}, + {STV_SCAN_RATE, 0x00}, + {STV_I2C_FLUSH, 0x04}, + {STV_REG00, 0x0b}, + {STV_REG01, 0xa7}, + {STV_REG02, 0xb7}, + {STV_REG03, 0x00}, + {STV_REG04, 0x00}, + {0x1536, 0x02}, + {0x1537, 0x00}, + {0x1538, 0x60}, + {0x1539, 0x01}, + {0x153a, 0x20}, + {0x153b, 0x01}, }; static const u8 vv6410_sensor_init[][2] = { -- cgit v0.10.2 From a0917ca4d776db110b129d148fffe3dba97ea9a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Andr=C3=A9n?= Date: Wed, 27 Jul 2011 17:20:38 -0300 Subject: [media] gspca-stv06xx: Fix sensor init indentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No functional changes on this patch. Signed-off-by: Erik Andrén Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h index f75c336..a25b887 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h +++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h @@ -236,24 +236,24 @@ static const struct stv_init stv_bridge_init[] = { static const u8 vv6410_sensor_init[][2] = { /* Setup registers */ - {VV6410_SETUP0, VV6410_SOFT_RESET}, - {VV6410_SETUP0, VV6410_LOW_POWER_MODE}, + {VV6410_SETUP0, VV6410_SOFT_RESET}, + {VV6410_SETUP0, VV6410_LOW_POWER_MODE}, /* Use shuffled read-out mode */ - {VV6410_SETUP1, BIT(6)}, + {VV6410_SETUP1, BIT(6)}, /* All modes to 1, FST, Fast QCK, Free running QCK, Free running LST, FST will qualify visible pixels */ - {VV6410_FGMODES, BIT(6) | BIT(4) | BIT(2) | BIT(0)}, - {VV6410_PINMAPPING, 0x00}, + {VV6410_FGMODES, BIT(6) | BIT(4) | BIT(2) | BIT(0)}, + {VV6410_PINMAPPING, 0x00}, /* Pre-clock generator divide off */ - {VV6410_DATAFORMAT, BIT(7) | BIT(0)}, + {VV6410_DATAFORMAT, BIT(7) | BIT(0)}, - {VV6410_CLKDIV, VV6410_CLK_DIV_2}, + {VV6410_CLKDIV, VV6410_CLK_DIV_2}, /* System registers */ /* Enable voltage doubler */ - {VV6410_AS0, BIT(6) | BIT(4) | BIT(3) | BIT(2) | BIT(1)}, - {VV6410_AT0, 0x00}, + {VV6410_AS0, BIT(6) | BIT(4) | BIT(3) | BIT(2) | BIT(1)}, + {VV6410_AT0, 0x00}, /* Power up audio, differential */ - {VV6410_AT1, BIT(4)|BIT(0)}, + {VV6410_AT1, BIT(4) | BIT(0)}, }; #endif -- cgit v0.10.2 From d6c5441f6204219fce7aefbe3e5ffead3815ef99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Andr=C3=A9n?= Date: Wed, 27 Jul 2011 17:21:14 -0300 Subject: [media] gspca-stv06xx: Remove writes to read-only registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Erik Andrén Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c index 51b6659..308add8 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c @@ -172,15 +172,6 @@ static int vv6410_start(struct sd *sd) struct cam *cam = &sd->gspca_dev.cam; u32 priv = cam->cam_mode[sd->gspca_dev.curr_mode].priv; - if (priv & VV6410_CROP_TO_QVGA) { - PDEBUG(D_CONF, "Cropping to QVGA"); - stv06xx_write_sensor(sd, VV6410_XENDH, 320 - 1); - stv06xx_write_sensor(sd, VV6410_YENDH, 240 - 1); - } else { - stv06xx_write_sensor(sd, VV6410_XENDH, 360 - 1); - stv06xx_write_sensor(sd, VV6410_YENDH, 294 - 1); - } - if (priv & VV6410_SUBSAMPLE) { PDEBUG(D_CONF, "Enabling subsampling"); stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02); -- cgit v0.10.2 From eaceba650dea4af61f6f3a4919caa096bb4c2929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Andr=C3=A9n?= Date: Wed, 27 Jul 2011 17:21:49 -0300 Subject: [media] gspca-stv06xx: Triple frame rate by decreasing the scan rate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Erik Andrén Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c index 308add8..b05a154 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c @@ -181,8 +181,8 @@ static int vv6410_start(struct sd *sd) } else { stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01); stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a); + stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x00); - stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x20); } /* Turn on LED */ -- cgit v0.10.2 From b05681b91709a19b40a452f566cc852619b30082 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 29 Jul 2011 02:23:20 -0300 Subject: [media] rc-main: Fix device de-registration logic rc unregister logic were deadly broken, preventing some drivers to be removed. Among the broken things, rc_dev_uevent() is being called during device_del(), causing a data filling on an area that it is not ready anymore. Also, some drivers have a stop callback defined, that needs to be called before data removal, as it stops data polling. Acked-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 51a23f4..666d4bb 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -928,10 +928,6 @@ out: static void rc_dev_release(struct device *device) { - struct rc_dev *dev = to_rc_dev(device); - - kfree(dev); - module_put(THIS_MODULE); } #define ADD_HOTPLUG_VAR(fmt, val...) \ @@ -945,6 +941,9 @@ static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env) { struct rc_dev *dev = to_rc_dev(device); + if (!dev || !dev->input_dev) + return -ENODEV; + if (dev->rc_map.name) ADD_HOTPLUG_VAR("NAME=%s", dev->rc_map.name); if (dev->driver_name) @@ -1013,10 +1012,16 @@ EXPORT_SYMBOL_GPL(rc_allocate_device); void rc_free_device(struct rc_dev *dev) { - if (dev) { + if (!dev) + return; + + if (dev->input_dev) input_free_device(dev->input_dev); - put_device(&dev->dev); - } + + put_device(&dev->dev); + + kfree(dev); + module_put(THIS_MODULE); } EXPORT_SYMBOL_GPL(rc_free_device); @@ -1143,14 +1148,18 @@ void rc_unregister_device(struct rc_dev *dev) if (dev->driver_type == RC_DRIVER_IR_RAW) ir_raw_event_unregister(dev); + /* Freeing the table should also call the stop callback */ + ir_free_table(&dev->rc_map); + IR_dprintk(1, "Freed keycode table\n"); + input_unregister_device(dev->input_dev); dev->input_dev = NULL; - ir_free_table(&dev->rc_map); - IR_dprintk(1, "Freed keycode table\n"); + device_del(&dev->dev); - device_unregister(&dev->dev); + rc_free_device(dev); } + EXPORT_SYMBOL_GPL(rc_unregister_device); /* -- cgit v0.10.2 From 6d51477470728074cea396a0127d73c5590dd441 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 29 Jul 2011 02:26:59 -0300 Subject: [media] em28xx: Fix IR unregister logic The input stop() callback already calls the em28xx_ir_stop method. Calling it again causes an oops. Acked-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c index 5d12b14..679da48 100644 --- a/drivers/media/video/em28xx/em28xx-input.c +++ b/drivers/media/video/em28xx/em28xx-input.c @@ -463,11 +463,11 @@ int em28xx_ir_fini(struct em28xx *dev) if (!ir) return 0; - em28xx_ir_stop(ir->rc); - rc_unregister_device(ir->rc); - kfree(ir); + if (ir->rc) + rc_unregister_device(ir->rc); /* done */ + kfree(ir); dev->ir = NULL; return 0; } -- cgit v0.10.2 From bfd4500c9abf3e70e9c563bcba5675bd302f5a4e Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 24 Jul 2011 20:29:16 -0300 Subject: [media] dvb-usb: prepare for multi-frontend support (MFE) Change adapter FE pointer as array of FE pointers. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c index 51f6439..753b86e 100644 --- a/drivers/media/dvb/dvb-usb/af9005.c +++ b/drivers/media/dvb/dvb-usb/af9005.c @@ -815,7 +815,7 @@ static int af9005_frontend_attach(struct dvb_usb_adapter *adap) debug_dump(buf, 8, printk); } } - adap->fe = af9005_fe_attach(adap->dev); + adap->fe[0] = af9005_fe_attach(adap->dev); return 0; } diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index d7ad05f..f966b0b 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -1111,10 +1111,10 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) } /* attach demodulator */ - adap->fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id], + adap->fe[0] = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id], &adap->dev->i2c_adap); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } static struct mt2060_config af9015_mt2060_config = { @@ -1188,49 +1188,49 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap) switch (af9015_af9013_config[adap->id].tuner) { case AF9013_TUNER_MT2060: case AF9013_TUNER_MT2060_2: - ret = dvb_attach(mt2060_attach, adap->fe, &adap->dev->i2c_adap, + ret = dvb_attach(mt2060_attach, adap->fe[0], &adap->dev->i2c_adap, &af9015_mt2060_config, af9015_config.mt2060_if1[adap->id]) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_QT1010: case AF9013_TUNER_QT1010A: - ret = dvb_attach(qt1010_attach, adap->fe, &adap->dev->i2c_adap, + ret = dvb_attach(qt1010_attach, adap->fe[0], &adap->dev->i2c_adap, &af9015_qt1010_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_TDA18271: - ret = dvb_attach(tda18271_attach, adap->fe, 0xc0, + ret = dvb_attach(tda18271_attach, adap->fe[0], 0xc0, &adap->dev->i2c_adap, &af9015_tda18271_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_TDA18218: - ret = dvb_attach(tda18218_attach, adap->fe, + ret = dvb_attach(tda18218_attach, adap->fe[0], &adap->dev->i2c_adap, &af9015_tda18218_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5003D: - ret = dvb_attach(mxl5005s_attach, adap->fe, + ret = dvb_attach(mxl5005s_attach, adap->fe[0], &adap->dev->i2c_adap, &af9015_mxl5003_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5005D: case AF9013_TUNER_MXL5005R: - ret = dvb_attach(mxl5005s_attach, adap->fe, + ret = dvb_attach(mxl5005s_attach, adap->fe[0], &adap->dev->i2c_adap, &af9015_mxl5005_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_ENV77H11D5: - ret = dvb_attach(dvb_pll_attach, adap->fe, 0xc0, + ret = dvb_attach(dvb_pll_attach, adap->fe[0], 0xc0, &adap->dev->i2c_adap, DVB_PLL_TDA665X) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MC44S803: - ret = dvb_attach(mc44s803_attach, adap->fe, + ret = dvb_attach(mc44s803_attach, adap->fe[0], &adap->dev->i2c_adap, &af9015_mc44s803_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5007T: - ret = dvb_attach(mxl5007t_attach, adap->fe, + ret = dvb_attach(mxl5007t_attach, adap->fe[0], &adap->dev->i2c_adap, 0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0; break; diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c index 2cbf19a..1ec88b6 100644 --- a/drivers/media/dvb/dvb-usb/anysee.c +++ b/drivers/media/dvb/dvb-usb/anysee.c @@ -488,13 +488,13 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) /* E30 */ /* attach demod */ - adap->fe = dvb_attach(mt352_attach, &anysee_mt352_config, + adap->fe[0] = dvb_attach(mt352_attach, &anysee_mt352_config, &adap->dev->i2c_adap); - if (adap->fe) + if (adap->fe[0]) break; /* attach demod */ - adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config, + adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_config, &adap->dev->i2c_adap); break; @@ -512,7 +512,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) goto error; /* attach demod */ - adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config, + adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_config, &adap->dev->i2c_adap); break; @@ -525,7 +525,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) goto error; /* attach demod */ - adap->fe = dvb_attach(tda10023_attach, &anysee_tda10023_config, + adap->fe[0] = dvb_attach(tda10023_attach, &anysee_tda10023_config, &adap->dev->i2c_adap, 0x48); break; @@ -538,7 +538,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) goto error; /* attach demod */ - adap->fe = dvb_attach(cx24116_attach, &anysee_cx24116_config, + adap->fe[0] = dvb_attach(cx24116_attach, &anysee_cx24116_config, &adap->dev->i2c_adap); break; @@ -580,12 +580,12 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) /* attach demod */ if (tmp == 0xc7) { /* TDA18212 config */ - adap->fe = dvb_attach(zl10353_attach, + adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_tda18212_config2, &adap->dev->i2c_adap); } else { /* PLL config */ - adap->fe = dvb_attach(zl10353_attach, + adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_config, &adap->dev->i2c_adap); } @@ -605,12 +605,12 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) /* attach demod */ if (tmp == 0xc7) { /* TDA18212 config */ - adap->fe = dvb_attach(tda10023_attach, + adap->fe[0] = dvb_attach(tda10023_attach, &anysee_tda10023_tda18212_config, &adap->dev->i2c_adap, 0x48); } else { /* PLL config */ - adap->fe = dvb_attach(tda10023_attach, + adap->fe[0] = dvb_attach(tda10023_attach, &anysee_tda10023_config, &adap->dev->i2c_adap, 0x48); } @@ -647,7 +647,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) goto error; /* attach demod */ - adap->fe = dvb_attach(zl10353_attach, + adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_tda18212_config, &adap->dev->i2c_adap); } else { @@ -670,7 +670,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) goto error; /* attach demod */ - adap->fe = dvb_attach(tda10023_attach, + adap->fe[0] = dvb_attach(tda10023_attach, &anysee_tda10023_tda18212_config, &adap->dev->i2c_adap, 0x48); } @@ -692,13 +692,13 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) goto error; /* attach demod */ - adap->fe = dvb_attach(stv0900_attach, &anysee_stv0900_config, + adap->fe[0] = dvb_attach(stv0900_attach, &anysee_stv0900_config, &adap->dev->i2c_adap, 0); break; } - if (!adap->fe) { + if (!adap->fe[0]) { /* we have no frontend :-( */ ret = -ENODEV; err("Unsupported Anysee version. " \ @@ -720,7 +720,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E30 */ /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc2 >> 1), + fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc2 >> 1), NULL, DVB_PLL_THOMSON_DTT7579); break; @@ -728,7 +728,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E30 Plus */ /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc2 >> 1), + fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc2 >> 1), &adap->dev->i2c_adap, DVB_PLL_THOMSON_DTT7579); break; @@ -736,7 +736,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E30 C Plus */ /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc0 >> 1), + fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1), &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); break; @@ -744,7 +744,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E30 S2 Plus */ /* attach LNB controller */ - fe = dvb_attach(isl6423_attach, adap->fe, &adap->dev->i2c_adap, + fe = dvb_attach(isl6423_attach, adap->fe[0], &adap->dev->i2c_adap, &anysee_isl6423_config); break; @@ -775,7 +775,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) goto error; /* attach tuner */ - fe = dvb_attach(tda18212_attach, adap->fe, &adap->dev->i2c_adap, + fe = dvb_attach(tda18212_attach, adap->fe[0], &adap->dev->i2c_adap, &anysee_tda18212_config); if (fe) break; @@ -786,7 +786,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) goto error; /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc0 >> 1), + fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1), &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); break; @@ -801,7 +801,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) goto error; /* attach tuner */ - fe = dvb_attach(tda18212_attach, adap->fe, &adap->dev->i2c_adap, + fe = dvb_attach(tda18212_attach, adap->fe[0], &adap->dev->i2c_adap, &anysee_tda18212_config); break; @@ -811,12 +811,12 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E7 PS2 */ /* attach tuner */ - fe = dvb_attach(stv6110_attach, adap->fe, + fe = dvb_attach(stv6110_attach, adap->fe[0], &anysee_stv6110_config, &adap->dev->i2c_adap); if (fe) { /* attach LNB controller */ - fe = dvb_attach(isl6423_attach, adap->fe, + fe = dvb_attach(isl6423_attach, adap->fe[0], &adap->dev->i2c_adap, &anysee_isl6423_config); } diff --git a/drivers/media/dvb/dvb-usb/au6610.c b/drivers/media/dvb/dvb-usb/au6610.c index 2351077..ebe6e1f 100644 --- a/drivers/media/dvb/dvb-usb/au6610.c +++ b/drivers/media/dvb/dvb-usb/au6610.c @@ -140,9 +140,9 @@ static struct zl10353_config au6610_zl10353_config = { static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap) { - adap->fe = dvb_attach(zl10353_attach, &au6610_zl10353_config, + adap->fe[0] = dvb_attach(zl10353_attach, &au6610_zl10353_config, &adap->dev->i2c_adap); - if (adap->fe == NULL) + if (adap->fe[0] == NULL) return -ENODEV; return 0; @@ -155,7 +155,7 @@ static struct qt1010_config au6610_qt1010_config = { static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap) { return dvb_attach(qt1010_attach, - adap->fe, &adap->dev->i2c_adap, + adap->fe[0], &adap->dev->i2c_adap, &au6610_qt1010_config) == NULL ? -ENODEV : 0; } diff --git a/drivers/media/dvb/dvb-usb/az6027.c b/drivers/media/dvb/dvb-usb/az6027.c index 57e2444..d59430c 100644 --- a/drivers/media/dvb/dvb-usb/az6027.c +++ b/drivers/media/dvb/dvb-usb/az6027.c @@ -910,16 +910,16 @@ static int az6027_frontend_attach(struct dvb_usb_adapter *adap) az6027_frontend_reset(adap); deb_info("adap = %p, dev = %p\n", adap, adap->dev); - adap->fe = stb0899_attach(&az6027_stb0899_config, &adap->dev->i2c_adap); + adap->fe[0] = stb0899_attach(&az6027_stb0899_config, &adap->dev->i2c_adap); - if (adap->fe) { + if (adap->fe[0]) { deb_info("found STB0899 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb0899_config.demod_address); - if (stb6100_attach(adap->fe, &az6027_stb6100_config, &adap->dev->i2c_adap)) { + if (stb6100_attach(adap->fe[0], &az6027_stb6100_config, &adap->dev->i2c_adap)) { deb_info("found STB6100 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb6100_config.tuner_address); - adap->fe->ops.set_voltage = az6027_set_voltage; + adap->fe[0]->ops.set_voltage = az6027_set_voltage; az6027_ci_init(adap); } else { - adap->fe = NULL; + adap->fe[0] = NULL; } } else warn("no front-end attached\n"); diff --git a/drivers/media/dvb/dvb-usb/ce6230.c b/drivers/media/dvb/dvb-usb/ce6230.c index 6d1a304..5655ce4 100644 --- a/drivers/media/dvb/dvb-usb/ce6230.c +++ b/drivers/media/dvb/dvb-usb/ce6230.c @@ -186,9 +186,9 @@ static struct zl10353_config ce6230_zl10353_config = { static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap) { deb_info("%s:\n", __func__); - adap->fe = dvb_attach(zl10353_attach, &ce6230_zl10353_config, + adap->fe[0] = dvb_attach(zl10353_attach, &ce6230_zl10353_config, &adap->dev->i2c_adap); - if (adap->fe == NULL) + if (adap->fe[0] == NULL) return -ENODEV; return 0; } @@ -214,7 +214,7 @@ static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) { int ret; deb_info("%s:\n", __func__); - ret = dvb_attach(mxl5005s_attach, adap->fe, &adap->dev->i2c_adap, + ret = dvb_attach(mxl5005s_attach, adap->fe[0], &adap->dev->i2c_adap, &ce6230_mxl5003s_config) == NULL ? -ENODEV : 0; return ret; } diff --git a/drivers/media/dvb/dvb-usb/cinergyT2-core.c b/drivers/media/dvb/dvb-usb/cinergyT2-core.c index 16f2ce2..0dd42bd 100644 --- a/drivers/media/dvb/dvb-usb/cinergyT2-core.c +++ b/drivers/media/dvb/dvb-usb/cinergyT2-core.c @@ -69,7 +69,7 @@ static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap) char state[3]; int ret; - adap->fe = cinergyt2_fe_attach(adap->dev); + adap->fe[0] = cinergyt2_fe_attach(adap->dev); ret = dvb_usb_generic_rw(adap->dev, query, sizeof(query), state, sizeof(state), 0); diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index acb5fb2..a76f431 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -725,7 +725,7 @@ static struct max2165_config mygica_d689_max2165_cfg = { /* Callbacks for DVB USB */ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(simple_tuner_attach, adap->fe, + dvb_attach(simple_tuner_attach, adap->fe[0], &adap->dev->i2c_adap, 0x61, TUNER_PHILIPS_FMD1216ME_MK3); return 0; @@ -733,27 +733,27 @@ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) static int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(dvb_pll_attach, adap->fe, 0x61, + dvb_attach(dvb_pll_attach, adap->fe[0], 0x61, NULL, DVB_PLL_THOMSON_DTT7579); return 0; } static int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, DVB_PLL_LG_Z201); + dvb_attach(dvb_pll_attach, adap->fe[0], 0x61, NULL, DVB_PLL_LG_Z201); return 0; } static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(dvb_pll_attach, adap->fe, 0x60, + dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, NULL, DVB_PLL_THOMSON_DTT7579); return 0; } static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(simple_tuner_attach, adap->fe, + dvb_attach(simple_tuner_attach, adap->fe[0], &adap->dev->i2c_adap, 0x61, TUNER_LG_TDVS_H06XF); return 0; } @@ -795,9 +795,9 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap) }; /* FIXME: generalize & move to common area */ - adap->fe->callback = dvico_bluebird_xc2028_callback; + adap->fe[0]->callback = dvico_bluebird_xc2028_callback; - fe = dvb_attach(xc2028_attach, adap->fe, &cfg); + fe = dvb_attach(xc2028_attach, adap->fe[0], &cfg); if (fe == NULL || fe->ops.tuner_ops.set_config == NULL) return -EIO; @@ -808,7 +808,7 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap) static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(mxl5005s_attach, adap->fe, + dvb_attach(mxl5005s_attach, adap->fe[0], &adap->dev->i2c_adap, &aver_a868r_tuner); return 0; } @@ -816,7 +816,7 @@ static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap) { struct dvb_frontend *fe; - fe = dvb_attach(mxl5005s_attach, adap->fe, + fe = dvb_attach(mxl5005s_attach, adap->fe[0], &adap->dev->i2c_adap, &d680_dmb_tuner); return (fe == NULL) ? -EIO : 0; } @@ -824,7 +824,7 @@ static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap) static int cxusb_mygica_d689_tuner_attach(struct dvb_usb_adapter *adap) { struct dvb_frontend *fe; - fe = dvb_attach(max2165_attach, adap->fe, + fe = dvb_attach(max2165_attach, adap->fe[0], &adap->dev->i2c_adap, &mygica_d689_max2165_cfg); return (fe == NULL) ? -EIO : 0; } @@ -837,7 +837,7 @@ static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap) cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, &b, 1); - if ((adap->fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config, + if ((adap->fe[0] = dvb_attach(cx22702_attach, &cxusb_cx22702_config, &adap->dev->i2c_adap)) != NULL) return 0; @@ -851,7 +851,7 @@ static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - if ((adap->fe = dvb_attach(lgdt330x_attach, &cxusb_lgdt3303_config, + if ((adap->fe[0] = dvb_attach(lgdt330x_attach, &cxusb_lgdt3303_config, &adap->dev->i2c_adap)) != NULL) return 0; @@ -860,9 +860,9 @@ static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) static int cxusb_aver_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) { - adap->fe = dvb_attach(lgdt330x_attach, &cxusb_aver_lgdt3303_config, + adap->fe[0] = dvb_attach(lgdt330x_attach, &cxusb_aver_lgdt3303_config, &adap->dev->i2c_adap); - if (adap->fe != NULL) + if (adap->fe[0] != NULL) return 0; return -EIO; @@ -876,7 +876,7 @@ static int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap) cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - if ((adap->fe = dvb_attach(mt352_attach, &cxusb_mt352_config, + if ((adap->fe[0] = dvb_attach(mt352_attach, &cxusb_mt352_config, &adap->dev->i2c_adap)) != NULL) return 0; @@ -890,9 +890,9 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap) cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - if (((adap->fe = dvb_attach(mt352_attach, &cxusb_dee1601_config, + if (((adap->fe[0] = dvb_attach(mt352_attach, &cxusb_dee1601_config, &adap->dev->i2c_adap)) != NULL) || - ((adap->fe = dvb_attach(zl10353_attach, + ((adap->fe[0] = dvb_attach(zl10353_attach, &cxusb_zl10353_dee1601_config, &adap->dev->i2c_adap)) != NULL)) return 0; @@ -917,7 +917,7 @@ static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap) cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1); cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); - if ((adap->fe = dvb_attach(zl10353_attach, + if ((adap->fe[0] = dvb_attach(zl10353_attach, &cxusb_zl10353_xc3028_config_no_i2c_gate, &adap->dev->i2c_adap)) == NULL) return -EIO; @@ -1031,9 +1031,9 @@ static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap) return -ENODEV; } - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, + adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &cxusb_dualdig4_rev2_config); - if (adap->fe == NULL) + if (adap->fe[0] == NULL) return -EIO; return 0; @@ -1084,15 +1084,15 @@ static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; struct i2c_adapter *tun_i2c = - dib7000p_get_i2c_master(adap->fe, + dib7000p_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); - if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, + if (dvb_attach(dib0070_attach, adap->fe[0], tun_i2c, &dib7070p_dib0070_config) == NULL) return -ENODEV; - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib7070_set_param_override; + st->set_param_save = adap->fe[0]->ops.tuner_ops.set_params; + adap->fe[0]->ops.tuner_ops.set_params = dib7070_set_param_override; return 0; } @@ -1108,12 +1108,12 @@ static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap) cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1); cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); - if ((adap->fe = dvb_attach(zl10353_attach, + if ((adap->fe[0] = dvb_attach(zl10353_attach, &cxusb_zl10353_xc3028_config, &adap->dev->i2c_adap)) != NULL) return 0; - if ((adap->fe = dvb_attach(mt352_attach, + if ((adap->fe[0] = dvb_attach(mt352_attach, &cxusb_mt352_xc3028_config, &adap->dev->i2c_adap)) != NULL) return 0; @@ -1172,8 +1172,8 @@ static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap) msleep(100); /* Attach frontend */ - adap->fe = dvb_attach(lgs8gxx_attach, &d680_lgs8gl5_cfg, &d->i2c_adap); - if (adap->fe == NULL) + adap->fe[0] = dvb_attach(lgs8gxx_attach, &d680_lgs8gl5_cfg, &d->i2c_adap); + if (adap->fe[0] == NULL) return -EIO; return 0; @@ -1223,9 +1223,9 @@ static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap) msleep(100); /* Attach frontend */ - adap->fe = dvb_attach(atbm8830_attach, &mygica_d689_atbm8830_cfg, + adap->fe[0] = dvb_attach(atbm8830_attach, &mygica_d689_atbm8830_cfg, &d->i2c_adap); - if (adap->fe == NULL) + if (adap->fe[0] == NULL) return -EIO; return 0; diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index d0ea5b6..754f8ec 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -101,7 +101,7 @@ static int bristol_frontend_attach(struct dvb_usb_adapter *adap) } } st->mt2060_if1[adap->id] = 1220; - return (adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, + return (adap->fe[0] = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, (10 + adap->id) << 1, &bristol_dib3000mc_config[adap->id])) == NULL ? -ENODEV : 0; } @@ -118,14 +118,14 @@ static int eeprom_read(struct i2c_adapter *adap,u8 adrs,u8 *pval) static int bristol_tuner_attach(struct dvb_usb_adapter *adap) { struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap; - struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1); + struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe[0], 1); s8 a; int if1=1220; if (adap->dev->udev->descriptor.idVendor == cpu_to_le16(USB_VID_HAUPPAUGE) && adap->dev->udev->descriptor.idProduct == cpu_to_le16(USB_PID_HAUPPAUGE_NOVA_T_500_2)) { if (!eeprom_read(prim_i2c,0x59 + adap->id,&a)) if1=1220+a; } - return dvb_attach(mt2060_attach,adap->fe, tun_i2c,&bristol_mt2060_config[adap->id], + return dvb_attach(mt2060_attach,adap->fe[0], tun_i2c,&bristol_mt2060_config[adap->id], if1) == NULL ? -ENODEV : 0; } @@ -279,10 +279,10 @@ static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap) } } - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1), + adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1), &stk7700d_dib7000p_mt2266_config[adap->id]); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap) @@ -306,17 +306,17 @@ static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap) } } - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1), + adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1), &stk7700d_dib7000p_mt2266_config[adap->id]); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap) { struct i2c_adapter *tun_i2c; - tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); - return dvb_attach(mt2266_attach, adap->fe, tun_i2c, + tun_i2c = dib7000p_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); + return dvb_attach(mt2266_attach, adap->fe[0], tun_i2c, &stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0; } @@ -396,8 +396,8 @@ static int stk7700ph_xc3028_callback(void *ptr, int component, switch (command) { case XC2028_TUNER_RESET: /* Send the tuner in then out of reset */ - dib7000p_set_gpio(adap->fe, 8, 0, 0); msleep(10); - dib7000p_set_gpio(adap->fe, 8, 0, 1); + dib7000p_set_gpio(adap->fe[0], 8, 0, 0); msleep(10); + dib7000p_set_gpio(adap->fe[0], 8, 0, 1); break; case XC2028_RESET_CLK: break; @@ -447,25 +447,25 @@ static int stk7700ph_frontend_attach(struct dvb_usb_adapter *adap) return -ENODEV; } - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, + adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7700ph_dib7700_xc3028_config); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap) { struct i2c_adapter *tun_i2c; - tun_i2c = dib7000p_get_i2c_master(adap->fe, + tun_i2c = dib7000p_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); stk7700ph_xc3028_config.i2c_adap = tun_i2c; /* FIXME: generalize & move to common area */ - adap->fe->callback = stk7700ph_xc3028_callback; + adap->fe[0]->callback = stk7700ph_xc3028_callback; - return dvb_attach(xc2028_attach, adap->fe, &stk7700ph_xc3028_config) + return dvb_attach(xc2028_attach, adap->fe[0], &stk7700ph_xc3028_config) == NULL ? -ENODEV : 0; } @@ -685,12 +685,12 @@ static int stk7700p_frontend_attach(struct dvb_usb_adapter *adap) st->mt2060_if1[0] = 1220; if (dib7000pc_detection(&adap->dev->i2c_adap)) { - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000p_config); + adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000p_config); st->is_dib7000pc = 1; } else - adap->fe = dvb_attach(dib7000m_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000m_config); + adap->fe[0] = dvb_attach(dib7000m_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000m_config); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } static struct mt2060_config stk7700p_mt2060_config = { @@ -709,11 +709,11 @@ static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap) if (!eeprom_read(prim_i2c,0x58,&a)) if1=1220+a; } if (st->is_dib7000pc) - tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + tun_i2c = dib7000p_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); else - tun_i2c = dib7000m_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + tun_i2c = dib7000m_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); - return dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk7700p_mt2060_config, + return dvb_attach(mt2060_attach, adap->fe[0], tun_i2c, &stk7700p_mt2060_config, if1) == NULL ? -ENODEV : 0; } @@ -843,33 +843,33 @@ static int dib7770_set_param_override(struct dvb_frontend *fe, static int dib7770p_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe, + struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); - if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, + if (dvb_attach(dib0070_attach, adap->fe[0], tun_i2c, &dib7770p_dib0070_config) == NULL) return -ENODEV; - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib7770_set_param_override; + st->set_param_save = adap->fe[0]->ops.tuner_ops.set_params; + adap->fe[0]->ops.tuner_ops.set_params = dib7770_set_param_override; return 0; } static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); if (adap->id == 0) { - if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[0]) == NULL) + if (dvb_attach(dib0070_attach, adap->fe[0], tun_i2c, &dib7070p_dib0070_config[0]) == NULL) return -ENODEV; } else { - if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[1]) == NULL) + if (dvb_attach(dib0070_attach, adap->fe[0], tun_i2c, &dib7070p_dib0070_config[1]) == NULL) return -ENODEV; } - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib7070_set_param_override; + st->set_param_save = adap->fe[0]->ops.tuner_ops.set_params; + adap->fe[0]->ops.tuner_ops.set_params = dib7070_set_param_override; return 0; } @@ -878,26 +878,26 @@ static int stk7700p_pid_filter(struct dvb_usb_adapter *adapter, int index, { struct dib0700_state *st = adapter->dev->priv; if (st->is_dib7000pc) - return dib7000p_pid_filter(adapter->fe, index, pid, onoff); - return dib7000m_pid_filter(adapter->fe, index, pid, onoff); + return dib7000p_pid_filter(adapter->fe[0], index, pid, onoff); + return dib7000m_pid_filter(adapter->fe[0], index, pid, onoff); } static int stk7700p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) { struct dib0700_state *st = adapter->dev->priv; if (st->is_dib7000pc) - return dib7000p_pid_filter_ctrl(adapter->fe, onoff); - return dib7000m_pid_filter_ctrl(adapter->fe, onoff); + return dib7000p_pid_filter_ctrl(adapter->fe[0], onoff); + return dib7000m_pid_filter_ctrl(adapter->fe[0], onoff); } static int stk70x0p_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) { - return dib7000p_pid_filter(adapter->fe, index, pid, onoff); + return dib7000p_pid_filter(adapter->fe[0], index, pid, onoff); } static int stk70x0p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) { - return dib7000p_pid_filter_ctrl(adapter->fe, onoff); + return dib7000p_pid_filter_ctrl(adapter->fe[0], onoff); } static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = { @@ -955,9 +955,9 @@ static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap) return -ENODEV; } - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, + adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &dib7070p_dib7000p_config); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } /* STK7770P */ @@ -1007,9 +1007,9 @@ static int stk7770p_frontend_attach(struct dvb_usb_adapter *adap) return -ENODEV; } - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, + adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &dib7770p_dib7000p_config); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } /* DIB807x generic */ @@ -1225,34 +1225,34 @@ static int dib807x_set_param_override(struct dvb_frontend *fe, static int dib807x_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe, + struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); if (adap->id == 0) { - if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, + if (dvb_attach(dib0070_attach, adap->fe[0], tun_i2c, &dib807x_dib0070_config[0]) == NULL) return -ENODEV; } else { - if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, + if (dvb_attach(dib0070_attach, adap->fe[0], tun_i2c, &dib807x_dib0070_config[1]) == NULL) return -ENODEV; } - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib807x_set_param_override; + st->set_param_save = adap->fe[0]->ops.tuner_ops.set_params; + adap->fe[0]->ops.tuner_ops.set_params = dib807x_set_param_override; return 0; } static int stk80xx_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) { - return dib8000_pid_filter(adapter->fe, index, pid, onoff); + return dib8000_pid_filter(adapter->fe[0], index, pid, onoff); } static int stk80xx_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) { - return dib8000_pid_filter_ctrl(adapter->fe, onoff); + return dib8000_pid_filter_ctrl(adapter->fe[0], onoff); } /* STK807x */ @@ -1276,10 +1276,10 @@ static int stk807x_frontend_attach(struct dvb_usb_adapter *adap) dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80); - adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, + adap->fe[0] = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib807x_dib8000_config[0]); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } /* STK807xPVR */ @@ -1305,10 +1305,10 @@ static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap) /* initialize IC 0 */ dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x80); - adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, + adap->fe[0] = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib807x_dib8000_config[0]); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap) @@ -1316,10 +1316,10 @@ static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap) /* initialize IC 1 */ dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x82); - adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, + adap->fe[0] = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, &dib807x_dib8000_config[1]); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } /* STK8096GP */ @@ -1546,13 +1546,13 @@ static int dib8096_set_param_override(struct dvb_frontend *fe, static int dib809x_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); - if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &dib809x_dib0090_config) == NULL) + if (dvb_attach(dib0090_register, adap->fe[0], tun_i2c, &dib809x_dib0090_config) == NULL) return -ENODEV; - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib8096_set_param_override; + st->set_param_save = adap->fe[0]->ops.tuner_ops.set_params; + adap->fe[0]->ops.tuner_ops.set_params = dib8096_set_param_override; return 0; } @@ -1575,30 +1575,30 @@ static int stk809x_frontend_attach(struct dvb_usb_adapter *adap) dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80); - adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); + adap->fe[0] = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } static int nim8096md_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; struct i2c_adapter *tun_i2c; - struct dvb_frontend *fe_slave = dib8000_get_slave_frontend(adap->fe, 1); + struct dvb_frontend *fe_slave = dib8000_get_slave_frontend(adap->fe[0], 1); if (fe_slave) { tun_i2c = dib8000_get_i2c_master(fe_slave, DIBX000_I2C_INTERFACE_TUNER, 1); if (dvb_attach(dib0090_register, fe_slave, tun_i2c, &dib809x_dib0090_config) == NULL) return -ENODEV; - fe_slave->dvb = adap->fe->dvb; + fe_slave->dvb = adap->fe[0]->dvb; fe_slave->ops.tuner_ops.set_params = dib8096_set_param_override; } - tun_i2c = dib8000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); - if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &dib809x_dib0090_config) == NULL) + tun_i2c = dib8000_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); + if (dvb_attach(dib0090_register, adap->fe[0], tun_i2c, &dib809x_dib0090_config) == NULL) return -ENODEV; - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib8096_set_param_override; + st->set_param_save = adap->fe[0]->ops.tuner_ops.set_params; + adap->fe[0]->ops.tuner_ops.set_params = dib8096_set_param_override; return 0; } @@ -1626,12 +1626,12 @@ static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap) dib8000_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, 0x80); - adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); - if (adap->fe == NULL) + adap->fe[0] = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); + if (adap->fe[0] == NULL) return -ENODEV; fe_slave = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, &dib809x_dib8000_config[1]); - dib8000_set_slave_frontend(adap->fe, fe_slave); + dib8000_set_slave_frontend(adap->fe[0], fe_slave); return fe_slave == NULL ? -ENODEV : 0; } @@ -1639,12 +1639,12 @@ static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap) /* STK9090M */ static int dib90x0_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) { - return dib9000_fw_pid_filter(adapter->fe, index, pid, onoff); + return dib9000_fw_pid_filter(adapter->fe[0], index, pid, onoff); } static int dib90x0_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) { - return dib9000_fw_pid_filter_ctrl(adapter->fe, onoff); + return dib9000_fw_pid_filter_ctrl(adapter->fe[0], onoff); } static int dib90x0_tuner_reset(struct dvb_frontend *fe, int onoff) @@ -1856,15 +1856,15 @@ static int stk9090m_frontend_attach(struct dvb_usb_adapter *adap) stk9090m_config.microcode_B_fe_size = state->frontend_firmware->size; stk9090m_config.microcode_B_fe_buffer = state->frontend_firmware->data; - adap->fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &stk9090m_config); + adap->fe[0] = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &stk9090m_config); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } static int dib9090_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *state = adap->priv; - struct i2c_adapter *i2c = dib9000_get_tuner_interface(adap->fe); + struct i2c_adapter *i2c = dib9000_get_tuner_interface(adap->fe[0]); u16 data_dib190[10] = { 1, 0x1374, 2, 0x01a2, @@ -1873,13 +1873,13 @@ static int dib9090_tuner_attach(struct dvb_usb_adapter *adap) 8, 0x0486, }; - if (dvb_attach(dib0090_fw_register, adap->fe, i2c, &dib9090_dib0090_config) == NULL) + if (dvb_attach(dib0090_fw_register, adap->fe[0], i2c, &dib9090_dib0090_config) == NULL) return -ENODEV; - i2c = dib9000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0); + i2c = dib9000_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_GPIO_1_2, 0); if (dib01x0_pmu_update(i2c, data_dib190, 10) != 0) return -ENODEV; dib0700_set_i2c_speed(adap->dev, 2000); - if (dib9000_firmware_post_pll_init(adap->fe) < 0) + if (dib9000_firmware_post_pll_init(adap->fe[0]) < 0) return -ENODEV; release_firmware(state->frontend_firmware); return 0; @@ -1925,16 +1925,16 @@ static int nim9090md_frontend_attach(struct dvb_usb_adapter *adap) nim9090md_config[1].microcode_B_fe_buffer = state->frontend_firmware->data; dib9000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, 0x80); - adap->fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &nim9090md_config[0]); + adap->fe[0] = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &nim9090md_config[0]); - if (adap->fe == NULL) + if (adap->fe[0] == NULL) return -ENODEV; - i2c = dib9000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_GPIO_3_4, 0); + i2c = dib9000_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_GPIO_3_4, 0); dib9000_i2c_enumeration(i2c, 1, 0x12, 0x82); fe_slave = dvb_attach(dib9000_attach, i2c, 0x82, &nim9090md_config[1]); - dib9000_set_slave_frontend(adap->fe, fe_slave); + dib9000_set_slave_frontend(adap->fe[0], fe_slave); return fe_slave == NULL ? -ENODEV : 0; } @@ -1951,26 +1951,26 @@ static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap) 0, 0x00ef, 8, 0x0406, }; - i2c = dib9000_get_tuner_interface(adap->fe); - if (dvb_attach(dib0090_fw_register, adap->fe, i2c, &nim9090md_dib0090_config[0]) == NULL) + i2c = dib9000_get_tuner_interface(adap->fe[0]); + if (dvb_attach(dib0090_fw_register, adap->fe[0], i2c, &nim9090md_dib0090_config[0]) == NULL) return -ENODEV; - i2c = dib9000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0); + i2c = dib9000_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_GPIO_1_2, 0); if (dib01x0_pmu_update(i2c, data_dib190, 10) < 0) return -ENODEV; dib0700_set_i2c_speed(adap->dev, 2000); - if (dib9000_firmware_post_pll_init(adap->fe) < 0) + if (dib9000_firmware_post_pll_init(adap->fe[0]) < 0) return -ENODEV; - fe_slave = dib9000_get_slave_frontend(adap->fe, 1); + fe_slave = dib9000_get_slave_frontend(adap->fe[0], 1); if (fe_slave != NULL) { - i2c = dib9000_get_component_bus_interface(adap->fe); + i2c = dib9000_get_component_bus_interface(adap->fe[0]); dib9000_set_i2c_adapter(fe_slave, i2c); i2c = dib9000_get_tuner_interface(fe_slave); if (dvb_attach(dib0090_fw_register, fe_slave, i2c, &nim9090md_dib0090_config[1]) == NULL) return -ENODEV; - fe_slave->dvb = adap->fe->dvb; - dib9000_fw_set_component_bus_speed(adap->fe, 2000); + fe_slave->dvb = adap->fe[0]->dvb; + dib9000_fw_set_component_bus_speed(adap->fe[0], 2000); if (dib9000_firmware_post_pll_init(fe_slave) < 0) return -ENODEV; } @@ -2393,23 +2393,23 @@ static int nim7090_frontend_attach(struct dvb_usb_adapter *adap) err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); return -ENODEV; } - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &nim7090_dib7000p_config); + adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &nim7090_dib7000p_config); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } static int nim7090_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe); + struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe[0]); - if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &nim7090_dib0090_config) == NULL) + if (dvb_attach(dib0090_register, adap->fe[0], tun_i2c, &nim7090_dib0090_config) == NULL) return -ENODEV; - dib7000p_set_gpio(adap->fe, 8, 0, 1); + dib7000p_set_gpio(adap->fe[0], 8, 0, 1); - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib7090_agc_startup; + st->set_param_save = adap->fe[0]->ops.tuner_ops.set_params; + adap->fe[0]->ops.tuner_ops.set_params = dib7090_agc_startup; return 0; } @@ -2439,11 +2439,11 @@ static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap) } dib0700_set_i2c_speed(adap->dev, 340); - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]); - if (adap->fe == NULL) + adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]); + if (adap->fe[0] == NULL) return -ENODEV; - dib7090_slave_reset(adap->fe); + dib7090_slave_reset(adap->fe[0]); return 0; } @@ -2452,50 +2452,50 @@ static int tfe7090pvr_frontend1_attach(struct dvb_usb_adapter *adap) { struct i2c_adapter *i2c; - if (adap->dev->adapter[0].fe == NULL) { + if (adap->dev->adapter[0].fe[0] == NULL) { err("the master dib7090 has to be initialized first"); return -ENODEV; /* the master device has not been initialized */ } - i2c = dib7000p_get_i2c_master(adap->dev->adapter[0].fe, DIBX000_I2C_INTERFACE_GPIO_6_7, 1); + i2c = dib7000p_get_i2c_master(adap->dev->adapter[0].fe[0], DIBX000_I2C_INTERFACE_GPIO_6_7, 1); if (dib7000p_i2c_enumeration(i2c, 1, 0x10, &tfe7090pvr_dib7000p_config[1]) != 0) { err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); return -ENODEV; } - adap->fe = dvb_attach(dib7000p_attach, i2c, 0x92, &tfe7090pvr_dib7000p_config[1]); + adap->fe[0] = dvb_attach(dib7000p_attach, i2c, 0x92, &tfe7090pvr_dib7000p_config[1]); dib0700_set_i2c_speed(adap->dev, 200); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } static int tfe7090pvr_tuner0_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe); + struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe[0]); - if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &tfe7090pvr_dib0090_config[0]) == NULL) + if (dvb_attach(dib0090_register, adap->fe[0], tun_i2c, &tfe7090pvr_dib0090_config[0]) == NULL) return -ENODEV; - dib7000p_set_gpio(adap->fe, 8, 0, 1); + dib7000p_set_gpio(adap->fe[0], 8, 0, 1); - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib7090_agc_startup; + st->set_param_save = adap->fe[0]->ops.tuner_ops.set_params; + adap->fe[0]->ops.tuner_ops.set_params = dib7090_agc_startup; return 0; } static int tfe7090pvr_tuner1_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe); + struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe[0]); - if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &tfe7090pvr_dib0090_config[1]) == NULL) + if (dvb_attach(dib0090_register, adap->fe[0], tun_i2c, &tfe7090pvr_dib0090_config[1]) == NULL) return -ENODEV; - dib7000p_set_gpio(adap->fe, 8, 0, 1); + dib7000p_set_gpio(adap->fe[0], 8, 0, 1); - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib7090_agc_startup; + st->set_param_save = adap->fe[0]->ops.tuner_ops.set_params; + adap->fe[0]->ops.tuner_ops.set_params = dib7090_agc_startup; return 0; } @@ -2555,14 +2555,14 @@ static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap) return -ENODEV; } - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]); - return adap->fe == NULL ? -ENODEV : 0; + adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]); + return adap->fe[0] == NULL ? -ENODEV : 0; } static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap) { - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x82, &stk7070pd_dib7000p_config[1]); - return adap->fe == NULL ? -ENODEV : 0; + adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x82, &stk7070pd_dib7000p_config[1]); + return adap->fe[0] == NULL ? -ENODEV : 0; } /* S5H1411 */ @@ -2617,9 +2617,9 @@ static int s5h1411_frontend_attach(struct dvb_usb_adapter *adap) dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 1); /* GPIOs are initialized, do the attach */ - adap->fe = dvb_attach(s5h1411_attach, &pinnacle_801e_config, + adap->fe[0] = dvb_attach(s5h1411_attach, &pinnacle_801e_config, &adap->dev->i2c_adap); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } static int dib0700_xc5000_tuner_callback(void *priv, int component, @@ -2649,9 +2649,9 @@ static struct xc5000_config s5h1411_xc5000_tunerconfig = { static int xc5000_tuner_attach(struct dvb_usb_adapter *adap) { /* FIXME: generalize & move to common area */ - adap->fe->callback = dib0700_xc5000_tuner_callback; + adap->fe[0]->callback = dib0700_xc5000_tuner_callback; - return dvb_attach(xc5000_attach, adap->fe, &adap->dev->i2c_adap, + return dvb_attach(xc5000_attach, adap->fe[0], &adap->dev->i2c_adap, &s5h1411_xc5000_tunerconfig) == NULL ? -ENODEV : 0; } @@ -2663,9 +2663,9 @@ static int dib0700_xc4000_tuner_callback(void *priv, int component, if (command == XC4000_TUNER_RESET) { /* Reset the tuner */ - dib7000p_set_gpio(adap->fe, 8, 0, 0); + dib7000p_set_gpio(adap->fe[0], 8, 0, 0); msleep(10); - dib7000p_set_gpio(adap->fe, 8, 0, 1); + dib7000p_set_gpio(adap->fe[0], 8, 0, 1); } else { err("xc4000: unknown tuner callback command: %d\n", command); return -EINVAL; @@ -2771,11 +2771,11 @@ static int pctv340e_frontend_attach(struct dvb_usb_adapter *adap) return -ENODEV; } - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x12, + adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x12, &pctv_340e_config); st->is_dib7000pc = 1; - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } static struct xc4000_config dib7000p_xc4000_tunerconfig = { @@ -2791,7 +2791,7 @@ static int xc4000_tuner_attach(struct dvb_usb_adapter *adap) struct i2c_adapter *tun_i2c; /* The xc4000 is not on the main i2c bus */ - tun_i2c = dib7000p_get_i2c_master(adap->fe, + tun_i2c = dib7000p_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); if (tun_i2c == NULL) { printk(KERN_ERR "Could not reach tuner i2c bus\n"); @@ -2799,9 +2799,9 @@ static int xc4000_tuner_attach(struct dvb_usb_adapter *adap) } /* Setup the reset callback */ - adap->fe->callback = dib0700_xc4000_tuner_callback; + adap->fe[0]->callback = dib0700_xc4000_tuner_callback; - return dvb_attach(xc4000_attach, adap->fe, tun_i2c, + return dvb_attach(xc4000_attach, adap->fe[0], tun_i2c, &dib7000p_xc4000_tunerconfig) == NULL ? -ENODEV : 0; } @@ -2857,16 +2857,16 @@ static int lgdt3305_frontend_attach(struct dvb_usb_adapter *adap) dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(30); - adap->fe = dvb_attach(lgdt3305_attach, + adap->fe[0] = dvb_attach(lgdt3305_attach, &hcw_lgdt3305_config, &adap->dev->i2c_adap); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } static int mxl5007t_tuner_attach(struct dvb_usb_adapter *adap) { - return dvb_attach(mxl5007t_attach, adap->fe, + return dvb_attach(mxl5007t_attach, adap->fe[0], &adap->dev->i2c_adap, 0x60, &hcw_mxl5007t_config) == NULL ? -ENODEV : 0; } diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c index 4c2a689..263235e 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-common.c +++ b/drivers/media/dvb/dvb-usb/dibusb-common.c @@ -23,7 +23,7 @@ int dibusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) if (adap->priv != NULL) { struct dibusb_state *st = adap->priv; if (st->ops.fifo_ctrl != NULL) - if (st->ops.fifo_ctrl(adap->fe,onoff)) { + if (st->ops.fifo_ctrl(adap->fe[0],onoff)) { err("error while controlling the fifo of the demod."); return -ENODEV; } @@ -37,7 +37,7 @@ int dibusb_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onof if (adap->priv != NULL) { struct dibusb_state *st = adap->priv; if (st->ops.pid_ctrl != NULL) - st->ops.pid_ctrl(adap->fe,index,pid,onoff); + st->ops.pid_ctrl(adap->fe[0],index,pid,onoff); } return 0; } @@ -48,7 +48,7 @@ int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) if (adap->priv != NULL) { struct dibusb_state *st = adap->priv; if (st->ops.pid_parse != NULL) - if (st->ops.pid_parse(adap->fe,onoff) < 0) + if (st->ops.pid_parse(adap->fe[0],onoff) < 0) err("could not handle pid_parser"); } return 0; @@ -254,8 +254,8 @@ int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap) msleep(1000); } - if ((adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000P_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL || - (adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000MC_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL) { + if ((adap->fe[0] = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000P_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL || + (adap->fe[0] = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000MC_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL) { if (adap->priv != NULL) { struct dibusb_state *st = adap->priv; st->ops.pid_parse = dib3000mc_pid_parse; @@ -309,15 +309,15 @@ int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap) } } - tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1); - if (dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) { + tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe[0], 1); + if (dvb_attach(mt2060_attach, adap->fe[0], tun_i2c, &stk3000p_mt2060_config, if1) == NULL) { /* not found - use panasonic pll parameters */ - if (dvb_attach(dvb_pll_attach, adap->fe, 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL) + if (dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL) return -ENOMEM; } else { st->mt2060_present = 1; /* set the correct parameters for the dib3000p */ - dib3000mc_set_config(adap->fe, &stk3000p_dib3000p_config); + dib3000mc_set_config(adap->fe[0], &stk3000p_dib3000p_config); } return 0; } diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c index 04d91bd..c653b32 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mb.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c @@ -31,11 +31,11 @@ static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap) demod_cfg.demod_address = 0x8; - if ((adap->fe = dvb_attach(dib3000mb_attach, &demod_cfg, + if ((adap->fe[0] = dvb_attach(dib3000mb_attach, &demod_cfg, &adap->dev->i2c_adap, &st->ops)) == NULL) return -ENODEV; - adap->fe->ops.i2c_gate_ctrl = dib3000mb_i2c_gate_ctrl; + adap->fe[0]->ops.i2c_gate_ctrl = dib3000mb_i2c_gate_ctrl; return 0; } @@ -46,7 +46,7 @@ static int dibusb_thomson_tuner_attach(struct dvb_usb_adapter *adap) st->tuner_addr = 0x61; - dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap, + dvb_attach(dvb_pll_attach, adap->fe[0], 0x61, &adap->dev->i2c_adap, DVB_PLL_TUA6010XS); return 0; } @@ -57,7 +57,7 @@ static int dibusb_panasonic_tuner_attach(struct dvb_usb_adapter *adap) st->tuner_addr = 0x60; - dvb_attach(dvb_pll_attach, adap->fe, 0x60, &adap->dev->i2c_adap, + dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, &adap->dev->i2c_adap, DVB_PLL_TDA665X); return 0; } @@ -78,16 +78,16 @@ static int dibusb_tuner_probe_and_attach(struct dvb_usb_adapter *adap) /* the Panasonic sits on I2C addrass 0x60, the Thomson on 0x61 */ msg[0].addr = msg[1].addr = st->tuner_addr = 0x60; - if (adap->fe->ops.i2c_gate_ctrl) - adap->fe->ops.i2c_gate_ctrl(adap->fe,1); + if (adap->fe[0]->ops.i2c_gate_ctrl) + adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0],1); if (i2c_transfer(&adap->dev->i2c_adap, msg, 2) != 2) { err("tuner i2c write failed."); ret = -EREMOTEIO; } - if (adap->fe->ops.i2c_gate_ctrl) - adap->fe->ops.i2c_gate_ctrl(adap->fe,0); + if (adap->fe[0]->ops.i2c_gate_ctrl) + adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0],0); if (b2[0] == 0xfe) { info("This device has the Thomson Cable onboard. Which is default."); diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c index f6344cd..1e17d15 100644 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -137,11 +137,11 @@ static int digitv_frontend_attach(struct dvb_usb_adapter *adap) { struct digitv_state *st = adap->dev->priv; - if ((adap->fe = dvb_attach(mt352_attach, &digitv_mt352_config, &adap->dev->i2c_adap)) != NULL) { + if ((adap->fe[0] = dvb_attach(mt352_attach, &digitv_mt352_config, &adap->dev->i2c_adap)) != NULL) { st->is_nxt6000 = 0; return 0; } - if ((adap->fe = dvb_attach(nxt6000_attach, &digitv_nxt6000_config, &adap->dev->i2c_adap)) != NULL) { + if ((adap->fe[0] = dvb_attach(nxt6000_attach, &digitv_nxt6000_config, &adap->dev->i2c_adap)) != NULL) { st->is_nxt6000 = 1; return 0; } @@ -152,11 +152,11 @@ static int digitv_tuner_attach(struct dvb_usb_adapter *adap) { struct digitv_state *st = adap->dev->priv; - if (!dvb_attach(dvb_pll_attach, adap->fe, 0x60, NULL, DVB_PLL_TDED4)) + if (!dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, NULL, DVB_PLL_TDED4)) return -ENODEV; if (st->is_nxt6000) - adap->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params; + adap->fe[0]->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params; return 0; } diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c index ecd86ec..ea2a46f 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u.c +++ b/drivers/media/dvb/dvb-usb/dtt200u.c @@ -90,7 +90,7 @@ static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state) static int dtt200u_frontend_attach(struct dvb_usb_adapter *adap) { - adap->fe = dtt200u_fe_attach(adap->dev); + adap->fe[0] = dtt200u_fe_attach(adap->dev); return 0; } diff --git a/drivers/media/dvb/dvb-usb/dtv5100.c b/drivers/media/dvb/dvb-usb/dtv5100.c index 078ce92..75ed55c 100644 --- a/drivers/media/dvb/dvb-usb/dtv5100.c +++ b/drivers/media/dvb/dvb-usb/dtv5100.c @@ -115,13 +115,13 @@ static struct zl10353_config dtv5100_zl10353_config = { static int dtv5100_frontend_attach(struct dvb_usb_adapter *adap) { - adap->fe = dvb_attach(zl10353_attach, &dtv5100_zl10353_config, + adap->fe[0] = dvb_attach(zl10353_attach, &dtv5100_zl10353_config, &adap->dev->i2c_adap); - if (adap->fe == NULL) + if (adap->fe[0] == NULL) return -EIO; /* disable i2c gate, or it won't work... is this safe? */ - adap->fe->ops.i2c_gate_ctrl = NULL; + adap->fe[0]->ops.i2c_gate_ctrl = NULL; return 0; } @@ -133,7 +133,7 @@ static struct qt1010_config dtv5100_qt1010_config = { static int dtv5100_tuner_attach(struct dvb_usb_adapter *adap) { return dvb_attach(qt1010_attach, - adap->fe, &adap->dev->i2c_adap, + adap->fe[0], &adap->dev->i2c_adap, &dtv5100_qt1010_config) == NULL ? -ENODEV : 0; } diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c index b3cb626..d8c0bd9 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c @@ -186,14 +186,14 @@ int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) } /* re-assign sleep and wakeup functions */ - if (adap->props.frontend_attach(adap) == 0 && adap->fe != NULL) { - adap->fe_init = adap->fe->ops.init; adap->fe->ops.init = dvb_usb_fe_wakeup; - adap->fe_sleep = adap->fe->ops.sleep; adap->fe->ops.sleep = dvb_usb_fe_sleep; + if (adap->props.frontend_attach(adap) == 0 && adap->fe[0] != NULL) { + adap->fe_init = adap->fe[0]->ops.init; adap->fe[0]->ops.init = dvb_usb_fe_wakeup; + adap->fe_sleep = adap->fe[0]->ops.sleep; adap->fe[0]->ops.sleep = dvb_usb_fe_sleep; - if (dvb_register_frontend(&adap->dvb_adap, adap->fe)) { + if (dvb_register_frontend(&adap->dvb_adap, adap->fe[0])) { err("Frontend registration failed."); - dvb_frontend_detach(adap->fe); - adap->fe = NULL; + dvb_frontend_detach(adap->fe[0]); + adap->fe[0] = NULL; return -ENODEV; } @@ -208,9 +208,9 @@ int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap) { - if (adap->fe != NULL) { - dvb_unregister_frontend(adap->fe); - dvb_frontend_detach(adap->fe); + if (adap->fe[0] != NULL) { + dvb_unregister_frontend(adap->fe[0]); + dvb_frontend_detach(adap->fe[0]); } return 0; } diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h index 7d35d07..2e57bff 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -363,7 +363,7 @@ struct dvb_usb_adapter { struct dmxdev dmxdev; struct dvb_demux demux; struct dvb_net dvb_net; - struct dvb_frontend *fe; + struct dvb_frontend *fe[1]; int max_feed_count; int (*fe_init) (struct dvb_frontend *); diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index 058b231..eb5dff5 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -992,18 +992,18 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d) struct dvb_tuner_ops *tuner_ops = NULL; if (demod_probe & 4) { - d->fe = dvb_attach(stv0900_attach, &dw2104a_stv0900_config, + d->fe[0] = dvb_attach(stv0900_attach, &dw2104a_stv0900_config, &d->dev->i2c_adap, 0); - if (d->fe != NULL) { - if (dvb_attach(stb6100_attach, d->fe, + if (d->fe[0] != NULL) { + if (dvb_attach(stb6100_attach, d->fe[0], &dw2104a_stb6100_config, &d->dev->i2c_adap)) { - tuner_ops = &d->fe->ops.tuner_ops; + tuner_ops = &d->fe[0]->ops.tuner_ops; tuner_ops->set_frequency = stb6100_set_freq; tuner_ops->get_frequency = stb6100_get_freq; tuner_ops->set_bandwidth = stb6100_set_bandw; tuner_ops->get_bandwidth = stb6100_get_bandw; - d->fe->ops.set_voltage = dw210x_set_voltage; + d->fe[0]->ops.set_voltage = dw210x_set_voltage; info("Attached STV0900+STB6100!\n"); return 0; } @@ -1011,13 +1011,13 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d) } if (demod_probe & 2) { - d->fe = dvb_attach(stv0900_attach, &dw2104_stv0900_config, + d->fe[0] = dvb_attach(stv0900_attach, &dw2104_stv0900_config, &d->dev->i2c_adap, 0); - if (d->fe != NULL) { - if (dvb_attach(stv6110_attach, d->fe, + if (d->fe[0] != NULL) { + if (dvb_attach(stv6110_attach, d->fe[0], &dw2104_stv6110_config, &d->dev->i2c_adap)) { - d->fe->ops.set_voltage = dw210x_set_voltage; + d->fe[0]->ops.set_voltage = dw210x_set_voltage; info("Attached STV0900+STV6110A!\n"); return 0; } @@ -1025,19 +1025,19 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d) } if (demod_probe & 1) { - d->fe = dvb_attach(cx24116_attach, &dw2104_config, + d->fe[0] = dvb_attach(cx24116_attach, &dw2104_config, &d->dev->i2c_adap); - if (d->fe != NULL) { - d->fe->ops.set_voltage = dw210x_set_voltage; + if (d->fe[0] != NULL) { + d->fe[0]->ops.set_voltage = dw210x_set_voltage; info("Attached cx24116!\n"); return 0; } } - d->fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config, + d->fe[0] = dvb_attach(ds3000_attach, &dw2104_ds3000_config, &d->dev->i2c_adap); - if (d->fe != NULL) { - d->fe->ops.set_voltage = dw210x_set_voltage; + if (d->fe[0] != NULL) { + d->fe[0]->ops.set_voltage = dw210x_set_voltage; info("Attached DS3000!\n"); return 0; } @@ -1053,22 +1053,22 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d) { if (dw2102_properties.i2c_algo == &dw2102_serit_i2c_algo) { /*dw2102_properties.adapter->tuner_attach = NULL;*/ - d->fe = dvb_attach(si21xx_attach, &serit_sp1511lhb_config, + d->fe[0] = dvb_attach(si21xx_attach, &serit_sp1511lhb_config, &d->dev->i2c_adap); - if (d->fe != NULL) { - d->fe->ops.set_voltage = dw210x_set_voltage; + if (d->fe[0] != NULL) { + d->fe[0]->ops.set_voltage = dw210x_set_voltage; info("Attached si21xx!\n"); return 0; } } if (dw2102_properties.i2c_algo == &dw2102_earda_i2c_algo) { - d->fe = dvb_attach(stv0288_attach, &earda_config, + d->fe[0] = dvb_attach(stv0288_attach, &earda_config, &d->dev->i2c_adap); - if (d->fe != NULL) { - if (dvb_attach(stb6000_attach, d->fe, 0x61, + if (d->fe[0] != NULL) { + if (dvb_attach(stb6000_attach, d->fe[0], 0x61, &d->dev->i2c_adap)) { - d->fe->ops.set_voltage = dw210x_set_voltage; + d->fe[0]->ops.set_voltage = dw210x_set_voltage; info("Attached stv0288!\n"); return 0; } @@ -1077,10 +1077,10 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d) if (dw2102_properties.i2c_algo == &dw2102_i2c_algo) { /*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/ - d->fe = dvb_attach(stv0299_attach, &sharp_z0194a_config, + d->fe[0] = dvb_attach(stv0299_attach, &sharp_z0194a_config, &d->dev->i2c_adap); - if (d->fe != NULL) { - d->fe->ops.set_voltage = dw210x_set_voltage; + if (d->fe[0] != NULL) { + d->fe[0]->ops.set_voltage = dw210x_set_voltage; info("Attached stv0299!\n"); return 0; } @@ -1090,9 +1090,9 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d) static int dw3101_frontend_attach(struct dvb_usb_adapter *d) { - d->fe = dvb_attach(tda10023_attach, &dw3101_tda10023_config, + d->fe[0] = dvb_attach(tda10023_attach, &dw3101_tda10023_config, &d->dev->i2c_adap, 0x48); - if (d->fe != NULL) { + if (d->fe[0] != NULL) { info("Attached tda10023!\n"); return 0; } @@ -1101,12 +1101,12 @@ static int dw3101_frontend_attach(struct dvb_usb_adapter *d) static int zl100313_frontend_attach(struct dvb_usb_adapter *d) { - d->fe = dvb_attach(mt312_attach, &zl313_config, + d->fe[0] = dvb_attach(mt312_attach, &zl313_config, &d->dev->i2c_adap); - if (d->fe != NULL) { - if (dvb_attach(zl10039_attach, d->fe, 0x60, + if (d->fe[0] != NULL) { + if (dvb_attach(zl10039_attach, d->fe[0], 0x60, &d->dev->i2c_adap)) { - d->fe->ops.set_voltage = dw210x_set_voltage; + d->fe[0]->ops.set_voltage = dw210x_set_voltage; info("Attached zl100313+zl10039!\n"); return 0; } @@ -1119,16 +1119,16 @@ static int stv0288_frontend_attach(struct dvb_usb_adapter *d) { u8 obuf[] = {7, 1}; - d->fe = dvb_attach(stv0288_attach, &earda_config, + d->fe[0] = dvb_attach(stv0288_attach, &earda_config, &d->dev->i2c_adap); - if (d->fe == NULL) + if (d->fe[0] == NULL) return -EIO; - if (NULL == dvb_attach(stb6000_attach, d->fe, 0x61, &d->dev->i2c_adap)) + if (NULL == dvb_attach(stb6000_attach, d->fe[0], 0x61, &d->dev->i2c_adap)) return -EIO; - d->fe->ops.set_voltage = dw210x_set_voltage; + d->fe[0]->ops.set_voltage = dw210x_set_voltage; dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); @@ -1143,14 +1143,14 @@ static int ds3000_frontend_attach(struct dvb_usb_adapter *d) struct s6x0_state *st = (struct s6x0_state *)d->dev->priv; u8 obuf[] = {7, 1}; - d->fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config, + d->fe[0] = dvb_attach(ds3000_attach, &dw2104_ds3000_config, &d->dev->i2c_adap); - if (d->fe == NULL) + if (d->fe[0] == NULL) return -EIO; - st->old_set_voltage = d->fe->ops.set_voltage; - d->fe->ops.set_voltage = s660_set_voltage; + st->old_set_voltage = d->fe[0]->ops.set_voltage; + d->fe[0]->ops.set_voltage = s660_set_voltage; dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); @@ -1163,12 +1163,12 @@ static int prof_7500_frontend_attach(struct dvb_usb_adapter *d) { u8 obuf[] = {7, 1}; - d->fe = dvb_attach(stv0900_attach, &prof_7500_stv0900_config, + d->fe[0] = dvb_attach(stv0900_attach, &prof_7500_stv0900_config, &d->dev->i2c_adap, 0); - if (d->fe == NULL) + if (d->fe[0] == NULL) return -EIO; - d->fe->ops.set_voltage = dw210x_set_voltage; + d->fe[0]->ops.set_voltage = dw210x_set_voltage; dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); @@ -1204,9 +1204,9 @@ static int su3000_frontend_attach(struct dvb_usb_adapter *d) if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0) err("command 0x51 transfer failed."); - d->fe = dvb_attach(ds3000_attach, &su3000_ds3000_config, + d->fe[0] = dvb_attach(ds3000_attach, &su3000_ds3000_config, &d->dev->i2c_adap); - if (d->fe == NULL) + if (d->fe[0] == NULL) return -EIO; info("Attached DS3000!\n"); @@ -1216,14 +1216,14 @@ static int su3000_frontend_attach(struct dvb_usb_adapter *d) static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(dvb_pll_attach, adap->fe, 0x60, + dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, &adap->dev->i2c_adap, DVB_PLL_OPERA1); return 0; } static int dw3101_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(dvb_pll_attach, adap->fe, 0x60, + dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, &adap->dev->i2c_adap, DVB_PLL_TUA6034); return 0; diff --git a/drivers/media/dvb/dvb-usb/ec168.c b/drivers/media/dvb/dvb-usb/ec168.c index 1ba3e5d..581bdfc 100644 --- a/drivers/media/dvb/dvb-usb/ec168.c +++ b/drivers/media/dvb/dvb-usb/ec168.c @@ -200,9 +200,9 @@ static struct ec100_config ec168_ec100_config = { static int ec168_ec100_frontend_attach(struct dvb_usb_adapter *adap) { deb_info("%s:\n", __func__); - adap->fe = dvb_attach(ec100_attach, &ec168_ec100_config, + adap->fe[0] = dvb_attach(ec100_attach, &ec168_ec100_config, &adap->dev->i2c_adap); - if (adap->fe == NULL) + if (adap->fe[0] == NULL) return -ENODEV; return 0; @@ -228,7 +228,7 @@ static struct mxl5005s_config ec168_mxl5003s_config = { static int ec168_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) { deb_info("%s:\n", __func__); - return dvb_attach(mxl5005s_attach, adap->fe, &adap->dev->i2c_adap, + return dvb_attach(mxl5005s_attach, adap->fe[0], &adap->dev->i2c_adap, &ec168_mxl5003s_config) == NULL ? -ENODEV : 0; } diff --git a/drivers/media/dvb/dvb-usb/friio.c b/drivers/media/dvb/dvb-usb/friio.c index 76159ae..0e4b559 100644 --- a/drivers/media/dvb/dvb-usb/friio.c +++ b/drivers/media/dvb/dvb-usb/friio.c @@ -403,8 +403,8 @@ static int friio_frontend_attach(struct dvb_usb_adapter *adap) if (friio_initialize(adap->dev) < 0) return -EIO; - adap->fe = jdvbt90502_attach(adap->dev); - if (adap->fe == NULL) + adap->fe[0] = jdvbt90502_attach(adap->dev); + if (adap->fe[0] == NULL) return -EIO; return 0; diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c index 6f596ed..fba24ed 100644 --- a/drivers/media/dvb/dvb-usb/gl861.c +++ b/drivers/media/dvb/dvb-usb/gl861.c @@ -103,9 +103,9 @@ static struct zl10353_config gl861_zl10353_config = { static int gl861_frontend_attach(struct dvb_usb_adapter *adap) { - adap->fe = dvb_attach(zl10353_attach, &gl861_zl10353_config, + adap->fe[0] = dvb_attach(zl10353_attach, &gl861_zl10353_config, &adap->dev->i2c_adap); - if (adap->fe == NULL) + if (adap->fe[0] == NULL) return -EIO; return 0; @@ -118,7 +118,7 @@ static struct qt1010_config gl861_qt1010_config = { static int gl861_tuner_attach(struct dvb_usb_adapter *adap) { return dvb_attach(qt1010_attach, - adap->fe, &adap->dev->i2c_adap, + adap->fe[0], &adap->dev->i2c_adap, &gl861_qt1010_config) == NULL ? -ENODEV : 0; } diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c index 1cb3d9a..f254e13 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk.c +++ b/drivers/media/dvb/dvb-usb/gp8psk.c @@ -230,7 +230,7 @@ static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) static int gp8psk_frontend_attach(struct dvb_usb_adapter *adap) { - adap->fe = gp8psk_fe_attach(adap->dev); + adap->fe[0] = gp8psk_fe_attach(adap->dev); return 0; } diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c index 37b1469..ef5911a 100644 --- a/drivers/media/dvb/dvb-usb/lmedm04.c +++ b/drivers/media/dvb/dvb-usb/lmedm04.c @@ -941,7 +941,7 @@ static int lme_name(struct dvb_usb_adapter *adap) const char *desc = adap->dev->desc->name; char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395", " SHARP:BS2F7HZ0194"}; - char *name = adap->fe->ops.info.name; + char *name = adap->fe[0]->ops.info.name; strlcpy(name, desc, 128); strlcat(name, fe_name[st->tuner_config], 128); @@ -958,10 +958,10 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) st->i2c_talk_onoff = 1; st->i2c_gate = 4; - adap->fe = dvb_attach(tda10086_attach, &tda10086_config, + adap->fe[0] = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap); - if (adap->fe) { + if (adap->fe[0]) { info("TUN Found Frontend TDA10086"); st->i2c_tuner_gate_w = 4; st->i2c_tuner_gate_r = 4; @@ -975,9 +975,9 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) } st->i2c_gate = 4; - adap->fe = dvb_attach(stv0299_attach, &sharp_z0194_config, + adap->fe[0] = dvb_attach(stv0299_attach, &sharp_z0194_config, &adap->dev->i2c_adap); - if (adap->fe) { + if (adap->fe[0]) { info("FE Found Stv0299"); st->i2c_tuner_gate_w = 4; st->i2c_tuner_gate_r = 5; @@ -991,9 +991,9 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) } st->i2c_gate = 5; - adap->fe = dvb_attach(stv0288_attach, &lme_config, + adap->fe[0] = dvb_attach(stv0288_attach, &lme_config, &adap->dev->i2c_adap); - if (adap->fe) { + if (adap->fe[0]) { info("FE Found Stv0288"); st->i2c_tuner_gate_w = 4; st->i2c_tuner_gate_r = 5; @@ -1010,15 +1010,15 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) end: if (ret) { - if (adap->fe) { - dvb_frontend_detach(adap->fe); - adap->fe = NULL; + if (adap->fe[0]) { + dvb_frontend_detach(adap->fe[0]); + adap->fe[0] = NULL; } adap->dev->props.rc.core.rc_codes = NULL; return -ENODEV; } - adap->fe->ops.set_voltage = dm04_lme2510_set_voltage; + adap->fe[0]->ops.set_voltage = dm04_lme2510_set_voltage; ret = lme_name(adap); return ret; } @@ -1031,17 +1031,17 @@ static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap) switch (st->tuner_config) { case TUNER_LG: - if (dvb_attach(tda826x_attach, adap->fe, 0xc0, + if (dvb_attach(tda826x_attach, adap->fe[0], 0xc0, &adap->dev->i2c_adap, 1)) ret = st->tuner_config; break; case TUNER_S7395: - if (dvb_attach(ix2505v_attach , adap->fe, &lme_tuner, + if (dvb_attach(ix2505v_attach , adap->fe[0], &lme_tuner, &adap->dev->i2c_adap)) ret = st->tuner_config; break; case TUNER_S0194: - if (dvb_attach(dvb_pll_attach , adap->fe, 0xc0, + if (dvb_attach(dvb_pll_attach , adap->fe[0], 0xc0, &adap->dev->i2c_adap, DVB_PLL_OPERA1)) ret = st->tuner_config; break; diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c index 9456792..ed5c161 100644 --- a/drivers/media/dvb/dvb-usb/m920x.c +++ b/drivers/media/dvb/dvb-usb/m920x.c @@ -501,7 +501,7 @@ static int m920x_mt352_frontend_attach(struct dvb_usb_adapter *adap) { deb("%s\n",__func__); - if ((adap->fe = dvb_attach(mt352_attach, + if ((adap->fe[0] = dvb_attach(mt352_attach, &m920x_mt352_config, &adap->dev->i2c_adap)) == NULL) return -EIO; @@ -513,7 +513,7 @@ static int m920x_tda10046_08_frontend_attach(struct dvb_usb_adapter *adap) { deb("%s\n",__func__); - if ((adap->fe = dvb_attach(tda10046_attach, + if ((adap->fe[0] = dvb_attach(tda10046_attach, &m920x_tda10046_08_config, &adap->dev->i2c_adap)) == NULL) return -EIO; @@ -525,7 +525,7 @@ static int m920x_tda10046_0b_frontend_attach(struct dvb_usb_adapter *adap) { deb("%s\n",__func__); - if ((adap->fe = dvb_attach(tda10046_attach, + if ((adap->fe[0] = dvb_attach(tda10046_attach, &m920x_tda10046_0b_config, &adap->dev->i2c_adap)) == NULL) return -EIO; @@ -537,7 +537,7 @@ static int m920x_qt1010_tuner_attach(struct dvb_usb_adapter *adap) { deb("%s\n",__func__); - if (dvb_attach(qt1010_attach, adap->fe, &adap->dev->i2c_adap, &m920x_qt1010_config) == NULL) + if (dvb_attach(qt1010_attach, adap->fe[0], &adap->dev->i2c_adap, &m920x_qt1010_config) == NULL) return -ENODEV; return 0; @@ -547,7 +547,7 @@ static int m920x_tda8275_60_tuner_attach(struct dvb_usb_adapter *adap) { deb("%s\n",__func__); - if (dvb_attach(tda827x_attach, adap->fe, 0x60, &adap->dev->i2c_adap, NULL) == NULL) + if (dvb_attach(tda827x_attach, adap->fe[0], 0x60, &adap->dev->i2c_adap, NULL) == NULL) return -ENODEV; return 0; @@ -557,7 +557,7 @@ static int m920x_tda8275_61_tuner_attach(struct dvb_usb_adapter *adap) { deb("%s\n",__func__); - if (dvb_attach(tda827x_attach, adap->fe, 0x61, &adap->dev->i2c_adap, NULL) == NULL) + if (dvb_attach(tda827x_attach, adap->fe[0], 0x61, &adap->dev->i2c_adap, NULL) == NULL) return -ENODEV; return 0; @@ -565,7 +565,7 @@ static int m920x_tda8275_61_tuner_attach(struct dvb_usb_adapter *adap) static int m920x_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(simple_tuner_attach, adap->fe, + dvb_attach(simple_tuner_attach, adap->fe[0], &adap->dev->i2c_adap, 0x61, TUNER_PHILIPS_FMD1216ME_MK3); return 0; diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c index 2e4fab7..170b1ef 100644 --- a/drivers/media/dvb/dvb-usb/opera1.c +++ b/drivers/media/dvb/dvb-usb/opera1.c @@ -263,10 +263,10 @@ static struct stv0299_config opera1_stv0299_config = { static int opera1_frontend_attach(struct dvb_usb_adapter *d) { - if ((d->fe = + if ((d->fe[0] = dvb_attach(stv0299_attach, &opera1_stv0299_config, &d->dev->i2c_adap)) != NULL) { - d->fe->ops.set_voltage = opera1_set_voltage; + d->fe[0]->ops.set_voltage = opera1_set_voltage; return 0; } info("not attached stv0299"); @@ -276,7 +276,7 @@ static int opera1_frontend_attach(struct dvb_usb_adapter *d) static int opera1_tuner_attach(struct dvb_usb_adapter *adap) { dvb_attach( - dvb_pll_attach, adap->fe, 0xc0>>1, + dvb_pll_attach, adap->fe[0], 0xc0>>1, &adap->dev->i2c_adap, DVB_PLL_OPERA1 ); return 0; diff --git a/drivers/media/dvb/dvb-usb/technisat-usb2.c b/drivers/media/dvb/dvb-usb/technisat-usb2.c index 473b95e..2a89d1ef 100644 --- a/drivers/media/dvb/dvb-usb/technisat-usb2.c +++ b/drivers/media/dvb/dvb-usb/technisat-usb2.c @@ -292,7 +292,7 @@ static void technisat_usb2_green_led_control(struct work_struct *work) { struct technisat_usb2_state *state = container_of(work, struct technisat_usb2_state, green_led_work.work); - struct dvb_frontend *fe = state->dev->adapter[0].fe; + struct dvb_frontend *fe = state->dev->adapter[0].fe[0]; if (state->power_state == 0) goto schedule; @@ -505,14 +505,14 @@ static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a) struct usb_device *udev = a->dev->udev; int ret; - a->fe = dvb_attach(stv090x_attach, &technisat_usb2_stv090x_config, + a->fe[0] = dvb_attach(stv090x_attach, &technisat_usb2_stv090x_config, &a->dev->i2c_adap, STV090x_DEMODULATOR_0); - if (a->fe) { + if (a->fe[0]) { struct stv6110x_devctl *ctl; ctl = dvb_attach(stv6110x_attach, - a->fe, + a->fe[0], &technisat_usb2_stv6110x_config, &a->dev->i2c_adap); @@ -532,8 +532,8 @@ static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a) /* call the init function once to initialize tuner's clock output divider and demod's master clock */ - if (a->fe->ops.init) - a->fe->ops.init(a->fe); + if (a->fe[0]->ops.init) + a->fe[0]->ops.init(a->fe[0]); if (mutex_lock_interruptible(&a->dev->i2c_mutex) < 0) return -EAGAIN; @@ -548,20 +548,20 @@ static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a) if (ret != 0) err("could not set IF_CLK to external"); - a->fe->ops.set_voltage = technisat_usb2_set_voltage; + a->fe[0]->ops.set_voltage = technisat_usb2_set_voltage; /* if everything was successful assign a nice name to the frontend */ - strlcpy(a->fe->ops.info.name, a->dev->desc->name, - sizeof(a->fe->ops.info.name)); + strlcpy(a->fe[0]->ops.info.name, a->dev->desc->name, + sizeof(a->fe[0]->ops.info.name)); } else { - dvb_frontend_detach(a->fe); - a->fe = NULL; + dvb_frontend_detach(a->fe[0]); + a->fe[0] = NULL; } } technisat_usb2_set_led_timer(a->dev, 1, 1); - return a->fe == NULL ? -ENODEV : 0; + return a->fe[0] == NULL ? -ENODEV : 0; } /* Remote control */ diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c index 0d4709f..c0f5ef5 100644 --- a/drivers/media/dvb/dvb-usb/ttusb2.c +++ b/drivers/media/dvb/dvb-usb/ttusb2.c @@ -195,7 +195,7 @@ static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap) if (usb_set_interface(adap->dev->udev,0,3) < 0) err("set interface to alts=3 failed"); - if ((adap->fe = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap)) == NULL) { + if ((adap->fe[0] = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap)) == NULL) { deb_info("TDA10086 attach failed\n"); return -ENODEV; } @@ -207,7 +207,7 @@ static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap) { if (usb_set_interface(adap->dev->udev, 0, 3) < 0) err("set interface to alts=3 failed"); - if ((adap->fe = dvb_attach(tda10023_attach, &tda10023_config, &adap->dev->i2c_adap, 0x48)) == NULL) { + if ((adap->fe[0] = dvb_attach(tda10023_attach, &tda10023_config, &adap->dev->i2c_adap, 0x48)) == NULL) { deb_info("TDA10023 attach failed\n"); return -ENODEV; } @@ -216,7 +216,7 @@ static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap) static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap) { - if (dvb_attach(tda827x_attach, adap->fe, 0x61, &adap->dev->i2c_adap, NULL) == NULL) { + if (dvb_attach(tda827x_attach, adap->fe[0], 0x61, &adap->dev->i2c_adap, NULL) == NULL) { printk(KERN_ERR "%s: No tda827x found!\n", __func__); return -ENODEV; } @@ -225,12 +225,12 @@ static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap) static int ttusb2_tuner_tda826x_attach(struct dvb_usb_adapter *adap) { - if (dvb_attach(tda826x_attach, adap->fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) { + if (dvb_attach(tda826x_attach, adap->fe[0], 0x60, &adap->dev->i2c_adap, 0) == NULL) { deb_info("TDA8263 attach failed\n"); return -ENODEV; } - if (dvb_attach(lnbp21_attach, adap->fe, &adap->dev->i2c_adap, 0, 0) == NULL) { + if (dvb_attach(lnbp21_attach, adap->fe[0], &adap->dev->i2c_adap, 0, 0) == NULL) { deb_info("LNBP21 attach failed\n"); return -ENODEV; } diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c index 118aab1..ed4765a 100644 --- a/drivers/media/dvb/dvb-usb/umt-010.c +++ b/drivers/media/dvb/dvb-usb/umt-010.c @@ -60,14 +60,14 @@ static int umt_mt352_frontend_attach(struct dvb_usb_adapter *adap) umt_config.demod_init = umt_mt352_demod_init; umt_config.demod_address = 0xf; - adap->fe = dvb_attach(mt352_attach, &umt_config, &adap->dev->i2c_adap); + adap->fe[0] = dvb_attach(mt352_attach, &umt_config, &adap->dev->i2c_adap); return 0; } static int umt_tuner_attach (struct dvb_usb_adapter *adap) { - dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, DVB_PLL_TUA6034); + dvb_attach(dvb_pll_attach, adap->fe[0], 0x61, NULL, DVB_PLL_TUA6034); return 0; } diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c index 54355f8..47b3462 100644 --- a/drivers/media/dvb/dvb-usb/vp702x.c +++ b/drivers/media/dvb/dvb-usb/vp702x.c @@ -320,7 +320,7 @@ static int vp702x_frontend_attach(struct dvb_usb_adapter *adap) vp702x_init_pid_filter(adap); - adap->fe = vp702x_fe_attach(adap->dev); + adap->fe[0] = vp702x_fe_attach(adap->dev); vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 1, 7, NULL, 0); return 0; diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index 3db89e3..4264523 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -214,7 +214,7 @@ static int vp7045_frontend_attach(struct dvb_usb_adapter *adap) /* Dump the EEPROM */ /* vp7045_read_eeprom(d,buf, 255, FX2_ID_ADDR); */ - adap->fe = vp7045_fe_attach(adap->dev); + adap->fe[0] = vp7045_fe_attach(adap->dev); return 0; } -- cgit v0.10.2 From 9bd9e3bd2c57530dfe3057dd0aa9bdb37824925d Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 25 Jul 2011 20:16:13 -0300 Subject: [media] dvb-usb: multi-frontend support (MFE) Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c index d8c0bd9..5e34df7 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c @@ -162,8 +162,11 @@ static int dvb_usb_fe_wakeup(struct dvb_frontend *fe) dvb_usb_device_power_ctrl(adap->dev, 1); - if (adap->fe_init) - adap->fe_init(fe); + if (adap->props.frontend_ctrl) + adap->props.frontend_ctrl(fe, 1); + + if (adap->fe_init[fe->id]) + adap->fe_init[fe->id](fe); return 0; } @@ -172,45 +175,89 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe) { struct dvb_usb_adapter *adap = fe->dvb->priv; - if (adap->fe_sleep) - adap->fe_sleep(fe); + if (adap->fe_sleep[fe->id]) + adap->fe_sleep[fe->id](fe); + + if (adap->props.frontend_ctrl) + adap->props.frontend_ctrl(fe, 0); return dvb_usb_device_power_ctrl(adap->dev, 0); } int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) { + int ret, i, x; + + memset(adap->fe, 0, sizeof(adap->fe)); + if (adap->props.frontend_attach == NULL) { - err("strange: '%s' #%d doesn't want to attach a frontend.",adap->dev->desc->name, adap->id); + err("strange: '%s' #%d doesn't want to attach a frontend.", + adap->dev->desc->name, adap->id); + return 0; } - /* re-assign sleep and wakeup functions */ - if (adap->props.frontend_attach(adap) == 0 && adap->fe[0] != NULL) { - adap->fe_init = adap->fe[0]->ops.init; adap->fe[0]->ops.init = dvb_usb_fe_wakeup; - adap->fe_sleep = adap->fe[0]->ops.sleep; adap->fe[0]->ops.sleep = dvb_usb_fe_sleep; + /* register all given adapter frontends */ + if (adap->props.num_frontends) + x = adap->props.num_frontends - 1; + else + x = 0; + + for (i = 0; i <= x; i++) { + ret = adap->props.frontend_attach(adap); + if (ret || adap->fe[i] == NULL) { + /* only print error when there is no FE at all */ + if (i == 0) + err("no frontend was attached by '%s'", + adap->dev->desc->name); + + return 0; + } - if (dvb_register_frontend(&adap->dvb_adap, adap->fe[0])) { - err("Frontend registration failed."); - dvb_frontend_detach(adap->fe[0]); - adap->fe[0] = NULL; - return -ENODEV; + adap->fe[i]->id = i; + + /* re-assign sleep and wakeup functions */ + adap->fe_init[i] = adap->fe[i]->ops.init; + adap->fe[i]->ops.init = dvb_usb_fe_wakeup; + adap->fe_sleep[i] = adap->fe[i]->ops.sleep; + adap->fe[i]->ops.sleep = dvb_usb_fe_sleep; + + if (dvb_register_frontend(&adap->dvb_adap, adap->fe[i])) { + err("Frontend %d registration failed.", i); + dvb_frontend_detach(adap->fe[i]); + adap->fe[i] = NULL; + /* In error case, do not try register more FEs, + * still leaving already registered FEs alive. */ + if (i == 0) + return -ENODEV; + else + return 0; } /* only attach the tuner if the demod is there */ if (adap->props.tuner_attach != NULL) adap->props.tuner_attach(adap); - } else - err("no frontend was attached by '%s'",adap->dev->desc->name); + } return 0; } int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap) { - if (adap->fe[0] != NULL) { - dvb_unregister_frontend(adap->fe[0]); - dvb_frontend_detach(adap->fe[0]); + int i; + + /* unregister all given adapter frontends */ + if (adap->props.num_frontends) + i = adap->props.num_frontends - 1; + else + i = 0; + + for (; i >= 0; i--) { + if (adap->fe[i] != NULL) { + dvb_unregister_frontend(adap->fe[i]); + dvb_frontend_detach(adap->fe[i]); + } } + return 0; } diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c index 2e3ea0f..f9af348 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c @@ -77,6 +77,10 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs) return ret; } + /* use exclusive FE lock if there is multiple shared FEs */ + if (adap->fe[1]) + adap->dvb_adap.mfe_shared = 1; + d->num_adapters_initialized++; d->state |= DVB_USB_STATE_DVB; } diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h index 2e57bff..a3e77b2 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -124,6 +124,8 @@ struct usb_data_stream_properties { * @caps: capabilities of the DVB USB device. * @pid_filter_count: number of PID filter position in the optional hardware * PID-filter. + * @num_frontends: number of frontends of the DVB USB adapter. + * @frontend_ctrl: called to power on/off active frontend. * @streaming_ctrl: called to start and stop the MPEG2-TS streaming of the * device (not URB submitting/killing). * @pid_filter_ctrl: called to en/disable the PID filter, if any. @@ -141,7 +143,9 @@ struct dvb_usb_adapter_properties { #define DVB_USB_ADAP_RECEIVES_204_BYTE_TS 0x08 int caps; int pid_filter_count; + int num_frontends; + int (*frontend_ctrl) (struct dvb_frontend *, int); int (*streaming_ctrl) (struct dvb_usb_adapter *, int); int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int); int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int); @@ -345,6 +349,7 @@ struct usb_data_stream { * * @stream: the usb data stream. */ +#define MAX_NO_OF_FE_PER_ADAP 2 struct dvb_usb_adapter { struct dvb_usb_device *dev; struct dvb_usb_adapter_properties props; @@ -363,11 +368,11 @@ struct dvb_usb_adapter { struct dmxdev dmxdev; struct dvb_demux demux; struct dvb_net dvb_net; - struct dvb_frontend *fe[1]; + struct dvb_frontend *fe[MAX_NO_OF_FE_PER_ADAP]; int max_feed_count; - int (*fe_init) (struct dvb_frontend *); - int (*fe_sleep) (struct dvb_frontend *); + int (*fe_init[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *); + int (*fe_sleep[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *); struct usb_data_stream stream; -- cgit v0.10.2 From 449d1a0ad1732476d394fb2b885092a5c554f983 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 25 Jul 2011 20:25:21 -0300 Subject: [media] anysee: use multi-frontend (MFE) Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c index 1ec88b6..d4d2420 100644 --- a/drivers/media/dvb/dvb-usb/anysee.c +++ b/drivers/media/dvb/dvb-usb/anysee.c @@ -446,6 +446,114 @@ static struct isl6423_config anysee_isl6423_config = { * IOE[5] STV0903 1=enabled */ +static int anysee_frontend_ctrl(struct dvb_frontend *fe, int onoff) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct anysee_state *state = adap->dev->priv; + int ret; + + deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff); + + /* no frontend sleep control */ + if (onoff == 0) + return 0; + + switch (state->hw) { + case ANYSEE_HW_507FA: /* 15 */ + /* E30 Combo Plus */ + /* E30 C Plus */ + + if ((fe->id ^ dvb_usb_anysee_delsys) == 0) { + /* disable DVB-T demod on IOD[0] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 0), + 0x01); + if (ret) + goto error; + + /* enable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5), + 0x20); + if (ret) + goto error; + + /* enable DVB-C tuner on IOE[0] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0), + 0x01); + if (ret) + goto error; + } else { + /* disable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5), + 0x20); + if (ret) + goto error; + + /* enable DVB-T demod on IOD[0] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), + 0x01); + if (ret) + goto error; + + /* enable DVB-T tuner on IOE[0] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0), + 0x01); + if (ret) + goto error; + } + + break; + case ANYSEE_HW_508TC: /* 18 */ + case ANYSEE_HW_508PTC: /* 21 */ + /* E7 TC */ + /* E7 PTC */ + + if ((fe->id ^ dvb_usb_anysee_delsys) == 0) { + /* disable DVB-T demod on IOD[6] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6), + 0x40); + if (ret) + goto error; + + /* enable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5), + 0x20); + if (ret) + goto error; + + /* enable IF route on IOE[0] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0), + 0x01); + if (ret) + goto error; + } else { + /* disable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5), + 0x20); + if (ret) + goto error; + + /* enable DVB-T demod on IOD[6] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 6), + 0x40); + if (ret) + goto error; + + /* enable IF route on IOE[0] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0), + 0x01); + if (ret) + goto error; + } + + break; + default: + ret = 0; + } + +error: + return ret; +} + static int anysee_frontend_attach(struct dvb_usb_adapter *adap) { int ret; @@ -466,27 +574,37 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) } }; - /* Check which hardware we have. - * We must do this call two times to get reliable values (hw bug). - */ - ret = anysee_get_hw_info(adap->dev, hw_info); - if (ret) - goto error; + /* detect hardware only once */ + if (adap->fe[0] == NULL) { + /* Check which hardware we have. + * We must do this call two times to get reliable values (hw bug). + */ + ret = anysee_get_hw_info(adap->dev, hw_info); + if (ret) + goto error; - ret = anysee_get_hw_info(adap->dev, hw_info); - if (ret) - goto error; + ret = anysee_get_hw_info(adap->dev, hw_info); + if (ret) + goto error; + + /* Meaning of these info bytes are guessed. */ + info("firmware version:%d.%d hardware id:%d", + hw_info[1], hw_info[2], hw_info[0]); - /* Meaning of these info bytes are guessed. */ - info("firmware version:%d.%d hardware id:%d", - hw_info[1], hw_info[2], hw_info[0]); + state->hw = hw_info[0]; + } - state->hw = hw_info[0]; + /* set current frondend ID for devices having two frondends */ + if (adap->fe[0]) + state->fe_id++; switch (state->hw) { case ANYSEE_HW_507T: /* 2 */ /* E30 */ + if (state->fe_id) + break; + /* attach demod */ adap->fe[0] = dvb_attach(mt352_attach, &anysee_mt352_config, &adap->dev->i2c_adap); @@ -501,6 +619,9 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) case ANYSEE_HW_507CD: /* 6 */ /* E30 Plus */ + if (state->fe_id) + break; + /* enable DVB-T demod on IOD[0] */ ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01); if (ret) @@ -512,26 +633,32 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) goto error; /* attach demod */ - adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_config, - &adap->dev->i2c_adap); + adap->fe[0] = dvb_attach(zl10353_attach, + &anysee_zl10353_config, &adap->dev->i2c_adap); break; case ANYSEE_HW_507DC: /* 10 */ /* E30 C Plus */ + if (state->fe_id) + break; + /* enable DVB-C demod on IOD[0] */ ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01); if (ret) goto error; /* attach demod */ - adap->fe[0] = dvb_attach(tda10023_attach, &anysee_tda10023_config, - &adap->dev->i2c_adap, 0x48); + adap->fe[0] = dvb_attach(tda10023_attach, + &anysee_tda10023_config, &adap->dev->i2c_adap, 0x48); break; case ANYSEE_HW_507SI: /* 11 */ /* E30 S2 Plus */ + if (state->fe_id) + break; + /* enable DVB-S/S2 demod on IOD[0] */ ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01); if (ret) @@ -564,55 +691,59 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) if (ret) goto error; - if (dvb_usb_anysee_delsys) { - /* disable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5), - 0x20); + if ((state->fe_id ^ dvb_usb_anysee_delsys) == 0) { + /* disable DVB-T demod on IOD[0] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 0), + 0x01); if (ret) goto error; - /* enable DVB-T demod on IOD[0] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), - 0x01); + /* enable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5), + 0x20); if (ret) goto error; /* attach demod */ if (tmp == 0xc7) { /* TDA18212 config */ - adap->fe[0] = dvb_attach(zl10353_attach, - &anysee_zl10353_tda18212_config2, - &adap->dev->i2c_adap); + adap->fe[state->fe_id] = dvb_attach( + tda10023_attach, + &anysee_tda10023_tda18212_config, + &adap->dev->i2c_adap, 0x48); } else { /* PLL config */ - adap->fe[0] = dvb_attach(zl10353_attach, - &anysee_zl10353_config, - &adap->dev->i2c_adap); + adap->fe[state->fe_id] = dvb_attach( + tda10023_attach, + &anysee_tda10023_config, + &adap->dev->i2c_adap, 0x48); } } else { - /* disable DVB-T demod on IOD[0] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 0), - 0x01); + /* disable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5), + 0x20); if (ret) goto error; - /* enable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5), - 0x20); + /* enable DVB-T demod on IOD[0] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), + 0x01); if (ret) goto error; /* attach demod */ if (tmp == 0xc7) { /* TDA18212 config */ - adap->fe[0] = dvb_attach(tda10023_attach, - &anysee_tda10023_tda18212_config, - &adap->dev->i2c_adap, 0x48); + adap->fe[state->fe_id] = dvb_attach( + zl10353_attach, + &anysee_zl10353_tda18212_config2, + &adap->dev->i2c_adap); } else { /* PLL config */ - adap->fe[0] = dvb_attach(tda10023_attach, - &anysee_tda10023_config, - &adap->dev->i2c_adap, 0x48); + adap->fe[state->fe_id] = dvb_attach( + zl10353_attach, + &anysee_zl10353_config, + &adap->dev->i2c_adap); } } @@ -627,52 +758,40 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) if (ret) goto error; - if (dvb_usb_anysee_delsys) { - /* disable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5), - 0x20); - if (ret) - goto error; - - /* enable DVB-T demod on IOD[6] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 6), + if ((state->fe_id ^ dvb_usb_anysee_delsys) == 0) { + /* disable DVB-T demod on IOD[6] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6), 0x40); if (ret) goto error; - /* enable IF route on IOE[0] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0), - 0x01); + /* enable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5), + 0x20); if (ret) goto error; /* attach demod */ - adap->fe[0] = dvb_attach(zl10353_attach, - &anysee_zl10353_tda18212_config, - &adap->dev->i2c_adap); + adap->fe[state->fe_id] = dvb_attach(tda10023_attach, + &anysee_tda10023_tda18212_config, + &adap->dev->i2c_adap, 0x48); } else { - /* disable DVB-T demod on IOD[6] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6), - 0x40); - if (ret) - goto error; - - /* enable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5), + /* disable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5), 0x20); if (ret) goto error; - /* enable IF route on IOE[0] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0), - 0x01); + /* enable DVB-T demod on IOD[6] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 6), + 0x40); if (ret) goto error; /* attach demod */ - adap->fe[0] = dvb_attach(tda10023_attach, - &anysee_tda10023_tda18212_config, - &adap->dev->i2c_adap, 0x48); + adap->fe[state->fe_id] = dvb_attach(zl10353_attach, + &anysee_zl10353_tda18212_config, + &adap->dev->i2c_adap); } break; @@ -681,6 +800,9 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) /* E7 S2 */ /* E7 PS2 */ + if (state->fe_id) + break; + /* enable transport stream on IOA[7] */ ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80); if (ret) @@ -713,7 +835,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) struct anysee_state *state = adap->dev->priv; struct dvb_frontend *fe; int ret; - deb_info("%s:\n", __func__); + deb_info("%s: fe=%d\n", __func__, state->fe_id); switch (state->hw) { case ANYSEE_HW_507T: /* 2 */ @@ -744,28 +866,14 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E30 S2 Plus */ /* attach LNB controller */ - fe = dvb_attach(isl6423_attach, adap->fe[0], &adap->dev->i2c_adap, - &anysee_isl6423_config); + fe = dvb_attach(isl6423_attach, adap->fe[0], + &adap->dev->i2c_adap, &anysee_isl6423_config); break; case ANYSEE_HW_507FA: /* 15 */ /* E30 Combo Plus */ /* E30 C Plus */ - if (dvb_usb_anysee_delsys) { - /* enable DVB-T tuner on IOE[0] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0), - 0x01); - if (ret) - goto error; - } else { - /* enable DVB-C tuner on IOE[0] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0), - 0x01); - if (ret) - goto error; - } - /* Try first attach TDA18212 silicon tuner on IOE[4], if that * fails attach old simple PLL. */ @@ -775,8 +883,8 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) goto error; /* attach tuner */ - fe = dvb_attach(tda18212_attach, adap->fe[0], &adap->dev->i2c_adap, - &anysee_tda18212_config); + fe = dvb_attach(tda18212_attach, adap->fe[state->fe_id], + &adap->dev->i2c_adap, &anysee_tda18212_config); if (fe) break; @@ -786,8 +894,9 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) goto error; /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1), - &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); + fe = dvb_attach(dvb_pll_attach, adap->fe[state->fe_id], + (0xc0 >> 1), &adap->dev->i2c_adap, + DVB_PLL_SAMSUNG_DTOS403IH102A); break; case ANYSEE_HW_508TC: /* 18 */ @@ -801,8 +910,8 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) goto error; /* attach tuner */ - fe = dvb_attach(tda18212_attach, adap->fe[0], &adap->dev->i2c_adap, - &anysee_tda18212_config); + fe = dvb_attach(tda18212_attach, adap->fe[state->fe_id], + &adap->dev->i2c_adap, &anysee_tda18212_config); break; case ANYSEE_HW_508S2: /* 19 */ @@ -918,6 +1027,8 @@ static struct dvb_usb_device_properties anysee_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 2, + .frontend_ctrl = anysee_frontend_ctrl, .streaming_ctrl = anysee_streaming_ctrl, .frontend_attach = anysee_frontend_attach, .tuner_attach = anysee_tuner_attach, diff --git a/drivers/media/dvb/dvb-usb/anysee.h b/drivers/media/dvb/dvb-usb/anysee.h index ad6ccd1..57ee500 100644 --- a/drivers/media/dvb/dvb-usb/anysee.h +++ b/drivers/media/dvb/dvb-usb/anysee.h @@ -59,6 +59,7 @@ enum cmd { struct anysee_state { u8 hw; /* PCB ID */ u8 seq; + u8 fe_id:1; /* frondend ID */ }; #define ANYSEE_HW_507T 2 /* E30 */ -- cgit v0.10.2 From a5f2db539bd2a977cdee3fecc5c15dd0941c1ab3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 31 Jul 2011 09:37:56 -0300 Subject: v4l2-ioctl: properly return -EINVAL when parameters are wrong Whan an ioctl is implemented, but the parameters are invalid, the error code should be -EINVAL. However, if the ioctl is not defined, it should return -ENOTTY instead. Reported-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index 002ce13..9f80e9d 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -55,6 +55,14 @@ memset((u8 *)(p) + offsetof(typeof(*(p)), field) + sizeof((p)->field), \ 0, sizeof(*(p)) - offsetof(typeof(*(p)), field) - sizeof((p)->field)) +#define no_ioctl_err(foo) ( ( \ + ops->vidioc_##foo##_fmt_vid_cap || \ + ops->vidioc_##foo##_fmt_vid_out || \ + ops->vidioc_##foo##_fmt_vid_cap_mplane || \ + ops->vidioc_##foo##_fmt_vid_out_mplane || \ + ops->vidioc_##foo##_fmt_vid_overlay || \ + ops->vidioc_##foo##_fmt_type_private) ? -EINVAL : -ENOTTY) + struct std_descr { v4l2_std_id std; const char *descr; @@ -591,7 +599,7 @@ static long __video_do_ioctl(struct file *file, ret = v4l2_prio_check(vfd->prio, vfh->prio); if (ret) goto exit_prio; - ret = -EINVAL; + ret = -ENOTTY; break; } } @@ -638,7 +646,7 @@ static long __video_do_ioctl(struct file *file, enum v4l2_priority *p = arg; if (!ops->vidioc_s_priority && !use_fh_prio) - break; + break; dbgarg(cmd, "setting priority to %d\n", *p); if (ops->vidioc_s_priority) ret = ops->vidioc_s_priority(file, fh, *p); @@ -654,37 +662,37 @@ static long __video_do_ioctl(struct file *file, switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (ops->vidioc_enum_fmt_vid_cap) + if (likely(ops->vidioc_enum_fmt_vid_cap)) ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f); break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - if (ops->vidioc_enum_fmt_vid_cap_mplane) + if (likely(ops->vidioc_enum_fmt_vid_cap_mplane)) ret = ops->vidioc_enum_fmt_vid_cap_mplane(file, fh, f); break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (ops->vidioc_enum_fmt_vid_overlay) + if (likely(ops->vidioc_enum_fmt_vid_overlay)) ret = ops->vidioc_enum_fmt_vid_overlay(file, fh, f); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (ops->vidioc_enum_fmt_vid_out) + if (likely(ops->vidioc_enum_fmt_vid_out)) ret = ops->vidioc_enum_fmt_vid_out(file, fh, f); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (ops->vidioc_enum_fmt_vid_out_mplane) + if (likely(ops->vidioc_enum_fmt_vid_out_mplane)) ret = ops->vidioc_enum_fmt_vid_out_mplane(file, fh, f); break; case V4L2_BUF_TYPE_PRIVATE: - if (ops->vidioc_enum_fmt_type_private) + if (likely(ops->vidioc_enum_fmt_type_private)) ret = ops->vidioc_enum_fmt_type_private(file, fh, f); break; default: break; } - if (!ret) + if (likely (!ret)) dbgarg(cmd, "index=%d, type=%d, flags=%d, " "pixelformat=%c%c%c%c, description='%s'\n", f->index, f->type, f->flags, @@ -693,6 +701,8 @@ static long __video_do_ioctl(struct file *file, (f->pixelformat >> 16) & 0xff, (f->pixelformat >> 24) & 0xff, f->description); + else if (ret == -ENOTTY) + ret = no_ioctl_err(enum); break; } case VIDIOC_G_FMT: @@ -744,7 +754,7 @@ static long __video_do_ioctl(struct file *file, v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (ops->vidioc_g_fmt_vid_overlay) + if (likely(ops->vidioc_g_fmt_vid_overlay)) ret = ops->vidioc_g_fmt_vid_overlay(file, fh, f); break; @@ -789,34 +799,36 @@ static long __video_do_ioctl(struct file *file, v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (ops->vidioc_g_fmt_vid_out_overlay) + if (likely(ops->vidioc_g_fmt_vid_out_overlay)) ret = ops->vidioc_g_fmt_vid_out_overlay(file, fh, f); break; case V4L2_BUF_TYPE_VBI_CAPTURE: - if (ops->vidioc_g_fmt_vbi_cap) + if (likely(ops->vidioc_g_fmt_vbi_cap)) ret = ops->vidioc_g_fmt_vbi_cap(file, fh, f); break; case V4L2_BUF_TYPE_VBI_OUTPUT: - if (ops->vidioc_g_fmt_vbi_out) + if (likely(ops->vidioc_g_fmt_vbi_out)) ret = ops->vidioc_g_fmt_vbi_out(file, fh, f); break; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - if (ops->vidioc_g_fmt_sliced_vbi_cap) + if (likely(ops->vidioc_g_fmt_sliced_vbi_cap)) ret = ops->vidioc_g_fmt_sliced_vbi_cap(file, fh, f); break; case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - if (ops->vidioc_g_fmt_sliced_vbi_out) + if (likely(ops->vidioc_g_fmt_sliced_vbi_out)) ret = ops->vidioc_g_fmt_sliced_vbi_out(file, fh, f); break; case V4L2_BUF_TYPE_PRIVATE: - if (ops->vidioc_g_fmt_type_private) + if (likely(ops->vidioc_g_fmt_type_private)) ret = ops->vidioc_g_fmt_type_private(file, fh, f); break; } + if (unlikely(ret == -ENOTTY)) + ret = no_ioctl_err(g); break; } @@ -926,33 +938,36 @@ static long __video_do_ioctl(struct file *file, break; case V4L2_BUF_TYPE_VBI_CAPTURE: CLEAR_AFTER_FIELD(f, fmt.vbi); - if (ops->vidioc_s_fmt_vbi_cap) + if (likely(ops->vidioc_s_fmt_vbi_cap)) ret = ops->vidioc_s_fmt_vbi_cap(file, fh, f); break; case V4L2_BUF_TYPE_VBI_OUTPUT: CLEAR_AFTER_FIELD(f, fmt.vbi); - if (ops->vidioc_s_fmt_vbi_out) + if (likely(ops->vidioc_s_fmt_vbi_out)) ret = ops->vidioc_s_fmt_vbi_out(file, fh, f); break; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: CLEAR_AFTER_FIELD(f, fmt.sliced); - if (ops->vidioc_s_fmt_sliced_vbi_cap) + if (likely(ops->vidioc_s_fmt_sliced_vbi_cap)) ret = ops->vidioc_s_fmt_sliced_vbi_cap(file, fh, f); break; case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: CLEAR_AFTER_FIELD(f, fmt.sliced); - if (ops->vidioc_s_fmt_sliced_vbi_out) + if (likely(ops->vidioc_s_fmt_sliced_vbi_out)) ret = ops->vidioc_s_fmt_sliced_vbi_out(file, fh, f); + break; case V4L2_BUF_TYPE_PRIVATE: /* CLEAR_AFTER_FIELD(f, fmt.raw_data); <- does nothing */ - if (ops->vidioc_s_fmt_type_private) + if (likely(ops->vidioc_s_fmt_type_private)) ret = ops->vidioc_s_fmt_type_private(file, fh, f); break; } + if (unlikely(ret == -ENOTTY)) + ret = no_ioctl_err(g); break; } case VIDIOC_TRY_FMT: @@ -1008,7 +1023,7 @@ static long __video_do_ioctl(struct file *file, break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: CLEAR_AFTER_FIELD(f, fmt.win); - if (ops->vidioc_try_fmt_vid_overlay) + if (likely(ops->vidioc_try_fmt_vid_overlay)) ret = ops->vidioc_try_fmt_vid_overlay(file, fh, f); break; @@ -1057,40 +1072,43 @@ static long __video_do_ioctl(struct file *file, break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: CLEAR_AFTER_FIELD(f, fmt.win); - if (ops->vidioc_try_fmt_vid_out_overlay) + if (likely(ops->vidioc_try_fmt_vid_out_overlay)) ret = ops->vidioc_try_fmt_vid_out_overlay(file, fh, f); break; case V4L2_BUF_TYPE_VBI_CAPTURE: CLEAR_AFTER_FIELD(f, fmt.vbi); - if (ops->vidioc_try_fmt_vbi_cap) + if (likely(ops->vidioc_try_fmt_vbi_cap)) ret = ops->vidioc_try_fmt_vbi_cap(file, fh, f); break; case V4L2_BUF_TYPE_VBI_OUTPUT: CLEAR_AFTER_FIELD(f, fmt.vbi); - if (ops->vidioc_try_fmt_vbi_out) + if (likely(ops->vidioc_try_fmt_vbi_out)) ret = ops->vidioc_try_fmt_vbi_out(file, fh, f); break; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: CLEAR_AFTER_FIELD(f, fmt.sliced); - if (ops->vidioc_try_fmt_sliced_vbi_cap) + if (likely(ops->vidioc_try_fmt_sliced_vbi_cap)) ret = ops->vidioc_try_fmt_sliced_vbi_cap(file, fh, f); break; case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: CLEAR_AFTER_FIELD(f, fmt.sliced); - if (ops->vidioc_try_fmt_sliced_vbi_out) + if (likely(ops->vidioc_try_fmt_sliced_vbi_out)) ret = ops->vidioc_try_fmt_sliced_vbi_out(file, fh, f); + else + ret = no_ioctl_err(try); break; case V4L2_BUF_TYPE_PRIVATE: /* CLEAR_AFTER_FIELD(f, fmt.raw_data); <- does nothing */ - if (ops->vidioc_try_fmt_type_private) + if (likely(ops->vidioc_try_fmt_type_private)) ret = ops->vidioc_try_fmt_type_private(file, fh, f); break; } - + if (unlikely(ret == -ENOTTY)) + ret = no_ioctl_err(g); break; } /* FIXME: Those buf reqs could be handled here, @@ -1262,16 +1280,15 @@ static long __video_do_ioctl(struct file *file, { v4l2_std_id *id = arg; - ret = 0; /* Calls the specific handler */ if (ops->vidioc_g_std) ret = ops->vidioc_g_std(file, fh, id); - else if (vfd->current_norm) + else if (vfd->current_norm) { + ret = 0; *id = vfd->current_norm; - else - ret = -EINVAL; + } - if (!ret) + if (likely(!ret)) dbgarg(cmd, "std=0x%08Lx\n", (long long unsigned)*id); break; } @@ -1288,8 +1305,6 @@ static long __video_do_ioctl(struct file *file, /* Calls the specific handler */ if (ops->vidioc_s_std) ret = ops->vidioc_s_std(file, fh, &norm); - else - ret = -EINVAL; /* Updates standard information */ if (ret >= 0) @@ -1812,7 +1827,7 @@ static long __video_do_ioctl(struct file *file, if (ops->vidioc_g_std) ret = ops->vidioc_g_std(file, fh, &std); else if (std == 0) - ret = -EINVAL; + ret = -ENOTTY; if (ret == 0) v4l2_video_std_frame_period(std, &p->parm.capture.timeperframe); -- cgit v0.10.2 From 79fcce3230b140f7675f8529ee53fe2f9644f902 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Wed, 3 Aug 2011 12:08:21 -0300 Subject: [media] DiBcom: protect the I2C bufer access This patch protects the I2C buffer access in order to manage concurrent access. This protection is done using mutex. Furthermore, for the dib9000, if a pid filtering command is received during the tuning, this pid filtering command is delayed to avoid any concurrent access issue. Cc: Mauro Carvalho Chehab Cc: Florian Mickler Cc: stable@kernel.org Signed-off-by: Olivier Grenie Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c index 1d47d4d..dc1cb17 100644 --- a/drivers/media/dvb/frontends/dib0070.c +++ b/drivers/media/dvb/frontends/dib0070.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "dvb_frontend.h" @@ -78,10 +79,18 @@ struct dib0070_state { struct i2c_msg msg[2]; u8 i2c_write_buffer[3]; u8 i2c_read_buffer[2]; + struct mutex i2c_buffer_lock; }; -static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg) +static u16 dib0070_read_reg(struct dib0070_state *state, u8 reg) { + u16 ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return 0; + } + state->i2c_write_buffer[0] = reg; memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); @@ -96,13 +105,23 @@ static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg) if (i2c_transfer(state->i2c, state->msg, 2) != 2) { printk(KERN_WARNING "DiB0070 I2C read failed\n"); - return 0; - } - return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + ret = 0; + } else + ret = (state->i2c_read_buffer[0] << 8) + | state->i2c_read_buffer[1]; + + mutex_unlock(&state->i2c_buffer_lock); + return ret; } static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) { + int ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } state->i2c_write_buffer[0] = reg; state->i2c_write_buffer[1] = val >> 8; state->i2c_write_buffer[2] = val & 0xff; @@ -115,9 +134,12 @@ static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) if (i2c_transfer(state->i2c, state->msg, 1) != 1) { printk(KERN_WARNING "DiB0070 I2C write failed\n"); - return -EREMOTEIO; - } - return 0; + ret = -EREMOTEIO; + } else + ret = 0; + + mutex_unlock(&state->i2c_buffer_lock); + return ret; } #define HARD_RESET(state) do { \ @@ -734,6 +756,7 @@ struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter state->cfg = cfg; state->i2c = i2c; state->fe = fe; + mutex_init(&state->i2c_buffer_lock); fe->tuner_priv = state; if (dib0070_reset(fe) != 0) diff --git a/drivers/media/dvb/frontends/dib0090.c b/drivers/media/dvb/frontends/dib0090.c index c9c935a..b174d1c 100644 --- a/drivers/media/dvb/frontends/dib0090.c +++ b/drivers/media/dvb/frontends/dib0090.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "dvb_frontend.h" @@ -196,6 +197,7 @@ struct dib0090_state { struct i2c_msg msg[2]; u8 i2c_write_buffer[3]; u8 i2c_read_buffer[2]; + struct mutex i2c_buffer_lock; }; struct dib0090_fw_state { @@ -208,10 +210,18 @@ struct dib0090_fw_state { struct i2c_msg msg; u8 i2c_write_buffer[2]; u8 i2c_read_buffer[2]; + struct mutex i2c_buffer_lock; }; static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg) { + u16 ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return 0; + } + state->i2c_write_buffer[0] = reg; memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); @@ -226,14 +236,24 @@ static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg) if (i2c_transfer(state->i2c, state->msg, 2) != 2) { printk(KERN_WARNING "DiB0090 I2C read failed\n"); - return 0; - } + ret = 0; + } else + ret = (state->i2c_read_buffer[0] << 8) + | state->i2c_read_buffer[1]; - return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + mutex_unlock(&state->i2c_buffer_lock); + return ret; } static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val) { + int ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + state->i2c_write_buffer[0] = reg & 0xff; state->i2c_write_buffer[1] = val >> 8; state->i2c_write_buffer[2] = val & 0xff; @@ -246,13 +266,23 @@ static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val) if (i2c_transfer(state->i2c, state->msg, 1) != 1) { printk(KERN_WARNING "DiB0090 I2C write failed\n"); - return -EREMOTEIO; - } - return 0; + ret = -EREMOTEIO; + } else + ret = 0; + + mutex_unlock(&state->i2c_buffer_lock); + return ret; } static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg) { + u16 ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return 0; + } + state->i2c_write_buffer[0] = reg; memset(&state->msg, 0, sizeof(struct i2c_msg)); @@ -262,13 +292,24 @@ static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg) state->msg.len = 2; if (i2c_transfer(state->i2c, &state->msg, 1) != 1) { printk(KERN_WARNING "DiB0090 I2C read failed\n"); - return 0; - } - return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + ret = 0; + } else + ret = (state->i2c_read_buffer[0] << 8) + | state->i2c_read_buffer[1]; + + mutex_unlock(&state->i2c_buffer_lock); + return ret; } static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val) { + int ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + state->i2c_write_buffer[0] = val >> 8; state->i2c_write_buffer[1] = val & 0xff; @@ -279,9 +320,12 @@ static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val) state->msg.len = 2; if (i2c_transfer(state->i2c, &state->msg, 1) != 1) { printk(KERN_WARNING "DiB0090 I2C write failed\n"); - return -EREMOTEIO; - } - return 0; + ret = -EREMOTEIO; + } else + ret = 0; + + mutex_unlock(&state->i2c_buffer_lock); + return ret; } #define HARD_RESET(state) do { if (cfg->reset) { if (cfg->sleep) cfg->sleep(fe, 0); msleep(10); cfg->reset(fe, 1); msleep(10); cfg->reset(fe, 0); msleep(10); } } while (0) @@ -2440,6 +2484,7 @@ struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapte st->config = config; st->i2c = i2c; st->fe = fe; + mutex_init(&st->i2c_buffer_lock); fe->tuner_priv = st; if (config->wbd == NULL) @@ -2471,6 +2516,7 @@ struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_ada st->config = config; st->i2c = i2c; st->fe = fe; + mutex_init(&st->i2c_buffer_lock); fe->tuner_priv = st; if (dib0090_fw_reset_digital(fe, st->config) != 0) diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c index 79cb1c2..dbb76d7 100644 --- a/drivers/media/dvb/frontends/dib7000m.c +++ b/drivers/media/dvb/frontends/dib7000m.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "dvb_frontend.h" @@ -55,6 +56,7 @@ struct dib7000m_state { struct i2c_msg msg[2]; u8 i2c_write_buffer[4]; u8 i2c_read_buffer[2]; + struct mutex i2c_buffer_lock; }; enum dib7000m_power_mode { @@ -69,6 +71,13 @@ enum dib7000m_power_mode { static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg) { + u16 ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return 0; + } + state->i2c_write_buffer[0] = (reg >> 8) | 0x80; state->i2c_write_buffer[1] = reg & 0xff; @@ -85,11 +94,21 @@ static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg) if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2) dprintk("i2c read error on %d",reg); - return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + mutex_unlock(&state->i2c_buffer_lock); + + return ret; } static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val) { + int ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + state->i2c_write_buffer[0] = (reg >> 8) & 0xff; state->i2c_write_buffer[1] = reg & 0xff; state->i2c_write_buffer[2] = (val >> 8) & 0xff; @@ -101,7 +120,10 @@ static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val) state->msg[0].buf = state->i2c_write_buffer; state->msg[0].len = 4; - return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0; + ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? + -EREMOTEIO : 0); + mutex_unlock(&state->i2c_buffer_lock); + return ret; } static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf) { @@ -1385,6 +1407,7 @@ struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, demod = &st->demod; demod->demodulator_priv = st; memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops)); + mutex_init(&st->i2c_buffer_lock); st->timf_default = cfg->bw->timf; diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index a64a538..4eb9c2b 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "dvb_math.h" #include "dvb_frontend.h" @@ -68,6 +69,7 @@ struct dib7000p_state { struct i2c_msg msg[2]; u8 i2c_write_buffer[4]; u8 i2c_read_buffer[2]; + struct mutex i2c_buffer_lock; }; enum dib7000p_power_mode { @@ -81,6 +83,13 @@ static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff); static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg) { + u16 ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return 0; + } + state->i2c_write_buffer[0] = reg >> 8; state->i2c_write_buffer[1] = reg & 0xff; @@ -97,11 +106,20 @@ static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg) if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2) dprintk("i2c read error on %d", reg); - return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + mutex_unlock(&state->i2c_buffer_lock); + return ret; } static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val) { + int ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + state->i2c_write_buffer[0] = (reg >> 8) & 0xff; state->i2c_write_buffer[1] = reg & 0xff; state->i2c_write_buffer[2] = (val >> 8) & 0xff; @@ -113,7 +131,10 @@ static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val) state->msg[0].buf = state->i2c_write_buffer; state->msg[0].len = 4; - return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0; + ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? + -EREMOTEIO : 0); + mutex_unlock(&state->i2c_buffer_lock); + return ret; } static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf) @@ -1646,6 +1667,7 @@ int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau return -ENOMEM; dpst->i2c_adap = i2c; + mutex_init(&dpst->i2c_buffer_lock); for (k = no_of_demods - 1; k >= 0; k--) { dpst->cfg = cfg[k]; @@ -2324,6 +2346,7 @@ struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, demod = &st->demod; demod->demodulator_priv = st; memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops)); + mutex_init(&st->i2c_buffer_lock); dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */ @@ -2333,8 +2356,9 @@ struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, st->version = dib7000p_read_word(st, 897); /* FIXME: make sure the dev.parent field is initialized, or else - request_firmware() will hit an OOPS (this should be moved somewhere - more common) */ + request_firmware() will hit an OOPS (this should be moved somewhere + more common) */ + st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent; /* FIXME: make sure the dev.parent field is initialized, or else request_firmware() will hit an OOPS (this should be moved somewhere diff --git a/drivers/media/dvb/frontends/dib8000.c b/drivers/media/dvb/frontends/dib8000.c index 7d2ea11..fe284d5 100644 --- a/drivers/media/dvb/frontends/dib8000.c +++ b/drivers/media/dvb/frontends/dib8000.c @@ -10,6 +10,8 @@ #include #include #include +#include + #include "dvb_math.h" #include "dvb_frontend.h" @@ -37,6 +39,7 @@ struct i2c_device { u8 addr; u8 *i2c_write_buffer; u8 *i2c_read_buffer; + struct mutex *i2c_buffer_lock; }; struct dib8000_state { @@ -77,6 +80,7 @@ struct dib8000_state { struct i2c_msg msg[2]; u8 i2c_write_buffer[4]; u8 i2c_read_buffer[2]; + struct mutex i2c_buffer_lock; }; enum dib8000_power_mode { @@ -86,24 +90,39 @@ enum dib8000_power_mode { static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg) { + u16 ret; struct i2c_msg msg[2] = { - {.addr = i2c->addr >> 1, .flags = 0, - .buf = i2c->i2c_write_buffer, .len = 2}, - {.addr = i2c->addr >> 1, .flags = I2C_M_RD, - .buf = i2c->i2c_read_buffer, .len = 2}, + {.addr = i2c->addr >> 1, .flags = 0, .len = 2}, + {.addr = i2c->addr >> 1, .flags = I2C_M_RD, .len = 2}, }; + if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return 0; + } + + msg[0].buf = i2c->i2c_write_buffer; msg[0].buf[0] = reg >> 8; msg[0].buf[1] = reg & 0xff; + msg[1].buf = i2c->i2c_read_buffer; if (i2c_transfer(i2c->adap, msg, 2) != 2) dprintk("i2c read error on %d", reg); - return (msg[1].buf[0] << 8) | msg[1].buf[1]; + ret = (msg[1].buf[0] << 8) | msg[1].buf[1]; + mutex_unlock(i2c->i2c_buffer_lock); + return ret; } static u16 dib8000_read_word(struct dib8000_state *state, u16 reg) { + u16 ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return 0; + } + state->i2c_write_buffer[0] = reg >> 8; state->i2c_write_buffer[1] = reg & 0xff; @@ -120,7 +139,10 @@ static u16 dib8000_read_word(struct dib8000_state *state, u16 reg) if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2) dprintk("i2c read error on %d", reg); - return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + mutex_unlock(&state->i2c_buffer_lock); + + return ret; } static u32 dib8000_read32(struct dib8000_state *state, u16 reg) @@ -135,22 +157,35 @@ static u32 dib8000_read32(struct dib8000_state *state, u16 reg) static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val) { - struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, - .buf = i2c->i2c_write_buffer, .len = 4}; + struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, .len = 4}; int ret = 0; + if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + + msg.buf = i2c->i2c_write_buffer; msg.buf[0] = (reg >> 8) & 0xff; msg.buf[1] = reg & 0xff; msg.buf[2] = (val >> 8) & 0xff; msg.buf[3] = val & 0xff; ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0; + mutex_unlock(i2c->i2c_buffer_lock); return ret; } static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val) { + int ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + state->i2c_write_buffer[0] = (reg >> 8) & 0xff; state->i2c_write_buffer[1] = reg & 0xff; state->i2c_write_buffer[2] = (val >> 8) & 0xff; @@ -162,7 +197,11 @@ static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val) state->msg[0].buf = state->i2c_write_buffer; state->msg[0].len = 4; - return i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ? -EREMOTEIO : 0; + ret = (i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ? + -EREMOTEIO : 0); + mutex_unlock(&state->i2c_buffer_lock); + + return ret; } static const s16 coeff_2k_sb_1seg_dqpsk[8] = { @@ -2434,8 +2473,15 @@ int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 defau if (!client.i2c_read_buffer) { dprintk("%s: not enough memory", __func__); ret = -ENOMEM; - goto error_memory; + goto error_memory_read; + } + client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL); + if (!client.i2c_buffer_lock) { + dprintk("%s: not enough memory", __func__); + ret = -ENOMEM; + goto error_memory_lock; } + mutex_init(client.i2c_buffer_lock); for (k = no_of_demods - 1; k >= 0; k--) { /* designated i2c address */ @@ -2476,8 +2522,10 @@ int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 defau } error: + kfree(client.i2c_buffer_lock); +error_memory_lock: kfree(client.i2c_read_buffer); -error_memory: +error_memory_read: kfree(client.i2c_write_buffer); return ret; @@ -2581,6 +2629,8 @@ struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, s state->i2c.addr = i2c_addr; state->i2c.i2c_write_buffer = state->i2c_write_buffer; state->i2c.i2c_read_buffer = state->i2c_read_buffer; + mutex_init(&state->i2c_buffer_lock); + state->i2c.i2c_buffer_lock = &state->i2c_buffer_lock; state->gpio_val = cfg->gpio_val; state->gpio_dir = cfg->gpio_dir; diff --git a/drivers/media/dvb/frontends/dib9000.c b/drivers/media/dvb/frontends/dib9000.c index a085588..b931074 100644 --- a/drivers/media/dvb/frontends/dib9000.c +++ b/drivers/media/dvb/frontends/dib9000.c @@ -38,6 +38,15 @@ struct i2c_device { #define DibInitLock(lock) mutex_init(lock) #define DibFreeLock(lock) +struct dib9000_pid_ctrl { +#define DIB9000_PID_FILTER_CTRL 0 +#define DIB9000_PID_FILTER 1 + u8 cmd; + u8 id; + u16 pid; + u8 onoff; +}; + struct dib9000_state { struct i2c_device i2c; @@ -99,6 +108,10 @@ struct dib9000_state { struct i2c_msg msg[2]; u8 i2c_write_buffer[255]; u8 i2c_read_buffer[255]; + DIB_LOCK demod_lock; + u8 get_frontend_internal; + struct dib9000_pid_ctrl pid_ctrl[10]; + s8 pid_ctrl_index; /* -1: empty list; -2: do not use the list */ }; static const u32 fe_info[44] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1743,19 +1756,56 @@ EXPORT_SYMBOL(dib9000_set_gpio); int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) { struct dib9000_state *state = fe->demodulator_priv; - u16 val = dib9000_read_word(state, 294 + 1) & 0xffef; + u16 val; + int ret; + + if ((state->pid_ctrl_index != -2) && (state->pid_ctrl_index < 9)) { + /* postpone the pid filtering cmd */ + dprintk("pid filter cmd postpone"); + state->pid_ctrl_index++; + state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER_CTRL; + state->pid_ctrl[state->pid_ctrl_index].onoff = onoff; + return 0; + } + + DibAcquireLock(&state->demod_lock); + + val = dib9000_read_word(state, 294 + 1) & 0xffef; val |= (onoff & 0x1) << 4; dprintk("PID filter enabled %d", onoff); - return dib9000_write_word(state, 294 + 1, val); + ret = dib9000_write_word(state, 294 + 1, val); + DibReleaseLock(&state->demod_lock); + return ret; + } EXPORT_SYMBOL(dib9000_fw_pid_filter_ctrl); int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) { struct dib9000_state *state = fe->demodulator_priv; + int ret; + + if (state->pid_ctrl_index != -2) { + /* postpone the pid filtering cmd */ + dprintk("pid filter postpone"); + if (state->pid_ctrl_index < 9) { + state->pid_ctrl_index++; + state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER; + state->pid_ctrl[state->pid_ctrl_index].id = id; + state->pid_ctrl[state->pid_ctrl_index].pid = pid; + state->pid_ctrl[state->pid_ctrl_index].onoff = onoff; + } else + dprintk("can not add any more pid ctrl cmd"); + return 0; + } + + DibAcquireLock(&state->demod_lock); dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff); - return dib9000_write_word(state, 300 + 1 + id, onoff ? (1 << 13) | pid : 0); + ret = dib9000_write_word(state, 300 + 1 + id, + onoff ? (1 << 13) | pid : 0); + DibReleaseLock(&state->demod_lock); + return ret; } EXPORT_SYMBOL(dib9000_fw_pid_filter); @@ -1778,6 +1828,7 @@ static void dib9000_release(struct dvb_frontend *demod) DibFreeLock(&state->platform.risc.mbx_lock); DibFreeLock(&state->platform.risc.mem_lock); DibFreeLock(&state->platform.risc.mem_mbx_lock); + DibFreeLock(&state->demod_lock); dibx000_exit_i2c_master(&st->i2c_master); i2c_del_adapter(&st->tuner_adap); @@ -1795,14 +1846,19 @@ static int dib9000_sleep(struct dvb_frontend *fe) { struct dib9000_state *state = fe->demodulator_priv; u8 index_frontend; - int ret; + int ret = 0; + DibAcquireLock(&state->demod_lock); for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]); if (ret < 0) - return ret; + goto error; } - return dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0); + ret = dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0); + +error: + DibReleaseLock(&state->demod_lock); + return ret; } static int dib9000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune) @@ -1816,7 +1872,10 @@ static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par struct dib9000_state *state = fe->demodulator_priv; u8 index_frontend, sub_index_frontend; fe_status_t stat; - int ret; + int ret = 0; + + if (state->get_frontend_internal == 0) + DibAcquireLock(&state->demod_lock); for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat); @@ -1846,14 +1905,15 @@ static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par state->fe[index_frontend]->dtv_property_cache.rolloff; } } - return 0; + ret = 0; + goto return_value; } } /* get the channel from master chip */ ret = dib9000_fw_get_channel(fe, fep); if (ret != 0) - return ret; + goto return_value; /* synchronize the cache with the other frontends */ for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { @@ -1866,8 +1926,12 @@ static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par state->fe[index_frontend]->dtv_property_cache.code_rate_LP = fe->dtv_property_cache.code_rate_LP; state->fe[index_frontend]->dtv_property_cache.rolloff = fe->dtv_property_cache.rolloff; } + ret = 0; - return 0; +return_value: + if (state->get_frontend_internal == 0) + DibReleaseLock(&state->demod_lock); + return ret; } static int dib9000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) @@ -1912,6 +1976,10 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par dprintk("dib9000: must specify bandwidth "); return 0; } + + state->pid_ctrl_index = -1; /* postpone the pid filtering cmd */ + DibAcquireLock(&state->demod_lock); + fe->dtv_property_cache.delivery_system = SYS_DVBT; /* set the master status */ @@ -1974,13 +2042,18 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par /* check the tune result */ if (exit_condition == 1) { /* tune failed */ dprintk("tune failed"); + DibReleaseLock(&state->demod_lock); + /* tune failed; put all the pid filtering cmd to junk */ + state->pid_ctrl_index = -1; return 0; } dprintk("tune success on frontend%i", index_frontend_success); /* synchronize all the channel cache */ + state->get_frontend_internal = 1; dib9000_get_frontend(state->fe[0], fep); + state->get_frontend_internal = 0; /* retune the other frontends with the found channel */ channel_status.status = CHANNEL_STATUS_PARAMETERS_SET; @@ -2025,6 +2098,28 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par /* turn off the diversity for the last frontend */ dib9000_fw_set_diversity_in(state->fe[index_frontend - 1], 0); + DibReleaseLock(&state->demod_lock); + if (state->pid_ctrl_index >= 0) { + u8 index_pid_filter_cmd; + u8 pid_ctrl_index = state->pid_ctrl_index; + + state->pid_ctrl_index = -2; + for (index_pid_filter_cmd = 0; + index_pid_filter_cmd <= pid_ctrl_index; + index_pid_filter_cmd++) { + if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER_CTRL) + dib9000_fw_pid_filter_ctrl(state->fe[0], + state->pid_ctrl[index_pid_filter_cmd].onoff); + else if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER) + dib9000_fw_pid_filter(state->fe[0], + state->pid_ctrl[index_pid_filter_cmd].id, + state->pid_ctrl[index_pid_filter_cmd].pid, + state->pid_ctrl[index_pid_filter_cmd].onoff); + } + } + /* do not postpone any more the pid filtering */ + state->pid_ctrl_index = -2; + return 0; } @@ -2041,6 +2136,7 @@ static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat) u8 index_frontend; u16 lock = 0, lock_slave = 0; + DibAcquireLock(&state->demod_lock); for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) lock_slave |= dib9000_read_lock(state->fe[index_frontend]); @@ -2059,6 +2155,8 @@ static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat) if ((lock & 0x0008) || (lock_slave & 0x0008)) *stat |= FE_HAS_LOCK; + DibReleaseLock(&state->demod_lock); + return 0; } @@ -2066,10 +2164,14 @@ static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber) { struct dib9000_state *state = fe->demodulator_priv; u16 *c; + int ret = 0; + DibAcquireLock(&state->demod_lock); DibAcquireLock(&state->platform.risc.mem_mbx_lock); - if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) - return -EIO; + if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { + ret = -EIO; + goto error; + } dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, state->i2c_read_buffer, 16 * 2); DibReleaseLock(&state->platform.risc.mem_mbx_lock); @@ -2077,7 +2179,10 @@ static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber) c = (u16 *)state->i2c_read_buffer; *ber = c[10] << 16 | c[11]; - return 0; + +error: + DibReleaseLock(&state->demod_lock); + return ret; } static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) @@ -2086,7 +2191,9 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) u8 index_frontend; u16 *c = (u16 *)state->i2c_read_buffer; u16 val; + int ret = 0; + DibAcquireLock(&state->demod_lock); *strength = 0; for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val); @@ -2097,8 +2204,10 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) } DibAcquireLock(&state->platform.risc.mem_mbx_lock); - if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) - return -EIO; + if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { + ret = -EIO; + goto error; + } dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); DibReleaseLock(&state->platform.risc.mem_mbx_lock); @@ -2107,7 +2216,10 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) *strength = 65535; else *strength += val; - return 0; + +error: + DibReleaseLock(&state->demod_lock); + return ret; } static u32 dib9000_get_snr(struct dvb_frontend *fe) @@ -2151,6 +2263,7 @@ static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr) u8 index_frontend; u32 snr_master; + DibAcquireLock(&state->demod_lock); snr_master = dib9000_get_snr(fe); for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) snr_master += dib9000_get_snr(state->fe[index_frontend]); @@ -2161,6 +2274,8 @@ static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr) } else *snr = 0; + DibReleaseLock(&state->demod_lock); + return 0; } @@ -2168,15 +2283,22 @@ static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) { struct dib9000_state *state = fe->demodulator_priv; u16 *c = (u16 *)state->i2c_read_buffer; + int ret = 0; + DibAcquireLock(&state->demod_lock); DibAcquireLock(&state->platform.risc.mem_mbx_lock); - if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) - return -EIO; + if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { + ret = -EIO; + goto error; + } dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); DibReleaseLock(&state->platform.risc.mem_mbx_lock); *unc = c[12]; - return 0; + +error: + DibReleaseLock(&state->demod_lock); + return ret; } int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, u8 first_addr) @@ -2322,6 +2444,10 @@ struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, c DibInitLock(&st->platform.risc.mbx_lock); DibInitLock(&st->platform.risc.mem_lock); DibInitLock(&st->platform.risc.mem_mbx_lock); + DibInitLock(&st->demod_lock); + st->get_frontend_internal = 0; + + st->pid_ctrl_index = -2; st->fe[0] = fe; fe->demodulator_priv = st; diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb/frontends/dibx000_common.c index dc5d17a..774d507 100644 --- a/drivers/media/dvb/frontends/dibx000_common.c +++ b/drivers/media/dvb/frontends/dibx000_common.c @@ -1,4 +1,5 @@ #include +#include #include "dibx000_common.h" @@ -10,6 +11,13 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val) { + int ret; + + if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + mst->i2c_write_buffer[0] = (reg >> 8) & 0xff; mst->i2c_write_buffer[1] = reg & 0xff; mst->i2c_write_buffer[2] = (val >> 8) & 0xff; @@ -21,11 +29,21 @@ static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val) mst->msg[0].buf = mst->i2c_write_buffer; mst->msg[0].len = 4; - return i2c_transfer(mst->i2c_adap, mst->msg, 1) != 1 ? -EREMOTEIO : 0; + ret = i2c_transfer(mst->i2c_adap, mst->msg, 1) != 1 ? -EREMOTEIO : 0; + mutex_unlock(&mst->i2c_buffer_lock); + + return ret; } static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg) { + u16 ret; + + if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return 0; + } + mst->i2c_write_buffer[0] = reg >> 8; mst->i2c_write_buffer[1] = reg & 0xff; @@ -42,7 +60,10 @@ static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg) if (i2c_transfer(mst->i2c_adap, mst->msg, 2) != 2) dprintk("i2c read error on %d", reg); - return (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1]; + ret = (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1]; + mutex_unlock(&mst->i2c_buffer_lock); + + return ret; } static int dibx000_is_i2c_done(struct dibx000_i2c_master *mst) @@ -257,6 +278,7 @@ static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) { struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); + int ret; if (num > 32) { dprintk("%s: too much I2C message to be transmitted (%i).\ @@ -264,10 +286,15 @@ static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap, return -ENOMEM; } - memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num)); - dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_6_7); + if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + + memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num)); + /* open the gate */ dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1); mst->msg[0].addr = mst->i2c_addr; @@ -282,7 +309,11 @@ static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap, mst->msg[num + 1].buf = &mst->i2c_write_buffer[4]; mst->msg[num + 1].len = 4; - return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO; + ret = (i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? + num : -EIO); + + mutex_unlock(&mst->i2c_buffer_lock); + return ret; } static struct i2c_algorithm dibx000_i2c_gated_gpio67_algo = { @@ -294,6 +325,7 @@ static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) { struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); + int ret; if (num > 32) { dprintk("%s: too much I2C message to be transmitted (%i).\ @@ -301,10 +333,14 @@ static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap, return -ENOMEM; } - memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num)); - dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER); + if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num)); + /* open the gate */ dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1); mst->msg[0].addr = mst->i2c_addr; @@ -319,7 +355,10 @@ static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap, mst->msg[num + 1].buf = &mst->i2c_write_buffer[4]; mst->msg[num + 1].len = 4; - return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO; + ret = (i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? + num : -EIO); + mutex_unlock(&mst->i2c_buffer_lock); + return ret; } static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = { @@ -390,8 +429,18 @@ static int i2c_adapter_init(struct i2c_adapter *i2c_adap, int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, struct i2c_adapter *i2c_adap, u8 i2c_addr) { - u8 tx[4]; - struct i2c_msg m = {.addr = i2c_addr >> 1,.buf = tx,.len = 4 }; + int ret; + + mutex_init(&mst->i2c_buffer_lock); + if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + memset(mst->msg, 0, sizeof(struct i2c_msg)); + mst->msg[0].addr = i2c_addr >> 1; + mst->msg[0].flags = 0; + mst->msg[0].buf = mst->i2c_write_buffer; + mst->msg[0].len = 4; mst->device_rev = device_rev; mst->i2c_adap = i2c_adap; @@ -431,9 +480,12 @@ int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, "DiBX000: could not initialize the master i2c_adapter\n"); /* initialize the i2c-master by closing the gate */ - dibx000_i2c_gate_ctrl(mst, tx, 0, 0); + dibx000_i2c_gate_ctrl(mst, mst->i2c_write_buffer, 0, 0); + + ret = (i2c_transfer(i2c_adap, mst->msg, 1) == 1); + mutex_unlock(&mst->i2c_buffer_lock); - return i2c_transfer(i2c_adap, &m, 1) == 1; + return ret; } EXPORT_SYMBOL(dibx000_init_i2c_master); diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h index f031165..5e01147 100644 --- a/drivers/media/dvb/frontends/dibx000_common.h +++ b/drivers/media/dvb/frontends/dibx000_common.h @@ -33,6 +33,7 @@ struct dibx000_i2c_master { struct i2c_msg msg[34]; u8 i2c_write_buffer[8]; u8 i2c_read_buffer[2]; + struct mutex i2c_buffer_lock; }; extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, -- cgit v0.10.2 From bff469f4167fdabfe15294f375577d7eadbaa1bb Mon Sep 17 00:00:00 2001 From: Olivier Grenie Date: Mon, 1 Aug 2011 12:45:58 -0300 Subject: [media] dib0700: protect the dib0700 buffer access This patch protects the common buffer access inside the dib0700 in order to manage concurrent access. This protection is done using mutex. Cc: Mauro Carvalho Chehab Cc: Florian Mickler Cc: stable@kernel.org Signed-off-by: Javier Marcet Signed-off-by: Olivier Grenie Signed-off-by: Patrick Boettcher [mchehab@redhat.com: dprint requires 3 arguments. Replaced by dib_info] Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index 5eb91b4..a224e94 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -30,6 +30,11 @@ int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, struct dib0700_state *st = d->priv; int ret; + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + deb_info("could not acquire lock"); + return 0; + } + ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), REQUEST_GET_VERSION, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, @@ -46,6 +51,7 @@ int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, if (fwtype != NULL) *fwtype = (st->buf[12] << 24) | (st->buf[13] << 16) | (st->buf[14] << 8) | st->buf[15]; + mutex_unlock(&d->usb_mutex); return ret; } @@ -108,7 +114,12 @@ int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val) { struct dib0700_state *st = d->priv; - s16 ret; + int ret; + + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + deb_info("could not acquire lock"); + return 0; + } st->buf[0] = REQUEST_SET_GPIO; st->buf[1] = gpio; @@ -116,6 +127,7 @@ int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_ ret = dib0700_ctrl_wr(d, st->buf, 3); + mutex_unlock(&d->usb_mutex); return ret; } @@ -125,6 +137,11 @@ static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets) int ret; if (st->fw_version >= 0x10201) { + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + deb_info("could not acquire lock"); + return 0; + } + st->buf[0] = REQUEST_SET_USB_XFER_LEN; st->buf[1] = (nb_ts_packets >> 8) & 0xff; st->buf[2] = nb_ts_packets & 0xff; @@ -132,6 +149,7 @@ static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets) deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets); ret = dib0700_ctrl_wr(d, st->buf, 3); + mutex_unlock(&d->usb_mutex); } else { deb_info("this firmware does not allow to change the USB xfer len\n"); ret = -EIO; @@ -208,6 +226,10 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg, } else { /* Write request */ + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + deb_info("could not acquire lock"); + return 0; + } st->buf[0] = REQUEST_NEW_I2C_WRITE; st->buf[1] = msg[i].addr << 1; st->buf[2] = (en_start << 7) | (en_stop << 6) | @@ -227,6 +249,7 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg, USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, st->buf, msg[i].len + 4, USB_CTRL_GET_TIMEOUT); + mutex_unlock(&d->usb_mutex); if (result < 0) { deb_info("i2c write error (status = %d)\n", result); break; @@ -249,6 +272,10 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap, if (mutex_lock_interruptible(&d->i2c_mutex) < 0) return -EAGAIN; + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + deb_info("could not acquire lock"); + return 0; + } for (i = 0; i < num; i++) { /* fill in the address */ @@ -279,6 +306,7 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap, break; } } + mutex_unlock(&d->usb_mutex); mutex_unlock(&d->i2c_mutex); return i; @@ -337,7 +365,12 @@ static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll, u16 pll_loopdiv, u16 free_div, u16 dsuScaler) { struct dib0700_state *st = d->priv; - s16 ret; + int ret; + + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + deb_info("could not acquire lock"); + return 0; + } st->buf[0] = REQUEST_SET_CLOCK; st->buf[1] = (en_pll << 7) | (pll_src << 6) | @@ -352,6 +385,7 @@ static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll, st->buf[9] = dsuScaler & 0xff; /* LSB */ ret = dib0700_ctrl_wr(d, st->buf, 10); + mutex_unlock(&d->usb_mutex); return ret; } @@ -360,10 +394,16 @@ int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz) { struct dib0700_state *st = d->priv; u16 divider; + int ret; if (scl_kHz == 0) return -EINVAL; + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + deb_info("could not acquire lock"); + return 0; + } + st->buf[0] = REQUEST_SET_I2C_PARAM; divider = (u16) (30000 / scl_kHz); st->buf[1] = 0; @@ -379,7 +419,11 @@ int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz) deb_info("setting I2C speed: %04x %04x %04x (%d kHz).", (st->buf[2] << 8) | (st->buf[3]), (st->buf[4] << 8) | st->buf[5], (st->buf[6] << 8) | st->buf[7], scl_kHz); - return dib0700_ctrl_wr(d, st->buf, 8); + + ret = dib0700_ctrl_wr(d, st->buf, 8); + mutex_unlock(&d->usb_mutex); + + return ret; } @@ -515,6 +559,11 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) } } + if (mutex_lock_interruptible(&adap->dev->usb_mutex) < 0) { + deb_info("could not acquire lock"); + return 0; + } + st->buf[0] = REQUEST_ENABLE_VIDEO; /* this bit gives a kind of command, * rather than enabling something or not */ @@ -548,7 +597,10 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) deb_info("data for streaming: %x %x\n", st->buf[1], st->buf[2]); - return dib0700_ctrl_wr(adap->dev, st->buf, 4); + ret = dib0700_ctrl_wr(adap->dev, st->buf, 4); + mutex_unlock(&adap->dev->usb_mutex); + + return ret; } int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type) @@ -557,6 +609,11 @@ int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type) struct dib0700_state *st = d->priv; int new_proto, ret; + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + deb_info("could not acquire lock"); + return 0; + } + st->buf[0] = REQUEST_SET_RC; st->buf[1] = 0; st->buf[2] = 0; @@ -567,23 +624,29 @@ int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type) else if (rc_type == RC_TYPE_NEC) new_proto = 0; else if (rc_type == RC_TYPE_RC6) { - if (st->fw_version < 0x10200) - return -EINVAL; + if (st->fw_version < 0x10200) { + ret = -EINVAL; + goto out; + } new_proto = 2; - } else - return -EINVAL; + } else { + ret = -EINVAL; + goto out; + } st->buf[1] = new_proto; ret = dib0700_ctrl_wr(d, st->buf, 3); if (ret < 0) { err("ir protocol setup failed"); - return ret; + goto out; } d->props.rc.core.protocol = rc_type; +out: + mutex_unlock(&d->usb_mutex); return ret; } -- cgit v0.10.2 From 680417bb318adc5f1f8f392730776176fbcdedd8 Mon Sep 17 00:00:00 2001 From: Olivier Grenie Date: Thu, 4 Aug 2011 13:10:03 -0300 Subject: [media] dib0700: correct error message The goal of this patch is to correct a previous patch. In case of error, the err() function should be used instead of dprintk() function. [mchehab@redhat.com: as I've replaced dprintk by deb_info, on the the previous patch, to avoid breaking bisect, I had to fix a merge conflict on this one] Signed-off-by: Olivier Grenie Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index a224e94..b693ed1 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -31,7 +31,7 @@ int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, int ret; if (mutex_lock_interruptible(&d->usb_mutex) < 0) { - deb_info("could not acquire lock"); + err("could not acquire lock"); return 0; } @@ -117,7 +117,7 @@ int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_ int ret; if (mutex_lock_interruptible(&d->usb_mutex) < 0) { - deb_info("could not acquire lock"); + err("could not acquire lock"); return 0; } @@ -138,7 +138,7 @@ static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets) if (st->fw_version >= 0x10201) { if (mutex_lock_interruptible(&d->usb_mutex) < 0) { - deb_info("could not acquire lock"); + err("could not acquire lock"); return 0; } @@ -227,7 +227,7 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg, } else { /* Write request */ if (mutex_lock_interruptible(&d->usb_mutex) < 0) { - deb_info("could not acquire lock"); + err("could not acquire lock"); return 0; } st->buf[0] = REQUEST_NEW_I2C_WRITE; @@ -273,7 +273,7 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap, if (mutex_lock_interruptible(&d->i2c_mutex) < 0) return -EAGAIN; if (mutex_lock_interruptible(&d->usb_mutex) < 0) { - deb_info("could not acquire lock"); + err("could not acquire lock"); return 0; } @@ -368,7 +368,7 @@ static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll, int ret; if (mutex_lock_interruptible(&d->usb_mutex) < 0) { - deb_info("could not acquire lock"); + err("could not acquire lock"); return 0; } @@ -400,7 +400,7 @@ int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz) return -EINVAL; if (mutex_lock_interruptible(&d->usb_mutex) < 0) { - deb_info("could not acquire lock"); + err("could not acquire lock"); return 0; } @@ -560,7 +560,7 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) } if (mutex_lock_interruptible(&adap->dev->usb_mutex) < 0) { - deb_info("could not acquire lock"); + err("could not acquire lock"); return 0; } @@ -610,7 +610,7 @@ int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type) int new_proto, ret; if (mutex_lock_interruptible(&d->usb_mutex) < 0) { - deb_info("could not acquire lock"); + err("could not acquire lock"); return 0; } -- cgit v0.10.2 From 572064280ecc9dc89227cf3797bc2144896a34f5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 25 Jul 2011 11:16:41 -0300 Subject: [media] adp1653: check platform_data before usage The driver requires platform_data to be present. That's why we need to check and fail in case of the absence of necessary data. Signed-off-by: Andy Shevchenko Cc: Mauro Carvalho Chehab Cc: Sakari Ailus Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/adp1653.c b/drivers/media/video/adp1653.c index be7befd..8ad89ff 100644 --- a/drivers/media/video/adp1653.c +++ b/drivers/media/video/adp1653.c @@ -413,6 +413,10 @@ static int adp1653_probe(struct i2c_client *client, struct adp1653_flash *flash; int ret; + /* we couldn't work without platform data */ + if (client->dev.platform_data == NULL) + return -ENODEV; + flash = kzalloc(sizeof(*flash), GFP_KERNEL); if (flash == NULL) return -ENOMEM; -- cgit v0.10.2 From 31ee95ec2d3dd3b6f68d7fa0f410045652895af2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 28 Jul 2011 04:59:38 -0300 Subject: [media] adp1653: check error code of adp1653_init_controls Potentially the adp1653_init_controls could return an error. In our case the error was ignored, meanwhile it means incorrect initialization of V4L2 controls. Additionally we have to free control handler structures in case of apd1653_init_controls or media_entity_init failure. Signed-off-by: Andy Shevchenko Cc: Sakari Ailus Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/adp1653.c b/drivers/media/video/adp1653.c index 8ad89ff..279d75d 100644 --- a/drivers/media/video/adp1653.c +++ b/drivers/media/video/adp1653.c @@ -429,12 +429,19 @@ static int adp1653_probe(struct i2c_client *client, flash->subdev.internal_ops = &adp1653_internal_ops; flash->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - adp1653_init_controls(flash); + ret = adp1653_init_controls(flash); + if (ret) + goto free_and_quit; ret = media_entity_init(&flash->subdev.entity, 0, NULL, 0); if (ret < 0) - kfree(flash); + goto free_and_quit; + return 0; + +free_and_quit: + v4l2_ctrl_handler_free(&flash->ctrls); + kfree(flash); return ret; } -- cgit v0.10.2 From ffd638e0e613578fbe82d5f2d9c1e5ec503a3a2b Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 18 Jul 2011 11:03:05 -0300 Subject: [media] v4l: Move event documentation from SUBSCRIBE_EVENT to DQEVENT Move documentation of structures used in DQEVENT from SUBSCRIBE_EVENT to DQEVENT. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml index 7769642..5200b68 100644 --- a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml +++ b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml @@ -135,6 +135,113 @@ + + struct <structname>v4l2_event_vsync</structname> + + &cs-str; + + + __u8 + field + The upcoming field. See &v4l2-field;. + + + +
+ + + struct <structname>v4l2_event_ctrl</structname> + + &cs-str; + + + __u32 + changes + + A bitmask that tells what has changed. See . + + + __u32 + type + + The type of the control. See &v4l2-ctrl-type;. + + + union (anonymous) + + + + + + + __s32 + value + The 32-bit value of the control for 32-bit control types. + This is 0 for string controls since the value of a string + cannot be passed using &VIDIOC-DQEVENT;. + + + + __s64 + value64 + The 64-bit value of the control for 64-bit control types. + + + __u32 + flags + + The control flags. See . + + + __s32 + minimum + + The minimum value of the control. See &v4l2-queryctrl;. + + + __s32 + maximum + + The maximum value of the control. See &v4l2-queryctrl;. + + + __s32 + step + + The step value of the control. See &v4l2-queryctrl;. + + + __s32 + default_value + + The default value value of the control. See &v4l2-queryctrl;. + + + +
+ + + Changes + + &cs-def; + + + V4L2_EVENT_CTRL_CH_VALUE + 0x0001 + This control event was triggered because the value of the control + changed. Special case: if a button control is pressed, then this + event is sent as well, even though there is not explicit value + associated with a button control. + + + V4L2_EVENT_CTRL_CH_FLAGS + 0x0002 + This control event was triggered because the control flags + changed. + + + +
&return-value; diff --git a/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml index 69c0d8a..275be96 100644 --- a/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml +++ b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml @@ -183,113 +183,6 @@ - - struct <structname>v4l2_event_vsync</structname> - - &cs-str; - - - __u8 - field - The upcoming field. See &v4l2-field;. - - - -
- - - struct <structname>v4l2_event_ctrl</structname> - - &cs-str; - - - __u32 - changes - - A bitmask that tells what has changed. See . - - - __u32 - type - - The type of the control. See &v4l2-ctrl-type;. - - - union (anonymous) - - - - - - - __s32 - value - The 32-bit value of the control for 32-bit control types. - This is 0 for string controls since the value of a string - cannot be passed using &VIDIOC-DQEVENT;. - - - - __s64 - value64 - The 64-bit value of the control for 64-bit control types. - - - __u32 - flags - - The control flags. See . - - - __s32 - minimum - - The minimum value of the control. See &v4l2-queryctrl;. - - - __s32 - maximum - - The maximum value of the control. See &v4l2-queryctrl;. - - - __s32 - step - - The step value of the control. See &v4l2-queryctrl;. - - - __s32 - default_value - - The default value value of the control. See &v4l2-queryctrl;. - - - -
- - - Changes - - &cs-def; - - - V4L2_EVENT_CTRL_CH_VALUE - 0x0001 - This control event was triggered because the value of the control - changed. Special case: if a button control is pressed, then this - event is sent as well, even though there is not explicit value - associated with a button control. - - - V4L2_EVENT_CTRL_CH_FLAGS - 0x0002 - This control event was triggered because the control flags - changed. - - - -
&return-value; -- cgit v0.10.2 From 9bed77ee2fb46b74782d0d9d14b92e9d07f3df6e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 28 Jul 2011 16:38:54 -0300 Subject: [media] tuner_xc2028: Allow selection of the frequency adjustment code for XC3028 This device is not using the proper demod IF. Instead of using the IF macro, it is specifying a IF frequency. This doesn't work, as xc3028 needs to load an specific SCODE for the tuner. In this case, there's no IF table for 5 MHz. Cc: stable@kernel.org Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index aa83f07..bcb45be 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -844,7 +844,7 @@ static int dvb_register(struct cx23885_tsport *port) static struct xc2028_ctrl ctl = { .fname = XC3028L_DEFAULT_FIRMWARE, .max_len = 64, - .demod = 5000, + .demod = XC3028_FE_DIBCOM52, /* This is true for all demods with v36 firmware? */ .type = XC2028_D2633, -- cgit v0.10.2 From d59a7b1dbce8b972ec2dc9fcaaae0bfa23687423 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Sat, 16 Jul 2011 00:51:00 -0300 Subject: [media] uvcvideo: Set alternate setting 0 on resume if the bus has been reset If the bus has been reset on resume, set the alternate setting to 0. This should be the default value, but some devices crash or otherwise misbehave if they don't receive a SET_INTERFACE request before any other video control request. Microdia's 0c45:6437 camera has been found to require this change or it will stop sending video data after resume. uvc_video.c] Signed-off-by: Ming Lei Signed-off-by: Laurent Pinchart Cc: stable@kernel.org Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index d29f9c2..e4100b1 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c @@ -1961,7 +1961,7 @@ static int __uvc_resume(struct usb_interface *intf, int reset) list_for_each_entry(stream, &dev->streams, list) { if (stream->intf == intf) - return uvc_video_resume(stream); + return uvc_video_resume(stream, reset); } uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB interface " diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index 8244167..ffd1158 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c @@ -1104,10 +1104,18 @@ int uvc_video_suspend(struct uvc_streaming *stream) * buffers, making sure userspace applications are notified of the problem * instead of waiting forever. */ -int uvc_video_resume(struct uvc_streaming *stream) +int uvc_video_resume(struct uvc_streaming *stream, int reset) { int ret; + /* If the bus has been reset on resume, set the alternate setting to 0. + * This should be the default value, but some devices crash or otherwise + * misbehave if they don't receive a SET_INTERFACE request before any + * other video control request. + */ + if (reset) + usb_set_interface(stream->dev->udev, stream->intfnum, 0); + stream->frozen = 0; ret = uvc_commit_video(stream, &stream->ctrl); diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index df32a43..cbdd49b 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h @@ -638,7 +638,7 @@ extern void uvc_mc_cleanup_entity(struct uvc_entity *entity); /* Video */ extern int uvc_video_init(struct uvc_streaming *stream); extern int uvc_video_suspend(struct uvc_streaming *stream); -extern int uvc_video_resume(struct uvc_streaming *stream); +extern int uvc_video_resume(struct uvc_streaming *stream, int reset); extern int uvc_video_enable(struct uvc_streaming *stream, int enable); extern int uvc_probe_video(struct uvc_streaming *stream, struct uvc_streaming_control *probe); -- cgit v0.10.2 From 47a09b082f70502195ee800bb0cd6f311b125c8f Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Thu, 14 Jul 2011 14:20:46 -0300 Subject: [media] imon: rate-limit send_packet spew There are folks with flaky imon hardware out there that doesn't always respond to requests to write to their displays for some reason, which can flood logs quickly when something like lcdproc is trying to constantly update the display, so lets rate-limit all that error spew. Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 6bc35ee..caa3e3a 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -516,19 +517,19 @@ static int send_packet(struct imon_context *ictx) if (retval) { ictx->tx.busy = false; smp_rmb(); /* ensure later readers know we're not busy */ - pr_err("error submitting urb(%d)\n", retval); + pr_err_ratelimited("error submitting urb(%d)\n", retval); } else { /* Wait for transmission to complete (or abort) */ mutex_unlock(&ictx->lock); retval = wait_for_completion_interruptible( &ictx->tx.finished); if (retval) - pr_err("task interrupted\n"); + pr_err_ratelimited("task interrupted\n"); mutex_lock(&ictx->lock); retval = ictx->tx.status; if (retval) - pr_err("packet tx failed (%d)\n", retval); + pr_err_ratelimited("packet tx failed (%d)\n", retval); } kfree(control_req); @@ -830,20 +831,20 @@ static ssize_t vfd_write(struct file *file, const char *buf, ictx = file->private_data; if (!ictx) { - pr_err("no context for device\n"); + pr_err_ratelimited("no context for device\n"); return -ENODEV; } mutex_lock(&ictx->lock); if (!ictx->dev_present_intf0) { - pr_err("no iMON device present\n"); + pr_err_ratelimited("no iMON device present\n"); retval = -ENODEV; goto exit; } if (n_bytes <= 0 || n_bytes > 32) { - pr_err("invalid payload size\n"); + pr_err_ratelimited("invalid payload size\n"); retval = -EINVAL; goto exit; } @@ -869,7 +870,7 @@ static ssize_t vfd_write(struct file *file, const char *buf, retval = send_packet(ictx); if (retval) { - pr_err("send packet failed for packet #%d\n", seq / 2); + pr_err_ratelimited("send packet #%d failed\n", seq / 2); goto exit; } else { seq += 2; @@ -883,7 +884,7 @@ static ssize_t vfd_write(struct file *file, const char *buf, ictx->usb_tx_buf[7] = (unsigned char) seq; retval = send_packet(ictx); if (retval) - pr_err("send packet failed for packet #%d\n", seq / 2); + pr_err_ratelimited("send packet #%d failed\n", seq / 2); exit: mutex_unlock(&ictx->lock); @@ -912,20 +913,21 @@ static ssize_t lcd_write(struct file *file, const char *buf, ictx = file->private_data; if (!ictx) { - pr_err("no context for device\n"); + pr_err_ratelimited("no context for device\n"); return -ENODEV; } mutex_lock(&ictx->lock); if (!ictx->display_supported) { - pr_err("no iMON display present\n"); + pr_err_ratelimited("no iMON display present\n"); retval = -ENODEV; goto exit; } if (n_bytes != 8) { - pr_err("invalid payload size: %d (expected 8)\n", (int)n_bytes); + pr_err_ratelimited("invalid payload size: %d (expected 8)\n", + (int)n_bytes); retval = -EINVAL; goto exit; } @@ -937,7 +939,7 @@ static ssize_t lcd_write(struct file *file, const char *buf, retval = send_packet(ictx); if (retval) { - pr_err("send packet failed!\n"); + pr_err_ratelimited("send packet failed!\n"); goto exit; } else { dev_dbg(ictx->dev, "%s: write %d bytes to LCD\n", -- cgit v0.10.2 From d1520c58eb84ad1ec973a257cd835c948215aab5 Mon Sep 17 00:00:00 2001 From: Luiz Ramos Date: Thu, 14 Jul 2011 23:08:39 -0300 Subject: [media] Fix wrong register mask in gspca/sonixj.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hello, When migrating from Slackware 13.1 to 13.37 (kernel 2.6.33.x to 2.6.37.6), there was some sort of regression with the external webcam installed at the notebook (0x45:6128, SN9C325+OM6802). In the version 2.6.37.6, the images got *very* dark, making the webcam almost unusable, unless if used with direct sunlight. Tracing back what happened, I concluded that changeset 0e4d413af caused some sort of odd effects - including this - to this specific model. Signed-off-by: Luiz Carlos Ramos Acked-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 81b8a60..2ad757d 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -2386,7 +2386,7 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, 0x01, 0x22); msleep(100); reg01 = SCL_SEL_OD | S_PDN_INV; - reg17 &= MCK_SIZE_MASK; + reg17 &= ~MCK_SIZE_MASK; reg17 |= 0x04; /* clock / 4 */ break; } -- cgit v0.10.2 From 2d84ca215f6d67f9ba7b3d4ab32265e085229662 Mon Sep 17 00:00:00 2001 From: Jose Alberto Reguero Date: Sat, 16 Jul 2011 08:38:13 -0300 Subject: [media] tda827x: improve recection with limit frequencies tda827x is currently taking the demod IF frequency into account while seeking for the proper tuner range. This is wrong, as the demod IF frequency has nothing to do with the tuner PLL. Signed-off-by: Jose Alberto Reguero Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/common/tuners/tda827x.c b/drivers/media/common/tuners/tda827x.c index b21b6ea..e0d5b43 100644 --- a/drivers/media/common/tuners/tda827x.c +++ b/drivers/media/common/tuners/tda827x.c @@ -176,7 +176,7 @@ static int tda827xo_set_params(struct dvb_frontend *fe, if_freq = 5000000; break; } - tuner_freq = params->frequency + if_freq; + tuner_freq = params->frequency; i = 0; while (tda827x_table[i].lomax < tuner_freq) { @@ -185,6 +185,8 @@ static int tda827xo_set_params(struct dvb_frontend *fe, i++; } + tuner_freq += if_freq; + N = ((tuner_freq + 125000) / 250000) << (tda827x_table[i].spd + 2); buf[0] = 0; buf[1] = (N>>8) | 0x40; @@ -540,7 +542,7 @@ static int tda827xa_set_params(struct dvb_frontend *fe, if_freq = 5000000; break; } - tuner_freq = params->frequency + if_freq; + tuner_freq = params->frequency; if (fe->ops.info.type == FE_QAM) { dprintk("%s select tda827xa_dvbc\n", __func__); @@ -554,6 +556,8 @@ static int tda827xa_set_params(struct dvb_frontend *fe, i++; } + tuner_freq += if_freq; + N = ((tuner_freq + 31250) / 62500) << frequency_map[i].spd; buf[0] = 0; // subaddress buf[1] = N >> 8; -- cgit v0.10.2 From a6fbd3b77ad0ad7b3020b4f50659e740ff68c719 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 18 Jul 2011 16:54:21 -0300 Subject: [media] mceusb: command/response updates from MS docs I was recently pointed to the document titled Windows-Media-Center-RC-IR-Collection-Green-Button-Specification-03-08-2011-V2.pdf which as of this writing, is publicly available from download.microsoft.com. It covers a LOT of the gaps in the mceusb driver, which to this point, was written almost entirely by reverse-engineering. First up, I'm updating the defines for all the MCE commands and responses to match their names in the spec. More to come... Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 85ff9a1..eee28a5 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -63,43 +63,90 @@ #define MCE_PULSE_MASK 0x7f /* Pulse mask */ #define MCE_MAX_PULSE_LENGTH 0x7f /* Longest transmittable pulse symbol */ -#define MCE_HW_CMD_HEADER 0xff /* MCE hardware command header */ -#define MCE_COMMAND_HEADER 0x9f /* MCE command header */ -#define MCE_COMMAND_MASK 0xe0 /* Mask out command bits */ -#define MCE_COMMAND_NULL 0x00 /* These show up various places... */ -/* if buf[i] & MCE_COMMAND_MASK == 0x80 and buf[i] != MCE_COMMAND_HEADER, - * then we're looking at a raw IR data sample */ -#define MCE_COMMAND_IRDATA 0x80 -#define MCE_PACKET_LENGTH_MASK 0x1f /* Packet length mask */ - -/* Sub-commands, which follow MCE_COMMAND_HEADER or MCE_HW_CMD_HEADER */ +/* + * The interface between the host and the IR hardware is command-response + * based. All commands and responses have a consistent format, where a lead + * byte always identifies the type of data following it. The lead byte has + * a port value in the 3 highest bits and a length value in the 5 lowest + * bits. + * + * The length field is overloaded, with a value of 11111 indicating that the + * following byte is a command or response code, and the length of the entire + * message is determined by the code. If the length field is not 11111, then + * it specifies the number of bytes of port data that follow. + */ +#define MCE_CMD 0x1f +#define MCE_PORT_IR 0x4 /* (0x4 << 5) | MCE_CMD = 0x9f */ +#define MCE_PORT_SYS 0x7 /* (0x7 << 5) | MCE_CMD = 0xff */ +#define MCE_PORT_SER 0x6 /* 0xc0 thru 0xdf flush & 0x1f bytes */ +#define MCE_PORT_MASK 0xe0 /* Mask out command bits */ + +/* Command port headers */ +#define MCE_CMD_PORT_IR 0x9f /* IR-related cmd/rsp */ +#define MCE_CMD_PORT_SYS 0xff /* System (non-IR) device cmd/rsp */ + +/* Commands that set device state (2-4 bytes in length) */ +#define MCE_CMD_RESET 0xfe /* Reset device, 2 bytes */ +#define MCE_CMD_RESUME 0xaa /* Resume device after error, 2 bytes */ +#define MCE_CMD_SETIRCFS 0x06 /* Set tx carrier, 4 bytes */ +#define MCE_CMD_SETIRTIMEOUT 0x0c /* Set timeout, 4 bytes */ +#define MCE_CMD_SETIRTXPORTS 0x08 /* Set tx ports, 3 bytes */ +#define MCE_CMD_SETIRRXPORTEN 0x14 /* Set rx ports, 3 bytes */ +#define MCE_CMD_FLASHLED 0x23 /* Flash receiver LED, 2 bytes */ + +/* Commands that query device state (all 2 bytes, unless noted) */ +#define MCE_CMD_GETIRCFS 0x07 /* Get carrier */ +#define MCE_CMD_GETIRTIMEOUT 0x0d /* Get timeout */ +#define MCE_CMD_GETIRTXPORTS 0x13 /* Get tx ports */ +#define MCE_CMD_GETIRRXPORTEN 0x15 /* Get rx ports */ +#define MCE_CMD_GETPORTSTATUS 0x11 /* Get tx port status, 3 bytes */ +#define MCE_CMD_GETIRNUMPORTS 0x16 /* Get number of ports */ +#define MCE_CMD_GETWAKESOURCE 0x17 /* Get wake source */ +#define MCE_CMD_GETEMVER 0x22 /* Get emulator interface version */ +#define MCE_CMD_GETDEVDETAILS 0x21 /* Get device details (em ver2 only) */ +#define MCE_CMD_GETWAKESUPPORT 0x20 /* Get wake details (em ver2 only) */ +#define MCE_CMD_GETWAKEVERSION 0x18 /* Get wake pattern (em ver2 only) */ + +/* Misc commands */ +#define MCE_CMD_NOP 0xff /* No operation */ + +/* Responses to commands (non-error cases) */ +#define MCE_RSP_EQIRCFS 0x06 /* tx carrier, 4 bytes */ +#define MCE_RSP_EQIRTIMEOUT 0x0c /* rx timeout, 4 bytes */ +#define MCE_RSP_GETWAKESOURCE 0x17 /* wake source, 3 bytes */ +#define MCE_RSP_EQIRTXPORTS 0x08 /* tx port mask, 3 bytes */ +#define MCE_RSP_EQIRRXPORTEN 0x14 /* rx port mask, 3 bytes */ +#define MCE_RSP_GETPORTSTATUS 0x11 /* tx port status, 7 bytes */ +#define MCE_RSP_EQIRRXCFCNT 0x15 /* rx carrier count, 4 bytes */ +#define MCE_RSP_EQIRNUMPORTS 0x16 /* number of ports, 4 bytes */ +#define MCE_RSP_EQWAKESUPPORT 0x20 /* wake capabilities, 3 bytes */ +#define MCE_RSP_EQWAKEVERSION 0x18 /* wake pattern details, 6 bytes */ +#define MCE_RSP_EQDEVDETAILS 0x21 /* device capabilities, 3 bytes */ +#define MCE_RSP_EQEMVER 0x22 /* emulator interface ver, 3 bytes */ +#define MCE_RSP_FLASHLED 0x23 /* success flashing LED, 2 bytes */ + +/* Responses to error cases, must send MCE_CMD_RESUME to clear them */ +#define MCE_RSP_CMD_ILLEGAL 0xfe /* illegal command for port, 2 bytes */ +#define MCE_RSP_TX_TIMEOUT 0x81 /* tx timed out, 2 bytes */ + +/* Misc commands/responses not defined in the MCE remote/transceiver spec */ #define MCE_CMD_SIG_END 0x01 /* End of signal */ #define MCE_CMD_PING 0x03 /* Ping device */ #define MCE_CMD_UNKNOWN 0x04 /* Unknown */ #define MCE_CMD_UNKNOWN2 0x05 /* Unknown */ -#define MCE_CMD_S_CARRIER 0x06 /* Set TX carrier frequency */ -#define MCE_CMD_G_CARRIER 0x07 /* Get TX carrier frequency */ -#define MCE_CMD_S_TXMASK 0x08 /* Set TX port bitmask */ #define MCE_CMD_UNKNOWN3 0x09 /* Unknown */ #define MCE_CMD_UNKNOWN4 0x0a /* Unknown */ #define MCE_CMD_G_REVISION 0x0b /* Get hw/sw revision */ -#define MCE_CMD_S_TIMEOUT 0x0c /* Set RX timeout value */ -#define MCE_CMD_G_TIMEOUT 0x0d /* Get RX timeout value */ #define MCE_CMD_UNKNOWN5 0x0e /* Unknown */ #define MCE_CMD_UNKNOWN6 0x0f /* Unknown */ -#define MCE_CMD_G_RXPORTSTS 0x11 /* Get RX port status */ -#define MCE_CMD_G_TXMASK 0x13 /* Set TX port bitmask */ -#define MCE_CMD_S_RXSENSOR 0x14 /* Set RX sensor (std/learning) */ -#define MCE_CMD_G_RXSENSOR 0x15 /* Get RX sensor (std/learning) */ -#define MCE_RSP_PULSE_COUNT 0x15 /* RX pulse count (only if learning) */ -#define MCE_CMD_TX_PORTS 0x16 /* Get number of TX ports */ -#define MCE_CMD_G_WAKESRC 0x17 /* Get wake source */ -#define MCE_CMD_UNKNOWN7 0x18 /* Unknown */ #define MCE_CMD_UNKNOWN8 0x19 /* Unknown */ #define MCE_CMD_UNKNOWN9 0x1b /* Unknown */ -#define MCE_CMD_DEVICE_RESET 0xaa /* Reset the hardware */ -#define MCE_RSP_CMD_INVALID 0xfe /* Invalid command issued */ +#define MCE_CMD_NULL 0x00 /* These show up various places... */ +/* if buf[i] & MCE_PORT_MASK == 0x80 and buf[i] != MCE_CMD_PORT_IR, + * then we're looking at a raw IR data sample */ +#define MCE_COMMAND_IRDATA 0x80 +#define MCE_PACKET_LENGTH_MASK 0x1f /* Packet length mask */ /* module parameters */ #ifdef CONFIG_USB_DEBUG @@ -390,46 +437,25 @@ struct mceusb_dev { enum mceusb_model_type model; }; -/* - * MCE Device Command Strings - * Device command responses vary from device to device... - * - DEVICE_RESET resets the hardware to its default state - * - GET_REVISION fetches the hardware/software revision, common - * replies are ff 0b 45 ff 1b 08 and ff 0b 50 ff 1b 42 - * - GET_CARRIER_FREQ gets the carrier mode and frequency of the - * device, with replies in the form of 9f 06 MM FF, where MM is 0-3, - * meaning clk of 10000000, 2500000, 625000 or 156250, and FF is - * ((clk / frequency) - 1) - * - GET_RX_TIMEOUT fetches the receiver timeout in units of 50us, - * response in the form of 9f 0c msb lsb - * - GET_TX_BITMASK fetches the transmitter bitmask, replies in - * the form of 9f 08 bm, where bm is the bitmask - * - GET_RX_SENSOR fetches the RX sensor setting -- long-range - * general use one or short-range learning one, in the form of - * 9f 14 ss, where ss is either 01 for long-range or 02 for short - * - SET_CARRIER_FREQ sets a new carrier mode and frequency - * - SET_TX_BITMASK sets the transmitter bitmask - * - SET_RX_TIMEOUT sets the receiver timeout - * - SET_RX_SENSOR sets which receiver sensor to use - */ -static char DEVICE_RESET[] = {MCE_COMMAND_NULL, MCE_HW_CMD_HEADER, - MCE_CMD_DEVICE_RESET}; -static char GET_REVISION[] = {MCE_HW_CMD_HEADER, MCE_CMD_G_REVISION}; -static char GET_UNKNOWN[] = {MCE_HW_CMD_HEADER, MCE_CMD_UNKNOWN7}; -static char GET_UNKNOWN2[] = {MCE_COMMAND_HEADER, MCE_CMD_UNKNOWN2}; -static char GET_CARRIER_FREQ[] = {MCE_COMMAND_HEADER, MCE_CMD_G_CARRIER}; -static char GET_RX_TIMEOUT[] = {MCE_COMMAND_HEADER, MCE_CMD_G_TIMEOUT}; -static char GET_TX_BITMASK[] = {MCE_COMMAND_HEADER, MCE_CMD_G_TXMASK}; -static char GET_RX_SENSOR[] = {MCE_COMMAND_HEADER, MCE_CMD_G_RXSENSOR}; +/* MCE Device Command Strings, generally a port and command pair */ +static char DEVICE_RESUME[] = {MCE_CMD_NULL, MCE_CMD_PORT_SYS, + MCE_CMD_RESUME}; +static char GET_REVISION[] = {MCE_CMD_PORT_SYS, MCE_CMD_G_REVISION}; +static char GET_WAKEVERSION[] = {MCE_CMD_PORT_SYS, MCE_CMD_GETWAKEVERSION}; +static char GET_UNKNOWN2[] = {MCE_CMD_PORT_IR, MCE_CMD_UNKNOWN2}; +static char GET_CARRIER_FREQ[] = {MCE_CMD_PORT_IR, MCE_CMD_GETIRCFS}; +static char GET_RX_TIMEOUT[] = {MCE_CMD_PORT_IR, MCE_CMD_GETIRTIMEOUT}; +static char GET_TX_BITMASK[] = {MCE_CMD_PORT_IR, MCE_CMD_GETIRTXPORTS}; +static char GET_RX_SENSOR[] = {MCE_CMD_PORT_IR, MCE_CMD_GETIRRXPORTEN}; /* sub in desired values in lower byte or bytes for full command */ /* FIXME: make use of these for transmit. -static char SET_CARRIER_FREQ[] = {MCE_COMMAND_HEADER, - MCE_CMD_S_CARRIER, 0x00, 0x00}; -static char SET_TX_BITMASK[] = {MCE_COMMAND_HEADER, MCE_CMD_S_TXMASK, 0x00}; -static char SET_RX_TIMEOUT[] = {MCE_COMMAND_HEADER, - MCE_CMD_S_TIMEOUT, 0x00, 0x00}; -static char SET_RX_SENSOR[] = {MCE_COMMAND_HEADER, - MCE_CMD_S_RXSENSOR, 0x00}; +static char SET_CARRIER_FREQ[] = {MCE_CMD_PORT_IR, + MCE_CMD_SETIRCFS, 0x00, 0x00}; +static char SET_TX_BITMASK[] = {MCE_CMD_PORT_IR, MCE_CMD_SETIRTXPORTS, 0x00}; +static char SET_RX_TIMEOUT[] = {MCE_CMD_PORT_IR, + MCE_CMD_SETIRTIMEOUT, 0x00, 0x00}; +static char SET_RX_SENSOR[] = {MCE_CMD_PORT_IR, + MCE_RSP_EQIRRXPORTEN, 0x00}; */ static int mceusb_cmdsize(u8 cmd, u8 subcmd) @@ -437,27 +463,33 @@ static int mceusb_cmdsize(u8 cmd, u8 subcmd) int datasize = 0; switch (cmd) { - case MCE_COMMAND_NULL: - if (subcmd == MCE_HW_CMD_HEADER) + case MCE_CMD_NULL: + if (subcmd == MCE_CMD_PORT_SYS) datasize = 1; break; - case MCE_HW_CMD_HEADER: + case MCE_CMD_PORT_SYS: switch (subcmd) { + case MCE_RSP_EQWAKEVERSION: + datasize = 4; + break; case MCE_CMD_G_REVISION: datasize = 2; break; + case MCE_RSP_EQWAKESUPPORT: + datasize = 1; + break; } - case MCE_COMMAND_HEADER: + case MCE_CMD_PORT_IR: switch (subcmd) { case MCE_CMD_UNKNOWN: - case MCE_CMD_S_CARRIER: - case MCE_CMD_S_TIMEOUT: - case MCE_RSP_PULSE_COUNT: + case MCE_RSP_EQIRCFS: + case MCE_RSP_EQIRTIMEOUT: + case MCE_RSP_EQIRRXCFCNT: datasize = 2; break; case MCE_CMD_SIG_END: - case MCE_CMD_S_TXMASK: - case MCE_CMD_S_RXSENSOR: + case MCE_RSP_EQIRTXPORTS: + case MCE_RSP_EQIRRXPORTEN: datasize = 1; break; } @@ -470,7 +502,7 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, { char codes[USB_BUFLEN * 3 + 1]; char inout[9]; - u8 cmd, subcmd, data1, data2; + u8 cmd, subcmd, data1, data2, data3, data4, data5; struct device *dev = ir->dev; int i, start, skip = 0; @@ -500,18 +532,26 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, subcmd = buf[start + 1] & 0xff; data1 = buf[start + 2] & 0xff; data2 = buf[start + 3] & 0xff; + data3 = buf[start + 4] & 0xff; + data4 = buf[start + 5] & 0xff; + data5 = buf[start + 6] & 0xff; switch (cmd) { - case MCE_COMMAND_NULL: - if ((subcmd == MCE_HW_CMD_HEADER) && - (data1 == MCE_CMD_DEVICE_RESET)) - dev_info(dev, "Device reset requested\n"); + case MCE_CMD_NULL: + if ((subcmd == MCE_CMD_PORT_SYS) && + (data1 == MCE_CMD_RESUME)) + dev_info(dev, "Device resume requested\n"); else dev_info(dev, "Unknown command 0x%02x 0x%02x\n", cmd, subcmd); break; - case MCE_HW_CMD_HEADER: + case MCE_CMD_PORT_SYS: switch (subcmd) { + case MCE_RSP_EQEMVER: + if (!out) + dev_info(dev, "Emulator interface version %x\n", + data1); + break; case MCE_CMD_G_REVISION: if (len == 2) dev_info(dev, "Get hw/sw rev?\n"); @@ -520,21 +560,32 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, "0x%02x 0x%02x\n", data1, data2, buf[start + 4], buf[start + 5]); break; - case MCE_CMD_DEVICE_RESET: - dev_info(dev, "Device reset requested\n"); + case MCE_CMD_RESUME: + dev_info(dev, "Device resume requested\n"); + break; + case MCE_RSP_CMD_ILLEGAL: + dev_info(dev, "Illegal PORT_SYS command\n"); + break; + case MCE_RSP_EQWAKEVERSION: + if (!out) + dev_info(dev, "Wake version, proto: 0x%02x, " + "payload: 0x%02x, address: 0x%02x, " + "version: 0x%02x\n", + data1, data2, data3, data4); break; - case MCE_RSP_CMD_INVALID: - dev_info(dev, "Previous command not supported\n"); + case MCE_RSP_GETPORTSTATUS: + if (!out) + /* We use data1 + 1 here, to match hw labels */ + dev_info(dev, "TX port %d: blaster is%s connected\n", + data1 + 1, data4 ? " not" : ""); break; - case MCE_CMD_UNKNOWN7: - case MCE_CMD_UNKNOWN9: default: dev_info(dev, "Unknown command 0x%02x 0x%02x\n", cmd, subcmd); break; } break; - case MCE_COMMAND_HEADER: + case MCE_CMD_PORT_IR: switch (subcmd) { case MCE_CMD_SIG_END: dev_info(dev, "End of signal\n"); @@ -546,47 +597,50 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, dev_info(dev, "Resp to 9f 05 of 0x%02x 0x%02x\n", data1, data2); break; - case MCE_CMD_S_CARRIER: + case MCE_CMD_SETIRCFS: dev_info(dev, "%s carrier mode and freq of " "0x%02x 0x%02x\n", inout, data1, data2); break; - case MCE_CMD_G_CARRIER: + case MCE_CMD_GETIRCFS: dev_info(dev, "Get carrier mode and freq\n"); break; - case MCE_CMD_S_TXMASK: + case MCE_RSP_EQIRTXPORTS: dev_info(dev, "%s transmit blaster mask of 0x%02x\n", inout, data1); break; - case MCE_CMD_S_TIMEOUT: + case MCE_RSP_EQIRTIMEOUT: /* value is in units of 50us, so x*50/1000 ms */ dev_info(dev, "%s receive timeout of %d ms\n", inout, ((data1 << 8) | data2) * MCE_TIME_UNIT / 1000); break; - case MCE_CMD_G_TIMEOUT: + case MCE_CMD_GETIRTIMEOUT: dev_info(dev, "Get receive timeout\n"); break; - case MCE_CMD_G_TXMASK: + case MCE_CMD_GETIRTXPORTS: dev_info(dev, "Get transmit blaster mask\n"); break; - case MCE_CMD_S_RXSENSOR: + case MCE_RSP_EQIRRXPORTEN: dev_info(dev, "%s %s-range receive sensor in use\n", inout, data1 == 0x02 ? "short" : "long"); break; - case MCE_CMD_G_RXSENSOR: - /* aka MCE_RSP_PULSE_COUNT */ + case MCE_CMD_GETIRRXPORTEN: + /* aka MCE_RSP_EQIRRXCFCNT */ if (out) dev_info(dev, "Get receive sensor\n"); else if (ir->learning_enabled) dev_info(dev, "RX pulse count: %d\n", ((data1 << 8) | data2)); break; - case MCE_RSP_CMD_INVALID: - dev_info(dev, "Error! Hardware is likely wedged...\n"); + case MCE_RSP_EQIRNUMPORTS: + if (out) + break; + dev_info(dev, "Num TX ports: %x, num RX ports: %x\n", + data1, data2); + break; + case MCE_RSP_CMD_ILLEGAL: + dev_info(dev, "Illegal PORT_IR command\n"); break; - case MCE_CMD_UNKNOWN2: - case MCE_CMD_UNKNOWN3: - case MCE_CMD_UNKNOWN5: default: dev_info(dev, "Unknown command 0x%02x 0x%02x\n", cmd, subcmd); @@ -599,8 +653,8 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, if (cmd == MCE_IRDATA_TRAILER) dev_info(dev, "End of raw IR data\n"); - else if ((cmd != MCE_COMMAND_HEADER) && - ((cmd & MCE_COMMAND_MASK) == MCE_COMMAND_IRDATA)) + else if ((cmd != MCE_CMD_PORT_IR) && + ((cmd & MCE_PORT_MASK) == MCE_COMMAND_IRDATA)) dev_info(dev, "Raw IR data, %d pulse/space samples\n", ir->rem); } @@ -616,9 +670,6 @@ static void mce_async_callback(struct urb *urb, struct pt_regs *regs) if (ir) { len = urb->actual_length; - mce_dbg(ir->dev, "callback called (status=%d len=%d)\n", - urb->status, len); - mceusb_dev_printdata(ir, urb->transfer_buffer, 0, len, true); } @@ -708,8 +759,8 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count) return -ENOMEM; /* MCE tx init header */ - cmdbuf[cmdcount++] = MCE_COMMAND_HEADER; - cmdbuf[cmdcount++] = MCE_CMD_S_TXMASK; + cmdbuf[cmdcount++] = MCE_CMD_PORT_IR; + cmdbuf[cmdcount++] = MCE_CMD_SETIRTXPORTS; cmdbuf[cmdcount++] = ir->tx_mask; /* Generate mce packet data */ @@ -795,8 +846,8 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier) struct mceusb_dev *ir = dev->priv; int clk = 10000000; int prescaler = 0, divisor = 0; - unsigned char cmdbuf[4] = { MCE_COMMAND_HEADER, - MCE_CMD_S_CARRIER, 0x00, 0x00 }; + unsigned char cmdbuf[4] = { MCE_CMD_PORT_IR, + MCE_CMD_SETIRCFS, 0x00, 0x00 }; /* Carrier has changed */ if (ir->carrier != carrier) { @@ -845,16 +896,16 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index) switch (ir->buf_in[index]) { /* 2-byte return value commands */ - case MCE_CMD_S_TIMEOUT: + case MCE_RSP_EQIRTIMEOUT: ir->rc->timeout = US_TO_NS((hi << 8 | lo) * MCE_TIME_UNIT); break; /* 1-byte return value commands */ - case MCE_CMD_S_TXMASK: + case MCE_RSP_EQIRTXPORTS: ir->tx_mask = hi; break; - case MCE_CMD_S_RXSENSOR: - ir->learning_enabled = (hi == 0x02); + case MCE_RSP_EQIRRXPORTEN: + ir->learning_enabled = ((hi & 0x02) == 0x02); break; default: break; @@ -903,8 +954,8 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) /* decode mce packets of the form (84),AA,BB,CC,DD */ /* IR data packets can span USB messages - rem */ ir->cmd = ir->buf_in[i]; - if ((ir->cmd == MCE_COMMAND_HEADER) || - ((ir->cmd & MCE_COMMAND_MASK) != + if ((ir->cmd == MCE_CMD_PORT_IR) || + ((ir->cmd & MCE_PORT_MASK) != MCE_COMMAND_IRDATA)) { ir->parser_state = SUBCMD; continue; @@ -1011,8 +1062,8 @@ static void mceusb_gen1_init(struct mceusb_dev *ir) 0x0000, 0x0100, NULL, 0, HZ * 3); mce_dbg(dev, "%s - retC = %d\n", __func__, ret); - /* device reset */ - mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET)); + /* device resume */ + mce_async_out(ir, DEVICE_RESUME, sizeof(DEVICE_RESUME)); /* get hw/sw revision? */ mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION)); @@ -1022,14 +1073,16 @@ static void mceusb_gen1_init(struct mceusb_dev *ir) static void mceusb_gen2_init(struct mceusb_dev *ir) { - /* device reset */ - mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET)); + /* device resume */ + mce_async_out(ir, DEVICE_RESUME, sizeof(DEVICE_RESUME)); /* get hw/sw revision? */ mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION)); - /* unknown what the next two actually return... */ - mce_async_out(ir, GET_UNKNOWN, sizeof(GET_UNKNOWN)); + /* get wake version (protocol, key, address) */ + mce_async_out(ir, GET_WAKEVERSION, sizeof(GET_WAKEVERSION)); + + /* unknown what this one actually returns... */ mce_async_out(ir, GET_UNKNOWN2, sizeof(GET_UNKNOWN2)); } -- cgit v0.10.2 From 417c0a23b7d0384682d6032fbc6a62ab25ce7c18 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 18 Jul 2011 16:54:22 -0300 Subject: [media] mceusb: give hardware time to reply to cmds Sometimes the init routine is blasting commands out to the hardware faster than it can reply. Throw a brief delay in there to give the hardware a chance to reply before we send the next command. Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index eee28a5..7af5738 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -735,6 +735,7 @@ static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data, static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size) { mce_request_packet(ir, data, size, MCEUSB_TX); + msleep(10); } static void mce_flush_rx_buffer(struct mceusb_dev *ir, int size) -- cgit v0.10.2 From fa3348980a504c01e300823ab743cb2d874327fa Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 18 Jul 2011 16:54:23 -0300 Subject: [media] mceusb: set wakeup bits for IR-based resume Its not uncommon for folks to force these bits enabled, because people do want to wake their htpc kit via their remote. Lets just set the bits for 'em. Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 7af5738..d095b4d 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #define DRIVER_VERSION "1.91" @@ -1287,6 +1288,10 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf, usb_set_intfdata(intf, ir); + /* enable wake via this device */ + device_set_wakeup_capable(ir->dev, true); + device_set_wakeup_enable(ir->dev, true); + dev_info(&intf->dev, "Registered %s on usb%d:%d\n", name, dev->bus->busnum, dev->devnum); -- cgit v0.10.2 From 4840b788ad608977d47964d39ee53a55bec41702 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 18 Jul 2011 16:54:24 -0300 Subject: [media] mceusb: issue device resume cmd when needed According to MS docs, the device firmware may halt after receiving an unknown instruction, but that it should be possible to tell the firmware to continue running by simply sending a device resume command. So lets do that. Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index d095b4d..181a9b6 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -436,6 +436,8 @@ struct mceusb_dev { char name[128]; char phys[64]; enum mceusb_model_type model; + + bool need_reset; /* flag to issue a device resume cmd */ }; /* MCE Device Command Strings, generally a port and command pair */ @@ -735,6 +737,14 @@ static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data, static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size) { + int rsize = sizeof(DEVICE_RESUME); + + if (ir->need_reset) { + ir->need_reset = false; + mce_request_packet(ir, DEVICE_RESUME, rsize, MCEUSB_TX); + msleep(10); + } + mce_request_packet(ir, data, size, MCEUSB_TX); msleep(10); } @@ -909,6 +919,9 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index) case MCE_RSP_EQIRRXPORTEN: ir->learning_enabled = ((hi & 0x02) == 0x02); break; + case MCE_RSP_CMD_ILLEGAL: + ir->need_reset = true; + break; default: break; } -- cgit v0.10.2 From ab1072eba9a635511279c72150b35c1cf95ceda1 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 18 Jul 2011 16:54:25 -0300 Subject: [media] mceusb: query device for firmware emulator version Supposedly, there are essentially three different classes of devices that are compatible with Microsoft's specs. First are the "legacy" devices, which are built using Microsoft-provided hardware specs and firmware. Second are "emulator" devices, which are built using custom hardware and firmware, written to emulate Microsoft's firmware. Third are "port" devices, which have their own device driver and firmware, which provides compatible data to higher levels of the stack. >From what I can tell, things like nuvoton-cir and fintek-cir are essentially "port" devices -- their raw IR buffer format is very similar to that of the mceusb devices. Now, within the mceusb driver, we have three different "generations", which at first, seemed like maybe they mapped to emulator versions. Unfortuantely, every single device I have responds "illegal command" to the query to get firmware emulator version from the hardware, which means they're either all emulator version 1, or they're legacy devices, and our different "generations" aren't at all related here. Though in theory, its possible the gen1 devices are "legacy" devices and the rest are emulator v1. There are some useful features of the v2 interface I was hoping to play with, but alas... Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 181a9b6..4c5909f 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -438,12 +438,14 @@ struct mceusb_dev { enum mceusb_model_type model; bool need_reset; /* flag to issue a device resume cmd */ + u8 emver; /* emulator interface version */ }; /* MCE Device Command Strings, generally a port and command pair */ static char DEVICE_RESUME[] = {MCE_CMD_NULL, MCE_CMD_PORT_SYS, MCE_CMD_RESUME}; static char GET_REVISION[] = {MCE_CMD_PORT_SYS, MCE_CMD_G_REVISION}; +static char GET_EMVER[] = {MCE_CMD_PORT_SYS, MCE_CMD_GETEMVER}; static char GET_WAKEVERSION[] = {MCE_CMD_PORT_SYS, MCE_CMD_GETWAKEVERSION}; static char GET_UNKNOWN2[] = {MCE_CMD_PORT_IR, MCE_CMD_UNKNOWN2}; static char GET_CARRIER_FREQ[] = {MCE_CMD_PORT_IR, MCE_CMD_GETIRCFS}; @@ -913,6 +915,9 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index) break; /* 1-byte return value commands */ + case MCE_RSP_EQEMVER: + ir->emver = hi; + break; case MCE_RSP_EQIRTXPORTS: ir->tx_mask = hi; break; @@ -1035,6 +1040,13 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs) usb_submit_urb(urb, GFP_ATOMIC); } +static void mceusb_get_emulator_version(struct mceusb_dev *ir) +{ + /* If we get no reply or an illegal command reply, its ver 1, says MS */ + ir->emver = 1; + mce_async_out(ir, GET_EMVER, sizeof(GET_EMVER)); +} + static void mceusb_gen1_init(struct mceusb_dev *ir) { int ret; @@ -1288,6 +1300,9 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf, mce_dbg(&intf->dev, "Flushing receive buffers\n"); mce_flush_rx_buffer(ir, maxp); + /* figure out which firmware/emulator version this hardware has */ + mceusb_get_emulator_version(ir); + /* initialize device */ if (ir->flags.microsoft_gen1) mceusb_gen1_init(ir); @@ -1305,8 +1320,8 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf, device_set_wakeup_capable(ir->dev, true); device_set_wakeup_enable(ir->dev, true); - dev_info(&intf->dev, "Registered %s on usb%d:%d\n", name, - dev->bus->busnum, dev->devnum); + dev_info(&intf->dev, "Registered %s with mce emulator interface " + "version %x\n", name, ir->emver); return 0; -- cgit v0.10.2 From a411e83944bc48ce274b1bafdb6929846815856c Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 18 Jul 2011 16:54:26 -0300 Subject: [media] mceusb: get misc port data from hardware According to the specs, you can read the number of tx ports, number of rx sensors, which tx ports have cables plugged into them, and which rx sensors are active. In practice, most of my devices do seem to report sane values for tx ports and rx sensors (but not all -- one without any tx ports reports having them), and most report the active sensor correctly, but only one of eight reports cabled tx ports correctly. So for the most part, this is just for informational purposes. Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 4c5909f..c4f3bc0 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -439,6 +439,10 @@ struct mceusb_dev { bool need_reset; /* flag to issue a device resume cmd */ u8 emver; /* emulator interface version */ + u8 num_txports; /* number of transmit ports */ + u8 num_rxports; /* number of receive sensors */ + u8 txports_cabled; /* bitmask of transmitters with cable */ + u8 rxports_active; /* bitmask of active receive sensors */ }; /* MCE Device Command Strings, generally a port and command pair */ @@ -450,6 +454,7 @@ static char GET_WAKEVERSION[] = {MCE_CMD_PORT_SYS, MCE_CMD_GETWAKEVERSION}; static char GET_UNKNOWN2[] = {MCE_CMD_PORT_IR, MCE_CMD_UNKNOWN2}; static char GET_CARRIER_FREQ[] = {MCE_CMD_PORT_IR, MCE_CMD_GETIRCFS}; static char GET_RX_TIMEOUT[] = {MCE_CMD_PORT_IR, MCE_CMD_GETIRTIMEOUT}; +static char GET_NUM_PORTS[] = {MCE_CMD_PORT_IR, MCE_CMD_GETIRNUMPORTS}; static char GET_TX_BITMASK[] = {MCE_CMD_PORT_IR, MCE_CMD_GETIRTXPORTS}; static char GET_RX_SENSOR[] = {MCE_CMD_PORT_IR, MCE_CMD_GETIRRXPORTEN}; /* sub in desired values in lower byte or bytes for full command */ @@ -543,6 +548,8 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, switch (cmd) { case MCE_CMD_NULL: + if (subcmd == MCE_CMD_NULL) + break; if ((subcmd == MCE_CMD_PORT_SYS) && (data1 == MCE_CMD_RESUME)) dev_info(dev, "Device resume requested\n"); @@ -909,10 +916,20 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index) u8 lo = ir->buf_in[index + 2] & 0xff; switch (ir->buf_in[index]) { + /* the one and only 5-byte return value command */ + case MCE_RSP_GETPORTSTATUS: + if ((ir->buf_in[index + 4] & 0xff) == 0x00) + ir->txports_cabled |= 1 << hi; + break; + /* 2-byte return value commands */ case MCE_RSP_EQIRTIMEOUT: ir->rc->timeout = US_TO_NS((hi << 8 | lo) * MCE_TIME_UNIT); break; + case MCE_RSP_EQIRNUMPORTS: + ir->num_txports = hi; + ir->num_rxports = lo; + break; /* 1-byte return value commands */ case MCE_RSP_EQEMVER: @@ -923,6 +940,7 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index) break; case MCE_RSP_EQIRRXPORTEN: ir->learning_enabled = ((hi & 0x02) == 0x02); + ir->rxports_active = hi; break; case MCE_RSP_CMD_ILLEGAL: ir->need_reset = true; @@ -1115,10 +1133,21 @@ static void mceusb_gen2_init(struct mceusb_dev *ir) static void mceusb_get_parameters(struct mceusb_dev *ir) { + int i; + unsigned char cmdbuf[3] = { MCE_CMD_PORT_SYS, + MCE_CMD_GETPORTSTATUS, 0x00 }; + + /* defaults, if the hardware doesn't support querying */ + ir->num_txports = 2; + ir->num_rxports = 2; + + /* get number of tx and rx ports */ + mce_async_out(ir, GET_NUM_PORTS, sizeof(GET_NUM_PORTS)); + /* get the carrier and frequency */ mce_async_out(ir, GET_CARRIER_FREQ, sizeof(GET_CARRIER_FREQ)); - if (!ir->flags.no_tx) + if (ir->num_txports && !ir->flags.no_tx) /* get the transmitter bitmask */ mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK)); @@ -1127,6 +1156,11 @@ static void mceusb_get_parameters(struct mceusb_dev *ir) /* get receiver sensor setting */ mce_async_out(ir, GET_RX_SENSOR, sizeof(GET_RX_SENSOR)); + + for (i = 0; i < ir->num_txports; i++) { + cmdbuf[2] = i; + mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); + } } static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) @@ -1322,6 +1356,10 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf, dev_info(&intf->dev, "Registered %s with mce emulator interface " "version %x\n", name, ir->emver); + dev_info(&intf->dev, "%x tx ports (0x%x cabled) and " + "%x rx sensors (0x%x active)\n", + ir->num_txports, ir->txports_cabled, + ir->num_rxports, ir->rxports_active); return 0; -- cgit v0.10.2 From b71969bee23ea0c44c594e5027ba26029d27afea Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 18 Jul 2011 16:54:27 -0300 Subject: [media] mceusb: flash LED (emu v2+ only) to signal end of init Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index c4f3bc0..8fa5a72 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -451,6 +451,7 @@ static char DEVICE_RESUME[] = {MCE_CMD_NULL, MCE_CMD_PORT_SYS, static char GET_REVISION[] = {MCE_CMD_PORT_SYS, MCE_CMD_G_REVISION}; static char GET_EMVER[] = {MCE_CMD_PORT_SYS, MCE_CMD_GETEMVER}; static char GET_WAKEVERSION[] = {MCE_CMD_PORT_SYS, MCE_CMD_GETWAKEVERSION}; +static char FLASH_LED[] = {MCE_CMD_PORT_SYS, MCE_CMD_FLASHLED}; static char GET_UNKNOWN2[] = {MCE_CMD_PORT_IR, MCE_CMD_UNKNOWN2}; static char GET_CARRIER_FREQ[] = {MCE_CMD_PORT_IR, MCE_CMD_GETIRCFS}; static char GET_RX_TIMEOUT[] = {MCE_CMD_PORT_IR, MCE_CMD_GETIRTIMEOUT}; @@ -591,6 +592,9 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, dev_info(dev, "TX port %d: blaster is%s connected\n", data1 + 1, data4 ? " not" : ""); break; + case MCE_CMD_FLASHLED: + dev_info(dev, "Attempting to flash LED\n"); + break; default: dev_info(dev, "Unknown command 0x%02x 0x%02x\n", cmd, subcmd); @@ -1163,6 +1167,14 @@ static void mceusb_get_parameters(struct mceusb_dev *ir) } } +static void mceusb_flash_led(struct mceusb_dev *ir) +{ + if (ir->emver < 2) + return; + + mce_async_out(ir, FLASH_LED, sizeof(FLASH_LED)); +} + static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) { struct device *dev = ir->dev; @@ -1345,6 +1357,8 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf, mceusb_get_parameters(ir); + mceusb_flash_led(ir); + if (!ir->flags.no_tx) mceusb_set_tx_mask(ir->rc, MCE_DEFAULT_TX_MASK); -- cgit v0.10.2 From e217fb43c47830857a685673ae0dc3e28493bb88 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 18 Jul 2011 16:54:28 -0300 Subject: [media] mceusb: report actual tx frequencies Rather than dumping out hex values, lets print the actual calculated frequency and period the hardware has been configured for. After this [ 2643.276215] mceusb 3-1:1.0: tx data: 9f 07 (length=2) [ 2643.276218] mceusb 3-1:1.0: Get carrier mode and freq [ 2643.277206] mceusb 3-1:1.0: rx data: 9f 06 01 42 (length=4) [ 2643.277209] mceusb 3-1:1.0: Got carrier of 37037 Hz (period 27us) Matches up perfectly with the table in Microsoft's docs. Of course, I've noticed on one of my devices that the MS-recommended default value of 1 for carrier pre-scaler and 66 for carrier period was butchered, and instead of converting 66 to hex (0x42 like above), they put in 0x66, so the hardware reports a default carrier of 24390Hz. Fortunately, I guess, this particular device is rx-only, but I wouldn't put it past other hw to screw up here too. Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 8fa5a72..e51637f 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -516,6 +516,7 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, u8 cmd, subcmd, data1, data2, data3, data4, data5; struct device *dev = ir->dev; int i, start, skip = 0; + u32 carrier, period; if (!debug) return; @@ -613,9 +614,14 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, dev_info(dev, "Resp to 9f 05 of 0x%02x 0x%02x\n", data1, data2); break; - case MCE_CMD_SETIRCFS: - dev_info(dev, "%s carrier mode and freq of " - "0x%02x 0x%02x\n", inout, data1, data2); + case MCE_RSP_EQIRCFS: + period = DIV_ROUND_CLOSEST( + (1 << data1 * 2) * (data2 + 1), 10); + if (!period) + break; + carrier = (1000 * 1000) / period; + dev_info(dev, "%s carrier of %u Hz (period %uus)\n", + inout, carrier, period); break; case MCE_CMD_GETIRCFS: dev_info(dev, "Get carrier mode and freq\n"); @@ -626,9 +632,9 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, break; case MCE_RSP_EQIRTIMEOUT: /* value is in units of 50us, so x*50/1000 ms */ + period = ((data1 << 8) | data2) * MCE_TIME_UNIT / 1000; dev_info(dev, "%s receive timeout of %d ms\n", - inout, - ((data1 << 8) | data2) * MCE_TIME_UNIT / 1000); + inout, period); break; case MCE_CMD_GETIRTIMEOUT: dev_info(dev, "Get receive timeout\n"); -- cgit v0.10.2 From fda516b72afcddbb617c75c93fe6316e4356a14b Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 18 Jul 2011 16:54:29 -0300 Subject: [media] mceusb: update version, copyright, author Add note about recent updates coming from Microsoft's publicly available specs on Windows Media Center remotes and receivers/transmitters. Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index e51637f..60d3c1e 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -1,7 +1,7 @@ /* * Driver for USB Windows Media Center Ed. eHome Infrared Transceivers * - * Copyright (c) 2010 by Jarod Wilson + * Copyright (c) 2010-2011, Jarod Wilson * * Based on the original lirc_mceusb and lirc_mceusb2 drivers, by Dan * Conti, Martin Blatter and Daniel Melander, the latter of which was @@ -15,6 +15,11 @@ * Jon Smirl, which included enhancements and simplifications to the * incoming IR buffer parsing routines. * + * Updated in July of 2011 with the aid of Microsoft's official + * remote/transceiver requirements and specification document, found at + * download.microsoft.com, title + * Windows-Media-Center-RC-IR-Collection-Green-Button-Specification-03-08-2011-V2.pdf + * * * 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 @@ -40,8 +45,8 @@ #include #include -#define DRIVER_VERSION "1.91" -#define DRIVER_AUTHOR "Jarod Wilson " +#define DRIVER_VERSION "1.92" +#define DRIVER_AUTHOR "Jarod Wilson " #define DRIVER_DESC "Windows Media Center Ed. eHome Infrared Transceiver " \ "device driver" #define DRIVER_NAME "mceusb" -- cgit v0.10.2 From ea3709435c7f2da8852c3d676874cd727253fc60 Mon Sep 17 00:00:00 2001 From: Doron Cohen Date: Wed, 20 Jul 2011 09:07:36 -0300 Subject: [media] siano: apply debug flag to module level Siano modules already had sms_dbg flag which is a module parameter which sets the debug mode so module prints messages to dmesg for debugging. The variable was static therefore apply only to the file which defines the module. In modules as smsmdtv.ko that contain a few files, the debug flag applied only for functions in that main file. flag was changed to be non-static and therefore can be accessed by all module files (although it is still not exported out of the module). Signed-off-by: Doron Cohen Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c index af121db..cf442dc 100644 --- a/drivers/media/dvb/siano/sms-cards.c +++ b/drivers/media/dvb/siano/sms-cards.c @@ -20,10 +20,6 @@ #include "sms-cards.h" #include "smsir.h" -static int sms_dbg; -module_param_named(cards_dbg, sms_dbg, int, 0644); -MODULE_PARM_DESC(cards_dbg, "set debug level (info=1, adv=2 (or-able))"); - static struct sms_board sms_boards[] = { [SMS_BOARD_UNKNOWN] = { .name = "Unknown board", diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c index 7331e84..c0acacc 100644 --- a/drivers/media/dvb/siano/smscoreapi.c +++ b/drivers/media/dvb/siano/smscoreapi.c @@ -39,7 +39,7 @@ #include "smsir.h" #include "smsendian.h" -static int sms_dbg; +int sms_dbg; module_param_named(debug, sms_dbg, int, 0644); MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); diff --git a/drivers/media/dvb/siano/smscoreapi.h b/drivers/media/dvb/siano/smscoreapi.h index c592ae0..bd1cafc 100644 --- a/drivers/media/dvb/siano/smscoreapi.h +++ b/drivers/media/dvb/siano/smscoreapi.h @@ -751,6 +751,7 @@ int smscore_led_state(struct smscore_device_t *core, int led); /* ------------------------------------------------------------------------ */ +extern int sms_dbg; #define DBG_INFO 1 #define DBG_ADV 2 diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c index 37c594f..b1f4911 100644 --- a/drivers/media/dvb/siano/smsdvb.c +++ b/drivers/media/dvb/siano/smsdvb.c @@ -60,10 +60,6 @@ struct smsdvb_client_t { static struct list_head g_smsdvb_clients; static struct mutex g_smsdvb_clientslock; -static int sms_dbg; -module_param_named(debug, sms_dbg, int, 0644); -MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); - /* Events that may come from DVB v3 adapter */ static void sms_board_dvb3_event(struct smsdvb_client_t *client, enum SMS_DVB3_EVENTS event) { diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c index 0c8164a..f8dca55 100644 --- a/drivers/media/dvb/siano/smsusb.c +++ b/drivers/media/dvb/siano/smsusb.c @@ -29,10 +29,6 @@ along with this program. If not, see . #include "sms-cards.h" #include "smsendian.h" -static int sms_dbg; -module_param_named(debug, sms_dbg, int, 0644); -MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); - #define USB1_BUFFER_SIZE 0x1000 #define USB2_BUFFER_SIZE 0x4000 -- cgit v0.10.2 From 3dbbf82f49865c84d472a89ada225039e5c825a0 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Mon, 25 Jul 2011 15:35:12 -0300 Subject: [media] it913x_fe: frontend and tuner driver v1.05 Fronted and Tuner Driver for ITE IT913x Series with inital support for IT9137 integrated demodulator and tuner device. The driver is loosely based on AF9035 series. However, support is not intended for this device specificity. The IT9137 tuner has been tested on UHF bands, but VHF has only been simulated. Possible TODO the tuner sections may be separated from the main driver. All future devices should use the it913x_fe_script_loader for other tuner devices. Signed-off-by: Malcolm Priestley [mchehab@redhat.com: Fix an issue at the Kconfig help] Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 32e08e3..17082df 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -661,6 +661,14 @@ config DVB_IX2505V help A DVB-S tuner module. Say Y when you want to support this frontend. +config DVB_IT913X_FE + tristate "it913x frontend and it9137 tuner" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-T tuner module. + Say Y when you want to support this frontend. + comment "Tools to develop new frontends" config DVB_DUMMY_FE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 6a6ba05..3da75ea 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -91,4 +91,5 @@ obj-$(CONFIG_DVB_STV0367) += stv0367.o obj-$(CONFIG_DVB_CXD2820R) += cxd2820r.o obj-$(CONFIG_DVB_DRXK) += drxk.o obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o +obj-$(CONFIG_DVB_IT913X_FE) += it913x-fe.o diff --git a/drivers/media/dvb/frontends/it913x-fe-priv.h b/drivers/media/dvb/frontends/it913x-fe-priv.h new file mode 100644 index 0000000..b80634ab --- /dev/null +++ b/drivers/media/dvb/frontends/it913x-fe-priv.h @@ -0,0 +1,342 @@ + +struct it913xset { u32 pro; + u32 address; + u8 reg[15]; + u8 count; +}; + +struct adctable { u32 adcFrequency; + u32 bandwidth; + u32 coeff_1_2048; + u32 coeff_1_4096; + u32 coeff_1_8191; + u32 coeff_1_8192; + u32 coeff_1_8193; + u32 coeff_2_2k; + u32 coeff_2_4k; + u32 coeff_2_8k; + u16 bfsfcw_fftinx_ratio; + u16 fftinx_bfsfcw_ratio; +}; + +/* clock and coeff tables only table 3 is used with IT9137*/ +/* TODO other tables relate AF9035 may be removed */ +static struct adctable tab1[] = { + { 20156250, BANDWIDTH_6_MHZ, + 0x02b8ba6e, 0x015c5d37, 0x00ae340d, 0x00ae2e9b, 0x00ae292a, + 0x015c5d37, 0x00ae2e9b, 0x0057174e, 0x02f1, 0x015c }, + { 20156250, BANDWIDTH_7_MHZ, + 0x032cd980, 0x01966cc0, 0x00cb3cba, 0x00cb3660, 0x00cb3007, + 0x01966cc0, 0x00cb3660, 0x00659b30, 0x0285, 0x0196 }, + { 20156250, BANDWIDTH_8_MHZ, + 0x03a0f893, 0x01d07c49, 0x00e84567, 0x00e83e25, 0x00e836e3, + 0x01d07c49, 0x00e83e25, 0x00741f12, 0x0234, 0x01d0 }, + { 20156250, BANDWIDTH_5_MHZ, + 0x02449b5c, 0x01224dae, 0x00912b60, 0x009126d7, 0x0091224e, + 0x01224dae, 0x009126d7, 0x0048936b, 0x0387, 0x0122 } +}; + +static struct adctable tab2[] = { + { 20187500, BANDWIDTH_6_MHZ, + 0x02b7a654, 0x015bd32a, 0x00adef04, 0x00ade995, 0x00ade426, + 0x015bd32a, 0x00ade995, 0x0056f4ca, 0x02f2, 0x015c }, + { 20187500, BANDWIDTH_7_MHZ, + 0x032b9761, 0x0195cbb1, 0x00caec30, 0x00cae5d8, 0x00cadf81, + 0x0195cbb1, 0x00cae5d8, 0x006572ec, 0x0286, 0x0196 }, + { 20187500, BANDWIDTH_8_MHZ, + 0x039f886f, 0x01cfc438, 0x00e7e95b, 0x00e7e21c, 0x00e7dadd, + 0x01cfc438, 0x00e7e21c, 0x0073f10e, 0x0235, 0x01d0 }, + { 20187500, BANDWIDTH_5_MHZ, + 0x0243b546, 0x0121daa3, 0x0090f1d9, 0x0090ed51, 0x0090e8ca, + 0x0121daa3, 0x0090ed51, 0x004876a9, 0x0388, 0x0122 } + +}; + +static struct adctable tab3[] = { + { 20250000, BANDWIDTH_6_MHZ, + 0x02b580ad, 0x015ac057, 0x00ad6597, 0x00ad602b, 0x00ad5ac1, + 0x015ac057, 0x00ad602b, 0x0056b016, 0x02f4, 0x015b }, + { 20250000, BANDWIDTH_7_MHZ, + 0x03291620, 0x01948b10, 0x00ca4bda, 0x00ca4588, 0x00ca3f36, + 0x01948b10, 0x00ca4588, 0x006522c4, 0x0288, 0x0195 }, + { 20250000, BANDWIDTH_8_MHZ, + 0x039cab92, 0x01ce55c9, 0x00e7321e, 0x00e72ae4, 0x00e723ab, + 0x01ce55c9, 0x00e72ae4, 0x00739572, 0x0237, 0x01ce }, + { 20250000, BANDWIDTH_5_MHZ, + 0x0241eb3b, 0x0120f59e, 0x00907f53, 0x00907acf, 0x0090764b, + 0x0120f59e, 0x00907acf, 0x00483d67, 0x038b, 0x0121 } + +}; + +static struct adctable tab4[] = { + { 20583333, BANDWIDTH_6_MHZ, + 0x02aa4598, 0x015522cc, 0x00aa96bb, 0x00aa9166, 0x00aa8c12, + 0x015522cc, 0x00aa9166, 0x005548b3, 0x0300, 0x0155 }, + { 20583333, BANDWIDTH_7_MHZ, + 0x031bfbdc, 0x018dfdee, 0x00c7052f, 0x00c6fef7, 0x00c6f8bf, + 0x018dfdee, 0x00c6fef7, 0x00637f7b, 0x0293, 0x018e }, + { 20583333, BANDWIDTH_8_MHZ, + 0x038db21f, 0x01c6d910, 0x00e373a3, 0x00e36c88, 0x00e3656d, + 0x01c6d910, 0x00e36c88, 0x0071b644, 0x0240, 0x01c7 }, + { 20583333, BANDWIDTH_5_MHZ, + 0x02388f54, 0x011c47aa, 0x008e2846, 0x008e23d5, 0x008e1f64, + 0x011c47aa, 0x008e23d5, 0x004711ea, 0x039a, 0x011c } + +}; + +static struct adctable tab5[] = { + { 20416667, BANDWIDTH_6_MHZ, + 0x02afd765, 0x0157ebb3, 0x00abfb39, 0x00abf5d9, 0x00abf07a, + 0x0157ebb3, 0x00abf5d9, 0x0055faed, 0x02fa, 0x0158 }, + { 20416667, BANDWIDTH_7_MHZ, + 0x03227b4b, 0x01913da6, 0x00c8a518, 0x00c89ed3, 0x00c8988e, + 0x01913da6, 0x00c89ed3, 0x00644f69, 0x028d, 0x0191 }, + { 20416667, BANDWIDTH_8_MHZ, + 0x03951f32, 0x01ca8f99, 0x00e54ef7, 0x00e547cc, 0x00e540a2, + 0x01ca8f99, 0x00e547cc, 0x0072a3e6, 0x023c, 0x01cb }, + { 20416667, BANDWIDTH_5_MHZ, + 0x023d337f, 0x011e99c0, 0x008f515a, 0x008f4ce0, 0x008f4865, + 0x011e99c0, 0x008f4ce0, 0x0047a670, 0x0393, 0x011f } + +}; + +static struct adctable tab6[] = { + { 20480000, BANDWIDTH_6_MHZ, + 0x02adb6db, 0x0156db6e, 0x00ab7312, 0x00ab6db7, 0x00ab685c, + 0x0156db6e, 0x00ab6db7, 0x0055b6db, 0x02fd, 0x0157 }, + { 20480000, BANDWIDTH_7_MHZ, + 0x03200000, 0x01900000, 0x00c80640, 0x00c80000, 0x00c7f9c0, + 0x01900000, 0x00c80000, 0x00640000, 0x028f, 0x0190 }, + { 20480000, BANDWIDTH_8_MHZ, + 0x03924925, 0x01c92492, 0x00e4996e, 0x00e49249, 0x00e48b25, + 0x01c92492, 0x00e49249, 0x00724925, 0x023d, 0x01c9 }, + { 20480000, BANDWIDTH_5_MHZ, + 0x023b6db7, 0x011db6db, 0x008edfe5, 0x008edb6e, 0x008ed6f7, + 0x011db6db, 0x008edb6e, 0x00476db7, 0x0396, 0x011e } +}; + +static struct adctable tab7[] = { + { 20500000, BANDWIDTH_6_MHZ, + 0x02ad0b99, 0x015685cc, 0x00ab4840, 0x00ab42e6, 0x00ab3d8c, + 0x015685cc, 0x00ab42e6, 0x0055a173, 0x02fd, 0x0157 }, + { 20500000, BANDWIDTH_7_MHZ, + 0x031f3832, 0x018f9c19, 0x00c7d44b, 0x00c7ce0c, 0x00c7c7ce, + 0x018f9c19, 0x00c7ce0c, 0x0063e706, 0x0290, 0x0190 }, + { 20500000, BANDWIDTH_8_MHZ, + 0x039164cb, 0x01c8b266, 0x00e46056, 0x00e45933, 0x00e45210, + 0x01c8b266, 0x00e45933, 0x00722c99, 0x023e, 0x01c9 }, + { 20500000, BANDWIDTH_5_MHZ, + 0x023adeff, 0x011d6f80, 0x008ebc36, 0x008eb7c0, 0x008eb34a, + 0x011d6f80, 0x008eb7c0, 0x00475be0, 0x0396, 0x011d } + +}; + +static struct adctable tab8[] = { + { 20625000, BANDWIDTH_6_MHZ, + 0x02a8e4bd, 0x0154725e, 0x00aa3e81, 0x00aa392f, 0x00aa33de, + 0x0154725e, 0x00aa392f, 0x00551c98, 0x0302, 0x0154 }, + { 20625000, BANDWIDTH_7_MHZ, + 0x031a6032, 0x018d3019, 0x00c69e41, 0x00c6980c, 0x00c691d8, + 0x018d3019, 0x00c6980c, 0x00634c06, 0x0294, 0x018d }, + { 20625000, BANDWIDTH_8_MHZ, + 0x038bdba6, 0x01c5edd3, 0x00e2fe02, 0x00e2f6ea, 0x00e2efd2, + 0x01c5edd3, 0x00e2f6ea, 0x00717b75, 0x0242, 0x01c6 }, + { 20625000, BANDWIDTH_5_MHZ, + 0x02376948, 0x011bb4a4, 0x008ddec1, 0x008dda52, 0x008dd5e3, + 0x011bb4a4, 0x008dda52, 0x0046ed29, 0x039c, 0x011c } + +}; + +struct table { + u32 xtal; + struct adctable *table; +}; + +static struct table fe_clockTable[] = { + {12000000, tab3}, /* FPGA */ + {16384000, tab6}, /* 16.38MHz */ + {20480000, tab6}, /* 20.48MHz */ + {36000000, tab3}, /* 36.00MHz */ + {30000000, tab1}, /* 30.00MHz */ + {26000000, tab4}, /* 26.00MHz */ + {28000000, tab5}, /* 28.00MHz */ + {32000000, tab7}, /* 32.00MHz */ + {34000000, tab2}, /* 34.00MHz */ + {24000000, tab1}, /* 24.00MHz */ + {22000000, tab8}, /* 22.00MHz */ + {12000000, tab3} /* 12.00MHz */ +}; + +/* fe get */ +fe_code_rate_t fe_code[] = { + FEC_1_2, + FEC_2_3, + FEC_3_4, + FEC_5_6, + FEC_7_8, + FEC_NONE, +}; + +fe_guard_interval_t fe_gi[] = { + GUARD_INTERVAL_1_32, + GUARD_INTERVAL_1_16, + GUARD_INTERVAL_1_8, + GUARD_INTERVAL_1_4, +}; + +fe_hierarchy_t fe_hi[] = { + HIERARCHY_NONE, + HIERARCHY_1, + HIERARCHY_2, + HIERARCHY_4, +}; + +fe_transmit_mode_t fe_mode[] = { + TRANSMISSION_MODE_2K, + TRANSMISSION_MODE_8K, + TRANSMISSION_MODE_4K, +}; + +fe_modulation_t fe_con[] = { + QPSK, + QAM_16, + QAM_64, +}; + +/* Standard demodulator functions */ +static struct it913xset set_solo_fe[] = { + {PRO_LINK, DVBT_INTEN, {0x04}, 0x01}, + {PRO_LINK, DVBT_ENABLE, {0x05}, 0x01}, + {PRO_DMOD, MP2IF_MPEG_PAR_MODE, {0x00}, 0x01}, + {PRO_LINK, HOSTB_MPEG_SER_MODE, {0x00}, 0x01}, + {PRO_LINK, HOSTB_MPEG_PAR_MODE, {0x00}, 0x01}, + {PRO_DMOD, DCA_UPPER_CHIP, {0x00}, 0x01}, + {PRO_LINK, HOSTB_DCA_UPPER, {0x00}, 0x01}, + {PRO_DMOD, DCA_LOWER_CHIP, {0x00}, 0x01}, + {PRO_LINK, HOSTB_DCA_LOWER, {0x00}, 0x01}, + {PRO_DMOD, DCA_PLATCH, {0x00}, 0x01}, + {PRO_DMOD, DCA_FPGA_LATCH, {0x00}, 0x01}, + {PRO_DMOD, DCA_STAND_ALONE, {0x01}, 0x01}, + {PRO_DMOD, DCA_ENABLE, {0x00}, 0x01}, + {PRO_DMOD, MP2IF_MPEG_PAR_MODE, {0x00}, 0x01}, + {PRO_DMOD, BFS_FCW, {0x00, 0x00, 0x00}, 0x03}, + {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ +}; + + +static struct it913xset init_1[] = { + {PRO_LINK, LOCK3_OUT, {0x01}, 0x01}, + {PRO_LINK, PADMISCDRSR, {0x01}, 0x01}, + {PRO_LINK, PADMISCDR2, {0x00}, 0x01}, + {PRO_LINK, PADMISCDR4, {0x00}, 0x01}, /* Power up */ + {PRO_LINK, PADMISCDR8, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ +}; + +/* ---------IT9137 0x38 tuner init---------- */ +static struct it913xset it9137_set[] = { + {PRO_DMOD, 0x0043, {0x00}, 0x01}, + {PRO_DMOD, 0x0046, {0x38}, 0x01}, + {PRO_DMOD, 0x0051, {0x01}, 0x01}, + {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0x0068, {0x0a}, 0x01}, + {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03}, + {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xc8, 0x01}, 0x05}, + {PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02}, + {PRO_DMOD, 0x0081, { 0x0a, 0x12, 0x02, 0x0a, 0x03, 0xc8, 0xb8, + 0xd0, 0xc3, 0x01 }, 0x0a}, + {PRO_DMOD, 0x008e, {0x01}, 0x01}, + {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05}, + {PRO_DMOD, 0x0099, {0x01}, 0x01}, + {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02}, + {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02}, + {PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04}, + {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02}, + {PRO_DMOD, 0x00b0, {0x01}, 0x01}, + {PRO_DMOD, 0x00b3, {0x02, 0x32}, 0x02}, + {PRO_DMOD, 0x00b6, {0x14}, 0x01}, + {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05}, 0x03}, + {PRO_DMOD, 0x00c4, {0x00}, 0x01}, + {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02}, + {PRO_DMOD, 0x00cc, {0x2e, 0x51, 0x33}, 0x03}, + {PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03}, + {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03}, + {PRO_DMOD, 0x00fc, { 0x02, 0x02, 0x02, 0x09, 0x50, 0x7b, 0x77, + 0x00, 0x02, 0xc8, 0x05, 0x7b }, 0x0c}, + {PRO_DMOD, 0x0109, {0x02}, 0x01}, + {PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02}, + {PRO_DMOD, 0x011a, {0xc8, 0x7b, 0xbc, 0xa0}, 0x04}, + {PRO_DMOD, 0x0122, {0x02, 0x18, 0xc3}, 0x03}, + {PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02}, + {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04}, + {PRO_DMOD, 0x0137, {0x01, 0x00, 0x07, 0x00, 0x06}, 0x05}, + {PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xc8}, 0x04}, + {PRO_DMOD, 0xf130, {0x04}, 0x01}, + {PRO_DMOD, 0xf132, {0x04}, 0x01}, + {PRO_DMOD, 0xf144, {0x1a}, 0x01}, + {PRO_DMOD, 0xf146, {0x00}, 0x01}, + {PRO_DMOD, 0xf14a, {0x01}, 0x01}, + {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf14f, {0x04}, 0x01}, + {PRO_DMOD, 0xf158, {0x7f}, 0x01}, + {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02}, + {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02}, + {PRO_DMOD, 0xf163, {0x05}, 0x01}, + {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03}, + {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf183, {0x01}, 0x01}, + {PRO_DMOD, 0xf19d, {0x40}, 0x01}, + {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02}, + {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02}, + {PRO_DMOD, 0xf204, {0x10}, 0x01}, + {PRO_DMOD, 0xf214, {0x00}, 0x01}, + {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04}, + {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05}, + {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04}, + {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03}, + {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, + {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02}, + {PRO_DMOD, 0xf5df, {0xfb, 0x00}, 0x02}, + {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03}, + {PRO_DMOD, 0xf5f8, {0x01}, 0x01}, + {PRO_DMOD, 0xf5fd, {0x01}, 0x01}, + {PRO_DMOD, 0xf600, { 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17, + 0x1f }, 0x08}, + {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04}, + {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04}, + {PRO_DMOD, 0xf78b, {0x01}, 0x01}, + {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03}, + {PRO_DMOD, 0xf905, {0x01}, 0x01}, + {PRO_DMOD, 0xfb06, {0x03}, 0x01}, + {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, + {PRO_LINK, GPIOH5_EN, {0x01}, 0x01}, + {PRO_LINK, GPIOH5_ON, {0x01}, 0x01}, + {PRO_LINK, GPIOH5_O, {0x00}, 0x01}, + {PRO_LINK, GPIOH5_O, {0x01}, 0x01},/* ?, but enable */ + {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ +}; + +static struct it913xset it9137_tuner[] = { + {PRO_DMOD, 0xec57, {0x00}, 0x01}, + {PRO_DMOD, 0xec58, {0x00}, 0x01}, + {PRO_DMOD, 0xec40, {0x00}, 0x01}, + {PRO_DMOD, 0xec02, { 0x00, 0x0c, 0x00, 0x40, 0x00, 0x80, 0x80, + 0x00, 0x00, 0x00, 0x00 }, 0x0b}, + {PRO_DMOD, 0xec0d, { 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }, 0x0b}, + {PRO_DMOD, 0xec19, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00}, 0x08}, + {PRO_DMOD, 0xec22, { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 }, 0x0a}, + {PRO_DMOD, 0xec3f, {0x01}, 0x01}, + /* Clear any existing tune */ + {PRO_DMOD, 0xec4c, {0xa8, 0x00, 0x00, 0x00, 0x00}, 0x05}, + {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ +}; + +static struct it913xset set_it9137_template[] = { + {PRO_DMOD, 0xee06, {0x00}, 0x01}, + {PRO_DMOD, 0xec56, {0x00}, 0x01}, + {PRO_DMOD, 0xec4c, {0x00, 0x00, 0x00, 0x00, 0x00}, 0x05}, + {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ +}; diff --git a/drivers/media/dvb/frontends/it913x-fe.c b/drivers/media/dvb/frontends/it913x-fe.c new file mode 100644 index 0000000..c92b3ec --- /dev/null +++ b/drivers/media/dvb/frontends/it913x-fe.c @@ -0,0 +1,747 @@ +/* + * Driver for it913x-fe Frontend + * + * with support for on chip it9137 integral tuner + * + * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com) + * IT9137 Copyright (C) ITE Tech Inc. + * + * 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 of the License, 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 +#include +#include +#include + +#include "dvb_frontend.h" +#include "it913x-fe.h" +#include "it913x-fe-priv.h" + +static int it913x_debug; + +module_param_named(debug, it913x_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); + +#define dprintk(level, args...) do { \ + if (level & it913x_debug) \ + printk(KERN_DEBUG "it913x-fe: " args); \ +} while (0) + +#define deb_info(args...) dprintk(0x01, args) +#define debug_data_snipet(level, name, p) \ + dprintk(level, name" (%02x%02x%02x%02x%02x%02x%02x%02x)", \ + *p, *(p+1), *(p+2), *(p+3), *(p+4), \ + *(p+5), *(p+6), *(p+7)); + +struct it913x_fe_state { + struct dvb_frontend frontend; + struct i2c_adapter *i2c_adap; + u8 i2c_addr; + u32 frequency; + u8 adf; + u32 crystalFrequency; + u32 adcFrequency; + u8 tuner_type; + struct adctable *table; + fe_status_t it913x_status; +}; + +static int it913x_read_reg(struct it913x_fe_state *state, + u32 reg, u8 *data, u8 count) +{ + int ret; + u8 pro = PRO_DMOD; /* All reads from demodulator */ + u8 b[4]; + struct i2c_msg msg[2] = { + { .addr = state->i2c_addr + (pro << 1), .flags = 0, + .buf = b, .len = sizeof(b) }, + { .addr = state->i2c_addr + (pro << 1), .flags = I2C_M_RD, + .buf = data, .len = count } + }; + b[0] = (u8) reg >> 24; + b[1] = (u8)(reg >> 16) & 0xff; + b[2] = (u8)(reg >> 8) & 0xff; + b[3] = (u8) reg & 0xff; + + ret = i2c_transfer(state->i2c_adap, msg, 2); + + return ret; +} + +static int it913x_read_reg_u8(struct it913x_fe_state *state, u32 reg) +{ + int ret; + u8 b[1]; + ret = it913x_read_reg(state, reg, &b[0], sizeof(b)); + return (ret < 0) ? -ENODEV : b[0]; +} + +static int it913x_write(struct it913x_fe_state *state, + u8 pro, u32 reg, u8 buf[], u8 count) +{ + u8 b[256]; + struct i2c_msg msg[1] = { + { .addr = state->i2c_addr + (pro << 1), .flags = 0, + .buf = b, .len = count + 4 } + }; + int ret; + + b[0] = (u8) reg >> 24; + b[1] = (u8)(reg >> 16) & 0xff; + b[2] = (u8)(reg >> 8) & 0xff; + b[3] = (u8) reg & 0xff; + memcpy(&b[4], buf, count); + + ret = i2c_transfer(state->i2c_adap, msg, 1); + + if (ret < 0) + return -EIO; + + return 0; +} + +static int it913x_write_reg(struct it913x_fe_state *state, + u8 pro, u32 reg, u32 data) +{ + int ret; + u8 b[4]; + u8 s; + + b[0] = data >> 24; + b[1] = (data >> 16) & 0xff; + b[2] = (data >> 8) & 0xff; + b[3] = data & 0xff; + /* expand write as needed */ + if (data < 0x100) + s = 3; + else if (data < 0x1000) + s = 2; + else if (data < 0x100000) + s = 1; + else + s = 0; + + ret = it913x_write(state, pro, reg, &b[s], sizeof(b) - s); + + return ret; +} + +static int it913x_fe_script_loader(struct it913x_fe_state *state, + struct it913xset *loadscript) +{ + int ret, i; + if (loadscript == NULL) + return -EINVAL; + + for (i = 0; i < 1000; ++i) { + if (loadscript[i].pro == 0xff) + break; + ret = it913x_write(state, loadscript[i].pro, + loadscript[i].address, + loadscript[i].reg, loadscript[i].count); + if (ret < 0) + return -ENODEV; + } + return 0; +} + +static int it9137_set_tuner(struct it913x_fe_state *state, + enum fe_bandwidth bandwidth, u32 frequency_m) +{ + struct it913xset *set_tuner = set_it9137_template; + int ret; + u32 frequency = frequency_m / 1000; + u32 freq; + u16 n_div; + u8 n; + u8 l_band; + u8 lna_band; + u8 bw; + + deb_info("Tuner Frequency %d Bandwidth %d", frequency, bandwidth); + + if (frequency >= 51000 && frequency <= 440000) { + l_band = 0; + lna_band = 0; + } else if (frequency > 440000 && frequency <= 484000) { + l_band = 1; + lna_band = 1; + } else if (frequency > 484000 && frequency <= 533000) { + l_band = 1; + lna_band = 2; + } else if (frequency > 533000 && frequency <= 587000) { + l_band = 1; + lna_band = 3; + } else if (frequency > 587000 && frequency <= 645000) { + l_band = 1; + lna_band = 4; + } else if (frequency > 645000 && frequency <= 710000) { + l_band = 1; + lna_band = 5; + } else if (frequency > 710000 && frequency <= 782000) { + l_band = 1; + lna_band = 6; + } else if (frequency > 782000 && frequency <= 860000) { + l_band = 1; + lna_band = 7; + } else if (frequency > 1450000 && frequency <= 1492000) { + l_band = 1; + lna_band = 0; + } else if (frequency > 1660000 && frequency <= 1685000) { + l_band = 1; + lna_band = 1; + } else + return -EINVAL; + set_tuner[0].reg[0] = lna_band; + + if (bandwidth == BANDWIDTH_5_MHZ) + bw = 0; + else if (bandwidth == BANDWIDTH_6_MHZ) + bw = 2; + else if (bandwidth == BANDWIDTH_7_MHZ) + bw = 4; + else if (bandwidth == BANDWIDTH_8_MHZ) + bw = 6; + else + bw = 6; + set_tuner[1].reg[0] = bw; + set_tuner[2].reg[0] = 0xa0 | (l_band << 3); + + if (frequency > 49000 && frequency <= 74000) { + n_div = 48; + n = 0; + } else if (frequency > 74000 && frequency <= 111000) { + n_div = 32; + n = 1; + } else if (frequency > 111000 && frequency <= 148000) { + n_div = 24; + n = 2; + } else if (frequency > 148000 && frequency <= 222000) { + n_div = 16; + n = 3; + } else if (frequency > 222000 && frequency <= 296000) { + n_div = 12; + n = 4; + } else if (frequency > 296000 && frequency <= 445000) { + n_div = 8; + n = 5; + } else if (frequency > 445000 && frequency <= 560000) { + n_div = 6; + n = 6; + } else if (frequency > 560000 && frequency <= 860000) { + n_div = 4; + n = 7; + } else if (frequency > 1450000 && frequency <= 1680000) { + n_div = 2; + n = 0; + } else + return -EINVAL; + + + /* Frequency + 3000 TODO not sure this is bandwidth setting */ + /* Xtal frequency 21327? but it works */ + freq = (u32) (n_div * 32 * (frequency + 3000) / 21327); + freq += (u32) n << 13; + set_tuner[2].reg[1] = freq & 0xff; + set_tuner[2].reg[2] = (freq >> 8) & 0xff; + + /* frequency */ + freq = (u32) (n_div * 32 * frequency / 21327); + freq += (u32) n << 13; + set_tuner[2].reg[3] = freq & 0xff; + set_tuner[2].reg[4] = (freq >> 8) & 0xff; + + deb_info("Frequency = %08x, Bandwidth = %02x, ", freq, bw); + + ret = it913x_fe_script_loader(state, set_tuner); + + return (ret < 0) ? -ENODEV : 0; + +} + +static int it913x_fe_select_bw(struct it913x_fe_state *state, + enum fe_bandwidth bandwidth, u32 adcFrequency) +{ + int ret, i; + u8 buffer[256]; + u32 coeff[8]; + u16 bfsfcw_fftinx_ratio; + u16 fftinx_bfsfcw_ratio; + u8 count; + u8 bw; + u8 adcmultiplier; + + deb_info("Bandwidth %d Adc %d", bandwidth, adcFrequency); + + if (bandwidth == BANDWIDTH_5_MHZ) + bw = 3; + else if (bandwidth == BANDWIDTH_6_MHZ) + bw = 0; + else if (bandwidth == BANDWIDTH_7_MHZ) + bw = 1; + else if (bandwidth == BANDWIDTH_8_MHZ) + bw = 2; + else + bw = 2; + + ret = it913x_write_reg(state, PRO_DMOD, REG_BW, bw); + + if (state->table == NULL) + return -EINVAL; + + /* In write order */ + coeff[0] = state->table[bw].coeff_1_2048; + coeff[1] = state->table[bw].coeff_2_2k; + coeff[2] = state->table[bw].coeff_1_8191; + coeff[3] = state->table[bw].coeff_1_8192; + coeff[4] = state->table[bw].coeff_1_8193; + coeff[5] = state->table[bw].coeff_2_8k; + coeff[6] = state->table[bw].coeff_1_4096; + coeff[7] = state->table[bw].coeff_2_4k; + bfsfcw_fftinx_ratio = state->table[bw].bfsfcw_fftinx_ratio; + fftinx_bfsfcw_ratio = state->table[bw].fftinx_bfsfcw_ratio; + + /* ADC multiplier */ + ret = it913x_read_reg_u8(state, ADC_X_2); + if (ret < 0) + return -EINVAL; + + adcmultiplier = ret; + + count = 0; + + /* Build Buffer for COEFF Registers */ + for (i = 0; i < 8; i++) { + if (adcmultiplier == 1) + coeff[i] /= 2; + buffer[count++] = (coeff[i] >> 24) & 0x3; + buffer[count++] = (coeff[i] >> 16) & 0xff; + buffer[count++] = (coeff[i] >> 8) & 0xff; + buffer[count++] = coeff[i] & 0xff; + } + + /* bfsfcw_fftinx_ratio register 0x21-0x22 */ + buffer[count++] = bfsfcw_fftinx_ratio & 0xff; + buffer[count++] = (bfsfcw_fftinx_ratio >> 8) & 0xff; + /* fftinx_bfsfcw_ratio register 0x23-0x24 */ + buffer[count++] = fftinx_bfsfcw_ratio & 0xff; + buffer[count++] = (fftinx_bfsfcw_ratio >> 8) & 0xff; + /* start at COEFF_1_2048 and write through to fftinx_bfsfcw_ratio*/ + ret = it913x_write(state, PRO_DMOD, COEFF_1_2048, buffer, count); + + for (i = 0; i < 42; i += 8) + debug_data_snipet(0x1, "Buffer", &buffer[i]); + + return ret; +} + + + +static int it913x_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct it913x_fe_state *state = fe->demodulator_priv; + int ret, i; + fe_status_t old_status = state->it913x_status; + *status = 0; + + if (state->it913x_status == 0) { + ret = it913x_read_reg_u8(state, EMPTY_CHANNEL_STATUS); + if (ret == 0x1) { + *status |= FE_HAS_SIGNAL; + for (i = 0; i < 40; i++) { + ret = it913x_read_reg_u8(state, MP2IF_SYNC_LK); + if (ret == 0x1) + break; + msleep(25); + } + if (ret == 0x1) + *status |= FE_HAS_CARRIER + | FE_HAS_VITERBI + | FE_HAS_SYNC; + state->it913x_status = *status; + } + } + + if (state->it913x_status & FE_HAS_SYNC) { + ret = it913x_read_reg_u8(state, TPSD_LOCK); + if (ret == 0x1) + *status |= FE_HAS_LOCK + | state->it913x_status; + else + state->it913x_status = 0; + if (old_status != state->it913x_status) + ret = it913x_write_reg(state, PRO_LINK, GPIOH3_O, ret); + } + + return 0; +} + +static int it913x_fe_read_signal_strength(struct dvb_frontend *fe, + u16 *strength) +{ + struct it913x_fe_state *state = fe->demodulator_priv; + int ret = it913x_read_reg_u8(state, SIGNAL_LEVEL); + /*SIGNAL_LEVEL always returns 100%! so using FE_HAS_SIGNAL as switch*/ + if (state->it913x_status & FE_HAS_SIGNAL) + ret = (ret * 0xff) / 0x64; + else + ret = 0x0; + ret |= ret << 0x8; + *strength = ret; + return 0; +} + +static int it913x_fe_read_snr(struct dvb_frontend *fe, u16* snr) +{ + struct it913x_fe_state *state = fe->demodulator_priv; + int ret = it913x_read_reg_u8(state, SIGNAL_QUALITY); + ret = (ret * 0xff) / 0x64; + ret |= (ret << 0x8); + *snr = ~ret; + return 0; +} + +static int it913x_fe_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + *ber = 0; + return 0; +} + +static int it913x_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + *ucblocks = 0; + return 0; +} + +static int it913x_fe_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct it913x_fe_state *state = fe->demodulator_priv; + int ret; + u8 reg[8]; + + ret = it913x_read_reg(state, REG_TPSD_TX_MODE, reg, sizeof(reg)); + + if (reg[3] < 3) + p->u.ofdm.constellation = fe_con[reg[3]]; + + if (reg[0] < 3) + p->u.ofdm.transmission_mode = fe_mode[reg[0]]; + + if (reg[1] < 4) + p->u.ofdm.guard_interval = fe_gi[reg[1]]; + + if (reg[2] < 4) + p->u.ofdm.hierarchy_information = fe_hi[reg[2]]; + + p->u.ofdm.code_rate_HP = (reg[6] < 6) ? fe_code[reg[6]] : FEC_NONE; + p->u.ofdm.code_rate_LP = (reg[7] < 6) ? fe_code[reg[7]] : FEC_NONE; + + return 0; +} + +static int it913x_fe_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct it913x_fe_state *state = fe->demodulator_priv; + int ret, i; + u8 empty_ch, last_ch; + + state->it913x_status = 0; + + /* Set bw*/ + ret = it913x_fe_select_bw(state, p->u.ofdm.bandwidth, + state->adcFrequency); + + /* Training Mode Off */ + ret = it913x_write_reg(state, PRO_LINK, TRAINING_MODE, 0x0); + + /* Clear Empty Channel */ + ret = it913x_write_reg(state, PRO_DMOD, EMPTY_CHANNEL_STATUS, 0x0); + + /* Clear bits */ + ret = it913x_write_reg(state, PRO_DMOD, MP2IF_SYNC_LK, 0x0); + /* LED on */ + ret = it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x1); + /* Select Band*/ + if ((p->frequency >= 51000000) && (p->frequency <= 230000000)) + i = 0; + else if ((p->frequency >= 350000000) && (p->frequency <= 900000000)) + i = 1; + else if ((p->frequency >= 1450000000) && (p->frequency <= 1680000000)) + i = 2; + else + return -EOPNOTSUPP; + + ret = it913x_write_reg(state, PRO_DMOD, FREE_BAND, i); + + deb_info("Frontend Set Tuner Type %02x", state->tuner_type); + switch (state->tuner_type) { + case IT9137: /* Tuner type 0x38 */ + ret = it9137_set_tuner(state, + p->u.ofdm.bandwidth, p->frequency); + break; + default: + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + break; + } + /* LED off */ + ret = it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x0); + /* Trigger ofsm */ + ret = it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x0); + last_ch = 2; + for (i = 0; i < 40; ++i) { + empty_ch = it913x_read_reg_u8(state, EMPTY_CHANNEL_STATUS); + if (last_ch == 1 && empty_ch == 1) + break; + if (last_ch == 2 && empty_ch == 2) + return 0; + last_ch = empty_ch; + msleep(25); + } + for (i = 0; i < 40; ++i) { + if (it913x_read_reg_u8(state, D_TPSD_LOCK) == 1) + break; + msleep(25); + } + + state->frequency = p->frequency; + return 0; +} + +static int it913x_fe_suspend(struct it913x_fe_state *state) +{ + int ret, i; + u8 b; + + ret = it913x_write_reg(state, PRO_DMOD, SUSPEND_FLAG, 0x1); + + ret |= it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x0); + + for (i = 0; i < 128; i++) { + ret = it913x_read_reg(state, SUSPEND_FLAG, &b, 1); + if (ret < 0) + return -EINVAL; + if (b == 0) + break; + + } + + ret |= it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x8); + /* Turn LED off */ + ret = it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x0); + + return 0; +} + +static int it913x_fe_sleep(struct dvb_frontend *fe) +{ + struct it913x_fe_state *state = fe->demodulator_priv; + return it913x_fe_suspend(state); +} + + +static u32 compute_div(u32 a, u32 b, u32 x) +{ + u32 res = 0; + u32 c = 0; + u32 i = 0; + + if (a > b) { + c = a / b; + a = a - c * b; + } + + for (i = 0; i < x; i++) { + if (a >= b) { + res += 1; + a -= b; + } + a <<= 1; + res <<= 1; + } + + res = (c << x) + res; + + return res; +} + +static int it913x_fe_start(struct it913x_fe_state *state) +{ + struct it913xset *set_fe; + struct it913xset *set_mode; + int ret; + u8 adf = (state->adf & 0xf); + u32 adc, xtal; + u8 b[4]; + + if (adf < 12) { + state->crystalFrequency = fe_clockTable[adf].xtal ; + state->table = fe_clockTable[adf].table; + state->adcFrequency = state->table->adcFrequency; + + adc = compute_div(state->adcFrequency, 1000000ul, 19ul); + xtal = compute_div(state->crystalFrequency, 1000000ul, 19ul); + + } else + return -EINVAL; + + deb_info("Xtal Freq :%d Adc Freq :%d Adc %08x Xtal %08x", + state->crystalFrequency, state->adcFrequency, adc, xtal); + + /* Set LED indicator on GPIOH3 */ + ret = it913x_write_reg(state, PRO_LINK, GPIOH3_EN, 0x1); + ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_ON, 0x1); + ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x1); + + ret |= it913x_write_reg(state, PRO_DMOD, 0xed81, 0x10); + ret |= it913x_write_reg(state, PRO_LINK, 0xf641, state->tuner_type); + ret |= it913x_write_reg(state, PRO_DMOD, 0xf5ca, 0x01); + ret |= it913x_write_reg(state, PRO_DMOD, 0xf715, 0x01); + + b[0] = xtal & 0xff; + b[1] = (xtal >> 8) & 0xff; + b[2] = (xtal >> 16) & 0xff; + b[3] = (xtal >> 24); + ret |= it913x_write(state, PRO_DMOD, XTAL_CLK, b , 4); + + b[0] = adc & 0xff; + b[1] = (adc >> 8) & 0xff; + b[2] = (adc >> 16) & 0xff; + ret |= it913x_write(state, PRO_DMOD, ADC_FREQ, b, 3); + + switch (state->tuner_type) { + case IT9137: /* Tuner type 0x38 */ + set_fe = it9137_set; + break; + default: + return -EINVAL; + } + /* set the demod */ + ret = it913x_fe_script_loader(state, set_fe); + /* Always solo frontend */ + set_mode = set_solo_fe; + ret |= it913x_fe_script_loader(state, set_mode); + + ret |= it913x_fe_suspend(state); + return 0; +} + +static int it913x_fe_init(struct dvb_frontend *fe) +{ + struct it913x_fe_state *state = fe->demodulator_priv; + struct it913xset *set_tuner; + int ret = 0; + + switch (state->tuner_type) { + case IT9137: /* Tuner type 0x38 */ + set_tuner = it9137_tuner; + break; + default: + return -EINVAL; + } + + /* set any tuner reg(s) */ + ret = it913x_fe_script_loader(state, set_tuner); + + it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x0); + + ret |= it913x_fe_script_loader(state, init_1); + + return (ret < 0) ? -ENODEV : 0; +} + +static void it913x_fe_release(struct dvb_frontend *fe) +{ + struct it913x_fe_state *state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops it913x_fe_ofdm_ops; + +struct dvb_frontend *it913x_fe_attach(struct i2c_adapter *i2c_adap, + u8 i2c_addr, u8 adf, u8 type) +{ + struct it913x_fe_state *state = NULL; + int ret; + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct it913x_fe_state), GFP_KERNEL); + if (state == NULL) + goto error; + + state->i2c_adap = i2c_adap; + state->i2c_addr = i2c_addr; + state->adf = adf; + state->tuner_type = type; + + ret = it913x_fe_start(state); + if (ret < 0) + goto error; + + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &it913x_fe_ofdm_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + + return &state->frontend; +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(it913x_fe_attach); + +static struct dvb_frontend_ops it913x_fe_ofdm_ops = { + + .info = { + .name = "it913x-fe DVB-T", + .type = FE_OFDM, + .frequency_min = 51000000, + .frequency_max = 1680000000, + .frequency_stepsize = 62500, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | + FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | + FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = it913x_fe_release, + + .init = it913x_fe_init, + .sleep = it913x_fe_sleep, + + .set_frontend = it913x_fe_set_frontend, + .get_frontend = it913x_fe_get_frontend, + + .read_status = it913x_fe_read_status, + .read_signal_strength = it913x_fe_read_signal_strength, + .read_snr = it913x_fe_read_snr, + .read_ber = it913x_fe_read_ber, + .read_ucblocks = it913x_fe_read_ucblocks, +}; + +MODULE_DESCRIPTION("it913x Frontend and it9137 tuner"); +MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); +MODULE_VERSION("1.05"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/it913x-fe.h b/drivers/media/dvb/frontends/it913x-fe.h new file mode 100644 index 0000000..9d97f32 --- /dev/null +++ b/drivers/media/dvb/frontends/it913x-fe.h @@ -0,0 +1,196 @@ +/* + * Driver for it913x Frontend + * + * + * 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 of the License, 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.= + */ + +#ifndef IT913X_FE_H +#define IT913X_FE_H + +#include +#include "dvb_frontend.h" +#if defined(CONFIG_DVB_IT913X_FE) || (defined(CONFIG_DVB_IT913X_FE_MODULE) && \ +defined(MODULE)) +extern struct dvb_frontend *it913x_fe_attach(struct i2c_adapter *i2c_adap, + u8 i2c_addr, u8 adf, u8 type); +#else +static inline struct dvb_frontend *it913x_fe_attach( + struct i2c_adapter *i2c_adap, u8 i2c_addr, u8 adf, u8 type) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_IT913X_FE */ +#define I2C_BASE_ADDR 0x10 +#define DEV_0 0x0 +#define DEV_1 0x10 +#define PRO_LINK 0x0 +#define PRO_DMOD 0x1 +#define DEV_0_DMOD (PRO_DMOD << 0x7) +#define DEV_1_DMOD (DEV_0_DMOD | DEV_1) +#define CHIP2_I2C_ADDR 0x3a + +#define AFE_MEM0 0xfb24 + +#define MP2_SW_RST 0xf99d +#define MP2IF2_SW_RST 0xf9a4 + +#define PADODPU 0xd827 +#define THIRDODPU 0xd828 +#define AGC_O_D 0xd829 + +#define EP0_TX_EN 0xdd11 +#define EP0_TX_NAK 0xdd13 +#define EP4_TX_LEN_LSB 0xdd88 +#define EP4_TX_LEN_MSB 0xdd89 +#define EP4_MAX_PKT 0xdd0c +#define EP5_TX_LEN_LSB 0xdd8a +#define EP5_TX_LEN_MSB 0xdd8b +#define EP5_MAX_PKT 0xdd0d + +#define IO_MUX_POWER_CLK 0xd800 +#define CLK_O_EN 0xd81a +#define I2C_CLK 0xf103 +#define I2C_CLK_100 0x7 +#define I2C_CLK_400 0x1a + +#define D_TPSD_LOCK 0xf5a9 +#define MP2IF2_EN 0xf9a3 +#define MP2IF_SERIAL 0xf985 +#define TSIS_ENABLE 0xf9cd +#define MP2IF2_HALF_PSB 0xf9a5 +#define MP2IF_STOP_EN 0xf9b5 +#define MPEG_FULL_SPEED 0xf990 +#define TOP_HOSTB_SER_MODE 0xd91c + +#define PID_RST 0xf992 +#define PID_EN 0xf993 +#define PID_INX_EN 0xf994 +#define PID_INX 0xf995 +#define PID_LSB 0xf996 +#define PID_MSB 0xf997 + +#define MP2IF_MPEG_PAR_MODE 0xf986 +#define DCA_UPPER_CHIP 0xf731 +#define DCA_LOWER_CHIP 0xf732 +#define DCA_PLATCH 0xf730 +#define DCA_FPGA_LATCH 0xf778 +#define DCA_STAND_ALONE 0xf73c +#define DCA_ENABLE 0xf776 + +#define DVBT_INTEN 0xf41f +#define DVBT_ENABLE 0xf41a +#define HOSTB_DCA_LOWER 0xd91f +#define HOSTB_MPEG_PAR_MODE 0xd91b +#define HOSTB_MPEG_SER_MODE 0xd91c +#define HOSTB_MPEG_SER_DO7 0xd91d +#define HOSTB_DCA_UPPER 0xd91e +#define PADMISCDR2 0xd830 +#define PADMISCDR4 0xd831 +#define PADMISCDR8 0xd832 +#define PADMISCDRSR 0xd833 +#define LOCK3_OUT 0xd8fd + +#define GPIOH1_O 0xd8af +#define GPIOH1_EN 0xd8b0 +#define GPIOH1_ON 0xd8b1 +#define GPIOH3_O 0xd8b3 +#define GPIOH3_EN 0xd8b4 +#define GPIOH3_ON 0xd8b5 +#define GPIOH5_O 0xd8bb +#define GPIOH5_EN 0xd8bc +#define GPIOH5_ON 0xd8bd + +#define AFE_MEM0 0xfb24 + +#define REG_TPSD_TX_MODE 0xf900 +#define REG_TPSD_GI 0xf901 +#define REG_TPSD_HIER 0xf902 +#define REG_TPSD_CONST 0xf903 +#define REG_BW 0xf904 +#define REG_PRIV 0xf905 +#define REG_TPSD_HP_CODE 0xf906 +#define REG_TPSD_LP_CODE 0xf907 + +#define MP2IF_SYNC_LK 0xf999 +#define ADC_FREQ 0xf1cd + +#define TRIGGER_OFSM 0x0000 +/* COEFF Registers start at 0x0001 to 0x0020 */ +#define COEFF_1_2048 0x0001 +#define XTAL_CLK 0x0025 +#define BFS_FCW 0x0029 +#define TPSD_LOCK 0x003c +#define TRAINING_MODE 0x0040 +#define ADC_X_2 0x0045 +#define TUNER_ID 0x0046 +#define EMPTY_CHANNEL_STATUS 0x0047 +#define SIGNAL_LEVEL 0x0048 +#define SIGNAL_QUALITY 0x0049 +#define EST_SIGNAL_LEVEL 0x004a +#define FREE_BAND 0x004b +#define SUSPEND_FLAG 0x004c +/* Build in tuners */ +#define IT9137 0x38 + +enum { + CMD_DEMOD_READ = 0, + CMD_DEMOD_WRITE, + CMD_TUNER_READ, + CMD_TUNER_WRITE, + CMD_REG_EEPROM_READ, + CMD_REG_EEPROM_WRITE, + CMD_DATA_READ, + CMD_VAR_READ = 8, + CMD_VAR_WRITE, + CMD_PLATFORM_GET, + CMD_PLATFORM_SET, + CMD_IP_CACHE, + CMD_IP_ADD, + CMD_IP_REMOVE, + CMD_PID_ADD, + CMD_PID_REMOVE, + CMD_SIPSI_GET, + CMD_SIPSI_MPE_RESET, + CMD_H_PID_ADD = 0x15, + CMD_H_PID_REMOVE, + CMD_ABORT, + CMD_IR_GET, + CMD_IR_SET, + CMD_FW_DOWNLOAD = 0x21, + CMD_QUERYINFO, + CMD_BOOT, + CMD_FW_DOWNLOAD_BEGIN, + CMD_FW_DOWNLOAD_END, + CMD_RUN_CODE, + CMD_SCATTER_READ = 0x28, + CMD_SCATTER_WRITE, + CMD_GENERIC_READ, + CMD_GENERIC_WRITE +}; + +enum { + READ_LONG, + WRITE_LONG, + READ_SHORT, + WRITE_SHORT, + READ_DATA, + WRITE_DATA, + WRITE_CMD, +}; + +#endif /* IT913X_FE_H */ -- cgit v0.10.2 From 52cb3e2757baefddaa159c3d3157a2c4a9e5f694 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Mon, 25 Jul 2011 15:34:45 -0300 Subject: [media] it9137: Fimrware retrival information for Kworld UB499-2T T09 (id 1b80:e409) Firmware information for Kworld UB499-2T T09 based on IT913x series. This device uses file dvb-usb-it9137-01.fw. Signed-off-by: Malcolm Priestley Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/dvb/it9137.txt b/Documentation/dvb/it9137.txt new file mode 100644 index 0000000..9e6726e --- /dev/null +++ b/Documentation/dvb/it9137.txt @@ -0,0 +1,9 @@ +To extract firmware for Kworld UB499-2T (id 1b80:e409) you need to copy the +following file(s) to this directory. + +IT9135BDA.sys Dated Mon 22 Mar 2010 02:20:08 GMT + +extract using dd +dd if=IT9135BDA.sys ibs=1 skip=69632 count=5731 of=dvb-usb-it9137-01.fw + +copy to default firmware location. -- cgit v0.10.2 From f6d8735493eb02248bc7d7b05d5967f9a68b5c44 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Mon, 25 Jul 2011 15:35:03 -0300 Subject: [media] it913x: Driver for Kworld UB499-2T (id 1b80:e409) v1.05 Driver for Kworld UB499-2T (id 1b80:e409) The device driver has been named it913x, so that support for other family members can be added later. TODOs Firmware support for other it913x devices. Remote control support, there are two known types. Signed-off-by: Malcolm Priestley [mchehab@redhat.com: Fix a merge conflict] Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 5d73dec..6e97bb3 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -374,3 +374,10 @@ config DVB_USB_TECHNISAT_USB2 select DVB_STV6110x if !DVB_FE_CUSTOMISE help Say Y here to support the Technisat USB2 DVB-S/S2 device + +config DVB_USB_IT913X + tristate "it913x driver" + depends on DVB_USB + select DVB_IT913X_FE + help + Say Y here to support the it913x device diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 4bac13d..3494d41 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -94,6 +94,9 @@ obj-$(CONFIG_DVB_USB_LME2510) += dvb-usb-lmedm04.o dvb-usb-technisat-usb2-objs = technisat-usb2.o obj-$(CONFIG_DVB_USB_TECHNISAT_USB2) += dvb-usb-technisat-usb2.o +dvb-usb-it913x-objs := it913x.o +obj-$(CONFIG_DVB_USB_IT913X) += dvb-usb-it913x.o + EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ # due to tuner-xc3028 EXTRA_CFLAGS += -Idrivers/media/common/tuners diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 2a79b8f..7433261 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -136,6 +136,7 @@ #define USB_PID_KWORLD_PC160_2T 0xc160 #define USB_PID_KWORLD_PC160_T 0xc161 #define USB_PID_KWORLD_UB383_T 0xe383 +#define USB_PID_KWORLD_UB499_2T_T09 0xe409 #define USB_PID_KWORLD_VSTREAM_COLD 0x17de #define USB_PID_KWORLD_VSTREAM_WARM 0x17df #define USB_PID_TERRATEC_CINERGY_T_USB_XE 0x0055 diff --git a/drivers/media/dvb/dvb-usb/it913x.c b/drivers/media/dvb/dvb-usb/it913x.c new file mode 100644 index 0000000..3900068 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/it913x.c @@ -0,0 +1,613 @@ +/* DVB USB compliant linux driver for IT9137 + * + * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com) + * IT9137 (C) ITE Tech Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2, as + * published by the Free Software Foundation. + * + * 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. + * + * + * see Documentation/dvb/README.dvb-usb for more information + * see Documentation/dvb/it9137.txt for firmware information + * + */ +#define DVB_USB_LOG_PREFIX "it913x" + +#include +#include +#include + +#include "dvb-usb.h" +#include "it913x-fe.h" + +/* debug */ +static int dvb_usb_it913x_debug; +#define l_dprintk(var, level, args...) do { \ + if ((var >= level)) \ + printk(KERN_DEBUG DVB_USB_LOG_PREFIX ": " args); \ +} while (0) + +#define deb_info(level, args...) l_dprintk(dvb_usb_it913x_debug, level, args) +#define debug_data_snipet(level, name, p) \ + deb_info(level, name" (%02x%02x%02x%02x%02x%02x%02x%02x)", \ + *p, *(p+1), *(p+2), *(p+3), *(p+4), \ + *(p+5), *(p+6), *(p+7)); + + +module_param_named(debug, dvb_usb_it913x_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))." + DVB_USB_DEBUG_STATUS); + +static int pid_filter; +module_param_named(pid, pid_filter, int, 0644); +MODULE_PARM_DESC(pid, "set default 0=on 1=off"); + +int cmd_counter; + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +struct it913x_state { + u8 id; +}; + +static int it913x_bulk_write(struct usb_device *dev, + u8 *snd, int len, u8 pipe) +{ + int ret, actual_l; + + ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe), + snd, len , &actual_l, 100); + return ret; +} + +static int it913x_bulk_read(struct usb_device *dev, + u8 *rev, int len, u8 pipe) +{ + int ret, actual_l; + + ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe), + rev, len , &actual_l, 200); + return ret; +} + +static u16 check_sum(u8 *p, u8 len) +{ + u16 sum = 0; + u8 i = 1; + while (i < len) + sum += (i++ & 1) ? (*p++) << 8 : *p++; + return ~sum; +} + +static int it913x_io(struct usb_device *udev, u8 mode, u8 pro, + u8 cmd, u32 reg, u8 addr, u8 *data, u8 len) +{ + int ret = 0, i, buf_size = 1; + u8 *buff; + u8 rlen; + u16 chk_sum; + + buff = kzalloc(256, GFP_KERNEL); + if (!buff) { + info("USB Buffer Failed"); + return -ENOMEM; + } + + buff[buf_size++] = pro; + buff[buf_size++] = cmd; + buff[buf_size++] = cmd_counter; + + switch (mode) { + case READ_LONG: + case WRITE_LONG: + buff[buf_size++] = len; + buff[buf_size++] = 2; + buff[buf_size++] = (reg >> 24); + buff[buf_size++] = (reg >> 16) & 0xff; + buff[buf_size++] = (reg >> 8) & 0xff; + buff[buf_size++] = reg & 0xff; + break; + case READ_SHORT: + buff[buf_size++] = addr; + break; + case WRITE_SHORT: + buff[buf_size++] = len; + buff[buf_size++] = addr; + buff[buf_size++] = (reg >> 8) & 0xff; + buff[buf_size++] = reg & 0xff; + break; + case READ_DATA: + case WRITE_DATA: + break; + case WRITE_CMD: + mode = 7; + break; + default: + kfree(buff); + return -EINVAL; + } + + if (mode & 1) { + for (i = 0; i < len ; i++) + buff[buf_size++] = data[i]; + } + chk_sum = check_sum(&buff[1], buf_size); + + buff[buf_size++] = chk_sum >> 8; + buff[0] = buf_size; + buff[buf_size++] = (chk_sum & 0xff); + + ret = it913x_bulk_write(udev, buff, buf_size , 0x02); + + ret |= it913x_bulk_read(udev, buff, (mode & 1) ? + 5 : len + 5 , 0x01); + + rlen = (mode & 0x1) ? 0x1 : len; + + if (mode & 1) + ret |= buff[2]; + else + memcpy(data, &buff[3], rlen); + + cmd_counter++; + + kfree(buff); + + return (ret < 0) ? -ENODEV : 0; +} + +static int it913x_wr_reg(struct usb_device *udev, u8 pro, u32 reg , u8 data) +{ + int ret; + u8 b[1]; + b[0] = data; + ret = it913x_io(udev, WRITE_LONG, pro, + CMD_DEMOD_WRITE, reg, 0, b, sizeof(b)); + + return ret; +} + +static int it913x_read_reg(struct usb_device *udev, u32 reg) +{ + int ret; + u8 data[1]; + + ret = it913x_io(udev, READ_LONG, DEV_0, + CMD_DEMOD_READ, reg, 0, &data[0], 1); + + return (ret < 0) ? ret : data[0]; +} + +static u32 it913x_query(struct usb_device *udev, u8 pro) +{ + int ret; + u32 res = 0; + u8 data[4]; + ret = it913x_io(udev, READ_LONG, pro, CMD_DEMOD_READ, + 0x1222, 0, &data[0], 1); + if (data[0] == 0x1) { + ret = it913x_io(udev, READ_SHORT, pro, + CMD_QUERYINFO, 0, 0x1, &data[0], 4); + res = (data[0] << 24) + (data[1] << 16) + + (data[2] << 8) + data[3]; + } + + return (ret < 0) ? 0 : res; +} + +static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + int ret = 0; + u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; + + if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) + return -EAGAIN; + deb_info(1, "PID_C (%02x)", onoff); + + if (!onoff) + ret = it913x_wr_reg(adap->dev->udev, pro, PID_RST, 0x1); + + mutex_unlock(&adap->dev->i2c_mutex); + return ret; +} + +static int it913x_pid_filter(struct dvb_usb_adapter *adap, + int index, u16 pid, int onoff) +{ + struct usb_device *udev = adap->dev->udev; + int ret = 0; + u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; + + if (pid_filter > 0) + return 0; + + if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) + return -EAGAIN; + deb_info(1, "PID_F (%02x)", onoff); + if (onoff) { + ret = it913x_wr_reg(udev, pro, PID_EN, 0x1); + + ret |= it913x_wr_reg(udev, pro, PID_LSB, (u8)(pid & 0xff)); + + ret |= it913x_wr_reg(udev, pro, PID_MSB, (u8)(pid >> 8)); + + ret |= it913x_wr_reg(udev, pro, PID_INX_EN, (u8)onoff); + + ret |= it913x_wr_reg(udev, pro, PID_INX, (u8)(index & 0x1f)); + + } + + mutex_unlock(&adap->dev->i2c_mutex); + return 0; +} + + +static int it913x_return_status(struct usb_device *udev) +{ + u32 firm = 0; + + firm = it913x_query(udev, DEV_0); + if (firm > 0) + info("Firmware Version %d", firm); + + return (firm > 0) ? firm : 0; +} + +static int it913x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + static u8 data[256]; + int ret; + u32 reg; + u8 pro; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + debug_data_snipet(1, "Message out", msg[0].buf); + deb_info(2, "num of messages %d address %02x", num, msg[0].addr); + + pro = (msg[0].addr & 0x2) ? DEV_0_DMOD : 0x0; + pro |= (msg[0].addr & 0x20) ? DEV_1 : DEV_0; + memcpy(data, msg[0].buf, msg[0].len); + reg = (data[0] << 24) + (data[1] << 16) + + (data[2] << 8) + data[3]; + if (num == 2) { + ret = it913x_io(d->udev, READ_LONG, pro, + CMD_DEMOD_READ, reg, 0, data, msg[1].len); + memcpy(msg[1].buf, data, msg[1].len); + } else + ret = it913x_io(d->udev, WRITE_LONG, pro, CMD_DEMOD_WRITE, + reg, 0, &data[4], msg[0].len - 4); + + mutex_unlock(&d->i2c_mutex); + + return ret; +} + +static u32 it913x_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm it913x_i2c_algo = { + .master_xfer = it913x_i2c_xfer, + .functionality = it913x_i2c_func, +}; + +/* Callbacks for DVB USB */ +static int it913x_identify_state(struct usb_device *udev, + struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, + int *cold) +{ + int ret = 0, firm_no; + u8 reg, adap, ep, tun0, tun1; + + firm_no = it913x_return_status(udev); + + ep = it913x_read_reg(udev, 0x49ac); + adap = it913x_read_reg(udev, 0x49c5); + tun0 = it913x_read_reg(udev, 0x49d0); + info("No. Adapters=%x Endpoints=%x Tuner Type=%x", adap, ep, tun0); + + if (firm_no > 0) { + *cold = 0; + return 0; + } + + if (adap > 2) { + tun1 = it913x_read_reg(udev, 0x49e0); + ret = it913x_wr_reg(udev, DEV_0, GPIOH1_EN, 0x1); + ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_ON, 0x1); + ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x1); + msleep(50); /* Delay noticed reset cycle ? */ + ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x0); + msleep(50); + reg = it913x_read_reg(udev, GPIOH1_O); + if (reg == 0) { + ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x1); + ret |= it913x_return_status(udev); + if (ret != 0) + ret = it913x_wr_reg(udev, DEV_0, + GPIOH1_O, 0x0); + } + } else + props->num_adapters = 1; + + reg = it913x_read_reg(udev, IO_MUX_POWER_CLK); + + ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, CHIP2_I2C_ADDR); + + ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x1); + + *cold = 1; + + return (ret < 0) ? -ENODEV : 0; +} + +static int it913x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + int ret = 0; + u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; + + if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) + return -EAGAIN; + deb_info(1, "STM (%02x)", onoff); + + if (!onoff) + ret = it913x_wr_reg(adap->dev->udev, pro, PID_RST, 0x1); + + + mutex_unlock(&adap->dev->i2c_mutex); + + return ret; +} + + +static int it913x_download_firmware(struct usb_device *udev, + const struct firmware *fw) +{ + int ret = 0, i; + u8 packet_size, dlen, tun1; + u8 *fw_data; + + packet_size = 0x29; + + tun1 = it913x_read_reg(udev, 0x49e0); + + ret = it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_100); + + info("FRM Starting Firmware Download"); + /* This uses scatter write firmware headers follow */ + /* 03 XX 00 XX = chip number? */ + + for (i = 0; i < fw->size; i += packet_size) { + if (i > 0) + packet_size = 0x39; + fw_data = (u8 *)(fw->data + i); + dlen = ((i + packet_size) > fw->size) + ? (fw->size - i) : packet_size; + ret |= it913x_io(udev, WRITE_DATA, DEV_0, + CMD_SCATTER_WRITE, 0, 0, fw_data, dlen); + udelay(1000); + } + + ret |= it913x_io(udev, WRITE_CMD, DEV_0, + CMD_BOOT, 0, 0, NULL, 0); + + msleep(100); + + if (ret < 0) + info("FRM Firmware Download Failed (%04x)" , ret); + else + info("FRM Firmware Download Completed - Resetting Device"); + + ret |= it913x_return_status(udev); + + msleep(30); + + ret |= it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_400); + + /* Tuner function */ + ret |= it913x_wr_reg(udev, DEV_0_DMOD , 0xec4c, 0xa0); + + ret |= it913x_wr_reg(udev, DEV_0, PADODPU, 0x0); + ret |= it913x_wr_reg(udev, DEV_0, AGC_O_D, 0x0); + if (tun1 > 0) { + ret |= it913x_wr_reg(udev, DEV_1, PADODPU, 0x0); + ret |= it913x_wr_reg(udev, DEV_1, AGC_O_D, 0x0); + } + + return (ret < 0) ? -ENODEV : 0; +} + +static int it913x_name(struct dvb_usb_adapter *adap) +{ + const char *desc = adap->dev->desc->name; + char *fe_name[] = {"_1", "_2", "_3", "_4"}; + char *name = adap->fe[0]->ops.info.name; + + strlcpy(name, desc, 128); + strlcat(name, fe_name[adap->id], 128); + + return 0; +} + +static int it913x_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct usb_device *udev = adap->dev->udev; + int ret = 0; + u8 adf = it913x_read_reg(udev, IO_MUX_POWER_CLK); + u8 adap_addr = I2C_BASE_ADDR + (adap->id << 5); + u16 ep_size = adap->props.stream.u.bulk.buffersize; + + adap->fe[0] = dvb_attach(it913x_fe_attach, + &adap->dev->i2c_adap, adap_addr, adf, IT9137); + + if (adap->id == 0 && adap->fe[0]) { + ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2_SW_RST, 0x1); + ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF2_SW_RST, 0x1); + ret = it913x_wr_reg(udev, DEV_0, EP0_TX_EN, 0x0f); + ret = it913x_wr_reg(udev, DEV_0, EP0_TX_NAK, 0x1b); + ret = it913x_wr_reg(udev, DEV_0, EP0_TX_EN, 0x2f); + ret = it913x_wr_reg(udev, DEV_0, EP4_TX_LEN_LSB, + ep_size & 0xff); + ret = it913x_wr_reg(udev, DEV_0, EP4_TX_LEN_MSB, ep_size >> 8); + ret = it913x_wr_reg(udev, DEV_0, EP4_MAX_PKT, 0x80); + } else if (adap->id == 1 && adap->fe[0]) { + ret = it913x_wr_reg(udev, DEV_0, EP0_TX_EN, 0x6f); + ret = it913x_wr_reg(udev, DEV_0, EP5_TX_LEN_LSB, + ep_size & 0xff); + ret = it913x_wr_reg(udev, DEV_0, EP5_TX_LEN_MSB, ep_size >> 8); + ret = it913x_wr_reg(udev, DEV_0, EP5_MAX_PKT, 0x80); + ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF2_EN, 0x1); + ret = it913x_wr_reg(udev, DEV_1_DMOD, MP2IF_SERIAL, 0x1); + ret = it913x_wr_reg(udev, DEV_1, TOP_HOSTB_SER_MODE, 0x1); + ret = it913x_wr_reg(udev, DEV_0_DMOD, TSIS_ENABLE, 0x1); + ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2_SW_RST, 0x0); + ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF2_SW_RST, 0x0); + ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF2_HALF_PSB, 0x0); + ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF_STOP_EN, 0x1); + ret = it913x_wr_reg(udev, DEV_1_DMOD, MPEG_FULL_SPEED, 0x0); + ret = it913x_wr_reg(udev, DEV_1_DMOD, MP2IF_STOP_EN, 0x0); + } else + return -ENODEV; + + ret = it913x_name(adap); + + return ret; +} + +/* DVB USB Driver */ +static struct dvb_usb_device_properties it913x_properties; + +static int it913x_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + cmd_counter = 0; + if (0 == dvb_usb_device_init(intf, &it913x_properties, + THIS_MODULE, NULL, adapter_nr)) { + info("DEV registering device driver"); + return 0; + } + + info("DEV it913x Error"); + return -ENODEV; + +} + +static struct usb_device_id it913x_table[] = { + { USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09) }, + {} /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, it913x_table); + +static struct dvb_usb_device_properties it913x_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = DEVICE_SPECIFIC, + .download_firmware = it913x_download_firmware, + .firmware = "dvb-usb-it9137-01.fw", + .no_reconnect = 1, + .size_of_priv = sizeof(struct it913x_state), + .num_adapters = 2, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER| + DVB_USB_ADAP_NEED_PID_FILTERING| + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .streaming_ctrl = it913x_streaming_ctrl, + .pid_filter_count = 31, + .pid_filter = it913x_pid_filter, + .pid_filter_ctrl = it913x_pid_filter_ctrl, + .frontend_attach = it913x_frontend_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 10, + .endpoint = 0x04, + .u = {/* Keep Low if PID filter on */ + .bulk = { + .buffersize = 3584, + + } + } + } + }, + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER| + DVB_USB_ADAP_NEED_PID_FILTERING| + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .streaming_ctrl = it913x_streaming_ctrl, + .pid_filter_count = 31, + .pid_filter = it913x_pid_filter, + .pid_filter_ctrl = it913x_pid_filter_ctrl, + .frontend_attach = it913x_frontend_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x05, + .u = { + .bulk = { + .buffersize = 3584, + + } + } + } + } + }, + .identify_state = it913x_identify_state, + .i2c_algo = &it913x_i2c_algo, + .num_device_descs = 1, + .devices = { + { "Kworld UB499-2T T09(IT9137)", + { &it913x_table[0], NULL }, + }, + + } +}; + +static struct usb_driver it913x_driver = { + .name = "it913x", + .probe = it913x_probe, + .disconnect = dvb_usb_device_exit, + .id_table = it913x_table, +}; + +/* module stuff */ +static int __init it913x_module_init(void) +{ + int result = usb_register(&it913x_driver); + if (result) { + err("usb_register failed. Error number %d", result); + return result; + } + + return 0; +} + +static void __exit it913x_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&it913x_driver); +} + +module_init(it913x_module_init); +module_exit(it913x_module_exit); + +MODULE_AUTHOR("Malcolm Priestley "); +MODULE_DESCRIPTION("it913x USB 2 Driver"); +MODULE_VERSION("1.05"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 3188d5485e8a0650fd877a54ada70581c29cd505 Mon Sep 17 00:00:00 2001 From: Benjamin Larsson Date: Wed, 27 Jul 2011 08:43:38 -0300 Subject: [media] get_dvb_firmware: Firmware extraction for IT9135 based devices Signed-off-by: Benjamin Larsson Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware index c466f58..65ebe20 100755 --- a/Documentation/dvb/get_dvb_firmware +++ b/Documentation/dvb/get_dvb_firmware @@ -27,7 +27,8 @@ use IO::Handle; "or51211", "or51132_qam", "or51132_vsb", "bluebird", "opera1", "cx231xx", "cx18", "cx23885", "pvrusb2", "mpc718", "af9015", "ngene", "az6027", "lme2510_lg", "lme2510c_s7395", - "lme2510c_s7395_old", "drxk", "drxk_terratec_h5"); + "lme2510c_s7395_old", "drxk", "drxk_terratec_h5", + "it9135" ); # Check args syntax() if (scalar(@ARGV) != 1); @@ -665,6 +666,26 @@ sub drxk_terratec_h5 { "$fwfile" } +sub it9135 { + my $url = "http://kworld.server261.com/kworld/CD/ITE_TiVme/V1.00/"; + my $zipfile = "Driver_V10.323.1.0412.100412.zip"; + my $hash = "79b597dc648698ed6820845c0c9d0d37"; + my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 0); + my $drvfile = "Driver_V10.323.1.0412.100412/Data/x86/IT9135BDA.sys"; + my $fwfile = "dvb-usb-it9137-01.fw"; + + checkstandard(); + + wgetfile($zipfile, $url . $zipfile); + verify($zipfile, $hash); + unzip($zipfile, $tmpdir); + extract("$tmpdir/$drvfile", 69632, 5731, "$fwfile"); + + "$fwfile" +} + + + # --------------------------------------------------------------- # Utilities -- cgit v0.10.2 From 93165b7774a04cf76bc46eb6c9181ab7a8b545d7 Mon Sep 17 00:00:00 2001 From: Julian Scheel Date: Thu, 28 Jul 2011 08:04:33 -0300 Subject: [media] Add support for new revision of KNC 1 DVB-C cards. Using tda10024 instead of tda10023, which is compatible to tda10023 driver Signed-off-by: Julian Scheel Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index e957d76..5b28bc6 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -1197,6 +1197,7 @@ static u8 read_pwm(struct budget_av *budget_av) #define SUBID_DVBC_KNC1 0x0020 #define SUBID_DVBC_KNC1_PLUS 0x0021 #define SUBID_DVBC_KNC1_MK3 0x0022 +#define SUBID_DVBC_KNC1_TDA10024 0x0028 #define SUBID_DVBC_KNC1_PLUS_MK3 0x0023 #define SUBID_DVBC_CINERGY1200 0x1156 #define SUBID_DVBC_CINERGY1200_MK3 0x1176 @@ -1316,6 +1317,7 @@ static void frontend_init(struct budget_av *budget_av) case SUBID_DVBC_EASYWATCH_MK3: case SUBID_DVBC_CINERGY1200_MK3: case SUBID_DVBC_KNC1_MK3: + case SUBID_DVBC_KNC1_TDA10024: case SUBID_DVBC_KNC1_PLUS_MK3: budget_av->reinitialise_demod = 1; budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240; @@ -1558,6 +1560,7 @@ MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP); MAKE_BUDGET_INFO(knc1spx4, "KNC1 DVB-S Plus X4", BUDGET_KNC1SP); MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP); MAKE_BUDGET_INFO(knc1cmk3, "KNC1 DVB-C MK3", BUDGET_KNC1C_MK3); +MAKE_BUDGET_INFO(knc1ctda10024, "KNC1 DVB-C TDA10024", BUDGET_KNC1C_TDA10024); MAKE_BUDGET_INFO(knc1cpmk3, "KNC1 DVB-C Plus MK3", BUDGET_KNC1CP_MK3); MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP); MAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S); @@ -1587,6 +1590,7 @@ static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020), MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021), MAKE_EXTENSION_PCI(knc1cmk3, 0x1894, 0x0022), + MAKE_EXTENSION_PCI(knc1ctda10024, 0x1894, 0x0028), MAKE_EXTENSION_PCI(knc1cpmk3, 0x1894, 0x0023), MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030), MAKE_EXTENSION_PCI(knc1tp, 0x1894, 0x0031), diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c index 37666d4..37d02fe 100644 --- a/drivers/media/dvb/ttpci/budget-core.c +++ b/drivers/media/dvb/ttpci/budget-core.c @@ -110,6 +110,7 @@ static int start_ts_capture(struct budget *budget) break; case BUDGET_CIN1200C_MK3: case BUDGET_KNC1C_MK3: + case BUDGET_KNC1C_TDA10024: case BUDGET_KNC1CP_MK3: if (budget->video_port == BUDGET_VIDEO_PORTA) { saa7146_write(dev, DD1_INIT, 0x06000200); @@ -434,6 +435,7 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, case BUDGET_KNC1CP: case BUDGET_CIN1200C: case BUDGET_KNC1C_MK3: + case BUDGET_KNC1C_TDA10024: case BUDGET_KNC1CP_MK3: case BUDGET_CIN1200C_MK3: budget->buffer_width = TS_WIDTH_DVBC; diff --git a/drivers/media/dvb/ttpci/budget.h b/drivers/media/dvb/ttpci/budget.h index 3ad0c67..3d8a806 100644 --- a/drivers/media/dvb/ttpci/budget.h +++ b/drivers/media/dvb/ttpci/budget.h @@ -104,6 +104,7 @@ static struct saa7146_pci_extension_data x_var = { \ #define BUDGET_KNC1C_MK3 16 #define BUDGET_KNC1CP_MK3 17 #define BUDGET_KNC1S2 18 +#define BUDGET_KNC1C_TDA10024 19 #define BUDGET_VIDEO_PORTA 0 #define BUDGET_VIDEO_PORTB 1 -- cgit v0.10.2 From eb28dc39d3e82674584cc768b9757d1cae222a52 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 28 Jul 2011 09:46:02 -0300 Subject: [media] drivers/media/dvb/dvb-usb/usb-urb.c: adjust array index Convert array index from the loop bound to the loop index. A simplified version of the semantic patch that fixes this problem is as // @@ expression e1,e2,ar; @@ for(e1 = 0; e1 < e2; e1++) { <... ar[ - e2 + e1 ] ...> } // Signed-off-by: Julia Lawall Signed-off-by: Andrew Morton Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/usb-urb.c b/drivers/media/dvb/dvb-usb/usb-urb.c index 86d6893..d62ee0f 100644 --- a/drivers/media/dvb/dvb-usb/usb-urb.c +++ b/drivers/media/dvb/dvb-usb/usb-urb.c @@ -148,7 +148,7 @@ static int usb_bulk_urb_init(struct usb_data_stream *stream) if (!stream->urb_list[i]) { deb_mem("not enough memory for urb_alloc_urb!.\n"); for (j = 0; j < i; j++) - usb_free_urb(stream->urb_list[i]); + usb_free_urb(stream->urb_list[j]); return -ENOMEM; } usb_fill_bulk_urb( stream->urb_list[i], stream->udev, @@ -181,7 +181,7 @@ static int usb_isoc_urb_init(struct usb_data_stream *stream) if (!stream->urb_list[i]) { deb_mem("not enough memory for urb_alloc_urb!\n"); for (j = 0; j < i; j++) - usb_free_urb(stream->urb_list[i]); + usb_free_urb(stream->urb_list[j]); return -ENOMEM; } -- cgit v0.10.2 From e36454376a8f4637c0767daa78cf1d96d162d71a Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 28 Jul 2011 18:59:30 -0300 Subject: [media] em28xx: use MFE lock for PCTV nanoStick T2 290e Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index e5916de..47b4cfa 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c @@ -609,7 +609,7 @@ static void unregister_dvb(struct em28xx_dvb *dvb) static int dvb_init(struct em28xx *dev) { - int result = 0; + int result = 0, mfe_shared = 0; struct em28xx_dvb *dvb; if (!dev->board.has_dvb) { @@ -772,6 +772,8 @@ static int dvb_init(struct em28xx *dev) dvb_frontend_detach(dvb->fe[1]); /* leave FE 0 still active */ } + + mfe_shared = 1; } break; case EM2884_BOARD_TERRATEC_H5: @@ -828,6 +830,9 @@ static int dvb_init(struct em28xx *dev) if (result < 0) goto out_free; + /* MFE lock */ + dvb->adapter.mfe_shared = mfe_shared; + em28xx_info("Successfully loaded em28xx-dvb\n"); ret: em28xx_set_mode(dev, EM28XX_SUSPEND); -- cgit v0.10.2 From 4c0cfa24f7e0e4b7d48075fcfe867035a4a2ccdf Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 28 Jul 2011 19:15:38 -0300 Subject: [media] af9015: map remote for Leadtek WinFast DTV2000DS Thanks to Thomas Gutzler for reporting this. Signed-off-by: Antti Palosaari Cc: Thomas Gutzler Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index f966b0b..d70bbe7 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -758,6 +758,8 @@ static const struct af9015_rc_setup af9015_rc_setup_usbids[] = { RC_MAP_MSI_DIGIVOX_III }, { (USB_VID_LEADTEK << 16) + USB_PID_WINFAST_DTV_DONGLE_GOLD, RC_MAP_LEADTEK_Y04G0051 }, + { (USB_VID_LEADTEK << 16) + USB_PID_WINFAST_DTV2000DS, + RC_MAP_LEADTEK_Y04G0051 }, { (USB_VID_AVERMEDIA << 16) + USB_PID_AVERMEDIA_VOLAR_X, RC_MAP_AVERMEDIA_M135A }, { (USB_VID_AFATECH << 16) + USB_PID_TREKSTOR_DVBT, -- cgit v0.10.2 From f68baeff4530593777295f9b94600b4960eddecd Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 28 Jul 2011 19:17:59 -0300 Subject: [media] af9015: use logic or instead of sum numbers Style issue. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index d70bbe7..b816600 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -744,31 +744,31 @@ static const struct af9015_rc_setup af9015_rc_setup_hashes[] = { }; static const struct af9015_rc_setup af9015_rc_setup_usbids[] = { - { (USB_VID_TERRATEC << 16) + USB_PID_TERRATEC_CINERGY_T_STICK_RC, + { (USB_VID_TERRATEC << 16) | USB_PID_TERRATEC_CINERGY_T_STICK_RC, RC_MAP_TERRATEC_SLIM_2 }, - { (USB_VID_TERRATEC << 16) + USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC, + { (USB_VID_TERRATEC << 16) | USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC, RC_MAP_TERRATEC_SLIM }, - { (USB_VID_VISIONPLUS << 16) + USB_PID_AZUREWAVE_AD_TU700, + { (USB_VID_VISIONPLUS << 16) | USB_PID_AZUREWAVE_AD_TU700, RC_MAP_AZUREWAVE_AD_TU700 }, - { (USB_VID_VISIONPLUS << 16) + USB_PID_TINYTWIN, + { (USB_VID_VISIONPLUS << 16) | USB_PID_TINYTWIN, RC_MAP_AZUREWAVE_AD_TU700 }, - { (USB_VID_MSI_2 << 16) + USB_PID_MSI_DIGI_VOX_MINI_III, + { (USB_VID_MSI_2 << 16) | USB_PID_MSI_DIGI_VOX_MINI_III, RC_MAP_MSI_DIGIVOX_III }, - { (USB_VID_MSI_2 << 16) + USB_PID_MSI_DIGIVOX_DUO, + { (USB_VID_MSI_2 << 16) | USB_PID_MSI_DIGIVOX_DUO, RC_MAP_MSI_DIGIVOX_III }, - { (USB_VID_LEADTEK << 16) + USB_PID_WINFAST_DTV_DONGLE_GOLD, + { (USB_VID_LEADTEK << 16) | USB_PID_WINFAST_DTV_DONGLE_GOLD, RC_MAP_LEADTEK_Y04G0051 }, - { (USB_VID_LEADTEK << 16) + USB_PID_WINFAST_DTV2000DS, + { (USB_VID_LEADTEK << 16) | USB_PID_WINFAST_DTV2000DS, RC_MAP_LEADTEK_Y04G0051 }, - { (USB_VID_AVERMEDIA << 16) + USB_PID_AVERMEDIA_VOLAR_X, + { (USB_VID_AVERMEDIA << 16) | USB_PID_AVERMEDIA_VOLAR_X, RC_MAP_AVERMEDIA_M135A }, - { (USB_VID_AFATECH << 16) + USB_PID_TREKSTOR_DVBT, + { (USB_VID_AFATECH << 16) | USB_PID_TREKSTOR_DVBT, RC_MAP_TREKSTOR }, - { (USB_VID_KWORLD_2 << 16) + USB_PID_TINYTWIN_2, + { (USB_VID_KWORLD_2 << 16) | USB_PID_TINYTWIN_2, RC_MAP_DIGITALNOW_TINYTWIN }, - { (USB_VID_GTEK << 16) + USB_PID_TINYTWIN_3, + { (USB_VID_GTEK << 16) | USB_PID_TINYTWIN_3, RC_MAP_DIGITALNOW_TINYTWIN }, - { (USB_VID_KWORLD_2 << 16) + USB_PID_SVEON_STV22, + { (USB_VID_KWORLD_2 << 16) | USB_PID_SVEON_STV22, RC_MAP_MSI_DIGIVOX_III }, { } }; -- cgit v0.10.2 From be85fefecb20b533a2c3f668a345f03f492aeea3 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 31 Jul 2011 01:37:10 -0300 Subject: [media] tda18271: Use printk extension %pV Deduplicate printk formats to save ~20KB text. $ size drivers/media/common/tuners/tda18271*o.* text data bss dec hex filename 10747 56 1920 12723 31b3 drivers/media/common/tuners/tda18271-common.o.new 18889 56 3112 22057 5629 drivers/media/common/tuners/tda18271-common.o.old 20561 204 4264 25029 61c5 drivers/media/common/tuners/tda18271-fe.o.new 31093 204 6000 37297 91b1 drivers/media/common/tuners/tda18271-fe.o.old 3681 6760 440 10881 2a81 drivers/media/common/tuners/tda18271-maps.o.new 5631 6760 680 13071 330f drivers/media/common/tuners/tda18271-maps.o.old Signed-off-by: Joe Perches Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/common/tuners/tda18271-common.c b/drivers/media/common/tuners/tda18271-common.c index aae40e5..39c6457 100644 --- a/drivers/media/common/tuners/tda18271-common.c +++ b/drivers/media/common/tuners/tda18271-common.c @@ -676,10 +676,28 @@ fail: return ret; } -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ +int _tda_printk(struct tda18271_priv *state, const char *level, + const char *func, const char *fmt, ...) +{ + struct va_format vaf; + va_list args; + int rtn; + + va_start(args, fmt); + + vaf.fmt = fmt; + vaf.va = &args; + + if (state) + rtn = printk("%s%s: [%d-%04x|%c] %pV", + level, func, i2c_adapter_id(state->i2c_props.adap), + state->i2c_props.addr, + (state->role == TDA18271_MASTER) ? 'M' : 'S', + &vaf); + else + rtn = printk("%s%s: %pV", level, func, &vaf); + + va_end(args); + + return rtn; +} diff --git a/drivers/media/common/tuners/tda18271-priv.h b/drivers/media/common/tuners/tda18271-priv.h index 9589ab0..94340f4 100644 --- a/drivers/media/common/tuners/tda18271-priv.h +++ b/drivers/media/common/tuners/tda18271-priv.h @@ -136,29 +136,26 @@ extern int tda18271_debug; #define DBG_ADV 8 #define DBG_CAL 16 -#define tda_printk(st, kern, fmt, arg...) do {\ - if (st) { \ - struct tda18271_priv *state = st; \ - printk(kern "%s: [%d-%04x|%s] " fmt, __func__, \ - i2c_adapter_id(state->i2c_props.adap), \ - state->i2c_props.addr, \ - (state->role == TDA18271_MASTER) \ - ? "M" : "S", ##arg); \ - } else \ - printk(kern "%s: " fmt, __func__, ##arg); \ +__attribute__((format(printf, 4, 5))) +int _tda_printk(struct tda18271_priv *state, const char *level, + const char *func, const char *fmt, ...); + +#define tda_printk(st, lvl, fmt, arg...) \ + _tda_printk(st, lvl, __func__, fmt, ##arg) + +#define tda_dprintk(st, lvl, fmt, arg...) \ +do { \ + if (tda18271_debug & lvl) \ + tda_printk(st, KERN_DEBUG, fmt, ##arg); \ } while (0) -#define tda_dprintk(st, lvl, fmt, arg...) do {\ - if (tda18271_debug & lvl) \ - tda_printk(st, KERN_DEBUG, fmt, ##arg); } while (0) - -#define tda_info(fmt, arg...) printk(KERN_INFO fmt, ##arg) -#define tda_warn(fmt, arg...) tda_printk(priv, KERN_WARNING, fmt, ##arg) -#define tda_err(fmt, arg...) tda_printk(priv, KERN_ERR, fmt, ##arg) -#define tda_dbg(fmt, arg...) tda_dprintk(priv, DBG_INFO, fmt, ##arg) -#define tda_map(fmt, arg...) tda_dprintk(priv, DBG_MAP, fmt, ##arg) -#define tda_reg(fmt, arg...) tda_dprintk(priv, DBG_REG, fmt, ##arg) -#define tda_cal(fmt, arg...) tda_dprintk(priv, DBG_CAL, fmt, ##arg) +#define tda_info(fmt, arg...) pr_info(fmt, ##arg) +#define tda_warn(fmt, arg...) tda_printk(priv, KERN_WARNING, fmt, ##arg) +#define tda_err(fmt, arg...) tda_printk(priv, KERN_ERR, fmt, ##arg) +#define tda_dbg(fmt, arg...) tda_dprintk(priv, DBG_INFO, fmt, ##arg) +#define tda_map(fmt, arg...) tda_dprintk(priv, DBG_MAP, fmt, ##arg) +#define tda_reg(fmt, arg...) tda_dprintk(priv, DBG_REG, fmt, ##arg) +#define tda_cal(fmt, arg...) tda_dprintk(priv, DBG_CAL, fmt, ##arg) #define tda_fail(ret) \ ({ \ -- cgit v0.10.2 From 2b50763a0b082e1fc40cca2a9b8936abf6e2437e Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 31 Jul 2011 04:30:10 -0300 Subject: [media] tda18212: Use standard logging, remove tda18212_priv.h Use the more current logging styles with pr_fmt. Remove now unnecessary private include. Signed-off-by: Joe Perches Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/common/tuners/tda18212.c b/drivers/media/common/tuners/tda18212.c index 1f1db20..e29cc2b 100644 --- a/drivers/media/common/tuners/tda18212.c +++ b/drivers/media/common/tuners/tda18212.c @@ -18,7 +18,20 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "tda18212_priv.h" +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include "tda18212.h" + +struct tda18212_priv { + struct tda18212_config *cfg; + struct i2c_adapter *i2c; +}; + +#define dbg(fmt, arg...) \ +do { \ + if (debug) \ + pr_info("%s: " fmt, __func__, ##arg); \ +} while (0) static int debug; module_param(debug, int, 0644); @@ -46,7 +59,8 @@ static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val, if (ret == 1) { ret = 0; } else { - warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len); + pr_warn("i2c wr failed ret:%d reg:%02x len:%d\n", + ret, reg, len); ret = -EREMOTEIO; } return ret; @@ -77,7 +91,8 @@ static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val, memcpy(val, buf, len); ret = 0; } else { - warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len); + pr_warn("i2c rd failed ret:%d reg:%02x len:%d\n", + ret, reg, len); ret = -EREMOTEIO; } @@ -129,8 +144,8 @@ static int tda18212_set_params(struct dvb_frontend *fe, { 0x92, 0x53, 0x03 }, /* DVB-C */ }; - dbg("%s: delsys=%d RF=%d BW=%d", __func__, - c->delivery_system, c->frequency, c->bandwidth_hz); + dbg("delsys=%d RF=%d BW=%d\n", + c->delivery_system, c->frequency, c->bandwidth_hz); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ @@ -196,7 +211,7 @@ exit: return ret; error: - dbg("%s: failed:%d", __func__, ret); + dbg("failed:%d\n", ret); goto exit; } @@ -245,13 +260,13 @@ struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ - dbg("%s: ret:%d chip ID:%02x", __func__, ret, val); + dbg("ret:%d chip ID:%02x\n", ret, val); if (ret || val != 0xc7) { kfree(priv); return NULL; } - info("NXP TDA18212HN successfully identified."); + pr_info("NXP TDA18212HN successfully identified\n"); memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops, sizeof(struct dvb_tuner_ops)); diff --git a/drivers/media/common/tuners/tda18212_priv.h b/drivers/media/common/tuners/tda18212_priv.h deleted file mode 100644 index 9adff93..0000000 --- a/drivers/media/common/tuners/tda18212_priv.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * NXP TDA18212HN silicon tuner driver - * - * Copyright (C) 2011 Antti Palosaari - * - * 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 of the License, 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef TDA18212_PRIV_H -#define TDA18212_PRIV_H - -#include "tda18212.h" - -#define LOG_PREFIX "tda18212" - -#undef dbg -#define dbg(f, arg...) \ - if (debug) \ - printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) -#undef err -#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) -#undef info -#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) -#undef warn -#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) - -struct tda18212_priv { - struct tda18212_config *cfg; - struct i2c_adapter *i2c; -}; - -#endif -- cgit v0.10.2 From 84b271488dcd2499e9d2c7cfa2abacfd4c5cd744 Mon Sep 17 00:00:00 2001 From: "istvan_v@mailbox.hu" Date: Sun, 31 Jul 2011 06:53:29 -0300 Subject: [media] cx88: notch filter control fixes This patch reduces the number of available choices for the notch filter type control so that the standard-specific filter types cannot be selected. It is now limited to being either 0 (4xFsc, the default) or 1 (square pixel optimized). The patch also removes the initialization of this control from cx88_reset(), since that is already done by init_controls(), which is called by cx8800_initdev(). Signed-off-by: Istvan Varga Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index fbcaa1c..fbfdd80 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -636,9 +636,6 @@ int cx88_reset(struct cx88_core *core) cx_write(MO_PCI_INTSTAT, 0xFFFFFFFF); // Clear PCI int cx_write(MO_INT1_STAT, 0xFFFFFFFF); // Clear RISC int - /* set default notch filter */ - cx_andor(MO_HTOTAL, 0x1800, (HLNotchFilter4xFsc << 11)); - /* Reset on-board parts */ cx_write(MO_SRST_IO, 0); msleep(10); diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 60d28fd..921c56d 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -266,7 +266,7 @@ static const struct cx88_ctrl cx8800_ctls[] = { .id = V4L2_CID_BAND_STOP_FILTER, .name = "Notch filter", .minimum = 0, - .maximum = 3, + .maximum = 1, .step = 1, .default_value = 0x0, .type = V4L2_CTRL_TYPE_INTEGER, -- cgit v0.10.2 From c9f88aa976b79a26561fb7754a1e0e00ff7626fe Mon Sep 17 00:00:00 2001 From: Jose Alberto Reguero Date: Mon, 8 Aug 2011 07:35:35 -0300 Subject: [media] ttusb2: add support for the dvb-t part of CT-3650 v3 Signed-off-by: Jose Alberto Reguero Reviewed-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c index c0f5ef5..bda37ce 100644 --- a/drivers/media/dvb/dvb-usb/ttusb2.c +++ b/drivers/media/dvb/dvb-usb/ttusb2.c @@ -30,6 +30,7 @@ #include "tda826x.h" #include "tda10086.h" #include "tda1002x.h" +#include "tda10048.h" #include "tda827x.h" #include "lnbp21.h" @@ -82,7 +83,7 @@ static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num { struct dvb_usb_device *d = i2c_get_adapdata(adap); static u8 obuf[60], ibuf[60]; - int i,read; + int i, write_read, read; if (mutex_lock_interruptible(&d->i2c_mutex) < 0) return -EAGAIN; @@ -91,28 +92,35 @@ static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num warn("more than 2 i2c messages at a time is not handled yet. TODO."); for (i = 0; i < num; i++) { - read = i+1 < num && (msg[i+1].flags & I2C_M_RD); + write_read = i+1 < num && (msg[i+1].flags & I2C_M_RD); + read = msg[i].flags & I2C_M_RD; - obuf[0] = (msg[i].addr << 1) | read; - obuf[1] = msg[i].len; + obuf[0] = (msg[i].addr << 1) | (write_read | read); + if (read) + obuf[1] = 0; + else + obuf[1] = msg[i].len; /* read request */ - if (read) + if (write_read) obuf[2] = msg[i+1].len; + else if (read) + obuf[2] = msg[i].len; else obuf[2] = 0; - memcpy(&obuf[3],msg[i].buf,msg[i].len); + memcpy(&obuf[3], msg[i].buf, msg[i].len); if (ttusb2_msg(d, CMD_I2C_XFER, obuf, msg[i].len+3, ibuf, obuf[2] + 3) < 0) { err("i2c transfer failed."); break; } - if (read) { - memcpy(msg[i+1].buf,&ibuf[3],msg[i+1].len); + if (write_read) { + memcpy(msg[i+1].buf, &ibuf[3], msg[i+1].len); i++; - } + } else if (read) + memcpy(msg[i].buf, &ibuf[3], msg[i].len); } mutex_unlock(&d->i2c_mutex); @@ -190,6 +198,25 @@ static struct tda10023_config tda10023_config = { .deltaf = 0xa511, }; +static struct tda10048_config tda10048_config = { + .demod_address = 0x10 >> 1, + .output_mode = TDA10048_PARALLEL_OUTPUT, + .inversion = TDA10048_INVERSION_ON, + .dtv6_if_freq_khz = TDA10048_IF_4000, + .dtv7_if_freq_khz = TDA10048_IF_4500, + .dtv8_if_freq_khz = TDA10048_IF_5000, + .clk_freq_khz = TDA10048_CLK_16000, + .no_firmware = 1, + .set_pll = true , + .pll_m = 5, + .pll_n = 3, + .pll_p = 0, +}; + +static struct tda827x_config tda827x_config = { + .config = 0, +}; + static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap) { if (usb_set_interface(adap->dev->udev,0,3) < 0) @@ -203,20 +230,56 @@ static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap) return 0; } +static int ttusb2_ct3650_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + + return adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0], enable); +} + static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap) { if (usb_set_interface(adap->dev->udev, 0, 3) < 0) err("set interface to alts=3 failed"); - if ((adap->fe[0] = dvb_attach(tda10023_attach, &tda10023_config, &adap->dev->i2c_adap, 0x48)) == NULL) { - deb_info("TDA10023 attach failed\n"); - return -ENODEV; + + if (adap->fe[0] == NULL) { + /* FE 0 DVB-C */ + adap->fe[0] = dvb_attach(tda10023_attach, + &tda10023_config, &adap->dev->i2c_adap, 0x48); + + if (adap->fe[0] == NULL) { + deb_info("TDA10023 attach failed\n"); + return -ENODEV; + } + } else { + adap->fe[1] = dvb_attach(tda10048_attach, + &tda10048_config, &adap->dev->i2c_adap); + + if (adap->fe[1] == NULL) { + deb_info("TDA10048 attach failed\n"); + return -ENODEV; + } + + /* tuner is behind TDA10023 I2C-gate */ + adap->fe[1]->ops.i2c_gate_ctrl = ttusb2_ct3650_i2c_gate_ctrl; + } + return 0; } static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap) { - if (dvb_attach(tda827x_attach, adap->fe[0], 0x61, &adap->dev->i2c_adap, NULL) == NULL) { + struct dvb_frontend *fe; + + /* MFE: select correct FE to attach tuner since that's called twice */ + if (adap->fe[1] == NULL) + fe = adap->fe[0]; + else + fe = adap->fe[1]; + + /* attach tuner */ + if (dvb_attach(tda827x_attach, fe, 0x61, &adap->dev->i2c_adap, &tda827x_config) == NULL) { printk(KERN_ERR "%s: No tda827x found!\n", __func__); return -ENODEV; } @@ -385,6 +448,7 @@ static struct dvb_usb_device_properties ttusb2_properties_ct3650 = { { .streaming_ctrl = NULL, + .num_frontends = 2, .frontend_attach = ttusb2_frontend_tda10023_attach, .tuner_attach = ttusb2_tuner_tda827x_attach, diff --git a/drivers/media/dvb/frontends/tda10048.c b/drivers/media/dvb/frontends/tda10048.c index 93f6a75..7f10594 100644 --- a/drivers/media/dvb/frontends/tda10048.c +++ b/drivers/media/dvb/frontends/tda10048.c @@ -206,15 +206,16 @@ static struct init_tab { static struct pll_tab { u32 clk_freq_khz; u32 if_freq_khz; - u8 m, n, p; } pll_tab[] = { - { TDA10048_CLK_4000, TDA10048_IF_36130, 10, 0, 0 }, - { TDA10048_CLK_16000, TDA10048_IF_3300, 10, 3, 0 }, - { TDA10048_CLK_16000, TDA10048_IF_3500, 10, 3, 0 }, - { TDA10048_CLK_16000, TDA10048_IF_3800, 10, 3, 0 }, - { TDA10048_CLK_16000, TDA10048_IF_4000, 10, 3, 0 }, - { TDA10048_CLK_16000, TDA10048_IF_4300, 10, 3, 0 }, - { TDA10048_CLK_16000, TDA10048_IF_36130, 10, 3, 0 }, + { TDA10048_CLK_4000, TDA10048_IF_36130 }, + { TDA10048_CLK_16000, TDA10048_IF_3300 }, + { TDA10048_CLK_16000, TDA10048_IF_3500 }, + { TDA10048_CLK_16000, TDA10048_IF_3800 }, + { TDA10048_CLK_16000, TDA10048_IF_4000 }, + { TDA10048_CLK_16000, TDA10048_IF_4300 }, + { TDA10048_CLK_16000, TDA10048_IF_4500 }, + { TDA10048_CLK_16000, TDA10048_IF_5000 }, + { TDA10048_CLK_16000, TDA10048_IF_36130 }, }; static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data) @@ -460,9 +461,6 @@ static int tda10048_set_if(struct dvb_frontend *fe, enum fe_bandwidth bw) state->freq_if_hz = pll_tab[i].if_freq_khz * 1000; state->xtal_hz = pll_tab[i].clk_freq_khz * 1000; - state->pll_mfactor = pll_tab[i].m; - state->pll_nfactor = pll_tab[i].n; - state->pll_pfactor = pll_tab[i].p; break; } } @@ -781,6 +779,10 @@ static int tda10048_init(struct dvb_frontend *fe) dprintk(1, "%s()\n", __func__); + /* PLL */ + init_tab[4].data = (u8)(state->pll_mfactor); + init_tab[5].data = (u8)(state->pll_nfactor) | 0x40; + /* Apply register defaults */ for (i = 0; i < ARRAY_SIZE(init_tab); i++) tda10048_writereg(state, init_tab[i].reg, init_tab[i].data); @@ -1123,7 +1125,7 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config, /* setup the state and clone the config */ memcpy(&state->config, config, sizeof(*config)); state->i2c = i2c; - state->fwloaded = 0; + state->fwloaded = config->no_firmware; state->bandwidth = BANDWIDTH_8_MHZ; /* check if the demod is present */ @@ -1135,6 +1137,17 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; + /* set pll */ + if (config->set_pll) { + state->pll_mfactor = config->pll_m; + state->pll_nfactor = config->pll_n; + state->pll_pfactor = config->pll_p; + } else { + state->pll_mfactor = 10; + state->pll_nfactor = 3; + state->pll_pfactor = 0; + } + /* Establish any defaults the the user didn't pass */ tda10048_establish_defaults(&state->frontend); diff --git a/drivers/media/dvb/frontends/tda10048.h b/drivers/media/dvb/frontends/tda10048.h index 8828cea..fb2ef5a 100644 --- a/drivers/media/dvb/frontends/tda10048.h +++ b/drivers/media/dvb/frontends/tda10048.h @@ -51,6 +51,7 @@ struct tda10048_config { #define TDA10048_IF_4300 4300 #define TDA10048_IF_4500 4500 #define TDA10048_IF_4750 4750 +#define TDA10048_IF_5000 5000 #define TDA10048_IF_36130 36130 u16 dtv6_if_freq_khz; u16 dtv7_if_freq_khz; @@ -62,6 +63,13 @@ struct tda10048_config { /* Disable I2C gate access */ u8 disable_gate_access; + + bool no_firmware; + + bool set_pll; + u8 pll_m; + u8 pll_p; + u8 pll_n; }; #if defined(CONFIG_DVB_TDA10048) || \ -- cgit v0.10.2 From eab00a0da292fa7118aaf20da78e834866de00ae Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 18 Jul 2011 08:40:03 -0300 Subject: [media] v4l: events: Define V4L2_EVENT_FRAME_SYNC Define a frame sync event to tell user space when the reception of a frame starts. Signed-off-by: Sakari Ailus Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml index 5200b68..e8714aa 100644 --- a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml +++ b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml @@ -88,6 +88,12 @@ + &v4l2-event-frame-sync; + frame + Event data for event V4L2_EVENT_FRAME_SYNC. + + + __u8 data[64] Event data. Defined by the event type. The union @@ -220,6 +226,22 @@ + + struct <structname>v4l2_event_frame_sync</structname> + + &cs-str; + + + __u32 + frame_sequence + + The sequence number of the frame being received. + + + + +
+ Changes diff --git a/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml index 275be96..5c70b61 100644 --- a/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml +++ b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml @@ -139,6 +139,22 @@ + V4L2_EVENT_FRAME_SYNC + 4 + + Triggered immediately when the reception of a + frame has begun. This event has a + &v4l2-event-frame-sync; associated with it. + + If the hardware needs to be stopped in the case of a + buffer underrun it might not be able to generate this event. + In such cases the frame_sequence + field in &v4l2-event-frame-sync; will not be incremented. This + causes two consecutive frame sequence numbers to have n times + frame interval in between them. + + + V4L2_EVENT_PRIVATE_START 0x08000000 Base event number for driver-private events. diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index fca24cc..a5359c6 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -2006,6 +2006,7 @@ struct v4l2_streamparm { #define V4L2_EVENT_VSYNC 1 #define V4L2_EVENT_EOS 2 #define V4L2_EVENT_CTRL 3 +#define V4L2_EVENT_FRAME_SYNC 4 #define V4L2_EVENT_PRIVATE_START 0x08000000 /* Payload for V4L2_EVENT_VSYNC */ @@ -2032,12 +2033,17 @@ struct v4l2_event_ctrl { __s32 default_value; }; +struct v4l2_event_frame_sync { + __u32 frame_sequence; +}; + struct v4l2_event { __u32 type; union { - struct v4l2_event_vsync vsync; - struct v4l2_event_ctrl ctrl; - __u8 data[64]; + struct v4l2_event_vsync vsync; + struct v4l2_event_ctrl ctrl; + struct v4l2_event_frame_sync frame_sync; + __u8 data[64]; } u; __u32 pending; __u32 sequence; -- cgit v0.10.2 From 69d232ae8e95a229e7544989d6014e875deeb121 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 15 Jun 2011 15:58:48 -0300 Subject: [media] omap3isp: ccdc: Use generic frame sync event instead of private HS_VS event The ccdc block in the omap3isp produces events whenever it starts receiving a new frame. A private HS_VS event was used for this previously. Now, the generic V4L2_EVENT_FRAME_SYNC event is being used for the purpose. This patch also provides the frame sequence number to user space. Signed-off-by: Sakari Ailus Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/video4linux/omap3isp.txt b/Documentation/video4linux/omap3isp.txt index 69be2c7..5dd1439 100644 --- a/Documentation/video4linux/omap3isp.txt +++ b/Documentation/video4linux/omap3isp.txt @@ -70,10 +70,11 @@ Events The OMAP 3 ISP driver does support the V4L2 event interface on CCDC and statistics (AEWB, AF and histogram) subdevs. -The CCDC subdev produces V4L2_EVENT_OMAP3ISP_HS_VS type event on HS_VS -interrupt which is used to signal frame start. The event is triggered exactly -when the reception of the first line of the frame starts in the CCDC module. -The event can be subscribed on the CCDC subdev. +The CCDC subdev produces V4L2_EVENT_FRAME_SYNC type event on HS_VS +interrupt which is used to signal frame start. Earlier version of this +driver used V4L2_EVENT_OMAP3ISP_HS_VS for this purpose. The event is +triggered exactly when the reception of the first line of the frame starts +in the CCDC module. The event can be subscribed on the CCDC subdev. (When using parallel interface one must pay account to correct configuration of the VS signal polarity. This is automatically correct when using the serial diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index 9d3459d..40b141c 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c @@ -1404,11 +1404,14 @@ static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event) static void ccdc_hs_vs_isr(struct isp_ccdc_device *ccdc) { + struct isp_pipeline *pipe = + to_isp_pipeline(&ccdc->video_out.video.entity); struct video_device *vdev = &ccdc->subdev.devnode; struct v4l2_event event; memset(&event, 0, sizeof(event)); - event.type = V4L2_EVENT_OMAP3ISP_HS_VS; + event.type = V4L2_EVENT_FRAME_SYNC; + event.u.frame_sync.frame_sequence = atomic_read(&pipe->frame_number); v4l2_event_queue(vdev, &event); } @@ -1690,7 +1693,11 @@ static long ccdc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) static int ccdc_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, struct v4l2_event_subscription *sub) { - if (sub->type != V4L2_EVENT_OMAP3ISP_HS_VS) + if (sub->type != V4L2_EVENT_FRAME_SYNC) + return -EINVAL; + + /* line number is zero at frame start */ + if (sub->id != 0) return -EINVAL; return v4l2_event_subscribe(fh, sub, OMAP3ISP_CCDC_NEVENTS); diff --git a/include/linux/omap3isp.h b/include/linux/omap3isp.h index b6111f8..c73a34c 100644 --- a/include/linux/omap3isp.h +++ b/include/linux/omap3isp.h @@ -62,14 +62,12 @@ * V4L2_EVENT_OMAP3ISP_AEWB: AEWB statistics data ready * V4L2_EVENT_OMAP3ISP_AF: AF statistics data ready * V4L2_EVENT_OMAP3ISP_HIST: Histogram statistics data ready - * V4L2_EVENT_OMAP3ISP_HS_VS: Horizontal/vertical synchronization detected */ #define V4L2_EVENT_OMAP3ISP_CLASS (V4L2_EVENT_PRIVATE_START | 0x100) #define V4L2_EVENT_OMAP3ISP_AEWB (V4L2_EVENT_OMAP3ISP_CLASS | 0x1) #define V4L2_EVENT_OMAP3ISP_AF (V4L2_EVENT_OMAP3ISP_CLASS | 0x2) #define V4L2_EVENT_OMAP3ISP_HIST (V4L2_EVENT_OMAP3ISP_CLASS | 0x3) -#define V4L2_EVENT_OMAP3ISP_HS_VS (V4L2_EVENT_OMAP3ISP_CLASS | 0x4) struct omap3isp_stat_event_status { __u32 frame_number; -- cgit v0.10.2 From 4d37ece757a83c2858de9e40b9fa3da511f9ce38 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 4 Aug 2011 04:13:59 -0300 Subject: [media] tuner/xc2028: Add I2C flush callback When loading the firmware, complete each chunk by sending an I2C flush command to the frontend. Some devices like the tm6000 seem to require this to properly flush the I2C buffers. The current code in tm6000 executes the flush command once after each I2C transfer, which slows down the firmware loading especially when loading large BASE type images. Signed-off-by: Thierry Reding Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/common/tuners/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c index 16fba6b..b6b2868 100644 --- a/drivers/media/common/tuners/tuner-xc2028.c +++ b/drivers/media/common/tuners/tuner-xc2028.c @@ -614,6 +614,13 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, p += len; size -= len; } + + /* silently fail if the frontend doesn't support I2C flush */ + rc = do_tuner_callback(fe, XC2028_I2C_FLUSH, 0); + if ((rc < 0) && (rc != -EINVAL)) { + tuner_err("error executing flush: %d\n", rc); + return rc; + } } return 0; } diff --git a/drivers/media/common/tuners/tuner-xc2028.h b/drivers/media/common/tuners/tuner-xc2028.h index 9778c96..9ebfb2d 100644 --- a/drivers/media/common/tuners/tuner-xc2028.h +++ b/drivers/media/common/tuners/tuner-xc2028.h @@ -54,6 +54,7 @@ struct xc2028_config { /* xc2028 commands for callback */ #define XC2028_TUNER_RESET 0 #define XC2028_RESET_CLK 1 +#define XC2028_I2C_FLUSH 2 #if defined(CONFIG_MEDIA_TUNER_XC2028) || (defined(CONFIG_MEDIA_TUNER_XC2028_MODULE) && defined(MODULE)) extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, -- cgit v0.10.2 From fd34cb08babcd898c6b0e30cd7d507ffa62685a1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 31 Aug 2011 15:12:45 -0300 Subject: [media] tuner/xc2028: Fix frequency offset for radio mode In radio mode, no frequency offset should be used. Instead of taking Thierry's patch that creates a separate function to calculate the digital offset, it seemed better to just keep everything at the same place. Reported-by: Thierry Reding Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/common/tuners/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c index b6b2868..3acbaa0 100644 --- a/drivers/media/common/tuners/tuner-xc2028.c +++ b/drivers/media/common/tuners/tuner-xc2028.c @@ -940,11 +940,16 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, * that xc2028 will be in a safe state. * Maybe this might also be needed for DTV. */ - if (new_type == V4L2_TUNER_ANALOG_TV) { + switch (new_type) { + case V4L2_TUNER_ANALOG_TV: rc = send_seq(priv, {0x00, 0x00}); - /* Analog modes require offset = 0 */ - } else { + /* Analog mode requires offset = 0 */ + break; + case V4L2_TUNER_RADIO: + /* Radio mode requires offset = 0 */ + break; + case V4L2_TUNER_DIGITAL_TV: /* * Digital modes require an offset to adjust to the * proper frequency. The offset depends on what -- cgit v0.10.2 From 3d1a51db7e908cd7b3440ecb4cbf00f15a8f33bf Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 4 Aug 2011 04:14:01 -0300 Subject: [media] tm6000: Miscellaneous cleanups This commit fixes a number of coding style issues as well as some issues reported by checkpatch and sparse. Signed-off-by: Thierry Reding Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/tm6000/tm6000-alsa.c b/drivers/staging/tm6000/tm6000-alsa.c index bd5fa89..8388243 100644 --- a/drivers/staging/tm6000/tm6000-alsa.c +++ b/drivers/staging/tm6000/tm6000-alsa.c @@ -397,7 +397,7 @@ static struct snd_pcm_ops snd_tm6000_pcm_ops = { /* * Alsa Constructor - Component probe */ -int tm6000_audio_init(struct tm6000_core *dev) +static int tm6000_audio_init(struct tm6000_core *dev) { struct snd_card *card; struct snd_tm6000_card *chip; @@ -490,7 +490,7 @@ static int tm6000_audio_fini(struct tm6000_core *dev) return 0; } -struct tm6000_ops audio_ops = { +static struct tm6000_ops audio_ops = { .type = TM6000_AUDIO, .name = "TM6000 Audio Extension", .init = tm6000_audio_init, diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c index 9227db5..7dbc500 100644 --- a/drivers/staging/tm6000/tm6000-cards.c +++ b/drivers/staging/tm6000/tm6000-cards.c @@ -87,7 +87,7 @@ struct tm6000_board { char *ir_codes; }; -struct tm6000_board tm6000_boards[] = { +static struct tm6000_board tm6000_boards[] = { [TM6000_BOARD_UNKNOWN] = { .name = "Unknown tm6000 video grabber", .caps = { @@ -394,7 +394,7 @@ struct tm6000_board tm6000_boards[] = { .has_zl10353 = 1, .has_eeprom = 1, .has_remote = 1, - .has_radio = 1. + .has_radio = 1, }, .gpio = { .tuner_reset = TM6010_GPIO_0, @@ -611,7 +611,7 @@ struct tm6000_board tm6000_boards[] = { }; /* table of devices that work with this driver */ -struct usb_device_id tm6000_id_table[] = { +static struct usb_device_id tm6000_id_table[] = { { USB_DEVICE(0x6000, 0x0001), .driver_info = TM5600_BOARD_GENERIC }, { USB_DEVICE(0x6000, 0x0002), .driver_info = TM6010_BOARD_GENERIC }, { USB_DEVICE(0x06e1, 0xf332), .driver_info = TM6000_BOARD_ADSTECH_DUAL_TV }, @@ -632,7 +632,7 @@ struct usb_device_id tm6000_id_table[] = { { USB_DEVICE(0x13d3, 0x3264), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, { USB_DEVICE(0x6000, 0xdec2), .driver_info = TM6010_BOARD_BEHOLD_WANDER_LITE }, { USB_DEVICE(0x6000, 0xdec3), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER_LITE }, - { }, + { } }; /* Control power led for show some activity */ @@ -787,8 +787,6 @@ EXPORT_SYMBOL_GPL(tm6000_tuner_callback); int tm6000_cards_setup(struct tm6000_core *dev) { - int i, rc; - /* * Board-specific initialization sequence. Handles all GPIO * initialization sequences that are board-specific. @@ -860,6 +858,9 @@ int tm6000_cards_setup(struct tm6000_core *dev) */ if (dev->gpio.tuner_reset) { + int rc; + int i; + for (i = 0; i < 2; i++) { rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.tuner_reset, 0x00); @@ -1168,7 +1169,7 @@ static int tm6000_usb_probe(struct usb_interface *interface, snprintf(dev->name, 29, "tm6000 #%d", nr); dev->model = id->driver_info; - if ((card[nr] >= 0) && (card[nr] < ARRAY_SIZE(tm6000_boards))) + if (card[nr] < ARRAY_SIZE(tm6000_boards)) dev->model = card[nr]; dev->udev = usbdev; @@ -1189,8 +1190,6 @@ static int tm6000_usb_probe(struct usb_interface *interface, speed = "unknown"; } - - /* Get endpoints */ for (i = 0; i < interface->num_altsetting; i++) { int ep; @@ -1274,7 +1273,6 @@ static int tm6000_usb_probe(struct usb_interface *interface, printk(KERN_INFO "tm6000: Found %s\n", tm6000_boards[dev->model].name); rc = tm6000_init_dev(dev); - if (rc < 0) goto err; diff --git a/drivers/staging/tm6000/tm6000-core.c b/drivers/staging/tm6000/tm6000-core.c index d7eb2e2..e14bd3d 100644 --- a/drivers/staging/tm6000/tm6000-core.c +++ b/drivers/staging/tm6000/tm6000-core.c @@ -42,7 +42,6 @@ int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req, if (len) data = kzalloc(len, GFP_KERNEL); - if (req_type & USB_DIR_IN) pipe = usb_rcvctrlpipe(dev->udev, 0); else { @@ -62,7 +61,7 @@ int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req, printk(">>> "); for (i = 0; i < len; i++) printk(" %02x", buf[i]); - printk("\n"); + printk("\n"); } } @@ -308,7 +307,7 @@ int tm6000_init_analog_mode(struct tm6000_core *dev) * FIXME: This is a hack! xc3028 "sleeps" when no channel is detected * for more than a few seconds. Not sure why, as this behavior does * not happen on other devices with xc3028. So, I suspect that it - * is yet another bug at tm6000. After start sleeping, decoding + * is yet another bug at tm6000. After start sleeping, decoding * doesn't start automatically. Instead, it requires some * I2C commands to wake it up. As we want to have image at the * beginning, we needed to add this hack. The better would be to @@ -390,7 +389,7 @@ struct reg_init { }; /* The meaning of those initializations are unknown */ -struct reg_init tm6000_init_tab[] = { +static struct reg_init tm6000_init_tab[] = { /* REG VALUE */ { TM6000_REQ07_RDF_PWDOWN_ACLK, 0x1f }, { TM6010_REQ07_RFF_SOFT_RESET, 0x08 }, @@ -458,7 +457,7 @@ struct reg_init tm6000_init_tab[] = { { TM6010_REQ05_R18_IMASK7, 0x00 }, }; -struct reg_init tm6010_init_tab[] = { +static struct reg_init tm6010_init_tab[] = { { TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x00 }, { TM6010_REQ07_RC4_HSTART0, 0xa0 }, { TM6010_REQ07_RC6_HEND0, 0x40 }, @@ -687,7 +686,7 @@ int tm6000_set_audio_rinput(struct tm6000_core *dev) return 0; } -void tm6010_set_mute_sif(struct tm6000_core *dev, u8 mute) +static void tm6010_set_mute_sif(struct tm6000_core *dev, u8 mute) { u8 mute_reg = 0; @@ -697,7 +696,7 @@ void tm6010_set_mute_sif(struct tm6000_core *dev, u8 mute) tm6000_set_reg_mask(dev, TM6010_REQ08_R0A_A_I2S_MOD, mute_reg, 0x08); } -void tm6010_set_mute_adc(struct tm6000_core *dev, u8 mute) +static void tm6010_set_mute_adc(struct tm6000_core *dev, u8 mute) { u8 mute_reg = 0; @@ -749,7 +748,7 @@ int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute) return 0; } -void tm6010_set_volume_sif(struct tm6000_core *dev, int vol) +static void tm6010_set_volume_sif(struct tm6000_core *dev, int vol) { u8 vol_reg; @@ -762,7 +761,7 @@ void tm6010_set_volume_sif(struct tm6000_core *dev, int vol) tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, vol_reg); } -void tm6010_set_volume_adc(struct tm6000_core *dev, int vol) +static void tm6010_set_volume_adc(struct tm6000_core *dev, int vol) { u8 vol_reg; diff --git a/drivers/staging/tm6000/tm6000-dvb.c b/drivers/staging/tm6000/tm6000-dvb.c index 0e0dfce..8f2a50b 100644 --- a/drivers/staging/tm6000/tm6000-dvb.c +++ b/drivers/staging/tm6000/tm6000-dvb.c @@ -105,7 +105,7 @@ static void tm6000_urb_received(struct urb *urb) } } -int tm6000_start_stream(struct tm6000_core *dev) +static int tm6000_start_stream(struct tm6000_core *dev) { int ret; unsigned int pipe, size; @@ -166,7 +166,7 @@ int tm6000_start_stream(struct tm6000_core *dev) return 0; } -void tm6000_stop_stream(struct tm6000_core *dev) +static void tm6000_stop_stream(struct tm6000_core *dev) { struct tm6000_dvb *dvb = dev->dvb; @@ -180,7 +180,7 @@ void tm6000_stop_stream(struct tm6000_core *dev) } } -int tm6000_start_feed(struct dvb_demux_feed *feed) +static int tm6000_start_feed(struct dvb_demux_feed *feed) { struct dvb_demux *demux = feed->demux; struct tm6000_core *dev = demux->priv; @@ -199,7 +199,7 @@ int tm6000_start_feed(struct dvb_demux_feed *feed) return 0; } -int tm6000_stop_feed(struct dvb_demux_feed *feed) +static int tm6000_stop_feed(struct dvb_demux_feed *feed) { struct dvb_demux *demux = feed->demux; struct tm6000_core *dev = demux->priv; @@ -222,7 +222,7 @@ int tm6000_stop_feed(struct dvb_demux_feed *feed) return 0; } -int tm6000_dvb_attach_frontend(struct tm6000_core *dev) +static int tm6000_dvb_attach_frontend(struct tm6000_core *dev) { struct tm6000_dvb *dvb = dev->dvb; @@ -247,7 +247,7 @@ int tm6000_dvb_attach_frontend(struct tm6000_core *dev) DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -int register_dvb(struct tm6000_core *dev) +static int register_dvb(struct tm6000_core *dev) { int ret = -1; struct tm6000_dvb *dvb = dev->dvb; @@ -359,7 +359,7 @@ err: return ret; } -void unregister_dvb(struct tm6000_core *dev) +static void unregister_dvb(struct tm6000_core *dev) { struct tm6000_dvb *dvb = dev->dvb; diff --git a/drivers/staging/tm6000/tm6000-input.c b/drivers/staging/tm6000/tm6000-input.c index 70a2c5f..405d127 100644 --- a/drivers/staging/tm6000/tm6000-input.c +++ b/drivers/staging/tm6000/tm6000-input.c @@ -284,7 +284,7 @@ static void tm6000_ir_stop(struct rc_dev *rc) cancel_delayed_work_sync(&ir->work); } -int tm6000_ir_change_protocol(struct rc_dev *rc, u64 rc_type) +static int tm6000_ir_change_protocol(struct rc_dev *rc, u64 rc_type) { struct tm6000_IR *ir = rc->priv; diff --git a/drivers/staging/tm6000/tm6000-stds.c b/drivers/staging/tm6000/tm6000-stds.c index 8b29d73..bebf1f3 100644 --- a/drivers/staging/tm6000/tm6000-stds.c +++ b/drivers/staging/tm6000/tm6000-stds.c @@ -22,7 +22,7 @@ #include "tm6000.h" #include "tm6000-regs.h" -static unsigned int tm6010_a_mode = 0; +static unsigned int tm6010_a_mode; module_param(tm6010_a_mode, int, 0644); MODULE_PARM_DESC(tm6010_a_mode, "set tm6010 sif audio mode"); @@ -674,6 +674,5 @@ ret: msleep(40); - return 0; } diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c index 8d8b939..ba9cd24 100644 --- a/drivers/staging/tm6000/tm6000-video.c +++ b/drivers/staging/tm6000/tm6000-video.c @@ -19,6 +19,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include #include #include @@ -202,17 +203,6 @@ static inline void buffer_filled(struct tm6000_core *dev, wake_up(&buf->vb.done); } -const char *tm6000_msg_type[] = { - "unknown(0)", /* 0 */ - "video", /* 1 */ - "audio", /* 2 */ - "vbi", /* 3 */ - "pts", /* 4 */ - "err", /* 5 */ - "unknown(6)", /* 6 */ - "unknown(7)", /* 7 */ -}; - /* * Identify the tm5600/6000 buffer header type and properly handles */ @@ -286,17 +276,18 @@ static int copy_streams(u8 *data, unsigned long len, if (size > TM6000_URB_MSG_LEN) size = TM6000_URB_MSG_LEN; pktsize = TM6000_URB_MSG_LEN; - /* calculate position in buffer - * and change the buffer + /* + * calculate position in buffer and change the buffer */ switch (cmd) { case TM6000_URB_MSG_VIDEO: if (!dev->radio) { if ((dev->isoc_ctl.vfield != field) && (field == 1)) { - /* Announces that a new buffer - * were filled - */ + /* + * Announces that a new buffer + * were filled + */ buffer_filled(dev, dma_q, vbuf); dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n"); @@ -321,7 +312,7 @@ static int copy_streams(u8 *data, unsigned long len, break; case TM6000_URB_MSG_AUDIO: case TM6000_URB_MSG_PTS: - size = pktsize; /* Size is always 180 bytes */ + size = pktsize; /* Size is always 180 bytes */ break; } } else { @@ -363,7 +354,8 @@ static int copy_streams(u8 *data, unsigned long len, } } if (ptr + pktsize > endp) { - /* End of URB packet, but cmd processing is not + /* + * End of URB packet, but cmd processing is not * complete. Preserve the state for a next packet */ dev->isoc_ctl.pos = pos + cpysize; @@ -1035,8 +1027,8 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; + struct tm6000_fh *fh = priv; + struct tm6000_core *dev = fh->dev; if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -1050,11 +1042,12 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; + struct tm6000_fh *fh = priv; + struct tm6000_core *dev = fh->dev; if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; + if (i != fh->type) return -EINVAL; @@ -1067,7 +1060,7 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) { int rc = 0; - struct tm6000_fh *fh = priv; + struct tm6000_fh *fh = priv; struct tm6000_core *dev = fh->dev; dev->norm = *norm; @@ -1464,9 +1457,6 @@ static int tm6000_open(struct file *file) int i, rc; int radio = 0; - printk(KERN_INFO "tm6000: open called (dev=%s)\n", - video_device_node_name(vdev)); - dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: open called (dev=%s)\n", video_device_node_name(vdev)); @@ -1507,12 +1497,13 @@ static int tm6000_open(struct file *file) tm6000_get_std_res(dev); - fh->width = dev->width; - fh->height = dev->height; + fh->width = dev->width; + fh->height = dev->height; dprintk(dev, V4L2_DEBUG_OPEN, "Open: fh=0x%08lx, dev=0x%08lx, " "dev->vidq=0x%08lx\n", - (unsigned long)fh, (unsigned long)dev, (unsigned long)&dev->vidq); + (unsigned long)fh, (unsigned long)dev, + (unsigned long)&dev->vidq); dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty " "queued=%d\n", list_empty(&dev->vidq.queued)); dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty " @@ -1583,8 +1574,7 @@ tm6000_poll(struct file *file, struct poll_table_struct *wait) buf = list_entry(fh->vb_vidq.stream.next, struct tm6000_buffer, vb.stream); } else { /* read() capture */ - return videobuf_poll_stream(file, &fh->vb_vidq, - wait); + return videobuf_poll_stream(file, &fh->vb_vidq, wait); } poll_wait(file, &buf->vb.done, wait); if (buf->vb.state == VIDEOBUF_DONE || @@ -1617,22 +1607,19 @@ static int tm6000_release(struct file *file) static int tm6000_mmap(struct file *file, struct vm_area_struct * vma) { - struct tm6000_fh *fh = file->private_data; - int ret; - - ret = videobuf_mmap_mapper(&fh->vb_vidq, vma); + struct tm6000_fh *fh = file->private_data; - return ret; + return videobuf_mmap_mapper(&fh->vb_vidq, vma); } static struct v4l2_file_operations tm6000_fops = { - .owner = THIS_MODULE, - .open = tm6000_open, - .release = tm6000_release, - .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ - .read = tm6000_read, - .poll = tm6000_poll, - .mmap = tm6000_mmap, + .owner = THIS_MODULE, + .open = tm6000_open, + .release = tm6000_release, + .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ + .read = tm6000_read, + .poll = tm6000_poll, + .mmap = tm6000_mmap, }; static const struct v4l2_ioctl_ops video_ioctl_ops = { @@ -1693,7 +1680,7 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = { .vidioc_s_frequency = vidioc_s_frequency, }; -struct video_device tm6000_radio_template = { +static struct video_device tm6000_radio_template = { .name = "tm6000", .fops = &radio_fops, .ioctl_ops = &radio_ioctl_ops, diff --git a/drivers/staging/tm6000/tm6000.h b/drivers/staging/tm6000/tm6000.h index c56da62..4323fc2 100644 --- a/drivers/staging/tm6000/tm6000.h +++ b/drivers/staging/tm6000/tm6000.h @@ -20,9 +20,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* Use the tm6000-hack, instead of the proper initialization code i*/ -/* #define HACK 1 */ - #include #include #include @@ -30,7 +27,7 @@ #include #include #include -#include + #include #include "dvb_demux.h" #include "dvb_frontend.h" -- cgit v0.10.2 From 3fd02b4456179544d93d7b64c3362d47d6050ec7 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 4 Aug 2011 04:14:02 -0300 Subject: [media] tm6000: Use correct input in radio mode In radio mode, the correct input is rinput. The pseudo index 5 is used but cannot be used to index the vinput array because that only has 3 elements. Signed-off-by: Thierry Reding Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/tm6000/tm6000-stds.c b/drivers/staging/tm6000/tm6000-stds.c index bebf1f3..cd69626 100644 --- a/drivers/staging/tm6000/tm6000-stds.c +++ b/drivers/staging/tm6000/tm6000-stds.c @@ -525,6 +525,7 @@ static int tm6000_load_std(struct tm6000_core *dev, int tm6000_set_standard(struct tm6000_core *dev) { + struct tm6000_input *input; int i, rc = 0; u8 reg_07_fe = 0x8a; u8 reg_08_f1 = 0xfc; @@ -533,12 +534,13 @@ int tm6000_set_standard(struct tm6000_core *dev) tm6000_get_std_res(dev); - if (dev->radio) { - /* todo */ - } + if (!dev->radio) + input = &dev->vinput[dev->input]; + else + input = &dev->rinput; if (dev->dev_type == TM6010) { - switch (dev->vinput[dev->input].vmux) { + switch (input->vmux) { case TM6000_VMUX_VIDEO_A: tm6000_set_reg(dev, TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4); tm6000_set_reg(dev, TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1); @@ -567,7 +569,7 @@ int tm6000_set_standard(struct tm6000_core *dev) default: break; } - switch (dev->vinput[dev->input].amux) { + switch (input->amux) { case TM6000_AMUX_ADC1: tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x00, 0x0f); @@ -602,32 +604,32 @@ int tm6000_set_standard(struct tm6000_core *dev) tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, reg_08_f1); tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, reg_07_fe); } else { - switch (dev->vinput[dev->input].vmux) { + switch (input->vmux) { case TM6000_VMUX_VIDEO_A: tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10); tm6000_set_reg(dev, TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00); tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x0f); tm6000_set_reg(dev, - REQ_03_SET_GET_MCU_PIN, dev->vinput[dev->input].v_gpio, 0); + REQ_03_SET_GET_MCU_PIN, input->v_gpio, 0); break; case TM6000_VMUX_VIDEO_B: tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x00); tm6000_set_reg(dev, TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00); tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x0f); tm6000_set_reg(dev, - REQ_03_SET_GET_MCU_PIN, dev->vinput[dev->input].v_gpio, 0); + REQ_03_SET_GET_MCU_PIN, input->v_gpio, 0); break; case TM6000_VMUX_VIDEO_AB: tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10); tm6000_set_reg(dev, TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x10); tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x00); tm6000_set_reg(dev, - REQ_03_SET_GET_MCU_PIN, dev->vinput[dev->input].v_gpio, 1); + REQ_03_SET_GET_MCU_PIN, input->v_gpio, 1); break; default: break; } - switch (dev->vinput[dev->input].amux) { + switch (input->amux) { case TM6000_AMUX_ADC1: tm6000_set_reg_mask(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0x00, 0x0f); @@ -640,7 +642,7 @@ int tm6000_set_standard(struct tm6000_core *dev) break; } } - if (dev->vinput[dev->input].type == TM6000_INPUT_SVIDEO) { + if (input->type == TM6000_INPUT_SVIDEO) { for (i = 0; i < ARRAY_SIZE(svideo_stds); i++) { if (dev->norm & svideo_stds[i].id) { rc = tm6000_load_std(dev, svideo_stds[i].common, @@ -668,8 +670,8 @@ ret: return rc; if ((dev->dev_type == TM6010) && - ((dev->vinput[dev->input].amux == TM6000_AMUX_SIF1) || - (dev->vinput[dev->input].amux == TM6000_AMUX_SIF2))) + ((input->amux == TM6000_AMUX_SIF1) || + (input->amux == TM6000_AMUX_SIF2))) tm6000_set_audio_std(dev); msleep(40); -- cgit v0.10.2 From 9dac920708abb2981d02e6922fd797ef388db5ce Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 4 Aug 2011 04:14:03 -0300 Subject: [media] tm6000: Implement I2C flush callback Signed-off-by: Thierry Reding Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c index 7dbc500..bac4309 100644 --- a/drivers/staging/tm6000/tm6000-cards.c +++ b/drivers/staging/tm6000/tm6000-cards.c @@ -780,6 +780,11 @@ int tm6000_tuner_callback(void *ptr, int component, int command, int arg) rc = tm6000_i2c_reset(dev, 100); break; } + break; + case XC2028_I2C_FLUSH: + tm6000_set_reg(dev, REQ_50_SET_START, 0, 0); + tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0); + break; } return rc; } diff --git a/drivers/staging/tm6000/tm6000-i2c.c b/drivers/staging/tm6000/tm6000-i2c.c index 5a651ea..76a8e3a 100644 --- a/drivers/staging/tm6000/tm6000-i2c.c +++ b/drivers/staging/tm6000/tm6000-i2c.c @@ -219,11 +219,6 @@ static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap, printk(" %02x", msgs[i].buf[byte]); rc = tm6000_i2c_send_regs(dev, addr, msgs[i].buf[0], msgs[i].buf + 1, msgs[i].len - 1); - - if (addr == dev->tuner_addr << 1) { - tm6000_set_reg(dev, REQ_50_SET_START, 0, 0); - tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0); - } } if (i2c_debug >= 2) printk("\n"); -- cgit v0.10.2 From 14f0915464f91574652afa95850e642abd205adc Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 4 Aug 2011 04:14:06 -0300 Subject: [media] tm6000: Flesh out the IRQ callback This brings the IRQ callback implementation more in line with how other drivers do it. Signed-off-by: Thierry Reding Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c index ba9cd24..bef6023 100644 --- a/drivers/staging/tm6000/tm6000-video.c +++ b/drivers/staging/tm6000/tm6000-video.c @@ -513,9 +513,21 @@ static void tm6000_irq_callback(struct urb *urb) struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq); int i; - if (!dev) + switch (urb->status) { + case 0: + case -ETIMEDOUT: + break; + + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: return; + default: + tm6000_err("urb completion error %d.\n", urb->status); + break; + } + spin_lock(&dev->slock); tm6000_isoc_copy(urb); spin_unlock(&dev->slock); -- cgit v0.10.2 From 4129e560fb92a9b2e90e1b80ee6ea8b416724e80 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 4 Aug 2011 04:14:07 -0300 Subject: [media] tm6000: Rename active interface register The register ACTIVE_VIDEO_IF register should be named ACTIVE_IF since it controls more than just the video interface. Signed-off-by: Thierry Reding Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/tm6000/tm6000-alsa.c b/drivers/staging/tm6000/tm6000-alsa.c index 8388243..cbe66ca 100644 --- a/drivers/staging/tm6000/tm6000-alsa.c +++ b/drivers/staging/tm6000/tm6000-alsa.c @@ -80,7 +80,7 @@ static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip) dprintk(1, "Starting audio DMA\n"); /* Enables audio */ - tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x40, 0x40); + tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_IF, 0x40, 0x40); tm6000_set_audio_bitrate(core, 48000); @@ -97,7 +97,7 @@ static int _tm6000_stop_audio_dma(struct snd_tm6000_card *chip) dprintk(1, "Stopping audio DMA\n"); /* Disables audio */ - tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x00, 0x40); + tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_IF, 0x00, 0x40); return 0; } diff --git a/drivers/staging/tm6000/tm6000-core.c b/drivers/staging/tm6000/tm6000-core.c index e14bd3d..2cd7bc4 100644 --- a/drivers/staging/tm6000/tm6000-core.c +++ b/drivers/staging/tm6000/tm6000-core.c @@ -187,11 +187,11 @@ void tm6000_set_fourcc_format(struct tm6000_core *dev) if (dev->dev_type == TM6010) { int val; - val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0) & 0xfc; + val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_IF, 0) & 0xfc; if (dev->fourcc == V4L2_PIX_FMT_UYVY) - tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val); + tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_IF, val); else - tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val | 1); + tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_IF, val | 1); } else { if (dev->fourcc == V4L2_PIX_FMT_UYVY) tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0); @@ -268,7 +268,7 @@ int tm6000_init_analog_mode(struct tm6000_core *dev) if (dev->dev_type == TM6010) { /* Enable video and audio */ - tm6000_set_reg_mask(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, + tm6000_set_reg_mask(dev, TM6010_REQ07_RCC_ACTIVE_IF, 0x60, 0x60); /* Disable TS input */ tm6000_set_reg_mask(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, @@ -334,7 +334,7 @@ int tm6000_init_digital_mode(struct tm6000_core *dev) { if (dev->dev_type == TM6010) { /* Disable video and audio */ - tm6000_set_reg_mask(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, + tm6000_set_reg_mask(dev, TM6010_REQ07_RCC_ACTIVE_IF, 0x00, 0x60); /* Enable TS input */ tm6000_set_reg_mask(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, @@ -462,7 +462,7 @@ static struct reg_init tm6010_init_tab[] = { { TM6010_REQ07_RC4_HSTART0, 0xa0 }, { TM6010_REQ07_RC6_HEND0, 0x40 }, { TM6010_REQ07_RCA_VEND0, 0x31 }, - { TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0xe1 }, + { TM6010_REQ07_RCC_ACTIVE_IF, 0xe1 }, { TM6010_REQ07_RE0_DVIDEO_SOURCE, 0x03 }, { TM6010_REQ07_RFE_POWER_DOWN, 0x7f }, diff --git a/drivers/staging/tm6000/tm6000-regs.h b/drivers/staging/tm6000/tm6000-regs.h index 5375a83..6e4ef95 100644 --- a/drivers/staging/tm6000/tm6000-regs.h +++ b/drivers/staging/tm6000/tm6000-regs.h @@ -270,7 +270,9 @@ enum { #define TM6010_REQ07_RCA_VEND0 0x07, 0xca #define TM6010_REQ07_RCB_DELAY 0x07, 0xcb /* ONLY for TM6010 */ -#define TM6010_REQ07_RCC_ACTIVE_VIDEO_IF 0x07, 0xcc +#define TM6010_REQ07_RCC_ACTIVE_IF 0x07, 0xcc +#define TM6010_REQ07_RCC_ACTIVE_IF_VIDEO_ENABLE (1 << 5) +#define TM6010_REQ07_RCC_ACTIVE_IF_AUDIO_ENABLE (1 << 6) #define TM6010_REQ07_RD0_USB_PERIPHERY_CONTROL 0x07, 0xd0 #define TM6010_REQ07_RD1_ADDR_FOR_REQ1 0x07, 0xd1 #define TM6010_REQ07_RD2_ADDR_FOR_REQ2 0x07, 0xd2 -- cgit v0.10.2 From 873545820a52e8ab6f6d54a748b1759b98f9354a Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 4 Aug 2011 04:14:08 -0300 Subject: [media] tm6000: Disable video interface in radio mode Video data is useless in radio mode, so the corresponding interface can be safely disabled. This should reduce the amount of isochronous traffic noticeably. Signed-off-by: Thierry Reding Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/tm6000/tm6000-core.c b/drivers/staging/tm6000/tm6000-core.c index 2cd7bc4..f85e5f2 100644 --- a/drivers/staging/tm6000/tm6000-core.c +++ b/drivers/staging/tm6000/tm6000-core.c @@ -267,9 +267,14 @@ int tm6000_init_analog_mode(struct tm6000_core *dev) struct v4l2_frequency f; if (dev->dev_type == TM6010) { + u8 active = TM6010_REQ07_RCC_ACTIVE_IF_AUDIO_ENABLE; + + if (!dev->radio) + active |= TM6010_REQ07_RCC_ACTIVE_IF_VIDEO_ENABLE; + /* Enable video and audio */ tm6000_set_reg_mask(dev, TM6010_REQ07_RCC_ACTIVE_IF, - 0x60, 0x60); + active, 0x60); /* Disable TS input */ tm6000_set_reg_mask(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x00, 0x40); -- cgit v0.10.2 From c0fa65ff9e7fdbdea7bf1bbc02fb2c3ee6814cc7 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 4 Aug 2011 04:14:09 -0300 Subject: [media] tm6000: Rework standard register tables This commit uses sentinel entries to terminate the TV standard register tables instead of hard-coding their size, allowing further entries to be added more easily. It is also more space-efficient if the tables have a varying number of entries. Signed-off-by: Thierry Reding Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/tm6000/tm6000-stds.c b/drivers/staging/tm6000/tm6000-stds.c index cd69626..f44451b 100644 --- a/drivers/staging/tm6000/tm6000-stds.c +++ b/drivers/staging/tm6000/tm6000-stds.c @@ -35,316 +35,303 @@ struct tm6000_reg_settings { struct tm6000_std_settings { v4l2_std_id id; - struct tm6000_reg_settings common[27]; + struct tm6000_reg_settings *common; +}; + +static struct tm6000_reg_settings composite_pal_m[] = { + { TM6010_REQ07_R3F_RESET, 0x01 }, + { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x04 }, + { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, + { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, + { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 }, + { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, + { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, + { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83 }, + { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a }, + { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe0 }, + { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, + { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, + { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, + { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, + { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, + { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x20 }, + { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 }, + { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c }, + { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, + { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 }, + { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, + { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc }, + { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, + { TM6010_REQ07_R3F_RESET, 0x00 }, + { 0, 0, 0 } +}; + +static struct tm6000_reg_settings composite_pal_nc[] = { + { TM6010_REQ07_R3F_RESET, 0x01 }, + { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x36 }, + { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, + { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, + { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02 }, + { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, + { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, + { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91 }, + { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f }, + { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x0c }, + { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, + { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, + { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, + { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, + { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c }, + { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c }, + { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 }, + { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c }, + { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, + { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 }, + { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, + { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc }, + { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, + { TM6010_REQ07_R3F_RESET, 0x00 }, + { 0, 0, 0 } +}; + +static struct tm6000_reg_settings composite_pal[] = { + { TM6010_REQ07_R3F_RESET, 0x01 }, + { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x32 }, + { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, + { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, + { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02 }, + { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, + { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25 }, + { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5 }, + { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63 }, + { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x50 }, + { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, + { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, + { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, + { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, + { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c }, + { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c }, + { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 }, + { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c }, + { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, + { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 }, + { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, + { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc }, + { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, + { TM6010_REQ07_R3F_RESET, 0x00 }, + { 0, 0, 0 } +}; + +static struct tm6000_reg_settings composite_secam[] = { + { TM6010_REQ07_R3F_RESET, 0x01 }, + { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x38 }, + { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, + { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, + { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02 }, + { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, + { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24 }, + { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92 }, + { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8 }, + { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed }, + { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, + { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, + { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, + { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, + { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c }, + { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c }, + { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 }, + { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c }, + { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18 }, + { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 }, + { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xff }, + { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, + { TM6010_REQ07_R3F_RESET, 0x00 }, + { 0, 0, 0 } +}; + +static struct tm6000_reg_settings composite_ntsc[] = { + { TM6010_REQ07_R3F_RESET, 0x01 }, + { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 }, + { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f }, + { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, + { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 }, + { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, + { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, + { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b }, + { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 }, + { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 }, + { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, + { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, + { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, + { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, + { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, + { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 }, + { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 }, + { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c }, + { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, + { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 }, + { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, + { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdd }, + { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, + { TM6010_REQ07_R3F_RESET, 0x00 }, + { 0, 0, 0 } }; static struct tm6000_std_settings composite_stds[] = { - { - .id = V4L2_STD_PAL_M, - .common = { - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x04}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe0}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x20}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F}, - - {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc}, - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - {TM6010_REQ07_R3F_RESET, 0x00}, - {0, 0, 0}, - }, - }, { - .id = V4L2_STD_PAL_Nc, - .common = { - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x36}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x0c}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F}, - - {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc}, - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - {TM6010_REQ07_R3F_RESET, 0x00}, - {0, 0, 0}, - }, - }, { - .id = V4L2_STD_PAL, - .common = { - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x32}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x50}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F}, - - {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc}, - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - {TM6010_REQ07_R3F_RESET, 0x00}, - {0, 0, 0}, - }, - }, { - .id = V4L2_STD_SECAM, - .common = { - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x38}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xFF}, - - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - {TM6010_REQ07_R3F_RESET, 0x00}, - {0, 0, 0}, - }, - }, { - .id = V4L2_STD_NTSC, - .common = { - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F}, - - {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdd}, - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - {TM6010_REQ07_R3F_RESET, 0x00}, - {0, 0, 0}, - }, - }, + { .id = V4L2_STD_PAL_M, .common = composite_pal_m, }, + { .id = V4L2_STD_PAL_Nc, .common = composite_pal_nc, }, + { .id = V4L2_STD_PAL, .common = composite_pal, }, + { .id = V4L2_STD_SECAM, .common = composite_secam, }, + { .id = V4L2_STD_NTSC, .common = composite_ntsc, }, }; -static struct tm6000_std_settings svideo_stds[] = { - { - .id = V4L2_STD_PAL_M, - .common = { - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x05}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe0}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F}, - - {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc}, - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - {TM6010_REQ07_R3F_RESET, 0x00}, - {0, 0, 0}, - }, - }, { - .id = V4L2_STD_PAL_Nc, - .common = { - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x37}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x0c}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F}, - - {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc}, - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - {TM6010_REQ07_R3F_RESET, 0x00}, - {0, 0, 0}, - }, - }, { - .id = V4L2_STD_PAL, - .common = { - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x33}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x30}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x50}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2a}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F}, - - {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc}, - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - {TM6010_REQ07_R3F_RESET, 0x00}, - {0, 0, 0}, - }, - }, { - .id = V4L2_STD_SECAM, - .common = { - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x39}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2a}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xFF}, - - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - {TM6010_REQ07_R3F_RESET, 0x00}, - {0, 0, 0}, - }, - }, { - .id = V4L2_STD_NTSC, - .common = { - {TM6010_REQ07_R3F_RESET, 0x01}, - {TM6010_REQ07_R00_VIDEO_CONTROL0, 0x01}, - {TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f}, - {TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f}, - {TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03}, - {TM6010_REQ07_R07_OUTPUT_CONTROL, 0x30}, - {TM6010_REQ07_R17_HLOOP_MAXSTATE, 0x8b}, - {TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e}, - {TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b}, - {TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2}, - {TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9}, - {TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c}, - {TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc}, - {TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc}, - {TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd}, - {TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88}, - {TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22}, - {TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61}, - {TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c}, - {TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c}, - {TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42}, - {TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6F}, - - {TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdd}, - {TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07}, - {TM6010_REQ07_R3F_RESET, 0x00}, - {0, 0, 0}, - }, - }, +static struct tm6000_reg_settings svideo_pal_m[] = { + { TM6010_REQ07_R3F_RESET, 0x01 }, + { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x05 }, + { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, + { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, + { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04 }, + { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, + { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, + { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83 }, + { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a }, + { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe0 }, + { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, + { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, + { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, + { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, + { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, + { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 }, + { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 }, + { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c }, + { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, + { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 }, + { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, + { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc }, + { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, + { TM6010_REQ07_R3F_RESET, 0x00 }, + { 0, 0, 0 } }; +static struct tm6000_reg_settings svideo_pal_nc[] = { + { TM6010_REQ07_R3F_RESET, 0x01 }, + { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x37 }, + { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, + { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, + { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04 }, + { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, + { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, + { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91 }, + { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f }, + { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x0c }, + { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, + { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, + { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, + { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, + { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, + { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 }, + { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 }, + { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c }, + { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, + { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 }, + { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, + { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc }, + { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, + { TM6010_REQ07_R3F_RESET, 0x00 }, + { 0, 0, 0 } +}; + +static struct tm6000_reg_settings svideo_pal[] = { + { TM6010_REQ07_R3F_RESET, 0x01 }, + { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x33 }, + { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, + { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, + { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04 }, + { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x30 }, + { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25 }, + { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5 }, + { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63 }, + { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x50 }, + { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, + { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, + { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, + { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, + { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c }, + { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2a }, + { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 }, + { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c }, + { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, + { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 }, + { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, + { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc }, + { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, + { TM6010_REQ07_R3F_RESET, 0x00 }, + { 0, 0, 0 } +}; + +static struct tm6000_reg_settings svideo_secam[] = { + { TM6010_REQ07_R3F_RESET, 0x01 }, + { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x39 }, + { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, + { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, + { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03 }, + { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, + { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24 }, + { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92 }, + { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8 }, + { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed }, + { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, + { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, + { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, + { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, + { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c }, + { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2a }, + { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 }, + { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c }, + { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18 }, + { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 }, + { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xff }, + { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, + { TM6010_REQ07_R3F_RESET, 0x00 }, + { 0, 0, 0 } +}; + +static struct tm6000_reg_settings svideo_ntsc[] = { + { TM6010_REQ07_R3F_RESET, 0x01 }, + { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x01 }, + { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f }, + { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, + { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03 }, + { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x30 }, + { TM6010_REQ07_R17_HLOOP_MAXSTATE, 0x8b }, + { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, + { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b }, + { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 }, + { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 }, + { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, + { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, + { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, + { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, + { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, + { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 }, + { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 }, + { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c }, + { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, + { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 }, + { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, + { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdd }, + { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, + { TM6010_REQ07_R3F_RESET, 0x00 }, + { 0, 0, 0 } +}; + +static struct tm6000_std_settings svideo_stds[] = { + { .id = V4L2_STD_PAL_M, .common = svideo_pal_m, }, + { .id = V4L2_STD_PAL_Nc, .common = svideo_pal_nc, }, + { .id = V4L2_STD_PAL, .common = svideo_pal, }, + { .id = V4L2_STD_SECAM, .common = svideo_secam, }, + { .id = V4L2_STD_NTSC, .common = svideo_ntsc, }, +}; static int tm6000_set_audio_std(struct tm6000_core *dev) { @@ -501,16 +488,12 @@ void tm6000_get_std_res(struct tm6000_core *dev) dev->width = 720; } -static int tm6000_load_std(struct tm6000_core *dev, - struct tm6000_reg_settings *set, int max_size) +static int tm6000_load_std(struct tm6000_core *dev, struct tm6000_reg_settings *set) { int i, rc; /* Load board's initialization table */ - for (i = 0; max_size; i++) { - if (!set[i].req) - return 0; - + for (i = 0; set[i].req; i++) { rc = tm6000_set_reg(dev, set[i].req, set[i].reg, set[i].value); if (rc < 0) { printk(KERN_ERR "Error %i while setting " @@ -645,9 +628,7 @@ int tm6000_set_standard(struct tm6000_core *dev) if (input->type == TM6000_INPUT_SVIDEO) { for (i = 0; i < ARRAY_SIZE(svideo_stds); i++) { if (dev->norm & svideo_stds[i].id) { - rc = tm6000_load_std(dev, svideo_stds[i].common, - sizeof(svideo_stds[i]. - common)); + rc = tm6000_load_std(dev, svideo_stds[i].common); goto ret; } } @@ -655,10 +636,7 @@ int tm6000_set_standard(struct tm6000_core *dev) } else { for (i = 0; i < ARRAY_SIZE(composite_stds); i++) { if (dev->norm & composite_stds[i].id) { - rc = tm6000_load_std(dev, - composite_stds[i].common, - sizeof(composite_stds[i]. - common)); + rc = tm6000_load_std(dev, composite_stds[i].common); goto ret; } } -- cgit v0.10.2 From fc4eab2cbae547fb278c2583b77ee0ff7f5832d3 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 4 Aug 2011 04:14:10 -0300 Subject: [media] tm6000: Add locking for USB transfers This commit introduces the usb_lock mutex to ensure that a USB request always gets the proper response. While this is currently not really necessary it will become important as there are more users. Signed-off-by: Thierry Reding Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c index bac4309..f247e7e 100644 --- a/drivers/staging/tm6000/tm6000-cards.c +++ b/drivers/staging/tm6000/tm6000-cards.c @@ -1168,6 +1168,7 @@ static int tm6000_usb_probe(struct usb_interface *interface, return -ENOMEM; } spin_lock_init(&dev->slock); + mutex_init(&dev->usb_lock); /* Increment usage count */ tm6000_devused |= 1<usb_lock); + if (len) data = kzalloc(len, GFP_KERNEL); @@ -86,9 +88,9 @@ int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req, } kfree(data); - msleep(5); + mutex_unlock(&dev->usb_lock); return ret; } diff --git a/drivers/staging/tm6000/tm6000.h b/drivers/staging/tm6000/tm6000.h index 4323fc2..cf57e1e 100644 --- a/drivers/staging/tm6000/tm6000.h +++ b/drivers/staging/tm6000/tm6000.h @@ -245,6 +245,7 @@ struct tm6000_core { /* locks */ struct mutex lock; + struct mutex usb_lock; /* usb transfer */ struct usb_device *udev; /* the usb device */ -- cgit v0.10.2 From 6f2e77bb955771a7b8de80ea519c1e9a82b864dd Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 4 Aug 2011 04:14:11 -0300 Subject: [media] tm6000: Properly count device usage When the USB device is disconnected, the device usage bit is not cleared properly. This leads to errors when a device is unplugged and replugged several times until all TM6000_MAXBOARDS bits are used and keeps the driver from binding to the device. Signed-off-by: Thierry Reding Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c index f247e7e..d2ee18f 100644 --- a/drivers/staging/tm6000/tm6000-cards.c +++ b/drivers/staging/tm6000/tm6000-cards.c @@ -1171,7 +1171,7 @@ static int tm6000_usb_probe(struct usb_interface *interface, mutex_init(&dev->usb_lock); /* Increment usage count */ - tm6000_devused |= 1<name, 29, "tm6000 #%d", nr); dev->model = id->driver_info; @@ -1287,7 +1287,7 @@ static int tm6000_usb_probe(struct usb_interface *interface, err: printk(KERN_ERR "tm6000: Error %d while registering\n", rc); - tm6000_devused &= ~(1<devno, &tm6000_devused); kfree(dev); } -- cgit v0.10.2 From 88e834a841bde22b4c0aa71809e02c118c5b219d Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 4 Aug 2011 04:14:12 -0300 Subject: [media] tm6000: Initialize isochronous transfers only once This fixes a memory leak where isochronous buffers would be set up for each video buffer, while it is sufficient to set them up only once per device. Signed-off-by: Thierry Reding Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c index bef6023..873c8ee 100644 --- a/drivers/staging/tm6000/tm6000-video.c +++ b/drivers/staging/tm6000/tm6000-video.c @@ -754,7 +754,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, struct tm6000_fh *fh = vq->priv_data; struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb); struct tm6000_core *dev = fh->dev; - int rc = 0, urb_init = 0; + int rc = 0; BUG_ON(NULL == fh->fmt); @@ -780,13 +780,9 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, rc = videobuf_iolock(vq, &buf->vb, NULL); if (rc != 0) goto fail; - urb_init = 1; } - if (!dev->isoc_ctl.num_bufs) - urb_init = 1; - - if (urb_init) { + if (!dev->isoc_ctl.num_bufs) { rc = tm6000_prepare_isoc(dev); if (rc < 0) goto fail; -- cgit v0.10.2 From dd0c8abf2ac853dad9a360f5e9d3d1cb5e5f7621 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 4 Aug 2011 04:14:13 -0300 Subject: [media] tm6000: Execute lightweight reset on close When the last user closes the device, perform a lightweight reset of the device to bring it into a well-known state. Note that this is not always enough with the TM6010, which sometimes needs a hard reset to get into a working state again. Signed-off-by: Thierry Reding Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/tm6000/tm6000-core.c b/drivers/staging/tm6000/tm6000-core.c index 31fdf15..9cef1d1 100644 --- a/drivers/staging/tm6000/tm6000-core.c +++ b/drivers/staging/tm6000/tm6000-core.c @@ -599,6 +599,49 @@ int tm6000_init(struct tm6000_core *dev) return rc; } +int tm6000_reset(struct tm6000_core *dev) +{ + int pipe; + int err; + + msleep(500); + + err = usb_set_interface(dev->udev, dev->isoc_in.bInterfaceNumber, 0); + if (err < 0) { + tm6000_err("failed to select interface %d, alt. setting 0\n", + dev->isoc_in.bInterfaceNumber); + return err; + } + + err = usb_reset_configuration(dev->udev); + if (err < 0) { + tm6000_err("failed to reset configuration\n"); + return err; + } + + msleep(5); + + err = usb_set_interface(dev->udev, dev->isoc_in.bInterfaceNumber, 2); + if (err < 0) { + tm6000_err("failed to select interface %d, alt. setting 2\n", + dev->isoc_in.bInterfaceNumber); + return err; + } + + msleep(5); + + pipe = usb_rcvintpipe(dev->udev, + dev->int_in.endp->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + + err = usb_clear_halt(dev->udev, pipe); + if (err < 0) { + tm6000_err("usb_clear_halt failed: %d\n", err); + return err; + } + + return 0; +} + int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate) { int val = 0; diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c index 873c8ee..df8e253 100644 --- a/drivers/staging/tm6000/tm6000-video.c +++ b/drivers/staging/tm6000/tm6000-video.c @@ -1603,9 +1603,16 @@ static int tm6000_release(struct file *file) dev->users--; res_free(dev, fh); + if (!dev->users) { + int err; + tm6000_uninit_isoc(dev); videobuf_mmap_free(&fh->vb_vidq); + + err = tm6000_reset(dev); + if (err < 0) + dev_err(&vdev->dev, "reset failed: %d\n", err); } kfree(fh); diff --git a/drivers/staging/tm6000/tm6000.h b/drivers/staging/tm6000/tm6000.h index cf57e1e..dac2063 100644 --- a/drivers/staging/tm6000/tm6000.h +++ b/drivers/staging/tm6000/tm6000.h @@ -311,6 +311,7 @@ int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value, u16 index, u16 mask); int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep); int tm6000_init(struct tm6000_core *dev); +int tm6000_reset(struct tm6000_core *dev); int tm6000_init_analog_mode(struct tm6000_core *dev); int tm6000_init_digital_mode(struct tm6000_core *dev); -- cgit v0.10.2 From aa4a583d3539729d1cbd64cda7a8be078a824df8 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 4 Aug 2011 04:14:15 -0300 Subject: [media] tm6000: Do not use video buffers in radio mode If the radio device is opened there is no need to initialize the video buffer queue because it is not used. Signed-off-by: Thierry Reding Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c index df8e253..1e5ace0 100644 --- a/drivers/staging/tm6000/tm6000-video.c +++ b/drivers/staging/tm6000/tm6000-video.c @@ -1530,13 +1530,13 @@ static int tm6000_open(struct file *file) dev->mode = TM6000_MODE_ANALOG; } - videobuf_queue_vmalloc_init(&fh->vb_vidq, &tm6000_video_qops, - NULL, &dev->slock, - fh->type, - V4L2_FIELD_INTERLACED, - sizeof(struct tm6000_buffer), fh, &dev->lock); - - if (fh->radio) { + if (!fh->radio) { + videobuf_queue_vmalloc_init(&fh->vb_vidq, &tm6000_video_qops, + NULL, &dev->slock, + fh->type, + V4L2_FIELD_INTERLACED, + sizeof(struct tm6000_buffer), fh, &dev->lock); + } else { dprintk(dev, V4L2_DEBUG_OPEN, "video_open: setting radio device\n"); dev->input = 5; tm6000_set_audio_rinput(dev); @@ -1608,7 +1608,9 @@ static int tm6000_release(struct file *file) int err; tm6000_uninit_isoc(dev); - videobuf_mmap_free(&fh->vb_vidq); + + if (!fh->radio) + videobuf_mmap_free(&fh->vb_vidq); err = tm6000_reset(dev); if (err < 0) -- cgit v0.10.2 From 8d90e1e382688d55a75677cc4c7210a697125554 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 4 Aug 2011 04:14:16 -0300 Subject: [media] tm6000: Plug memory leak on PCM free When releasing hardware resources, the DMA buffer allocated to the PCM device needs to be freed to prevent a memory leak. Signed-off-by: Thierry Reding Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/tm6000/tm6000-alsa.c b/drivers/staging/tm6000/tm6000-alsa.c index cbe66ca..7d675c7 100644 --- a/drivers/staging/tm6000/tm6000-alsa.c +++ b/drivers/staging/tm6000/tm6000-alsa.c @@ -304,6 +304,7 @@ static int snd_tm6000_hw_free(struct snd_pcm_substream *substream) schedule_work(&core->wq_trigger); } + dsp_buffer_free(substream); return 0; } -- cgit v0.10.2 From f009a946d7cb23df00f497b11f550086d0442592 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 4 Aug 2011 04:14:17 -0300 Subject: [media] tm6000: Enable audio clock in radio mode Signed-off-by: Thierry Reding Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/tm6000/tm6000-stds.c b/drivers/staging/tm6000/tm6000-stds.c index f44451b..9a4145d 100644 --- a/drivers/staging/tm6000/tm6000-stds.c +++ b/drivers/staging/tm6000/tm6000-stds.c @@ -357,6 +357,7 @@ static int tm6000_set_audio_std(struct tm6000_core *dev) tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe); tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13); tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80); + tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, 0xff); return 0; } -- cgit v0.10.2 From d657229ac4378700976fb2333c7433c5ea379d08 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 4 Aug 2011 04:14:18 -0300 Subject: [media] tm6000: Enable radio mode for Cinergy Hybrid XE Signed-off-by: Thierry Reding Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c index d2ee18f..8483c56 100644 --- a/drivers/staging/tm6000/tm6000-cards.c +++ b/drivers/staging/tm6000/tm6000-cards.c @@ -468,6 +468,7 @@ static struct tm6000_board tm6000_boards[] = { .has_zl10353 = 1, .has_eeprom = 1, .has_remote = 1, + .has_radio = 1, }, .gpio = { .tuner_reset = TM6010_GPIO_2, @@ -493,6 +494,10 @@ static struct tm6000_board tm6000_boards[] = { .amux = TM6000_AMUX_ADC2, }, }, + .rinput = { + .type = TM6000_INPUT_RADIO, + .amux = TM6000_AMUX_SIF1, + }, }, [TM5600_BOARD_TERRATEC_GRABSTER] = { .name = "Terratec Grabster AV 150/250 MX", -- cgit v0.10.2 From f8dbab29f4d4b977a56776af0d5296b0e6386aef Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 1 Sep 2011 02:57:02 -0300 Subject: [media] tm6000: Don't try to use a non-existing interface > [34883.426065] tm6000 #0: registered device video0 > [34883.430591] Trident TVMaster TM5600/TM6000/TM6010 USB2 board (Load status: 0) > [34883.437763] usbcore: registered new interface driver tm6000 > [34884.608372] BUG: unable to handle kernel NULL pointer dereference at 00000002 > [34884.615514] IP: [] tm6000_reset+0xd7/0x11c [tm6000] The dev->int_in USB interfaces is used by some devices for the Remote Controller. Not all devices seem to define this interface, so, tm6000_reset should not try to set the interface to it on such devices. Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/tm6000/tm6000-core.c b/drivers/staging/tm6000/tm6000-core.c index 9cef1d1..b3c4e05 100644 --- a/drivers/staging/tm6000/tm6000-core.c +++ b/drivers/staging/tm6000/tm6000-core.c @@ -621,6 +621,12 @@ int tm6000_reset(struct tm6000_core *dev) msleep(5); + /* + * Not all devices have int_in defined + */ + if (!dev->int_in.endp) + return 0; + err = usb_set_interface(dev->udev, dev->isoc_in.bInterfaceNumber, 2); if (err < 0) { tm6000_err("failed to select interface %d, alt. setting 2\n", -- cgit v0.10.2 From f00fd919ef71b3d6d52dbfa7ce827679d92af713 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 4 Aug 2011 07:29:33 -0300 Subject: [media] drivers/media/video/hexium_gemini.c: delete useless initialization Delete nontrivial initialization that is immediately overwritten by the result of an allocation function. The semantic match that makes this change is as follows: // @@ type T; identifier i; expression e; @@ ( T i = \(0\|NULL\|ERR_PTR(...)\); | -T i = e; +T i; ) ... when != i i = \(kzalloc\|kcalloc\|kmalloc\)(...); // Signed-off-by: Julia Lawall Acked-by: Jean Delvare Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/hexium_gemini.c b/drivers/media/video/hexium_gemini.c index cbc505a..b37c12f 100644 --- a/drivers/media/video/hexium_gemini.c +++ b/drivers/media/video/hexium_gemini.c @@ -351,7 +351,7 @@ static struct saa7146_ext_vv vv_data; /* this function only gets called when the probing was successful */ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) { - struct hexium *hexium = (struct hexium *) dev->ext_priv; + struct hexium *hexium; int ret; DEB_EE((".\n")); -- cgit v0.10.2 From 56ce5ac41af87c157cf4c6e4e6fec31d7d48025e Mon Sep 17 00:00:00 2001 From: Andreas Oberritter Date: Thu, 4 Aug 2011 12:33:12 -0300 Subject: [media] DVB: dvb_frontend: fix stale parameters on initial frontend event Modify it to use the data given by the user. Signed-off-by: Andreas Oberritter Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index efe9c30..23d79d0 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1827,6 +1827,13 @@ static int dvb_frontend_ioctl_legacy(struct file *file, dtv_property_cache_sync(fe, c, &fepriv->parameters_in); } + /* + * Initialize output parameters to match the values given by + * the user. FE_SET_FRONTEND triggers an initial frontend event + * with status = 0, which copies output parameters to userspace. + */ + fepriv->parameters_out = fepriv->parameters_in; + memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings)); memcpy(&fetunesettings.parameters, parg, sizeof (struct dvb_frontend_parameters)); -- cgit v0.10.2 From 5c9f480bdb584944b5af390ccdd8c3e586bdafdb Mon Sep 17 00:00:00 2001 From: Andreas Oberritter Date: Thu, 4 Aug 2011 12:33:13 -0300 Subject: [media] DVB: dvb_frontend: avoid possible race condition on first event enqueued before the frontend thread wakes up. Signed-off-by: Andreas Oberritter Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 23d79d0..45ea843 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1891,8 +1891,8 @@ static int dvb_frontend_ioctl_legacy(struct file *file, /* Request the search algorithm to search */ fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; - dvb_frontend_wakeup(fe); dvb_frontend_add_event(fe, 0); + dvb_frontend_wakeup(fe); fepriv->status = 0; err = 0; break; -- cgit v0.10.2 From 20640bea87c31a823dba3756b1a5248197f0905f Mon Sep 17 00:00:00 2001 From: Andreas Oberritter Date: Thu, 4 Aug 2011 12:33:14 -0300 Subject: [media] DVB: dvb_frontend: clear stale events on FE_SET_FRONTEND the first event after an attempt to tune. Signed-off-by: Andreas Oberritter Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 45ea843..4102311 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -220,6 +220,16 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe, return 0; } +static void dvb_frontend_clear_events(struct dvb_frontend *fe) +{ + struct dvb_frontend_private *fepriv = fe->frontend_priv; + struct dvb_fe_events *events = &fepriv->events; + + mutex_lock(&events->mtx); + events->eventr = events->eventw; + mutex_unlock(&events->mtx); +} + static void dvb_frontend_init(struct dvb_frontend *fe) { dprintk ("DVB: initialising adapter %i frontend %i (%s)...\n", @@ -1891,6 +1901,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file, /* Request the search algorithm to search */ fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; + dvb_frontend_clear_events(fe); dvb_frontend_add_event(fe, 0); dvb_frontend_wakeup(fe); fepriv->status = 0; -- cgit v0.10.2 From 77b1e2fbbdfa0ee5cdf6c928b711493a3738468e Mon Sep 17 00:00:00 2001 From: Andreas Oberritter Date: Thu, 4 Aug 2011 12:33:15 -0300 Subject: [media] DVB: dvb_frontend: update locking in dvb_frontend_{add, get_event} - fepriv->parameters_out isn't protected by events->mtx, so move the call to fe->ops.get_frontend out of the locked area. - move the assignment of e->status into the locked area. - use direct assignment instead of memcpy. - use mutex_lock instead of mutex_lock_interruptible, because all code paths protected by this mutex won't block. Signed-off-by: Andreas Oberritter Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 4102311..d02c32e 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -149,30 +149,25 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) dprintk ("%s\n", __func__); - if (mutex_lock_interruptible (&events->mtx)) - return; + if ((status & FE_HAS_LOCK) && fe->ops.get_frontend) + fe->ops.get_frontend(fe, &fepriv->parameters_out); - wp = (events->eventw + 1) % MAX_EVENT; + mutex_lock(&events->mtx); + wp = (events->eventw + 1) % MAX_EVENT; if (wp == events->eventr) { events->overflow = 1; events->eventr = (events->eventr + 1) % MAX_EVENT; } e = &events->events[events->eventw]; - - if (status & FE_HAS_LOCK) - if (fe->ops.get_frontend) - fe->ops.get_frontend(fe, &fepriv->parameters_out); - + e->status = status; e->parameters = fepriv->parameters_out; events->eventw = wp; mutex_unlock(&events->mtx); - e->status = status; - wake_up_interruptible (&events->wait_queue); } @@ -207,14 +202,9 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe, return ret; } - if (mutex_lock_interruptible (&events->mtx)) - return -ERESTARTSYS; - - memcpy (event, &events->events[events->eventr], - sizeof(struct dvb_frontend_event)); - + mutex_lock(&events->mtx); + *event = events->events[events->eventr]; events->eventr = (events->eventr + 1) % MAX_EVENT; - mutex_unlock(&events->mtx); return 0; -- cgit v0.10.2 From 297875b6a1f3910c883e4b00bb9bc3e6c3aa6ab7 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 14 Jul 2011 18:10:44 -0300 Subject: [media] videobuf2: Do not unconditionally map S/G buffers into kernel space The one in-tree videobuf2-dma-sg driver (mmp-camera) has no need for a kernel-space mapping of the buffers; one suspects that most other drivers would not either. The videobuf2-dma-sg module does the right thing if buf->vaddr == NULL - it maps the buffer on demand if somebody needs it. So let's not map the buffer at allocation time; that will save a little CPU time and a lot of address space in the vmalloc range. Signed-off-by: Jonathan Corbet Acked-by: Marek Szyprowski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/videobuf2-dma-sg.c b/drivers/media/video/videobuf2-dma-sg.c index 065f468..3bad8b1 100644 --- a/drivers/media/video/videobuf2-dma-sg.c +++ b/drivers/media/video/videobuf2-dma-sg.c @@ -75,12 +75,6 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size) printk(KERN_DEBUG "%s: Allocated buffer of %d pages\n", __func__, buf->sg_desc.num_pages); - - if (!buf->vaddr) - buf->vaddr = vm_map_ram(buf->pages, - buf->sg_desc.num_pages, - -1, - PAGE_KERNEL); return buf; fail_pages_alloc: -- cgit v0.10.2 From 2f00e158b59bf83b8e6bc84130ac291a28827e76 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Thu, 14 Jul 2011 19:04:49 -0300 Subject: [media] redrat3: remove unused dev struct members Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index a166044..61287fc 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -195,11 +195,6 @@ struct redrat3_dev { dma_addr_t dma_in; dma_addr_t dma_out; - /* true if write urb is busy */ - bool write_busy; - /* wait for the write to finish */ - struct completion write_finished; - /* locks this structure */ struct mutex lock; @@ -207,8 +202,6 @@ struct redrat3_dev { struct timer_list rx_timeout; u32 hw_timeout; - /* Is the device currently receiving? */ - bool recv_in_progress; /* is the detector enabled*/ bool det_enabled; /* Is the device currently transmitting?*/ -- cgit v0.10.2 From f2d0c1c625bc79aa524b52eea2de4262a9be1d90 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Thu, 14 Jul 2011 19:06:08 -0300 Subject: [media] em28xx: add em28xx_ prefix to functions Makes it more straight-forward to follow stack traces if the functions don't have generic names. Using this as a crutch while trying to better understand the lockdep warnings I get when loading the em28xx driver. CC: Devin Heitmueller Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index 47b4cfa..b3406eb 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c @@ -122,7 +122,7 @@ static inline void print_err_status(struct em28xx *dev, } } -static inline int dvb_isoc_copy(struct em28xx *dev, struct urb *urb) +static inline int em28xx_dvb_isoc_copy(struct em28xx *dev, struct urb *urb) { int i; @@ -155,7 +155,7 @@ static inline int dvb_isoc_copy(struct em28xx *dev, struct urb *urb) return 0; } -static int start_streaming(struct em28xx_dvb *dvb) +static int em28xx_start_streaming(struct em28xx_dvb *dvb) { int rc; struct em28xx *dev = dvb->adapter.priv; @@ -175,10 +175,10 @@ static int start_streaming(struct em28xx_dvb *dvb) return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS, EM28XX_DVB_NUM_BUFS, max_dvb_packet_size, - dvb_isoc_copy); + em28xx_dvb_isoc_copy); } -static int stop_streaming(struct em28xx_dvb *dvb) +static int em28xx_stop_streaming(struct em28xx_dvb *dvb) { struct em28xx *dev = dvb->adapter.priv; @@ -189,7 +189,7 @@ static int stop_streaming(struct em28xx_dvb *dvb) return 0; } -static int start_feed(struct dvb_demux_feed *feed) +static int em28xx_start_feed(struct dvb_demux_feed *feed) { struct dvb_demux *demux = feed->demux; struct em28xx_dvb *dvb = demux->priv; @@ -203,7 +203,7 @@ static int start_feed(struct dvb_demux_feed *feed) rc = dvb->nfeeds; if (dvb->nfeeds == 1) { - ret = start_streaming(dvb); + ret = em28xx_start_streaming(dvb); if (ret < 0) rc = ret; } @@ -212,7 +212,7 @@ static int start_feed(struct dvb_demux_feed *feed) return rc; } -static int stop_feed(struct dvb_demux_feed *feed) +static int em28xx_stop_feed(struct dvb_demux_feed *feed) { struct dvb_demux *demux = feed->demux; struct em28xx_dvb *dvb = demux->priv; @@ -222,7 +222,7 @@ static int stop_feed(struct dvb_demux_feed *feed) dvb->nfeeds--; if (0 == dvb->nfeeds) - err = stop_streaming(dvb); + err = em28xx_stop_streaming(dvb); mutex_unlock(&dvb->lock); return err; @@ -380,7 +380,7 @@ static void terratec_h5_init(struct em28xx *dev) em28xx_gpio_set(dev, terratec_h5_end); }; -static int mt352_terratec_xs_init(struct dvb_frontend *fe) +static int em28xx_mt352_terratec_xs_init(struct dvb_frontend *fe) { /* Values extracted from a USB trace of the Terratec Windows driver */ static u8 clock_config[] = { CLOCK_CTL, 0x38, 0x2c }; @@ -412,7 +412,7 @@ static struct mt352_config terratec_xs_mt352_cfg = { .demod_address = (0x1e >> 1), .no_tuner = 1, .if2 = 45600, - .demod_init = mt352_terratec_xs_init, + .demod_init = em28xx_mt352_terratec_xs_init, }; static struct tda10023_config em28xx_tda10023_config = { @@ -442,7 +442,7 @@ static struct tda18271_config em28xx_cxd2820r_tda18271_config = { /* ------------------------------------------------------------------ */ -static int attach_xc3028(u8 addr, struct em28xx *dev) +static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev) { struct dvb_frontend *fe; struct xc2028_config cfg; @@ -472,10 +472,8 @@ static int attach_xc3028(u8 addr, struct em28xx *dev) /* ------------------------------------------------------------------ */ -static int register_dvb(struct em28xx_dvb *dvb, - struct module *module, - struct em28xx *dev, - struct device *device) +static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module, + struct em28xx *dev, struct device *device) { int result; @@ -522,8 +520,8 @@ static int register_dvb(struct em28xx_dvb *dvb, dvb->demux.priv = dvb; dvb->demux.filternum = 256; dvb->demux.feednum = 256; - dvb->demux.start_feed = start_feed; - dvb->demux.stop_feed = stop_feed; + dvb->demux.start_feed = em28xx_start_feed; + dvb->demux.stop_feed = em28xx_stop_feed; result = dvb_dmx_init(&dvb->demux); if (result < 0) { @@ -591,7 +589,7 @@ fail_adapter: return result; } -static void unregister_dvb(struct em28xx_dvb *dvb) +static void em28xx_unregister_dvb(struct em28xx_dvb *dvb) { dvb_net_release(&dvb->net); dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); @@ -607,7 +605,7 @@ static void unregister_dvb(struct em28xx_dvb *dvb) dvb_unregister_adapter(&dvb->adapter); } -static int dvb_init(struct em28xx *dev) +static int em28xx_dvb_init(struct em28xx *dev) { int result = 0, mfe_shared = 0; struct em28xx_dvb *dvb; @@ -648,7 +646,7 @@ static int dvb_init(struct em28xx *dev) dvb->fe[0] = dvb_attach(lgdt330x_attach, &em2880_lgdt3303_dev, &dev->i2c_adap); - if (attach_xc3028(0x61, dev) < 0) { + if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; } @@ -657,7 +655,7 @@ static int dvb_init(struct em28xx *dev) dvb->fe[0] = dvb_attach(zl10353_attach, &em28xx_zl10353_with_xc3028, &dev->i2c_adap); - if (attach_xc3028(0x61, dev) < 0) { + if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; } @@ -668,7 +666,7 @@ static int dvb_init(struct em28xx *dev) dvb->fe[0] = dvb_attach(zl10353_attach, &em28xx_zl10353_xc3028_no_i2c_gate, &dev->i2c_adap); - if (attach_xc3028(0x61, dev) < 0) { + if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; } @@ -689,7 +687,7 @@ static int dvb_init(struct em28xx *dev) &dev->i2c_adap); } - if (attach_xc3028(0x61, dev) < 0) { + if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; } @@ -699,7 +697,7 @@ static int dvb_init(struct em28xx *dev) dvb->fe[0] = dvb_attach(s5h1409_attach, &em28xx_s5h1409_with_xc3028, &dev->i2c_adap); - if (attach_xc3028(0x61, dev) < 0) { + if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; } @@ -720,7 +718,7 @@ static int dvb_init(struct em28xx *dev) case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E: dvb->fe[0] = dvb_attach(drxd_attach, &em28xx_drxd, NULL, &dev->i2c_adap, &dev->udev->dev); - if (attach_xc3028(0x61, dev) < 0) { + if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; } @@ -825,7 +823,7 @@ static int dvb_init(struct em28xx *dev) dvb->fe[0]->callback = em28xx_tuner_callback; /* register everything */ - result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev); + result = em28xx_register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev); if (result < 0) goto out_free; @@ -845,7 +843,7 @@ out_free: goto ret; } -static int dvb_fini(struct em28xx *dev) +static int em28xx_dvb_fini(struct em28xx *dev) { if (!dev->board.has_dvb) { /* This device does not support the extension */ @@ -853,7 +851,7 @@ static int dvb_fini(struct em28xx *dev) } if (dev->dvb) { - unregister_dvb(dev->dvb); + em28xx_unregister_dvb(dev->dvb); kfree(dev->dvb); dev->dvb = NULL; } @@ -864,8 +862,8 @@ static int dvb_fini(struct em28xx *dev) static struct em28xx_ops dvb_ops = { .id = EM28XX_DVB, .name = "Em28xx dvb Extension", - .init = dvb_init, - .fini = dvb_fini, + .init = em28xx_dvb_init, + .fini = em28xx_dvb_fini, }; static int __init em28xx_dvb_register(void) -- cgit v0.10.2 From 8513e14457ad05c517f6f6f520c270a6eebf0472 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 3 Sep 2011 11:40:02 -0300 Subject: [media] dvb-core, tda18271c2dd: define get_if_frequency() callback Tuners in general convert a high frequency carrier into an Intermediate Frequency (IF). Digital tuners like tda18271, xc3028, etc. generally allow changing the IF frequency, although they generally have recommented settings for the IF. Analog tuners, have a fixed IF frequency, that depends on the physical characteristics of some analog components. For digital tuners, it makes sense to have ways to configure IF, via the tuner's configuration structure, like what's done inside the tda18271-fe maps. The demods need to know what IF is used by the tuner, as it will need to convert internally from IF into baseband. Currently, the bridge driver needs to fill a per-demod configuration struct for it, or pass it via a dvb_attach parameter. The tda18271 datasheet recommends to use different IF's for different delivery system types and for different bandwidths. The DRX-K demod also needs to know the IF frequency in order to work, just like all other demods. However, as it accepts different delivery systems (DVB-C and DVB-T), the IF may change if the standard and/or bandwidth is changed. So, the usual procedure of passing it via a config struct doesn't work. One might try to code it as two separate IF frequencies, or even as a table in function of the delivery system and the bandwidth, but this will be messy. So, it is better and simpler to just add a new callback for it and require the tuners that can be used with MFE frontends like drx-k to implement a new callback to return the used IF. Signed-off-by: Mauro Carvalho Chehab Acked-by: Antti Palosaari diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index 5590eb6..67bbfa7 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -209,6 +209,7 @@ struct dvb_tuner_ops { int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency); int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth); + int (*get_if_frequency)(struct dvb_frontend *fe, u32 *frequency); #define TUNER_STATUS_LOCKED 1 #define TUNER_STATUS_STEREO 2 diff --git a/drivers/media/dvb/frontends/drxk_hard.c b/drivers/media/dvb/frontends/drxk_hard.c index 41b0838..f6431ef 100644 --- a/drivers/media/dvb/frontends/drxk_hard.c +++ b/drivers/media/dvb/frontends/drxk_hard.c @@ -6211,6 +6211,14 @@ static int drxk_set_parameters(struct dvb_frontend *fe, u32 IF; dprintk(1, "\n"); + + if (!fe->ops.tuner_ops.get_if_frequency) { + printk(KERN_ERR + "drxk: Error: get_if_frequency() not defined at tuner. Can't work without it!\n"); + return -EINVAL; + } + + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); if (fe->ops.tuner_ops.set_params) @@ -6218,7 +6226,7 @@ static int drxk_set_parameters(struct dvb_frontend *fe, if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); state->param = *p; - fe->ops.tuner_ops.get_frequency(fe, &IF); + fe->ops.tuner_ops.get_if_frequency(fe, &IF); Start(state, 0, IF); /* printk(KERN_DEBUG "drxk: %s IF=%d done\n", __func__, IF); */ diff --git a/drivers/media/dvb/frontends/tda18271c2dd.c b/drivers/media/dvb/frontends/tda18271c2dd.c index 0384e8d..1b1bf20 100644 --- a/drivers/media/dvb/frontends/tda18271c2dd.c +++ b/drivers/media/dvb/frontends/tda18271c2dd.c @@ -1195,7 +1195,7 @@ static int GetSignalStrength(s32 *pSignalStrength, u32 RFAgc, u32 IFAgc) } #endif -static int get_frequency(struct dvb_frontend *fe, u32 *frequency) +static int get_if_frequency(struct dvb_frontend *fe, u32 *frequency) { struct tda_state *state = fe->tuner_priv; @@ -1222,7 +1222,7 @@ static struct dvb_tuner_ops tuner_ops = { .sleep = sleep, .set_params = set_params, .release = release, - .get_frequency = get_frequency, + .get_if_frequency = get_if_frequency, .get_bandwidth = get_bandwidth, }; -- cgit v0.10.2 From 0c61cc3ba4c9b74cfdd6a1ee07492199ffdd9818 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 6 Aug 2011 05:00:34 -0300 Subject: [media] dib7000p: return error code on allocation failure The goto needs to be moved after the assignment. Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index 4eb9c2b..ce8534f 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -1598,8 +1598,8 @@ int dib7000pc_detection(struct i2c_adapter *i2c_adap) return -ENOMEM; rx = kzalloc(2*sizeof(u8), GFP_KERNEL); if (!rx) { - goto rx_memory_error; ret = -ENOMEM; + goto rx_memory_error; } msg[0].buf = tx; -- cgit v0.10.2 From 2f098cb1c8b226a99595512e1029c8d1680f69cd Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 6 Aug 2011 05:01:51 -0300 Subject: [media] dib9000: return error code on failure The ret = -EIO needs to be before the goto. Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/frontends/dib9000.c b/drivers/media/dvb/frontends/dib9000.c index b931074..e276b11 100644 --- a/drivers/media/dvb/frontends/dib9000.c +++ b/drivers/media/dvb/frontends/dib9000.c @@ -1180,8 +1180,8 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p DibAcquireLock(&state->platform.risc.mem_mbx_lock); if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { - goto error; ret = -EIO; + goto error; } dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_UNION, -- cgit v0.10.2 From 83dc314bea4d701e3e5fa048314dfb02f7ef769c Mon Sep 17 00:00:00 2001 From: Andreas Oberritter Date: Mon, 8 Aug 2011 11:54:35 -0300 Subject: [media] DVB: Add SYS_TURBO for north american turbo code FEC Signed-off-by: Andreas Oberritter Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media/dvb/dvbproperty.xml b/Documentation/DocBook/media/dvb/dvbproperty.xml index 207e1a5..75bea04 100644 --- a/Documentation/DocBook/media/dvb/dvbproperty.xml +++ b/Documentation/DocBook/media/dvb/dvbproperty.xml @@ -352,6 +352,7 @@ typedef enum fe_delivery_system { SYS_CMMB, SYS_DAB, SYS_DVBT2, + SYS_TURBO, } fe_delivery_system_t; diff --git a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h index 36a3ed6..1b1094c 100644 --- a/include/linux/dvb/frontend.h +++ b/include/linux/dvb/frontend.h @@ -349,6 +349,7 @@ typedef enum fe_delivery_system { SYS_CMMB, SYS_DAB, SYS_DVBT2, + SYS_TURBO, } fe_delivery_system_t; struct dtv_cmds_h { -- cgit v0.10.2 From 14f55794b24506a82e995a92e599a3aa9d08781e Mon Sep 17 00:00:00 2001 From: Andreas Oberritter Date: Mon, 8 Aug 2011 11:54:36 -0300 Subject: [media] DVB: dvb_frontend: Fix compatibility criteria for satellite receivers identify a satellite receiver by its 'delivery_system' instead of 'modulation', which may overlap between different delivery systems. Signed-off-by: Andreas Oberritter Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index d02c32e..d218fe2 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1132,16 +1132,13 @@ static void dtv_property_adv_params_sync(struct dvb_frontend *fe) p->frequency = c->frequency; p->inversion = c->inversion; - switch(c->modulation) { - case PSK_8: - case APSK_16: - case APSK_32: - case QPSK: + if (c->delivery_system == SYS_DSS || + c->delivery_system == SYS_DVBS || + c->delivery_system == SYS_DVBS2 || + c->delivery_system == SYS_ISDBS || + c->delivery_system == SYS_TURBO) { p->u.qpsk.symbol_rate = c->symbol_rate; p->u.qpsk.fec_inner = c->fec_inner; - break; - default: - break; } /* Fake out a generic DVB-T request so we pass validation in the ioctl */ -- cgit v0.10.2 From 8fc74fdb0f877dc13981fb112ea6b16b04690fc2 Mon Sep 17 00:00:00 2001 From: Andreas Oberritter Date: Mon, 8 Aug 2011 11:54:37 -0300 Subject: [media] DVB: gp8psk-fe: use SYS_TURBO Signed-off-by: Andreas Oberritter Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c index 60d11e5..5426267 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk-fe.c +++ b/drivers/media/dvb/dvb-usb/gp8psk-fe.c @@ -144,19 +144,25 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend* fe, cmd[6] = (freq >> 16) & 0xff; cmd[7] = (freq >> 24) & 0xff; + /* backwards compatibility: DVB-S + 8-PSK were used for Turbo-FEC */ + if (c->delivery_system == SYS_DVBS && c->modulation == PSK_8) + c->delivery_system = SYS_TURBO; + switch (c->delivery_system) { case SYS_DVBS: - /* Allow QPSK and 8PSK (even for DVB-S) */ - if (c->modulation != QPSK && c->modulation != PSK_8) { + if (c->modulation != QPSK) { deb_fe("%s: unsupported modulation selected (%d)\n", __func__, c->modulation); return -EOPNOTSUPP; } c->fec_inner = FEC_AUTO; break; - case SYS_DVBS2: + case SYS_DVBS2: /* kept for backwards compatibility */ deb_fe("%s: DVB-S2 delivery system selected\n", __func__); break; + case SYS_TURBO: + deb_fe("%s: Turbo-FEC delivery system selected\n", __func__); + break; default: deb_fe("%s: unsupported delivery system selected (%d)\n", @@ -189,7 +195,10 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend* fe, default: cmd[9] = 5; break; } - cmd[8] = ADV_MOD_DVB_QPSK; + if (c->delivery_system == SYS_TURBO) + cmd[8] = ADV_MOD_TURBO_QPSK; + else + cmd[8] = ADV_MOD_DVB_QPSK; break; case PSK_8: /* PSK_8 is for compatibility with DN */ cmd[8] = ADV_MOD_TURBO_8PSK; -- cgit v0.10.2 From 7fc9da2a8f721efe9813fdff5d95a516999615a0 Mon Sep 17 00:00:00 2001 From: Andreas Oberritter Date: Sat, 3 Sep 2011 14:26:33 -0300 Subject: [media] DVB: improve documentation for satellite delivery systems - Move voltage and tone to DVB-S. - Add turbo code. - In DVB-S2 and turbo code sections, refer to DVB-S, as both are extensions to DVB-S. - Add modulation to DVB-S2. Signed-off-by: Andreas Oberritter Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media/dvb/dvbproperty.xml b/Documentation/DocBook/media/dvb/dvbproperty.xml index 75bea04..3bc8a61 100644 --- a/Documentation/DocBook/media/dvb/dvbproperty.xml +++ b/Documentation/DocBook/media/dvb/dvbproperty.xml @@ -810,6 +810,8 @@ typedef enum fe_hierarchy { DTV_INVERSION DTV_SYMBOL_RATE DTV_INNER_FEC + DTV_VOLTAGE + DTV_TONE Future implementations might add those two missing parameters: @@ -819,25 +821,18 @@ typedef enum fe_hierarchy {
DVB-S2 delivery system - The following parameters are valid for DVB-S2: + In addition to all parameters valid for DVB-S, DVB-S2 supports the following parameters: - DTV_API_VERSION - DTV_DELIVERY_SYSTEM - DTV_TUNE - DTV_CLEAR - DTV_FREQUENCY - DTV_INVERSION - DTV_SYMBOL_RATE - DTV_INNER_FEC - DTV_VOLTAGE - DTV_TONE + DTV_MODULATION DTV_PILOT DTV_ROLLOFF - Future implementations might add those two missing parameters: +
+
+ Turbo code delivery system + In addition to all parameters valid for DVB-S, turbo code supports the following parameters: - DTV_DISEQC_MASTER - DTV_DISEQC_SLAVE_REPLY + DTV_MODULATION
-- cgit v0.10.2 From 6fb2bdfa068676f436fd333c460549ed64549c5e Mon Sep 17 00:00:00 2001 From: Andreas Oberritter Date: Sat, 3 Sep 2011 14:26:34 -0300 Subject: [media] DVB: Change API version in documentation: 3 -> 5.4 Signed-off-by: Andreas Oberritter Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media/dvb/intro.xml b/Documentation/DocBook/media/dvb/intro.xml index c75dc7c..170064a 100644 --- a/Documentation/DocBook/media/dvb/intro.xml +++ b/Documentation/DocBook/media/dvb/intro.xml @@ -205,7 +205,7 @@ a partial path like: additional include file linux/dvb/version.h exists, which defines the constant DVB_API_VERSION. This document -describes DVB_API_VERSION 3. +describes DVB_API_VERSION 5.4.
-- cgit v0.10.2 From 0db4bf42baae95ddd457b0c4911e851c9169750e Mon Sep 17 00:00:00 2001 From: Steve Kerrison Date: Tue, 9 Aug 2011 07:16:21 -0300 Subject: [media] CXD2820R: Replace i2c message translation with repeater gate control This patch implements an i2c_gate_ctrl op for the cxd2820r. Thanks to Robert Schlabbach for identifying the register address and field to set. The old i2c intercept code that prefixed messages with a passthrough byte has been removed and the PCTV nanoStick T2 290e entry in em28xx-dvb has been updated appropriately. Tested for DVB-T2 use; I would appreciate it if somebody with DVB-C capabilities could test it as well - from inspection I cannot see any problems. This is patch v2. It fixes some schoolboy style errors and removes superfluous i2c entries in cxd2820r.h. Signed-off-by: Steve Kerrison Acked-by: Antti Palosaari Tested-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/frontends/cxd2820r.h b/drivers/media/dvb/frontends/cxd2820r.h index 2906582..03cab7b 100644 --- a/drivers/media/dvb/frontends/cxd2820r.h +++ b/drivers/media/dvb/frontends/cxd2820r.h @@ -93,9 +93,6 @@ extern struct dvb_frontend *cxd2820r_attach( struct i2c_adapter *i2c, struct dvb_frontend *fe ); -extern struct i2c_adapter *cxd2820r_get_tuner_i2c_adapter( - struct dvb_frontend *fe -); #else static inline struct dvb_frontend *cxd2820r_attach( const struct cxd2820r_config *config, @@ -106,12 +103,6 @@ static inline struct dvb_frontend *cxd2820r_attach( printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -static inline struct i2c_adapter *cxd2820r_get_tuner_i2c_adapter( - struct dvb_frontend *fe -) -{ - return NULL; -} #endif diff --git a/drivers/media/dvb/frontends/cxd2820r_c.c b/drivers/media/dvb/frontends/cxd2820r_c.c index 3c07d40..b85f501 100644 --- a/drivers/media/dvb/frontends/cxd2820r_c.c +++ b/drivers/media/dvb/frontends/cxd2820r_c.c @@ -335,4 +335,3 @@ int cxd2820r_get_tune_settings_c(struct dvb_frontend *fe, return 0; } - diff --git a/drivers/media/dvb/frontends/cxd2820r_core.c b/drivers/media/dvb/frontends/cxd2820r_core.c index d416e85..0151267 100644 --- a/drivers/media/dvb/frontends/cxd2820r_core.c +++ b/drivers/media/dvb/frontends/cxd2820r_core.c @@ -727,70 +727,20 @@ static void cxd2820r_release(struct dvb_frontend *fe) struct cxd2820r_priv *priv = fe->demodulator_priv; dbg("%s", __func__); - if (fe->ops.info.type == FE_OFDM) { - i2c_del_adapter(&priv->tuner_i2c_adapter); + if (fe->ops.info.type == FE_OFDM) kfree(priv); - } return; } -static u32 cxd2820r_tuner_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static int cxd2820r_tuner_i2c_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg msg[], int num) -{ - struct cxd2820r_priv *priv = i2c_get_adapdata(i2c_adap); - int ret; - u8 *obuf = kmalloc(msg[0].len + 2, GFP_KERNEL); - struct i2c_msg msg2[2] = { - { - .addr = priv->cfg.i2c_address, - .flags = 0, - .len = msg[0].len + 2, - .buf = obuf, - }, { - .addr = priv->cfg.i2c_address, - .flags = I2C_M_RD, - .len = msg[1].len, - .buf = msg[1].buf, - } - }; - - if (!obuf) - return -ENOMEM; - - obuf[0] = 0x09; - obuf[1] = (msg[0].addr << 1); - if (num == 2) { /* I2C read */ - obuf[1] = (msg[0].addr << 1) | I2C_M_RD; /* I2C RD flag */ - msg2[0].len = msg[0].len + 2 - 1; /* '-1' maybe HW bug ? */ - } - memcpy(&obuf[2], msg[0].buf, msg[0].len); - - ret = i2c_transfer(priv->i2c, msg2, num); - if (ret < 0) - warn("tuner i2c failed ret:%d", ret); - - kfree(obuf); - - return ret; -} - -static struct i2c_algorithm cxd2820r_tuner_i2c_algo = { - .master_xfer = cxd2820r_tuner_i2c_xfer, - .functionality = cxd2820r_tuner_i2c_func, -}; - -struct i2c_adapter *cxd2820r_get_tuner_i2c_adapter(struct dvb_frontend *fe) +static int cxd2820r_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) { struct cxd2820r_priv *priv = fe->demodulator_priv; - return &priv->tuner_i2c_adapter; + dbg("%s: %d", __func__, enable); + + /* Bit 0 of reg 0xdb in bank 0x00 controls I2C repeater */ + return cxd2820r_wr_reg_mask(priv, 0xdb, enable ? 1 : 0, 0x1); } -EXPORT_SYMBOL(cxd2820r_get_tuner_i2c_adapter); static struct dvb_frontend_ops cxd2820r_ops[2]; @@ -831,18 +781,6 @@ struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg, priv->fe[0].demodulator_priv = priv; priv->fe[1].demodulator_priv = priv; - /* create tuner i2c adapter */ - strlcpy(priv->tuner_i2c_adapter.name, - "CXD2820R tuner I2C adapter", - sizeof(priv->tuner_i2c_adapter.name)); - priv->tuner_i2c_adapter.algo = &cxd2820r_tuner_i2c_algo; - priv->tuner_i2c_adapter.algo_data = NULL; - i2c_set_adapdata(&priv->tuner_i2c_adapter, priv); - if (i2c_add_adapter(&priv->tuner_i2c_adapter) < 0) { - err("tuner I2C bus could not be initialized"); - goto error; - } - return &priv->fe[0]; } else { @@ -883,6 +821,7 @@ static struct dvb_frontend_ops cxd2820r_ops[2] = { .sleep = cxd2820r_sleep, .get_tune_settings = cxd2820r_get_tune_settings, + .i2c_gate_ctrl = cxd2820r_i2c_gate_ctrl, .get_frontend = cxd2820r_get_frontend, @@ -911,6 +850,7 @@ static struct dvb_frontend_ops cxd2820r_ops[2] = { .sleep = cxd2820r_sleep, .get_tune_settings = cxd2820r_get_tune_settings, + .i2c_gate_ctrl = cxd2820r_i2c_gate_ctrl, .set_frontend = cxd2820r_set_frontend, .get_frontend = cxd2820r_get_frontend, diff --git a/drivers/media/dvb/frontends/cxd2820r_priv.h b/drivers/media/dvb/frontends/cxd2820r_priv.h index 0c0ebc9..9553913 100644 --- a/drivers/media/dvb/frontends/cxd2820r_priv.h +++ b/drivers/media/dvb/frontends/cxd2820r_priv.h @@ -50,7 +50,6 @@ struct cxd2820r_priv { struct i2c_adapter *i2c; struct dvb_frontend fe[2]; struct cxd2820r_config cfg; - struct i2c_adapter tuner_i2c_adapter; struct mutex fe_lock; /* FE lock */ int active_fe:2; /* FE lock, -1=NONE, 0=DVB-T/T2, 1=DVB-C */ diff --git a/drivers/media/dvb/frontends/cxd2820r_t.c b/drivers/media/dvb/frontends/cxd2820r_t.c index 6582564..a04f9c8 100644 --- a/drivers/media/dvb/frontends/cxd2820r_t.c +++ b/drivers/media/dvb/frontends/cxd2820r_t.c @@ -446,4 +446,3 @@ int cxd2820r_get_tune_settings_t(struct dvb_frontend *fe, return 0; } - diff --git a/drivers/media/dvb/frontends/cxd2820r_t2.c b/drivers/media/dvb/frontends/cxd2820r_t2.c index c47b35c..6548588 100644 --- a/drivers/media/dvb/frontends/cxd2820r_t2.c +++ b/drivers/media/dvb/frontends/cxd2820r_t2.c @@ -420,4 +420,3 @@ int cxd2820r_get_tune_settings_t2(struct dvb_frontend *fe, return 0; } - diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index b3406eb..b606fc7 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c @@ -438,6 +438,7 @@ static struct cxd2820r_config em28xx_cxd2820r_config = { static struct tda18271_config em28xx_cxd2820r_tda18271_config = { .output_opt = TDA18271_OUTPUT_LT_OFF, + .gate = TDA18271_GATE_DIGITAL, }; /* ------------------------------------------------------------------ */ @@ -751,11 +752,9 @@ static int em28xx_dvb_init(struct em28xx *dev) dvb->fe[0] = dvb_attach(cxd2820r_attach, &em28xx_cxd2820r_config, &dev->i2c_adap, NULL); if (dvb->fe[0]) { - struct i2c_adapter *i2c_tuner; - i2c_tuner = cxd2820r_get_tuner_i2c_adapter(dvb->fe[0]); /* FE 0 attach tuner */ if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60, - i2c_tuner, &em28xx_cxd2820r_tda18271_config)) { + &dev->i2c_adap, &em28xx_cxd2820r_tda18271_config)) { dvb_frontend_detach(dvb->fe[0]); result = -EINVAL; goto out_free; @@ -766,7 +765,7 @@ static int em28xx_dvb_init(struct em28xx *dev) dvb->fe[1]->id = 1; /* FE 1 attach tuner */ if (!dvb_attach(tda18271_attach, dvb->fe[1], 0x60, - i2c_tuner, &em28xx_cxd2820r_tda18271_config)) { + &dev->i2c_adap, &em28xx_cxd2820r_tda18271_config)) { dvb_frontend_detach(dvb->fe[1]); /* leave FE 0 still active */ } -- cgit v0.10.2 From e9013fb6eb397df9fd2e71d4f31a8bad4e65d046 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 9 Aug 2011 12:52:38 -0300 Subject: [media] ddbridge: fix ddb_ioctl() There were a several problems in this function: 1) Potential integer overflow in the comparison: if (fio.write_len + fio.read_len > 1028) { 2) If the user gave bogus values for write_len and read_len then returning -EINVAL is more appropriate than returning -ENOMEM. 3) wbuf was set to the address of an array and could never be NULL so I removed the pointless NULL check. 4) The call to vfree(wbuf) was improper. That array is part of a larger struct and isn't allocated by itself. 5) flashio() can't actually fail, but we may as well add error handling in case this changes later. 6) In the default case where an ioctl is not implemented then returning -ENOTTY is more appropriate than returning -EFAULT. Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/ddbridge/ddbridge-core.c b/drivers/media/dvb/ddbridge/ddbridge-core.c index 573d540..fe56703 100644 --- a/drivers/media/dvb/ddbridge/ddbridge-core.c +++ b/drivers/media/dvb/ddbridge/ddbridge-core.c @@ -1438,7 +1438,7 @@ static long ddb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct ddb *dev = file->private_data; void *parg = (void *)arg; - int res = -EFAULT; + int res; switch (cmd) { case IOCTL_DDB_FLASHIO: @@ -1447,29 +1447,29 @@ static long ddb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) u8 *rbuf, *wbuf; if (copy_from_user(&fio, parg, sizeof(fio))) - break; - if (fio.write_len + fio.read_len > 1028) { - printk(KERN_ERR "IOBUF too small\n"); - return -ENOMEM; - } + return -EFAULT; + + if (fio.write_len > 1028 || fio.read_len > 1028) + return -EINVAL; + if (fio.write_len + fio.read_len > 1028) + return -EINVAL; + wbuf = &dev->iobuf[0]; - if (!wbuf) - return -ENOMEM; rbuf = wbuf + fio.write_len; - if (copy_from_user(wbuf, fio.write_buf, fio.write_len)) { - vfree(wbuf); - break; - } - res = flashio(dev, wbuf, fio.write_len, - rbuf, fio.read_len); + + if (copy_from_user(wbuf, fio.write_buf, fio.write_len)) + return -EFAULT; + res = flashio(dev, wbuf, fio.write_len, rbuf, fio.read_len); + if (res) + return res; if (copy_to_user(fio.read_buf, rbuf, fio.read_len)) - res = -EFAULT; + return -EFAULT; break; } default: - break; + return -ENOTTY; } - return res; + return 0; } static const struct file_operations ddb_fops = { -- cgit v0.10.2 From e6a476fd5f6593e023250b0ab00b0b68117a5da2 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 10 Aug 2011 06:32:29 -0300 Subject: [media] MAINTAINERS: add entries for s5p-mfc and s5p-tv drivers Both driver has been merged to v3.1-rc1, so add its authors as maintainers. Signed-off-by: Marek Szyprowski Signed-off-by: Kamil Debski Signed-off-by: Tomasz Stanislawski Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/MAINTAINERS b/MAINTAINERS index 1d2e79d..7739e4c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1084,6 +1084,24 @@ F: arch/arm/plat-s5p/dev-fimc* F: arch/arm/plat-samsung/include/plat/*fimc* F: drivers/media/video/s5p-fimc/ +ARM/SAMSUNG S5P SERIES Multi Format Codec (MFC) SUPPORT +M: Kyungmin Park +M: Kamil Debski +L: linux-arm-kernel@lists.infradead.org +L: linux-media@vger.kernel.org +S: Maintained +F: arch/arm/plat-s5p/dev-mfc.c +F: drivers/media/video/s5p-mfc/ + +ARM/SAMSUNG S5P SERIES TV SUBSYSTEM SUPPORT +M: Kyungmin Park +M: Tomasz Stanislawski +L: linux-arm-kernel@lists.infradead.org +L: linux-media@vger.kernel.org +S: Maintained +F: arch/arm/plat-s5p/dev-tv.c +F: drivers/media/video/s5p-tv/ + ARM/SHMOBILE ARM ARCHITECTURE M: Paul Mundt M: Magnus Damm -- cgit v0.10.2 From 0163b924c5c54f9737357f622fd923a9d80556bd Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 12 Aug 2011 08:40:08 -0300 Subject: [media] drivers/media/video/zr364xx.c: add missing cleanup code It seems just as necessary to free cam->vdev and cam in this error case as in the next one. Signed-off-by: Julia Lawall Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c index c492846..e78cf94 100644 --- a/drivers/media/video/zr364xx.c +++ b/drivers/media/video/zr364xx.c @@ -1638,6 +1638,9 @@ static int zr364xx_probe(struct usb_interface *intf, if (!cam->read_endpoint) { dev_err(&intf->dev, "Could not find bulk-in endpoint\n"); + video_device_release(cam->vdev); + kfree(cam); + cam = NULL; return -ENOMEM; } -- cgit v0.10.2 From 63f409a444fa295247363a28381314683d6f4596 Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Sun, 14 Aug 2011 09:18:46 -0300 Subject: [media] Add missing OK key to PCTV IR keymap Hi, The following patch adds the IR code for the missing "OK" key to the Pinnacle PCTV HD map. This map is now used by the PCTV 290e DVB-T2 device, whose remote control has 26 buttons. Signed-off-by: Chris Rankin Reviewed-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c index 8d558ae..31fc64cd 100644 --- a/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c +++ b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c @@ -20,6 +20,7 @@ static struct rc_map_table pinnacle_pctv_hd[] = { { 0x0701, KEY_MENU }, /* Pinnacle logo */ { 0x0739, KEY_POWER }, { 0x0703, KEY_VOLUMEUP }, + { 0x0705, KEY_OK }, { 0x0709, KEY_VOLUMEDOWN }, { 0x0706, KEY_CHANNELUP }, { 0x070c, KEY_CHANNELDOWN }, -- cgit v0.10.2 From 3f5c14d3d3d7a3f508f2fffa62731f13f8efdfba Mon Sep 17 00:00:00 2001 From: Arnaud Lacombe Date: Mon, 15 Aug 2011 02:07:08 -0300 Subject: [media] drivers/media: do not use EXTRA_CFLAGS Usage of these flags has been deprecated for nearly 4 years by: commit f77bf01425b11947eeb3b5b54685212c302741b8 Author: Sam Ravnborg Date: Mon Oct 15 22:25:06 2007 +0200 kbuild: introduce ccflags-y, asflags-y and ldflags-y Moreover, these flags (at least EXTRA_CFLAGS) have been documented for command line use. By default, gmake(1) do not override command line setting, so this is likely to result in build failure or unexpected behavior. Replace their usage by Kbuild's `{as,cc,ld}flags-y'. Cc: Sam Ravnborg Cc: Mauro Carvalho Chehab Cc: linux-media@vger.kernel.org Signed-off-by: Arnaud Lacombe Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile index 20d24fc..196c12a 100644 --- a/drivers/media/common/tuners/Makefile +++ b/drivers/media/common/tuners/Makefile @@ -28,5 +28,5 @@ obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/dvb/frontends diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile index b97cf72..3d04a8d 100644 --- a/drivers/media/dvb/b2c2/Makefile +++ b/drivers/media/dvb/b2c2/Makefile @@ -12,5 +12,5 @@ obj-$(CONFIG_DVB_B2C2_FLEXCOP_PCI) += b2c2-flexcop-pci.o b2c2-flexcop-usb-objs = flexcop-usb.o obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ -EXTRA_CFLAGS += -Idrivers/media/common/tuners/ +ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ +ccflags-y += -Idrivers/media/common/tuners/ diff --git a/drivers/media/dvb/bt8xx/Makefile b/drivers/media/dvb/bt8xx/Makefile index d98f1d4..0713b3a 100644 --- a/drivers/media/dvb/bt8xx/Makefile +++ b/drivers/media/dvb/bt8xx/Makefile @@ -1,6 +1,6 @@ obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends -EXTRA_CFLAGS += -Idrivers/media/video/bt8xx -EXTRA_CFLAGS += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/video/bt8xx +ccflags-y += -Idrivers/media/common/tuners diff --git a/drivers/media/dvb/ddbridge/Makefile b/drivers/media/dvb/ddbridge/Makefile index de4fe19..cf7214e 100644 --- a/drivers/media/dvb/ddbridge/Makefile +++ b/drivers/media/dvb/ddbridge/Makefile @@ -6,9 +6,9 @@ ddbridge-objs := ddbridge-core.o obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends/ -EXTRA_CFLAGS += -Idrivers/media/common/tuners/ +ccflags-y += -Idrivers/media/dvb/dvb-core/ +ccflags-y += -Idrivers/media/dvb/frontends/ +ccflags-y += -Idrivers/media/common/tuners/ # For the staging CI driver cxd2099 -EXTRA_CFLAGS += -Idrivers/staging/cxd2099/ +ccflags-y += -Idrivers/staging/cxd2099/ diff --git a/drivers/media/dvb/dm1105/Makefile b/drivers/media/dvb/dm1105/Makefile index 8ac28b0..95a008b 100644 --- a/drivers/media/dvb/dm1105/Makefile +++ b/drivers/media/dvb/dm1105/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_DVB_DM1105) += dm1105.o -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 3494d41..03ae657 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -97,7 +97,7 @@ obj-$(CONFIG_DVB_USB_TECHNISAT_USB2) += dvb-usb-technisat-usb2.o dvb-usb-it913x-objs := it913x.o obj-$(CONFIG_DVB_USB_IT913X) += dvb-usb-it913x.o -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ +ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ # due to tuner-xc3028 -EXTRA_CFLAGS += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/common/tuners diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 3da75ea..18d045d 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -2,8 +2,8 @@ # Makefile for the kernel DVB frontend device drivers. # -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -EXTRA_CFLAGS += -Idrivers/media/common/tuners/ +ccflags-y += -Idrivers/media/dvb/dvb-core/ +ccflags-y += -Idrivers/media/common/tuners/ stb0899-objs = stb0899_drv.o stb0899_algo.o stv0900-objs = stv0900_core.o stv0900_sw.o diff --git a/drivers/media/dvb/mantis/Makefile b/drivers/media/dvb/mantis/Makefile index 98dc5cd..ec8116d 100644 --- a/drivers/media/dvb/mantis/Makefile +++ b/drivers/media/dvb/mantis/Makefile @@ -25,4 +25,4 @@ obj-$(CONFIG_MANTIS_CORE) += mantis_core.o obj-$(CONFIG_DVB_MANTIS) += mantis.o obj-$(CONFIG_DVB_HOPPER) += hopper.o -EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ +ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff --git a/drivers/media/dvb/ngene/Makefile b/drivers/media/dvb/ngene/Makefile index 2bc9687..8987361 100644 --- a/drivers/media/dvb/ngene/Makefile +++ b/drivers/media/dvb/ngene/Makefile @@ -6,9 +6,9 @@ ngene-objs := ngene-core.o ngene-i2c.o ngene-cards.o ngene-dvb.o obj-$(CONFIG_DVB_NGENE) += ngene.o -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends/ -EXTRA_CFLAGS += -Idrivers/media/common/tuners/ +ccflags-y += -Idrivers/media/dvb/dvb-core/ +ccflags-y += -Idrivers/media/dvb/frontends/ +ccflags-y += -Idrivers/media/common/tuners/ # For the staging CI driver cxd2099 -EXTRA_CFLAGS += -Idrivers/staging/cxd2099/ +ccflags-y += -Idrivers/staging/cxd2099/ diff --git a/drivers/media/dvb/pluto2/Makefile b/drivers/media/dvb/pluto2/Makefile index 7ac1287..7008223 100644 --- a/drivers/media/dvb/pluto2/Makefile +++ b/drivers/media/dvb/pluto2/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_DVB_PLUTO2) += pluto2.o -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ +ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff --git a/drivers/media/dvb/pt1/Makefile b/drivers/media/dvb/pt1/Makefile index a66da17..d80d8e8 100644 --- a/drivers/media/dvb/pt1/Makefile +++ b/drivers/media/dvb/pt1/Makefile @@ -2,4 +2,4 @@ earth-pt1-objs := pt1.o va1j5jf8007s.o va1j5jf8007t.o obj-$(CONFIG_DVB_PT1) += earth-pt1.o -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/dvb/dvb-core -Idrivers/media/dvb/frontends diff --git a/drivers/media/dvb/siano/Makefile b/drivers/media/dvb/siano/Makefile index c54140b..f233b57 100644 --- a/drivers/media/dvb/siano/Makefile +++ b/drivers/media/dvb/siano/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_SMS_SIANO_MDTV) += smsmdtv.o smsdvb.o obj-$(CONFIG_SMS_USB_DRV) += smsusb.o obj-$(CONFIG_SMS_SDIO_DRV) += smssdio.o -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m) +ccflags-y += $(extra-cflags-y) $(extra-cflags-m) diff --git a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile index 8a4d5bb..f6e8693 100644 --- a/drivers/media/dvb/ttpci/Makefile +++ b/drivers/media/dvb/ttpci/Makefile @@ -17,5 +17,5 @@ obj-$(CONFIG_DVB_BUDGET_CI) += budget-ci.o obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ -EXTRA_CFLAGS += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ +ccflags-y += -Idrivers/media/common/tuners diff --git a/drivers/media/dvb/ttusb-budget/Makefile b/drivers/media/dvb/ttusb-budget/Makefile index fbe2b95..8d6c4ac 100644 --- a/drivers/media/dvb/ttusb-budget/Makefile +++ b/drivers/media/dvb/ttusb-budget/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_DVB_TTUSB_BUDGET) += dvb-ttusb-budget.o -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends diff --git a/drivers/media/dvb/ttusb-dec/Makefile b/drivers/media/dvb/ttusb-dec/Makefile index 2d70a82..ed28b53 100644 --- a/drivers/media/dvb/ttusb-dec/Makefile +++ b/drivers/media/dvb/ttusb-dec/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o ttusbdecfe.o -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ +ccflags-y += -Idrivers/media/dvb/dvb-core/ diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile index f484a6e..390daf9 100644 --- a/drivers/media/radio/Makefile +++ b/drivers/media/radio/Makefile @@ -27,4 +27,4 @@ obj-$(CONFIG_RADIO_TIMBERDALE) += radio-timb.o obj-$(CONFIG_RADIO_WL1273) += radio-wl1273.o obj-$(CONFIG_RADIO_WL128X) += wl128x/ -EXTRA_CFLAGS += -Isound +ccflags-y += -Isound diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 2723900..c06f515 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -190,6 +190,6 @@ obj-y += davinci/ obj-$(CONFIG_ARCH_OMAP) += omap/ -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends -EXTRA_CFLAGS += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/common/tuners diff --git a/drivers/media/video/au0828/Makefile b/drivers/media/video/au0828/Makefile index 5c7f2f7..bd22223 100644 --- a/drivers/media/video/au0828/Makefile +++ b/drivers/media/video/au0828/Makefile @@ -2,8 +2,8 @@ au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o au0828-vid obj-$(CONFIG_VIDEO_AU0828) += au0828.o -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/dvb/frontends -EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m) +ccflags-y += $(extra-cflags-y) $(extra-cflags-m) diff --git a/drivers/media/video/bt8xx/Makefile b/drivers/media/video/bt8xx/Makefile index e415f6f..3f9a2b2 100644 --- a/drivers/media/video/bt8xx/Makefile +++ b/drivers/media/video/bt8xx/Makefile @@ -8,6 +8,6 @@ bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \ obj-$(CONFIG_VIDEO_BT848) += bttv.o -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/video +ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core diff --git a/drivers/media/video/cx18/Makefile b/drivers/media/video/cx18/Makefile index 2fadd9d..a86bab5 100644 --- a/drivers/media/video/cx18/Makefile +++ b/drivers/media/video/cx18/Makefile @@ -8,6 +8,6 @@ cx18-alsa-objs := cx18-alsa-main.o cx18-alsa-pcm.o obj-$(CONFIG_VIDEO_CX18) += cx18.o obj-$(CONFIG_VIDEO_CX18_ALSA) += cx18-alsa.o -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends -EXTRA_CFLAGS += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/common/tuners diff --git a/drivers/media/video/cx231xx/Makefile b/drivers/media/video/cx231xx/Makefile index 2c24843..b334897 100644 --- a/drivers/media/video/cx231xx/Makefile +++ b/drivers/media/video/cx231xx/Makefile @@ -8,9 +8,9 @@ obj-$(CONFIG_VIDEO_CX231XX) += cx231xx.o obj-$(CONFIG_VIDEO_CX231XX_ALSA) += cx231xx-alsa.o obj-$(CONFIG_VIDEO_CX231XX_DVB) += cx231xx-dvb.o -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-usb +ccflags-y += -Idrivers/media/video +ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/dvb/dvb-usb diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile index 23293c7..185cc01 100644 --- a/drivers/media/video/cx23885/Makefile +++ b/drivers/media/video/cx23885/Makefile @@ -7,9 +7,9 @@ cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o \ obj-$(CONFIG_VIDEO_CX23885) += cx23885.o obj-$(CONFIG_MEDIA_ALTERA_CI) += altera-ci.o -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/video +ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/dvb/frontends -EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m) +ccflags-y += $(extra-cflags-y) $(extra-cflags-m) diff --git a/drivers/media/video/cx25840/Makefile b/drivers/media/video/cx25840/Makefile index 2ee96d3..dc40dde 100644 --- a/drivers/media/video/cx25840/Makefile +++ b/drivers/media/video/cx25840/Makefile @@ -3,4 +3,4 @@ cx25840-objs := cx25840-core.o cx25840-audio.o cx25840-firmware.o \ obj-$(CONFIG_VIDEO_CX25840) += cx25840.o -EXTRA_CFLAGS += -Idrivers/media/video +ccflags-y += -Idrivers/media/video diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile index 5b7e267..c1a2785 100644 --- a/drivers/media/video/cx88/Makefile +++ b/drivers/media/video/cx88/Makefile @@ -10,7 +10,7 @@ obj-$(CONFIG_VIDEO_CX88_BLACKBIRD) += cx88-blackbird.o obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/video +ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile index 38aaa00..2abdf76 100644 --- a/drivers/media/video/em28xx/Makefile +++ b/drivers/media/video/em28xx/Makefile @@ -9,8 +9,8 @@ obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/video +ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/gspca/gl860/Makefile b/drivers/media/video/gspca/gl860/Makefile index 13c9403..f511ecc 100644 --- a/drivers/media/video/gspca/gl860/Makefile +++ b/drivers/media/video/gspca/gl860/Makefile @@ -6,5 +6,5 @@ gspca_gl860-objs := gl860.o \ gl860-ov9655.o \ gl860-mi2020.o -EXTRA_CFLAGS += -Idrivers/media/video/gspca +ccflags-y += -Idrivers/media/video/gspca diff --git a/drivers/media/video/gspca/m5602/Makefile b/drivers/media/video/gspca/m5602/Makefile index bf7a19a..7f52961 100644 --- a/drivers/media/video/gspca/m5602/Makefile +++ b/drivers/media/video/gspca/m5602/Makefile @@ -8,4 +8,4 @@ gspca_m5602-objs := m5602_core.o \ m5602_s5k83a.o \ m5602_s5k4aa.o -EXTRA_CFLAGS += -Idrivers/media/video/gspca +ccflags-y += -Idrivers/media/video/gspca diff --git a/drivers/media/video/gspca/stv06xx/Makefile b/drivers/media/video/gspca/stv06xx/Makefile index 2f3c3a6..5b318fa 100644 --- a/drivers/media/video/gspca/stv06xx/Makefile +++ b/drivers/media/video/gspca/stv06xx/Makefile @@ -6,5 +6,5 @@ gspca_stv06xx-objs := stv06xx.o \ stv06xx_pb0100.o \ stv06xx_st6422.o -EXTRA_CFLAGS += -Idrivers/media/video/gspca +ccflags-y += -Idrivers/media/video/gspca diff --git a/drivers/media/video/hdpvr/Makefile b/drivers/media/video/hdpvr/Makefile index 3baa9f6..52f057f 100644 --- a/drivers/media/video/hdpvr/Makefile +++ b/drivers/media/video/hdpvr/Makefile @@ -2,6 +2,6 @@ hdpvr-objs := hdpvr-control.o hdpvr-core.o hdpvr-video.o hdpvr-i2c.o obj-$(CONFIG_VIDEO_HDPVR) += hdpvr.o -EXTRA_CFLAGS += -Idrivers/media/video +ccflags-y += -Idrivers/media/video -EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m) +ccflags-y += $(extra-cflags-y) $(extra-cflags-m) diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile index 26ce0d6..71ab76a 100644 --- a/drivers/media/video/ivtv/Makefile +++ b/drivers/media/video/ivtv/Makefile @@ -7,8 +7,8 @@ ivtv-objs := ivtv-routing.o ivtv-cards.o ivtv-controls.o \ obj-$(CONFIG_VIDEO_IVTV) += ivtv.o obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/video +ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/omap3isp/Makefile b/drivers/media/video/omap3isp/Makefile index b1b34477..e8847e7 100644 --- a/drivers/media/video/omap3isp/Makefile +++ b/drivers/media/video/omap3isp/Makefile @@ -1,8 +1,6 @@ # Makefile for OMAP3 ISP driver -ifdef CONFIG_VIDEO_OMAP3_DEBUG -EXTRA_CFLAGS += -DDEBUG -endif +ccflags-$(CONFIG_VIDEO_OMAP3_DEBUG) += -DDEBUG omap3-isp-objs += \ isp.o ispqueue.o ispvideo.o \ diff --git a/drivers/media/video/pvrusb2/Makefile b/drivers/media/video/pvrusb2/Makefile index de2fc14..c17f37d 100644 --- a/drivers/media/video/pvrusb2/Makefile +++ b/drivers/media/video/pvrusb2/Makefile @@ -16,7 +16,7 @@ pvrusb2-objs := pvrusb2-i2c-core.o \ obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2.o -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/video +ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile index 8a5ff4d..a646ccf 100644 --- a/drivers/media/video/saa7134/Makefile +++ b/drivers/media/video/saa7134/Makefile @@ -10,7 +10,7 @@ obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/video +ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/saa7164/Makefile b/drivers/media/video/saa7164/Makefile index 6303a8e..ecd5811 100644 --- a/drivers/media/video/saa7164/Makefile +++ b/drivers/media/video/saa7164/Makefile @@ -4,9 +4,9 @@ saa7164-objs := saa7164-cards.o saa7164-core.o saa7164-i2c.o saa7164-dvb.o \ obj-$(CONFIG_VIDEO_SAA7164) += saa7164.o -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/video +ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/dvb/frontends -EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m) +ccflags-y += $(extra-cflags-y) $(extra-cflags-m) diff --git a/drivers/media/video/tlg2300/Makefile b/drivers/media/video/tlg2300/Makefile index 81bb7fd..ea09b9a 100644 --- a/drivers/media/video/tlg2300/Makefile +++ b/drivers/media/video/tlg2300/Makefile @@ -2,8 +2,8 @@ poseidon-objs := pd-video.o pd-alsa.o pd-dvb.o pd-radio.o pd-main.o obj-$(CONFIG_VIDEO_TLG2300) += poseidon.o -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +ccflags-y += -Idrivers/media/video +ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/usbvision/Makefile b/drivers/media/video/usbvision/Makefile index 3387187..aea1e3b 100644 --- a/drivers/media/video/usbvision/Makefile +++ b/drivers/media/video/usbvision/Makefile @@ -2,5 +2,5 @@ usbvision-objs := usbvision-core.o usbvision-video.o usbvision-i2c.o usbvision- obj-$(CONFIG_VIDEO_USBVISION) += usbvision.o -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/video +ccflags-y += -Idrivers/media/common/tuners -- cgit v0.10.2 From 674ce34333f49a5aea778e7659e7fe637dc1dab3 Mon Sep 17 00:00:00 2001 From: Andreas Oberritter Date: Tue, 16 Aug 2011 11:04:06 -0300 Subject: [media] DVB: dvb_frontend: remove static assignments from dtv_property_cache_sync() dtv_property_cache_init(). dtv_property_process_get(). overwritten with invalid values, leading to partially incorrect results when calling FE_GET_PROPERTY. Signed-off-by: Andreas Oberritter Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index d218fe2..a716627 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1019,6 +1019,29 @@ static int is_legacy_delivery_system(fe_delivery_system_t s) return 0; } +/* Initialize the cache with some default values derived from the + * legacy frontend_info structure. + */ +static void dtv_property_cache_init(struct dvb_frontend *fe, + struct dtv_frontend_properties *c) +{ + switch (fe->ops.info.type) { + case FE_QPSK: + c->modulation = QPSK; /* implied for DVB-S in legacy API */ + c->rolloff = ROLLOFF_35;/* implied for DVB-S */ + c->delivery_system = SYS_DVBS; + break; + case FE_QAM: + c->delivery_system = SYS_DVBC_ANNEX_AC; + break; + case FE_OFDM: + c->delivery_system = SYS_DVBT; + break; + case FE_ATSC: + break; + } +} + /* Synchronise the legacy tuning parameters into the cache, so that demodulator * drivers can use a single set_frontend tuning function, regardless of whether * it's being used for the legacy or new API, reducing code and complexity. @@ -1032,17 +1055,13 @@ static void dtv_property_cache_sync(struct dvb_frontend *fe, switch (fe->ops.info.type) { case FE_QPSK: - c->modulation = QPSK; /* implied for DVB-S in legacy API */ - c->rolloff = ROLLOFF_35;/* implied for DVB-S */ c->symbol_rate = p->u.qpsk.symbol_rate; c->fec_inner = p->u.qpsk.fec_inner; - c->delivery_system = SYS_DVBS; break; case FE_QAM: c->symbol_rate = p->u.qam.symbol_rate; c->fec_inner = p->u.qam.fec_inner; c->modulation = p->u.qam.modulation; - c->delivery_system = SYS_DVBC_ANNEX_AC; break; case FE_OFDM: if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) @@ -1060,7 +1079,6 @@ static void dtv_property_cache_sync(struct dvb_frontend *fe, c->transmission_mode = p->u.ofdm.transmission_mode; c->guard_interval = p->u.ofdm.guard_interval; c->hierarchy = p->u.ofdm.hierarchy_information; - c->delivery_system = SYS_DVBT; break; case FE_ATSC: c->modulation = p->u.vsb.modulation; @@ -1821,6 +1839,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file, memcpy (&fepriv->parameters_in, parg, sizeof (struct dvb_frontend_parameters)); + dtv_property_cache_init(fe, c); dtv_property_cache_sync(fe, c, &fepriv->parameters_in); } -- cgit v0.10.2 From c0f856d3f0e0643c617a86756fd58f23766cfe25 Mon Sep 17 00:00:00 2001 From: Andreas Oberritter Date: Tue, 16 Aug 2011 11:04:07 -0300 Subject: [media] DVB: increment minor version after addition of SYS_TURBO Signed-off-by: Andreas Oberritter Signed-off-by: Mauro Carvalho Chehab diff --git a/include/linux/dvb/version.h b/include/linux/dvb/version.h index 1421cc8..66594b1 100644 --- a/include/linux/dvb/version.h +++ b/include/linux/dvb/version.h @@ -24,6 +24,6 @@ #define _DVBVERSION_H_ #define DVB_API_VERSION 5 -#define DVB_API_VERSION_MINOR 3 +#define DVB_API_VERSION_MINOR 4 #endif /*_DVBVERSION_H_*/ -- cgit v0.10.2 From f38f33395232db1a03d21b992af1714cbffbdec4 Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Sat, 20 Aug 2011 08:08:34 -0300 Subject: [media] em28xx: pass correct buffer size to snprintf snprintf()'s size parameter includes space for the terminating '\0' character. Signed-off-by: Chris Rankin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 3e3959f..d947026 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -3154,7 +3154,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, goto err; } - snprintf(dev->name, 29, "em28xx #%d", nr); + snprintf(dev->name, sizeof(dev->name), "em28xx #%d", nr); dev->devno = nr; dev->model = id->driver_info; dev->alt = -1; -- cgit v0.10.2 From 38b61eb2dac06fdc42815b004e9824d8196cfcfb Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Sat, 20 Aug 2011 08:21:03 -0300 Subject: [media] em28xx: use atomic bit operations for devices-in-use mask Use atomic bit operations for the em28xx_devused mask, to prevent an unlikely race condition should two adapters be plugged in simultaneously. The operations also clearer than explicit bit manipulation anyway. Signed-off-by: Chris Rankin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index d947026..677db14 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -60,7 +60,7 @@ static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; module_param_array(card, int, NULL, 0444); MODULE_PARM_DESC(card, "card type"); -/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */ +/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS - 1 */ static unsigned long em28xx_devused; struct em28xx_hash_table { @@ -2793,7 +2793,7 @@ void em28xx_release_resources(struct em28xx *dev) usb_put_dev(dev->udev); /* Mark device as unused */ - em28xx_devused &= ~(1 << dev->devno); + clear_bit(dev->devno, &em28xx_devused); }; /* @@ -3015,8 +3015,16 @@ static int em28xx_usb_probe(struct usb_interface *interface, udev = usb_get_dev(interface_to_usbdev(interface)); /* Check to see next free device and mark as used */ - nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS); - em28xx_devused |= 1<= EM28XX_MAXBOARDS) { + /* No free device slots */ + printk(DRIVER_NAME ": Supports only %i em28xx boards.\n", + EM28XX_MAXBOARDS); + retval = -ENOMEM; + goto err_no_slot; + } + } while (test_and_set_bit(nr, &em28xx_devused)); /* Don't register audio interfaces */ if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { @@ -3027,7 +3035,6 @@ static int em28xx_usb_probe(struct usb_interface *interface, ifnum, interface->altsetting[0].desc.bInterfaceClass); - em28xx_devused &= ~(1<= EM28XX_MAXBOARDS) { - printk(DRIVER_NAME ": Supports only %i em28xx boards.\n", - EM28XX_MAXBOARDS); - em28xx_devused &= ~(1<alt_max_pkt_size == NULL) { em28xx_errdev("out of memory!\n"); - em28xx_devused &= ~(1<lock); retval = em28xx_init_dev(&dev, udev, interface, nr); if (retval) { - em28xx_devused &= ~(1<devno); mutex_unlock(&dev->lock); kfree(dev); goto err; @@ -3220,6 +3215,10 @@ static int em28xx_usb_probe(struct usb_interface *interface, return 0; err: + clear_bit(nr, &em28xx_devused); + +err_no_slot: + usb_put_dev(udev); return retval; } -- cgit v0.10.2 From 6c03e38b34dcfcdfa2f10cf984995a48f030f039 Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Sat, 20 Aug 2011 08:28:17 -0300 Subject: [media] em28xx: clean up resources should init fail This patch ensures that the em28xx_init_dev() function cleans up after itself, in the event that it fails. This isimportant because the struct em28xx will be deallocated if em28xx_init_dev() returns an error. [mchehab@redhat.com: Fix merge conflicts and simplify the goto labels] Signed-off-by: Chris Rankin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 677db14..5fddcd0 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -2806,7 +2806,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, { struct em28xx *dev = *devhandle; int retval; - int errCode; dev->udev = udev; mutex_init(&dev->ctrl_urb_lock); @@ -2883,8 +2882,8 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, } if (dev->is_audio_only) { - errCode = em28xx_audio_setup(dev); - if (errCode) + retval = em28xx_audio_setup(dev); + if (retval) return -ENODEV; em28xx_add_into_devlist(dev); em28xx_init_extension(dev); @@ -2903,7 +2902,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, /* Resets I2C speed */ em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed); if (retval < 0) { - em28xx_errdev("%s: em28xx_write_regs_req failed!" + em28xx_errdev("%s: em28xx_write_reg failed!" " retval [%d]\n", __func__, retval); return retval; @@ -2917,12 +2916,11 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, } /* register i2c bus */ - errCode = em28xx_i2c_register(dev); - if (errCode < 0) { - v4l2_device_unregister(&dev->v4l2_dev); - em28xx_errdev("%s: em28xx_i2c_register - errCode [%d]!\n", - __func__, errCode); - return errCode; + retval = em28xx_i2c_register(dev); + if (retval < 0) { + em28xx_errdev("%s: em28xx_i2c_register - error [%d]!\n", + __func__, retval); + goto unregister_dev; } /* @@ -2936,11 +2934,11 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, em28xx_card_setup(dev); /* Configure audio */ - errCode = em28xx_audio_setup(dev); - if (errCode < 0) { - v4l2_device_unregister(&dev->v4l2_dev); - em28xx_errdev("%s: Error while setting audio - errCode [%d]!\n", - __func__, errCode); + retval = em28xx_audio_setup(dev); + if (retval < 0) { + em28xx_errdev("%s: Error while setting audio - error [%d]!\n", + __func__, retval); + goto fail; } /* wake i2c devices */ @@ -2954,31 +2952,28 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, if (dev->board.has_msp34xx) { /* Send a reset to other chips via gpio */ - errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7); - if (errCode < 0) { - em28xx_errdev("%s: em28xx_write_regs_req - " - "msp34xx(1) failed! errCode [%d]\n", - __func__, errCode); - return errCode; + retval = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7); + if (retval < 0) { + em28xx_errdev("%s: em28xx_write_reg - " + "msp34xx(1) failed! error [%d]\n", + __func__, retval); + goto fail; } msleep(3); - errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff); - if (errCode < 0) { - em28xx_errdev("%s: em28xx_write_regs_req - " - "msp34xx(2) failed! errCode [%d]\n", - __func__, errCode); - return errCode; + retval = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff); + if (retval < 0) { + em28xx_errdev("%s: em28xx_write_reg - " + "msp34xx(2) failed! error [%d]\n", + __func__, retval); + goto fail; } msleep(3); } - em28xx_add_into_devlist(dev); - retval = em28xx_register_analog_devices(dev); if (retval < 0) { - em28xx_release_resources(dev); - goto fail_reg_devices; + goto fail; } em28xx_init_extension(dev); @@ -2988,7 +2983,12 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, return 0; -fail_reg_devices: +fail: + em28xx_i2c_unregister(dev); + +unregister_dev: + v4l2_device_unregister(&dev->v4l2_dev); + return retval; } diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index 57b1b5c..ebff917 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -1195,13 +1195,6 @@ void em28xx_remove_from_devlist(struct em28xx *dev) mutex_unlock(&em28xx_devlist_mutex); }; -void em28xx_add_into_devlist(struct em28xx *dev) -{ - mutex_lock(&em28xx_devlist_mutex); - list_add_tail(&dev->devlist, &em28xx_devlist); - mutex_unlock(&em28xx_devlist_mutex); -}; - /* * Extension interface */ @@ -1239,14 +1232,13 @@ EXPORT_SYMBOL(em28xx_unregister_extension); void em28xx_init_extension(struct em28xx *dev) { - struct em28xx_ops *ops = NULL; + const struct em28xx_ops *ops = NULL; mutex_lock(&em28xx_devlist_mutex); - if (!list_empty(&em28xx_extension_devlist)) { - list_for_each_entry(ops, &em28xx_extension_devlist, next) { - if (ops->init) - ops->init(dev); - } + list_add_tail(&dev->devlist, &em28xx_devlist); + list_for_each_entry(ops, &em28xx_extension_devlist, next) { + if (ops->init) + ops->init(dev); } mutex_unlock(&em28xx_devlist_mutex); } -- cgit v0.10.2 From 76424a0a50982e4026c7d1d5a0cddc92eecc5969 Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Sat, 20 Aug 2011 08:31:05 -0300 Subject: [media] em28xx: move printk lines outside mutex lock There's no reason to still be holding the device list mutex for either of these printk statements. Signed-off-by: Chris Rankin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index ebff917..bd481ab 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -1210,8 +1210,8 @@ int em28xx_register_extension(struct em28xx_ops *ops) list_for_each_entry(dev, &em28xx_devlist, devlist) { ops->init(dev); } - printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name); mutex_unlock(&em28xx_devlist_mutex); + printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name); return 0; } EXPORT_SYMBOL(em28xx_register_extension); @@ -1224,9 +1224,9 @@ void em28xx_unregister_extension(struct em28xx_ops *ops) list_for_each_entry(dev, &em28xx_devlist, devlist) { ops->fini(dev); } - printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name); list_del(&ops->next); mutex_unlock(&em28xx_devlist_mutex); + printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name); } EXPORT_SYMBOL(em28xx_unregister_extension); -- cgit v0.10.2 From 0b8bd83cf393832f1d00096b866d888b75b374c3 Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Sat, 20 Aug 2011 16:01:26 -0300 Subject: [media] em28xx: don't sleep on disconnect The DVB framework will try to power-down an adapter that no-one is using any more, but this assumes that the adapter is still connected to the machine. That's not always true for a USB adapter, so disable the sleep operations when the adapter has been physically unplugged. This prevents I2C write failures with error -19 from appearing occasionally in the dmesg log. Signed-off-by: Chris Rankin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c index 57022e8..63cc400 100644 --- a/drivers/media/common/tuners/tda18271-fe.c +++ b/drivers/media/common/tuners/tda18271-fe.c @@ -1230,7 +1230,7 @@ static int tda18271_set_config(struct dvb_frontend *fe, void *priv_cfg) return 0; } -static struct dvb_tuner_ops tda18271_tuner_ops = { +static const struct dvb_tuner_ops tda18271_tuner_ops = { .info = { .name = "NXP TDA18271HD", .frequency_min = 45000000, diff --git a/drivers/media/dvb/frontends/cxd2820r_core.c b/drivers/media/dvb/frontends/cxd2820r_core.c index 0151267..036480f 100644 --- a/drivers/media/dvb/frontends/cxd2820r_core.c +++ b/drivers/media/dvb/frontends/cxd2820r_core.c @@ -742,7 +742,7 @@ static int cxd2820r_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) return cxd2820r_wr_reg_mask(priv, 0xdb, enable ? 1 : 0, 0x1); } -static struct dvb_frontend_ops cxd2820r_ops[2]; +static const struct dvb_frontend_ops cxd2820r_ops[2]; struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg, struct i2c_adapter *i2c, struct dvb_frontend *fe) @@ -796,7 +796,7 @@ error: } EXPORT_SYMBOL(cxd2820r_attach); -static struct dvb_frontend_ops cxd2820r_ops[2] = { +static const struct dvb_frontend_ops cxd2820r_ops[2] = { { /* DVB-T/T2 */ .info = { diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index b606fc7..62b558d 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c @@ -842,6 +842,13 @@ out_free: goto ret; } +static inline void prevent_sleep(struct dvb_frontend_ops *ops) +{ + ops->set_voltage = NULL; + ops->sleep = NULL; + ops->tuner_ops.sleep = NULL; +} + static int em28xx_dvb_fini(struct em28xx *dev) { if (!dev->board.has_dvb) { @@ -850,8 +857,19 @@ static int em28xx_dvb_fini(struct em28xx *dev) } if (dev->dvb) { - em28xx_unregister_dvb(dev->dvb); - kfree(dev->dvb); + struct em28xx_dvb *dvb = dev->dvb; + + if (dev->state & DEV_DISCONNECTED) { + /* We cannot tell the device to sleep + * once it has been unplugged. */ + if (dvb->fe[0]) + prevent_sleep(&dvb->fe[0]->ops); + if (dvb->fe[1]) + prevent_sleep(&dvb->fe[1]->ops); + } + + em28xx_unregister_dvb(dvb); + kfree(dvb); dev->dvb = NULL; } -- cgit v0.10.2 From 44d0b80e5ff741d502a6ccc8685a18bda1ac9da4 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 21 Aug 2011 19:56:44 -0300 Subject: [media] saa7146: Use current logging styles Standardize the mechanisms to emit logging messages. A few other modules used an #include from saa7146, convert those at the same time. Add pr_fmt. Convert printks to pr_ Convert printks without KERN_ to appropriate pr_. Convert logging macros requiring multiple parentheses to normal style. Removed embedded prefixes when pr_fmt was added. Whitespace cleanups when around other conversions. Use printf extension %pM to print mac address. Coalesce format strings. Signed-off-by: Joe Perches Acked-by: Michael Hunold Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c index 9af2140..f5d53a2 100644 --- a/drivers/media/common/saa7146_core.c +++ b/drivers/media/common/saa7146_core.c @@ -18,6 +18,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include LIST_HEAD(saa7146_devices); @@ -35,10 +37,9 @@ static void dump_registers(struct saa7146_dev* dev) { int i = 0; - INFO((" @ %li jiffies:\n",jiffies)); - for(i = 0; i <= 0x148; i+=4) { - printk("0x%03x: 0x%08x\n",i,saa7146_read(dev,i)); - } + pr_info(" @ %li jiffies:\n", jiffies); + for (i = 0; i <= 0x148; i += 4) + pr_info("0x%03x: 0x%08x\n", i, saa7146_read(dev, i)); } #endif @@ -72,9 +73,8 @@ static inline int saa7146_wait_for_debi_done_sleep(struct saa7146_dev *dev, if (saa7146_read(dev, MC2) & 2) break; if (err) { - printk(KERN_ERR "%s: %s timed out while waiting for " - "registers getting programmed\n", - dev->name, __func__); + pr_err("%s: %s timed out while waiting for registers getting programmed\n", + dev->name, __func__); return -ETIMEDOUT; } msleep(1); @@ -88,8 +88,8 @@ static inline int saa7146_wait_for_debi_done_sleep(struct saa7146_dev *dev, break; saa7146_read(dev, MC2); if (err) { - DEB_S(("%s: %s timed out while waiting for transfer " - "completion\n", dev->name, __func__)); + DEB_S("%s: %s timed out while waiting for transfer completion\n", + dev->name, __func__); return -ETIMEDOUT; } msleep(1); @@ -109,9 +109,8 @@ static inline int saa7146_wait_for_debi_done_busyloop(struct saa7146_dev *dev, if (saa7146_read(dev, MC2) & 2) break; if (!loops--) { - printk(KERN_ERR "%s: %s timed out while waiting for " - "registers getting programmed\n", - dev->name, __func__); + pr_err("%s: %s timed out while waiting for registers getting programmed\n", + dev->name, __func__); return -ETIMEDOUT; } udelay(1); @@ -124,8 +123,8 @@ static inline int saa7146_wait_for_debi_done_busyloop(struct saa7146_dev *dev, break; saa7146_read(dev, MC2); if (!loops--) { - DEB_S(("%s: %s timed out while waiting for transfer " - "completion\n", dev->name, __func__)); + DEB_S("%s: %s timed out while waiting for transfer completion\n", + dev->name, __func__); return -ETIMEDOUT; } udelay(5); @@ -264,7 +263,9 @@ int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt ptr = pt->cpu; for (i = 0; i < sglen; i++, list++) { /* - printk("i:%d, adr:0x%08x, len:%d, offset:%d\n", i,sg_dma_address(list), sg_dma_len(list), list->offset); + pr_debug("i:%d, adr:0x%08x, len:%d, offset:%d\n", + i, sg_dma_address(list), sg_dma_len(list), + list->offset); */ for (p = 0; p * 4096 < list->length; p++, ptr++) { *ptr = cpu_to_le32(sg_dma_address(list) + p * 4096); @@ -281,9 +282,9 @@ int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt /* ptr = pt->cpu; - printk("offset: %d\n",pt->offset); + pr_debug("offset: %d\n", pt->offset); for(i=0;i<5;i++) { - printk("ptr1 %d: 0x%08x\n",i,ptr[i]); + pr_debug("ptr1 %d: 0x%08x\n", i, ptr[i]); } */ return 0; @@ -314,7 +315,7 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id) } } if (0 != (isr & (MASK_27))) { - DEB_INT(("irq: RPS0 (0x%08x).\n",isr)); + DEB_INT("irq: RPS0 (0x%08x)\n", isr); if (dev->vv_data && dev->vv_callback) dev->vv_callback(dev,isr); isr &= ~MASK_27; @@ -333,14 +334,15 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id) } else { u32 psr = saa7146_read(dev, PSR); u32 ssr = saa7146_read(dev, SSR); - printk(KERN_WARNING "%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n", - dev->name, isr, psr, ssr); + pr_warn("%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n", + dev->name, isr, psr, ssr); } isr &= ~(MASK_16|MASK_17); } if( 0 != isr ) { - ERR(("warning: interrupt enabled, but not handled properly.(0x%08x)\n",isr)); - ERR(("disabling interrupt source(s)!\n")); + ERR("warning: interrupt enabled, but not handled properly.(0x%08x)\n", + isr); + ERR("disabling interrupt source(s)!\n"); SAA7146_IER_DISABLE(dev,isr); } saa7146_write(dev, ISR, ack_isr); @@ -360,15 +362,15 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent /* clear out mem for sure */ dev = kzalloc(sizeof(struct saa7146_dev), GFP_KERNEL); if (!dev) { - ERR(("out of memory.\n")); + ERR("out of memory\n"); goto out; } - DEB_EE(("pci:%p\n",pci)); + DEB_EE("pci:%p\n", pci); err = pci_enable_device(pci); if (err < 0) { - ERR(("pci_enable_device() failed.\n")); + ERR("pci_enable_device() failed\n"); goto err_free; } @@ -389,7 +391,7 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent dev->mem = ioremap(pci_resource_start(pci, 0), pci_resource_len(pci, 0)); if (!dev->mem) { - ERR(("ioremap() failed.\n")); + ERR("ioremap() failed\n"); err = -ENODEV; goto err_release; } @@ -414,7 +416,7 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent err = request_irq(pci->irq, interrupt_hw, IRQF_SHARED | IRQF_DISABLED, dev->name, dev); if (err < 0) { - ERR(("request_irq() failed.\n")); + ERR("request_irq() failed\n"); goto err_unmap; } @@ -444,7 +446,9 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent /* create a nice device name */ sprintf(dev->name, "saa7146 (%d)", saa7146_num); - INFO(("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x).\n", dev->mem, dev->revision, pci->irq, pci->subsystem_vendor, pci->subsystem_device)); + pr_info("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x)\n", + dev->mem, dev->revision, pci->irq, + pci->subsystem_vendor, pci->subsystem_device); dev->ext = ext; mutex_init(&dev->v4l2_lock); @@ -464,12 +468,12 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent err = -ENODEV; if (ext->probe && ext->probe(dev)) { - DEB_D(("ext->probe() failed for %p. skipping device.\n",dev)); + DEB_D("ext->probe() failed for %p. skipping device.\n", dev); goto err_free_i2c; } if (ext->attach(dev, pci_ext)) { - DEB_D(("ext->attach() failed for %p. skipping device.\n",dev)); + DEB_D("ext->attach() failed for %p. skipping device.\n", dev); goto err_free_i2c; } /* V4L extensions will set the pci drvdata to the v4l2_device in the @@ -521,7 +525,7 @@ static void saa7146_remove_one(struct pci_dev *pdev) { NULL, 0 } }, *p; - DEB_EE(("dev:%p\n",dev)); + DEB_EE("dev:%p\n", dev); dev->ext->detach(dev); /* Zero the PCI drvdata after use. */ @@ -552,21 +556,21 @@ static void saa7146_remove_one(struct pci_dev *pdev) int saa7146_register_extension(struct saa7146_extension* ext) { - DEB_EE(("ext:%p\n",ext)); + DEB_EE("ext:%p\n", ext); ext->driver.name = ext->name; ext->driver.id_table = ext->pci_tbl; ext->driver.probe = saa7146_init_one; ext->driver.remove = saa7146_remove_one; - printk("saa7146: register extension '%s'.\n",ext->name); + pr_info("register extension '%s'\n", ext->name); return pci_register_driver(&ext->driver); } int saa7146_unregister_extension(struct saa7146_extension* ext) { - DEB_EE(("ext:%p\n",ext)); - printk("saa7146: unregister extension '%s'.\n",ext->name); + DEB_EE("ext:%p\n", ext); + pr_info("unregister extension '%s'\n", ext->name); pci_unregister_driver(&ext->driver); return 0; } diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c index 1bd3dd7..a925461 100644 --- a/drivers/media/common/saa7146_fops.c +++ b/drivers/media/common/saa7146_fops.c @@ -1,3 +1,5 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include /****************************************************************************/ @@ -9,21 +11,23 @@ int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit) struct saa7146_vv *vv = dev->vv_data; if (fh->resources & bit) { - DEB_D(("already allocated! want: 0x%02x, cur:0x%02x\n",bit,vv->resources)); + DEB_D("already allocated! want: 0x%02x, cur:0x%02x\n", + bit, vv->resources); /* have it already allocated */ return 1; } /* is it free? */ if (vv->resources & bit) { - DEB_D(("locked! vv->resources:0x%02x, we want:0x%02x\n",vv->resources,bit)); + DEB_D("locked! vv->resources:0x%02x, we want:0x%02x\n", + vv->resources, bit); /* no, someone else uses it */ return 0; } /* it's free, grab it */ - fh->resources |= bit; + fh->resources |= bit; vv->resources |= bit; - DEB_D(("res: get 0x%02x, cur:0x%02x\n",bit,vv->resources)); + DEB_D("res: get 0x%02x, cur:0x%02x\n", bit, vv->resources); return 1; } @@ -34,9 +38,9 @@ void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits) BUG_ON((fh->resources & bits) != bits); - fh->resources &= ~bits; + fh->resources &= ~bits; vv->resources &= ~bits; - DEB_D(("res: put 0x%02x, cur:0x%02x\n",bits,vv->resources)); + DEB_D("res: put 0x%02x, cur:0x%02x\n", bits, vv->resources); } @@ -47,7 +51,7 @@ void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q, struct saa7146_buf *buf) { struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - DEB_EE(("dev:%p, buf:%p\n",dev,buf)); + DEB_EE("dev:%p, buf:%p\n", dev, buf); BUG_ON(in_interrupt()); @@ -66,18 +70,19 @@ int saa7146_buffer_queue(struct saa7146_dev *dev, struct saa7146_buf *buf) { assert_spin_locked(&dev->slock); - DEB_EE(("dev:%p, dmaq:%p, buf:%p\n", dev, q, buf)); + DEB_EE("dev:%p, dmaq:%p, buf:%p\n", dev, q, buf); BUG_ON(!q); if (NULL == q->curr) { q->curr = buf; - DEB_D(("immediately activating buffer %p\n", buf)); + DEB_D("immediately activating buffer %p\n", buf); buf->activate(dev,buf,NULL); } else { list_add_tail(&buf->vb.queue,&q->queue); buf->vb.state = VIDEOBUF_QUEUED; - DEB_D(("adding buffer %p to queue. (active buffer present)\n", buf)); + DEB_D("adding buffer %p to queue. (active buffer present)\n", + buf); } return 0; } @@ -87,14 +92,14 @@ void saa7146_buffer_finish(struct saa7146_dev *dev, int state) { assert_spin_locked(&dev->slock); - DEB_EE(("dev:%p, dmaq:%p, state:%d\n", dev, q, state)); - DEB_EE(("q->curr:%p\n",q->curr)); + DEB_EE("dev:%p, dmaq:%p, state:%d\n", dev, q, state); + DEB_EE("q->curr:%p\n", q->curr); BUG_ON(!q->curr); /* finish current buffer */ if (NULL == q->curr) { - DEB_D(("aiii. no current buffer\n")); + DEB_D("aiii. no current buffer\n"); return; } @@ -112,7 +117,7 @@ void saa7146_buffer_next(struct saa7146_dev *dev, BUG_ON(!q); - DEB_INT(("dev:%p, dmaq:%p, vbi:%d\n", dev, q, vbi)); + DEB_INT("dev:%p, dmaq:%p, vbi:%d\n", dev, q, vbi); assert_spin_locked(&dev->slock); if (!list_empty(&q->queue)) { @@ -122,10 +127,11 @@ void saa7146_buffer_next(struct saa7146_dev *dev, if (!list_empty(&q->queue)) next = list_entry(q->queue.next,struct saa7146_buf, vb.queue); q->curr = buf; - DEB_INT(("next buffer: buf:%p, prev:%p, next:%p\n", buf, q->queue.prev,q->queue.next)); + DEB_INT("next buffer: buf:%p, prev:%p, next:%p\n", + buf, q->queue.prev, q->queue.next); buf->activate(dev,buf,next); } else { - DEB_INT(("no next buffer. stopping.\n")); + DEB_INT("no next buffer. stopping.\n"); if( 0 != vbi ) { /* turn off video-dma3 */ saa7146_write(dev,MC1, MASK_20); @@ -162,11 +168,11 @@ void saa7146_buffer_timeout(unsigned long data) struct saa7146_dev *dev = q->dev; unsigned long flags; - DEB_EE(("dev:%p, dmaq:%p\n", dev, q)); + DEB_EE("dev:%p, dmaq:%p\n", dev, q); spin_lock_irqsave(&dev->slock,flags); if (q->curr) { - DEB_D(("timeout on %p\n", q->curr)); + DEB_D("timeout on %p\n", q->curr); saa7146_buffer_finish(dev,q,VIDEOBUF_ERROR); } @@ -194,12 +200,12 @@ static int fops_open(struct file *file) enum v4l2_buf_type type; - DEB_EE(("file:%p, dev:%s\n", file, video_device_node_name(vdev))); + DEB_EE("file:%p, dev:%s\n", file, video_device_node_name(vdev)); if (mutex_lock_interruptible(&saa7146_devices_lock)) return -ERESTARTSYS; - DEB_D(("using: %p\n",dev)); + DEB_D("using: %p\n", dev); type = vdev->vfl_type == VFL_TYPE_GRABBER ? V4L2_BUF_TYPE_VIDEO_CAPTURE @@ -207,7 +213,7 @@ static int fops_open(struct file *file) /* check if an extension is registered */ if( NULL == dev->ext ) { - DEB_S(("no extension registered for this device.\n")); + DEB_S("no extension registered for this device\n"); result = -ENODEV; goto out; } @@ -215,7 +221,7 @@ static int fops_open(struct file *file) /* allocate per open data */ fh = kzalloc(sizeof(*fh),GFP_KERNEL); if (NULL == fh) { - DEB_S(("cannot allocate memory for per open data.\n")); + DEB_S("cannot allocate memory for per open data\n"); result = -ENOMEM; goto out; } @@ -225,13 +231,13 @@ static int fops_open(struct file *file) fh->type = type; if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - DEB_S(("initializing vbi...\n")); + DEB_S("initializing vbi...\n"); if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) result = saa7146_vbi_uops.open(dev,file); if (dev->ext_vv_data->vbi_fops.open) dev->ext_vv_data->vbi_fops.open(file); } else { - DEB_S(("initializing video...\n")); + DEB_S("initializing video...\n"); result = saa7146_video_uops.open(dev,file); } @@ -259,7 +265,7 @@ static int fops_release(struct file *file) struct saa7146_fh *fh = file->private_data; struct saa7146_dev *dev = fh->dev; - DEB_EE(("file:%p\n", file)); + DEB_EE("file:%p\n", file); if (mutex_lock_interruptible(&saa7146_devices_lock)) return -ERESTARTSYS; @@ -289,12 +295,14 @@ static int fops_mmap(struct file *file, struct vm_area_struct * vma) switch (fh->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: { - DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, vma:%p\n",file, vma)); + DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, vma:%p\n", + file, vma); q = &fh->video_q; break; } case V4L2_BUF_TYPE_VBI_CAPTURE: { - DEB_EE(("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, vma:%p\n",file, vma)); + DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, vma:%p\n", + file, vma); q = &fh->vbi_q; break; } @@ -312,14 +320,14 @@ static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait) struct videobuf_buffer *buf = NULL; struct videobuf_queue *q; - DEB_EE(("file:%p, poll:%p\n",file, wait)); + DEB_EE("file:%p, poll:%p\n", file, wait); if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { if( 0 == fh->vbi_q.streaming ) return videobuf_poll_stream(file, &fh->vbi_q, wait); q = &fh->vbi_q; } else { - DEB_D(("using video queue.\n")); + DEB_D("using video queue\n"); q = &fh->video_q; } @@ -327,17 +335,17 @@ static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait) buf = list_entry(q->stream.next, struct videobuf_buffer, stream); if (!buf) { - DEB_D(("buf == NULL!\n")); + DEB_D("buf == NULL!\n"); return POLLERR; } poll_wait(file, &buf->done, wait); if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) { - DEB_D(("poll succeeded!\n")); + DEB_D("poll succeeded!\n"); return POLLIN|POLLRDNORM; } - DEB_D(("nothing to poll for, buf->state:%d\n",buf->state)); + DEB_D("nothing to poll for, buf->state:%d\n", buf->state); return 0; } @@ -346,18 +354,20 @@ static ssize_t fops_read(struct file *file, char __user *data, size_t count, lof struct saa7146_fh *fh = file->private_data; switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: { -// DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun", file, data, (unsigned long)count)); + case V4L2_BUF_TYPE_VIDEO_CAPTURE: +/* + DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun", + file, data, (unsigned long)count); +*/ return saa7146_video_uops.read(file,data,count,ppos); - } - case V4L2_BUF_TYPE_VBI_CAPTURE: { -// DEB_EE(("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n", file, data, (unsigned long)count)); + case V4L2_BUF_TYPE_VBI_CAPTURE: +/* + DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n", + file, data, (unsigned long)count); +*/ if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) return saa7146_vbi_uops.read(file,data,count,ppos); - else - return -EINVAL; - } - break; + return -EINVAL; default: BUG(); return 0; @@ -398,22 +408,22 @@ static void vv_callback(struct saa7146_dev *dev, unsigned long status) { u32 isr = status; - DEB_INT(("dev:%p, isr:0x%08x\n",dev,(u32)status)); + DEB_INT("dev:%p, isr:0x%08x\n", dev, (u32)status); if (0 != (isr & (MASK_27))) { - DEB_INT(("irq: RPS0 (0x%08x).\n",isr)); + DEB_INT("irq: RPS0 (0x%08x)\n", isr); saa7146_video_uops.irq_done(dev,isr); } if (0 != (isr & (MASK_28))) { u32 mc2 = saa7146_read(dev, MC2); if( 0 != (mc2 & MASK_15)) { - DEB_INT(("irq: RPS1 vbi workaround (0x%08x).\n",isr)); + DEB_INT("irq: RPS1 vbi workaround (0x%08x)\n", isr); wake_up(&dev->vv_data->vbi_wq); saa7146_write(dev,MC2, MASK_31); return; } - DEB_INT(("irq: RPS1 (0x%08x).\n",isr)); + DEB_INT("irq: RPS1 (0x%08x)\n", isr); saa7146_vbi_uops.irq_done(dev,isr); } } @@ -429,13 +439,13 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv) vv = kzalloc(sizeof(struct saa7146_vv), GFP_KERNEL); if (vv == NULL) { - ERR(("out of memory. aborting.\n")); + ERR("out of memory. aborting.\n"); return -ENOMEM; } ext_vv->ops = saa7146_video_ioctl_ops; ext_vv->core_ops = &saa7146_video_ioctl_ops; - DEB_EE(("dev:%p\n",dev)); + DEB_EE("dev:%p\n", dev); /* set default values for video parts of the saa7146 */ saa7146_write(dev, BCS_CTRL, 0x80400040); @@ -450,7 +460,7 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv) vv->d_clipping.cpu_addr = pci_alloc_consistent(dev->pci, SAA7146_CLIPPING_MEM, &vv->d_clipping.dma_handle); if( NULL == vv->d_clipping.cpu_addr ) { - ERR(("out of memory. aborting.\n")); + ERR("out of memory. aborting.\n"); kfree(vv); return -1; } @@ -471,7 +481,7 @@ int saa7146_vv_release(struct saa7146_dev* dev) { struct saa7146_vv *vv = dev->vv_data; - DEB_EE(("dev:%p\n",dev)); + DEB_EE("dev:%p\n", dev); v4l2_device_unregister(&dev->v4l2_dev); pci_free_consistent(dev->pci, SAA7146_CLIPPING_MEM, vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle); @@ -490,7 +500,7 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, int err; int i; - DEB_EE(("dev:%p, name:'%s', type:%d\n",dev,name,type)); + DEB_EE("dev:%p, name:'%s', type:%d\n", dev, name, type); // released by vfd->release vfd = video_device_alloc(); @@ -509,13 +519,13 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, err = video_register_device(vfd, type, -1); if (err < 0) { - ERR(("cannot register v4l2 device. skipping.\n")); + ERR("cannot register v4l2 device. skipping.\n"); video_device_release(vfd); return err; } - INFO(("%s: registered device %s [v4l2]\n", - dev->name, video_device_node_name(vfd))); + pr_info("%s: registered device %s [v4l2]\n", + dev->name, video_device_node_name(vfd)); *vid = vfd; return 0; @@ -524,7 +534,7 @@ EXPORT_SYMBOL_GPL(saa7146_register_device); int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev) { - DEB_EE(("dev:%p\n",dev)); + DEB_EE("dev:%p\n", dev); video_unregister_device(*vid); *vid = NULL; diff --git a/drivers/media/common/saa7146_hlp.c b/drivers/media/common/saa7146_hlp.c index 1d1d8d2..79ad73a 100644 --- a/drivers/media/common/saa7146_hlp.c +++ b/drivers/media/common/saa7146_hlp.c @@ -1,3 +1,5 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include @@ -711,8 +713,8 @@ static int calculate_video_dma_grab_packed(struct saa7146_dev* dev, struct saa71 int depth = sfmt->depth; - DEB_CAP(("[size=%dx%d,fields=%s]\n", - width,height,v4l2_field_names[field])); + DEB_CAP("[size=%dx%d,fields=%s]\n", + width, height, v4l2_field_names[field]); if( bytesperline != 0) { vdma1.pitch = bytesperline*2; @@ -837,8 +839,8 @@ static int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa71 BUG_ON(0 == buf->pt[1].dma); BUG_ON(0 == buf->pt[2].dma); - DEB_CAP(("[size=%dx%d,fields=%s]\n", - width,height,v4l2_field_names[field])); + DEB_CAP("[size=%dx%d,fields=%s]\n", + width, height, v4l2_field_names[field]); /* fixme: look at bytesperline! */ @@ -998,12 +1000,12 @@ void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struc struct saa7146_vv *vv = dev->vv_data; u32 vdma1_prot_addr; - DEB_CAP(("buf:%p, next:%p\n",buf,next)); + DEB_CAP("buf:%p, next:%p\n", buf, next); vdma1_prot_addr = saa7146_read(dev, PROT_ADDR1); if( 0 == vdma1_prot_addr ) { /* clear out beginning of streaming bit (rps register 0)*/ - DEB_CAP(("forcing sync to new frame\n")); + DEB_CAP("forcing sync to new frame\n"); saa7146_write(dev, MC2, MASK_27 ); } diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c index b2ba9dc..2202719 100644 --- a/drivers/media/common/saa7146_i2c.c +++ b/drivers/media/common/saa7146_i2c.c @@ -1,8 +1,10 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include static u32 saa7146_i2c_func(struct i2c_adapter *adapter) { -//fm DEB_I2C(("'%s'.\n", adapter->name)); + /* DEB_I2C("'%s'\n", adapter->name); */ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_QUICK @@ -14,9 +16,7 @@ static u32 saa7146_i2c_func(struct i2c_adapter *adapter) static inline u32 saa7146_i2c_status(struct saa7146_dev *dev) { u32 iicsta = saa7146_read(dev, I2C_STATUS); -/* - DEB_I2C(("status: 0x%08x\n",iicsta)); -*/ + /* DEB_I2C("status: 0x%08x\n", iicsta); */ return iicsta; } @@ -39,10 +39,11 @@ static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, __le32 *op) plus one extra byte to address the device */ mem = 1 + ((mem-1) / 3); - /* we assume that op points to a memory of at least SAA7146_I2C_MEM bytes - size. if we exceed this limit... */ - if ( (4*mem) > SAA7146_I2C_MEM ) { -//fm DEB_I2C(("cannot prepare i2c-message.\n")); + /* we assume that op points to a memory of at least + * SAA7146_I2C_MEM bytes size. if we exceed this limit... + */ + if ((4 * mem) > SAA7146_I2C_MEM) { + /* DEB_I2C("cannot prepare i2c-message\n"); */ return -ENOMEM; } @@ -123,7 +124,7 @@ static int saa7146_i2c_reset(struct saa7146_dev *dev) if ( 0 != ( status & SAA7146_I2C_BUSY) ) { /* yes, kill ongoing operation */ - DEB_I2C(("busy_state detected.\n")); + DEB_I2C("busy_state detected\n"); /* set "ABORT-OPERATION"-bit (bit 7)*/ saa7146_write(dev, I2C_STATUS, (dev->i2c_bitrate | MASK_07)); @@ -141,7 +142,7 @@ static int saa7146_i2c_reset(struct saa7146_dev *dev) if ( dev->i2c_bitrate != status ) { - DEB_I2C(("error_state detected. status:0x%08x\n",status)); + DEB_I2C("error_state detected. status:0x%08x\n", status); /* Repeat the abort operation. This seems to be necessary after serious protocol errors caused by e.g. the SAA7740 */ @@ -164,7 +165,7 @@ static int saa7146_i2c_reset(struct saa7146_dev *dev) /* if any error is still present, a fatal error has occurred ... */ status = saa7146_i2c_status(dev); if ( dev->i2c_bitrate != status ) { - DEB_I2C(("fatal error. status:0x%08x\n",status)); + DEB_I2C("fatal error. status:0x%08x\n", status); return -1; } @@ -181,7 +182,8 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int shor unsigned long timeout; /* write out i2c-command */ - DEB_I2C(("before: 0x%08x (status: 0x%08x), %d\n",*dword,saa7146_read(dev, I2C_STATUS), dev->i2c_op)); + DEB_I2C("before: 0x%08x (status: 0x%08x), %d\n", + *dword, saa7146_read(dev, I2C_STATUS), dev->i2c_op); if( 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags)) { @@ -202,7 +204,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int shor /* a signal arrived */ return -ERESTARTSYS; - printk(KERN_WARNING "%s %s [irq]: timed out waiting for end of xfer\n", + pr_warn("%s %s [irq]: timed out waiting for end of xfer\n", dev->name, __func__); return -EIO; } @@ -220,7 +222,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int shor break; } if (time_after(jiffies,timeout)) { - printk(KERN_WARNING "%s %s: timed out waiting for MC2\n", + pr_warn("%s %s: timed out waiting for MC2\n", dev->name, __func__); return -EIO; } @@ -237,7 +239,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int shor /* this is normal when probing the bus * (no answer from nonexisistant device...) */ - printk(KERN_WARNING "%s %s [poll]: timed out waiting for end of xfer\n", + pr_warn("%s %s [poll]: timed out waiting for end of xfer\n", dev->name, __func__); return -EIO; } @@ -257,24 +259,24 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int shor if ( 0 == (status & SAA7146_I2C_ERR) || 0 == (status & SAA7146_I2C_BUSY) ) { /* it may take some time until ERR goes high - ignore */ - DEB_I2C(("unexpected i2c status %04x\n", status)); + DEB_I2C("unexpected i2c status %04x\n", status); } if( 0 != (status & SAA7146_I2C_SPERR) ) { - DEB_I2C(("error due to invalid start/stop condition.\n")); + DEB_I2C("error due to invalid start/stop condition\n"); } if( 0 != (status & SAA7146_I2C_DTERR) ) { - DEB_I2C(("error in data transmission.\n")); + DEB_I2C("error in data transmission\n"); } if( 0 != (status & SAA7146_I2C_DRERR) ) { - DEB_I2C(("error when receiving data.\n")); + DEB_I2C("error when receiving data\n"); } if( 0 != (status & SAA7146_I2C_AL) ) { - DEB_I2C(("error because arbitration lost.\n")); + DEB_I2C("error because arbitration lost\n"); } /* we handle address-errors here */ if( 0 != (status & SAA7146_I2C_APERR) ) { - DEB_I2C(("error in address phase.\n")); + DEB_I2C("error in address phase\n"); return -EREMOTEIO; } @@ -284,7 +286,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int shor /* read back data, just in case we were reading ... */ *dword = cpu_to_le32(saa7146_read(dev, I2C_TRANSFER)); - DEB_I2C(("after: 0x%08x\n",*dword)); + DEB_I2C("after: 0x%08x\n", *dword); return 0; } @@ -299,7 +301,7 @@ static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *m return -ERESTARTSYS; for(i=0;i err ) { - DEB_I2C(("could not reset i2c-device.\n")); + DEB_I2C("could not reset i2c-device\n"); goto out; } @@ -336,7 +338,7 @@ static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *m address error and trust the saa7146 address error detection. */ if (-EREMOTEIO == err && 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags)) goto out; - DEB_I2C(("error while sending message(s). starting again.\n")); + DEB_I2C("error while sending message(s). starting again\n"); break; } } @@ -356,13 +358,13 @@ static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *m /* if any things had to be read, get the results */ if ( 0 != saa7146_i2c_msg_cleanup(msgs, num, buffer)) { - DEB_I2C(("could not cleanup i2c-message.\n")); + DEB_I2C("could not cleanup i2c-message\n"); err = -1; goto out; } /* return the number of delivered messages */ - DEB_I2C(("transmission successful. (msg:%d).\n",err)); + DEB_I2C("transmission successful. (msg:%d)\n", err); out: /* another bug in revision 0: the i2c-registers get uploaded randomly by other uploads, so we better clear them out before continuing */ @@ -370,7 +372,7 @@ out: __le32 zero = 0; saa7146_i2c_reset(dev); if( 0 != saa7146_i2c_writeout(dev, &zero, short_delay)) { - INFO(("revision 0 error. this should never happen.\n")); + pr_info("revision 0 error. this should never happen\n"); } } @@ -400,7 +402,7 @@ static struct i2c_algorithm saa7146_algo = { int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate) { - DEB_EE(("bitrate: 0x%08x\n",bitrate)); + DEB_EE("bitrate: 0x%08x\n", bitrate); /* enable i2c-port pins */ saa7146_write(dev, MC1, (MASK_08 | MASK_24)); diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c index afe8580..b2e7183 100644 --- a/drivers/media/common/saa7146_vbi.c +++ b/drivers/media/common/saa7146_vbi.c @@ -14,7 +14,7 @@ static int vbi_workaround(struct saa7146_dev *dev) DECLARE_WAITQUEUE(wait, current); - DEB_VBI(("dev:%p\n",dev)); + DEB_VBI("dev:%p\n", dev); /* once again, a bug in the saa7146: the brs acquisition is buggy and especially the BXO-counter does not work @@ -40,14 +40,14 @@ static int vbi_workaround(struct saa7146_dev *dev) WRITE_RPS1(0xc000008c); /* wait for vbi_a or vbi_b*/ if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) { - DEB_D(("...using port b\n")); + DEB_D("...using port b\n"); WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_E_FID_B); WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_O_FID_B); /* WRITE_RPS1(CMD_PAUSE | MASK_09); */ } else { - DEB_D(("...using port a\n")); + DEB_D("...using port a\n"); WRITE_RPS1(CMD_PAUSE | MASK_10); } /* upload brs */ @@ -103,7 +103,7 @@ static int vbi_workaround(struct saa7146_dev *dev) schedule(); - DEB_VBI(("brs bug workaround %d/1.\n",i)); + DEB_VBI("brs bug workaround %d/1\n", i); remove_wait_queue(&vv->vbi_wq, &wait); current->state = TASK_RUNNING; @@ -116,7 +116,8 @@ static int vbi_workaround(struct saa7146_dev *dev) if(signal_pending(current)) { - DEB_VBI(("aborted (rps:0x%08x).\n",saa7146_read(dev,RPS_ADDR1))); + DEB_VBI("aborted (rps:0x%08x)\n", + saa7146_read(dev, RPS_ADDR1)); /* stop rps1 for sure */ saa7146_write(dev, MC1, MASK_29); @@ -207,7 +208,7 @@ static int buffer_activate(struct saa7146_dev *dev, struct saa7146_vv *vv = dev->vv_data; buf->vb.state = VIDEOBUF_ACTIVE; - DEB_VBI(("dev:%p, buf:%p, next:%p\n",dev,buf,next)); + DEB_VBI("dev:%p, buf:%p, next:%p\n", dev, buf, next); saa7146_set_vbi_capture(dev,buf,next); mod_timer(&vv->vbi_q.timeout, jiffies+BUFFER_TIMEOUT); @@ -228,10 +229,10 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e llength = vbi_pixel_to_capture; size = lines * llength; - DEB_VBI(("vb:%p\n",vb)); + DEB_VBI("vb:%p\n", vb); if (0 != buf->vb.baddr && buf->vb.bsize < size) { - DEB_VBI(("size mismatch.\n")); + DEB_VBI("size mismatch\n"); return -EINVAL; } @@ -263,7 +264,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e return 0; oops: - DEB_VBI(("error out.\n")); + DEB_VBI("error out\n"); saa7146_dma_free(dev,q,buf); return err; @@ -279,7 +280,7 @@ static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned *size = lines * llength; *count = 2; - DEB_VBI(("count:%d, size:%d\n",*count,*size)); + DEB_VBI("count:%d, size:%d\n", *count, *size); return 0; } @@ -292,7 +293,7 @@ static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) struct saa7146_vv *vv = dev->vv_data; struct saa7146_buf *buf = (struct saa7146_buf *)vb; - DEB_VBI(("vb:%p\n",vb)); + DEB_VBI("vb:%p\n", vb); saa7146_buffer_queue(dev,&vv->vbi_q,buf); } @@ -303,7 +304,7 @@ static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) struct saa7146_dev *dev = fh->dev; struct saa7146_buf *buf = (struct saa7146_buf *)vb; - DEB_VBI(("vb:%p\n",vb)); + DEB_VBI("vb:%p\n", vb); saa7146_dma_free(dev,q,buf); } @@ -321,7 +322,7 @@ static void vbi_stop(struct saa7146_fh *fh, struct file *file) struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; unsigned long flags; - DEB_VBI(("dev:%p, fh:%p\n",dev, fh)); + DEB_VBI("dev:%p, fh:%p\n", dev, fh); spin_lock_irqsave(&dev->slock,flags); @@ -354,14 +355,14 @@ static void vbi_read_timeout(unsigned long data) struct saa7146_fh *fh = file->private_data; struct saa7146_dev *dev = fh->dev; - DEB_VBI(("dev:%p, fh:%p\n",dev, fh)); + DEB_VBI("dev:%p, fh:%p\n", dev, fh); vbi_stop(fh, file); } static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv) { - DEB_VBI(("dev:%p\n",dev)); + DEB_VBI("dev:%p\n", dev); INIT_LIST_HEAD(&vv->vbi_q.queue); @@ -380,11 +381,11 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file) u32 arbtr_ctrl = saa7146_read(dev, PCI_BT_V1); int ret = 0; - DEB_VBI(("dev:%p, fh:%p\n",dev,fh)); + DEB_VBI("dev:%p, fh:%p\n", dev, fh); ret = saa7146_res_get(fh, RESOURCE_DMA3_BRS); if (0 == ret) { - DEB_S(("cannot get vbi RESOURCE_DMA3_BRS resource\n")); + DEB_S("cannot get vbi RESOURCE_DMA3_BRS resource\n"); return -EBUSY; } @@ -425,7 +426,7 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file) saa7146_write(dev, BRS_CTRL, 0x00000001); if (0 != (ret = vbi_workaround(dev))) { - DEB_VBI(("vbi workaround failed!\n")); + DEB_VBI("vbi workaround failed!\n"); /* return ret;*/ } } @@ -439,7 +440,7 @@ static void vbi_close(struct saa7146_dev *dev, struct file *file) { struct saa7146_fh *fh = file->private_data; struct saa7146_vv *vv = dev->vv_data; - DEB_VBI(("dev:%p, fh:%p\n",dev,fh)); + DEB_VBI("dev:%p, fh:%p\n", dev, fh); if( fh == vv->vbi_streaming ) { vbi_stop(fh, file); @@ -453,13 +454,13 @@ static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status) spin_lock(&dev->slock); if (vv->vbi_q.curr) { - DEB_VBI(("dev:%p, curr:%p\n",dev,vv->vbi_q.curr)); + DEB_VBI("dev:%p, curr:%p\n", dev, vv->vbi_q.curr); /* this must be += 2, one count for each field */ vv->vbi_fieldcount+=2; vv->vbi_q.curr->vb.field_count = vv->vbi_fieldcount; saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE); } else { - DEB_VBI(("dev:%p\n",dev)); + DEB_VBI("dev:%p\n", dev); } saa7146_buffer_next(dev,&vv->vbi_q,1); @@ -473,7 +474,7 @@ static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff struct saa7146_vv *vv = dev->vv_data; ssize_t ret = 0; - DEB_VBI(("dev:%p, fh:%p\n",dev,fh)); + DEB_VBI("dev:%p, fh:%p\n", dev, fh); if( NULL == vv->vbi_streaming ) { // fixme: check if dma3 is available @@ -482,7 +483,8 @@ static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff } if( fh != vv->vbi_streaming ) { - DEB_VBI(("open %p is already using vbi capture.",vv->vbi_streaming)); + DEB_VBI("open %p is already using vbi capture\n", + vv->vbi_streaming); return -EBUSY; } diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c index 9aafa4e..fcdf4a0 100644 --- a/drivers/media/common/saa7146_video.c +++ b/drivers/media/common/saa7146_video.c @@ -1,3 +1,5 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include @@ -94,7 +96,7 @@ struct saa7146_format* saa7146_format_by_fourcc(struct saa7146_dev *dev, int fou } } - DEB_D(("unknown pixelformat:'%4.4s'\n",(char *)&fourcc)); + DEB_D("unknown pixelformat:'%4.4s'\n", (char *)&fourcc); return NULL; } @@ -107,32 +109,32 @@ int saa7146_start_preview(struct saa7146_fh *fh) struct v4l2_format fmt; int ret = 0, err = 0; - DEB_EE(("dev:%p, fh:%p\n",dev,fh)); + DEB_EE("dev:%p, fh:%p\n", dev, fh); /* check if we have overlay informations */ if( NULL == fh->ov.fh ) { - DEB_D(("no overlay data available. try S_FMT first.\n")); + DEB_D("no overlay data available. try S_FMT first.\n"); return -EAGAIN; } /* check if streaming capture is running */ if (IS_CAPTURE_ACTIVE(fh) != 0) { - DEB_D(("streaming capture is active.\n")); + DEB_D("streaming capture is active\n"); return -EBUSY; } /* check if overlay is running */ if (IS_OVERLAY_ACTIVE(fh) != 0) { if (vv->video_fh == fh) { - DEB_D(("overlay is already active.\n")); + DEB_D("overlay is already active\n"); return 0; } - DEB_D(("overlay is already active in another open.\n")); + DEB_D("overlay is already active in another open\n"); return -EBUSY; } if (0 == saa7146_res_get(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) { - DEB_D(("cannot get necessary overlay resources\n")); + DEB_D("cannot get necessary overlay resources\n"); return -EBUSY; } @@ -145,13 +147,13 @@ int saa7146_start_preview(struct saa7146_fh *fh) fh->ov.win = fmt.fmt.win; vv->ov_data = &fh->ov; - DEB_D(("%dx%d+%d+%d %s field=%s\n", - fh->ov.win.w.width,fh->ov.win.w.height, - fh->ov.win.w.left,fh->ov.win.w.top, - vv->ov_fmt->name,v4l2_field_names[fh->ov.win.field])); + DEB_D("%dx%d+%d+%d %s field=%s\n", + fh->ov.win.w.width, fh->ov.win.w.height, + fh->ov.win.w.left, fh->ov.win.w.top, + vv->ov_fmt->name, v4l2_field_names[fh->ov.win.field]); if (0 != (ret = saa7146_enable_overlay(fh))) { - DEB_D(("enabling overlay failed: %d\n",ret)); + DEB_D("enabling overlay failed: %d\n", ret); saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); return ret; } @@ -168,22 +170,22 @@ int saa7146_stop_preview(struct saa7146_fh *fh) struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; - DEB_EE(("dev:%p, fh:%p\n",dev,fh)); + DEB_EE("dev:%p, fh:%p\n", dev, fh); /* check if streaming capture is running */ if (IS_CAPTURE_ACTIVE(fh) != 0) { - DEB_D(("streaming capture is active.\n")); + DEB_D("streaming capture is active\n"); return -EBUSY; } /* check if overlay is running at all */ if ((vv->video_status & STATUS_OVERLAY) == 0) { - DEB_D(("no active overlay.\n")); + DEB_D("no active overlay\n"); return 0; } if (vv->video_fh != fh) { - DEB_D(("overlay is active, but in another open.\n")); + DEB_D("overlay is active, but in another open\n"); return -EBUSY; } @@ -268,7 +270,7 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu int length = dma->sglen; struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); - DEB_EE(("dev:%p, buf:%p, sg_len:%d\n",dev,buf,length)); + DEB_EE("dev:%p, buf:%p, sg_len:%d\n", dev, buf, length); if( 0 != IS_PLANAR(sfmt->trans)) { struct saa7146_pgtable *pt1 = &buf->pt[0]; @@ -288,7 +290,8 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu m3 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1; o1 = size%PAGE_SIZE; o2 = (size+(size/4))%PAGE_SIZE; - DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2)); + DEB_CAP("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n", + size, m1, m2, m3, o1, o2); break; } case 16: { @@ -298,7 +301,8 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu m3 = ((2*size+PAGE_SIZE)/PAGE_SIZE)-1; o1 = size%PAGE_SIZE; o2 = (size+(size/2))%PAGE_SIZE; - DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2)); + DEB_CAP("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n", + size, m1, m2, m3, o1, o2); break; } default: { @@ -387,23 +391,23 @@ static int video_begin(struct saa7146_fh *fh) unsigned int resource; int ret = 0, err = 0; - DEB_EE(("dev:%p, fh:%p\n",dev,fh)); + DEB_EE("dev:%p, fh:%p\n", dev, fh); if ((vv->video_status & STATUS_CAPTURE) != 0) { if (vv->video_fh == fh) { - DEB_S(("already capturing.\n")); + DEB_S("already capturing\n"); return 0; } - DEB_S(("already capturing in another open.\n")); + DEB_S("already capturing in another open\n"); return -EBUSY; } if ((vv->video_status & STATUS_OVERLAY) != 0) { - DEB_S(("warning: suspending overlay video for streaming capture.\n")); + DEB_S("warning: suspending overlay video for streaming capture\n"); vv->ov_suspend = vv->video_fh; err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */ if (0 != err) { - DEB_D(("suspending video failed. aborting\n")); + DEB_D("suspending video failed. aborting\n"); return err; } } @@ -420,7 +424,7 @@ static int video_begin(struct saa7146_fh *fh) ret = saa7146_res_get(fh, resource); if (0 == ret) { - DEB_S(("cannot get capture resource %d\n",resource)); + DEB_S("cannot get capture resource %d\n", resource); if (vv->ov_suspend != NULL) { saa7146_start_preview(vv->ov_suspend); vv->ov_suspend = NULL; @@ -448,15 +452,15 @@ static int video_end(struct saa7146_fh *fh, struct file *file) unsigned long flags; unsigned int resource; u32 dmas = 0; - DEB_EE(("dev:%p, fh:%p\n",dev,fh)); + DEB_EE("dev:%p, fh:%p\n", dev, fh); if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) { - DEB_S(("not capturing.\n")); + DEB_S("not capturing\n"); return 0; } if (vv->video_fh != fh) { - DEB_S(("capturing, but in another open.\n")); + DEB_S("capturing, but in another open\n"); return -EBUSY; } @@ -530,7 +534,7 @@ static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *f struct saa7146_vv *vv = dev->vv_data; struct saa7146_format *fmt; - DEB_EE(("VIDIOC_S_FBUF\n")); + DEB_EE("VIDIOC_S_FBUF\n"); if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) return -EPERM; @@ -542,13 +546,13 @@ static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *f /* planar formats are not allowed for overlay video, clipping and video dma would clash */ if (fmt->flags & FORMAT_IS_PLANAR) - DEB_S(("planar pixelformat '%4.4s' not allowed for overlay\n", - (char *)&fmt->pixelformat)); + DEB_S("planar pixelformat '%4.4s' not allowed for overlay\n", + (char *)&fmt->pixelformat); /* check if overlay is running */ if (IS_OVERLAY_ACTIVE(fh) != 0) { if (vv->video_fh != fh) { - DEB_D(("refusing to change framebuffer informations while overlay is active in another open.\n")); + DEB_D("refusing to change framebuffer informations while overlay is active in another open\n"); return -EBUSY; } } @@ -559,7 +563,7 @@ static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *f if (vv->ov_fb.fmt.bytesperline < vv->ov_fb.fmt.width) { vv->ov_fb.fmt.bytesperline = vv->ov_fb.fmt.width * fmt->depth / 8; - DEB_D(("setting bytesperline to %d\n", vv->ov_fb.fmt.bytesperline)); + DEB_D("setting bytesperline to %d\n", vv->ov_fb.fmt.bytesperline); } return 0; } @@ -588,7 +592,7 @@ static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl * if (ctrl == NULL) return -EINVAL; - DEB_EE(("VIDIOC_QUERYCTRL: id:%d\n", c->id)); + DEB_EE("VIDIOC_QUERYCTRL: id:%d\n", c->id); *c = *ctrl; return 0; } @@ -607,25 +611,25 @@ static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c) case V4L2_CID_BRIGHTNESS: value = saa7146_read(dev, BCS_CTRL); c->value = 0xff & (value >> 24); - DEB_D(("V4L2_CID_BRIGHTNESS: %d\n", c->value)); + DEB_D("V4L2_CID_BRIGHTNESS: %d\n", c->value); break; case V4L2_CID_CONTRAST: value = saa7146_read(dev, BCS_CTRL); c->value = 0x7f & (value >> 16); - DEB_D(("V4L2_CID_CONTRAST: %d\n", c->value)); + DEB_D("V4L2_CID_CONTRAST: %d\n", c->value); break; case V4L2_CID_SATURATION: value = saa7146_read(dev, BCS_CTRL); c->value = 0x7f & (value >> 0); - DEB_D(("V4L2_CID_SATURATION: %d\n", c->value)); + DEB_D("V4L2_CID_SATURATION: %d\n", c->value); break; case V4L2_CID_VFLIP: c->value = vv->vflip; - DEB_D(("V4L2_CID_VFLIP: %d\n", c->value)); + DEB_D("V4L2_CID_VFLIP: %d\n", c->value); break; case V4L2_CID_HFLIP: c->value = vv->hflip; - DEB_D(("V4L2_CID_HFLIP: %d\n", c->value)); + DEB_D("V4L2_CID_HFLIP: %d\n", c->value); break; default: return -EINVAL; @@ -641,7 +645,7 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) ctrl = ctrl_by_id(c->id); if (NULL == ctrl) { - DEB_D(("unknown control %d\n", c->id)); + DEB_D("unknown control %d\n", c->id); return -EINVAL; } @@ -686,14 +690,14 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) case V4L2_CID_HFLIP: /* fixme: we can support changing VFLIP and HFLIP here... */ if (IS_CAPTURE_ACTIVE(fh) != 0) { - DEB_D(("V4L2_CID_HFLIP while active capture.\n")); + DEB_D("V4L2_CID_HFLIP while active capture\n"); return -EBUSY; } vv->hflip = c->value; break; case V4L2_CID_VFLIP: if (IS_CAPTURE_ACTIVE(fh) != 0) { - DEB_D(("V4L2_CID_VFLIP while active capture.\n")); + DEB_D("V4L2_CID_VFLIP while active capture\n"); return -EBUSY; } vv->vflip = c->value; @@ -748,7 +752,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_forma int maxw, maxh; int calc_bpl; - DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh)); + DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh); fmt = saa7146_format_by_fourcc(dev, f->fmt.pix.pixelformat); if (NULL == fmt) @@ -777,7 +781,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_forma vv->last_field = V4L2_FIELD_INTERLACED; break; default: - DEB_D(("no known field mode '%d'.\n", field)); + DEB_D("no known field mode '%d'\n", field); return -EINVAL; } @@ -796,8 +800,9 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_forma f->fmt.pix.bytesperline = calc_bpl; f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; - DEB_D(("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n", f->fmt.pix.width, - f->fmt.pix.height, f->fmt.pix.bytesperline, f->fmt.pix.sizeimage)); + DEB_D("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n", + f->fmt.pix.width, f->fmt.pix.height, + f->fmt.pix.bytesperline, f->fmt.pix.sizeimage); return 0; } @@ -811,22 +816,23 @@ static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_f enum v4l2_field field; int maxw, maxh; - DEB_EE(("dev:%p\n", dev)); + DEB_EE("dev:%p\n", dev); if (NULL == vv->ov_fb.base) { - DEB_D(("no fb base set.\n")); + DEB_D("no fb base set\n"); return -EINVAL; } if (NULL == vv->ov_fmt) { - DEB_D(("no fb fmt set.\n")); + DEB_D("no fb fmt set\n"); return -EINVAL; } if (win->w.width < 48 || win->w.height < 32) { - DEB_D(("min width/height. (%d,%d)\n", win->w.width, win->w.height)); + DEB_D("min width/height. (%d,%d)\n", + win->w.width, win->w.height); return -EINVAL; } if (win->clipcount > 16) { - DEB_D(("clipcount too big.\n")); + DEB_D("clipcount too big\n"); return -EINVAL; } @@ -848,7 +854,7 @@ static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_f case V4L2_FIELD_INTERLACED: break; default: - DEB_D(("no known field mode '%d'.\n", field)); + DEB_D("no known field mode '%d'\n", field); return -EINVAL; } @@ -868,16 +874,17 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *__fh, struct v4l2_forma struct saa7146_vv *vv = dev->vv_data; int err; - DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh)); + DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh); if (IS_CAPTURE_ACTIVE(fh) != 0) { - DEB_EE(("streaming capture is active\n")); + DEB_EE("streaming capture is active\n"); return -EBUSY; } err = vidioc_try_fmt_vid_cap(file, fh, f); if (0 != err) return err; fh->video_fmt = f->fmt.pix; - DEB_EE(("set to pixelformat '%4.4s'\n", (char *)&fh->video_fmt.pixelformat)); + DEB_EE("set to pixelformat '%4.4s'\n", + (char *)&fh->video_fmt.pixelformat); return 0; } @@ -888,7 +895,7 @@ static int vidioc_s_fmt_vid_overlay(struct file *file, void *__fh, struct v4l2_f struct saa7146_vv *vv = dev->vv_data; int err; - DEB_EE(("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n", dev, fh)); + DEB_EE("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n", dev, fh); err = vidioc_try_fmt_vid_overlay(file, fh, f); if (0 != err) return err; @@ -931,7 +938,7 @@ static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm) if (e->index < 0 ) return -EINVAL; if( e->index < dev->ext_vv_data->num_stds ) { - DEB_EE(("VIDIOC_ENUMSTD: index:%d\n",e->index)); + DEB_EE("VIDIOC_ENUMSTD: index:%d\n", e->index); v4l2_video_std_construct(e, dev->ext_vv_data->stds[e->index].id, dev->ext_vv_data->stds[e->index].name); return 0; } @@ -946,10 +953,10 @@ static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id) int found = 0; int err, i; - DEB_EE(("VIDIOC_S_STD\n")); + DEB_EE("VIDIOC_S_STD\n"); if ((vv->video_status & STATUS_CAPTURE) == STATUS_CAPTURE) { - DEB_D(("cannot change video standard while streaming capture is active\n")); + DEB_D("cannot change video standard while streaming capture is active\n"); return -EBUSY; } @@ -957,7 +964,7 @@ static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id) vv->ov_suspend = vv->video_fh; err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */ if (0 != err) { - DEB_D(("suspending video failed. aborting\n")); + DEB_D("suspending video failed. aborting\n"); return err; } } @@ -978,11 +985,11 @@ static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id) } if (!found) { - DEB_EE(("VIDIOC_S_STD: standard not found.\n")); + DEB_EE("VIDIOC_S_STD: standard not found\n"); return -EINVAL; } - DEB_EE(("VIDIOC_S_STD: set to standard to '%s'\n", vv->standard->name)); + DEB_EE("VIDIOC_S_STD: set to standard to '%s'\n", vv->standard->name); return 0; } @@ -990,7 +997,7 @@ static int vidioc_overlay(struct file *file, void *fh, unsigned int on) { int err; - DEB_D(("VIDIOC_OVERLAY on:%d\n", on)); + DEB_D("VIDIOC_OVERLAY on:%d\n", on); if (on) err = saa7146_start_preview(fh); else @@ -1047,7 +1054,7 @@ static int vidioc_streamon(struct file *file, void *__fh, enum v4l2_buf_type typ struct saa7146_fh *fh = __fh; int err; - DEB_D(("VIDIOC_STREAMON, type:%d\n", type)); + DEB_D("VIDIOC_STREAMON, type:%d\n", type); err = video_begin(fh); if (err) @@ -1066,18 +1073,18 @@ static int vidioc_streamoff(struct file *file, void *__fh, enum v4l2_buf_type ty struct saa7146_vv *vv = dev->vv_data; int err; - DEB_D(("VIDIOC_STREAMOFF, type:%d\n", type)); + DEB_D("VIDIOC_STREAMOFF, type:%d\n", type); /* ugly: we need to copy some checks from video_end(), because videobuf_streamoff() relies on the capture running. check and fix this */ if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) { - DEB_S(("not capturing.\n")); + DEB_S("not capturing\n"); return 0; } if (vv->video_fh != fh) { - DEB_S(("capturing, but in another open.\n")); + DEB_S("capturing, but in another open\n"); return -EBUSY; } @@ -1087,7 +1094,7 @@ static int vidioc_streamoff(struct file *file, void *__fh, enum v4l2_buf_type ty else if (type == V4L2_BUF_TYPE_VBI_CAPTURE) err = videobuf_streamoff(&fh->vbi_q); if (0 != err) { - DEB_D(("warning: videobuf_streamoff() failed.\n")); + DEB_D("warning: videobuf_streamoff() failed\n"); video_end(fh, file); } else { err = video_end(fh, file); @@ -1174,25 +1181,27 @@ static int buffer_prepare(struct videobuf_queue *q, struct saa7146_buf *buf = (struct saa7146_buf *)vb; int size,err = 0; - DEB_CAP(("vbuf:%p\n",vb)); + DEB_CAP("vbuf:%p\n", vb); /* sanity checks */ if (fh->video_fmt.width < 48 || fh->video_fmt.height < 32 || fh->video_fmt.width > vv->standard->h_max_out || fh->video_fmt.height > vv->standard->v_max_out) { - DEB_D(("w (%d) / h (%d) out of bounds.\n",fh->video_fmt.width,fh->video_fmt.height)); + DEB_D("w (%d) / h (%d) out of bounds\n", + fh->video_fmt.width, fh->video_fmt.height); return -EINVAL; } size = fh->video_fmt.sizeimage; if (0 != buf->vb.baddr && buf->vb.bsize < size) { - DEB_D(("size mismatch.\n")); + DEB_D("size mismatch\n"); return -EINVAL; } - DEB_CAP(("buffer_prepare [size=%dx%d,bytes=%d,fields=%s]\n", - fh->video_fmt.width,fh->video_fmt.height,size,v4l2_field_names[fh->video_fmt.field])); + DEB_CAP("buffer_prepare [size=%dx%d,bytes=%d,fields=%s]\n", + fh->video_fmt.width, fh->video_fmt.height, + size, v4l2_field_names[fh->video_fmt.field]); if (buf->vb.width != fh->video_fmt.width || buf->vb.bytesperline != fh->video_fmt.bytesperline || buf->vb.height != fh->video_fmt.height || @@ -1238,7 +1247,7 @@ static int buffer_prepare(struct videobuf_queue *q, return 0; oops: - DEB_D(("error out.\n")); + DEB_D("error out\n"); saa7146_dma_free(dev,q,buf); return err; @@ -1259,7 +1268,7 @@ static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned *count = (max_memory*1048576) / *size; } - DEB_CAP(("%d buffers, %d bytes each.\n",*count,*size)); + DEB_CAP("%d buffers, %d bytes each\n", *count, *size); return 0; } @@ -1272,7 +1281,7 @@ static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) struct saa7146_vv *vv = dev->vv_data; struct saa7146_buf *buf = (struct saa7146_buf *)vb; - DEB_CAP(("vbuf:%p\n",vb)); + DEB_CAP("vbuf:%p\n", vb); saa7146_buffer_queue(fh->dev,&vv->video_q,buf); } @@ -1283,7 +1292,7 @@ static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) struct saa7146_dev *dev = fh->dev; struct saa7146_buf *buf = (struct saa7146_buf *)vb; - DEB_CAP(("vbuf:%p\n",vb)); + DEB_CAP("vbuf:%p\n", vb); saa7146_dma_free(dev,q,buf); @@ -1368,7 +1377,7 @@ static void video_irq_done(struct saa7146_dev *dev, unsigned long st) struct saa7146_dmaqueue *q = &vv->video_q; spin_lock(&dev->slock); - DEB_CAP(("called.\n")); + DEB_CAP("called\n"); /* only finish the buffer if we have one... */ if( NULL != q->curr ) { @@ -1386,15 +1395,15 @@ static ssize_t video_read(struct file *file, char __user *data, size_t count, lo struct saa7146_vv *vv = dev->vv_data; ssize_t ret = 0; - DEB_EE(("called.\n")); + DEB_EE("called\n"); if ((vv->video_status & STATUS_CAPTURE) != 0) { /* fixme: should we allow read() captures while streaming capture? */ if (vv->video_fh == fh) { - DEB_S(("already capturing.\n")); + DEB_S("already capturing\n"); return -EBUSY; } - DEB_S(("already capturing in another open.\n")); + DEB_S("already capturing in another open\n"); return -EBUSY; } diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c index cdd31ca..ee8ee1d 100644 --- a/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/drivers/media/dvb/ttpci/av7110_v4l.c @@ -25,6 +25,8 @@ * the project's page is at http://www.linuxtv.org/ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -253,7 +255,7 @@ static int av7110_dvb_c_switch(struct saa7146_fh *fh) switch (av7110->current_input) { case 1: - dprintk(1, "switching SAA7113 to Analog Tuner Input.\n"); + dprintk(1, "switching SAA7113 to Analog Tuner Input\n"); msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0000); // loudspeaker source msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0000); // headphone source msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0000); // SCART 1 source @@ -263,7 +265,7 @@ static int av7110_dvb_c_switch(struct saa7146_fh *fh) if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) { if (ves1820_writereg(dev, 0x09, 0x0f, 0x60)) - dprintk(1, "setting band in demodulator failed.\n"); + dprintk(1, "setting band in demodulator failed\n"); } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // TDA9819 pin9(STD) saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); // TDA9819 pin30(VIF) @@ -272,17 +274,17 @@ static int av7110_dvb_c_switch(struct saa7146_fh *fh) dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num); break; case 2: - dprintk(1, "switching SAA7113 to Video AV CVBS Input.\n"); + dprintk(1, "switching SAA7113 to Video AV CVBS Input\n"); if (i2c_writereg(av7110, 0x48, 0x02, 0xd2) != 1) dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num); break; case 3: - dprintk(1, "switching SAA7113 to Video AV Y/C Input.\n"); + dprintk(1, "switching SAA7113 to Video AV Y/C Input\n"); if (i2c_writereg(av7110, 0x48, 0x02, 0xd9) != 1) dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num); break; default: - dprintk(1, "switching SAA7113 to Input: AV7110: SAA7113: invalid input.\n"); + dprintk(1, "switching SAA7113 to Input: AV7110: SAA7113: invalid input\n"); } } else { adswitch = 0; @@ -299,7 +301,7 @@ static int av7110_dvb_c_switch(struct saa7146_fh *fh) if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) { if (ves1820_writereg(dev, 0x09, 0x0f, 0x20)) - dprintk(1, "setting band in demodulator failed.\n"); + dprintk(1, "setting band in demodulator failed\n"); } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD) saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF) @@ -413,7 +415,7 @@ static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; - dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x.\n", f->frequency); + dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x\n", f->frequency); if (!av7110->analog_tuner_flags || av7110->current_input != 1) return -EINVAL; @@ -429,7 +431,7 @@ static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; - dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x.\n", f->frequency); + dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x\n", f->frequency); if (!av7110->analog_tuner_flags || av7110->current_input != 1) return -EINVAL; @@ -689,12 +691,12 @@ int av7110_init_analog_module(struct av7110 *av7110) if (i2c_writereg(av7110, 0x80, 0x0, 0x80) == 1 && i2c_writereg(av7110, 0x80, 0x0, 0) == 1) { - printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n", + pr_info("DVB-C analog module @ card %d detected, initializing MSP3400\n", av7110->dvb_adapter.num); av7110->adac_type = DVB_ADAC_MSP34x0; } else if (i2c_writereg(av7110, 0x84, 0x0, 0x80) == 1 && i2c_writereg(av7110, 0x84, 0x0, 0) == 1) { - printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3415\n", + pr_info("DVB-C analog module @ card %d detected, initializing MSP3415\n", av7110->dvb_adapter.num); av7110->adac_type = DVB_ADAC_MSP34x5; } else @@ -715,7 +717,7 @@ int av7110_init_analog_module(struct av7110 *av7110) msp_writereg(av7110, MSP_WR_DSP, 0x000d, 0x1900); // prescale SCART if (i2c_writereg(av7110, 0x48, 0x01, 0x00)!=1) { - INFO(("saa7113 not accessible.\n")); + pr_info("saa7113 not accessible\n"); } else { u8 *i = saa7113_init_regs; @@ -733,7 +735,7 @@ int av7110_init_analog_module(struct av7110 *av7110) /* setup for DVB by default */ if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) { if (ves1820_writereg(av7110->dev, 0x09, 0x0f, 0x20)) - dprintk(1, "setting band in demodulator failed.\n"); + dprintk(1, "setting band in demodulator failed\n"); } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD) saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF) @@ -797,7 +799,7 @@ int av7110_init_v4l(struct av7110 *av7110) ret = saa7146_vv_init(dev, vv_data); if (ret) { - ERR(("cannot init capture device. skipping.\n")); + ERR("cannot init capture device. skipping\n"); return -ENODEV; } vv_data->ops.vidioc_enum_input = vidioc_enum_input; @@ -814,12 +816,12 @@ int av7110_init_v4l(struct av7110 *av7110) vv_data->ops.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out; if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) { - ERR(("cannot register capture device. skipping.\n")); + ERR("cannot register capture device. skipping\n"); saa7146_vv_release(dev); return -ENODEV; } if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) - ERR(("cannot register vbi v4l2 device. skipping.\n")); + ERR("cannot register vbi v4l2 device. skipping\n"); return 0; } diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 5b28bc6..91b7d53 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -33,6 +33,8 @@ * the project's page is at http://www.linuxtv.org/ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "budget.h" #include "stv0299.h" #include "stb0899_drv.h" @@ -149,7 +151,7 @@ static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int ad result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1); if (result == -ETIMEDOUT) { ciintf_slot_shutdown(ca, slot); - printk(KERN_INFO "budget-av: cam ejected 1\n"); + pr_info("cam ejected 1\n"); } return result; } @@ -168,7 +170,7 @@ static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int a result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1); if (result == -ETIMEDOUT) { ciintf_slot_shutdown(ca, slot); - printk(KERN_INFO "budget-av: cam ejected 2\n"); + pr_info("cam ejected 2\n"); } return result; } @@ -187,7 +189,7 @@ static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 addre result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0); if (result == -ETIMEDOUT) { ciintf_slot_shutdown(ca, slot); - printk(KERN_INFO "budget-av: cam ejected 3\n"); + pr_info("cam ejected 3\n"); return -ETIMEDOUT; } return result; @@ -207,7 +209,7 @@ static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 addr result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0); if (result == -ETIMEDOUT) { ciintf_slot_shutdown(ca, slot); - printk(KERN_INFO "budget-av: cam ejected 5\n"); + pr_info("cam ejected 5\n"); } return result; } @@ -289,7 +291,7 @@ static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open if (saa7146_read(saa, PSR) & MASK_06) { if (budget_av->slot_status == SLOTSTATUS_NONE) { budget_av->slot_status = SLOTSTATUS_PRESENT; - printk(KERN_INFO "budget-av: cam inserted A\n"); + pr_info("cam inserted A\n"); } } saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); @@ -306,11 +308,11 @@ static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1); if ((result >= 0) && (budget_av->slot_status == SLOTSTATUS_NONE)) { budget_av->slot_status = SLOTSTATUS_PRESENT; - printk(KERN_INFO "budget-av: cam inserted B\n"); + pr_info("cam inserted B\n"); } else if (result < 0) { if (budget_av->slot_status != SLOTSTATUS_NONE) { ciintf_slot_shutdown(ca, slot); - printk(KERN_INFO "budget-av: cam ejected 5\n"); + pr_info("cam ejected 5\n"); return 0; } } @@ -365,11 +367,11 @@ static int ciintf_init(struct budget_av *budget_av) if ((result = dvb_ca_en50221_init(&budget_av->budget.dvb_adapter, &budget_av->ca, 0, 1)) != 0) { - printk(KERN_ERR "budget-av: ci initialisation failed.\n"); + pr_err("ci initialisation failed\n"); goto error; } - printk(KERN_INFO "budget-av: ci interface initialised.\n"); + pr_info("ci interface initialised\n"); return 0; error: @@ -1345,8 +1347,7 @@ static void frontend_init(struct budget_av *budget_av) } if (fe == NULL) { - printk(KERN_ERR "budget-av: A frontend driver was not found " - "for device [%04x:%04x] subsystem [%04x:%04x]\n", + pr_err("A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", saa->pci->vendor, saa->pci->device, saa->pci->subsystem_vendor, @@ -1358,7 +1359,7 @@ static void frontend_init(struct budget_av *budget_av) if (dvb_register_frontend(&budget_av->budget.dvb_adapter, budget_av->budget.dvb_frontend)) { - printk(KERN_ERR "budget-av: Frontend registration failed!\n"); + pr_err("Frontend registration failed!\n"); dvb_frontend_detach(budget_av->budget.dvb_frontend); budget_av->budget.dvb_frontend = NULL; } @@ -1416,7 +1417,7 @@ static struct v4l2_input knc1_inputs[KNC1_INPUTS] = { static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) { - dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index); + dprintk(1, "VIDIOC_ENUMINPUT %d\n", i->index); if (i->index >= KNC1_INPUTS) return -EINVAL; memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input)); @@ -1430,7 +1431,7 @@ static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) *i = budget_av->cur_input; - dprintk(1, "VIDIOC_G_INPUT %d.\n", *i); + dprintk(1, "VIDIOC_G_INPUT %d\n", *i); return 0; } @@ -1439,7 +1440,7 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input) struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; struct budget_av *budget_av = (struct budget_av *)dev->ext_priv; - dprintk(1, "VIDIOC_S_INPUT %d.\n", input); + dprintk(1, "VIDIOC_S_INPUT %d\n", input); return saa7113_setinput(budget_av, input); } @@ -1478,7 +1479,7 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio if (0 != saa7146_vv_init(dev, &vv_data)) { /* fixme: proper cleanup here */ - ERR(("cannot init vv subsystem.\n")); + ERR("cannot init vv subsystem\n"); return err; } vv_data.ops.vidioc_enum_input = vidioc_enum_input; @@ -1487,7 +1488,7 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) { /* fixme: proper cleanup here */ - ERR(("cannot register capture v4l2 device.\n")); + ERR("cannot register capture v4l2 device\n"); saa7146_vv_release(dev); return err; } @@ -1504,13 +1505,12 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio mac = budget_av->budget.dvb_adapter.proposed_mac; if (i2c_readregs(&budget_av->budget.i2c_adap, 0xa0, 0x30, mac, 6)) { - printk(KERN_ERR "KNC1-%d: Could not read MAC from KNC1 card\n", + pr_err("KNC1-%d: Could not read MAC from KNC1 card\n", budget_av->budget.dvb_adapter.num); memset(mac, 0, 6); } else { - printk(KERN_INFO "KNC1-%d: MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", - budget_av->budget.dvb_adapter.num, - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + pr_info("KNC1-%d: MAC addr = %pM\n", + budget_av->budget.dvb_adapter.num, mac); } budget_av->budget.dvb_adapter.priv = budget_av; diff --git a/drivers/media/video/hexium_gemini.c b/drivers/media/video/hexium_gemini.c index b37c12f..9cb039e 100644 --- a/drivers/media/video/hexium_gemini.c +++ b/drivers/media/video/hexium_gemini.c @@ -21,6 +21,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define DEBUG_VARIABLE debug #include @@ -175,13 +177,14 @@ static int hexium_init_done(struct saa7146_dev *dev) union i2c_smbus_data data; int i = 0; - DEB_D(("hexium_init_done called.\n")); + DEB_D("hexium_init_done called\n"); /* initialize the helper ics to useful values */ for (i = 0; i < sizeof(hexium_ks0127b); i++) { data.byte = hexium_ks0127b[i]; if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) { - printk("hexium_gemini: hexium_init_done() failed for address 0x%02x\n", i); + pr_err("hexium_init_done() failed for address 0x%02x\n", + i); } } @@ -192,7 +195,7 @@ static int hexium_set_input(struct hexium *hexium, int input) { union i2c_smbus_data data; - DEB_D((".\n")); + DEB_D("\n"); data.byte = hexium_input_select[input].byte; if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, hexium_input_select[input].adr, I2C_SMBUS_BYTE_DATA, &data)) { @@ -207,12 +210,13 @@ static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec) union i2c_smbus_data data; int i = 0; - DEB_D((".\n")); + DEB_D("\n"); while (vdec[i].adr != -1) { data.byte = vdec[i].byte; if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, vdec[i].adr, I2C_SMBUS_BYTE_DATA, &data)) { - printk("hexium_init_done: hexium_set_standard() failed for address 0x%02x\n", i); + pr_err("hexium_init_done: hexium_set_standard() failed for address 0x%02x\n", + i); return -1; } i++; @@ -222,14 +226,14 @@ static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec) static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) { - DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); + DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index); if (i->index >= HEXIUM_INPUTS) return -EINVAL; memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); - DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index)); + DEB_D("v4l2_ioctl: VIDIOC_ENUMINPUT %d\n", i->index); return 0; } @@ -240,7 +244,7 @@ static int vidioc_g_input(struct file *file, void *fh, unsigned int *input) *input = hexium->cur_input; - DEB_D(("VIDIOC_G_INPUT: %d\n", *input)); + DEB_D("VIDIOC_G_INPUT: %d\n", *input); return 0; } @@ -249,7 +253,7 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input) struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; struct hexium *hexium = (struct hexium *) dev->ext_priv; - DEB_EE(("VIDIOC_S_INPUT %d.\n", input)); + DEB_EE("VIDIOC_S_INPUT %d\n", input); if (input >= HEXIUM_INPUTS) return -EINVAL; @@ -270,7 +274,7 @@ static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl * for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { if (hexium_controls[i].id == qc->id) { *qc = hexium_controls[i]; - DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id)); + DEB_D("VIDIOC_QUERYCTRL %d\n", qc->id); return 0; } } @@ -293,7 +297,7 @@ static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc) if (vc->id == V4L2_CID_PRIVATE_BASE) { vc->value = hexium->cur_bw; - DEB_D(("VIDIOC_G_CTRL BW:%d.\n", vc->value)); + DEB_D("VIDIOC_G_CTRL BW:%d\n", vc->value); return 0; } return -EINVAL; @@ -316,7 +320,7 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc) if (vc->id == V4L2_CID_PRIVATE_BASE) hexium->cur_bw = vc->value; - DEB_D(("VIDIOC_S_CTRL BW:%d.\n", hexium->cur_bw)); + DEB_D("VIDIOC_S_CTRL BW:%d\n", hexium->cur_bw); if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) { hexium_set_standard(hexium, hexium_pal); @@ -354,11 +358,11 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d struct hexium *hexium; int ret; - DEB_EE((".\n")); + DEB_EE("\n"); hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL); if (NULL == hexium) { - printk("hexium_gemini: not enough kernel memory in hexium_attach().\n"); + pr_err("not enough kernel memory in hexium_attach()\n"); return -ENOMEM; } dev->ext_priv = hexium; @@ -371,7 +375,7 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d }; saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480); if (i2c_add_adapter(&hexium->i2c_adapter) < 0) { - DEB_S(("cannot register i2c-device. skipping.\n")); + DEB_S("cannot register i2c-device. skipping.\n"); kfree(hexium); return -EFAULT; } @@ -402,11 +406,11 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d vv_data.ops.vidioc_s_input = vidioc_s_input; ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER); if (ret < 0) { - printk("hexium_gemini: cannot register capture v4l2 device. skipping.\n"); + pr_err("cannot register capture v4l2 device. skipping.\n"); return ret; } - printk("hexium_gemini: found 'hexium gemini' frame grabber-%d.\n", hexium_num); + pr_info("found 'hexium gemini' frame grabber-%d\n", hexium_num); hexium_num++; return 0; @@ -416,7 +420,7 @@ static int hexium_detach(struct saa7146_dev *dev) { struct hexium *hexium = (struct hexium *) dev->ext_priv; - DEB_EE(("dev:%p\n", dev)); + DEB_EE("dev:%p\n", dev); saa7146_unregister_device(&hexium->video_dev, dev); saa7146_vv_release(dev); @@ -508,7 +512,7 @@ static struct saa7146_extension hexium_extension = { static int __init hexium_init_module(void) { if (0 != saa7146_register_extension(&hexium_extension)) { - DEB_S(("failed to register extension.\n")); + DEB_S("failed to register extension\n"); return -ENODEV; } diff --git a/drivers/media/video/hexium_orion.c b/drivers/media/video/hexium_orion.c index 6ad7e1c..74861a4 100644 --- a/drivers/media/video/hexium_orion.c +++ b/drivers/media/video/hexium_orion.c @@ -21,6 +21,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define DEBUG_VARIABLE debug #include @@ -209,7 +211,7 @@ static int hexium_probe(struct saa7146_dev *dev) union i2c_smbus_data data; int err = 0; - DEB_EE((".\n")); + DEB_EE("\n"); /* there are no hexium orion cards with revision 0 saa7146s */ if (0 == dev->revision) { @@ -218,7 +220,7 @@ static int hexium_probe(struct saa7146_dev *dev) hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL); if (NULL == hexium) { - printk("hexium_orion: hexium_probe: not enough kernel memory.\n"); + pr_err("hexium_probe: not enough kernel memory\n"); return -ENOMEM; } @@ -234,7 +236,7 @@ static int hexium_probe(struct saa7146_dev *dev) }; saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480); if (i2c_add_adapter(&hexium->i2c_adapter) < 0) { - DEB_S(("cannot register i2c-device. skipping.\n")); + DEB_S("cannot register i2c-device. skipping.\n"); kfree(hexium); return -EFAULT; } @@ -248,7 +250,7 @@ static int hexium_probe(struct saa7146_dev *dev) /* detect newer Hexium Orion cards by subsystem ids */ if (0x17c8 == dev->pci->subsystem_vendor && 0x0101 == dev->pci->subsystem_device) { - printk("hexium_orion: device is a Hexium Orion w/ 1 SVHS + 3 BNC inputs.\n"); + pr_info("device is a Hexium Orion w/ 1 SVHS + 3 BNC inputs\n"); /* we store the pointer in our private data field */ dev->ext_priv = hexium; hexium->type = HEXIUM_ORION_1SVHS_3BNC; @@ -256,7 +258,7 @@ static int hexium_probe(struct saa7146_dev *dev) } if (0x17c8 == dev->pci->subsystem_vendor && 0x2101 == dev->pci->subsystem_device) { - printk("hexium_orion: device is a Hexium Orion w/ 4 BNC inputs.\n"); + pr_info("device is a Hexium Orion w/ 4 BNC inputs\n"); /* we store the pointer in our private data field */ dev->ext_priv = hexium; hexium->type = HEXIUM_ORION_4BNC; @@ -266,7 +268,7 @@ static int hexium_probe(struct saa7146_dev *dev) /* check if this is an old hexium Orion card by looking at a saa7110 at address 0x4e */ if (0 == (err = i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, &data))) { - printk("hexium_orion: device is a Hexium HV-PCI6/Orion (old).\n"); + pr_info("device is a Hexium HV-PCI6/Orion (old)\n"); /* we store the pointer in our private data field */ dev->ext_priv = hexium; hexium->type = HEXIUM_HV_PCI6_ORION; @@ -288,13 +290,13 @@ static int hexium_init_done(struct saa7146_dev *dev) union i2c_smbus_data data; int i = 0; - DEB_D(("hexium_init_done called.\n")); + DEB_D("hexium_init_done called\n"); /* initialize the helper ics to useful values */ for (i = 0; i < sizeof(hexium_saa7110); i++) { data.byte = hexium_saa7110[i]; if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) { - printk("hexium_orion: failed for address 0x%02x\n", i); + pr_err("failed for address 0x%02x\n", i); } } @@ -306,7 +308,7 @@ static int hexium_set_input(struct hexium *hexium, int input) union i2c_smbus_data data; int i = 0; - DEB_D((".\n")); + DEB_D("\n"); for (i = 0; i < 8; i++) { int adr = hexium_input_select[input].data[i].adr; @@ -314,7 +316,7 @@ static int hexium_set_input(struct hexium *hexium, int input) if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, adr, I2C_SMBUS_BYTE_DATA, &data)) { return -1; } - printk("%d: 0x%02x => 0x%02x\n",input, adr,data.byte); + pr_debug("%d: 0x%02x => 0x%02x\n", input, adr, data.byte); } return 0; @@ -322,14 +324,14 @@ static int hexium_set_input(struct hexium *hexium, int input) static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) { - DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); + DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index); if (i->index >= HEXIUM_INPUTS) return -EINVAL; memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); - DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index)); + DEB_D("v4l2_ioctl: VIDIOC_ENUMINPUT %d\n", i->index); return 0; } @@ -340,7 +342,7 @@ static int vidioc_g_input(struct file *file, void *fh, unsigned int *input) *input = hexium->cur_input; - DEB_D(("VIDIOC_G_INPUT: %d\n", *input)); + DEB_D("VIDIOC_G_INPUT: %d\n", *input); return 0; } @@ -365,18 +367,18 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d { struct hexium *hexium = (struct hexium *) dev->ext_priv; - DEB_EE((".\n")); + DEB_EE("\n"); saa7146_vv_init(dev, &vv_data); vv_data.ops.vidioc_enum_input = vidioc_enum_input; vv_data.ops.vidioc_g_input = vidioc_g_input; vv_data.ops.vidioc_s_input = vidioc_s_input; if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) { - printk("hexium_orion: cannot register capture v4l2 device. skipping.\n"); + pr_err("cannot register capture v4l2 device. skipping.\n"); return -1; } - printk("hexium_orion: found 'hexium orion' frame grabber-%d.\n", hexium_num); + pr_err("found 'hexium orion' frame grabber-%d\n", hexium_num); hexium_num++; /* the rest */ @@ -390,7 +392,7 @@ static int hexium_detach(struct saa7146_dev *dev) { struct hexium *hexium = (struct hexium *) dev->ext_priv; - DEB_EE(("dev:%p\n", dev)); + DEB_EE("dev:%p\n", dev); saa7146_unregister_device(&hexium->video_dev, dev); saa7146_vv_release(dev); @@ -479,7 +481,7 @@ static struct saa7146_extension extension = { static int __init hexium_init_module(void) { if (0 != saa7146_register_extension(&extension)) { - DEB_S(("failed to register extension.\n")); + DEB_S("failed to register extension\n"); return -ENODEV; } diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c index 0b38500..f0c3968 100644 --- a/drivers/media/video/mxb.c +++ b/drivers/media/video/mxb.c @@ -21,6 +21,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define DEBUG_VARIABLE debug #include @@ -171,7 +173,7 @@ static int mxb_probe(struct saa7146_dev *dev) mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL); if (mxb == NULL) { - DEB_D(("not enough kernel memory.\n")); + DEB_D("not enough kernel memory\n"); return -ENOMEM; } @@ -179,7 +181,7 @@ static int mxb_probe(struct saa7146_dev *dev) saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480); if (i2c_add_adapter(&mxb->i2c_adapter) < 0) { - DEB_S(("cannot register i2c-device. skipping.\n")); + DEB_S("cannot register i2c-device. skipping.\n"); kfree(mxb); return -EFAULT; } @@ -200,7 +202,7 @@ static int mxb_probe(struct saa7146_dev *dev) /* check if all devices are present */ if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c || !mxb->tda9840 || !mxb->saa7111a || !mxb->tuner) { - printk("mxb: did not find all i2c devices. aborting\n"); + pr_err("did not find all i2c devices. aborting\n"); i2c_del_adapter(&mxb->i2c_adapter); kfree(mxb); return -ENODEV; @@ -346,11 +348,11 @@ static int mxb_init_done(struct saa7146_dev* dev) msg.buf = &mxb_saa7740_init[i].data[0]; err = i2c_transfer(&mxb->i2c_adapter, &msg, 1); if (err != 1) { - DEB_D(("failed to initialize 'sound arena module'.\n")); + DEB_D("failed to initialize 'sound arena module'\n"); goto err; } } - INFO(("'sound arena module' detected.\n")); + pr_info("'sound arena module' detected\n"); } err: /* the rest for saa7146: you should definitely set some basic values @@ -390,7 +392,7 @@ static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl * for (i = MAXCONTROLS - 1; i >= 0; i--) { if (mxb_controls[i].id == qc->id) { *qc = mxb_controls[i]; - DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id)); + DEB_D("VIDIOC_QUERYCTRL %d\n", qc->id); return 0; } } @@ -413,11 +415,11 @@ static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc) if (vc->id == V4L2_CID_AUDIO_MUTE) { vc->value = mxb->cur_mute; - DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value)); + DEB_D("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d\n", vc->value); return 0; } - DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value)); + DEB_EE("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d\n", vc->value); return 0; } @@ -440,14 +442,14 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc) /* switch the audio-source */ tea6420_route_line(mxb, vc->value ? 6 : video_audio_connect[mxb->cur_input]); - DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n", vc->value)); + DEB_EE("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d\n", vc->value); } return 0; } static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) { - DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); + DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index); if (i->index >= MXB_INPUTS) return -EINVAL; memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input)); @@ -460,7 +462,7 @@ static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) struct mxb *mxb = (struct mxb *)dev->ext_priv; *i = mxb->cur_input; - DEB_EE(("VIDIOC_G_INPUT %d.\n", *i)); + DEB_EE("VIDIOC_G_INPUT %d\n", *i); return 0; } @@ -471,7 +473,7 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input) int err = 0; int i = 0; - DEB_EE(("VIDIOC_S_INPUT %d.\n", input)); + DEB_EE("VIDIOC_S_INPUT %d\n", input); if (input >= MXB_INPUTS) return -EINVAL; @@ -514,7 +516,7 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input) /* switch video in saa7111a */ if (saa7111a_call(mxb, video, s_routing, i, SAA7111_FMT_CCIR, 0)) - printk(KERN_ERR "VIDIOC_S_INPUT: could not address saa7111a.\n"); + pr_err("VIDIOC_S_INPUT: could not address saa7111a\n"); /* switch the audio-source only if necessary */ if (0 == mxb->cur_mute) @@ -529,11 +531,12 @@ static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t) struct mxb *mxb = (struct mxb *)dev->ext_priv; if (t->index) { - DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index)); + DEB_D("VIDIOC_G_TUNER: channel %d does not have a tuner attached\n", + t->index); return -EINVAL; } - DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index)); + DEB_EE("VIDIOC_G_TUNER: %d\n", t->index); memset(t, 0, sizeof(*t)); strlcpy(t->name, "TV Tuner", sizeof(t->name)); @@ -550,7 +553,8 @@ static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t) struct mxb *mxb = (struct mxb *)dev->ext_priv; if (t->index) { - DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n", t->index)); + DEB_D("VIDIOC_S_TUNER: channel %d does not have a tuner attached\n", + t->index); return -EINVAL; } @@ -564,14 +568,14 @@ static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency struct mxb *mxb = (struct mxb *)dev->ext_priv; if (mxb->cur_input) { - DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n", - mxb->cur_input)); + DEB_D("VIDIOC_G_FREQ: channel %d does not have a tuner!\n", + mxb->cur_input); return -EINVAL; } *f = mxb->cur_freq; - DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency)); + DEB_EE("VIDIOC_G_FREQ: freq:0x%08x\n", mxb->cur_freq.frequency); return 0; } @@ -588,12 +592,13 @@ static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency return -EINVAL; if (mxb->cur_input) { - DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", mxb->cur_input)); + DEB_D("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", + mxb->cur_input); return -EINVAL; } mxb->cur_freq = *f; - DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency)); + DEB_EE("VIDIOC_S_FREQUENCY: freq:0x%08x\n", mxb->cur_freq.frequency); /* tune in desired frequency */ tuner_call(mxb, tuner, s_frequency, &mxb->cur_freq); @@ -612,18 +617,18 @@ static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a) struct mxb *mxb = (struct mxb *)dev->ext_priv; if (a->index > MXB_INPUTS) { - DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index)); + DEB_D("VIDIOC_G_AUDIO %d out of range\n", a->index); return -EINVAL; } - DEB_EE(("VIDIOC_G_AUDIO %d.\n", a->index)); + DEB_EE("VIDIOC_G_AUDIO %d\n", a->index); memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio)); return 0; } static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a) { - DEB_D(("VIDIOC_S_AUDIO %d.\n", a->index)); + DEB_D("VIDIOC_S_AUDIO %d\n", a->index); return 0; } @@ -655,11 +660,11 @@ static long vidioc_default(struct file *file, void *fh, bool valid_prio, int i = *(int *)arg; if (i < 0 || i >= MXB_AUDIOS) { - DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n", i)); + DEB_D("invalid argument to MXB_S_AUDIO_CD: i:%d\n", i); return -EINVAL; } - DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n", i)); + DEB_EE("MXB_S_AUDIO_CD: i:%d\n", i); tea6420_route_cd(mxb, i); return 0; @@ -669,17 +674,18 @@ static long vidioc_default(struct file *file, void *fh, bool valid_prio, int i = *(int *)arg; if (i < 0 || i >= MXB_AUDIOS) { - DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n", i)); + DEB_D("invalid argument to MXB_S_AUDIO_LINE: i:%d\n", + i); return -EINVAL; } - DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n", i)); + DEB_EE("MXB_S_AUDIO_LINE: i:%d\n", i); tea6420_route_line(mxb, i); return 0; } default: /* - DEB2(printk("does not handle this ioctl.\n")); + DEB2(pr_err("does not handle this ioctl\n")); */ return -ENOIOCTLCMD; } @@ -693,7 +699,7 @@ static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data { struct mxb *mxb; - DEB_EE(("dev:%p\n", dev)); + DEB_EE("dev:%p\n", dev); saa7146_vv_init(dev, &vv_data); if (mxb_probe(dev)) { @@ -720,7 +726,7 @@ static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data #endif vv_data.ops.vidioc_default = vidioc_default; if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) { - ERR(("cannot register capture v4l2 device. skipping.\n")); + ERR("cannot register capture v4l2 device. skipping.\n"); saa7146_vv_release(dev); return -1; } @@ -728,11 +734,11 @@ static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/ if (MXB_BOARD_CAN_DO_VBI(dev)) { if (saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) { - ERR(("cannot register vbi v4l2 device. skipping.\n")); + ERR("cannot register vbi v4l2 device. skipping.\n"); } } - printk("mxb: found Multimedia eXtension Board #%d.\n", mxb_num); + pr_info("found Multimedia eXtension Board #%d\n", mxb_num); mxb_num++; mxb_init_done(dev); @@ -743,7 +749,7 @@ static int mxb_detach(struct saa7146_dev *dev) { struct mxb *mxb = (struct mxb *)dev->ext_priv; - DEB_EE(("dev:%p\n", dev)); + DEB_EE("dev:%p\n", dev); saa7146_unregister_device(&mxb->video_dev,dev); if (MXB_BOARD_CAN_DO_VBI(dev)) @@ -765,7 +771,7 @@ static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standa if (V4L2_STD_PAL_I == standard->id) { v4l2_std_id std = V4L2_STD_PAL_I; - DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n")); + DEB_D("VIDIOC_S_STD: setting mxb for PAL_I\n"); /* set the 7146 gpio register -- I don't know what this does exactly */ saa7146_write(dev, GPIO_CTRL, 0x00404050); /* unset the 7111 gpio register -- I don't know what this does exactly */ @@ -774,7 +780,7 @@ static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standa } else { v4l2_std_id std = V4L2_STD_PAL_BG; - DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n")); + DEB_D("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM\n"); /* set the 7146 gpio register -- I don't know what this does exactly */ saa7146_write(dev, GPIO_CTRL, 0x00404050); /* set the 7111 gpio register -- I don't know what this does exactly */ @@ -852,7 +858,7 @@ static struct saa7146_extension extension = { static int __init mxb_init_module(void) { if (saa7146_register_extension(&extension)) { - DEB_S(("failed to register extension.\n")); + DEB_S("failed to register extension\n"); return -ENODEV; } diff --git a/include/media/saa7146.h b/include/media/saa7146.h index 7982714..5017500 100644 --- a/include/media/saa7146.h +++ b/include/media/saa7146.h @@ -25,24 +25,32 @@ extern unsigned int saa7146_debug; -//#define DEBUG_PROLOG printk("(0x%08x)(0x%08x) %s: %s(): ",(dev==0?-1:(dev->mem==0?-1:saa7146_read(dev,RPS_ADDR0))),(dev==0?-1:(dev->mem==0?-1:saa7146_read(dev,IER))),KBUILD_MODNAME,__func__) - #ifndef DEBUG_VARIABLE #define DEBUG_VARIABLE saa7146_debug #endif -#define DEBUG_PROLOG printk("%s: %s(): ",KBUILD_MODNAME, __func__) -#define INFO(x) { printk("%s: ",KBUILD_MODNAME); printk x; } - -#define ERR(x) { DEBUG_PROLOG; printk x; } - -#define DEB_S(x) if (0!=(DEBUG_VARIABLE&0x01)) { DEBUG_PROLOG; printk x; } /* simple debug messages */ -#define DEB_D(x) if (0!=(DEBUG_VARIABLE&0x02)) { DEBUG_PROLOG; printk x; } /* more detailed debug messages */ -#define DEB_EE(x) if (0!=(DEBUG_VARIABLE&0x04)) { DEBUG_PROLOG; printk x; } /* print enter and exit of functions */ -#define DEB_I2C(x) if (0!=(DEBUG_VARIABLE&0x08)) { DEBUG_PROLOG; printk x; } /* i2c debug messages */ -#define DEB_VBI(x) if (0!=(DEBUG_VARIABLE&0x10)) { DEBUG_PROLOG; printk x; } /* vbi debug messages */ -#define DEB_INT(x) if (0!=(DEBUG_VARIABLE&0x20)) { DEBUG_PROLOG; printk x; } /* interrupt debug messages */ -#define DEB_CAP(x) if (0!=(DEBUG_VARIABLE&0x40)) { DEBUG_PROLOG; printk x; } /* capture debug messages */ +#define ERR(fmt, ...) pr_err("%s: " fmt, __func__, ##__VA_ARGS__) + +#define _DBG(mask, fmt, ...) \ +do { \ + if (DEBUG_VARIABLE & mask) \ + pr_debug("%s(): " fmt, __func__, ##__VA_ARGS__); \ +} while (0) + +/* simple debug messages */ +#define DEB_S(fmt, ...) _DBG(0x01, fmt, ##__VA_ARGS__) +/* more detailed debug messages */ +#define DEB_D(fmt, ...) _DBG(0x02, fmt, ##__VA_ARGS__) +/* print enter and exit of functions */ +#define DEB_EE(fmt, ...) _DBG(0x04, fmt, ##__VA_ARGS__) +/* i2c debug messages */ +#define DEB_I2C(fmt, ...) _DBG(0x08, fmt, ##__VA_ARGS__) +/* vbi debug messages */ +#define DEB_VBI(fmt, ...) _DBG(0x10, fmt, ##__VA_ARGS__) +/* interrupt debug messages */ +#define DEB_INT(fmt, ...) _DBG(0x20, fmt, ##__VA_ARGS__) +/* capture debug messages */ +#define DEB_CAP(fmt, ...) _DBG(0x40, fmt, ##__VA_ARGS__) #define SAA7146_ISR_CLEAR(x,y) \ saa7146_write(x, ISR, (y)); -- cgit v0.10.2 From 86b0dbef777a1fbb9922e304f047921d4e9d9c40 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 21 Aug 2011 19:56:45 -0300 Subject: [media] rc-core.h: Surround macro with do {} while (0) Macros coded with if statements should be do { if... } while (0) so the macros can be used in other if tests. Use ##__VA_ARGS__ for variadic macro as well. Signed-off-by: Joe Perches Signed-off-by: Mauro Carvalho Chehab diff --git a/include/media/rc-core.h b/include/media/rc-core.h index b1f19b7..b0c494a 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h @@ -23,8 +23,11 @@ #include extern int rc_core_debug; -#define IR_dprintk(level, fmt, arg...) if (rc_core_debug >= level) \ - printk(KERN_DEBUG "%s: " fmt , __func__, ## arg) +#define IR_dprintk(level, fmt, ...) \ +do { \ + if (rc_core_debug >= level) \ + pr_debug("%s: " fmt, __func__, ##__VA_ARGS__); \ +} while (0) enum rc_driver_type { RC_DRIVER_SCANCODE = 0, /* Driver or hardware generates a scancode */ -- cgit v0.10.2 From 7de3461c93a6d65355113cca333723eb8a1a0225 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 21 Aug 2011 19:56:46 -0300 Subject: [media] ene_ir: Use current logging styles Add pr_fmt. Convert ene_warn and ene_notice to pr_. Use pr_debug in __dbg macro and a little neatening. Signed-off-by: Joe Perches Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index 2b9c2569..cf10ecf 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -30,6 +30,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -118,31 +120,31 @@ static int ene_hw_detect(struct ene_device *dev) dev->pll_freq == ENE_DEFAULT_PLL_FREQ ? 2 : 4; if (hw_revision == 0xFF) { - ene_warn("device seems to be disabled"); - ene_warn("send a mail to lirc-list@lists.sourceforge.net"); - ene_warn("please attach output of acpidump and dmidecode"); + pr_warn("device seems to be disabled\n"); + pr_warn("send a mail to lirc-list@lists.sourceforge.net\n"); + pr_warn("please attach output of acpidump and dmidecode\n"); return -ENODEV; } - ene_notice("chip is 0x%02x%02x - kbver = 0x%02x, rev = 0x%02x", - chip_major, chip_minor, old_ver, hw_revision); + pr_notice("chip is 0x%02x%02x - kbver = 0x%02x, rev = 0x%02x\n", + chip_major, chip_minor, old_ver, hw_revision); - ene_notice("PLL freq = %d", dev->pll_freq); + pr_notice("PLL freq = %d\n", dev->pll_freq); if (chip_major == 0x33) { - ene_warn("chips 0x33xx aren't supported"); + pr_warn("chips 0x33xx aren't supported\n"); return -ENODEV; } if (chip_major == 0x39 && chip_minor == 0x26 && hw_revision == 0xC0) { dev->hw_revision = ENE_HW_C; - ene_notice("KB3926C detected"); + pr_notice("KB3926C detected\n"); } else if (old_ver == 0x24 && hw_revision == 0xC0) { dev->hw_revision = ENE_HW_B; - ene_notice("KB3926B detected"); + pr_notice("KB3926B detected\n"); } else { dev->hw_revision = ENE_HW_D; - ene_notice("KB3926D or higher detected"); + pr_notice("KB3926D or higher detected\n"); } /* detect features hardware supports */ @@ -152,7 +154,7 @@ static int ene_hw_detect(struct ene_device *dev) fw_reg1 = ene_read_reg(dev, ENE_FW1); fw_reg2 = ene_read_reg(dev, ENE_FW2); - ene_notice("Firmware regs: %02x %02x", fw_reg1, fw_reg2); + pr_notice("Firmware regs: %02x %02x\n", fw_reg1, fw_reg2); dev->hw_use_gpio_0a = !!(fw_reg2 & ENE_FW2_GP0A); dev->hw_learning_and_tx_capable = !!(fw_reg2 & ENE_FW2_LEARNING); @@ -161,30 +163,29 @@ static int ene_hw_detect(struct ene_device *dev) if (dev->hw_learning_and_tx_capable) dev->hw_fan_input = !!(fw_reg2 & ENE_FW2_FAN_INPUT); - ene_notice("Hardware features:"); + pr_notice("Hardware features:\n"); if (dev->hw_learning_and_tx_capable) { - ene_notice("* Supports transmitting & learning mode"); - ene_notice(" This feature is rare and therefore,"); - ene_notice(" you are welcome to test it,"); - ene_notice(" and/or contact the author via:"); - ene_notice(" lirc-list@lists.sourceforge.net"); - ene_notice(" or maximlevitsky@gmail.com"); + pr_notice("* Supports transmitting & learning mode\n"); + pr_notice(" This feature is rare and therefore,\n"); + pr_notice(" you are welcome to test it,\n"); + pr_notice(" and/or contact the author via:\n"); + pr_notice(" lirc-list@lists.sourceforge.net\n"); + pr_notice(" or maximlevitsky@gmail.com\n"); - ene_notice("* Uses GPIO %s for IR raw input", - dev->hw_use_gpio_0a ? "40" : "0A"); + pr_notice("* Uses GPIO %s for IR raw input\n", + dev->hw_use_gpio_0a ? "40" : "0A"); if (dev->hw_fan_input) - ene_notice("* Uses unused fan feedback input as source" - " of demodulated IR data"); + pr_notice("* Uses unused fan feedback input as source of demodulated IR data\n"); } if (!dev->hw_fan_input) - ene_notice("* Uses GPIO %s for IR demodulated input", - dev->hw_use_gpio_0a ? "0A" : "40"); + pr_notice("* Uses GPIO %s for IR demodulated input\n", + dev->hw_use_gpio_0a ? "0A" : "40"); if (dev->hw_extra_buffer) - ene_notice("* Uses new style input buffer"); + pr_notice("* Uses new style input buffer\n"); return 0; } @@ -215,13 +216,13 @@ static void ene_rx_setup_hw_buffer(struct ene_device *dev) dev->buffer_len = dev->extra_buf1_len + dev->extra_buf2_len + 8; - ene_notice("Hardware uses 2 extended buffers:"); - ene_notice(" 0x%04x - len : %d", dev->extra_buf1_address, - dev->extra_buf1_len); - ene_notice(" 0x%04x - len : %d", dev->extra_buf2_address, - dev->extra_buf2_len); + pr_notice("Hardware uses 2 extended buffers:\n"); + pr_notice(" 0x%04x - len : %d\n", + dev->extra_buf1_address, dev->extra_buf1_len); + pr_notice(" 0x%04x - len : %d\n", + dev->extra_buf2_address, dev->extra_buf2_len); - ene_notice("Total buffer len = %d", dev->buffer_len); + pr_notice("Total buffer len = %d\n", dev->buffer_len); if (dev->buffer_len > 64 || dev->buffer_len < 16) goto error; @@ -240,7 +241,7 @@ static void ene_rx_setup_hw_buffer(struct ene_device *dev) ene_set_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND); return; error: - ene_warn("Error validating extra buffers, device probably won't work"); + pr_warn("Error validating extra buffers, device probably won't work\n"); dev->hw_extra_buffer = false; ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND); } @@ -588,7 +589,7 @@ static void ene_tx_enable(struct ene_device *dev) dbg("TX: Transmitter #2 is connected"); if (!(fwreg2 & (ENE_FW2_EMMITER1_CONN | ENE_FW2_EMMITER2_CONN))) - ene_warn("TX: transmitter cable isn't connected!"); + pr_warn("TX: transmitter cable isn't connected!\n"); /* disable receive on revc */ if (dev->hw_revision == ENE_HW_C) @@ -615,7 +616,7 @@ static void ene_tx_sample(struct ene_device *dev) bool pulse = dev->tx_sample_pulse; if (!dev->tx_buffer) { - ene_warn("TX: BUG: attempt to transmit NULL buffer"); + pr_warn("TX: BUG: attempt to transmit NULL buffer\n"); return; } @@ -1049,7 +1050,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) dev->hw_learning_and_tx_capable = true; setup_timer(&dev->tx_sim_timer, ene_tx_irqsim, (long unsigned int)dev); - ene_warn("Simulation of TX activated"); + pr_warn("Simulation of TX activated\n"); } if (!dev->hw_learning_and_tx_capable) @@ -1089,7 +1090,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) if (error < 0) goto error; - ene_notice("driver has been successfully loaded"); + pr_notice("driver has been successfully loaded\n"); return 0; error: if (dev && dev->irq >= 0) diff --git a/drivers/media/rc/ene_ir.h b/drivers/media/rc/ene_ir.h index 017c209..fd108d9 100644 --- a/drivers/media/rc/ene_ir.h +++ b/drivers/media/rc/ene_ir.h @@ -182,20 +182,11 @@ #define ENE_HW_C 2 /* 3926C */ #define ENE_HW_D 3 /* 3926D or later */ -#define ene_printk(level, text, ...) \ - printk(level ENE_DRIVER_NAME ": " text "\n", ## __VA_ARGS__) - -#define ene_notice(text, ...) ene_printk(KERN_NOTICE, text, ## __VA_ARGS__) -#define ene_warn(text, ...) ene_printk(KERN_WARNING, text, ## __VA_ARGS__) - - -#define __dbg(level, format, ...) \ - do { \ - if (debug >= level) \ - printk(KERN_DEBUG ENE_DRIVER_NAME \ - ": " format "\n", ## __VA_ARGS__); \ - } while (0) - +#define __dbg(level, format, ...) \ +do { \ + if (debug >= level) \ + pr_debug(format "\n", ## __VA_ARGS__); \ +} while (0) #define dbg(format, ...) __dbg(1, format, ## __VA_ARGS__) #define dbg_verbose(format, ...) __dbg(2, format, ## __VA_ARGS__) -- cgit v0.10.2 From d8a10ac948545d8a4261728719af39b5dffaf7da Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 21 Aug 2011 19:56:47 -0300 Subject: [media] winbond-cir: Use current logging styles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add pr_fmt, convert printks to pr_. Signed-off-by: Joe Perches Acked-by: David Härdeman Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index bec8abc..13f54b5 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c @@ -41,6 +41,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -1155,12 +1157,12 @@ wbcir_init(void) case IR_PROTOCOL_RC6: break; default: - printk(KERN_ERR DRVNAME ": Invalid power-on protocol\n"); + pr_err("Invalid power-on protocol\n"); } ret = pnp_register_driver(&wbcir_driver); if (ret) - printk(KERN_ERR DRVNAME ": Unable to register driver\n"); + pr_err("Unable to register driver\n"); return ret; } -- cgit v0.10.2 From 8af443e581ab57a6a38f595eb40be3514ea55195 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 21 Aug 2011 19:56:48 -0300 Subject: [media] bt8xx: Use current logging styles This converts some messages that were emitted at KERN_INFO to KERN_DEBUG. All of these messages were guarded by bttv_debug tests. Add pr_fmt. Convert printks to pr_ Convert printks without KERN_ to appropriate pr_. Removed embedded prefixes when pr_fmt was added. Whitespace cleanups when around other conversions. Macros coded with if statements should be do { if... } while (0) so the macros can be used in other if tests. Use ##__VA_ARGS__ for variadic macro as well. Coalesce format strings. Signed-off-by: Joe Perches Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 5b15f63..5939021 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -25,6 +25,8 @@ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -2905,19 +2907,17 @@ void __devinit bttv_idcard(struct bttv *btv) if (type != -1) { /* found it */ - printk(KERN_INFO "bttv%d: detected: %s [card=%d], " - "PCI subsystem ID is %04x:%04x\n", - btv->c.nr,cards[type].name,cards[type].cardnr, - btv->cardid & 0xffff, - (btv->cardid >> 16) & 0xffff); + pr_info("%d: detected: %s [card=%d], PCI subsystem ID is %04x:%04x\n", + btv->c.nr, cards[type].name, cards[type].cardnr, + btv->cardid & 0xffff, + (btv->cardid >> 16) & 0xffff); btv->c.type = cards[type].cardnr; } else { /* 404 */ - printk(KERN_INFO "bttv%d: subsystem: %04x:%04x (UNKNOWN)\n", - btv->c.nr, btv->cardid & 0xffff, - (btv->cardid >> 16) & 0xffff); - printk(KERN_DEBUG "please mail id, board name and " - "the correct card= insmod option to linux-media@vger.kernel.org\n"); + pr_info("%d: subsystem: %04x:%04x (UNKNOWN)\n", + btv->c.nr, btv->cardid & 0xffff, + (btv->cardid >> 16) & 0xffff); + pr_debug("please mail id, board name and the correct card= insmod option to linux-media@vger.kernel.org\n"); } } @@ -2926,10 +2926,10 @@ void __devinit bttv_idcard(struct bttv *btv) btv->c.type=card[btv->c.nr]; /* print which card config we are using */ - printk(KERN_INFO "bttv%d: using: %s [card=%d,%s]\n",btv->c.nr, - bttv_tvcards[btv->c.type].name, btv->c.type, - card[btv->c.nr] < bttv_num_tvcards - ? "insmod option" : "autodetected"); + pr_info("%d: using: %s [card=%d,%s]\n", + btv->c.nr, bttv_tvcards[btv->c.type].name, btv->c.type, + card[btv->c.nr] < bttv_num_tvcards + ? "insmod option" : "autodetected"); /* overwrite gpio stuff ?? */ if (UNSET == audioall && UNSET == audiomux[0]) @@ -2948,12 +2948,13 @@ void __devinit bttv_idcard(struct bttv *btv) } } bttv_tvcards[btv->c.type].gpiomask = (UNSET != gpiomask) ? gpiomask : gpiobits; - printk(KERN_INFO "bttv%d: gpio config override: mask=0x%x, mux=", - btv->c.nr,bttv_tvcards[btv->c.type].gpiomask); + pr_info("%d: gpio config override: mask=0x%x, mux=", + btv->c.nr, bttv_tvcards[btv->c.type].gpiomask); for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) { - printk("%s0x%x", i ? "," : "", bttv_tvcards[btv->c.type].gpiomux[i]); + pr_cont("%s0x%x", + i ? "," : "", bttv_tvcards[btv->c.type].gpiomux[i]); } - printk("\n"); + pr_cont("\n"); } /* @@ -2974,8 +2975,8 @@ static void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256]) if (-1 != type) { btv->c.type = type; - printk("bttv%d: detected by eeprom: %s [card=%d]\n", - btv->c.nr, bttv_tvcards[btv->c.type].name, btv->c.type); + pr_info("%d: detected by eeprom: %s [card=%d]\n", + btv->c.nr, bttv_tvcards[btv->c.type].name, btv->c.type); } } @@ -3019,7 +3020,7 @@ static void flyvideo_gpio(struct bttv *btv) tuner_type = 3; /* Philips SECAM(+PAL) FQ1216ME or FI1216MF */ break; default: - printk(KERN_INFO "bttv%d: FlyVideo_gpio: unknown tuner type.\n", btv->c.nr); + pr_info("%d: FlyVideo_gpio: unknown tuner type\n", btv->c.nr); break; } @@ -3036,13 +3037,13 @@ static void flyvideo_gpio(struct bttv *btv) if (is_capture_only) tuner_type = TUNER_ABSENT; /* No tuner present */ - printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n", - btv->c.nr, has_radio ? "yes" : "no ", - has_remote ? "yes" : "no ", tuner_type, gpio); - printk(KERN_INFO "bttv%d: FlyVideo LR90=%s tda9821/tda9820=%s capture_only=%s\n", - btv->c.nr, is_lr90 ? "yes" : "no ", - has_tda9820_tda9821 ? "yes" : "no ", - is_capture_only ? "yes" : "no "); + pr_info("%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n", + btv->c.nr, has_radio ? "yes" : "no", + has_remote ? "yes" : "no", tuner_type, gpio); + pr_info("%d: FlyVideo LR90=%s tda9821/tda9820=%s capture_only=%s\n", + btv->c.nr, is_lr90 ? "yes" : "no", + has_tda9820_tda9821 ? "yes" : "no", + is_capture_only ? "yes" : "no"); if (tuner_type != UNSET) /* only set if known tuner autodetected, else let insmod option through */ btv->tuner_type = tuner_type; @@ -3091,12 +3092,11 @@ static void miro_pinnacle_gpio(struct bttv *btv) if (btv->c.type == BTTV_BOARD_PINNACLE) btv->c.type = BTTV_BOARD_PINNACLEPRO; } - printk(KERN_INFO - "bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n", - btv->c.nr, id+1, btv->tuner_type, - !btv->has_radio ? "no" : - (btv->has_matchbox ? "matchbox" : "fmtuner"), - (-1 == msp) ? "no" : "yes"); + pr_info("%d: miro: id=%d tuner=%d radio=%s stereo=%s\n", + btv->c.nr, id+1, btv->tuner_type, + !btv->has_radio ? "no" : + (btv->has_matchbox ? "matchbox" : "fmtuner"), + (-1 == msp) ? "no" : "yes"); } else { /* new cards with microtune tuner */ id = 63 - id; @@ -3138,9 +3138,8 @@ static void miro_pinnacle_gpio(struct bttv *btv) } if (-1 != msp) btv->c.type = BTTV_BOARD_PINNACLEPRO; - printk(KERN_INFO - "bttv%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n", - btv->c.nr, id, info, btv->has_radio ? "yes" : "no"); + pr_info("%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n", + btv->c.nr, id, info, btv->has_radio ? "yes" : "no"); btv->tuner_type = TUNER_MT2032; } } @@ -3202,7 +3201,7 @@ static void gvc1100_muxsel(struct bttv *btv, unsigned int input) static void init_lmlbt4x(struct bttv *btv) { - printk(KERN_DEBUG "LMLBT4x init\n"); + pr_debug("LMLBT4x init\n"); btwrite(0x000000, BT848_GPIO_REG_INP); gpio_inout(0xffffff, 0x0006C0); gpio_write(0x000000); @@ -3246,7 +3245,7 @@ static void bttv_reset_audio(struct bttv *btv) return; if (bttv_debug) - printk("bttv%d: BT878A ARESET\n",btv->c.nr); + pr_debug("%d: BT878A ARESET\n", btv->c.nr); btwrite((1<<7), 0x058); udelay(10); btwrite( 0, 0x058); @@ -3349,7 +3348,8 @@ void __devinit bttv_init_card2(struct bttv *btv) case BTTV_BOARD_MAGICTVIEW061: if (btv->cardid == 0x3002144f) { btv->has_radio=1; - printk("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->c.nr); + pr_info("%d: radio detected by subsystem id (CPH05x)\n", + btv->c.nr); } break; case BTTV_BOARD_STB2: @@ -3438,17 +3438,16 @@ void __devinit bttv_init_card2(struct bttv *btv) btv->tuner_type = tuner[btv->c.nr]; if (btv->tuner_type == TUNER_ABSENT) - printk(KERN_INFO "bttv%d: tuner absent\n", btv->c.nr); - else if(btv->tuner_type == UNSET) - printk(KERN_WARNING "bttv%d: tuner type unset\n", btv->c.nr); + pr_info("%d: tuner absent\n", btv->c.nr); + else if (btv->tuner_type == UNSET) + pr_warn("%d: tuner type unset\n", btv->c.nr); else - printk(KERN_INFO "bttv%d: tuner type=%d\n", btv->c.nr, - btv->tuner_type); + pr_info("%d: tuner type=%d\n", btv->c.nr, btv->tuner_type); if (autoload != UNSET) { - printk(KERN_WARNING "bttv%d: the autoload option is obsolete.\n", btv->c.nr); - printk(KERN_WARNING "bttv%d: use option msp3400, tda7432 or tvaudio to\n", btv->c.nr); - printk(KERN_WARNING "bttv%d: override which audio module should be used.\n", btv->c.nr); + pr_warn("%d: the autoload option is obsolete\n", btv->c.nr); + pr_warn("%d: use option msp3400, tda7432 or tvaudio to override which audio module should be used\n", + btv->c.nr); } if (UNSET == btv->tuner_type) @@ -3541,8 +3540,7 @@ void __devinit bttv_init_card2(struct bttv *btv) } default: - printk(KERN_WARNING "bttv%d: unknown audiodev value!\n", - btv->c.nr); + pr_warn("%d: unknown audiodev value!\n", btv->c.nr); return; } @@ -3585,8 +3583,7 @@ void __devinit bttv_init_card2(struct bttv *btv) return; no_audio: - printk(KERN_WARNING "bttv%d: audio absent, no audio device found!\n", - btv->c.nr); + pr_warn("%d: audio absent, no audio device found!\n", btv->c.nr); } @@ -3639,19 +3636,19 @@ static void modtec_eeprom(struct bttv *btv) { if( strncmp(&(eeprom_data[0x1e]),"Temic 4066 FY5",14) ==0) { btv->tuner_type=TUNER_TEMIC_4066FY5_PAL_I; - printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n", - btv->c.nr,&eeprom_data[0x1e]); + pr_info("%d: Modtec: Tuner autodetected by eeprom: %s\n", + btv->c.nr, &eeprom_data[0x1e]); } else if (strncmp(&(eeprom_data[0x1e]),"Alps TSBB5",10) ==0) { btv->tuner_type=TUNER_ALPS_TSBB5_PAL_I; - printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n", - btv->c.nr,&eeprom_data[0x1e]); + pr_info("%d: Modtec: Tuner autodetected by eeprom: %s\n", + btv->c.nr, &eeprom_data[0x1e]); } else if (strncmp(&(eeprom_data[0x1e]),"Philips FM1246",14) ==0) { btv->tuner_type=TUNER_PHILIPS_NTSC; - printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n", - btv->c.nr,&eeprom_data[0x1e]); + pr_info("%d: Modtec: Tuner autodetected by eeprom: %s\n", + btv->c.nr, &eeprom_data[0x1e]); } else { - printk("bttv%d: Modtec: Unknown TunerString: %s\n", - btv->c.nr,&eeprom_data[0x1e]); + pr_info("%d: Modtec: Unknown TunerString: %s\n", + btv->c.nr, &eeprom_data[0x1e]); } } @@ -3663,7 +3660,7 @@ static void __devinit hauppauge_eeprom(struct bttv *btv) btv->tuner_type = tv.tuner_type; btv->has_radio = tv.has_radio; - printk("bttv%d: Hauppauge eeprom indicates model#%d\n", + pr_info("%d: Hauppauge eeprom indicates model#%d\n", btv->c.nr, tv.model); /* @@ -3671,7 +3668,7 @@ static void __devinit hauppauge_eeprom(struct bttv *btv) * type based on model #. */ if(tv.model == 64900) { - printk("bttv%d: Switching board type from %s to %s\n", + pr_info("%d: Switching board type from %s to %s\n", btv->c.nr, bttv_tvcards[btv->c.type].name, bttv_tvcards[BTTV_BOARD_HAUPPAUGE_IMPACTVCB].name); @@ -3698,8 +3695,7 @@ static int terratec_active_radio_upgrade(struct bttv *btv) freq=88000/62.5; tea5757_write(btv, 5 * freq + 0x358); /* write 0x1ed8 */ if (0x1ed8 == tea5757_read(btv)) { - printk("bttv%d: Terratec Active Radio Upgrade found.\n", - btv->c.nr); + pr_info("%d: Terratec Active Radio Upgrade found\n", btv->c.nr); btv->has_radio = 1; btv->has_saa6588 = 1; btv->has_matchbox = 1; @@ -3771,13 +3767,12 @@ static int __devinit pvr_boot(struct bttv *btv) rc = request_firmware(&fw_entry, "hcwamc.rbf", &btv->c.pci->dev); if (rc != 0) { - printk(KERN_WARNING "bttv%d: no altera firmware [via hotplug]\n", - btv->c.nr); + pr_warn("%d: no altera firmware [via hotplug]\n", btv->c.nr); return rc; } rc = pvr_altera_load(btv, fw_entry->data, fw_entry->size); - printk(KERN_INFO "bttv%d: altera firmware upload %s\n", - btv->c.nr, (rc < 0) ? "failed" : "ok"); + pr_info("%d: altera firmware upload %s\n", + btv->c.nr, (rc < 0) ? "failed" : "ok"); release_firmware(fw_entry); return rc; } @@ -3873,29 +3868,27 @@ static void __devinit osprey_eeprom(struct bttv *btv, const u8 ee[256]) break; default: /* unknown...leave generic, but get serial # */ - printk(KERN_INFO "bttv%d: " - "osprey eeprom: unknown card type 0x%04x\n", - btv->c.nr, type); + pr_info("%d: osprey eeprom: unknown card type 0x%04x\n", + btv->c.nr, type); break; } serial = get_unaligned_be32((__be32 *)(ee+6)); } - printk(KERN_INFO "bttv%d: osprey eeprom: card=%d '%s' serial=%u\n", - btv->c.nr, cardid, - cardid>0 ? bttv_tvcards[cardid].name : "Unknown", serial); + pr_info("%d: osprey eeprom: card=%d '%s' serial=%u\n", + btv->c.nr, cardid, + cardid > 0 ? bttv_tvcards[cardid].name : "Unknown", serial); if (cardid<0 || btv->c.type == cardid) return; /* card type isn't set correctly */ if (card[btv->c.nr] < bttv_num_tvcards) { - printk(KERN_WARNING "bttv%d: osprey eeprom: " - "Not overriding user specified card type\n", btv->c.nr); + pr_warn("%d: osprey eeprom: Not overriding user specified card type\n", + btv->c.nr); } else { - printk(KERN_INFO "bttv%d: osprey eeprom: " - "Changing card type from %d to %d\n", btv->c.nr, - btv->c.type, cardid); + pr_info("%d: osprey eeprom: Changing card type from %d to %d\n", + btv->c.nr, btv->c.type, cardid); btv->c.type = cardid; } } @@ -3938,14 +3931,14 @@ static void __devinit avermedia_eeprom(struct bttv *btv) if (tuner_format == 0x09) tuner_type = TUNER_LG_NTSC_NEW_TAPC; /* TAPC-G702P */ - printk(KERN_INFO "bttv%d: Avermedia eeprom[0x%02x%02x]: tuner=", + pr_info("%d: Avermedia eeprom[0x%02x%02x]: tuner=", btv->c.nr, eeprom_data[0x41], eeprom_data[0x42]); if (tuner_type) { btv->tuner_type = tuner_type; - printk(KERN_CONT "%d", tuner_type); + pr_cont("%d", tuner_type); } else - printk(KERN_CONT "Unknown type"); - printk(KERN_CONT " radio:%s remote control:%s\n", + pr_cont("Unknown type"); + pr_cont(" radio:%s remote control:%s\n", tuner_tv_fm ? "yes" : "no", btv->has_remote ? "yes" : "no"); } @@ -3993,8 +3986,8 @@ static void __devinit boot_msp34xx(struct bttv *btv, int pin) if (bttv_gpio) bttv_gpio_tracking(btv,"msp34xx"); if (bttv_verbose) - printk(KERN_INFO "bttv%d: Hauppauge/Voodoo msp34xx: reset line " - "init [%d]\n", btv->c.nr, pin); + pr_info("%d: Hauppauge/Voodoo msp34xx: reset line init [%d]\n", + btv->c.nr, pin); } /* ----------------------------------------------------------------------- */ @@ -4034,7 +4027,7 @@ static void __devinit init_PXC200(struct bttv *btv) btwrite(BT848_ADC_RESERVED|BT848_ADC_AGC_EN, BT848_ADC); /* Initialise MAX517 DAC */ - printk(KERN_INFO "Setting DAC reference voltage level ...\n"); + pr_info("Setting DAC reference voltage level ...\n"); bttv_I2CWrite(btv,0x5E,0,0x80,1); /* Initialise 12C508 PIC */ @@ -4043,7 +4036,7 @@ static void __devinit init_PXC200(struct bttv *btv) * argument so the numbers are different */ - printk(KERN_INFO "Initialising 12C508 PIC chip ...\n"); + pr_info("Initialising 12C508 PIC chip ...\n"); /* First of all, enable the clock line. This is used in the PXC200-F */ val = btread(BT848_GPIO_DMA_CTL); @@ -4062,13 +4055,12 @@ static void __devinit init_PXC200(struct bttv *btv) for (i = 0; i < ARRAY_SIZE(vals); i++) { tmp=bttv_I2CWrite(btv,0x1E,0,vals[i],1); if (tmp != -1) { - printk(KERN_INFO - "I2C Write(%2.2x) = %i\nI2C Read () = %2.2x\n\n", + pr_info("I2C Write(%2.2x) = %i\nI2C Read () = %2.2x\n\n", vals[i],tmp,bttv_I2CRead(btv,0x1F,NULL)); } } - printk(KERN_INFO "PXC200 Initialised.\n"); + pr_info("PXC200 Initialised\n"); } @@ -4107,8 +4099,7 @@ init_RTV24 (struct bttv *btv) uint32_t dataRead = 0; long watchdog_value = 0x0E; - printk (KERN_INFO - "bttv%d: Adlink RTV-24 initialisation in progress ...\n", + pr_info("%d: Adlink RTV-24 initialisation in progress ...\n", btv->c.nr); btwrite (0x00c3feff, BT848_GPIO_OUT_EN); @@ -4122,8 +4113,7 @@ init_RTV24 (struct bttv *btv) dataRead = btread (BT848_GPIO_DATA); if ((((dataRead >> 18) & 0x01) != 0) || (((dataRead >> 19) & 0x01) != 1)) { - printk (KERN_INFO - "bttv%d: Adlink RTV-24 initialisation(1) ERROR_CPLD_Check_Failed (read %d)\n", + pr_info("%d: Adlink RTV-24 initialisation(1) ERROR_CPLD_Check_Failed (read %d)\n", btv->c.nr, dataRead); } @@ -4136,15 +4126,13 @@ init_RTV24 (struct bttv *btv) dataRead = btread (BT848_GPIO_DATA); if ((((dataRead >> 18) & 0x01) != 0) || (((dataRead >> 19) & 0x01) != 0)) { - printk (KERN_INFO - "bttv%d: Adlink RTV-24 initialisation(2) ERROR_CPLD_Check_Failed (read %d)\n", + pr_info("%d: Adlink RTV-24 initialisation(2) ERROR_CPLD_Check_Failed (read %d)\n", btv->c.nr, dataRead); return; } - printk (KERN_INFO - "bttv%d: Adlink RTV-24 initialisation complete.\n", btv->c.nr); + pr_info("%d: Adlink RTV-24 initialisation complete\n", btv->c.nr); } @@ -4261,22 +4249,25 @@ static int tea5757_read(struct bttv *btv) while (bus_in(btv,btv->mbox_data) && time_before(jiffies, timeout)) schedule(); if (bus_in(btv,btv->mbox_data)) { - printk(KERN_WARNING "bttv%d: tea5757: read timeout\n",btv->c.nr); + pr_warn("%d: tea5757: read timeout\n", btv->c.nr); return -1; } - dprintk("bttv%d: tea5757:",btv->c.nr); + dprintk("%d: tea5757:", btv->c.nr); for (i = 0; i < 24; i++) { udelay(5); bus_high(btv,btv->mbox_clk); udelay(5); - dprintk("%c",(bus_in(btv,btv->mbox_most) == 0)?'T':'-'); + dprintk_cont("%c", + bus_in(btv, btv->mbox_most) == 0 ? 'T' : '-'); bus_low(btv,btv->mbox_clk); value <<= 1; value |= (bus_in(btv,btv->mbox_data) == 0)?0:1; /* MSB first */ - dprintk("%c", (bus_in(btv,btv->mbox_most) == 0)?'S':'M'); + dprintk_cont("%c", + bus_in(btv, btv->mbox_most) == 0 ? 'S' : 'M'); } - dprintk("\nbttv%d: tea5757: read 0x%X\n", btv->c.nr, value); + dprintk_cont("\n"); + dprintk("%d: tea5757: read 0x%X\n", btv->c.nr, value); return value; } @@ -4295,7 +4286,7 @@ static int tea5757_write(struct bttv *btv, int value) if (bttv_gpio) bttv_gpio_tracking(btv,"tea5757 write"); - dprintk("bttv%d: tea5757: write 0x%X\n", btv->c.nr, value); + dprintk("%d: tea5757: write 0x%X\n", btv->c.nr, value); bus_low(btv,btv->mbox_clk); bus_high(btv,btv->mbox_we); for (i = 0; i < 25; i++) { @@ -4547,7 +4538,7 @@ static void picolo_tetra_init(struct bttv *btv) static void picolo_tetra_muxsel (struct bttv* btv, unsigned int input) { - dprintk (KERN_DEBUG "bttv%d : picolo_tetra_muxsel => input = %d\n",btv->c.nr,input); + dprintk("%d : picolo_tetra_muxsel => input = %d\n", btv->c.nr, input); /*Just set the right path in the analog multiplexers : channel 1 -> 4 ==> Analog Mux ==> MUX0*/ /*GPIO[20]&GPIO[21] used to choose the right input*/ btwrite (input<<20,BT848_GPIO_DATA); @@ -4592,7 +4583,7 @@ static void ivc120_muxsel(struct bttv *btv, unsigned int input) int key = input % 4; int matrix = input / 4; - dprintk("bttv%d: ivc120_muxsel: Input - %02d | TDA - %02d | In - %02d\n", + dprintk("%d: ivc120_muxsel: Input - %02d | TDA - %02d | In - %02d\n", btv->c.nr, input, matrix, key); /* Handles the input selection on the TDA8540's */ @@ -4649,15 +4640,17 @@ static void PXC200_muxsel(struct bttv *btv, unsigned int input) buf[1]=0; rc=bttv_I2CWrite(btv,(PX_I2C_PIC<<1),buf[0],buf[1],1); if (rc) { - printk(KERN_DEBUG "bttv%d: PXC200_muxsel: pic cfg write failed:%d\n", btv->c.nr,rc); + pr_debug("%d: PXC200_muxsel: pic cfg write failed:%d\n", + btv->c.nr, rc); /* not PXC ? do nothing */ - return; + return; } rc=bttv_I2CRead(btv,(PX_I2C_PIC<<1),NULL); if (!(rc & PX_CFG_PXC200F)) { - printk(KERN_DEBUG "bttv%d: PXC200_muxsel: not PXC200F rc:%d \n", btv->c.nr,rc); - return; + pr_debug("%d: PXC200_muxsel: not PXC200F rc:%d\n", + btv->c.nr, rc); + return; } @@ -4696,7 +4689,7 @@ static void PXC200_muxsel(struct bttv *btv, unsigned int input) else /* older device */ btand(~BT848_IFORM_MUXSEL,BT848_IFORM); - printk(KERN_DEBUG "bttv%d: setting input channel to:%d\n", btv->c.nr,(int)mux); + pr_debug("%d: setting input channel to:%d\n", btv->c.nr, (int)mux); } static void phytec_muxsel(struct bttv *btv, unsigned int input) @@ -4847,29 +4840,27 @@ void __init bttv_check_chipset(void) /* print warnings about any quirks found */ if (triton1) - printk(KERN_INFO "bttv: Host bridge needs ETBF enabled.\n"); + pr_info("Host bridge needs ETBF enabled\n"); if (vsfx) - printk(KERN_INFO "bttv: Host bridge needs VSFX enabled.\n"); + pr_info("Host bridge needs VSFX enabled\n"); if (pcipci_fail) { - printk(KERN_INFO "bttv: bttv and your chipset may not work " - "together.\n"); + pr_info("bttv and your chipset may not work together\n"); if (!no_overlay) { - printk(KERN_INFO "bttv: overlay will be disabled.\n"); + pr_info("overlay will be disabled\n"); no_overlay = 1; } else { - printk(KERN_INFO "bttv: overlay forced. Use this " - "option at your own risk.\n"); + pr_info("overlay forced. Use this option at your own risk.\n"); } } if (UNSET != latency) - printk(KERN_INFO "bttv: pci latency fixup [%d]\n",latency); + pr_info("pci latency fixup [%d]\n", latency); while ((dev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, dev))) { unsigned char b; pci_read_config_byte(dev, 0x53, &b); if (bttv_debug) - printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, " - "bufcon=0x%02x\n",b); + pr_info("Host bridge: 82441FX Natoma, bufcon=0x%02x\n", + b); } } @@ -4882,12 +4873,13 @@ int __devinit bttv_handle_chipset(struct bttv *btv) if (bttv_verbose) { if (triton1) - printk(KERN_INFO "bttv%d: enabling ETBF (430FX/VP3 compatibilty)\n",btv->c.nr); + pr_info("%d: enabling ETBF (430FX/VP3 compatibility)\n", + btv->c.nr); if (vsfx && btv->id >= 878) - printk(KERN_INFO "bttv%d: enabling VSFX\n",btv->c.nr); + pr_info("%d: enabling VSFX\n", btv->c.nr); if (UNSET != latency) - printk(KERN_INFO "bttv%d: setting pci timer to %d\n", - btv->c.nr,latency); + pr_info("%d: setting pci timer to %d\n", + btv->c.nr, latency); } if (btv->id < 878) { diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 14444de..3dd0660 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -34,6 +34,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -942,8 +944,8 @@ static void free_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bits) { if ((fh->resources & bits) != bits) { - /* trying to free ressources not allocated by us ... */ - printk("bttv: BUG! (btres)\n"); + /* trying to free resources not allocated by us ... */ + pr_err("BUG! (btres)\n"); } fh->resources &= ~bits; btv->resources &= ~bits; @@ -1000,7 +1002,7 @@ static void set_pll(struct bttv *btv) return; if (btv->pll.pll_ofreq == btv->pll.pll_current) { - dprintk("bttv%d: PLL: no change required\n",btv->c.nr); + dprintk("%d: PLL: no change required\n", btv->c.nr); return; } @@ -1008,21 +1010,23 @@ static void set_pll(struct bttv *btv) /* no PLL needed */ if (btv->pll.pll_current == 0) return; - bttv_printk(KERN_INFO "bttv%d: PLL can sleep, using XTAL (%d).\n", - btv->c.nr,btv->pll.pll_ifreq); + if (bttv_verbose) + pr_info("%d: PLL can sleep, using XTAL (%d)\n", + btv->c.nr, btv->pll.pll_ifreq); btwrite(0x00,BT848_TGCTRL); btwrite(0x00,BT848_PLL_XCI); btv->pll.pll_current = 0; return; } - bttv_printk(KERN_INFO "bttv%d: PLL: %d => %d ",btv->c.nr, - btv->pll.pll_ifreq, btv->pll.pll_ofreq); + if (bttv_verbose) + pr_info("%d: Setting PLL: %d => %d (needs up to 100ms)\n", + btv->c.nr, + btv->pll.pll_ifreq, btv->pll.pll_ofreq); set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq); for (i=0; i<10; i++) { /* Let other people run while the PLL stabilizes */ - bttv_printk("."); msleep(10); if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) { @@ -1030,12 +1034,14 @@ static void set_pll(struct bttv *btv) } else { btwrite(0x08,BT848_TGCTRL); btv->pll.pll_current = btv->pll.pll_ofreq; - bttv_printk(" ok\n"); + if (bttv_verbose) + pr_info("PLL set ok\n"); return; } } btv->pll.pll_current = -1; - bttv_printk("failed\n"); + if (bttv_verbose) + pr_info("Setting PLL failed\n"); return; } @@ -1047,7 +1053,7 @@ static void bt848A_set_timing(struct bttv *btv) int fsc = bttv_tvnorms[btv->tvnorm].Fsc; if (btv->input == btv->dig) { - dprintk("bttv%d: load digital timing table (table_idx=%d)\n", + dprintk("%d: load digital timing table (table_idx=%d)\n", btv->c.nr,table_idx); /* timing change...reset timing generator address */ @@ -1076,7 +1082,7 @@ static void bt848_bright(struct bttv *btv, int bright) { int value; - // printk("bttv: set bright: %d\n",bright); // DEBUG + // printk("set bright: %d\n", bright); // DEBUG btv->bright = bright; /* We want -128 to 127 we get 0-65535 */ @@ -1150,8 +1156,7 @@ video_mux(struct bttv *btv, unsigned int input) } mux = bttv_muxsel(btv, input); btaor(mux<<5, ~(3<<5), BT848_IFORM); - dprintk(KERN_DEBUG "bttv%d: video mux: input=%d mux=%d\n", - btv->c.nr,input,mux); + dprintk("%d: video mux: input=%d mux=%d\n", btv->c.nr, input, mux); /* card specific hook */ if(bttv_tvcards[btv->c.type].muxsel_hook) @@ -1440,7 +1445,7 @@ static void bttv_reinit_bt848(struct bttv *btv) unsigned long flags; if (bttv_verbose) - printk(KERN_INFO "bttv%d: reset, reinitialize\n",btv->c.nr); + pr_info("%d: reset, reinitialize\n", btv->c.nr); spin_lock_irqsave(&btv->s_lock,flags); btv->errors=0; bttv_set_dma(btv,0); @@ -1622,8 +1627,8 @@ void bttv_gpio_tracking(struct bttv *btv, char *comment) unsigned int outbits, data; outbits = btread(BT848_GPIO_OUT_EN); data = btread(BT848_GPIO_DATA); - printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n", - btv->c.nr,outbits,data & outbits, data & ~outbits, comment); + pr_debug("%d: gpio: en=%08x, out=%08x in=%08x [%s]\n", + btv->c.nr, outbits, data & outbits, data & ~outbits, comment); } static void bttv_field_count(struct bttv *btv) @@ -1668,7 +1673,7 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh, unsigned long flags; int retval = 0; - dprintk("switch_overlay: enter [new=%p]\n",new); + dprintk("switch_overlay: enter [new=%p]\n", new); if (new) new->vb.state = VIDEOBUF_DONE; spin_lock_irqsave(&btv->s_lock,flags); @@ -1678,7 +1683,8 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh, bttv_set_dma(btv, 0x03); spin_unlock_irqrestore(&btv->s_lock,flags); if (NULL != old) { - dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state); + dprintk("switch_overlay: old=%p state is %d\n", + old, old->vb.state); bttv_dma_free(&fh->cap,btv, old); kfree(old); } @@ -2029,11 +2035,11 @@ static int bttv_log_status(struct file *file, void *f) struct bttv_fh *fh = f; struct bttv *btv = fh->btv; - printk(KERN_INFO "bttv%d: ======== START STATUS CARD #%d ========\n", - btv->c.nr, btv->c.nr); + pr_info("%d: ======== START STATUS CARD #%d ========\n", + btv->c.nr, btv->c.nr); bttv_call_all(btv, core, log_status); - printk(KERN_INFO "bttv%d: ======== END STATUS CARD #%d ========\n", - btv->c.nr, btv->c.nr); + pr_info("%d: ======== END STATUS CARD #%d ========\n", + btv->c.nr, btv->c.nr); return 0; } @@ -2598,7 +2604,7 @@ static int bttv_s_fmt_vid_overlay(struct file *file, void *priv, struct bttv *btv = fh->btv; if (no_overlay > 0) { - printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + pr_err("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); return -EINVAL; } @@ -2673,7 +2679,7 @@ static int bttv_enum_fmt_vid_overlay(struct file *file, void *priv, int rc; if (no_overlay > 0) { - printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + pr_err("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); return -EINVAL; } @@ -2714,7 +2720,7 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on) return -EINVAL; } if (unlikely(!fh->ov.setup_ok)) { - dprintk("bttv%d: overlay: !setup_ok\n", btv->c.nr); + dprintk("%d: overlay: !setup_ok\n", btv->c.nr); retval = -EINVAL; } if (retval) @@ -3091,8 +3097,8 @@ static ssize_t bttv_read(struct file *file, char __user *data, if (fh->btv->errors) bttv_reinit_bt848(fh->btv); - dprintk("bttv%d: read count=%d type=%s\n", - fh->btv->c.nr,(int)count,v4l2_type_names[fh->type]); + dprintk("%d: read count=%d type=%s\n", + fh->btv->c.nr, (int)count, v4l2_type_names[fh->type]); switch (fh->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: @@ -3174,7 +3180,7 @@ static int bttv_open(struct file *file) struct bttv_fh *fh; enum v4l2_buf_type type = 0; - dprintk(KERN_DEBUG "bttv: open dev=%s\n", video_device_node_name(vdev)); + dprintk("open dev=%s\n", video_device_node_name(vdev)); if (vdev->vfl_type == VFL_TYPE_GRABBER) { type = V4L2_BUF_TYPE_VIDEO_CAPTURE; @@ -3185,8 +3191,8 @@ static int bttv_open(struct file *file) return -ENODEV; } - dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n", - btv->c.nr,v4l2_type_names[type]); + dprintk("%d: open called (type=%s)\n", + btv->c.nr, v4l2_type_names[type]); /* allocate per filehandle data */ fh = kmalloc(sizeof(*fh), GFP_KERNEL); @@ -3288,7 +3294,7 @@ bttv_mmap(struct file *file, struct vm_area_struct *vma) { struct bttv_fh *fh = file->private_data; - dprintk("bttv%d: mmap type=%s 0x%lx+%ld\n", + dprintk("%d: mmap type=%s 0x%lx+%ld\n", fh->btv->c.nr, v4l2_type_names[fh->type], vma->vm_start, vma->vm_end - vma->vm_start); return videobuf_mmap_mapper(bttv_queue(fh),vma); @@ -3370,9 +3376,9 @@ static int radio_open(struct file *file) struct bttv *btv = video_drvdata(file); struct bttv_fh *fh; - dprintk("bttv: open dev=%s\n", video_device_node_name(vdev)); + dprintk("open dev=%s\n", video_device_node_name(vdev)); - dprintk("bttv%d: open called (radio)\n",btv->c.nr); + dprintk("%d: open called (radio)\n", btv->c.nr); /* allocate per filehandle data */ fh = kmalloc(sizeof(*fh), GFP_KERNEL); @@ -3616,12 +3622,12 @@ static int bttv_risc_decode(u32 risc) }; int i; - printk("0x%08x [ %s", risc, + pr_cont("0x%08x [ %s", risc, instr[risc >> 28] ? instr[risc >> 28] : "INVALID"); for (i = ARRAY_SIZE(bits)-1; i >= 0; i--) if (risc & (1 << (i + 12))) - printk(" %s",bits[i]); - printk(" count=%d ]\n", risc & 0xfff); + pr_cont(" %s", bits[i]); + pr_cont(" count=%d ]\n", risc & 0xfff); return incr[risc >> 28] ? incr[risc >> 28] : 1; } @@ -3630,16 +3636,18 @@ static void bttv_risc_disasm(struct bttv *btv, { unsigned int i,j,n; - printk("%s: risc disasm: %p [dma=0x%08lx]\n", - btv->c.v4l2_dev.name, risc->cpu, (unsigned long)risc->dma); + pr_info("%s: risc disasm: %p [dma=0x%08lx]\n", + btv->c.v4l2_dev.name, risc->cpu, (unsigned long)risc->dma); for (i = 0; i < (risc->size >> 2); i += n) { - printk("%s: 0x%lx: ", btv->c.v4l2_dev.name, - (unsigned long)(risc->dma + (i<<2))); + pr_info("%s: 0x%lx: ", + btv->c.v4l2_dev.name, + (unsigned long)(risc->dma + (i<<2))); n = bttv_risc_decode(le32_to_cpu(risc->cpu[i])); for (j = 1; j < n; j++) - printk("%s: 0x%lx: 0x%08x [ arg #%d ]\n", - btv->c.v4l2_dev.name, (unsigned long)(risc->dma + ((i+j)<<2)), - risc->cpu[i+j], j); + pr_info("%s: 0x%lx: 0x%08x [ arg #%d ]\n", + btv->c.v4l2_dev.name, + (unsigned long)(risc->dma + ((i+j)<<2)), + risc->cpu[i+j], j); if (0 == risc->cpu[i]) break; } @@ -3647,17 +3655,18 @@ static void bttv_risc_disasm(struct bttv *btv, static void bttv_print_riscaddr(struct bttv *btv) { - printk(" main: %08Lx\n", - (unsigned long long)btv->main.dma); - printk(" vbi : o=%08Lx e=%08Lx\n", - btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0, - btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0); - printk(" cap : o=%08Lx e=%08Lx\n", - btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0, - btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0); - printk(" scr : o=%08Lx e=%08Lx\n", - btv->screen ? (unsigned long long)btv->screen->top.dma : 0, - btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0); + pr_info(" main: %08llx\n", (unsigned long long)btv->main.dma); + pr_info(" vbi : o=%08llx e=%08llx\n", + btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0, + btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0); + pr_info(" cap : o=%08llx e=%08llx\n", + btv->curr.top + ? (unsigned long long)btv->curr.top->top.dma : 0, + btv->curr.bottom + ? (unsigned long long)btv->curr.bottom->bottom.dma : 0); + pr_info(" scr : o=%08llx e=%08llx\n", + btv->screen ? (unsigned long long)btv->screen->top.dma : 0, + btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0); bttv_risc_disasm(btv, &btv->main); } @@ -3690,34 +3699,34 @@ static void bttv_print_irqbits(u32 print, u32 mark) { unsigned int i; - printk("bits:"); + pr_cont("bits:"); for (i = 0; i < ARRAY_SIZE(irq_name); i++) { if (print & (1 << i)) - printk(" %s",irq_name[i]); + pr_cont(" %s", irq_name[i]); if (mark & (1 << i)) - printk("*"); + pr_cont("*"); } } static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc) { - printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n", - btv->c.nr, - (unsigned long)btv->main.dma, - (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_VBI+1]), - (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_FIELD+1]), - (unsigned long)rc); + pr_warn("%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n", + btv->c.nr, + (unsigned long)btv->main.dma, + (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_VBI+1]), + (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_FIELD+1]), + (unsigned long)rc); if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) { - printk("bttv%d: Oh, there (temporarely?) is no input signal. " - "Ok, then this is harmless, don't worry ;)\n", - btv->c.nr); + pr_notice("%d: Oh, there (temporarily?) is no input signal. " + "Ok, then this is harmless, don't worry ;)\n", + btv->c.nr); return; } - printk("bttv%d: Uhm. Looks like we have unusual high IRQ latencies.\n", - btv->c.nr); - printk("bttv%d: Lets try to catch the culpit red-handed ...\n", - btv->c.nr); + pr_notice("%d: Uhm. Looks like we have unusual high IRQ latencies\n", + btv->c.nr); + pr_notice("%d: Lets try to catch the culpit red-handed ...\n", + btv->c.nr); dump_stack(); } @@ -3798,9 +3807,9 @@ bttv_irq_next_video(struct bttv *btv, struct bttv_buffer_set *set) } } - dprintk("bttv%d: next set: top=%p bottom=%p [screen=%p,irq=%d,%d]\n", - btv->c.nr,set->top, set->bottom, - btv->screen,set->frame_irq,set->top_irq); + dprintk("%d: next set: top=%p bottom=%p [screen=%p,irq=%d,%d]\n", + btv->c.nr, set->top, set->bottom, + btv->screen, set->frame_irq, set->top_irq); return 0; } @@ -3815,7 +3824,8 @@ bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup, if (wakeup->top == wakeup->bottom) { if (NULL != wakeup->top && curr->top != wakeup->top) { if (irq_debug > 1) - printk("bttv%d: wakeup: both=%p\n",btv->c.nr,wakeup->top); + pr_debug("%d: wakeup: both=%p\n", + btv->c.nr, wakeup->top); wakeup->top->vb.ts = ts; wakeup->top->vb.field_count = btv->field_count; wakeup->top->vb.state = state; @@ -3824,7 +3834,8 @@ bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup, } else { if (NULL != wakeup->top && curr->top != wakeup->top) { if (irq_debug > 1) - printk("bttv%d: wakeup: top=%p\n",btv->c.nr,wakeup->top); + pr_debug("%d: wakeup: top=%p\n", + btv->c.nr, wakeup->top); wakeup->top->vb.ts = ts; wakeup->top->vb.field_count = btv->field_count; wakeup->top->vb.state = state; @@ -3832,7 +3843,8 @@ bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup, } if (NULL != wakeup->bottom && curr->bottom != wakeup->bottom) { if (irq_debug > 1) - printk("bttv%d: wakeup: bottom=%p\n",btv->c.nr,wakeup->bottom); + pr_debug("%d: wakeup: bottom=%p\n", + btv->c.nr, wakeup->bottom); wakeup->bottom->vb.ts = ts; wakeup->bottom->vb.field_count = btv->field_count; wakeup->bottom->vb.state = state; @@ -3866,11 +3878,11 @@ static void bttv_irq_timeout(unsigned long data) unsigned long flags; if (bttv_verbose) { - printk(KERN_INFO "bttv%d: timeout: drop=%d irq=%d/%d, risc=%08x, ", - btv->c.nr, btv->framedrop, btv->irq_me, btv->irq_total, - btread(BT848_RISC_COUNT)); + pr_info("%d: timeout: drop=%d irq=%d/%d, risc=%08x, ", + btv->c.nr, btv->framedrop, btv->irq_me, btv->irq_total, + btread(BT848_RISC_COUNT)); bttv_print_irqbits(btread(BT848_INT_STAT),0); - printk("\n"); + pr_cont("\n"); } spin_lock_irqsave(&btv->s_lock,flags); @@ -4033,21 +4045,23 @@ static irqreturn_t bttv_irq(int irq, void *dev_id) dstat=btread(BT848_DSTATUS); if (irq_debug) { - printk(KERN_DEBUG "bttv%d: irq loop=%d fc=%d " - "riscs=%x, riscc=%08x, ", - btv->c.nr, count, btv->field_count, - stat>>28, btread(BT848_RISC_COUNT)); + pr_debug("%d: irq loop=%d fc=%d riscs=%x, riscc=%08x, ", + btv->c.nr, count, btv->field_count, + stat>>28, btread(BT848_RISC_COUNT)); bttv_print_irqbits(stat,astat); if (stat & BT848_INT_HLOCK) - printk(" HLOC => %s", (dstat & BT848_DSTATUS_HLOC) - ? "yes" : "no"); + pr_cont(" HLOC => %s", + dstat & BT848_DSTATUS_HLOC + ? "yes" : "no"); if (stat & BT848_INT_VPRES) - printk(" PRES => %s", (dstat & BT848_DSTATUS_PRES) - ? "yes" : "no"); + pr_cont(" PRES => %s", + dstat & BT848_DSTATUS_PRES + ? "yes" : "no"); if (stat & BT848_INT_FMTCHG) - printk(" NUML => %s", (dstat & BT848_DSTATUS_NUML) - ? "625" : "525"); - printk("\n"); + pr_cont(" NUML => %s", + dstat & BT848_DSTATUS_NUML + ? "625" : "525"); + pr_cont("\n"); } if (astat&BT848_INT_VSYNC) @@ -4075,18 +4089,19 @@ static irqreturn_t bttv_irq(int irq, void *dev_id) audio_mute(btv, btv->mute); /* trigger automute */ if (astat & (BT848_INT_SCERR|BT848_INT_OCERR)) { - printk(KERN_INFO "bttv%d: %s%s @ %08x,",btv->c.nr, - (astat & BT848_INT_SCERR) ? "SCERR" : "", - (astat & BT848_INT_OCERR) ? "OCERR" : "", - btread(BT848_RISC_COUNT)); + pr_info("%d: %s%s @ %08x,", + btv->c.nr, + (astat & BT848_INT_SCERR) ? "SCERR" : "", + (astat & BT848_INT_OCERR) ? "OCERR" : "", + btread(BT848_RISC_COUNT)); bttv_print_irqbits(stat,astat); - printk("\n"); + pr_cont("\n"); if (bttv_debug) bttv_print_riscaddr(btv); } if (fdsr && astat & BT848_INT_FDSR) { - printk(KERN_INFO "bttv%d: FDSR @ %08x\n", - btv->c.nr,btread(BT848_RISC_COUNT)); + pr_info("%d: FDSR @ %08x\n", + btv->c.nr, btread(BT848_RISC_COUNT)); if (bttv_debug) bttv_print_riscaddr(btv); } @@ -4097,11 +4112,11 @@ static irqreturn_t bttv_irq(int irq, void *dev_id) if (count > 8 || !(astat & BT848_INT_GPINT)) { btwrite(0, BT848_INT_MASK); - printk(KERN_ERR - "bttv%d: IRQ lockup, cleared int mask [", btv->c.nr); + pr_err("%d: IRQ lockup, cleared int mask [", + btv->c.nr); } else { - printk(KERN_ERR - "bttv%d: IRQ lockup, clearing GPINT from int mask [", btv->c.nr); + pr_err("%d: IRQ lockup, clearing GPINT from int mask [", + btv->c.nr); btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT), BT848_INT_MASK); @@ -4109,7 +4124,7 @@ static irqreturn_t bttv_irq(int irq, void *dev_id) bttv_print_irqbits(stat,astat); - printk("]\n"); + pr_cont("]\n"); } } btv->irq_total++; @@ -4171,7 +4186,7 @@ static void bttv_unregister_video(struct bttv *btv) static int __devinit bttv_register_video(struct bttv *btv) { if (no_overlay > 0) - printk("bttv: Overlay support disabled.\n"); + pr_notice("Overlay support disabled\n"); /* video */ btv->video_dev = vdev_init(btv, &bttv_video_template, "video"); @@ -4181,12 +4196,11 @@ static int __devinit bttv_register_video(struct bttv *btv) if (video_register_device(btv->video_dev, VFL_TYPE_GRABBER, video_nr[btv->c.nr]) < 0) goto err; - printk(KERN_INFO "bttv%d: registered device %s\n", - btv->c.nr, video_device_node_name(btv->video_dev)); + pr_info("%d: registered device %s\n", + btv->c.nr, video_device_node_name(btv->video_dev)); if (device_create_file(&btv->video_dev->dev, &dev_attr_card)<0) { - printk(KERN_ERR "bttv%d: device_create_file 'card' " - "failed\n", btv->c.nr); + pr_err("%d: device_create_file 'card' failed\n", btv->c.nr); goto err; } @@ -4198,8 +4212,8 @@ static int __devinit bttv_register_video(struct bttv *btv) if (video_register_device(btv->vbi_dev, VFL_TYPE_VBI, vbi_nr[btv->c.nr]) < 0) goto err; - printk(KERN_INFO "bttv%d: registered device %s\n", - btv->c.nr, video_device_node_name(btv->vbi_dev)); + pr_info("%d: registered device %s\n", + btv->c.nr, video_device_node_name(btv->vbi_dev)); if (!btv->has_radio) return 0; @@ -4210,8 +4224,8 @@ static int __devinit bttv_register_video(struct bttv *btv) if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO, radio_nr[btv->c.nr]) < 0) goto err; - printk(KERN_INFO "bttv%d: registered device %s\n", - btv->c.nr, video_device_node_name(btv->radio_dev)); + pr_info("%d: registered device %s\n", + btv->c.nr, video_device_node_name(btv->radio_dev)); /* all done */ return 0; @@ -4244,10 +4258,10 @@ static int __devinit bttv_probe(struct pci_dev *dev, if (bttv_num == BTTV_MAX) return -ENOMEM; - printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num); + pr_info("Bt8xx card found (%d)\n", bttv_num); bttvs[bttv_num] = btv = kzalloc(sizeof(*btv), GFP_KERNEL); if (btv == NULL) { - printk(KERN_ERR "bttv: out of memory.\n"); + pr_err("out of memory\n"); return -ENOMEM; } btv->c.nr = bttv_num; @@ -4277,21 +4291,19 @@ static int __devinit bttv_probe(struct pci_dev *dev, btv->c.pci = dev; btv->id = dev->device; if (pci_enable_device(dev)) { - printk(KERN_WARNING "bttv%d: Can't enable device.\n", - btv->c.nr); + pr_warn("%d: Can't enable device\n", btv->c.nr); return -EIO; } if (pci_set_dma_mask(dev, DMA_BIT_MASK(32))) { - printk(KERN_WARNING "bttv%d: No suitable DMA available.\n", - btv->c.nr); + pr_warn("%d: No suitable DMA available\n", btv->c.nr); return -EIO; } if (!request_mem_region(pci_resource_start(dev,0), pci_resource_len(dev,0), btv->c.v4l2_dev.name)) { - printk(KERN_WARNING "bttv%d: can't request iomem (0x%llx).\n", - btv->c.nr, - (unsigned long long)pci_resource_start(dev,0)); + pr_warn("%d: can't request iomem (0x%llx)\n", + btv->c.nr, + (unsigned long long)pci_resource_start(dev, 0)); return -EBUSY; } pci_set_master(dev); @@ -4299,22 +4311,21 @@ static int __devinit bttv_probe(struct pci_dev *dev, result = v4l2_device_register(&dev->dev, &btv->c.v4l2_dev); if (result < 0) { - printk(KERN_WARNING "bttv%d: v4l2_device_register() failed\n", btv->c.nr); + pr_warn("%d: v4l2_device_register() failed\n", btv->c.nr); goto fail0; } btv->revision = dev->revision; pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); - printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ", - bttv_num,btv->id, btv->revision, pci_name(dev)); - printk("irq: %d, latency: %d, mmio: 0x%llx\n", - btv->c.pci->irq, lat, - (unsigned long long)pci_resource_start(dev,0)); + pr_info("%d: Bt%d (rev %d) at %s, irq: %d, latency: %d, mmio: 0x%llx\n", + bttv_num, btv->id, btv->revision, pci_name(dev), + btv->c.pci->irq, lat, + (unsigned long long)pci_resource_start(dev, 0)); schedule(); btv->bt848_mmio = ioremap(pci_resource_start(dev, 0), 0x1000); if (NULL == btv->bt848_mmio) { - printk("bttv%d: ioremap() failed\n", btv->c.nr); + pr_err("%d: ioremap() failed\n", btv->c.nr); result = -EIO; goto fail1; } @@ -4327,8 +4338,8 @@ static int __devinit bttv_probe(struct pci_dev *dev, result = request_irq(btv->c.pci->irq, bttv_irq, IRQF_SHARED | IRQF_DISABLED, btv->c.v4l2_dev.name, (void *)btv); if (result < 0) { - printk(KERN_ERR "bttv%d: can't get IRQ %d\n", - bttv_num,btv->c.pci->irq); + pr_err("%d: can't get IRQ %d\n", + bttv_num, btv->c.pci->irq); goto fail1; } @@ -4433,7 +4444,7 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev) struct bttv *btv = to_bttv(v4l2_dev); if (bttv_verbose) - printk("bttv%d: unloading\n",btv->c.nr); + pr_info("%d: unloading\n", btv->c.nr); if (bttv_tvcards[btv->c.type].has_dvb) flush_request_modules(btv); @@ -4481,7 +4492,7 @@ static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state) struct bttv_buffer_set idle; unsigned long flags; - dprintk("bttv%d: suspend %d\n", btv->c.nr, state.event); + dprintk("%d: suspend %d\n", btv->c.nr, state.event); /* stop dma + irqs */ spin_lock_irqsave(&btv->s_lock,flags); @@ -4517,14 +4528,13 @@ static int bttv_resume(struct pci_dev *pci_dev) unsigned long flags; int err; - dprintk("bttv%d: resume\n", btv->c.nr); + dprintk("%d: resume\n", btv->c.nr); /* restore pci state */ if (btv->state.disabled) { err=pci_enable_device(pci_dev); if (err) { - printk(KERN_WARNING "bttv%d: Can't enable device.\n", - btv->c.nr); + pr_warn("%d: Can't enable device\n", btv->c.nr); return err; } btv->state.disabled = 0; @@ -4532,8 +4542,7 @@ static int bttv_resume(struct pci_dev *pci_dev) err=pci_set_power_state(pci_dev, PCI_D0); if (err) { pci_disable_device(pci_dev); - printk(KERN_WARNING "bttv%d: Can't enable device.\n", - btv->c.nr); + pr_warn("%d: Can't enable device\n", btv->c.nr); btv->state.disabled = 1; return err; } @@ -4585,22 +4594,21 @@ static int __init bttv_init_module(void) bttv_num = 0; - printk(KERN_INFO "bttv: driver version %s loaded\n", - BTTV_VERSION); + pr_info("driver version %s loaded\n", BTTV_VERSION); if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME) gbuffers = 2; if (gbufsize > BTTV_MAX_FBUF) gbufsize = BTTV_MAX_FBUF; gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK; if (bttv_verbose) - printk(KERN_INFO "bttv: using %d buffers with %dk (%d pages) each for capture\n", - gbuffers, gbufsize >> 10, gbufsize >> PAGE_SHIFT); + pr_info("using %d buffers with %dk (%d pages) each for capture\n", + gbuffers, gbufsize >> 10, gbufsize >> PAGE_SHIFT); bttv_check_chipset(); ret = bus_register(&bttv_sub_bus_type); if (ret < 0) { - printk(KERN_WARNING "bttv: bus_register error: %d\n", ret); + pr_warn("bus_register error: %d\n", ret); return ret; } ret = pci_register_driver(&bttv_pci_driver); diff --git a/drivers/media/video/bt8xx/bttv-gpio.c b/drivers/media/video/bt8xx/bttv-gpio.c index 13ce72c..922e823 100644 --- a/drivers/media/video/bt8xx/bttv-gpio.c +++ b/drivers/media/video/bt8xx/bttv-gpio.c @@ -26,6 +26,8 @@ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -99,7 +101,7 @@ int bttv_sub_add_device(struct bttv_core *core, char *name) kfree(sub); return err; } - printk("bttv%d: add subdevice \"%s\"\n", core->nr, dev_name(&sub->dev)); + pr_info("%d: add subdevice \"%s\"\n", core->nr, dev_name(&sub->dev)); list_add_tail(&sub->list,&core->subs); return 0; } diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c index d49b675..e3952af 100644 --- a/drivers/media/video/bt8xx/bttv-i2c.c +++ b/drivers/media/video/bt8xx/bttv-i2c.c @@ -27,6 +27,8 @@ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -154,9 +156,7 @@ bttv_i2c_sendbytes(struct bttv *btv, const struct i2c_msg *msg, int last) if (retval == 0) goto eio; if (i2c_debug) { - printk(" addr << 1, msg->buf[0]); - if (!(xmit & BT878_I2C_NOSTOP)) - printk(" >\n"); + pr_cont(" addr << 1, msg->buf[0]); } for (cnt = 1; cnt < msg->len; cnt++ ) { @@ -170,19 +170,18 @@ bttv_i2c_sendbytes(struct bttv *btv, const struct i2c_msg *msg, int last) goto err; if (retval == 0) goto eio; - if (i2c_debug) { - printk(" %02x", msg->buf[cnt]); - if (!(xmit & BT878_I2C_NOSTOP)) - printk(" >\n"); - } + if (i2c_debug) + pr_cont(" %02x", msg->buf[cnt]); } + if (!(xmit & BT878_I2C_NOSTOP)) + pr_cont(">\n"); return msg->len; eio: retval = -EIO; err: if (i2c_debug) - printk(" ERR: %d\n",retval); + pr_cont(" ERR: %d\n",retval); return retval; } @@ -193,7 +192,7 @@ bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last) u32 cnt; int retval; - for(cnt = 0; cnt < msg->len; cnt++) { + for (cnt = 0; cnt < msg->len; cnt++) { xmit = (msg->addr << 25) | (1 << 24) | I2C_HW; if (cnt < msg->len-1) xmit |= BT848_I2C_W3B; @@ -201,6 +200,12 @@ bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last) xmit |= BT878_I2C_NOSTOP; if (cnt) xmit |= BT878_I2C_NOSTART; + + if (i2c_debug) { + if (!(xmit & BT878_I2C_NOSTART)) + pr_cont(" addr << 1) +1); + } + btwrite(xmit, BT848_I2C); retval = bttv_i2c_wait_done(btv); if (retval < 0) @@ -209,20 +214,20 @@ bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last) goto eio; msg->buf[cnt] = ((u32)btread(BT848_I2C) >> 8) & 0xff; if (i2c_debug) { - if (!(xmit & BT878_I2C_NOSTART)) - printk(" addr << 1) +1); - printk(" =%02x", msg->buf[cnt]); - if (!(xmit & BT878_I2C_NOSTOP)) - printk(" >\n"); + pr_cont(" =%02x", msg->buf[cnt]); } + if (i2c_debug && !(xmit & BT878_I2C_NOSTOP)) + pr_cont(" >\n"); } + + return msg->len; eio: retval = -EIO; err: if (i2c_debug) - printk(" ERR: %d\n",retval); + pr_cont(" ERR: %d\n",retval); return retval; } @@ -234,7 +239,8 @@ static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int int i; if (i2c_debug) - printk("bt-i2c:"); + pr_debug("bt-i2c:"); + btwrite(BT848_INT_I2CDONE|BT848_INT_RACK, BT848_INT_STAT); for (i = 0 ; i < num; i++) { if (msgs[i].flags & I2C_M_RD) { @@ -271,20 +277,20 @@ int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for) if (0 != btv->i2c_rc) return -1; if (bttv_verbose && NULL != probe_for) - printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ", - btv->c.nr,probe_for,addr); + pr_info("%d: i2c: checking for %s @ 0x%02x... ", + btv->c.nr, probe_for, addr); btv->i2c_client.addr = addr >> 1; if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) { if (NULL != probe_for) { if (bttv_verbose) - printk("not found\n"); + pr_cont("not found\n"); } else - printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n", - btv->c.nr,addr); + pr_warn("%d: i2c read 0x%x: error\n", + btv->c.nr, addr); return -1; } if (bttv_verbose && NULL != probe_for) - printk("found\n"); + pr_cont("found\n"); return buffer; } @@ -335,8 +341,8 @@ static void do_i2c_scan(char *name, struct i2c_client *c) rc = i2c_master_recv(c,&buf,0); if (rc < 0) continue; - printk("%s: i2c scan: found device @ 0x%x [%s]\n", - name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); + pr_info("%s: i2c scan: found device @ 0x%x [%s]\n", + name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); } } diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c index 677d70c..ef4c7cd 100644 --- a/drivers/media/video/bt8xx/bttv-input.c +++ b/drivers/media/video/bt8xx/bttv-input.c @@ -18,6 +18,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -36,9 +38,10 @@ static int ir_rc5_remote_gap = 885; module_param(ir_rc5_remote_gap, int, 0644); #undef dprintk -#define dprintk(arg...) do { \ - if (ir_debug >= 1) \ - printk(arg); \ +#define dprintk(fmt, ...) \ +do { \ + if (ir_debug >= 1) \ + pr_info(fmt, ##__VA_ARGS__); \ } while (0) #define DEVNAME "bttv-input" @@ -62,7 +65,7 @@ static void ir_handle_key(struct bttv *btv) /* extract data */ data = ir_extract_bits(gpio, ir->mask_keycode); - dprintk(KERN_INFO DEVNAME ": irq gpio=0x%x code=%d | %s%s%s\n", + dprintk("irq gpio=0x%x code=%d | %s%s%s\n", gpio, data, ir->polling ? "poll" : "irq", (gpio & ir->mask_keydown) ? " down" : "", @@ -96,7 +99,7 @@ static void ir_enltv_handle_key(struct bttv *btv) keyup = (gpio & ir->mask_keyup) ? 1 << 31 : 0; if ((ir->last_gpio & 0x7f) != data) { - dprintk(KERN_INFO DEVNAME ": gpio=0x%x code=%d | %s\n", + dprintk("gpio=0x%x code=%d | %s\n", gpio, data, (gpio & ir->mask_keyup) ? " up" : "up/down"); @@ -107,7 +110,7 @@ static void ir_enltv_handle_key(struct bttv *btv) if ((ir->last_gpio & 1 << 31) == keyup) return; - dprintk(KERN_INFO DEVNAME ":(cnt) gpio=0x%x code=%d | %s\n", + dprintk("(cnt) gpio=0x%x code=%d | %s\n", gpio, data, (gpio & ir->mask_keyup) ? " up" : "down"); @@ -177,13 +180,12 @@ static u32 bttv_rc5_decode(unsigned int code) rc5 |= 1; break; case 3: - dprintk(KERN_INFO DEVNAME ":rc5_decode(%x) bad code\n", + dprintk("rc5_decode(%x) bad code\n", org_code); return 0; } } - dprintk(KERN_INFO DEVNAME ":" - "code=%x, rc5=%x, start=%x, toggle=%x, address=%x, " + dprintk("code=%x, rc5=%x, start=%x, toggle=%x, address=%x, " "instr=%x\n", rc5, org_code, RC5_START(rc5), RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5)); return rc5; @@ -212,20 +214,20 @@ static void bttv_rc5_timer_end(unsigned long data) /* Allow some timer jitter (RC5 is ~24ms anyway so this is ok) */ if (gap < 28000) { - dprintk(KERN_INFO DEVNAME ": spurious timer_end\n"); + dprintk("spurious timer_end\n"); return; } if (ir->last_bit < 20) { /* ignore spurious codes (caused by light/other remotes) */ - dprintk(KERN_INFO DEVNAME ": short code: %x\n", ir->code); + dprintk("short code: %x\n", ir->code); } else { ir->code = (ir->code << ir->shift_by) | 1; rc5 = bttv_rc5_decode(ir->code); /* two start bits? */ if (RC5_START(rc5) != ir->start) { - printk(KERN_INFO DEVNAME ":" + pr_info(DEVNAME ":" " rc5 start bits invalid: %u\n", RC5_START(rc5)); /* right address? */ @@ -235,8 +237,7 @@ static void bttv_rc5_timer_end(unsigned long data) /* Good code */ rc_keydown(ir->dev, instr, toggle); - dprintk(KERN_INFO DEVNAME ":" - " instruction %x, toggle %x\n", + dprintk("instruction %x, toggle %x\n", instr, toggle); } } @@ -265,7 +266,7 @@ static int bttv_rc5_irq(struct bttv *btv) tv.tv_usec - ir->base_time.tv_usec; } - dprintk(KERN_INFO DEVNAME ": RC5 IRQ: gap %d us for %s\n", + dprintk("RC5 IRQ: gap %d us for %s\n", gap, (gpio & 0x20) ? "mark" : "space"); /* remote IRQ? */ @@ -340,14 +341,14 @@ static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) /* poll IR chip */ if (1 != i2c_master_recv(ir->c, &b, 1)) { - dprintk(KERN_INFO DEVNAME ": read error\n"); + dprintk("read error\n"); return -EIO; } /* ignore 0xaa */ if (b==0xaa) return 0; - dprintk(KERN_INFO DEVNAME ": key %02x\n", b); + dprintk("key %02x\n", b); /* * NOTE: @@ -517,7 +518,7 @@ int bttv_input_init(struct bttv *btv) break; } if (NULL == ir_codes) { - dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n", btv->c.type); + dprintk("Ooops: IR config error [card=%d]\n", btv->c.type); err = -ENODEV; goto err_out_free; } diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c index 9b57d09..82cc47d 100644 --- a/drivers/media/video/bt8xx/bttv-risc.c +++ b/drivers/media/video/bt8xx/bttv-risc.c @@ -24,6 +24,8 @@ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -473,8 +475,7 @@ bttv_set_dma(struct bttv *btv, int override) capctl |= (btv->cap_ctl & 0x0c) ? 0x0c : 0x00; /* vbi data */ capctl |= override; - d2printk(KERN_DEBUG - "bttv%d: capctl=%x lirq=%d top=%08Lx/%08Lx even=%08Lx/%08Lx\n", + d2printk("%d: capctl=%x lirq=%d top=%08llx/%08llx even=%08llx/%08llx\n", btv->c.nr,capctl,btv->loop_irq, btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0, btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0, @@ -517,8 +518,8 @@ bttv_risc_init_main(struct bttv *btv) if ((rc = btcx_riscmem_alloc(btv->c.pci,&btv->main,PAGE_SIZE)) < 0) return rc; - dprintk(KERN_DEBUG "bttv%d: risc main @ %08Lx\n", - btv->c.nr,(unsigned long long)btv->main.dma); + dprintk("%d: risc main @ %08llx\n", + btv->c.nr, (unsigned long long)btv->main.dma); btv->main.cpu[0] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC | BT848_FIFO_STATUS_VRE); @@ -557,12 +558,12 @@ bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc, unsigned long next = btv->main.dma + ((slot+2) << 2); if (NULL == risc) { - d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=NULL\n", - btv->c.nr,risc,slot); + d2printk("%d: risc=%p slot[%d]=NULL\n", btv->c.nr, risc, slot); btv->main.cpu[slot+1] = cpu_to_le32(next); } else { - d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=%08Lx irq=%d\n", - btv->c.nr,risc,slot,(unsigned long long)risc->dma,irqflags); + d2printk("%d: risc=%p slot[%d]=%08llx irq=%d\n", + btv->c.nr, risc, slot, + (unsigned long long)risc->dma, irqflags); cmd = BT848_RISC_JUMP; if (irqflags) { cmd |= BT848_RISC_IRQ; @@ -708,8 +709,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm; struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - dprintk(KERN_DEBUG - "bttv%d: buffer field: %s format: %s size: %dx%d\n", + dprintk("%d: buffer field: %s format: %s size: %dx%d\n", btv->c.nr, v4l2_field_names[buf->vb.field], buf->fmt->name, buf->vb.width, buf->vb.height); @@ -870,10 +870,9 @@ bttv_overlay_risc(struct bttv *btv, struct bttv_buffer *buf) { /* check interleave, bottom+top fields */ - dprintk(KERN_DEBUG - "bttv%d: overlay fields: %s format: %s size: %dx%d\n", + dprintk("%d: overlay fields: %s format: %s size: %dx%d\n", btv->c.nr, v4l2_field_names[buf->vb.field], - fmt->name,ov->w.width,ov->w.height); + fmt->name, ov->w.width, ov->w.height); /* calculate geometry */ bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height, diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c index e79a402..b433267 100644 --- a/drivers/media/video/bt8xx/bttv-vbi.c +++ b/drivers/media/video/bt8xx/bttv-vbi.c @@ -23,6 +23,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -65,8 +67,11 @@ MODULE_PARM_DESC(vbi_debug,"vbi code debug messages, default is 0 (no)"); #ifdef dprintk # undef dprintk #endif -#define dprintk(fmt, arg...) if (vbi_debug) \ - printk(KERN_DEBUG "bttv%d/vbi: " fmt, btv->c.nr , ## arg) +#define dprintk(fmt, ...) \ +do { \ + if (vbi_debug) \ + pr_debug("%d: " fmt, btv->c.nr, ##__VA_ARGS__); \ +} while (0) #define IMAGE_SIZE(fmt) \ (((fmt)->count[0] + (fmt)->count[1]) * (fmt)->samples_per_line) diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h index 318edf2..db943a8d 100644 --- a/drivers/media/video/bt8xx/bttvp.h +++ b/drivers/media/video/bt8xx/bttvp.h @@ -310,9 +310,21 @@ extern unsigned int bttv_gpio; extern void bttv_gpio_tracking(struct bttv *btv, char *comment); extern int init_bttv_i2c(struct bttv *btv); -#define bttv_printk if (bttv_verbose) printk -#define dprintk if (bttv_debug >= 1) printk -#define d2printk if (bttv_debug >= 2) printk +#define dprintk(fmt, ...) \ +do { \ + if (bttv_debug >= 1) \ + pr_debug(fmt, ##__VA_ARGS__); \ +} while (0) +#define dprintk_cont(fmt, ...) \ +do { \ + if (bttv_debug >= 1) \ + pr_cont(fmt, ##__VA_ARGS__); \ +} while (0) +#define d2printk(fmt, ...) \ +do { \ + if (bttv_debug >= 2) \ + printk(fmt, ##__VA_ARGS__); \ +} while (0) #define BTTV_MAX_FBUF 0x208000 #define BTTV_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ -- cgit v0.10.2 From 857011e4d9bf47b39abcc89541a58c56e4df34be Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 21 Aug 2011 19:56:50 -0300 Subject: [media] et61x251: Use current logging styles Add pr_fmt and convert printks to pr_ Remove explicit prefixes from logging messages. One of the prefixes was defective, a copy/paste error. Use ##__VA_ARGS__ for variadic macros. Whitespace neatening. Signed-off-by: Joe Perches Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/et61x251/et61x251.h b/drivers/media/video/et61x251/et61x251.h index 14bb907..337ded4 100644 --- a/drivers/media/video/et61x251/et61x251.h +++ b/drivers/media/video/et61x251/et61x251.h @@ -165,45 +165,49 @@ et61x251_attach_sensor(struct et61x251_device* cam, #undef DBG #undef KDBG #ifdef ET61X251_DEBUG -# define DBG(level, fmt, args...) \ -do { \ - if (debug >= (level)) { \ - if ((level) == 1) \ - dev_err(&cam->usbdev->dev, fmt "\n", ## args); \ - else if ((level) == 2) \ - dev_info(&cam->usbdev->dev, fmt "\n", ## args); \ - else if ((level) >= 3) \ - dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", \ - __FILE__, __func__, __LINE__ , ## args); \ - } \ +#define DBG(level, fmt, ...) \ +do { \ + if (debug >= (level)) { \ + if ((level) == 1) \ + dev_err(&cam->usbdev->dev, fmt "\n", \ + ##__VA_ARGS__); \ + else if ((level) == 2) \ + dev_info(&cam->usbdev->dev, fmt "\n", \ + ##__VA_ARGS__); \ + else if ((level) >= 3) \ + dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", \ + __FILE__, __func__, __LINE__, \ + ##__VA_ARGS__); \ + } \ } while (0) -# define KDBG(level, fmt, args...) \ -do { \ - if (debug >= (level)) { \ - if ((level) == 1 || (level) == 2) \ - pr_info("et61x251: " fmt "\n", ## args); \ - else if ((level) == 3) \ - pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__, \ - __func__, __LINE__ , ## args); \ - } \ +#define KDBG(level, fmt, ...) \ +do { \ + if (debug >= (level)) { \ + if ((level) == 1 || (level) == 2) \ + pr_info(fmt "\n", ##__VA_ARGS__); \ + else if ((level) == 3) \ + pr_debug("[%s:%s:%d] " fmt "\n", \ + __FILE__, __func__, __LINE__, \ + ##__VA_ARGS__); \ + } \ } while (0) -# define V4LDBG(level, name, cmd) \ -do { \ - if (debug >= (level)) \ - v4l_print_ioctl(name, cmd); \ +#define V4LDBG(level, name, cmd) \ +do { \ + if (debug >= (level)) \ + v4l_print_ioctl(name, cmd); \ } while (0) #else -# define DBG(level, fmt, args...) do {;} while(0) -# define KDBG(level, fmt, args...) do {;} while(0) -# define V4LDBG(level, name, cmd) do {;} while(0) +#define DBG(level, fmt, ...) do {;} while(0) +#define KDBG(level, fmt, ...) do {;} while(0) +#define V4LDBG(level, name, cmd) do {;} while(0) #endif #undef PDBG -#define PDBG(fmt, args...) \ -dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __func__, \ - __LINE__ , ## args) +#define PDBG(fmt, ...) \ + dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", \ + __FILE__, __func__, __LINE__, ##__VA_ARGS__) #undef PDBGG -#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ +#define PDBGG(fmt, args...) do {;} while (0) /* placeholder */ #endif /* _ET61X251_H_ */ diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index 9a1e80a..d3777c8 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -18,6 +18,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * ***************************************************************************/ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include diff --git a/drivers/media/video/et61x251/et61x251_tas5130d1b.c b/drivers/media/video/et61x251/et61x251_tas5130d1b.c index 04b7fbb..ced2e16 100644 --- a/drivers/media/video/et61x251/et61x251_tas5130d1b.c +++ b/drivers/media/video/et61x251/et61x251_tas5130d1b.c @@ -19,6 +19,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * ***************************************************************************/ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "et61x251_sensor.h" -- cgit v0.10.2 From d650fc30c0328eceb0e48f348e01e073b5a7f1f6 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 21 Aug 2011 19:56:51 -0300 Subject: [media] gl860: Use current logging styles Add pr_fmt. Convert err macro use to pr_err. Signed-off-by: Joe Perches Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/gl860/gl860.c b/drivers/media/video/gspca/gl860/gl860.c index e8e071a..2ced3b7 100644 --- a/drivers/media/video/gspca/gl860/gl860.c +++ b/drivers/media/video/gspca/gl860/gl860.c @@ -18,6 +18,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "gspca.h" #include "gl860.h" @@ -572,9 +575,8 @@ int gl860_RTx(struct gspca_dev *gspca_dev, } if (r < 0) - err("ctrl transfer failed %4d " - "[p%02x r%d v%04x i%04x len%d]", - r, pref, req, val, index, len); + pr_err("ctrl transfer failed %4d [p%02x r%d v%04x i%04x len%d]\n", + r, pref, req, val, index, len); else if (len > 1 && r < len) PDEBUG(D_ERR, "short ctrl transfer %d/%d", r, len); -- cgit v0.10.2 From bdfe91f411bd05392952efc1afdce8bda1923517 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 21 Aug 2011 19:56:52 -0300 Subject: [media] m5602: Use current logging styles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add pr_fmt and convert usb style logging macro uses to pr_. Coalesce format strings. Signed-off-by: Joe Perches Acked-by: Erik Andrén Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/m5602/m5602_core.c b/drivers/media/video/gspca/m5602/m5602_core.c index a7722b1..67533e5 100644 --- a/drivers/media/video/gspca/m5602/m5602_core.c +++ b/drivers/media/video/gspca/m5602/m5602_core.c @@ -16,6 +16,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "m5602_ov9650.h" #include "m5602_ov7660.h" #include "m5602_mt9m111.h" @@ -192,10 +194,9 @@ static void m5602_dump_bridge(struct sd *sd) for (i = 0; i < 0x80; i++) { unsigned char val = 0; m5602_read_bridge(sd, i, &val); - info("ALi m5602 address 0x%x contains 0x%x", i, val); + pr_info("ALi m5602 address 0x%x contains 0x%x\n", i, val); } - info("Warning: The ALi m5602 webcam probably won't work " - "until it's power cycled"); + pr_info("Warning: The ALi m5602 webcam probably won't work until it's power cycled\n"); } static int m5602_probe_sensor(struct sd *sd) @@ -231,7 +232,7 @@ static int m5602_probe_sensor(struct sd *sd) return 0; /* More sensor probe function goes here */ - info("Failed to find a sensor"); + pr_info("Failed to find a sensor\n"); sd->sensor = NULL; return -ENODEV; } diff --git a/drivers/media/video/gspca/m5602/m5602_mt9m111.c b/drivers/media/video/gspca/m5602/m5602_mt9m111.c index 0d605a5..6268aa2 100644 --- a/drivers/media/video/gspca/m5602/m5602_mt9m111.c +++ b/drivers/media/video/gspca/m5602/m5602_mt9m111.c @@ -16,6 +16,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "m5602_mt9m111.h" static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val); @@ -163,7 +165,7 @@ int mt9m111_probe(struct sd *sd) if (force_sensor) { if (force_sensor == MT9M111_SENSOR) { - info("Forcing a %s sensor", mt9m111.name); + pr_info("Forcing a %s sensor\n", mt9m111.name); goto sensor_found; } /* If we want to force another sensor, don't try to probe this @@ -191,7 +193,7 @@ int mt9m111_probe(struct sd *sd) return -ENODEV; if ((data[0] == 0x14) && (data[1] == 0x3a)) { - info("Detected a mt9m111 sensor"); + pr_info("Detected a mt9m111 sensor\n"); goto sensor_found; } @@ -612,34 +614,34 @@ static void mt9m111_dump_registers(struct sd *sd) { u8 address, value[2] = {0x00, 0x00}; - info("Dumping the mt9m111 register state"); + pr_info("Dumping the mt9m111 register state\n"); - info("Dumping the mt9m111 sensor core registers"); + pr_info("Dumping the mt9m111 sensor core registers\n"); value[1] = MT9M111_SENSOR_CORE; m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); for (address = 0; address < 0xff; address++) { m5602_read_sensor(sd, address, value, 2); - info("register 0x%x contains 0x%x%x", - address, value[0], value[1]); + pr_info("register 0x%x contains 0x%x%x\n", + address, value[0], value[1]); } - info("Dumping the mt9m111 color pipeline registers"); + pr_info("Dumping the mt9m111 color pipeline registers\n"); value[1] = MT9M111_COLORPIPE; m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); for (address = 0; address < 0xff; address++) { m5602_read_sensor(sd, address, value, 2); - info("register 0x%x contains 0x%x%x", - address, value[0], value[1]); + pr_info("register 0x%x contains 0x%x%x\n", + address, value[0], value[1]); } - info("Dumping the mt9m111 camera control registers"); + pr_info("Dumping the mt9m111 camera control registers\n"); value[1] = MT9M111_CAMERA_CONTROL; m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); for (address = 0; address < 0xff; address++) { m5602_read_sensor(sd, address, value, 2); - info("register 0x%x contains 0x%x%x", - address, value[0], value[1]); + pr_info("register 0x%x contains 0x%x%x\n", + address, value[0], value[1]); } - info("mt9m111 register state dump complete"); + pr_info("mt9m111 register state dump complete\n"); } diff --git a/drivers/media/video/gspca/m5602/m5602_ov7660.c b/drivers/media/video/gspca/m5602/m5602_ov7660.c index b12f604..9a14835 100644 --- a/drivers/media/video/gspca/m5602/m5602_ov7660.c +++ b/drivers/media/video/gspca/m5602/m5602_ov7660.c @@ -16,6 +16,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "m5602_ov7660.h" static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val); @@ -149,7 +151,7 @@ int ov7660_probe(struct sd *sd) if (force_sensor) { if (force_sensor == OV7660_SENSOR) { - info("Forcing an %s sensor", ov7660.name); + pr_info("Forcing an %s sensor\n", ov7660.name); goto sensor_found; } /* If we want to force another sensor, @@ -180,10 +182,10 @@ int ov7660_probe(struct sd *sd) if (m5602_read_sensor(sd, OV7660_VER, &ver_id, 1)) return -ENODEV; - info("Sensor reported 0x%x%x", prod_id, ver_id); + pr_info("Sensor reported 0x%x%x\n", prod_id, ver_id); if ((prod_id == 0x76) && (ver_id == 0x60)) { - info("Detected a ov7660 sensor"); + pr_info("Detected a ov7660 sensor\n"); goto sensor_found; } return -ENODEV; @@ -457,17 +459,16 @@ static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val) static void ov7660_dump_registers(struct sd *sd) { int address; - info("Dumping the ov7660 register state"); + pr_info("Dumping the ov7660 register state\n"); for (address = 0; address < 0xa9; address++) { u8 value; m5602_read_sensor(sd, address, &value, 1); - info("register 0x%x contains 0x%x", - address, value); + pr_info("register 0x%x contains 0x%x\n", address, value); } - info("ov7660 register state dump complete"); + pr_info("ov7660 register state dump complete\n"); - info("Probing for which registers that are read/write"); + pr_info("Probing for which registers that are read/write\n"); for (address = 0; address < 0xff; address++) { u8 old_value, ctrl_value; u8 test_value[2] = {0xff, 0xff}; @@ -477,9 +478,9 @@ static void ov7660_dump_registers(struct sd *sd) m5602_read_sensor(sd, address, &ctrl_value, 1); if (ctrl_value == test_value[0]) - info("register 0x%x is writeable", address); + pr_info("register 0x%x is writeable\n", address); else - info("register 0x%x is read only", address); + pr_info("register 0x%x is read only\n", address); /* Restore original value */ m5602_write_sensor(sd, address, &old_value, 1); diff --git a/drivers/media/video/gspca/m5602/m5602_ov9650.c b/drivers/media/video/gspca/m5602/m5602_ov9650.c index 703d486..2114a8b 100644 --- a/drivers/media/video/gspca/m5602/m5602_ov9650.c +++ b/drivers/media/video/gspca/m5602/m5602_ov9650.c @@ -16,6 +16,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "m5602_ov9650.h" static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val); @@ -299,7 +301,7 @@ int ov9650_probe(struct sd *sd) if (force_sensor) { if (force_sensor == OV9650_SENSOR) { - info("Forcing an %s sensor", ov9650.name); + pr_info("Forcing an %s sensor\n", ov9650.name); goto sensor_found; } /* If we want to force another sensor, @@ -330,7 +332,7 @@ int ov9650_probe(struct sd *sd) return -ENODEV; if ((prod_id == 0x96) && (ver_id == 0x52)) { - info("Detected an ov9650 sensor"); + pr_info("Detected an ov9650 sensor\n"); goto sensor_found; } return -ENODEV; @@ -850,17 +852,16 @@ static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) static void ov9650_dump_registers(struct sd *sd) { int address; - info("Dumping the ov9650 register state"); + pr_info("Dumping the ov9650 register state\n"); for (address = 0; address < 0xa9; address++) { u8 value; m5602_read_sensor(sd, address, &value, 1); - info("register 0x%x contains 0x%x", - address, value); + pr_info("register 0x%x contains 0x%x\n", address, value); } - info("ov9650 register state dump complete"); + pr_info("ov9650 register state dump complete\n"); - info("Probing for which registers that are read/write"); + pr_info("Probing for which registers that are read/write\n"); for (address = 0; address < 0xff; address++) { u8 old_value, ctrl_value; u8 test_value[2] = {0xff, 0xff}; @@ -870,9 +871,9 @@ static void ov9650_dump_registers(struct sd *sd) m5602_read_sensor(sd, address, &ctrl_value, 1); if (ctrl_value == test_value[0]) - info("register 0x%x is writeable", address); + pr_info("register 0x%x is writeable\n", address); else - info("register 0x%x is read only", address); + pr_info("register 0x%x is read only\n", address); /* Restore original value */ m5602_write_sensor(sd, address, &old_value, 1); diff --git a/drivers/media/video/gspca/m5602/m5602_po1030.c b/drivers/media/video/gspca/m5602/m5602_po1030.c index 1febd34..b877169 100644 --- a/drivers/media/video/gspca/m5602/m5602_po1030.c +++ b/drivers/media/video/gspca/m5602/m5602_po1030.c @@ -16,6 +16,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "m5602_po1030.h" static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); @@ -197,7 +199,7 @@ int po1030_probe(struct sd *sd) if (force_sensor) { if (force_sensor == PO1030_SENSOR) { - info("Forcing a %s sensor", po1030.name); + pr_info("Forcing a %s sensor\n", po1030.name); goto sensor_found; } /* If we want to force another sensor, don't try to probe this @@ -221,7 +223,7 @@ int po1030_probe(struct sd *sd) return -ENODEV; if (dev_id_h == 0x30) { - info("Detected a po1030 sensor"); + pr_info("Detected a po1030 sensor\n"); goto sensor_found; } return -ENODEV; @@ -267,7 +269,7 @@ int po1030_init(struct sd *sd) break; default: - info("Invalid stream command, exiting init"); + pr_info("Invalid stream command, exiting init\n"); return -EINVAL; } } @@ -733,16 +735,15 @@ static void po1030_dump_registers(struct sd *sd) int address; u8 value = 0; - info("Dumping the po1030 sensor core registers"); + pr_info("Dumping the po1030 sensor core registers\n"); for (address = 0; address < 0x7f; address++) { m5602_read_sensor(sd, address, &value, 1); - info("register 0x%x contains 0x%x", - address, value); + pr_info("register 0x%x contains 0x%x\n", address, value); } - info("po1030 register state dump complete"); + pr_info("po1030 register state dump complete\n"); - info("Probing for which registers that are read/write"); + pr_info("Probing for which registers that are read/write\n"); for (address = 0; address < 0xff; address++) { u8 old_value, ctrl_value; u8 test_value[2] = {0xff, 0xff}; @@ -752,9 +753,9 @@ static void po1030_dump_registers(struct sd *sd) m5602_read_sensor(sd, address, &ctrl_value, 1); if (ctrl_value == test_value[0]) - info("register 0x%x is writeable", address); + pr_info("register 0x%x is writeable\n", address); else - info("register 0x%x is read only", address); + pr_info("register 0x%x is read only\n", address); /* Restore original value */ m5602_write_sensor(sd, address, &old_value, 1); diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c index d27280b..cc8ec3f 100644 --- a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c +++ b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c @@ -16,6 +16,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "m5602_s5k4aa.h" static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); @@ -240,7 +242,7 @@ int s5k4aa_probe(struct sd *sd) if (force_sensor) { if (force_sensor == S5K4AA_SENSOR) { - info("Forcing a %s sensor", s5k4aa.name); + pr_info("Forcing a %s sensor\n", s5k4aa.name); goto sensor_found; } /* If we want to force another sensor, don't try to probe this @@ -276,7 +278,7 @@ int s5k4aa_probe(struct sd *sd) data, 2); break; default: - info("Invalid stream command, exiting init"); + pr_info("Invalid stream command, exiting init\n"); return -EINVAL; } } @@ -292,7 +294,7 @@ int s5k4aa_probe(struct sd *sd) if (memcmp(prod_id, expected_prod_id, sizeof(prod_id))) return -ENODEV; else - info("Detected a s5k4aa sensor"); + pr_info("Detected a s5k4aa sensor\n"); sensor_found: sensor_settings = kmalloc( @@ -347,7 +349,7 @@ int s5k4aa_start(struct sd *sd) break; default: - err("Invalid stream command, exiting init"); + pr_err("Invalid stream command, exiting init\n"); return -EINVAL; } } @@ -383,7 +385,7 @@ int s5k4aa_start(struct sd *sd) break; default: - err("Invalid stream command, exiting init"); + pr_err("Invalid stream command, exiting init\n"); return -EINVAL; } } @@ -447,7 +449,7 @@ int s5k4aa_init(struct sd *sd) init_s5k4aa[i][1], data, 2); break; default: - info("Invalid stream command, exiting init"); + pr_info("Invalid stream command, exiting init\n"); return -EINVAL; } } @@ -686,20 +688,21 @@ static void s5k4aa_dump_registers(struct sd *sd) m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1); for (page = 0; page < 16; page++) { m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1); - info("Dumping the s5k4aa register state for page 0x%x", page); + pr_info("Dumping the s5k4aa register state for page 0x%x\n", + page); for (address = 0; address <= 0xff; address++) { u8 value = 0; m5602_read_sensor(sd, address, &value, 1); - info("register 0x%x contains 0x%x", - address, value); + pr_info("register 0x%x contains 0x%x\n", + address, value); } } - info("s5k4aa register state dump complete"); + pr_info("s5k4aa register state dump complete\n"); for (page = 0; page < 16; page++) { m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1); - info("Probing for which registers that are " - "read/write for page 0x%x", page); + pr_info("Probing for which registers that are read/write for page 0x%x\n", + page); for (address = 0; address <= 0xff; address++) { u8 old_value, ctrl_value, test_value = 0xff; @@ -708,14 +711,16 @@ static void s5k4aa_dump_registers(struct sd *sd) m5602_read_sensor(sd, address, &ctrl_value, 1); if (ctrl_value == test_value) - info("register 0x%x is writeable", address); + pr_info("register 0x%x is writeable\n", + address); else - info("register 0x%x is read only", address); + pr_info("register 0x%x is read only\n", + address); /* Restore original value */ m5602_write_sensor(sd, address, &old_value, 1); } } - info("Read/write register probing complete"); + pr_info("Read/write register probing complete\n"); m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1); } diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.c b/drivers/media/video/gspca/m5602/m5602_s5k83a.c index fbd9154..1de743a 100644 --- a/drivers/media/video/gspca/m5602/m5602_s5k83a.c +++ b/drivers/media/video/gspca/m5602/m5602_s5k83a.c @@ -16,6 +16,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include "m5602_s5k83a.h" @@ -135,7 +137,7 @@ int s5k83a_probe(struct sd *sd) if (force_sensor) { if (force_sensor == S5K83A_SENSOR) { - info("Forcing a %s sensor", s5k83a.name); + pr_info("Forcing a %s sensor\n", s5k83a.name); goto sensor_found; } /* If we want to force another sensor, don't try to probe this @@ -168,7 +170,7 @@ int s5k83a_probe(struct sd *sd) if ((prod_id == 0xff) || (ver_id == 0xff)) return -ENODEV; else - info("Detected a s5k83a sensor"); + pr_info("Detected a s5k83a sensor\n"); sensor_found: sens_priv = kmalloc( @@ -227,7 +229,7 @@ int s5k83a_init(struct sd *sd) init_s5k83a[i][1], data, 2); break; default: - info("Invalid stream command, exiting init"); + pr_info("Invalid stream command, exiting init\n"); return -EINVAL; } } @@ -273,7 +275,7 @@ static int rotation_thread_function(void *data) s5k83a_get_rotation(sd, ®); if (previous_rotation != reg) { previous_rotation = reg; - info("Camera was flipped"); + pr_info("Camera was flipped\n"); s5k83a_get_vflip((struct gspca_dev *) sd, &vflip); s5k83a_get_hflip((struct gspca_dev *) sd, &hflip); @@ -566,20 +568,20 @@ static void s5k83a_dump_registers(struct sd *sd) for (page = 0; page < 16; page++) { m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1); - info("Dumping the s5k83a register state for page 0x%x", page); + pr_info("Dumping the s5k83a register state for page 0x%x\n", + page); for (address = 0; address <= 0xff; address++) { u8 val = 0; m5602_read_sensor(sd, address, &val, 1); - info("register 0x%x contains 0x%x", - address, val); + pr_info("register 0x%x contains 0x%x\n", address, val); } } - info("s5k83a register state dump complete"); + pr_info("s5k83a register state dump complete\n"); for (page = 0; page < 16; page++) { m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1); - info("Probing for which registers that are read/write " - "for page 0x%x", page); + pr_info("Probing for which registers that are read/write for page 0x%x\n", + page); for (address = 0; address <= 0xff; address++) { u8 old_val, ctrl_val, test_val = 0xff; @@ -588,14 +590,16 @@ static void s5k83a_dump_registers(struct sd *sd) m5602_read_sensor(sd, address, &ctrl_val, 1); if (ctrl_val == test_val) - info("register 0x%x is writeable", address); + pr_info("register 0x%x is writeable\n", + address); else - info("register 0x%x is read only", address); + pr_info("register 0x%x is read only\n", + address); /* Restore original val */ m5602_write_sensor(sd, address, &old_val, 1); } } - info("Read/write register probing complete"); + pr_info("Read/write register probing complete\n"); m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1); } -- cgit v0.10.2 From 70a429954799bbf71f87abf12aaa35bf52cd9913 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 21 Aug 2011 19:56:53 -0300 Subject: [media] finepix: Use current logging styles Add pr_fmt. Convert usb style logging macros to pr_. Signed-off-by: Joe Perches Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/finepix.c b/drivers/media/video/gspca/finepix.c index 987b4b6..ea48200 100644 --- a/drivers/media/video/gspca/finepix.c +++ b/drivers/media/video/gspca/finepix.c @@ -18,6 +18,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "finepix" #include "gspca.h" @@ -182,7 +184,7 @@ static int sd_start(struct gspca_dev *gspca_dev) /* Init the device */ ret = command(gspca_dev, 0); if (ret < 0) { - err("init failed %d", ret); + pr_err("init failed %d\n", ret); return ret; } @@ -194,14 +196,14 @@ static int sd_start(struct gspca_dev *gspca_dev) FPIX_MAX_TRANSFER, &len, FPIX_TIMEOUT); if (ret < 0) { - err("usb_bulk_msg failed %d", ret); + pr_err("usb_bulk_msg failed %d\n", ret); return ret; } /* Request a frame, but don't read it */ ret = command(gspca_dev, 1); if (ret < 0) { - err("frame request failed %d", ret); + pr_err("frame request failed %d\n", ret); return ret; } -- cgit v0.10.2 From be612514c0f9d543d3689111755e1aa6a008e88f Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 21 Aug 2011 19:56:54 -0300 Subject: [media] pac207: Use current logging styles Add pr_fmt. Convert usb style logging macros to pr_. Coalesce formats. Signed-off-by: Joe Perches Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c index 81739a2..1600df1 100644 --- a/drivers/media/video/gspca/pac207.c +++ b/drivers/media/video/gspca/pac207.c @@ -23,6 +23,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "pac207" #include @@ -178,8 +180,8 @@ static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index, 0x00, index, gspca_dev->usb_buf, length, PAC207_CTRL_TIMEOUT); if (err < 0) - err("Failed to write registers to index 0x%04X, error %d)", - index, err); + pr_err("Failed to write registers to index 0x%04X, error %d\n", + index, err); return err; } @@ -194,8 +196,8 @@ static int pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value) USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, value, index, NULL, 0, PAC207_CTRL_TIMEOUT); if (err) - err("Failed to write a register (index 0x%04X," - " value 0x%02X, error %d)", index, value, err); + pr_err("Failed to write a register (index 0x%04X, value 0x%02X, error %d)\n", + index, value, err); return err; } @@ -210,8 +212,8 @@ static int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index) 0x00, index, gspca_dev->usb_buf, 1, PAC207_CTRL_TIMEOUT); if (res < 0) { - err("Failed to read a register (index 0x%04X, error %d)", - index, res); + pr_err("Failed to read a register (index 0x%04X, error %d)\n", + index, res); return res; } -- cgit v0.10.2 From 91f5842b327d4c91f0ab2d9775ac1357054cf951 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 21 Aug 2011 19:56:55 -0300 Subject: [media] sn9c20x: Use current logging styles Add pr_fmt. Convert usb style logging macros to pr_. Signed-off-by: Joe Perches Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c index c431900..9b3a052 100644 --- a/drivers/media/video/gspca/sn9c20x.c +++ b/drivers/media/video/gspca/sn9c20x.c @@ -18,6 +18,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include "gspca.h" @@ -1123,7 +1125,7 @@ static int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length) length, 500); if (unlikely(result < 0 || result != length)) { - err("Read register failed 0x%02X", reg); + pr_err("Read register failed 0x%02X\n", reg); return -EIO; } return 0; @@ -1144,7 +1146,7 @@ static int reg_w(struct gspca_dev *gspca_dev, u16 reg, length, 500); if (unlikely(result < 0 || result != length)) { - err("Write register failed index 0x%02X", reg); + pr_err("Write register failed index 0x%02X\n", reg); return -EIO; } return 0; @@ -1275,14 +1277,14 @@ static int ov9650_init_sensor(struct gspca_dev *gspca_dev) return -EINVAL; if (id != 0x7fa2) { - err("sensor id for ov9650 doesn't match (0x%04x)", id); + pr_err("sensor id for ov9650 doesn't match (0x%04x)\n", id); return -ENODEV; } for (i = 0; i < ARRAY_SIZE(ov9650_init); i++) { if (i2c_w1(gspca_dev, ov9650_init[i].reg, ov9650_init[i].val) < 0) { - err("OV9650 sensor initialization failed"); + pr_err("OV9650 sensor initialization failed\n"); return -ENODEV; } } @@ -1299,7 +1301,7 @@ static int ov9655_init_sensor(struct gspca_dev *gspca_dev) for (i = 0; i < ARRAY_SIZE(ov9655_init); i++) { if (i2c_w1(gspca_dev, ov9655_init[i].reg, ov9655_init[i].val) < 0) { - err("OV9655 sensor initialization failed"); + pr_err("OV9655 sensor initialization failed\n"); return -ENODEV; } } @@ -1318,7 +1320,7 @@ static int soi968_init_sensor(struct gspca_dev *gspca_dev) for (i = 0; i < ARRAY_SIZE(soi968_init); i++) { if (i2c_w1(gspca_dev, soi968_init[i].reg, soi968_init[i].val) < 0) { - err("SOI968 sensor initialization failed"); + pr_err("SOI968 sensor initialization failed\n"); return -ENODEV; } } @@ -1338,7 +1340,7 @@ static int ov7660_init_sensor(struct gspca_dev *gspca_dev) for (i = 0; i < ARRAY_SIZE(ov7660_init); i++) { if (i2c_w1(gspca_dev, ov7660_init[i].reg, ov7660_init[i].val) < 0) { - err("OV7660 sensor initialization failed"); + pr_err("OV7660 sensor initialization failed\n"); return -ENODEV; } } @@ -1355,7 +1357,7 @@ static int ov7670_init_sensor(struct gspca_dev *gspca_dev) for (i = 0; i < ARRAY_SIZE(ov7670_init); i++) { if (i2c_w1(gspca_dev, ov7670_init[i].reg, ov7670_init[i].val) < 0) { - err("OV7670 sensor initialization failed"); + pr_err("OV7670 sensor initialization failed\n"); return -ENODEV; } } @@ -1379,14 +1381,14 @@ static int mt9v_init_sensor(struct gspca_dev *gspca_dev) for (i = 0; i < ARRAY_SIZE(mt9v011_init); i++) { if (i2c_w2(gspca_dev, mt9v011_init[i].reg, mt9v011_init[i].val) < 0) { - err("MT9V011 sensor initialization failed"); + pr_err("MT9V011 sensor initialization failed\n"); return -ENODEV; } } sd->hstart = 2; sd->vstart = 2; sd->sensor = SENSOR_MT9V011; - info("MT9V011 sensor detected"); + pr_info("MT9V011 sensor detected\n"); return 0; } @@ -1397,7 +1399,7 @@ static int mt9v_init_sensor(struct gspca_dev *gspca_dev) for (i = 0; i < ARRAY_SIZE(mt9v111_init); i++) { if (i2c_w2(gspca_dev, mt9v111_init[i].reg, mt9v111_init[i].val) < 0) { - err("MT9V111 sensor initialization failed"); + pr_err("MT9V111 sensor initialization failed\n"); return -ENODEV; } } @@ -1407,7 +1409,7 @@ static int mt9v_init_sensor(struct gspca_dev *gspca_dev) sd->hstart = 2; sd->vstart = 2; sd->sensor = SENSOR_MT9V111; - info("MT9V111 sensor detected"); + pr_info("MT9V111 sensor detected\n"); return 0; } @@ -1422,14 +1424,14 @@ static int mt9v_init_sensor(struct gspca_dev *gspca_dev) for (i = 0; i < ARRAY_SIZE(mt9v112_init); i++) { if (i2c_w2(gspca_dev, mt9v112_init[i].reg, mt9v112_init[i].val) < 0) { - err("MT9V112 sensor initialization failed"); + pr_err("MT9V112 sensor initialization failed\n"); return -ENODEV; } } sd->hstart = 6; sd->vstart = 2; sd->sensor = SENSOR_MT9V112; - info("MT9V112 sensor detected"); + pr_info("MT9V112 sensor detected\n"); return 0; } @@ -1443,7 +1445,7 @@ static int mt9m112_init_sensor(struct gspca_dev *gspca_dev) for (i = 0; i < ARRAY_SIZE(mt9m112_init); i++) { if (i2c_w2(gspca_dev, mt9m112_init[i].reg, mt9m112_init[i].val) < 0) { - err("MT9M112 sensor initialization failed"); + pr_err("MT9M112 sensor initialization failed\n"); return -ENODEV; } } @@ -1461,7 +1463,7 @@ static int mt9m111_init_sensor(struct gspca_dev *gspca_dev) for (i = 0; i < ARRAY_SIZE(mt9m111_init); i++) { if (i2c_w2(gspca_dev, mt9m111_init[i].reg, mt9m111_init[i].val) < 0) { - err("MT9M111 sensor initialization failed"); + pr_err("MT9M111 sensor initialization failed\n"); return -ENODEV; } } @@ -1485,20 +1487,20 @@ static int mt9m001_init_sensor(struct gspca_dev *gspca_dev) switch (id) { case 0x8411: case 0x8421: - info("MT9M001 color sensor detected"); + pr_info("MT9M001 color sensor detected\n"); break; case 0x8431: - info("MT9M001 mono sensor detected"); + pr_info("MT9M001 mono sensor detected\n"); break; default: - err("No MT9M001 chip detected, ID = %x\n", id); + pr_err("No MT9M001 chip detected, ID = %x\n\n", id); return -ENODEV; } for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) { if (i2c_w2(gspca_dev, mt9m001_init[i].reg, mt9m001_init[i].val) < 0) { - err("MT9M001 sensor initialization failed"); + pr_err("MT9M001 sensor initialization failed\n"); return -ENODEV; } } @@ -1517,7 +1519,7 @@ static int hv7131r_init_sensor(struct gspca_dev *gspca_dev) for (i = 0; i < ARRAY_SIZE(hv7131r_init); i++) { if (i2c_w1(gspca_dev, hv7131r_init[i].reg, hv7131r_init[i].val) < 0) { - err("HV7131R Sensor initialization failed"); + pr_err("HV7131R Sensor initialization failed\n"); return -ENODEV; } } @@ -2103,7 +2105,7 @@ static int sd_init(struct gspca_dev *gspca_dev) for (i = 0; i < ARRAY_SIZE(bridge_init); i++) { value = bridge_init[i][1]; if (reg_w(gspca_dev, bridge_init[i][0], &value, 1) < 0) { - err("Device initialization failed"); + pr_err("Device initialization failed\n"); return -ENODEV; } } @@ -2114,7 +2116,7 @@ static int sd_init(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, 0x1006, 0x20); if (reg_w(gspca_dev, 0x10c0, i2c_init, 9) < 0) { - err("Device initialization failed"); + pr_err("Device initialization failed\n"); return -ENODEV; } @@ -2122,27 +2124,27 @@ static int sd_init(struct gspca_dev *gspca_dev) case SENSOR_OV9650: if (ov9650_init_sensor(gspca_dev) < 0) return -ENODEV; - info("OV9650 sensor detected"); + pr_info("OV9650 sensor detected\n"); break; case SENSOR_OV9655: if (ov9655_init_sensor(gspca_dev) < 0) return -ENODEV; - info("OV9655 sensor detected"); + pr_info("OV9655 sensor detected\n"); break; case SENSOR_SOI968: if (soi968_init_sensor(gspca_dev) < 0) return -ENODEV; - info("SOI968 sensor detected"); + pr_info("SOI968 sensor detected\n"); break; case SENSOR_OV7660: if (ov7660_init_sensor(gspca_dev) < 0) return -ENODEV; - info("OV7660 sensor detected"); + pr_info("OV7660 sensor detected\n"); break; case SENSOR_OV7670: if (ov7670_init_sensor(gspca_dev) < 0) return -ENODEV; - info("OV7670 sensor detected"); + pr_info("OV7670 sensor detected\n"); break; case SENSOR_MT9VPRB: if (mt9v_init_sensor(gspca_dev) < 0) @@ -2151,12 +2153,12 @@ static int sd_init(struct gspca_dev *gspca_dev) case SENSOR_MT9M111: if (mt9m111_init_sensor(gspca_dev) < 0) return -ENODEV; - info("MT9M111 sensor detected"); + pr_info("MT9M111 sensor detected\n"); break; case SENSOR_MT9M112: if (mt9m112_init_sensor(gspca_dev) < 0) return -ENODEV; - info("MT9M112 sensor detected"); + pr_info("MT9M112 sensor detected\n"); break; case SENSOR_MT9M001: if (mt9m001_init_sensor(gspca_dev) < 0) @@ -2165,10 +2167,10 @@ static int sd_init(struct gspca_dev *gspca_dev) case SENSOR_HV7131R: if (hv7131r_init_sensor(gspca_dev) < 0) return -ENODEV; - info("HV7131R sensor detected"); + pr_info("HV7131R sensor detected\n"); break; default: - info("Unsupported Sensor"); + pr_info("Unsupported Sensor\n"); return -ENODEV; } @@ -2263,19 +2265,19 @@ static int sd_start(struct gspca_dev *gspca_dev) switch (mode & SCALE_MASK) { case SCALE_1280x1024: scale = 0xc0; - info("Set 1280x1024"); + pr_info("Set 1280x1024\n"); break; case SCALE_640x480: scale = 0x80; - info("Set 640x480"); + pr_info("Set 640x480\n"); break; case SCALE_320x240: scale = 0x90; - info("Set 320x240"); + pr_info("Set 320x240\n"); break; case SCALE_160x120: scale = 0xa0; - info("Set 160x120"); + pr_info("Set 160x120\n"); break; } -- cgit v0.10.2 From 1b19e42952963ae2a09a655f487de15b7c81c5b7 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 21 Aug 2011 19:56:56 -0300 Subject: [media] t613: Use current logging styles Add pr_fmt. Convert usb style logging macros to pr_. Signed-off-by: Joe Perches Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c index d1d733b..90f0877 100644 --- a/drivers/media/video/gspca/t613.c +++ b/drivers/media/video/gspca/t613.c @@ -26,6 +26,8 @@ * Costantino Leandro */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "t613" #include @@ -572,7 +574,7 @@ static void reg_w_buf(struct gspca_dev *gspca_dev, tmpbuf = kmemdup(buffer, len, GFP_KERNEL); if (!tmpbuf) { - err("Out of memory"); + pr_err("Out of memory\n"); return; } usb_control_msg(gspca_dev->dev, @@ -598,7 +600,7 @@ static void reg_w_ixbuf(struct gspca_dev *gspca_dev, } else { p = tmpbuf = kmalloc(len * 2, GFP_KERNEL); if (!tmpbuf) { - err("Out of memory"); + pr_err("Out of memory\n"); return; } } @@ -652,7 +654,7 @@ static void om6802_sensor_init(struct gspca_dev *gspca_dev) } byte = reg_r(gspca_dev, 0x0063); if (byte != 0x17) { - err("Bad sensor reset %02x", byte); + pr_err("Bad sensor reset %02x\n", byte); /* continue? */ } @@ -890,7 +892,7 @@ static int sd_init(struct gspca_dev *gspca_dev) sd->sensor = SENSOR_OM6802; break; default: - err("unknown sensor %04x", sensor_id); + pr_err("unknown sensor %04x\n", sensor_id); return -EINVAL; } @@ -905,7 +907,7 @@ static int sd_init(struct gspca_dev *gspca_dev) break; /* OK */ } if (i < 0) { - err("Bad sensor reset %02x", test_byte); + pr_err("Bad sensor reset %02x\n", test_byte); return -EIO; } reg_w_buf(gspca_dev, n2, sizeof n2); -- cgit v0.10.2 From 42f4e774a30d0e9894741b62af4174c73ecc53da Mon Sep 17 00:00:00 2001 From: Andreas Oberritter Date: Wed, 24 Aug 2011 14:33:52 -0300 Subject: [media] DVB: dvb_frontend: check function pointers on reinitialize Signed-off-by: Andreas Oberritter Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index a716627..4b05931 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -577,12 +577,10 @@ restart: if (fepriv->reinitialise) { dvb_frontend_init(fe); - if (fepriv->tone != -1) { + if (fe->ops.set_tone && fepriv->tone != -1) fe->ops.set_tone(fe, fepriv->tone); - } - if (fepriv->voltage != -1) { + if (fe->ops.set_voltage && fepriv->voltage != -1) fe->ops.set_voltage(fe, fepriv->voltage); - } fepriv->reinitialise = 0; } -- cgit v0.10.2 From 133a9fe949862d9ed8411fb423739f4cee08232d Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 21 Aug 2011 19:56:57 -0300 Subject: [media] gspca: Use current logging styles Add pr_fmt. Convert usb style logging macros to pr_. Remove now unused old usb style logging macros. Signed-off-by: Joe Perches Acked-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/benq.c b/drivers/media/video/gspca/benq.c index a09c470..f4357f7 100644 --- a/drivers/media/video/gspca/benq.c +++ b/drivers/media/video/gspca/benq.c @@ -18,6 +18,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "benq" #include "gspca.h" @@ -62,7 +64,7 @@ static void reg_w(struct gspca_dev *gspca_dev, 0, 500); if (ret < 0) { - err("reg_w err %d", ret); + pr_err("reg_w err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -91,7 +93,7 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev) ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, gspca_dev->nbalt - 1); if (ret < 0) { - err("usb_set_interface failed"); + pr_err("usb_set_interface failed\n"); return ret; } /* reg_w(gspca_dev, 0x0003, 0x0002); */ @@ -113,7 +115,7 @@ static int sd_start(struct gspca_dev *gspca_dev) for (n = 0; n < 4; n++) { urb = usb_alloc_urb(SD_NPKT, GFP_KERNEL); if (!urb) { - err("usb_alloc_urb failed"); + pr_err("usb_alloc_urb failed\n"); return -ENOMEM; } gspca_dev->urb[n] = urb; @@ -123,7 +125,7 @@ static int sd_start(struct gspca_dev *gspca_dev) &urb->transfer_dma); if (urb->transfer_buffer == NULL) { - err("usb_alloc_coherent failed"); + pr_err("usb_alloc_coherent failed\n"); return -ENOMEM; } urb->dev = gspca_dev->dev; @@ -181,7 +183,7 @@ static void sd_isoc_irq(struct urb *urb) if (gspca_dev->frozen) return; #endif - err("urb status: %d", urb->status); + pr_err("urb status: %d\n", urb->status); return; } @@ -209,7 +211,7 @@ static void sd_isoc_irq(struct urb *urb) if (st == 0) st = urb->iso_frame_desc[i].status; if (st) { - err("ISOC data error: [%d] status=%d", + pr_err("ISOC data error: [%d] status=%d\n", i, st); gspca_dev->last_packet_type = DISCARD_PACKET; continue; @@ -256,10 +258,10 @@ static void sd_isoc_irq(struct urb *urb) /* resubmit the URBs */ st = usb_submit_urb(urb0, GFP_ATOMIC); if (st < 0) - err("usb_submit_urb(0) ret %d", st); + pr_err("usb_submit_urb(0) ret %d\n", st); st = usb_submit_urb(urb, GFP_ATOMIC); if (st < 0) - err("usb_submit_urb() ret %d", st); + pr_err("usb_submit_urb() ret %d\n", st); } /* sub-driver description */ diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c index 8b39849..4c56dbe 100644 --- a/drivers/media/video/gspca/conex.c +++ b/drivers/media/video/gspca/conex.c @@ -19,6 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "conex" #include "gspca.h" @@ -129,7 +131,7 @@ static void reg_r(struct gspca_dev *gspca_dev, #ifdef GSPCA_DEBUG if (len > USB_BUF_SZ) { - err("reg_r: buffer overflow"); + pr_err("reg_r: buffer overflow\n"); return; } #endif @@ -169,7 +171,7 @@ static void reg_w(struct gspca_dev *gspca_dev, #ifdef GSPCA_DEBUG if (len > USB_BUF_SZ) { - err("reg_w: buffer overflow"); + pr_err("reg_w: buffer overflow\n"); return; } PDEBUG(D_USBO, "reg write [%02x] = %02x..", index, *buffer); diff --git a/drivers/media/video/gspca/cpia1.c b/drivers/media/video/gspca/cpia1.c index f2a9451..f9b86b2 100644 --- a/drivers/media/video/gspca/cpia1.c +++ b/drivers/media/video/gspca/cpia1.c @@ -26,6 +26,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "cpia1" #include @@ -550,8 +552,7 @@ retry: gspca_dev->usb_buf, databytes, 1000); if (ret < 0) - err("usb_control_msg %02x, error %d", command[1], - ret); + pr_err("usb_control_msg %02x, error %d\n", command[1], ret); if (ret == -EPIPE && retries > 0) { retries--; @@ -1279,7 +1280,7 @@ static void monitor_exposure(struct gspca_dev *gspca_dev) cmd[7] = 0; ret = cpia_usb_transferCmd(gspca_dev, cmd); if (ret) { - err("ReadVPRegs(30,4,9,8) - failed: %d", ret); + pr_err("ReadVPRegs(30,4,9,8) - failed: %d\n", ret); return; } exp_acc = gspca_dev->usb_buf[0]; diff --git a/drivers/media/video/gspca/etoms.c b/drivers/media/video/gspca/etoms.c index 4b2c483..0357d6d 100644 --- a/drivers/media/video/gspca/etoms.c +++ b/drivers/media/video/gspca/etoms.c @@ -18,6 +18,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "etoms" #include "gspca.h" @@ -236,7 +238,7 @@ static void reg_r(struct gspca_dev *gspca_dev, #ifdef GSPCA_DEBUG if (len > USB_BUF_SZ) { - err("reg_r: buffer overflow"); + pr_err("reg_r: buffer overflow\n"); return; } #endif @@ -274,7 +276,7 @@ static void reg_w(struct gspca_dev *gspca_dev, #ifdef GSPCA_DEBUG if (len > USB_BUF_SZ) { - err("reg_w: buffer overflow"); + pr_err("reg_w: buffer overflow\n"); return; } PDEBUG(D_USBO, "reg write [%02x] = %02x..", index, *buffer); diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 5da4879..a3c2d36 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -21,6 +21,8 @@ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "gspca" #include @@ -148,7 +150,7 @@ static void int_irq(struct urb *urb) if (ret == 0) { ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret < 0) - err("Resubmit URB failed with error %i", ret); + pr_err("Resubmit URB failed with error %i\n", ret); } } @@ -177,8 +179,8 @@ static int gspca_input_connect(struct gspca_dev *dev) err = input_register_device(input_dev); if (err) { - err("Input device registration failed with error %i", - err); + pr_err("Input device registration failed with error %i\n", + err); input_dev->dev.parent = NULL; input_free_device(input_dev); } else { @@ -323,8 +325,8 @@ static void fill_frame(struct gspca_dev *gspca_dev, /* check the packet status and length */ st = urb->iso_frame_desc[i].status; if (st) { - err("ISOC data error: [%d] len=%d, status=%d", - i, len, st); + pr_err("ISOC data error: [%d] len=%d, status=%d\n", + i, len, st); gspca_dev->last_packet_type = DISCARD_PACKET; continue; } @@ -346,7 +348,7 @@ resubmit: /* resubmit the URB */ st = usb_submit_urb(urb, GFP_ATOMIC); if (st < 0) - err("usb_submit_urb() ret %d", st); + pr_err("usb_submit_urb() ret %d\n", st); } /* @@ -400,7 +402,7 @@ resubmit: if (gspca_dev->cam.bulk_nurbs != 0) { st = usb_submit_urb(urb, GFP_ATOMIC); if (st < 0) - err("usb_submit_urb() ret %d", st); + pr_err("usb_submit_urb() ret %d\n", st); } } @@ -464,7 +466,7 @@ void gspca_frame_add(struct gspca_dev *gspca_dev, } else { /* !! image is NULL only when last pkt is LAST or DISCARD if (gspca_dev->image == NULL) { - err("gspca_frame_add() image == NULL"); + pr_err("gspca_frame_add() image == NULL\n"); return; } */ @@ -525,7 +527,7 @@ static int frame_alloc(struct gspca_dev *gspca_dev, struct file *file, count = GSPCA_MAX_FRAMES - 1; gspca_dev->frbuf = vmalloc_32(frsz * count); if (!gspca_dev->frbuf) { - err("frame alloc failed"); + pr_err("frame alloc failed\n"); return -ENOMEM; } gspca_dev->capt_file = file; @@ -597,7 +599,7 @@ static int gspca_set_alt0(struct gspca_dev *gspca_dev) return 0; ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0); if (ret < 0) - err("set alt 0 err %d", ret); + pr_err("set alt 0 err %d\n", ret); return ret; } @@ -673,7 +675,7 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev) } } if (ep == NULL) { - err("no transfer endpoint found"); + pr_err("no transfer endpoint found\n"); return NULL; } PDEBUG(D_STREAM, "use alt %d ep 0x%02x", @@ -682,7 +684,7 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev) if (gspca_dev->nbalt > 1) { ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i); if (ret < 0) { - err("set alt %d err %d", i, ret); + pr_err("set alt %d err %d\n", i, ret); ep = NULL; } } @@ -731,7 +733,7 @@ static int create_urbs(struct gspca_dev *gspca_dev, for (n = 0; n < nurbs; n++) { urb = usb_alloc_urb(npkt, GFP_KERNEL); if (!urb) { - err("usb_alloc_urb failed"); + pr_err("usb_alloc_urb failed\n"); return -ENOMEM; } gspca_dev->urb[n] = urb; @@ -741,7 +743,7 @@ static int create_urbs(struct gspca_dev *gspca_dev, &urb->transfer_dma); if (urb->transfer_buffer == NULL) { - err("usb_alloc_coherent failed"); + pr_err("usb_alloc_coherent failed\n"); return -ENOMEM; } urb->dev = gspca_dev->dev; @@ -854,8 +856,8 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) break; gspca_stream_off(gspca_dev); if (ret != -ENOSPC) { - err("usb_submit_urb alt %d err %d", - gspca_dev->alt, ret); + pr_err("usb_submit_urb alt %d err %d\n", + gspca_dev->alt, ret); goto out; } @@ -2202,12 +2204,12 @@ int gspca_dev_probe2(struct usb_interface *intf, dev_size = sizeof *gspca_dev; gspca_dev = kzalloc(dev_size, GFP_KERNEL); if (!gspca_dev) { - err("couldn't kzalloc gspca struct"); + pr_err("couldn't kzalloc gspca struct\n"); return -ENOMEM; } gspca_dev->usb_buf = kmalloc(USB_BUF_SZ, GFP_KERNEL); if (!gspca_dev->usb_buf) { - err("out of memory"); + pr_err("out of memory\n"); ret = -ENOMEM; goto out; } @@ -2264,7 +2266,7 @@ int gspca_dev_probe2(struct usb_interface *intf, VFL_TYPE_GRABBER, -1); if (ret < 0) { - err("video_register_device err %d", ret); + pr_err("video_register_device err %d\n", ret); goto out; } @@ -2296,8 +2298,8 @@ int gspca_dev_probe(struct usb_interface *intf, /* we don't handle multi-config cameras */ if (dev->descriptor.bNumConfigurations != 1) { - err("%04x:%04x too many config", - id->idVendor, id->idProduct); + pr_err("%04x:%04x too many config\n", + id->idVendor, id->idProduct); return -ENODEV; } @@ -2480,7 +2482,7 @@ EXPORT_SYMBOL(gspca_auto_gain_n_exposure); /* -- module insert / remove -- */ static int __init gspca_init(void) { - info("v" DRIVER_VERSION_NUMBER " registered"); + pr_info("v" DRIVER_VERSION_NUMBER " registered\n"); return 0; } static void __exit gspca_exit(void) diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h index 49e2fcb..e444f16 100644 --- a/drivers/media/video/gspca/gspca.h +++ b/drivers/media/video/gspca/gspca.h @@ -14,11 +14,12 @@ #ifdef GSPCA_DEBUG /* GSPCA our debug messages */ extern int gspca_debug; -#define PDEBUG(level, fmt, args...) \ - do {\ - if (gspca_debug & (level)) \ - printk(KERN_INFO MODULE_NAME ": " fmt "\n", ## args); \ - } while (0) +#define PDEBUG(level, fmt, ...) \ +do { \ + if (gspca_debug & (level)) \ + pr_info(fmt, ##__VA_ARGS__); \ +} while (0) + #define D_ERR 0x01 #define D_PROBE 0x02 #define D_CONF 0x04 @@ -29,17 +30,8 @@ extern int gspca_debug; #define D_USBO 0x00 #define D_V4L2 0x0100 #else -#define PDEBUG(level, fmt, args...) +#define PDEBUG(level, fmt, ...) #endif -#undef err -#define err(fmt, args...) \ - printk(KERN_ERR MODULE_NAME ": " fmt "\n", ## args) -#undef info -#define info(fmt, args...) \ - printk(KERN_INFO MODULE_NAME ": " fmt "\n", ## args) -#undef warn -#define warn(fmt, args...) \ - printk(KERN_WARNING MODULE_NAME ": " fmt "\n", ## args) #define GSPCA_MAX_FRAMES 16 /* maximum number of video frame buffers */ /* image transfers */ diff --git a/drivers/media/video/gspca/jeilinj.c b/drivers/media/video/gspca/jeilinj.c index 1bd9c4b..4ccc08d 100644 --- a/drivers/media/video/gspca/jeilinj.c +++ b/drivers/media/video/gspca/jeilinj.c @@ -24,6 +24,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "jeilinj" #include @@ -113,8 +115,8 @@ static void jlj_write2(struct gspca_dev *gspca_dev, unsigned char *command) usb_sndbulkpipe(gspca_dev->dev, 3), gspca_dev->usb_buf, 2, NULL, 500); if (retval < 0) { - err("command write [%02x] error %d", - gspca_dev->usb_buf[0], retval); + pr_err("command write [%02x] error %d\n", + gspca_dev->usb_buf[0], retval); gspca_dev->usb_err = retval; } } @@ -131,8 +133,8 @@ static void jlj_read1(struct gspca_dev *gspca_dev, unsigned char response) gspca_dev->usb_buf, 1, NULL, 500); response = gspca_dev->usb_buf[0]; if (retval < 0) { - err("read command [%02x] error %d", - gspca_dev->usb_buf[0], retval); + pr_err("read command [%02x] error %d\n", + gspca_dev->usb_buf[0], retval); gspca_dev->usb_err = retval; } } diff --git a/drivers/media/video/gspca/kinect.c b/drivers/media/video/gspca/kinect.c index 26fc206..9ed15a1 100644 --- a/drivers/media/video/gspca/kinect.c +++ b/drivers/media/video/gspca/kinect.c @@ -24,6 +24,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "kinect" #include "gspca.h" @@ -141,7 +143,7 @@ static int send_cmd(struct gspca_dev *gspca_dev, uint16_t cmd, void *cmdbuf, struct cam_hdr *rhdr = (void *)ibuf; if (cmd_len & 1 || cmd_len > (0x400 - sizeof(*chdr))) { - err("send_cmd: Invalid command length (0x%x)", cmd_len); + pr_err("send_cmd: Invalid command length (0x%x)\n", cmd_len); return -1; } @@ -157,7 +159,7 @@ static int send_cmd(struct gspca_dev *gspca_dev, uint16_t cmd, void *cmdbuf, PDEBUG(D_USBO, "Control cmd=%04x tag=%04x len=%04x: %d", cmd, sd->cam_tag, cmd_len, res); if (res < 0) { - err("send_cmd: Output control transfer failed (%d)", res); + pr_err("send_cmd: Output control transfer failed (%d)\n", res); return res; } @@ -166,33 +168,35 @@ static int send_cmd(struct gspca_dev *gspca_dev, uint16_t cmd, void *cmdbuf, } while (actual_len == 0); PDEBUG(D_USBO, "Control reply: %d", res); if (actual_len < sizeof(*rhdr)) { - err("send_cmd: Input control transfer failed (%d)", res); + pr_err("send_cmd: Input control transfer failed (%d)\n", res); return res; } actual_len -= sizeof(*rhdr); if (rhdr->magic[0] != 0x52 || rhdr->magic[1] != 0x42) { - err("send_cmd: Bad magic %02x %02x", rhdr->magic[0], - rhdr->magic[1]); + pr_err("send_cmd: Bad magic %02x %02x\n", + rhdr->magic[0], rhdr->magic[1]); return -1; } if (rhdr->cmd != chdr->cmd) { - err("send_cmd: Bad cmd %02x != %02x", rhdr->cmd, chdr->cmd); + pr_err("send_cmd: Bad cmd %02x != %02x\n", + rhdr->cmd, chdr->cmd); return -1; } if (rhdr->tag != chdr->tag) { - err("send_cmd: Bad tag %04x != %04x", rhdr->tag, chdr->tag); + pr_err("send_cmd: Bad tag %04x != %04x\n", + rhdr->tag, chdr->tag); return -1; } if (cpu_to_le16(rhdr->len) != (actual_len/2)) { - err("send_cmd: Bad len %04x != %04x", - cpu_to_le16(rhdr->len), (int)(actual_len/2)); + pr_err("send_cmd: Bad len %04x != %04x\n", + cpu_to_le16(rhdr->len), (int)(actual_len/2)); return -1; } if (actual_len > reply_len) { - warn("send_cmd: Data buffer is %d bytes long, but got %d bytes", - reply_len, actual_len); + pr_warn("send_cmd: Data buffer is %d bytes long, but got %d bytes\n", + reply_len, actual_len); memcpy(replybuf, ibuf+sizeof(*rhdr), reply_len); } else { memcpy(replybuf, ibuf+sizeof(*rhdr), actual_len); @@ -218,8 +222,8 @@ static int write_register(struct gspca_dev *gspca_dev, uint16_t reg, if (res < 0) return res; if (res != 2) { - warn("send_cmd returned %d [%04x %04x], 0000 expected", - res, reply[0], reply[1]); + pr_warn("send_cmd returned %d [%04x %04x], 0000 expected\n", + res, reply[0], reply[1]); } return 0; } @@ -353,8 +357,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *__data, int len) return; if (hdr->magic[0] != 'R' || hdr->magic[1] != 'B') { - warn("[Stream %02x] Invalid magic %02x%02x", sd->stream_flag, - hdr->magic[0], hdr->magic[1]); + pr_warn("[Stream %02x] Invalid magic %02x%02x\n", + sd->stream_flag, hdr->magic[0], hdr->magic[1]); return; } @@ -368,7 +372,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *__data, int len) gspca_frame_add(gspca_dev, LAST_PACKET, data, datalen); else - warn("Packet type not recognized..."); + pr_warn("Packet type not recognized...\n"); } /* sub-driver description */ diff --git a/drivers/media/video/gspca/konica.c b/drivers/media/video/gspca/konica.c index 5964691..f3f7fe0 100644 --- a/drivers/media/video/gspca/konica.c +++ b/drivers/media/video/gspca/konica.c @@ -28,6 +28,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "konica" #include @@ -200,7 +202,7 @@ static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index) 0, 1000); if (ret < 0) { - err("reg_w err %d", ret); + pr_err("reg_w err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -221,7 +223,7 @@ static void reg_r(struct gspca_dev *gspca_dev, u16 value, u16 index) 2, 1000); if (ret < 0) { - err("reg_w err %d", ret); + pr_err("reg_w err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -284,7 +286,7 @@ static int sd_start(struct gspca_dev *gspca_dev) intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); if (!alt) { - err("Couldn't get altsetting"); + pr_err("Couldn't get altsetting\n"); return -EIO; } @@ -315,7 +317,7 @@ static int sd_start(struct gspca_dev *gspca_dev) le16_to_cpu(alt->endpoint[i].desc.wMaxPacketSize); urb = usb_alloc_urb(SD_NPKT, GFP_KERNEL); if (!urb) { - err("usb_alloc_urb failed"); + pr_err("usb_alloc_urb failed\n"); return -ENOMEM; } gspca_dev->urb[n] = urb; @@ -324,7 +326,7 @@ static int sd_start(struct gspca_dev *gspca_dev) GFP_KERNEL, &urb->transfer_dma); if (urb->transfer_buffer == NULL) { - err("usb_buffer_alloc failed"); + pr_err("usb_buffer_alloc failed\n"); return -ENOMEM; } @@ -386,7 +388,7 @@ static void sd_isoc_irq(struct urb *urb) PDEBUG(D_ERR, "urb status: %d", urb->status); st = usb_submit_urb(urb, GFP_ATOMIC); if (st < 0) - err("resubmit urb error %d", st); + pr_err("resubmit urb error %d\n", st); return; } @@ -477,7 +479,7 @@ resubmit: } st = usb_submit_urb(status_urb, GFP_ATOMIC); if (st < 0) - err("usb_submit_urb(status_urb) ret %d", st); + pr_err("usb_submit_urb(status_urb) ret %d\n", st); } static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c index 0196209..ef45fa5 100644 --- a/drivers/media/video/gspca/mars.c +++ b/drivers/media/video/gspca/mars.c @@ -19,6 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "mars" #include "gspca.h" @@ -178,8 +180,8 @@ static void reg_w(struct gspca_dev *gspca_dev, &alen, 500); /* timeout in milliseconds */ if (ret < 0) { - err("reg write [%02x] error %d", - gspca_dev->usb_buf[0], ret); + pr_err("reg write [%02x] error %d\n", + gspca_dev->usb_buf[0], ret); gspca_dev->usb_err = ret; } } diff --git a/drivers/media/video/gspca/mr97310a.c b/drivers/media/video/gspca/mr97310a.c index 97e5079..473e813 100644 --- a/drivers/media/video/gspca/mr97310a.c +++ b/drivers/media/video/gspca/mr97310a.c @@ -40,6 +40,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "mr97310a" #include "gspca.h" @@ -267,7 +269,7 @@ static int mr_write(struct gspca_dev *gspca_dev, int len) usb_sndbulkpipe(gspca_dev->dev, 4), gspca_dev->usb_buf, len, NULL, 500); if (rc < 0) - err("reg write [%02x] error %d", + pr_err("reg write [%02x] error %d\n", gspca_dev->usb_buf[0], rc); return rc; } @@ -281,7 +283,7 @@ static int mr_read(struct gspca_dev *gspca_dev, int len) usb_rcvbulkpipe(gspca_dev->dev, 3), gspca_dev->usb_buf, len, NULL, 500); if (rc < 0) - err("reg read [%02x] error %d", + pr_err("reg read [%02x] error %d\n", gspca_dev->usb_buf[0], rc); return rc; } @@ -540,7 +542,7 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->sensor_type = 1; break; default: - err("Unknown CIF Sensor id : %02x", + pr_err("Unknown CIF Sensor id : %02x\n", gspca_dev->usb_buf[1]); return -ENODEV; } @@ -575,10 +577,10 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->sensor_type = 2; } else if ((gspca_dev->usb_buf[0] != 0x03) && (gspca_dev->usb_buf[0] != 0x04)) { - err("Unknown VGA Sensor id Byte 0: %02x", - gspca_dev->usb_buf[0]); - err("Defaults assumed, may not work"); - err("Please report this"); + pr_err("Unknown VGA Sensor id Byte 0: %02x\n", + gspca_dev->usb_buf[0]); + pr_err("Defaults assumed, may not work\n"); + pr_err("Please report this\n"); } /* Sakar Digital color needs to be adjusted. */ if ((gspca_dev->usb_buf[0] == 0x03) && @@ -595,10 +597,10 @@ static int sd_config(struct gspca_dev *gspca_dev, /* Nothing to do here. */ break; default: - err("Unknown VGA Sensor id Byte 1: %02x", - gspca_dev->usb_buf[1]); - err("Defaults assumed, may not work"); - err("Please report this"); + pr_err("Unknown VGA Sensor id Byte 1: %02x\n", + gspca_dev->usb_buf[1]); + pr_err("Defaults assumed, may not work\n"); + pr_err("Please report this\n"); } } PDEBUG(D_PROBE, "MR97310A VGA camera detected, sensor: %d", diff --git a/drivers/media/video/gspca/nw80x.c b/drivers/media/video/gspca/nw80x.c index 8e754fd..7681814 100644 --- a/drivers/media/video/gspca/nw80x.c +++ b/drivers/media/video/gspca/nw80x.c @@ -20,6 +20,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "nw80x" #include "gspca.h" @@ -1571,7 +1573,7 @@ static void reg_w(struct gspca_dev *gspca_dev, len, 500); if (ret < 0) { - err("reg_w err %d", ret); + pr_err("reg_w err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -1592,7 +1594,7 @@ static void reg_r(struct gspca_dev *gspca_dev, 0x00, index, gspca_dev->usb_buf, len, 500); if (ret < 0) { - err("reg_r err %d", ret); + pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; return; } @@ -1802,7 +1804,8 @@ static int sd_config(struct gspca_dev *gspca_dev, } } if (webcam_chip[sd->webcam] != sd->bridge) { - err("Bad webcam type %d for NW80%d", sd->webcam, sd->bridge); + pr_err("Bad webcam type %d for NW80%d\n", + sd->webcam, sd->bridge); gspca_dev->usb_err = -ENODEV; return gspca_dev->usb_err; } diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index 0800433..17d0d56 100644 --- a/drivers/media/video/gspca/ov519.c +++ b/drivers/media/video/gspca/ov519.c @@ -36,6 +36,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "ov519" #include @@ -2171,7 +2174,7 @@ static void reg_w(struct sd *sd, u16 index, u16 value) sd->gspca_dev.usb_buf, 1, 500); leave: if (ret < 0) { - err("reg_w %02x failed %d", index, ret); + pr_err("reg_w %02x failed %d\n", index, ret); sd->gspca_dev.usb_err = ret; return; } @@ -2210,7 +2213,7 @@ static int reg_r(struct sd *sd, u16 index) PDEBUG(D_USBI, "GET %02x 0000 %04x %02x", req, index, ret); } else { - err("reg_r %02x failed %d", index, ret); + pr_err("reg_r %02x failed %d\n", index, ret); sd->gspca_dev.usb_err = ret; } @@ -2235,7 +2238,7 @@ static int reg_r8(struct sd *sd, if (ret >= 0) { ret = sd->gspca_dev.usb_buf[0]; } else { - err("reg_r8 %02x failed %d", index, ret); + pr_err("reg_r8 %02x failed %d\n", index, ret); sd->gspca_dev.usb_err = ret; } @@ -2288,7 +2291,7 @@ static void ov518_reg_w32(struct sd *sd, u16 index, u32 value, int n) 0, index, sd->gspca_dev.usb_buf, n, 500); if (ret < 0) { - err("reg_w32 %02x failed %d", index, ret); + pr_err("reg_w32 %02x failed %d\n", index, ret); sd->gspca_dev.usb_err = ret; } } @@ -2457,7 +2460,7 @@ static void ovfx2_i2c_w(struct sd *sd, u8 reg, u8 value) (u16) value, (u16) reg, NULL, 0, 500); if (ret < 0) { - err("ovfx2_i2c_w %02x failed %d", reg, ret); + pr_err("ovfx2_i2c_w %02x failed %d\n", reg, ret); sd->gspca_dev.usb_err = ret; } @@ -2481,7 +2484,7 @@ static int ovfx2_i2c_r(struct sd *sd, u8 reg) ret = sd->gspca_dev.usb_buf[0]; PDEBUG(D_USBI, "ovfx2_i2c_r %02x %02x", reg, ret); } else { - err("ovfx2_i2c_r %02x failed %d", reg, ret); + pr_err("ovfx2_i2c_r %02x failed %d\n", reg, ret); sd->gspca_dev.usb_err = ret; } @@ -2727,7 +2730,7 @@ static void ov_hires_configure(struct sd *sd) int high, low; if (sd->bridge != BRIDGE_OVFX2) { - err("error hires sensors only supported with ovfx2"); + pr_err("error hires sensors only supported with ovfx2\n"); return; } @@ -2762,7 +2765,7 @@ static void ov_hires_configure(struct sd *sd) } break; } - err("Error unknown sensor type: %02x%02x", high, low); + pr_err("Error unknown sensor type: %02x%02x\n", high, low); } /* This initializes the OV8110, OV8610 sensor. The OV8110 uses @@ -2783,7 +2786,7 @@ static void ov8xx0_configure(struct sd *sd) if ((rc & 3) == 1) sd->sensor = SEN_OV8610; else - err("Unknown image sensor version: %d", rc & 3); + pr_err("Unknown image sensor version: %d\n", rc & 3); } /* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses @@ -2840,8 +2843,8 @@ static void ov7xx0_configure(struct sd *sd) if (high == 0x76) { switch (low) { case 0x30: - err("Sensor is an OV7630/OV7635"); - err("7630 is not supported by this driver"); + pr_err("Sensor is an OV7630/OV7635\n"); + pr_err("7630 is not supported by this driver\n"); return; case 0x40: PDEBUG(D_PROBE, "Sensor is an OV7645"); @@ -2869,7 +2872,7 @@ static void ov7xx0_configure(struct sd *sd) sd->sensor = SEN_OV7620; } } else { - err("Unknown image sensor version: %d", rc & 3); + pr_err("Unknown image sensor version: %d\n", rc & 3); } } @@ -2892,8 +2895,7 @@ static void ov6xx0_configure(struct sd *sd) switch (rc) { case 0x00: sd->sensor = SEN_OV6630; - warn("WARNING: Sensor is an OV66308. Your camera may have"); - warn("been misdetected in previous driver versions."); + pr_warn("WARNING: Sensor is an OV66308. Your camera may have been misdetected in previous driver versions.\n"); break; case 0x01: sd->sensor = SEN_OV6620; @@ -2909,11 +2911,10 @@ static void ov6xx0_configure(struct sd *sd) break; case 0x90: sd->sensor = SEN_OV6630; - warn("WARNING: Sensor is an OV66307. Your camera may have"); - warn("been misdetected in previous driver versions."); + pr_warn("WARNING: Sensor is an OV66307. Your camera may have been misdetected in previous driver versions.\n"); break; default: - err("FATAL: Unknown sensor version: 0x%02x", rc); + pr_err("FATAL: Unknown sensor version: 0x%02x\n", rc); return; } @@ -3407,7 +3408,7 @@ static int sd_init(struct gspca_dev *gspca_dev) } else if (init_ov_sensor(sd, OV_HIRES_SID) >= 0) { ov_hires_configure(sd); } else { - err("Can't determine sensor slave IDs"); + pr_err("Can't determine sensor slave IDs\n"); goto error; } @@ -3592,7 +3593,7 @@ static void ov511_mode_init_regs(struct sd *sd) intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); if (!alt) { - err("Couldn't get altsetting"); + pr_err("Couldn't get altsetting\n"); sd->gspca_dev.usb_err = -EIO; return; } @@ -3715,7 +3716,7 @@ static void ov518_mode_init_regs(struct sd *sd) intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); if (!alt) { - err("Couldn't get altsetting"); + pr_err("Couldn't get altsetting\n"); sd->gspca_dev.usb_err = -EIO; return; } diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c index 0c6369b..76907ec 100644 --- a/drivers/media/video/gspca/ov534.c +++ b/drivers/media/video/gspca/ov534.c @@ -28,6 +28,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "ov534" #include "gspca.h" @@ -775,7 +777,7 @@ static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val) USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT); if (ret < 0) { - err("write failed %d", ret); + pr_err("write failed %d\n", ret); gspca_dev->usb_err = ret; } } @@ -794,7 +796,7 @@ static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg) 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT); PDEBUG(D_USBI, "GET 01 0000 %04x %02x", reg, gspca_dev->usb_buf[0]); if (ret < 0) { - err("read failed %d", ret); + pr_err("read failed %d\n", ret); gspca_dev->usb_err = ret; } return gspca_dev->usb_buf[0]; @@ -858,7 +860,7 @@ static void sccb_reg_write(struct gspca_dev *gspca_dev, u8 reg, u8 val) ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3); if (!sccb_check_status(gspca_dev)) { - err("sccb_reg_write failed"); + pr_err("sccb_reg_write failed\n"); gspca_dev->usb_err = -EIO; } } @@ -868,11 +870,11 @@ static u8 sccb_reg_read(struct gspca_dev *gspca_dev, u16 reg) ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg); ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2); if (!sccb_check_status(gspca_dev)) - err("sccb_reg_read failed 1"); + pr_err("sccb_reg_read failed 1\n"); ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2); if (!sccb_check_status(gspca_dev)) - err("sccb_reg_read failed 2"); + pr_err("sccb_reg_read failed 2\n"); return ov534_reg_read(gspca_dev, OV534_REG_READ); } diff --git a/drivers/media/video/gspca/ov534_9.c b/drivers/media/video/gspca/ov534_9.c index aaf5428..a954a31 100644 --- a/drivers/media/video/gspca/ov534_9.c +++ b/drivers/media/video/gspca/ov534_9.c @@ -24,6 +24,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "ov534_9" #include "gspca.h" @@ -785,7 +787,7 @@ static void reg_w_i(struct gspca_dev *gspca_dev, u16 reg, u8 val) USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT); if (ret < 0) { - err("reg_w failed %d", ret); + pr_err("reg_w failed %d\n", ret); gspca_dev->usb_err = ret; } } @@ -810,7 +812,7 @@ static u8 reg_r(struct gspca_dev *gspca_dev, u16 reg) 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT); PDEBUG(D_USBI, "reg_r [%04x] -> %02x", reg, gspca_dev->usb_buf[0]); if (ret < 0) { - err("reg_r err %d", ret); + pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; } return gspca_dev->usb_buf[0]; @@ -848,7 +850,7 @@ static void sccb_write(struct gspca_dev *gspca_dev, u8 reg, u8 val) reg_w_i(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3); if (!sccb_check_status(gspca_dev)) - err("sccb_write failed"); + pr_err("sccb_write failed\n"); } static u8 sccb_read(struct gspca_dev *gspca_dev, u16 reg) @@ -856,11 +858,11 @@ static u8 sccb_read(struct gspca_dev *gspca_dev, u16 reg) reg_w(gspca_dev, OV534_REG_SUBADDR, reg); reg_w(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2); if (!sccb_check_status(gspca_dev)) - err("sccb_read failed 1"); + pr_err("sccb_read failed 1\n"); reg_w(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2); if (!sccb_check_status(gspca_dev)) - err("sccb_read failed 2"); + pr_err("sccb_read failed 2\n"); return reg_r(gspca_dev, OV534_REG_READ); } diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c index 5615d7b..1c44f78 100644 --- a/drivers/media/video/gspca/pac7302.c +++ b/drivers/media/video/gspca/pac7302.c @@ -61,6 +61,8 @@ 3 | 0x21 | sethvflip() */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "pac7302" #include @@ -408,8 +410,8 @@ static void reg_w_buf(struct gspca_dev *gspca_dev, index, gspca_dev->usb_buf, len, 500); if (ret < 0) { - err("reg_w_buf failed index 0x%02x, error %d", - index, ret); + pr_err("reg_w_buf failed index 0x%02x, error %d\n", + index, ret); gspca_dev->usb_err = ret; } } @@ -431,8 +433,8 @@ static void reg_w(struct gspca_dev *gspca_dev, 0, index, gspca_dev->usb_buf, 1, 500); if (ret < 0) { - err("reg_w() failed index 0x%02x, value 0x%02x, error %d", - index, value, ret); + pr_err("reg_w() failed index 0x%02x, value 0x%02x, error %d\n", + index, value, ret); gspca_dev->usb_err = ret; } } @@ -466,9 +468,8 @@ static void reg_w_page(struct gspca_dev *gspca_dev, 0, index, gspca_dev->usb_buf, 1, 500); if (ret < 0) { - err("reg_w_page() failed index 0x%02x, " - "value 0x%02x, error %d", - index, page[index], ret); + pr_err("reg_w_page() failed index 0x%02x, value 0x%02x, error %d\n", + index, page[index], ret); gspca_dev->usb_err = ret; break; } diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c index f8801b5..7509d05 100644 --- a/drivers/media/video/gspca/pac7311.c +++ b/drivers/media/video/gspca/pac7311.c @@ -49,6 +49,8 @@ for max gain, 0x14 for minimal gain. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "pac7311" #include @@ -276,8 +278,8 @@ static void reg_w_buf(struct gspca_dev *gspca_dev, index, gspca_dev->usb_buf, len, 500); if (ret < 0) { - err("reg_w_buf() failed index 0x%02x, error %d", - index, ret); + pr_err("reg_w_buf() failed index 0x%02x, error %d\n", + index, ret); gspca_dev->usb_err = ret; } } @@ -299,8 +301,8 @@ static void reg_w(struct gspca_dev *gspca_dev, 0, index, gspca_dev->usb_buf, 1, 500); if (ret < 0) { - err("reg_w() failed index 0x%02x, value 0x%02x, error %d", - index, value, ret); + pr_err("reg_w() failed index 0x%02x, value 0x%02x, error %d\n", + index, value, ret); gspca_dev->usb_err = ret; } } @@ -334,9 +336,8 @@ static void reg_w_page(struct gspca_dev *gspca_dev, 0, index, gspca_dev->usb_buf, 1, 500); if (ret < 0) { - err("reg_w_page() failed index 0x%02x, " - "value 0x%02x, error %d", - index, page[index], ret); + pr_err("reg_w_page() failed index 0x%02x, value 0x%02x, error %d\n", + index, page[index], ret); gspca_dev->usb_err = ret; break; } diff --git a/drivers/media/video/gspca/se401.c b/drivers/media/video/gspca/se401.c index 4c283c2..3b71bbc 100644 --- a/drivers/media/video/gspca/se401.c +++ b/drivers/media/video/gspca/se401.c @@ -23,6 +23,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "se401" #define BULK_SIZE 4096 @@ -144,8 +146,8 @@ static void se401_write_req(struct gspca_dev *gspca_dev, u16 req, u16 value, value, 0, NULL, 0, 1000); if (err < 0) { if (!silent) - err("write req failed req %#04x val %#04x error %d", - req, value, err); + pr_err("write req failed req %#04x val %#04x error %d\n", + req, value, err); gspca_dev->usb_err = err; } } @@ -158,7 +160,7 @@ static void se401_read_req(struct gspca_dev *gspca_dev, u16 req, int silent) return; if (USB_BUF_SZ < READ_REQ_SIZE) { - err("USB_BUF_SZ too small!!"); + pr_err("USB_BUF_SZ too small!!\n"); gspca_dev->usb_err = -ENOBUFS; return; } @@ -169,7 +171,8 @@ static void se401_read_req(struct gspca_dev *gspca_dev, u16 req, int silent) 0, 0, gspca_dev->usb_buf, READ_REQ_SIZE, 1000); if (err < 0) { if (!silent) - err("read req failed req %#04x error %d", req, err); + pr_err("read req failed req %#04x error %d\n", + req, err); gspca_dev->usb_err = err; } } @@ -188,8 +191,8 @@ static void se401_set_feature(struct gspca_dev *gspca_dev, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, param, selector, NULL, 0, 1000); if (err < 0) { - err("set feature failed sel %#04x param %#04x error %d", - selector, param, err); + pr_err("set feature failed sel %#04x param %#04x error %d\n", + selector, param, err); gspca_dev->usb_err = err; } } @@ -202,7 +205,7 @@ static int se401_get_feature(struct gspca_dev *gspca_dev, u16 selector) return gspca_dev->usb_err; if (USB_BUF_SZ < 2) { - err("USB_BUF_SZ too small!!"); + pr_err("USB_BUF_SZ too small!!\n"); gspca_dev->usb_err = -ENOBUFS; return gspca_dev->usb_err; } @@ -213,7 +216,8 @@ static int se401_get_feature(struct gspca_dev *gspca_dev, u16 selector) USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, selector, gspca_dev->usb_buf, 2, 1000); if (err < 0) { - err("get feature failed sel %#04x error %d", selector, err); + pr_err("get feature failed sel %#04x error %d\n", + selector, err); gspca_dev->usb_err = err; return err; } @@ -300,21 +304,21 @@ static int sd_config(struct gspca_dev *gspca_dev, return gspca_dev->usb_err; if (cd[1] != 0x41) { - err("Wrong descriptor type"); + pr_err("Wrong descriptor type\n"); return -ENODEV; } if (!(cd[2] & SE401_FORMAT_BAYER)) { - err("Bayer format not supported!"); + pr_err("Bayer format not supported!\n"); return -ENODEV; } if (cd[3]) - info("ExtraFeatures: %d", cd[3]); + pr_info("ExtraFeatures: %d\n", cd[3]); n = cd[4] | (cd[5] << 8); if (n > MAX_MODES) { - err("Too many frame sizes"); + pr_err("Too many frame sizes\n"); return -ENODEV; } @@ -353,15 +357,16 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->fmts[i].pixelformat = V4L2_PIX_FMT_SBGGR8; sd->fmts[i].bytesperline = widths[i]; sd->fmts[i].sizeimage = widths[i] * heights[i]; - info("Frame size: %dx%d bayer", widths[i], heights[i]); + pr_info("Frame size: %dx%d bayer\n", + widths[i], heights[i]); } else { /* Found a match use janggu compression */ sd->fmts[i].pixelformat = V4L2_PIX_FMT_SE401; sd->fmts[i].bytesperline = 0; sd->fmts[i].sizeimage = widths[i] * heights[i] * 3; - info("Frame size: %dx%d 1/%dth janggu", - widths[i], heights[i], - sd->fmts[i].priv * sd->fmts[i].priv); + pr_info("Frame size: %dx%d 1/%dth janggu\n", + widths[i], heights[i], + sd->fmts[i].priv * sd->fmts[i].priv); } } @@ -571,11 +576,12 @@ static void sd_pkt_scan_janggu(struct gspca_dev *gspca_dev, u8 *data, int len) plen = ((bits + 47) >> 4) << 1; /* Sanity checks */ if (plen > 1024) { - err("invalid packet len %d restarting stream", plen); + pr_err("invalid packet len %d restarting stream\n", + plen); goto error; } if (info == 3) { - err("unknown frame info value restarting stream"); + pr_err("unknown frame info value restarting stream\n"); goto error; } @@ -599,8 +605,8 @@ static void sd_pkt_scan_janggu(struct gspca_dev *gspca_dev, u8 *data, int len) break; case 1: /* EOF */ if (sd->pixels_read != imagesize) { - err("frame size %d expected %d", - sd->pixels_read, imagesize); + pr_err("frame size %d expected %d\n", + sd->pixels_read, imagesize); goto error; } sd_complete_frame(gspca_dev, sd->packet, plen); diff --git a/drivers/media/video/gspca/sn9c2028.c b/drivers/media/video/gspca/sn9c2028.c index 4271f86..48aae39 100644 --- a/drivers/media/video/gspca/sn9c2028.c +++ b/drivers/media/video/gspca/sn9c2028.c @@ -18,6 +18,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "sn9c2028" #include "gspca.h" @@ -75,8 +77,8 @@ static int sn9c2028_command(struct gspca_dev *gspca_dev, u8 *command) USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, 2, 0, gspca_dev->usb_buf, 6, 500); if (rc < 0) { - err("command write [%02x] error %d", - gspca_dev->usb_buf[0], rc); + pr_err("command write [%02x] error %d\n", + gspca_dev->usb_buf[0], rc); return rc; } @@ -93,7 +95,7 @@ static int sn9c2028_read1(struct gspca_dev *gspca_dev) USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, 1, 0, gspca_dev->usb_buf, 1, 500); if (rc != 1) { - err("read1 error %d", rc); + pr_err("read1 error %d\n", rc); return (rc < 0) ? rc : -EIO; } PDEBUG(D_USBI, "read1 response %02x", gspca_dev->usb_buf[0]); @@ -109,7 +111,7 @@ static int sn9c2028_read4(struct gspca_dev *gspca_dev, u8 *reading) USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, 4, 0, gspca_dev->usb_buf, 4, 500); if (rc != 4) { - err("read4 error %d", rc); + pr_err("read4 error %d\n", rc); return (rc < 0) ? rc : -EIO; } memcpy(reading, gspca_dev->usb_buf, 4); @@ -131,7 +133,7 @@ static int sn9c2028_long_command(struct gspca_dev *gspca_dev, u8 *command) for (i = 0; i < 256 && status < 2; i++) status = sn9c2028_read1(gspca_dev); if (status != 2) { - err("long command status read error %d", status); + pr_err("long command status read error %d\n", status); return (status < 0) ? status : -EIO; } @@ -638,7 +640,7 @@ static int sd_start(struct gspca_dev *gspca_dev) err_code = start_vivitar_cam(gspca_dev); break; default: - err("Starting unknown camera, please report this"); + pr_err("Starting unknown camera, please report this\n"); return -ENXIO; } diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 2ad757d..816008f 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -19,6 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "sonixj" #include @@ -1395,7 +1397,7 @@ static void reg_r(struct gspca_dev *gspca_dev, return; #ifdef GSPCA_DEBUG if (len > USB_BUF_SZ) { - err("reg_r: buffer overflow"); + pr_err("reg_r: buffer overflow\n"); return; } #endif @@ -1408,7 +1410,7 @@ static void reg_r(struct gspca_dev *gspca_dev, 500); PDEBUG(D_USBI, "reg_r [%02x] -> %02x", value, gspca_dev->usb_buf[0]); if (ret < 0) { - err("reg_r err %d", ret); + pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -1432,7 +1434,7 @@ static void reg_w1(struct gspca_dev *gspca_dev, gspca_dev->usb_buf, 1, 500); if (ret < 0) { - err("reg_w1 err %d", ret); + pr_err("reg_w1 err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -1449,7 +1451,7 @@ static void reg_w(struct gspca_dev *gspca_dev, value, buffer[0], buffer[1]); #ifdef GSPCA_DEBUG if (len > USB_BUF_SZ) { - err("reg_w: buffer overflow"); + pr_err("reg_w: buffer overflow\n"); return; } #endif @@ -1462,7 +1464,7 @@ static void reg_w(struct gspca_dev *gspca_dev, gspca_dev->usb_buf, len, 500); if (ret < 0) { - err("reg_w err %d", ret); + pr_err("reg_w err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -1502,7 +1504,7 @@ static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val) gspca_dev->usb_buf, 8, 500); if (ret < 0) { - err("i2c_w1 err %d", ret); + pr_err("i2c_w1 err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -1527,7 +1529,7 @@ static void i2c_w8(struct gspca_dev *gspca_dev, 500); msleep(2); if (ret < 0) { - err("i2c_w8 err %d", ret); + pr_err("i2c_w8 err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -1591,7 +1593,7 @@ static void hv7131r_probe(struct gspca_dev *gspca_dev) PDEBUG(D_PROBE, "Sensor HV7131R found"); return; } - warn("Erroneous HV7131R ID 0x%02x 0x%02x 0x%02x", + pr_warn("Erroneous HV7131R ID 0x%02x 0x%02x 0x%02x\n", gspca_dev->usb_buf[0], gspca_dev->usb_buf[1], gspca_dev->usb_buf[2]); } @@ -1710,7 +1712,7 @@ static void ov7648_probe(struct gspca_dev *gspca_dev) sd->sensor = SENSOR_PO1030; return; } - err("Unknown sensor %04x", val); + pr_err("Unknown sensor %04x\n", val); } /* 0c45:6142 sensor may be po2030n, gc0305 or gc0307 */ @@ -1748,7 +1750,7 @@ static void po2030n_probe(struct gspca_dev *gspca_dev) PDEBUG(D_PROBE, "Sensor po2030n"); /* sd->sensor = SENSOR_PO2030N; */ } else { - err("Unknown sensor ID %04x", val); + pr_err("Unknown sensor ID %04x\n", val); } } diff --git a/drivers/media/video/gspca/spca1528.c b/drivers/media/video/gspca/spca1528.c index 76c006b..4131be5 100644 --- a/drivers/media/video/gspca/spca1528.c +++ b/drivers/media/video/gspca/spca1528.c @@ -18,6 +18,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "spca1528" #include "gspca.h" @@ -171,7 +173,7 @@ static void reg_r(struct gspca_dev *gspca_dev, PDEBUG(D_USBI, "GET %02x 0000 %04x %02x", req, index, gspca_dev->usb_buf[0]); if (ret < 0) { - err("reg_r err %d", ret); + pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -193,7 +195,7 @@ static void reg_w(struct gspca_dev *gspca_dev, value, index, NULL, 0, 500); if (ret < 0) { - err("reg_w err %d", ret); + pr_err("reg_w err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -217,7 +219,7 @@ static void reg_wb(struct gspca_dev *gspca_dev, value, index, gspca_dev->usb_buf, 1, 500); if (ret < 0) { - err("reg_w err %d", ret); + pr_err("reg_w err %d\n", ret); gspca_dev->usb_err = ret; } } diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c index 3e76951..bb82c94 100644 --- a/drivers/media/video/gspca/spca500.c +++ b/drivers/media/video/gspca/spca500.c @@ -19,6 +19,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "spca500" #include "gspca.h" @@ -396,7 +398,7 @@ static int reg_w(struct gspca_dev *gspca_dev, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, index, NULL, 0, 500); if (ret < 0) - err("reg write: error %d", ret); + pr_err("reg write: error %d\n", ret); return ret; } @@ -418,7 +420,7 @@ static int reg_r_12(struct gspca_dev *gspca_dev, gspca_dev->usb_buf, length, 500); /* timeout */ if (ret < 0) { - err("reg_r_12 err %d", ret); + pr_err("reg_r_12 err %d\n", ret); return ret; } return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0]; diff --git a/drivers/media/video/gspca/spca501.c b/drivers/media/video/gspca/spca501.c index f7ef282..7aaac72 100644 --- a/drivers/media/video/gspca/spca501.c +++ b/drivers/media/video/gspca/spca501.c @@ -19,6 +19,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "spca501" #include "gspca.h" @@ -1852,7 +1854,7 @@ static int reg_write(struct usb_device *dev, PDEBUG(D_USBO, "reg write: 0x%02x 0x%02x 0x%02x", req, index, value); if (ret < 0) - err("reg write: error %d", ret); + pr_err("reg write: error %d\n", ret); return ret; } diff --git a/drivers/media/video/gspca/spca505.c b/drivers/media/video/gspca/spca505.c index e5bf865..16722dc 100644 --- a/drivers/media/video/gspca/spca505.c +++ b/drivers/media/video/gspca/spca505.c @@ -19,6 +19,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "spca505" #include "gspca.h" @@ -578,7 +580,7 @@ static int reg_write(struct usb_device *dev, PDEBUG(D_USBO, "reg write: 0x%02x,0x%02x:0x%02x, %d", req, index, value, ret); if (ret < 0) - err("reg write: error %d", ret); + pr_err("reg write: error %d\n", ret); return ret; } @@ -685,8 +687,8 @@ static int sd_start(struct gspca_dev *gspca_dev) return ret; } if (ret != 0x0101) { - err("After vector read returns 0x%04x should be 0x0101", - ret); + pr_err("After vector read returns 0x%04x should be 0x0101\n", + ret); } ret = reg_write(gspca_dev->dev, 0x06, 0x16, 0x0a); diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c index 9d0b460..a44fe3d 100644 --- a/drivers/media/video/gspca/spca508.c +++ b/drivers/media/video/gspca/spca508.c @@ -18,6 +18,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "spca508" #include "gspca.h" @@ -1275,7 +1277,7 @@ static int reg_write(struct usb_device *dev, PDEBUG(D_USBO, "reg write i:0x%04x = 0x%02x", index, value); if (ret < 0) - err("reg write: error %d", ret); + pr_err("reg write: error %d\n", ret); return ret; } @@ -1297,7 +1299,7 @@ static int reg_read(struct gspca_dev *gspca_dev, PDEBUG(D_USBI, "reg read i:%04x --> %02x", index, gspca_dev->usb_buf[0]); if (ret < 0) { - err("reg_read err %d", ret); + pr_err("reg_read err %d\n", ret); return ret; } return gspca_dev->usb_buf[0]; diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c index e836e77..c82fd53 100644 --- a/drivers/media/video/gspca/spca561.c +++ b/drivers/media/video/gspca/spca561.c @@ -20,6 +20,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "spca561" #include @@ -315,7 +317,7 @@ static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value) value, index, NULL, 0, 500); PDEBUG(D_USBO, "reg write: 0x%02x:0x%02x", index, value); if (ret < 0) - err("reg write: error %d", ret); + pr_err("reg write: error %d\n", ret); } static void write_vector(struct gspca_dev *gspca_dev, diff --git a/drivers/media/video/gspca/sq905.c b/drivers/media/video/gspca/sq905.c index 5ba96af..df805f7 100644 --- a/drivers/media/video/gspca/sq905.c +++ b/drivers/media/video/gspca/sq905.c @@ -33,6 +33,8 @@ * drivers. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "sq905" #include @@ -123,8 +125,7 @@ static int sq905_command(struct gspca_dev *gspca_dev, u16 index) SQ905_COMMAND, index, gspca_dev->usb_buf, 1, SQ905_CMD_TIMEOUT); if (ret < 0) { - err("%s: usb_control_msg failed (%d)", - __func__, ret); + pr_err("%s: usb_control_msg failed (%d)\n", __func__, ret); return ret; } @@ -135,8 +136,7 @@ static int sq905_command(struct gspca_dev *gspca_dev, u16 index) SQ905_PING, 0, gspca_dev->usb_buf, 1, SQ905_CMD_TIMEOUT); if (ret < 0) { - err("%s: usb_control_msg failed 2 (%d)", - __func__, ret); + pr_err("%s: usb_control_msg failed 2 (%d)\n", __func__, ret); return ret; } @@ -158,7 +158,7 @@ static int sq905_ack_frame(struct gspca_dev *gspca_dev) SQ905_READ_DONE, 0, gspca_dev->usb_buf, 1, SQ905_CMD_TIMEOUT); if (ret < 0) { - err("%s: usb_control_msg failed (%d)", __func__, ret); + pr_err("%s: usb_control_msg failed (%d)\n", __func__, ret); return ret; } @@ -186,7 +186,7 @@ sq905_read_data(struct gspca_dev *gspca_dev, u8 *data, int size, int need_lock) if (need_lock) mutex_unlock(&gspca_dev->usb_lock); if (ret < 0) { - err("%s: usb_control_msg failed (%d)", __func__, ret); + pr_err("%s: usb_control_msg failed (%d)\n", __func__, ret); return ret; } ret = usb_bulk_msg(gspca_dev->dev, @@ -195,8 +195,7 @@ sq905_read_data(struct gspca_dev *gspca_dev, u8 *data, int size, int need_lock) /* successful, it returns 0, otherwise negative */ if (ret < 0 || act_len != size) { - err("bulk read fail (%d) len %d/%d", - ret, act_len, size); + pr_err("bulk read fail (%d) len %d/%d\n", ret, act_len, size); return -EIO; } return 0; @@ -226,7 +225,7 @@ static void sq905_dostream(struct work_struct *work) buffer = kmalloc(SQ905_MAX_TRANSFER, GFP_KERNEL | GFP_DMA); if (!buffer) { - err("Couldn't allocate USB buffer"); + pr_err("Couldn't allocate USB buffer\n"); goto quit_stream; } diff --git a/drivers/media/video/gspca/sq905c.c b/drivers/media/video/gspca/sq905c.c index 457563b..c2c0560 100644 --- a/drivers/media/video/gspca/sq905c.c +++ b/drivers/media/video/gspca/sq905c.c @@ -27,6 +27,8 @@ * and may contain code fragments from it. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "sq905c" #include @@ -95,8 +97,7 @@ static int sq905c_command(struct gspca_dev *gspca_dev, u16 command, u16 index) command, index, NULL, 0, SQ905C_CMD_TIMEOUT); if (ret < 0) { - err("%s: usb_control_msg failed (%d)", - __func__, ret); + pr_err("%s: usb_control_msg failed (%d)\n", __func__, ret); return ret; } @@ -115,8 +116,7 @@ static int sq905c_read(struct gspca_dev *gspca_dev, u16 command, u16 index, command, index, gspca_dev->usb_buf, size, SQ905C_CMD_TIMEOUT); if (ret < 0) { - err("%s: usb_control_msg failed (%d)", - __func__, ret); + pr_err("%s: usb_control_msg failed (%d)\n", __func__, ret); return ret; } @@ -146,7 +146,7 @@ static void sq905c_dostream(struct work_struct *work) buffer = kmalloc(SQ905C_MAX_TRANSFER, GFP_KERNEL | GFP_DMA); if (!buffer) { - err("Couldn't allocate USB buffer"); + pr_err("Couldn't allocate USB buffer\n"); goto quit_stream; } diff --git a/drivers/media/video/gspca/sq930x.c b/drivers/media/video/gspca/sq930x.c index 8215d5d..e4255b4 100644 --- a/drivers/media/video/gspca/sq930x.c +++ b/drivers/media/video/gspca/sq930x.c @@ -20,6 +20,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "sq930x" #include "gspca.h" @@ -468,7 +470,7 @@ static void reg_r(struct gspca_dev *gspca_dev, value, 0, gspca_dev->usb_buf, len, 500); if (ret < 0) { - err("reg_r %04x failed %d", value, ret); + pr_err("reg_r %04x failed %d\n", value, ret); gspca_dev->usb_err = ret; } } @@ -488,7 +490,7 @@ static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index) 500); msleep(30); if (ret < 0) { - err("reg_w %04x %04x failed %d", value, index, ret); + pr_err("reg_w %04x %04x failed %d\n", value, index, ret); gspca_dev->usb_err = ret; } } @@ -511,7 +513,7 @@ static void reg_wb(struct gspca_dev *gspca_dev, u16 value, u16 index, 1000); msleep(30); if (ret < 0) { - err("reg_wb %04x %04x failed %d", value, index, ret); + pr_err("reg_wb %04x %04x failed %d\n", value, index, ret); gspca_dev->usb_err = ret; } } @@ -556,7 +558,7 @@ static void i2c_write(struct sd *sd, gspca_dev->usb_buf, buf - gspca_dev->usb_buf, 500); if (ret < 0) { - err("i2c_write failed %d", ret); + pr_err("i2c_write failed %d\n", ret); gspca_dev->usb_err = ret; } } @@ -575,7 +577,7 @@ static void ucbus_write(struct gspca_dev *gspca_dev, #ifdef GSPCA_DEBUG if ((batchsize - 1) * 3 > USB_BUF_SZ) { - err("Bug: usb_buf overflow"); + pr_err("Bug: usb_buf overflow\n"); gspca_dev->usb_err = -ENOMEM; return; } @@ -612,7 +614,7 @@ static void ucbus_write(struct gspca_dev *gspca_dev, gspca_dev->usb_buf, buf - gspca_dev->usb_buf, 500); if (ret < 0) { - err("ucbus_write failed %d", ret); + pr_err("ucbus_write failed %d\n", ret); gspca_dev->usb_err = ret; return; } @@ -688,7 +690,7 @@ static void cmos_probe(struct gspca_dev *gspca_dev) break; } if (i >= ARRAY_SIZE(probe_order)) { - err("Unknown sensor"); + pr_err("Unknown sensor\n"); gspca_dev->usb_err = -EINVAL; return; } @@ -696,7 +698,8 @@ static void cmos_probe(struct gspca_dev *gspca_dev) switch (sd->sensor) { case SENSOR_OV7660: case SENSOR_OV9630: - err("Sensor %s not yet treated", sensor_tb[sd->sensor].name); + pr_err("Sensor %s not yet treated\n", + sensor_tb[sd->sensor].name); gspca_dev->usb_err = -EINVAL; break; } @@ -1091,7 +1094,7 @@ static void sd_dq_callback(struct gspca_dev *gspca_dev) gspca_dev->cam.bulk_nurbs = 1; ret = usb_submit_urb(gspca_dev->urb[0], GFP_ATOMIC); if (ret < 0) - err("sd_dq_callback() err %d", ret); + pr_err("sd_dq_callback() err %d\n", ret); /* wait a little time, otherwise the webcam crashes */ msleep(100); diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c index 7637477..42a7a28 100644 --- a/drivers/media/video/gspca/stk014.c +++ b/drivers/media/video/gspca/stk014.c @@ -18,6 +18,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "stk014" #include "gspca.h" @@ -137,7 +139,7 @@ static u8 reg_r(struct gspca_dev *gspca_dev, gspca_dev->usb_buf, 1, 500); if (ret < 0) { - err("reg_r err %d", ret); + pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; return 0; } @@ -162,7 +164,7 @@ static void reg_w(struct gspca_dev *gspca_dev, 0, 500); if (ret < 0) { - err("reg_w err %d", ret); + pr_err("reg_w err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -192,7 +194,7 @@ static void rcv_val(struct gspca_dev *gspca_dev, &alen, 500); /* timeout in milliseconds */ if (ret < 0) { - err("rcv_val err %d", ret); + pr_err("rcv_val err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -235,7 +237,7 @@ static void snd_val(struct gspca_dev *gspca_dev, &alen, 500); /* timeout in milliseconds */ if (ret < 0) { - err("snd_val err %d", ret); + pr_err("snd_val err %d\n", ret); gspca_dev->usb_err = ret; } else { if (ads == 0x003f08) { @@ -315,7 +317,7 @@ static int sd_init(struct gspca_dev *gspca_dev) ret = reg_r(gspca_dev, 0x0740); if (gspca_dev->usb_err >= 0) { if (ret != 0xff) { - err("init reg: 0x%02x", ret); + pr_err("init reg: 0x%02x\n", ret); gspca_dev->usb_err = -EIO; } } @@ -349,8 +351,8 @@ static int sd_start(struct gspca_dev *gspca_dev) gspca_dev->iface, gspca_dev->alt); if (ret < 0) { - err("set intf %d %d failed", - gspca_dev->iface, gspca_dev->alt); + pr_err("set intf %d %d failed\n", + gspca_dev->iface, gspca_dev->alt); gspca_dev->usb_err = ret; goto out; } diff --git a/drivers/media/video/gspca/stv0680.c b/drivers/media/video/gspca/stv0680.c index e2ef41c..4dcc7e3 100644 --- a/drivers/media/video/gspca/stv0680.c +++ b/drivers/media/video/gspca/stv0680.c @@ -27,6 +27,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "stv0680" #include "gspca.h" @@ -79,7 +81,7 @@ static int stv_sndctrl(struct gspca_dev *gspca_dev, int set, u8 req, u16 val, val, 0, gspca_dev->usb_buf, size, 500); if ((ret < 0) && (req != 0x0a)) - err("usb_control_msg error %i, request = 0x%x, error = %i", + pr_err("usb_control_msg error %i, request = 0x%x, error = %i\n", set, req, ret); return ret; @@ -236,7 +238,7 @@ static int sd_config(struct gspca_dev *gspca_dev, if (stv_sndctrl(gspca_dev, 2, 0x06, 0x0100, 0x12) != 0x12 || gspca_dev->usb_buf[8] != 0x53 || gspca_dev->usb_buf[9] != 0x05) { - err("Could not get descriptor 0100."); + pr_err("Could not get descriptor 0100\n"); return stv0680_handle_error(gspca_dev, -EIO); } diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.c b/drivers/media/video/gspca/stv06xx/stv06xx.c index abf1658..b1fca7d 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx.c @@ -27,6 +27,8 @@ * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include "stv06xx_sensor.h" @@ -189,7 +191,7 @@ int stv06xx_read_sensor(struct sd *sd, const u8 address, u16 *value) 0x04, 0x40, 0x1400, 0, buf, I2C_BUFFER_LENGTH, STV06XX_URB_MSG_TIMEOUT); if (err < 0) { - err("I2C: Read error writing address: %d", err); + pr_err("I2C: Read error writing address: %d\n", err); return err; } @@ -213,14 +215,14 @@ static void stv06xx_dump_bridge(struct sd *sd) int i; u8 data, buf; - info("Dumping all stv06xx bridge registers"); + pr_info("Dumping all stv06xx bridge registers\n"); for (i = 0x1400; i < 0x160f; i++) { stv06xx_read_bridge(sd, i, &data); - info("Read 0x%x from address 0x%x", data, i); + pr_info("Read 0x%x from address 0x%x\n", data, i); } - info("Testing stv06xx bridge registers for writability"); + pr_info("Testing stv06xx bridge registers for writability\n"); for (i = 0x1400; i < 0x160f; i++) { stv06xx_read_bridge(sd, i, &data); buf = data; @@ -228,12 +230,12 @@ static void stv06xx_dump_bridge(struct sd *sd) stv06xx_write_bridge(sd, i, 0xff); stv06xx_read_bridge(sd, i, &data); if (data == 0xff) - info("Register 0x%x is read/write", i); + pr_info("Register 0x%x is read/write\n", i); else if (data != buf) - info("Register 0x%x is read/write," - " but only partially", i); + pr_info("Register 0x%x is read/write, but only partially\n", + i); else - info("Register 0x%x is read-only", i); + pr_info("Register 0x%x is read-only\n", i); stv06xx_write_bridge(sd, i, buf); } diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c index b815685..a8698b7 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c @@ -28,6 +28,8 @@ * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "stv06xx_hdcs.h" static const struct ctrl hdcs1x00_ctrl[] = { @@ -428,7 +430,7 @@ static int hdcs_probe_1x00(struct sd *sd) if (ret < 0 || sensor != 0x08) return -ENODEV; - info("HDCS-1000/1100 sensor detected"); + pr_info("HDCS-1000/1100 sensor detected\n"); sd->gspca_dev.cam.cam_mode = hdcs1x00_mode; sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1x00_mode); @@ -487,7 +489,7 @@ static int hdcs_probe_1020(struct sd *sd) if (ret < 0 || sensor != 0x10) return -ENODEV; - info("HDCS-1020 sensor detected"); + pr_info("HDCS-1020 sensor detected\n"); sd->gspca_dev.cam.cam_mode = hdcs1020_mode; sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1020_mode); @@ -601,11 +603,11 @@ static int hdcs_dump(struct sd *sd) { u16 reg, val; - info("Dumping sensor registers:"); + pr_info("Dumping sensor registers:\n"); for (reg = HDCS_IDENT; reg <= HDCS_ROWEXPH; reg++) { stv06xx_read_sensor(sd, reg, &val); - info("reg 0x%02x = 0x%02x", reg, val); + pr_info("reg 0x%02x = 0x%02x\n", reg, val); } return 0; } diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c index 75a5b9c..26f14fc 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c @@ -44,6 +44,8 @@ * PB_CFILLIN = R5 = 0x0E (14 dec) : Sets the frame rate */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "stv06xx_pb0100.h" static const struct ctrl pb0100_ctrl[] = { @@ -190,7 +192,7 @@ static int pb0100_probe(struct sd *sd) if (!sensor_settings) return -ENOMEM; - info("Photobit pb0100 sensor detected"); + pr_info("Photobit pb0100 sensor detected\n"); sd->gspca_dev.cam.cam_mode = pb0100_mode; sd->gspca_dev.cam.nmodes = ARRAY_SIZE(pb0100_mode); diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c index 8a456de..9940e03 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c @@ -26,6 +26,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "stv06xx_st6422.h" /* controls */ @@ -136,7 +138,7 @@ static int st6422_probe(struct sd *sd) if (sd->bridge != BRIDGE_ST6422) return -ENODEV; - info("st6422 sensor detected"); + pr_info("st6422 sensor detected\n"); sensor_settings = kmalloc(sizeof *sensor_settings, GFP_KERNEL); if (!sensor_settings) diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c index b05a154..a5c69d9 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c @@ -27,6 +27,8 @@ * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "stv06xx_vv6410.h" static struct v4l2_pix_format vv6410_mode[] = { @@ -112,7 +114,7 @@ static int vv6410_probe(struct sd *sd) return -ENODEV; if (data == 0x19) { - info("vv6410 sensor detected"); + pr_info("vv6410 sensor detected\n"); sensor_settings = kmalloc(ARRAY_SIZE(vv6410_ctrl) * sizeof(s32), GFP_KERNEL); @@ -222,11 +224,11 @@ static int vv6410_dump(struct sd *sd) u8 i; int err = 0; - info("Dumping all vv6410 sensor registers"); + pr_info("Dumping all vv6410 sensor registers\n"); for (i = 0; i < 0xff && !err; i++) { u16 data; err = stv06xx_read_sensor(sd, i, &data); - info("Register 0x%x contained 0x%x", i, data); + pr_info("Register 0x%x contained 0x%x\n", i, data); } return (err < 0) ? err : 0; } diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c index 6ec2329..c890977 100644 --- a/drivers/media/video/gspca/sunplus.c +++ b/drivers/media/video/gspca/sunplus.c @@ -19,6 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "sunplus" #include "gspca.h" @@ -325,7 +327,7 @@ static void reg_r(struct gspca_dev *gspca_dev, #ifdef GSPCA_DEBUG if (len > USB_BUF_SZ) { - err("reg_r: buffer overflow"); + pr_err("reg_r: buffer overflow\n"); return; } #endif @@ -340,7 +342,7 @@ static void reg_r(struct gspca_dev *gspca_dev, len ? gspca_dev->usb_buf : NULL, len, 500); if (ret < 0) { - err("reg_r err %d", ret); + pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -365,7 +367,7 @@ static void reg_w_1(struct gspca_dev *gspca_dev, gspca_dev->usb_buf, 1, 500); if (ret < 0) { - err("reg_w_1 err %d", ret); + pr_err("reg_w_1 err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -385,7 +387,7 @@ static void reg_w_riv(struct gspca_dev *gspca_dev, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, index, NULL, 0, 500); if (ret < 0) { - err("reg_w_riv err %d", ret); + pr_err("reg_w_riv err %d\n", ret); gspca_dev->usb_err = ret; return; } diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c index 6caed73..7ee2c82 100644 --- a/drivers/media/video/gspca/vc032x.c +++ b/drivers/media/video/gspca/vc032x.c @@ -20,6 +20,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "vc032x" #include "gspca.h" @@ -3169,7 +3171,7 @@ static void reg_r_i(struct gspca_dev *gspca_dev, index, gspca_dev->usb_buf, len, 500); if (ret < 0) { - err("reg_r err %d", ret); + pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -3210,7 +3212,7 @@ static void reg_w_i(struct gspca_dev *gspca_dev, value, index, NULL, 0, 500); if (ret < 0) { - err("reg_w err %d", ret); + pr_err("reg_w err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -3235,8 +3237,7 @@ static u16 read_sensor_register(struct gspca_dev *gspca_dev, reg_r(gspca_dev, 0xa1, 0xb33f, 1); if (!(gspca_dev->usb_buf[0] & 0x02)) { - err("I2c Bus Busy Wait %02x", - gspca_dev->usb_buf[0]); + pr_err("I2c Bus Busy Wait %02x\n", gspca_dev->usb_buf[0]); return 0; } reg_w(gspca_dev, 0xa0, address, 0xb33a); @@ -3349,7 +3350,7 @@ static void i2c_write(struct gspca_dev *gspca_dev, msleep(20); } while (--retry > 0); if (retry <= 0) - err("i2c_write timeout"); + pr_err("i2c_write timeout\n"); } static void put_tab_to_reg(struct gspca_dev *gspca_dev, @@ -3446,7 +3447,7 @@ static int sd_init(struct gspca_dev *gspca_dev) switch (sensor) { case -1: - err("Unknown sensor..."); + pr_err("Unknown sensor...\n"); return -EINVAL; case SENSOR_HV7131R: PDEBUG(D_PROBE, "Find Sensor HV7131R"); diff --git a/drivers/media/video/gspca/vicam.c b/drivers/media/video/gspca/vicam.c index 84dfbab..81dd4c9 100644 --- a/drivers/media/video/gspca/vicam.c +++ b/drivers/media/video/gspca/vicam.c @@ -26,6 +26,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "vicam" #define HEADER_SIZE 64 @@ -117,7 +119,7 @@ static int vicam_control_msg(struct gspca_dev *gspca_dev, u8 request, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, index, data, len, 1000); if (ret < 0) - err("control msg req %02X error %d", request, ret); + pr_err("control msg req %02X error %d\n", request, ret); return ret; } @@ -189,8 +191,8 @@ static int vicam_read_frame(struct gspca_dev *gspca_dev, u8 *data, int size) data, size, &act_len, 10000); /* successful, it returns 0, otherwise negative */ if (ret < 0 || act_len != size) { - err("bulk read fail (%d) len %d/%d", - ret, act_len, size); + pr_err("bulk read fail (%d) len %d/%d\n", + ret, act_len, size); return -EIO; } return 0; @@ -216,7 +218,7 @@ static void vicam_dostream(struct work_struct *work) HEADER_SIZE; buffer = kmalloc(frame_sz, GFP_KERNEL | GFP_DMA); if (!buffer) { - err("Couldn't allocate USB buffer"); + pr_err("Couldn't allocate USB buffer\n"); goto exit; } @@ -269,7 +271,7 @@ static int sd_init(struct gspca_dev *gspca_dev) ret = request_ihex_firmware(&fw, "vicam/firmware.fw", &gspca_dev->dev->dev); if (ret) { - err("Failed to load \"vicam/firmware.fw\": %d\n", ret); + pr_err("Failed to load \"vicam/firmware.fw\": %d\n", ret); return ret; } diff --git a/drivers/media/video/gspca/w996Xcf.c b/drivers/media/video/gspca/w996Xcf.c index 4a9e622..27d2cef 100644 --- a/drivers/media/video/gspca/w996Xcf.c +++ b/drivers/media/video/gspca/w996Xcf.c @@ -31,6 +31,8 @@ the sensor drivers to v4l2 sub drivers, and properly split of this driver from ov519.c */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define W9968CF_I2C_BUS_DELAY 4 /* delay in us for I2C bit r/w operations */ #define Y_QUANTABLE (&sd->jpeg_hdr[JPEG_QT0_OFFSET]) @@ -81,7 +83,7 @@ static void w9968cf_write_fsb(struct sd *sd, u16* data) USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, value, 0x06, sd->gspca_dev.usb_buf, 6, 500); if (ret < 0) { - err("Write FSB registers failed (%d)", ret); + pr_err("Write FSB registers failed (%d)\n", ret); sd->gspca_dev.usb_err = ret; } } @@ -108,7 +110,7 @@ static void w9968cf_write_sb(struct sd *sd, u16 value) udelay(W9968CF_I2C_BUS_DELAY); if (ret < 0) { - err("Write SB reg [01] %04x failed", value); + pr_err("Write SB reg [01] %04x failed\n", value); sd->gspca_dev.usb_err = ret; } } @@ -135,7 +137,7 @@ static int w9968cf_read_sb(struct sd *sd) ret = sd->gspca_dev.usb_buf[0] | (sd->gspca_dev.usb_buf[1] << 8); } else { - err("Read SB reg [01] failed"); + pr_err("Read SB reg [01] failed\n"); sd->gspca_dev.usb_err = ret; } diff --git a/drivers/media/video/gspca/xirlink_cit.c b/drivers/media/video/gspca/xirlink_cit.c index c089a0f..3aed42a 100644 --- a/drivers/media/video/gspca/xirlink_cit.c +++ b/drivers/media/video/gspca/xirlink_cit.c @@ -27,6 +27,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "xirlink-cit" #include @@ -800,8 +802,8 @@ static int cit_write_reg(struct gspca_dev *gspca_dev, u16 value, u16 index) USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, value, index, NULL, 0, 1000); if (err < 0) - err("Failed to write a register (index 0x%04X," - " value 0x%02X, error %d)", index, value, err); + pr_err("Failed to write a register (index 0x%04X, value 0x%02X, error %d)\n", + index, value, err); return 0; } @@ -816,8 +818,8 @@ static int cit_read_reg(struct gspca_dev *gspca_dev, u16 index, int verbose) USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0x00, index, buf, 8, 1000); if (res < 0) { - err("Failed to read a register (index 0x%04X, error %d)", - index, res); + pr_err("Failed to read a register (index 0x%04X, error %d)\n", + index, res); return res; } @@ -1587,7 +1589,7 @@ static int cit_get_packet_size(struct gspca_dev *gspca_dev) intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface); alt = usb_altnum_to_altsetting(intf, gspca_dev->alt); if (!alt) { - err("Couldn't get altsetting"); + pr_err("Couldn't get altsetting\n"); return -EIO; } @@ -2824,7 +2826,7 @@ static int sd_isoc_nego(struct gspca_dev *gspca_dev) ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1); if (ret < 0) - err("set alt 1 err %d", ret); + pr_err("set alt 1 err %d\n", ret); return ret; } diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c index 61cdd56..9d78fb8 100644 --- a/drivers/media/video/gspca/zc3xx.c +++ b/drivers/media/video/gspca/zc3xx.c @@ -19,6 +19,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define MODULE_NAME "zc3xx" #include @@ -5666,7 +5668,7 @@ static u8 reg_r_i(struct gspca_dev *gspca_dev, index, gspca_dev->usb_buf, 1, 500); if (ret < 0) { - err("reg_r_i err %d", ret); + pr_err("reg_r_i err %d\n", ret); gspca_dev->usb_err = ret; return 0; } @@ -5698,7 +5700,7 @@ static void reg_w_i(struct gspca_dev *gspca_dev, value, index, NULL, 0, 500); if (ret < 0) { - err("reg_w_i err %d", ret); + pr_err("reg_w_i err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -5724,7 +5726,7 @@ static u16 i2c_read(struct gspca_dev *gspca_dev, msleep(20); retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */ if (retbyte != 0x00) - err("i2c_r status error %02x", retbyte); + pr_err("i2c_r status error %02x\n", retbyte); retval = reg_r_i(gspca_dev, 0x0095); /* read Lowbyte */ retval |= reg_r_i(gspca_dev, 0x0096) << 8; /* read Hightbyte */ PDEBUG(D_USBI, "i2c r [%02x] -> %04x (%02x)", @@ -5748,7 +5750,7 @@ static u8 i2c_write(struct gspca_dev *gspca_dev, msleep(1); retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */ if (retbyte != 0x00) - err("i2c_w status error %02x", retbyte); + pr_err("i2c_w status error %02x\n", retbyte); PDEBUG(D_USBO, "i2c w [%02x] = %02x%02x (%02x)", reg, valH, valL, retbyte); return retbyte; @@ -6497,7 +6499,7 @@ static int sd_init(struct gspca_dev *gspca_dev) PDEBUG(D_PROBE, "Sensor GC0303"); break; default: - warn("Unknown sensor - set to TAS5130C"); + pr_warn("Unknown sensor - set to TAS5130C\n"); sd->sensor = SENSOR_TAS5130C; } break; @@ -6603,7 +6605,7 @@ static int sd_init(struct gspca_dev *gspca_dev) sd->sensor = SENSOR_OV7620; /* same sensor (?) */ break; default: - err("Unknown sensor %04x", sensor); + pr_err("Unknown sensor %04x\n", sensor); return -EINVAL; } } -- cgit v0.10.2 From f8a26f052a5f62c7555d09680c1fe8cbfcac590f Mon Sep 17 00:00:00 2001 From: Edward Sheldrake Date: Fri, 26 Aug 2011 12:59:30 -0300 Subject: [media] drxd: fix divide error Fix division by zero in drxd triggered by running "femon" before any DVB tuning has been done (by "scandvb" or anything else). Signed-off-by: Edward Sheldrake Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/frontends/drxd_hard.c b/drivers/media/dvb/frontends/drxd_hard.c index 2238bf0..bcad01c 100644 --- a/drivers/media/dvb/frontends/drxd_hard.c +++ b/drivers/media/dvb/frontends/drxd_hard.c @@ -889,10 +889,15 @@ static int ReadIFAgc(struct drxd_state *state, u32 * pValue) u32 R2 = state->if_agc_cfg.R2; u32 R3 = state->if_agc_cfg.R3; - u32 Vmax = (3300 * R2) / (R1 + R2); - u32 Rpar = (R2 * R3) / (R3 + R2); - u32 Vmin = (3300 * Rpar) / (R1 + Rpar); - u32 Vout = Vmin + ((Vmax - Vmin) * Value) / 1024; + u32 Vmax, Rpar, Vmin, Vout; + + if (R2 == 0 && (R1 == 0 || R3 == 0)) + return 0; + + Vmax = (3300 * R2) / (R1 + R2); + Rpar = (R2 * R3) / (R3 + R2); + Vmin = (3300 * Rpar) / (R1 + Rpar); + Vout = Vmin + ((Vmax - Vmin) * Value) / 1024; *pValue = Vout; } -- cgit v0.10.2 From 4c66c9205c0788e18eb09d482461aa2f551ee046 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 29 Aug 2011 00:05:35 -0300 Subject: [media] dvb-usb: add ATSC support for the Hauppauge WinTV-Aero-M Adds new driver, mxl111sf, to support the WinTV-Aero-M Signed-off-by: Michael Krufky Reviewed-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 6e97bb3..2c773827 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -381,3 +381,11 @@ config DVB_USB_IT913X select DVB_IT913X_FE help Say Y here to support the it913x device + +config DVB_USB_MXL111SF + tristate "MxL111SF DTV USB2.0 support" + depends on DVB_USB + select DVB_LGDT3305 if !DVB_FE_CUSTOMISE + select VIDEO_TVEEPROM + help + Say Y here to support the MxL111SF USB2.0 DTV receiver. diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 03ae657..06f75f6 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -97,6 +97,10 @@ obj-$(CONFIG_DVB_USB_TECHNISAT_USB2) += dvb-usb-technisat-usb2.o dvb-usb-it913x-objs := it913x.o obj-$(CONFIG_DVB_USB_IT913X) += dvb-usb-it913x.o +dvb-usb-mxl111sf-objs = mxl111sf.o mxl111sf-phy.o mxl111sf-i2c.o mxl111sf-gpio.o +obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-usb-mxl111sf.o +obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o + ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ # due to tuner-xc3028 ccflags-y += -Idrivers/media/common/tuners diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-gpio.c b/drivers/media/dvb/dvb-usb/mxl111sf-gpio.c new file mode 100644 index 0000000..e4121cb --- /dev/null +++ b/drivers/media/dvb/dvb-usb/mxl111sf-gpio.c @@ -0,0 +1,763 @@ +/* + * mxl111sf-gpio.c - driver for the MaxLinear MXL111SF + * + * Copyright (C) 2010 Michael Krufky + * + * 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 of the License, 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 "mxl111sf-gpio.h" +#include "mxl111sf-i2c.h" +#include "mxl111sf.h" + +/* ------------------------------------------------------------------------- */ + +#define MXL_GPIO_MUX_REG_0 0x84 +#define MXL_GPIO_MUX_REG_1 0x89 +#define MXL_GPIO_MUX_REG_2 0x82 + +#define MXL_GPIO_DIR_INPUT 0 +#define MXL_GPIO_DIR_OUTPUT 1 + + +static int mxl111sf_set_gpo_state(struct mxl111sf_state *state, u8 pin, u8 val) +{ + int ret; + u8 tmp; + + mxl_debug_adv("(%d, %d)", pin, val); + + if ((pin > 0) && (pin < 8)) { + ret = mxl111sf_read_reg(state, 0x19, &tmp); + if (mxl_fail(ret)) + goto fail; + tmp &= ~(1 << (pin - 1)); + tmp |= (val << (pin - 1)); + ret = mxl111sf_write_reg(state, 0x19, tmp); + if (mxl_fail(ret)) + goto fail; + } else if (pin <= 10) { + if (pin == 0) + pin += 7; + ret = mxl111sf_read_reg(state, 0x30, &tmp); + if (mxl_fail(ret)) + goto fail; + tmp &= ~(1 << (pin - 3)); + tmp |= (val << (pin - 3)); + ret = mxl111sf_write_reg(state, 0x30, tmp); + if (mxl_fail(ret)) + goto fail; + } else + ret = -EINVAL; +fail: + return ret; +} + +static int mxl111sf_get_gpi_state(struct mxl111sf_state *state, u8 pin, u8 *val) +{ + int ret; + u8 tmp; + + mxl_debug("(0x%02x)", pin); + + *val = 0; + + switch (pin) { + case 0: + case 1: + case 2: + case 3: + ret = mxl111sf_read_reg(state, 0x23, &tmp); + if (mxl_fail(ret)) + goto fail; + *val = (tmp >> (pin + 4)) & 0x01; + break; + case 4: + case 5: + case 6: + case 7: + ret = mxl111sf_read_reg(state, 0x2f, &tmp); + if (mxl_fail(ret)) + goto fail; + *val = (tmp >> pin) & 0x01; + break; + case 8: + case 9: + case 10: + ret = mxl111sf_read_reg(state, 0x22, &tmp); + if (mxl_fail(ret)) + goto fail; + *val = (tmp >> (pin - 3)) & 0x01; + break; + default: + return -EINVAL; /* invalid pin */ + } +fail: + return ret; +} + +struct mxl_gpio_cfg { + u8 pin; + u8 dir; + u8 val; +}; + +static int mxl111sf_config_gpio_pins(struct mxl111sf_state *state, + struct mxl_gpio_cfg *gpio_cfg) +{ + int ret; + u8 tmp; + + mxl_debug_adv("(%d, %d)", gpio_cfg->pin, gpio_cfg->dir); + + switch (gpio_cfg->pin) { + case 0: + case 1: + case 2: + case 3: + ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_0, &tmp); + if (mxl_fail(ret)) + goto fail; + tmp &= ~(1 << (gpio_cfg->pin + 4)); + tmp |= (gpio_cfg->dir << (gpio_cfg->pin + 4)); + ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_0, tmp); + if (mxl_fail(ret)) + goto fail; + break; + case 4: + case 5: + case 6: + case 7: + ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_1, &tmp); + if (mxl_fail(ret)) + goto fail; + tmp &= ~(1 << gpio_cfg->pin); + tmp |= (gpio_cfg->dir << gpio_cfg->pin); + ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_1, tmp); + if (mxl_fail(ret)) + goto fail; + break; + case 8: + case 9: + case 10: + ret = mxl111sf_read_reg(state, MXL_GPIO_MUX_REG_2, &tmp); + if (mxl_fail(ret)) + goto fail; + tmp &= ~(1 << (gpio_cfg->pin - 3)); + tmp |= (gpio_cfg->dir << (gpio_cfg->pin - 3)); + ret = mxl111sf_write_reg(state, MXL_GPIO_MUX_REG_2, tmp); + if (mxl_fail(ret)) + goto fail; + break; + default: + return -EINVAL; /* invalid pin */ + } + + ret = (MXL_GPIO_DIR_OUTPUT == gpio_cfg->dir) ? + mxl111sf_set_gpo_state(state, + gpio_cfg->pin, gpio_cfg->val) : + mxl111sf_get_gpi_state(state, + gpio_cfg->pin, &gpio_cfg->val); + mxl_fail(ret); +fail: + return ret; +} + +static int mxl111sf_hw_do_set_gpio(struct mxl111sf_state *state, + int gpio, int direction, int val) +{ + struct mxl_gpio_cfg gpio_config = { + .pin = gpio, + .dir = direction, + .val = val, + }; + + mxl_debug("(%d, %d, %d)", gpio, direction, val); + + return mxl111sf_config_gpio_pins(state, &gpio_config); +} + +/* ------------------------------------------------------------------------- */ + +#define PIN_MUX_MPEG_MODE_MASK 0x40 /* 0x17 <6> */ +#define PIN_MUX_MPEG_PAR_EN_MASK 0x01 /* 0x18 <0> */ +#define PIN_MUX_MPEG_SER_EN_MASK 0x02 /* 0x18 <1> */ +#define PIN_MUX_MPG_IN_MUX_MASK 0x80 /* 0x3D <7> */ +#define PIN_MUX_BT656_ENABLE_MASK 0x04 /* 0x12 <2> */ +#define PIN_MUX_I2S_ENABLE_MASK 0x40 /* 0x15 <6> */ +#define PIN_MUX_SPI_MODE_MASK 0x10 /* 0x3D <4> */ +#define PIN_MUX_MCLK_EN_CTRL_MASK 0x10 /* 0x82 <4> */ +#define PIN_MUX_MPSYN_EN_CTRL_MASK 0x20 /* 0x82 <5> */ +#define PIN_MUX_MDVAL_EN_CTRL_MASK 0x40 /* 0x82 <6> */ +#define PIN_MUX_MPERR_EN_CTRL_MASK 0x80 /* 0x82 <7> */ +#define PIN_MUX_MDAT_EN_0_MASK 0x10 /* 0x84 <4> */ +#define PIN_MUX_MDAT_EN_1_MASK 0x20 /* 0x84 <5> */ +#define PIN_MUX_MDAT_EN_2_MASK 0x40 /* 0x84 <6> */ +#define PIN_MUX_MDAT_EN_3_MASK 0x80 /* 0x84 <7> */ +#define PIN_MUX_MDAT_EN_4_MASK 0x10 /* 0x89 <4> */ +#define PIN_MUX_MDAT_EN_5_MASK 0x20 /* 0x89 <5> */ +#define PIN_MUX_MDAT_EN_6_MASK 0x40 /* 0x89 <6> */ +#define PIN_MUX_MDAT_EN_7_MASK 0x80 /* 0x89 <7> */ + +int mxl111sf_config_pin_mux_modes(struct mxl111sf_state *state, + enum mxl111sf_mux_config pin_mux_config) +{ + u8 r12, r15, r17, r18, r3D, r82, r84, r89; + int ret; + + mxl_debug("(%d)", pin_mux_config); + + ret = mxl111sf_read_reg(state, 0x17, &r17); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_read_reg(state, 0x18, &r18); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_read_reg(state, 0x12, &r12); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_read_reg(state, 0x15, &r15); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_read_reg(state, 0x82, &r82); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_read_reg(state, 0x84, &r84); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_read_reg(state, 0x89, &r89); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_read_reg(state, 0x3D, &r3D); + if (mxl_fail(ret)) + goto fail; + + switch (pin_mux_config) { + case PIN_MUX_TS_OUT_PARALLEL: + /* mpeg_mode = 1 */ + r17 |= PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 1 */ + r18 |= PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 0 */ + r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 0 */ + r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 0 */ + r12 &= ~PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 0 */ + r15 &= ~PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 0 */ + r3D &= ~PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 1 */ + r82 |= PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 1 */ + r82 |= PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 1 */ + r82 |= PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 1 */ + r82 |= PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0xF */ + r84 |= 0xF0; + /* mdat_en_ctrl[7:4] = 0xF */ + r89 |= 0xF0; + break; + case PIN_MUX_TS_OUT_SERIAL: + /* mpeg_mode = 1 */ + r17 |= PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 0 */ + r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 1 */ + r18 |= PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 0 */ + r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 0 */ + r12 &= ~PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 0 */ + r15 &= ~PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 0 */ + r3D &= ~PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 1 */ + r82 |= PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 1 */ + r82 |= PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 1 */ + r82 |= PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 1 */ + r82 |= PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0xF */ + r84 |= 0xF0; + /* mdat_en_ctrl[7:4] = 0xF */ + r89 |= 0xF0; + break; + case PIN_MUX_GPIO_MODE: + /* mpeg_mode = 0 */ + r17 &= ~PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 0 */ + r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 0 */ + r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 0 */ + r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 0 */ + r12 &= ~PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 0 */ + r15 &= ~PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 0 */ + r3D &= ~PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0x0 */ + r84 &= 0x0F; + /* mdat_en_ctrl[7:4] = 0x0 */ + r89 &= 0x0F; + break; + case PIN_MUX_TS_SERIAL_IN_MODE_0: + /* mpeg_mode = 0 */ + r17 &= ~PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 0 */ + r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 1 */ + r18 |= PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 0 */ + r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 0 */ + r12 &= ~PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 0 */ + r15 &= ~PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 0 */ + r3D &= ~PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0x0 */ + r84 &= 0x0F; + /* mdat_en_ctrl[7:4] = 0x0 */ + r89 &= 0x0F; + break; + case PIN_MUX_TS_SERIAL_IN_MODE_1: + /* mpeg_mode = 0 */ + r17 &= ~PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 0 */ + r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 1 */ + r18 |= PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 1 */ + r3D |= PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 0 */ + r12 &= ~PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 0 */ + r15 &= ~PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 0 */ + r3D &= ~PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0x0 */ + r84 &= 0x0F; + /* mdat_en_ctrl[7:4] = 0x0 */ + r89 &= 0x0F; + break; + case PIN_MUX_TS_SPI_IN_MODE_1: + /* mpeg_mode = 0 */ + r17 &= ~PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 0 */ + r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 1 */ + r18 |= PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 1 */ + r3D |= PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 0 */ + r12 &= ~PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 1 */ + r15 |= PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 1 */ + r3D |= PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0x0 */ + r84 &= 0x0F; + /* mdat_en_ctrl[7:4] = 0x0 */ + r89 &= 0x0F; + break; + case PIN_MUX_TS_SPI_IN_MODE_0: + /* mpeg_mode = 0 */ + r17 &= ~PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 0 */ + r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 1 */ + r18 |= PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 0 */ + r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 0 */ + r12 &= ~PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 1 */ + r15 |= PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 1 */ + r3D |= PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0x0 */ + r84 &= 0x0F; + /* mdat_en_ctrl[7:4] = 0x0 */ + r89 &= 0x0F; + break; + case PIN_MUX_TS_PARALLEL_IN: + /* mpeg_mode = 0 */ + r17 &= ~PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 1 */ + r18 |= PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 0 */ + r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 0 */ + r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 0 */ + r12 &= ~PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 0 */ + r15 &= ~PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 0 */ + r3D &= ~PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0x0 */ + r84 &= 0x0F; + /* mdat_en_ctrl[7:4] = 0x0 */ + r89 &= 0x0F; + break; + case PIN_MUX_BT656_I2S_MODE: + /* mpeg_mode = 0 */ + r17 &= ~PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 0 */ + r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 0 */ + r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 0 */ + r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 1 */ + r12 |= PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 1 */ + r15 |= PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 0 */ + r3D &= ~PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0x0 */ + r84 &= 0x0F; + /* mdat_en_ctrl[7:4] = 0x0 */ + r89 &= 0x0F; + break; + case PIN_MUX_DEFAULT: + default: + /* mpeg_mode = 1 */ + r17 |= PIN_MUX_MPEG_MODE_MASK; + /* mpeg_par_en = 0 */ + r18 &= ~PIN_MUX_MPEG_PAR_EN_MASK; + /* mpeg_ser_en = 0 */ + r18 &= ~PIN_MUX_MPEG_SER_EN_MASK; + /* mpg_in_mux = 0 */ + r3D &= ~PIN_MUX_MPG_IN_MUX_MASK; + /* bt656_enable = 0 */ + r12 &= ~PIN_MUX_BT656_ENABLE_MASK; + /* i2s_enable = 0 */ + r15 &= ~PIN_MUX_I2S_ENABLE_MASK; + /* spi_mode = 0 */ + r3D &= ~PIN_MUX_SPI_MODE_MASK; + /* mclk_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MCLK_EN_CTRL_MASK; + /* mperr_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPERR_EN_CTRL_MASK; + /* mdval_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MDVAL_EN_CTRL_MASK; + /* mpsyn_en_ctrl = 0 */ + r82 &= ~PIN_MUX_MPSYN_EN_CTRL_MASK; + /* mdat_en_ctrl[3:0] = 0x0 */ + r84 &= 0x0F; + /* mdat_en_ctrl[7:4] = 0x0 */ + r89 &= 0x0F; + break; + } + + ret = mxl111sf_write_reg(state, 0x17, r17); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_write_reg(state, 0x18, r18); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_write_reg(state, 0x12, r12); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_write_reg(state, 0x15, r15); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_write_reg(state, 0x82, r82); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_write_reg(state, 0x84, r84); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_write_reg(state, 0x89, r89); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_write_reg(state, 0x3D, r3D); + if (mxl_fail(ret)) + goto fail; +fail: + return ret; +} + +/* ------------------------------------------------------------------------- */ + +static int mxl111sf_hw_set_gpio(struct mxl111sf_state *state, int gpio, int val) +{ + return mxl111sf_hw_do_set_gpio(state, gpio, MXL_GPIO_DIR_OUTPUT, val); +} + +static int mxl111sf_hw_gpio_initialize(struct mxl111sf_state *state) +{ + u8 gpioval = 0x07; /* write protect enabled, signal LEDs off */ + int i, ret; + + mxl_debug("()"); + + for (i = 3; i < 8; i++) { + ret = mxl111sf_hw_set_gpio(state, i, (gpioval >> i) & 0x01); + if (mxl_fail(ret)) + break; + } + + return ret; +} + +#define PCA9534_I2C_ADDR (0x40 >> 1) +static int pca9534_set_gpio(struct mxl111sf_state *state, int gpio, int val) +{ + u8 w[2] = { 1, 0 }; + u8 r = 0; + struct i2c_msg msg[] = { + { .addr = PCA9534_I2C_ADDR, + .flags = 0, .buf = w, .len = 1 }, + { .addr = PCA9534_I2C_ADDR, + .flags = I2C_M_RD, .buf = &r, .len = 1 }, + }; + + mxl_debug("(%d, %d)", gpio, val); + + /* read current GPIO levels from flip-flop */ + i2c_transfer(&state->d->i2c_adap, msg, 2); + + /* prepare write buffer with current GPIO levels */ + msg[0].len = 2; +#if 0 + w[0] = 1; +#endif + w[1] = r; + + /* clear the desired GPIO */ + w[1] &= ~(1 << gpio); + + /* set the desired GPIO value */ + w[1] |= ((val ? 1 : 0) << gpio); + + /* write new GPIO levels to flip-flop */ + i2c_transfer(&state->d->i2c_adap, &msg[0], 1); + + return 0; +} + +static int pca9534_init_port_expander(struct mxl111sf_state *state) +{ + u8 w[2] = { 1, 0x07 }; /* write protect enabled, signal LEDs off */ + + struct i2c_msg msg = { + .addr = PCA9534_I2C_ADDR, + .flags = 0, .buf = w, .len = 2 + }; + + mxl_debug("()"); + + i2c_transfer(&state->d->i2c_adap, &msg, 1); + + /* configure all pins as outputs */ + w[0] = 3; + w[1] = 0; + + i2c_transfer(&state->d->i2c_adap, &msg, 1); + + return 0; +} + +int mxl111sf_set_gpio(struct mxl111sf_state *state, int gpio, int val) +{ + mxl_debug("(%d, %d)", gpio, val); + + switch (state->gpio_port_expander) { + default: + mxl_printk(KERN_ERR, + "gpio_port_expander undefined, assuming PCA9534"); + /* fall-thru */ + case mxl111sf_PCA9534: + return pca9534_set_gpio(state, gpio, val); + case mxl111sf_gpio_hw: + return mxl111sf_hw_set_gpio(state, gpio, val); + } +} + +static int mxl111sf_probe_port_expander(struct mxl111sf_state *state) +{ + int ret; + u8 w = 1; + u8 r = 0; + struct i2c_msg msg[] = { + { .flags = 0, .buf = &w, .len = 1 }, + { .flags = I2C_M_RD, .buf = &r, .len = 1 }, + }; + + mxl_debug("()"); + + msg[0].addr = 0x70 >> 1; + msg[1].addr = 0x70 >> 1; + + /* read current GPIO levels from flip-flop */ + ret = i2c_transfer(&state->d->i2c_adap, msg, 2); + if (ret == 2) { + state->port_expander_addr = msg[0].addr; + state->gpio_port_expander = mxl111sf_PCA9534; + mxl_debug("found port expander at 0x%02x", + state->port_expander_addr); + return 0; + } + + msg[0].addr = 0x40 >> 1; + msg[1].addr = 0x40 >> 1; + + ret = i2c_transfer(&state->d->i2c_adap, msg, 2); + if (ret == 2) { + state->port_expander_addr = msg[0].addr; + state->gpio_port_expander = mxl111sf_PCA9534; + mxl_debug("found port expander at 0x%02x", + state->port_expander_addr); + return 0; + } + state->port_expander_addr = 0xff; + state->gpio_port_expander = mxl111sf_gpio_hw; + mxl_debug("using hardware gpio"); + return 0; +} + +int mxl111sf_init_port_expander(struct mxl111sf_state *state) +{ + mxl_debug("()"); + + if (0x00 == state->port_expander_addr) + mxl111sf_probe_port_expander(state); + + switch (state->gpio_port_expander) { + default: + mxl_printk(KERN_ERR, + "gpio_port_expander undefined, assuming PCA9534"); + /* fall-thru */ + case mxl111sf_PCA9534: + return pca9534_init_port_expander(state); + case mxl111sf_gpio_hw: + return mxl111sf_hw_gpio_initialize(state); + } +} + +/* ------------------------------------------------------------------------ */ + +int mxl111sf_gpio_mode_switch(struct mxl111sf_state *state, unsigned int mode) +{ +/* GPO: + * 3 - ATSC/MH# | 1 = ATSC transport, 0 = MH transport | default 0 + * 4 - ATSC_RST## | 1 = ATSC enable, 0 = ATSC Reset | default 0 + * 5 - ATSC_EN | 1 = ATSC power enable, 0 = ATSC power off | default 0 + * 6 - MH_RESET# | 1 = MH enable, 0 = MH Reset | default 0 + * 7 - MH_EN | 1 = MH power enable, 0 = MH power off | default 0 + */ + mxl_debug("(%d)", mode); + + switch (mode) { + case MXL111SF_GPIO_MOD_MH: + mxl111sf_set_gpio(state, 4, 0); + mxl111sf_set_gpio(state, 5, 0); + msleep(50); + mxl111sf_set_gpio(state, 7, 1); + msleep(50); + mxl111sf_set_gpio(state, 6, 1); + msleep(50); + + mxl111sf_set_gpio(state, 3, 0); + break; + case MXL111SF_GPIO_MOD_ATSC: + mxl111sf_set_gpio(state, 6, 0); + mxl111sf_set_gpio(state, 7, 0); + msleep(50); + mxl111sf_set_gpio(state, 5, 1); + msleep(50); + mxl111sf_set_gpio(state, 4, 1); + msleep(50); + mxl111sf_set_gpio(state, 3, 1); + break; + default: /* DVBT / STANDBY */ + mxl111sf_init_port_expander(state); + break; + } + return 0; +} + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-gpio.h b/drivers/media/dvb/dvb-usb/mxl111sf-gpio.h new file mode 100644 index 0000000..0220f54 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/mxl111sf-gpio.h @@ -0,0 +1,56 @@ +/* + * mxl111sf-gpio.h - driver for the MaxLinear MXL111SF + * + * Copyright (C) 2010 Michael Krufky + * + * 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 of the License, 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. + */ + +#ifndef _DVB_USB_MXL111SF_GPIO_H_ +#define _DVB_USB_MXL111SF_GPIO_H_ + +#include "mxl111sf.h" + +int mxl111sf_set_gpio(struct mxl111sf_state *state, int gpio, int val); +int mxl111sf_init_port_expander(struct mxl111sf_state *state); + +#define MXL111SF_GPIO_MOD_DVBT 0 +#define MXL111SF_GPIO_MOD_MH 1 +#define MXL111SF_GPIO_MOD_ATSC 2 +int mxl111sf_gpio_mode_switch(struct mxl111sf_state *state, unsigned int mode); + +enum mxl111sf_mux_config { + PIN_MUX_DEFAULT = 0, + PIN_MUX_TS_OUT_PARALLEL, + PIN_MUX_TS_OUT_SERIAL, + PIN_MUX_GPIO_MODE, + PIN_MUX_TS_SERIAL_IN_MODE_0, + PIN_MUX_TS_SERIAL_IN_MODE_1, + PIN_MUX_TS_SPI_IN_MODE_0, + PIN_MUX_TS_SPI_IN_MODE_1, + PIN_MUX_TS_PARALLEL_IN, + PIN_MUX_BT656_I2S_MODE, +}; + +int mxl111sf_config_pin_mux_modes(struct mxl111sf_state *state, + enum mxl111sf_mux_config pin_mux_config); + +#endif /* _DVB_USB_MXL111SF_GPIO_H_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-i2c.c b/drivers/media/dvb/dvb-usb/mxl111sf-i2c.c new file mode 100644 index 0000000..a330987 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/mxl111sf-i2c.c @@ -0,0 +1,851 @@ +/* + * mxl111sf-i2c.c - driver for the MaxLinear MXL111SF + * + * Copyright (C) 2010 Michael Krufky + * + * 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 of the License, 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 "mxl111sf-i2c.h" +#include "mxl111sf.h" + +/* SW-I2C ----------------------------------------------------------------- */ + +#define SW_I2C_ADDR 0x1a +#define SW_I2C_EN 0x02 +#define SW_SCL_OUT 0x04 +#define SW_SDA_OUT 0x08 +#define SW_SDA_IN 0x04 + +#define SW_I2C_BUSY_ADDR 0x2f +#define SW_I2C_BUSY 0x02 + +static int mxl111sf_i2c_bitbang_sendbyte(struct mxl111sf_state *state, + u8 byte) +{ + int i, ret; + u8 data = 0; + + mxl_i2c("(0x%02x)", byte); + + ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data); + if (mxl_fail(ret)) + goto fail; + + for (i = 0; i < 8; i++) { + + data = (byte & (0x80 >> i)) ? SW_SDA_OUT : 0; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | data); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | data | SW_SCL_OUT); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | data); + if (mxl_fail(ret)) + goto fail; + } + + /* last bit was 0 so we need to release SDA */ + if (!(byte & 1)) { + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SDA_OUT); + if (mxl_fail(ret)) + goto fail; + } + + /* CLK high for ACK readback */ + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data); + if (mxl_fail(ret)) + goto fail; + + /* drop the CLK after getting ACK, SDA will go high right away */ + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SDA_OUT); + if (mxl_fail(ret)) + goto fail; + + if (data & SW_SDA_IN) + ret = -EIO; +fail: + return ret; +} + +static int mxl111sf_i2c_bitbang_recvbyte(struct mxl111sf_state *state, + u8 *pbyte) +{ + int i, ret; + u8 byte = 0; + u8 data = 0; + + mxl_i2c("()"); + + *pbyte = 0; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SDA_OUT); + if (mxl_fail(ret)) + goto fail; + + for (i = 0; i < 8; i++) { + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | + SW_SCL_OUT | SW_SDA_OUT); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data); + if (mxl_fail(ret)) + goto fail; + + if (data & SW_SDA_IN) + byte |= (0x80 >> i); + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SDA_OUT); + if (mxl_fail(ret)) + goto fail; + } + *pbyte = byte; +fail: + return ret; +} + +static int mxl111sf_i2c_start(struct mxl111sf_state *state) +{ + int ret; + + mxl_i2c("()"); + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SCL_OUT); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN); /* start */ + mxl_fail(ret); +fail: + return ret; +} + +static int mxl111sf_i2c_stop(struct mxl111sf_state *state) +{ + int ret; + + mxl_i2c("()"); + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN); /* stop */ + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SCL_OUT); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_SCL_OUT | SW_SDA_OUT); + mxl_fail(ret); +fail: + return ret; +} + +static int mxl111sf_i2c_ack(struct mxl111sf_state *state) +{ + int ret; + u8 b = 0; + + mxl_i2c("()"); + + ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &b); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN); + if (mxl_fail(ret)) + goto fail; + + /* pull SDA low */ + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SCL_OUT); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SDA_OUT); + mxl_fail(ret); +fail: + return ret; +} + +static int mxl111sf_i2c_nack(struct mxl111sf_state *state) +{ + int ret; + + mxl_i2c("()"); + + /* SDA high to signal last byte read from slave */ + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, SW_I2C_ADDR, + 0x10 | SW_I2C_EN | SW_SDA_OUT); + mxl_fail(ret); +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static int mxl111sf_i2c_sw_xfer_msg(struct mxl111sf_state *state, + struct i2c_msg *msg) +{ + int i, ret; + + mxl_i2c("()"); + + if (msg->flags & I2C_M_RD) { + + ret = mxl111sf_i2c_start(state); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_i2c_bitbang_sendbyte(state, + (msg->addr << 1) | 0x01); + if (mxl_fail(ret)) { + mxl111sf_i2c_stop(state); + goto fail; + } + + for (i = 0; i < msg->len; i++) { + ret = mxl111sf_i2c_bitbang_recvbyte(state, + &msg->buf[i]); + if (mxl_fail(ret)) { + mxl111sf_i2c_stop(state); + goto fail; + } + + if (i < msg->len - 1) + mxl111sf_i2c_ack(state); + } + + mxl111sf_i2c_nack(state); + + ret = mxl111sf_i2c_stop(state); + if (mxl_fail(ret)) + goto fail; + + } else { + + ret = mxl111sf_i2c_start(state); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_i2c_bitbang_sendbyte(state, + (msg->addr << 1) & 0xfe); + if (mxl_fail(ret)) { + mxl111sf_i2c_stop(state); + goto fail; + } + + for (i = 0; i < msg->len; i++) { + ret = mxl111sf_i2c_bitbang_sendbyte(state, + msg->buf[i]); + if (mxl_fail(ret)) { + mxl111sf_i2c_stop(state); + goto fail; + } + } + + /* FIXME: we only want to do this on the last transaction */ + mxl111sf_i2c_stop(state); + } +fail: + return ret; +} + +/* HW-I2C ----------------------------------------------------------------- */ + +#define USB_WRITE_I2C_CMD 0x99 +#define USB_READ_I2C_CMD 0xdd +#define USB_END_I2C_CMD 0xfe + +#define USB_WRITE_I2C_CMD_LEN 26 +#define USB_READ_I2C_CMD_LEN 24 + +#define I2C_MUX_REG 0x30 +#define I2C_CONTROL_REG 0x00 +#define I2C_SLAVE_ADDR_REG 0x08 +#define I2C_DATA_REG 0x0c +#define I2C_INT_STATUS_REG 0x10 + +static int mxl111sf_i2c_send_data(struct mxl111sf_state *state, + u8 index, u8 *wdata) +{ + int ret = mxl111sf_ctrl_msg(state->d, wdata[0], + &wdata[1], 25, NULL, 0); + mxl_fail(ret); + + return ret; +} + +static int mxl111sf_i2c_get_data(struct mxl111sf_state *state, + u8 index, u8 *wdata, u8 *rdata) +{ + int ret = mxl111sf_ctrl_msg(state->d, wdata[0], + &wdata[1], 25, rdata, 24); + mxl_fail(ret); + + return ret; +} + +static u8 mxl111sf_i2c_check_status(struct mxl111sf_state *state) +{ + u8 status = 0; + u8 buf[26]; + + mxl_i2c_adv("()"); + + buf[0] = USB_READ_I2C_CMD; + buf[1] = 0x00; + + buf[2] = I2C_INT_STATUS_REG; + buf[3] = 0x00; + buf[4] = 0x00; + + buf[5] = USB_END_I2C_CMD; + + mxl111sf_i2c_get_data(state, 0, buf, buf); + + if (buf[1] & 0x04) + status = 1; + + return status; +} + +static u8 mxl111sf_i2c_check_fifo(struct mxl111sf_state *state) +{ + u8 status = 0; + u8 buf[26]; + + mxl_i2c("()"); + + buf[0] = USB_READ_I2C_CMD; + buf[1] = 0x00; + + buf[2] = I2C_MUX_REG; + buf[3] = 0x00; + buf[4] = 0x00; + + buf[5] = I2C_INT_STATUS_REG; + buf[6] = 0x00; + buf[7] = 0x00; + buf[8] = USB_END_I2C_CMD; + + mxl111sf_i2c_get_data(state, 0, buf, buf); + + if (0x08 == (buf[1] & 0x08)) + status = 1; + + if ((buf[5] & 0x02) == 0x02) + mxl_i2c("(buf[5] & 0x02) == 0x02"); /* FIXME */ + + return status; +} + +static int mxl111sf_i2c_readagain(struct mxl111sf_state *state, + u8 count, u8 *rbuf) +{ + u8 i2c_w_data[26]; + u8 i2c_r_data[24]; + u8 i = 0; + u8 fifo_status = 0; + int ret; + int status = 0; + + mxl_i2c("read %d bytes", count); + + while ((fifo_status == 0) && (i++ < 5)) + fifo_status = mxl111sf_i2c_check_fifo(state); + + i2c_w_data[0] = 0xDD; + i2c_w_data[1] = 0x00; + + for (i = 2; i < 26; i++) + i2c_w_data[i] = 0xFE; + + for (i = 0; i < count; i++) { + i2c_w_data[2+(i*3)] = 0x0C; + i2c_w_data[3+(i*3)] = 0x00; + i2c_w_data[4+(i*3)] = 0x00; + } + + ret = mxl111sf_i2c_get_data(state, 0, i2c_w_data, i2c_r_data); + + /* Check for I2C NACK status */ + if (mxl111sf_i2c_check_status(state) == 1) { + mxl_i2c("error!"); + } else { + for (i = 0; i < count; i++) { + rbuf[i] = i2c_r_data[(i*3)+1]; + mxl_i2c("%02x\t %02x", + i2c_r_data[(i*3)+1], + i2c_r_data[(i*3)+2]); + } + + status = 1; + } + + return status; +} + +#define HWI2C400 1 +static int mxl111sf_i2c_hw_xfer_msg(struct mxl111sf_state *state, + struct i2c_msg *msg) +{ + int i, k, ret = 0; + u16 index = 0; + u8 buf[26]; + u8 i2c_r_data[24]; + u16 block_len; + u16 left_over_len; + u8 rd_status[8]; + u8 ret_status; + u8 readbuff[26]; + + mxl_i2c("addr: 0x%02x, read buff len: %d, write buff len: %d", + msg->addr, (msg->flags & I2C_M_RD) ? msg->len : 0, + (!msg->flags & I2C_M_RD) ? msg->len : 0); + + for (index = 0; index < 26; index++) + buf[index] = USB_END_I2C_CMD; + + /* command to indicate data payload is destined for I2C interface */ + buf[0] = USB_WRITE_I2C_CMD; + buf[1] = 0x00; + + /* enable I2C interface */ + buf[2] = I2C_MUX_REG; + buf[3] = 0x80; + buf[4] = 0x00; + + /* enable I2C interface */ + buf[5] = I2C_MUX_REG; + buf[6] = 0x81; + buf[7] = 0x00; + + /* set Timeout register on I2C interface */ + buf[8] = 0x14; + buf[9] = 0xff; + buf[10] = 0x00; +#if 0 + /* enable Interrupts on I2C interface */ + buf[8] = 0x24; + buf[9] = 0xF7; + buf[10] = 0x00; +#endif + buf[11] = 0x24; + buf[12] = 0xF7; + buf[13] = 0x00; + + ret = mxl111sf_i2c_send_data(state, 0, buf); + + /* write data on I2C bus */ + if ((!msg->flags & I2C_M_RD) && (msg->len > 0)) { + mxl_i2c("%d\t%02x", msg->len, msg->buf[0]); + + /* control register on I2C interface to initialize I2C bus */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0x5E; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + + /* I2C Slave device Address */ + buf[5] = I2C_SLAVE_ADDR_REG; + buf[6] = (msg->addr); + buf[7] = 0x00; + buf[8] = USB_END_I2C_CMD; + ret = mxl111sf_i2c_send_data(state, 0, buf); + + /* check for slave device status */ + if (mxl111sf_i2c_check_status(state) == 1) { + mxl_i2c("NACK writing slave address %02x", + msg->addr); + /* if NACK, stop I2C bus and exit */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0x4E; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + ret = -EIO; + goto exit; + } + + /* I2C interface can do I2C operations in block of 8 bytes of + I2C data. calculation to figure out number of blocks of i2c + data required to program */ + block_len = (msg->len / 8); + left_over_len = (msg->len % 8); + index = 0; + + mxl_i2c("block_len %d, left_over_len %d", + block_len, left_over_len); + + for (index = 0; index < block_len; index++) { + for (i = 0; i < 8; i++) { + /* write data on I2C interface */ + buf[2+(i*3)] = I2C_DATA_REG; + buf[3+(i*3)] = msg->buf[(index*8)+i]; + buf[4+(i*3)] = 0x00; + } + + ret = mxl111sf_i2c_send_data(state, 0, buf); + + /* check for I2C NACK status */ + if (mxl111sf_i2c_check_status(state) == 1) { + mxl_i2c("NACK writing slave address %02x", + msg->addr); + + /* if NACK, stop I2C bus and exit */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0x4E; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + ret = -EIO; + goto exit; + } + + } + + if (left_over_len) { + for (k = 0; k < 26; k++) + buf[k] = USB_END_I2C_CMD; + + buf[0] = 0x99; + buf[1] = 0x00; + + for (i = 0; i < left_over_len; i++) { + buf[2+(i*3)] = I2C_DATA_REG; + buf[3+(i*3)] = msg->buf[(index*8)+i]; + mxl_i2c("index = %d %d data %d", + index, i, msg->buf[(index*8)+i]); + buf[4+(i*3)] = 0x00; + } + ret = mxl111sf_i2c_send_data(state, 0, buf); + + /* check for I2C NACK status */ + if (mxl111sf_i2c_check_status(state) == 1) { + mxl_i2c("NACK writing slave address %02x", + msg->addr); + + /* if NACK, stop I2C bus and exit */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0x4E; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + ret = -EIO; + goto exit; + } + + } + + /* issue I2C STOP after write */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0x4E; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + + } + + /* read data from I2C bus */ + if ((msg->flags & I2C_M_RD) && (msg->len > 0)) { + mxl_i2c("read buf len %d", msg->len); + + /* command to indicate data payload is + destined for I2C interface */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0xDF; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + + /* I2C xfer length */ + buf[5] = 0x14; + buf[6] = (msg->len & 0xFF); + buf[7] = 0; + + /* I2C slave device Address */ + buf[8] = I2C_SLAVE_ADDR_REG; + buf[9] = msg->addr; + buf[10] = 0x00; + buf[11] = USB_END_I2C_CMD; + ret = mxl111sf_i2c_send_data(state, 0, buf); + + /* check for I2C NACK status */ + if (mxl111sf_i2c_check_status(state) == 1) { + mxl_i2c("NACK reading slave address %02x", + msg->addr); + + /* if NACK, stop I2C bus and exit */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0xC7; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + ret = -EIO; + goto exit; + } + + /* I2C interface can do I2C operations in block of 8 bytes of + I2C data. calculation to figure out number of blocks of + i2c data required to program */ + block_len = ((msg->len) / 8); + left_over_len = ((msg->len) % 8); + index = 0; + + mxl_i2c("block_len %d, left_over_len %d", + block_len, left_over_len); + + /* command to read data from I2C interface */ + buf[0] = USB_READ_I2C_CMD; + buf[1] = 0x00; + + for (index = 0; index < block_len; index++) { + /* setup I2C read request packet on I2C interface */ + for (i = 0; i < 8; i++) { + buf[2+(i*3)] = I2C_DATA_REG; + buf[3+(i*3)] = 0x00; + buf[4+(i*3)] = 0x00; + } + + ret = mxl111sf_i2c_get_data(state, 0, buf, i2c_r_data); + + /* check for I2C NACK status */ + if (mxl111sf_i2c_check_status(state) == 1) { + mxl_i2c("NACK reading slave address %02x", + msg->addr); + + /* if NACK, stop I2C bus and exit */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0xC7; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + ret = -EIO; + goto exit; + } + + /* copy data from i2c data payload to read buffer */ + for (i = 0; i < 8; i++) { + rd_status[i] = i2c_r_data[(i*3)+2]; + + if (rd_status[i] == 0x04) { + if (i < 7) { + mxl_i2c("i2c fifo empty!" + " @ %d", i); + msg->buf[(index*8)+i] = + i2c_r_data[(i*3)+1]; + /* read again */ + ret_status = + mxl111sf_i2c_readagain( + state, 8-(i+1), + readbuff); + if (ret_status == 1) { + for (k = 0; + k < 8-(i+1); + k++) { + + msg->buf[(index*8)+(k+i+1)] = + readbuff[k]; + mxl_i2c("read data: %02x\t %02x", + msg->buf[(index*8)+(k+i)], + (index*8)+(k+i)); + mxl_i2c("read data: %02x\t %02x", + msg->buf[(index*8)+(k+i+1)], + readbuff[k]); + + } + goto stop_copy; + } else { + mxl_i2c("readagain " + "ERROR!"); + } + } else { + msg->buf[(index*8)+i] = + i2c_r_data[(i*3)+1]; + } + } else { + msg->buf[(index*8)+i] = + i2c_r_data[(i*3)+1]; + } + } +stop_copy: + ; + + } + + if (left_over_len) { + for (k = 0; k < 26; k++) + buf[k] = USB_END_I2C_CMD; + + buf[0] = 0xDD; + buf[1] = 0x00; + + for (i = 0; i < left_over_len; i++) { + buf[2+(i*3)] = I2C_DATA_REG; + buf[3+(i*3)] = 0x00; + buf[4+(i*3)] = 0x00; + } + ret = mxl111sf_i2c_get_data(state, 0, buf, + i2c_r_data); + + /* check for I2C NACK status */ + if (mxl111sf_i2c_check_status(state) == 1) { + mxl_i2c("NACK reading slave address %02x", + msg->addr); + + /* if NACK, stop I2C bus and exit */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0xC7; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + ret = -EIO; + goto exit; + } + + for (i = 0; i < left_over_len; i++) { + msg->buf[(block_len*8)+i] = + i2c_r_data[(i*3)+1]; + mxl_i2c("read data: %02x\t %02x", + i2c_r_data[(i*3)+1], + i2c_r_data[(i*3)+2]); + } + } + + /* indicate I2C interface to issue NACK + after next I2C read op */ + buf[0] = USB_WRITE_I2C_CMD; + buf[1] = 0x00; + + /* control register */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0x17; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + + buf[5] = USB_END_I2C_CMD; + ret = mxl111sf_i2c_send_data(state, 0, buf); + + /* control register */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0xC7; + buf[4] = (HWI2C400) ? 0x03 : 0x0D; + + } +exit: + /* STOP and disable I2C MUX */ + buf[0] = USB_WRITE_I2C_CMD; + buf[1] = 0x00; + + /* de-initilize I2C BUS */ + buf[5] = USB_END_I2C_CMD; + mxl111sf_i2c_send_data(state, 0, buf); + + /* Control Register */ + buf[2] = I2C_CONTROL_REG; + buf[3] = 0xDF; + buf[4] = 0x03; + + /* disable I2C interface */ + buf[5] = I2C_MUX_REG; + buf[6] = 0x00; + buf[7] = 0x00; + + /* de-initilize I2C BUS */ + buf[8] = USB_END_I2C_CMD; + mxl111sf_i2c_send_data(state, 0, buf); + + /* disable I2C interface */ + buf[2] = I2C_MUX_REG; + buf[3] = 0x81; + buf[4] = 0x00; + + /* disable I2C interface */ + buf[5] = I2C_MUX_REG; + buf[6] = 0x00; + buf[7] = 0x00; + + /* disable I2C interface */ + buf[8] = I2C_MUX_REG; + buf[9] = 0x00; + buf[10] = 0x00; + + buf[11] = USB_END_I2C_CMD; + mxl111sf_i2c_send_data(state, 0, buf); + + return ret; +} + +/* ------------------------------------------------------------------------ */ + +int mxl111sf_i2c_xfer(struct i2c_adapter *adap, + struct i2c_msg msg[], int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct mxl111sf_state *state = d->priv; + int hwi2c = (state->chip_rev > MXL111SF_V6); + int i, ret; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + ret = (hwi2c) ? + mxl111sf_i2c_hw_xfer_msg(state, &msg[i]) : + mxl111sf_i2c_sw_xfer_msg(state, &msg[i]); + if (mxl_fail(ret)) { + mxl_debug_adv("failed with error %d on i2c " + "transaction %d of %d, %sing %d bytes " + "to/from 0x%02x", ret, i+1, num, + (msg[i].flags & I2C_M_RD) ? + "read" : "writ", + msg[i].len, msg[i].addr); + + break; + } + } + + mutex_unlock(&d->i2c_mutex); + + return i == num ? num : -EREMOTEIO; +} + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-i2c.h b/drivers/media/dvb/dvb-usb/mxl111sf-i2c.h new file mode 100644 index 0000000..a57a45f --- /dev/null +++ b/drivers/media/dvb/dvb-usb/mxl111sf-i2c.h @@ -0,0 +1,35 @@ +/* + * mxl111sf-i2c.h - driver for the MaxLinear MXL111SF + * + * Copyright (C) 2010 Michael Krufky + * + * 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 of the License, 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. + */ + +#ifndef _DVB_USB_MXL111SF_I2C_H_ +#define _DVB_USB_MXL111SF_I2C_H_ + +#include + +int mxl111sf_i2c_xfer(struct i2c_adapter *adap, + struct i2c_msg msg[], int num); + +#endif /* _DVB_USB_MXL111SF_I2C_H_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-phy.c b/drivers/media/dvb/dvb-usb/mxl111sf-phy.c new file mode 100644 index 0000000..91dc1fc --- /dev/null +++ b/drivers/media/dvb/dvb-usb/mxl111sf-phy.c @@ -0,0 +1,342 @@ +/* + * mxl111sf-phy.c - driver for the MaxLinear MXL111SF + * + * Copyright (C) 2010 Michael Krufky + * + * 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 of the License, 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 "mxl111sf-phy.h" +#include "mxl111sf-reg.h" + +int mxl111sf_init_tuner_demod(struct mxl111sf_state *state) +{ + struct mxl111sf_reg_ctrl_info mxl_111_overwrite_default[] = { + {0x07, 0xff, 0x0c}, + {0x58, 0xff, 0x9d}, + {0x09, 0xff, 0x00}, + {0x06, 0xff, 0x06}, + {0xc8, 0xff, 0x40}, /* ED_LE_WIN_OLD = 0 */ + {0x8d, 0x01, 0x01}, /* NEGATE_Q */ + {0x32, 0xff, 0xac}, /* DIG_RFREFSELECT = 12 */ + {0x42, 0xff, 0x43}, /* DIG_REG_AMP = 4 */ + {0x74, 0xff, 0xc4}, /* SSPUR_FS_PRIO = 4 */ + {0x71, 0xff, 0xe6}, /* SPUR_ROT_PRIO_VAL = 1 */ + {0x83, 0xff, 0x64}, /* INF_FILT1_THD_SC = 100 */ + {0x85, 0xff, 0x64}, /* INF_FILT2_THD_SC = 100 */ + {0x88, 0xff, 0xf0}, /* INF_THD = 240 */ + {0x6f, 0xf0, 0xb0}, /* DFE_DLY = 11 */ + {0x00, 0xff, 0x01}, /* Change to page 1 */ + {0x81, 0xff, 0x11}, /* DSM_FERR_BYPASS = 1 */ + {0xf4, 0xff, 0x07}, /* DIG_FREQ_CORR = 1 */ + {0xd4, 0x1f, 0x0f}, /* SPUR_TEST_NOISE_TH = 15 */ + {0xd6, 0xff, 0x0c}, /* SPUR_TEST_NOISE_PAPR = 12 */ + {0x00, 0xff, 0x00}, /* Change to page 0 */ + {0, 0, 0} + }; + + mxl_debug("()"); + + return mxl111sf_ctrl_program_regs(state, mxl_111_overwrite_default); +} + +int mxl1x1sf_soft_reset(struct mxl111sf_state *state) +{ + int ret; + mxl_debug("()"); + + ret = mxl111sf_write_reg(state, 0xff, 0x00); /* AIC */ + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_write_reg(state, 0x02, 0x01); /* get out of reset */ + mxl_fail(ret); +fail: + return ret; +} + +int mxl1x1sf_set_device_mode(struct mxl111sf_state *state, int mode) +{ + int ret; + + mxl_debug("(%s)", MXL_SOC_MODE == mode ? + "MXL_SOC_MODE" : "MXL_TUNER_MODE"); + + /* set device mode */ + ret = mxl111sf_write_reg(state, 0x03, + MXL_SOC_MODE == mode ? 0x01 : 0x00); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg_mask(state, + 0x7d, 0x40, MXL_SOC_MODE == mode ? + 0x00 : /* enable impulse noise filter, + INF_BYP = 0 */ + 0x40); /* disable impulse noise filter, + INF_BYP = 1 */ + if (mxl_fail(ret)) + goto fail; + + state->device_mode = mode; +fail: + return ret; +} + +/* power up tuner */ +int mxl1x1sf_top_master_ctrl(struct mxl111sf_state *state, int onoff) +{ + mxl_debug("(%d)", onoff); + + return mxl111sf_write_reg(state, 0x01, onoff ? 0x01 : 0x00); +} + +int mxl111sf_disable_656_port(struct mxl111sf_state *state) +{ + mxl_debug("()"); + + return mxl111sf_write_reg_mask(state, 0x12, 0x04, 0x00); +} + +int mxl111sf_enable_usb_output(struct mxl111sf_state *state) +{ + mxl_debug("()"); + + return mxl111sf_write_reg_mask(state, 0x17, 0x40, 0x00); +} + +/* initialize TSIF as input port of MxL1X1SF for MPEG2 data transfer */ +int mxl111sf_config_mpeg_in(struct mxl111sf_state *state, + unsigned int parallel_serial, + unsigned int msb_lsb_1st, + unsigned int clock_phase, + unsigned int mpeg_valid_pol, + unsigned int mpeg_sync_pol) +{ + int ret; + u8 mode, tmp; + + mxl_debug("(%u,%u,%u,%u,%u)", parallel_serial, msb_lsb_1st, + clock_phase, mpeg_valid_pol, mpeg_sync_pol); + + /* Enable PIN MUX */ + ret = mxl111sf_write_reg(state, V6_PIN_MUX_MODE_REG, V6_ENABLE_PIN_MUX); + mxl_fail(ret); + + /* Configure MPEG Clock phase */ + mxl111sf_read_reg(state, V6_MPEG_IN_CLK_INV_REG, &mode); + + if (clock_phase == TSIF_NORMAL) + mode &= ~V6_INVERTED_CLK_PHASE; + else + mode |= V6_INVERTED_CLK_PHASE; + + ret = mxl111sf_write_reg(state, V6_MPEG_IN_CLK_INV_REG, mode); + mxl_fail(ret); + + /* Configure data input mode, MPEG Valid polarity, MPEG Sync polarity + * Get current configuration */ + ret = mxl111sf_read_reg(state, V6_MPEG_IN_CTRL_REG, &mode); + mxl_fail(ret); + + /* Data Input mode */ + if (parallel_serial == TSIF_INPUT_PARALLEL) { + /* Disable serial mode */ + mode &= ~V6_MPEG_IN_DATA_SERIAL; + + /* Enable Parallel mode */ + mode |= V6_MPEG_IN_DATA_PARALLEL; + } else { + /* Disable Parallel mode */ + mode &= ~V6_MPEG_IN_DATA_PARALLEL; + + /* Enable Serial Mode */ + mode |= V6_MPEG_IN_DATA_SERIAL; + + /* If serial interface is chosen, configure + MSB or LSB order in transmission */ + ret = mxl111sf_read_reg(state, + V6_MPEG_INOUT_BIT_ORDER_CTRL_REG, + &tmp); + mxl_fail(ret); + + if (msb_lsb_1st == MPEG_SER_MSB_FIRST_ENABLED) + tmp |= V6_MPEG_SER_MSB_FIRST; + else + tmp &= ~V6_MPEG_SER_MSB_FIRST; + + ret = mxl111sf_write_reg(state, + V6_MPEG_INOUT_BIT_ORDER_CTRL_REG, + tmp); + mxl_fail(ret); + } + + /* MPEG Sync polarity */ + if (mpeg_sync_pol == TSIF_NORMAL) + mode &= ~V6_INVERTED_MPEG_SYNC; + else + mode |= V6_INVERTED_MPEG_SYNC; + + /* MPEG Valid polarity */ + if (mpeg_valid_pol == 0) + mode &= ~V6_INVERTED_MPEG_VALID; + else + mode |= V6_INVERTED_MPEG_VALID; + + ret = mxl111sf_write_reg(state, V6_MPEG_IN_CTRL_REG, mode); + mxl_fail(ret); + + return ret; +} + +int mxl111sf_init_i2s_port(struct mxl111sf_state *state, u8 sample_size) +{ + static struct mxl111sf_reg_ctrl_info init_i2s[] = { + {0x1b, 0xff, 0x1e}, /* pin mux mode, Choose 656/I2S input */ + {0x15, 0x60, 0x60}, /* Enable I2S */ + {0x17, 0xe0, 0x20}, /* Input, MPEG MODE USB, + Inverted 656 Clock, I2S_SOFT_RESET, + 0 : Normal operation, 1 : Reset State */ +#if 0 + {0x12, 0x01, 0x00}, /* AUDIO_IRQ_CLR (Overflow Indicator) */ +#endif + {0x00, 0xff, 0x02}, /* Change to Control Page */ + {0x26, 0x0d, 0x0d}, /* I2S_MODE & BT656_SRC_SEL for FPGA only */ + {0x00, 0xff, 0x00}, + {0, 0, 0} + }; + int ret; + + mxl_debug("(0x%02x)", sample_size); + + ret = mxl111sf_ctrl_program_regs(state, init_i2s); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, V6_I2S_NUM_SAMPLES_REG, sample_size); + mxl_fail(ret); +fail: + return ret; +} + +int mxl111sf_disable_i2s_port(struct mxl111sf_state *state) +{ + static struct mxl111sf_reg_ctrl_info disable_i2s[] = { + {0x15, 0x40, 0x00}, + {0, 0, 0} + }; + + mxl_debug("()"); + + return mxl111sf_ctrl_program_regs(state, disable_i2s); +} + +int mxl111sf_config_i2s(struct mxl111sf_state *state, + u8 msb_start_pos, u8 data_width) +{ + int ret; + u8 tmp; + + mxl_debug("(0x%02x, 0x%02x)", msb_start_pos, data_width); + + ret = mxl111sf_read_reg(state, V6_I2S_STREAM_START_BIT_REG, &tmp); + if (mxl_fail(ret)) + goto fail; + + tmp &= 0xe0; + tmp |= msb_start_pos; + ret = mxl111sf_write_reg(state, V6_I2S_STREAM_START_BIT_REG, tmp); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_read_reg(state, V6_I2S_STREAM_END_BIT_REG, &tmp); + if (mxl_fail(ret)) + goto fail; + + tmp &= 0xe0; + tmp |= data_width; + ret = mxl111sf_write_reg(state, V6_I2S_STREAM_END_BIT_REG, tmp); + mxl_fail(ret); +fail: + return ret; +} + +int mxl111sf_config_spi(struct mxl111sf_state *state, int onoff) +{ + u8 val; + int ret; + + mxl_debug("(%d)", onoff); + + ret = mxl111sf_write_reg(state, 0x00, 0x02); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_read_reg(state, V8_SPI_MODE_REG, &val); + if (mxl_fail(ret)) + goto fail; + + if (onoff) + val |= 0x04; + else + val &= ~0x04; + + ret = mxl111sf_write_reg(state, V8_SPI_MODE_REG, val); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_write_reg(state, 0x00, 0x00); + if (mxl_fail(ret)) + goto fail; +fail: + return ret; +} + +int mxl111sf_idac_config(struct mxl111sf_state *state, + u8 control_mode, u8 current_setting, + u8 current_value, u8 hysteresis_value) +{ + int ret; + u8 val; + /* current value will be set for both automatic & manual IDAC control */ + val = current_value; + + if (control_mode == IDAC_MANUAL_CONTROL) { + /* enable manual control of IDAC */ + val |= IDAC_MANUAL_CONTROL_BIT_MASK; + + if (current_setting == IDAC_CURRENT_SINKING_ENABLE) + /* enable current sinking in manual mode */ + val |= IDAC_CURRENT_SINKING_BIT_MASK; + else + /* disable current sinking in manual mode */ + val &= ~IDAC_CURRENT_SINKING_BIT_MASK; + } else { + /* disable manual control of IDAC */ + val &= ~IDAC_MANUAL_CONTROL_BIT_MASK; + + /* set hysteresis value reg: 0x0B<5:0> */ + ret = mxl111sf_write_reg(state, V6_IDAC_HYSTERESIS_REG, + (hysteresis_value & 0x3F)); + } + + ret = mxl111sf_write_reg(state, V6_IDAC_SETTINGS_REG, val); + + return val; +} + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-phy.h b/drivers/media/dvb/dvb-usb/mxl111sf-phy.h new file mode 100644 index 0000000..f075607 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/mxl111sf-phy.h @@ -0,0 +1,53 @@ +/* + * mxl111sf-phy.h - driver for the MaxLinear MXL111SF + * + * Copyright (C) 2010 Michael Krufky + * + * 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 of the License, 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. + */ + +#ifndef _DVB_USB_MXL111SF_PHY_H_ +#define _DVB_USB_MXL111SF_PHY_H_ + +#include "mxl111sf.h" + +int mxl1x1sf_soft_reset(struct mxl111sf_state *state); +int mxl1x1sf_set_device_mode(struct mxl111sf_state *state, int mode); +int mxl1x1sf_top_master_ctrl(struct mxl111sf_state *state, int onoff); +int mxl111sf_disable_656_port(struct mxl111sf_state *state); +int mxl111sf_init_tuner_demod(struct mxl111sf_state *state); +int mxl111sf_enable_usb_output(struct mxl111sf_state *state); +int mxl111sf_config_mpeg_in(struct mxl111sf_state *state, + unsigned int parallel_serial, + unsigned int msb_lsb_1st, + unsigned int clock_phase, + unsigned int mpeg_valid_pol, + unsigned int mpeg_sync_pol); +int mxl111sf_config_i2s(struct mxl111sf_state *state, + u8 msb_start_pos, u8 data_width); +int mxl111sf_init_i2s_port(struct mxl111sf_state *state, u8 sample_size); +int mxl111sf_disable_i2s_port(struct mxl111sf_state *state); +int mxl111sf_config_spi(struct mxl111sf_state *state, int onoff); +int mxl111sf_idac_config(struct mxl111sf_state *state, + u8 control_mode, u8 current_setting, + u8 current_value, u8 hysteresis_value); + +#endif /* _DVB_USB_MXL111SF_PHY_H_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-reg.h b/drivers/media/dvb/dvb-usb/mxl111sf-reg.h new file mode 100644 index 0000000..17831b0 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/mxl111sf-reg.h @@ -0,0 +1,179 @@ +/* + * mxl111sf-reg.h - driver for the MaxLinear MXL111SF + * + * Copyright (C) 2010 Michael Krufky + * + * 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 of the License, 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. + */ + +#ifndef _DVB_USB_MXL111SF_REG_H_ +#define _DVB_USB_MXL111SF_REG_H_ + +#define CHIP_ID_REG 0xFC +#define TOP_CHIP_REV_ID_REG 0xFA + +#define V6_SNR_RB_LSB_REG 0x27 +#define V6_SNR_RB_MSB_REG 0x28 + +#define V6_N_ACCUMULATE_REG 0x11 +#define V6_RS_AVG_ERRORS_LSB_REG 0x2C +#define V6_RS_AVG_ERRORS_MSB_REG 0x2D + +#define V6_IRQ_STATUS_REG 0x24 +#define IRQ_MASK_FEC_LOCK 0x10 + +#define V6_SYNC_LOCK_REG 0x28 +#define SYNC_LOCK_MASK 0x10 + +#define V6_RS_LOCK_DET_REG 0x28 +#define RS_LOCK_DET_MASK 0x08 + +#define V6_INITACQ_NODETECT_REG 0x20 +#define V6_FORCE_NFFT_CPSIZE_REG 0x20 + +#define V6_CODE_RATE_TPS_REG 0x29 +#define V6_CODE_RATE_TPS_MASK 0x07 + + +#define V6_CP_LOCK_DET_REG 0x28 +#define V6_CP_LOCK_DET_MASK 0x04 + +#define V6_TPS_HIERACHY_REG 0x29 +#define V6_TPS_HIERARCHY_INFO_MASK 0x40 + +#define V6_MODORDER_TPS_REG 0x2A +#define V6_PARAM_CONSTELLATION_MASK 0x30 + +#define V6_MODE_TPS_REG 0x2A +#define V6_PARAM_FFT_MODE_MASK 0x0C + + +#define V6_CP_TPS_REG 0x29 +#define V6_PARAM_GI_MASK 0x30 + +#define V6_TPS_LOCK_REG 0x2A +#define V6_PARAM_TPS_LOCK_MASK 0x40 + +#define V6_FEC_PER_COUNT_REG 0x2E +#define V6_FEC_PER_SCALE_REG 0x2B +#define V6_FEC_PER_SCALE_MASK 0x03 +#define V6_FEC_PER_CLR_REG 0x20 +#define V6_FEC_PER_CLR_MASK 0x01 + +#define V6_PIN_MUX_MODE_REG 0x1B +#define V6_ENABLE_PIN_MUX 0x1E + +#define V6_I2S_NUM_SAMPLES_REG 0x16 + +#define V6_MPEG_IN_CLK_INV_REG 0x17 +#define V6_MPEG_IN_CTRL_REG 0x18 + +#define V6_INVERTED_CLK_PHASE 0x20 +#define V6_MPEG_IN_DATA_PARALLEL 0x01 +#define V6_MPEG_IN_DATA_SERIAL 0x02 + +#define V6_INVERTED_MPEG_SYNC 0x04 +#define V6_INVERTED_MPEG_VALID 0x08 + +#define TSIF_INPUT_PARALLEL 0 +#define TSIF_INPUT_SERIAL 1 +#define TSIF_NORMAL 0 + +#define V6_MPEG_INOUT_BIT_ORDER_CTRL_REG 0x19 +#define V6_MPEG_SER_MSB_FIRST 0x80 +#define MPEG_SER_MSB_FIRST_ENABLED 0x01 + +#define V6_656_I2S_BUFF_STATUS_REG 0x2F +#define V6_656_OVERFLOW_MASK_BIT 0x08 +#define V6_I2S_OVERFLOW_MASK_BIT 0x01 + +#define V6_I2S_STREAM_START_BIT_REG 0x14 +#define V6_I2S_STREAM_END_BIT_REG 0x15 +#define I2S_RIGHT_JUSTIFIED 0 +#define I2S_LEFT_JUSTIFIED 1 +#define I2S_DATA_FORMAT 2 + +#define V6_TUNER_LOOP_THRU_CONTROL_REG 0x09 +#define V6_ENABLE_LOOP_THRU 0x01 + +#define TOTAL_NUM_IF_OUTPUT_FREQ 16 + +#define TUNER_NORMAL_IF_SPECTRUM 0x0 +#define TUNER_INVERT_IF_SPECTRUM 0x10 + +#define V6_TUNER_IF_SEL_REG 0x06 +#define V6_TUNER_IF_FCW_REG 0x3C +#define V6_TUNER_IF_FCW_BYP_REG 0x3D +#define V6_RF_LOCK_STATUS_REG 0x23 + +#define NUM_DIG_TV_CHANNEL 1000 + +#define V6_DIG_CLK_FREQ_SEL_REG 0x07 +#define V6_REF_SYNTH_INT_REG 0x5C +#define V6_REF_SYNTH_REMAIN_REG 0x58 +#define V6_DIG_RFREFSELECT_REG 0x32 +#define V6_XTAL_CLK_OUT_GAIN_REG 0x31 +#define V6_TUNER_LOOP_THRU_CTRL_REG 0x09 +#define V6_DIG_XTAL_ENABLE_REG 0x06 +#define V6_DIG_XTAL_BIAS_REG 0x66 +#define V6_XTAL_CAP_REG 0x08 + +#define V6_GPO_CTRL_REG 0x18 +#define MXL_GPO_0 0x00 +#define MXL_GPO_1 0x01 +#define V6_GPO_0_MASK 0x10 +#define V6_GPO_1_MASK 0x20 + +#define V6_111SF_GPO_CTRL_REG 0x19 +#define MXL_111SF_GPO_1 0x00 +#define MXL_111SF_GPO_2 0x01 +#define MXL_111SF_GPO_3 0x02 +#define MXL_111SF_GPO_4 0x03 +#define MXL_111SF_GPO_5 0x04 +#define MXL_111SF_GPO_6 0x05 +#define MXL_111SF_GPO_7 0x06 + +#define MXL_111SF_GPO_0_MASK 0x01 +#define MXL_111SF_GPO_1_MASK 0x02 +#define MXL_111SF_GPO_2_MASK 0x04 +#define MXL_111SF_GPO_3_MASK 0x08 +#define MXL_111SF_GPO_4_MASK 0x10 +#define MXL_111SF_GPO_5_MASK 0x20 +#define MXL_111SF_GPO_6_MASK 0x40 + +#define V6_ATSC_CONFIG_REG 0x0A + +#define MXL_MODE_REG 0x03 +#define START_TUNE_REG 0x1C + +#define V6_IDAC_HYSTERESIS_REG 0x0B +#define V6_IDAC_SETTINGS_REG 0x0C +#define IDAC_MANUAL_CONTROL 1 +#define IDAC_CURRENT_SINKING_ENABLE 1 +#define IDAC_MANUAL_CONTROL_BIT_MASK 0x80 +#define IDAC_CURRENT_SINKING_BIT_MASK 0x40 + +#define V8_SPI_MODE_REG 0xE9 + +#define V6_DIG_RF_PWR_LSB_REG 0x46 +#define V6_DIG_RF_PWR_MSB_REG 0x47 + +#endif /* _DVB_USB_MXL111SF_REG_H_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c b/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c new file mode 100644 index 0000000..a634105 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c @@ -0,0 +1,476 @@ +/* + * mxl111sf-tuner.c - driver for the MaxLinear MXL111SF CMOS tuner + * + * Copyright (C) 2010 Michael Krufky + * + * 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 of the License, 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 "mxl111sf-tuner.h" +#include "mxl111sf-phy.h" +#include "mxl111sf-reg.h" + +/* debug */ +static int mxl111sf_tuner_debug; +module_param_named(debug, mxl111sf_tuner_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); + +#define mxl_dbg(fmt, arg...) \ + if (mxl111sf_tuner_debug) \ + mxl_printk(KERN_DEBUG, fmt, ##arg) + +/* ------------------------------------------------------------------------ */ + +struct mxl111sf_tuner_state { + struct mxl111sf_state *mxl_state; + + struct mxl111sf_tuner_config *cfg; + + u32 frequency; + u32 bandwidth; +}; + +static int mxl111sf_tuner_read_reg(struct mxl111sf_tuner_state *state, + u8 addr, u8 *data) +{ + return (state->cfg->read_reg) ? + state->cfg->read_reg(state->mxl_state, addr, data) : + -EINVAL; +} + +static int mxl111sf_tuner_write_reg(struct mxl111sf_tuner_state *state, + u8 addr, u8 data) +{ + return (state->cfg->write_reg) ? + state->cfg->write_reg(state->mxl_state, addr, data) : + -EINVAL; +} + +static int mxl111sf_tuner_program_regs(struct mxl111sf_tuner_state *state, + struct mxl111sf_reg_ctrl_info *ctrl_reg_info) +{ + return (state->cfg->program_regs) ? + state->cfg->program_regs(state->mxl_state, ctrl_reg_info) : + -EINVAL; +} + +static int mxl1x1sf_tuner_top_master_ctrl(struct mxl111sf_tuner_state *state, + int onoff) +{ + return (state->cfg->top_master_ctrl) ? + state->cfg->top_master_ctrl(state->mxl_state, onoff) : + -EINVAL; +} + +/* ------------------------------------------------------------------------ */ + +static struct mxl111sf_reg_ctrl_info mxl_phy_tune_rf[] = { + {0x1d, 0x7f, 0x00}, /* channel bandwidth section 1/2/3, + DIG_MODEINDEX, _A, _CSF, */ + {0x1e, 0xff, 0x00}, /* channel frequency (lo and fractional) */ + {0x1f, 0xff, 0x00}, /* channel frequency (hi for integer portion) */ + {0, 0, 0} +}; + +/* ------------------------------------------------------------------------ */ + +static struct mxl111sf_reg_ctrl_info *mxl111sf_calc_phy_tune_regs(u32 freq, + u8 bw) +{ + u8 filt_bw; + + /* set channel bandwidth */ + switch (bw) { + case 0: /* ATSC */ + filt_bw = 25; + break; + case 1: /* QAM */ + filt_bw = 69; + break; + case 6: + filt_bw = 21; + break; + case 7: + filt_bw = 42; + break; + case 8: + filt_bw = 63; + break; + default: + err("%s: invalid bandwidth setting!", __func__); + return NULL; + } + + /* calculate RF channel */ + freq /= 1000000; + + freq *= 64; +#if 0 + /* do round */ + freq += 0.5; +#endif + /* set bandwidth */ + mxl_phy_tune_rf[0].data = filt_bw; + + /* set RF */ + mxl_phy_tune_rf[1].data = (freq & 0xff); + mxl_phy_tune_rf[2].data = (freq >> 8) & 0xff; + + /* start tune */ + return mxl_phy_tune_rf; +} + +static int mxl1x1sf_tuner_set_if_output_freq(struct mxl111sf_tuner_state *state) +{ + int ret; + u8 ctrl; +#if 0 + u16 iffcw; + u32 if_freq; +#endif + mxl_dbg("(IF polarity = %d, IF freq = 0x%02x)", + state->cfg->invert_spectrum, state->cfg->if_freq); + + /* set IF polarity */ + ctrl = state->cfg->invert_spectrum; + + ctrl |= state->cfg->if_freq; + + ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_SEL_REG, ctrl); + if (mxl_fail(ret)) + goto fail; + +#if 0 + if_freq /= 1000000; + + /* do round */ + if_freq += 0.5; + + if (MXL_IF_LO == state->cfg->if_freq) { + ctrl = 0x08; + iffcw = (u16)(if_freq / (108 * 4096)); + } else if (MXL_IF_HI == state->cfg->if_freq) { + ctrl = 0x08; + iffcw = (u16)(if_freq / (216 * 4096)); + } else { + ctrl = 0; + iffcw = 0; + } + + ctrl |= (iffcw >> 8); +#endif + ret = mxl111sf_tuner_read_reg(state, V6_TUNER_IF_FCW_BYP_REG, &ctrl); + if (mxl_fail(ret)) + goto fail; + + ctrl &= 0xf0; + ctrl |= 0x90; + + ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_BYP_REG, ctrl); + if (mxl_fail(ret)) + goto fail; + +#if 0 + ctrl = iffcw & 0x00ff; +#endif + ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_REG, ctrl); + mxl_fail(ret); +fail: + return ret; +} + +static int mxl1x1sf_tune_rf(struct dvb_frontend *fe, u32 freq, u8 bw) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + static struct mxl111sf_reg_ctrl_info *reg_ctrl_array; + int ret; + u8 mxl_mode; + + mxl_dbg("(freq = %d, bw = 0x%x)", freq, bw); + + /* stop tune */ + ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 0); + if (mxl_fail(ret)) + goto fail; + + /* check device mode */ + ret = mxl111sf_tuner_read_reg(state, MXL_MODE_REG, &mxl_mode); + if (mxl_fail(ret)) + goto fail; + + /* Fill out registers for channel tune */ + reg_ctrl_array = mxl111sf_calc_phy_tune_regs(freq, bw); + if (!reg_ctrl_array) + return -EINVAL; + + ret = mxl111sf_tuner_program_regs(state, reg_ctrl_array); + if (mxl_fail(ret)) + goto fail; + + if ((mxl_mode & MXL_DEV_MODE_MASK) == MXL_TUNER_MODE) { + /* IF tuner mode only */ + mxl1x1sf_tuner_top_master_ctrl(state, 0); + mxl1x1sf_tuner_top_master_ctrl(state, 1); + mxl1x1sf_tuner_set_if_output_freq(state); + } + + ret = mxl111sf_tuner_write_reg(state, START_TUNE_REG, 1); + if (mxl_fail(ret)) + goto fail; + + if (state->cfg->ant_hunt) + state->cfg->ant_hunt(fe); +fail: + return ret; +} + +static int mxl1x1sf_tuner_get_lock_status(struct mxl111sf_tuner_state *state, + int *rf_synth_lock, + int *ref_synth_lock) +{ + int ret; + u8 data; + + *rf_synth_lock = 0; + *ref_synth_lock = 0; + + ret = mxl111sf_tuner_read_reg(state, V6_RF_LOCK_STATUS_REG, &data); + if (mxl_fail(ret)) + goto fail; + + *ref_synth_lock = ((data & 0x03) == 0x03) ? 1 : 0; + *rf_synth_lock = ((data & 0x0c) == 0x0c) ? 1 : 0; +fail: + return ret; +} + +#if 0 +static int mxl1x1sf_tuner_loop_thru_ctrl(struct mxl111sf_tuner_state *state, + int onoff) +{ + return mxl111sf_tuner_write_reg(state, V6_TUNER_LOOP_THRU_CTRL_REG, + onoff ? 1 : 0); +} +#endif + +/* ------------------------------------------------------------------------ */ + +static int mxl111sf_tuner_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + int ret; + u8 bw; + + mxl_dbg("()"); + + if (fe->ops.info.type == FE_ATSC) { + switch (params->u.vsb.modulation) { + case VSB_8: + case VSB_16: + bw = 0; /* ATSC */ + break; + case QAM_64: + case QAM_256: + bw = 1; /* US CABLE */ + break; + default: + err("%s: modulation not set!", __func__); + return -EINVAL; + } + } else if (fe->ops.info.type == FE_OFDM) { + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + bw = 6; + break; + case BANDWIDTH_7_MHZ: + bw = 7; + break; + case BANDWIDTH_8_MHZ: + bw = 8; + break; + default: + err("%s: bandwidth not set!", __func__); + return -EINVAL; + } + } else { + err("%s: modulation type not supported!", __func__); + return -EINVAL; + } + ret = mxl1x1sf_tune_rf(fe, params->frequency, bw); + if (mxl_fail(ret)) + goto fail; + + state->frequency = params->frequency; + state->bandwidth = (fe->ops.info.type == FE_OFDM) ? + params->u.ofdm.bandwidth : 0; +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +#if 0 +static int mxl111sf_tuner_init(struct dvb_frontend *fe) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + int ret; + + /* wake from standby handled by usb driver */ + + return ret; +} + +static int mxl111sf_tuner_sleep(struct dvb_frontend *fe) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + int ret; + + /* enter standby mode handled by usb driver */ + + return ret; +} +#endif + +/* ------------------------------------------------------------------------ */ + +static int mxl111sf_tuner_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + int rf_locked, ref_locked, ret; + + *status = 0; + + ret = mxl1x1sf_tuner_get_lock_status(state, &rf_locked, &ref_locked); + if (mxl_fail(ret)) + goto fail; + mxl_info("%s%s", rf_locked ? "rf locked " : "", + ref_locked ? "ref locked" : ""); + + if ((rf_locked) || (ref_locked)) + *status |= TUNER_STATUS_LOCKED; +fail: + return ret; +} + +static int mxl111sf_get_rf_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + u8 val1, val2; + int ret; + + *strength = 0; + + ret = mxl111sf_tuner_write_reg(state, 0x00, 0x02); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_LSB_REG, &val1); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_tuner_read_reg(state, V6_DIG_RF_PWR_MSB_REG, &val2); + if (mxl_fail(ret)) + goto fail; + + *strength = val1 | ((val2 & 0x07) << 8); +fail: + ret = mxl111sf_tuner_write_reg(state, 0x00, 0x00); + mxl_fail(ret); + + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static int mxl111sf_tuner_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + *frequency = state->frequency; + return 0; +} + +static int mxl111sf_tuner_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + *bandwidth = state->bandwidth; + return 0; +} + +static int mxl111sf_tuner_release(struct dvb_frontend *fe) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + mxl_dbg("()"); + kfree(state); + fe->tuner_priv = NULL; + return 0; +} + +/* ------------------------------------------------------------------------- */ + +static struct dvb_tuner_ops mxl111sf_tuner_tuner_ops = { + .info = { + .name = "MaxLinear MxL111SF", +#if 0 + .frequency_min = , + .frequency_max = , + .frequency_step = , +#endif + }, +#if 0 + .init = mxl111sf_tuner_init, + .sleep = mxl111sf_tuner_sleep, +#endif + .set_params = mxl111sf_tuner_set_params, + .get_status = mxl111sf_tuner_get_status, + .get_rf_strength = mxl111sf_get_rf_strength, + .get_frequency = mxl111sf_tuner_get_frequency, + .get_bandwidth = mxl111sf_tuner_get_bandwidth, + .release = mxl111sf_tuner_release, +}; + +struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe, + struct mxl111sf_state *mxl_state, + struct mxl111sf_tuner_config *cfg) +{ + struct mxl111sf_tuner_state *state = NULL; + + mxl_dbg("()"); + + state = kzalloc(sizeof(struct mxl111sf_tuner_state), GFP_KERNEL); + if (state == NULL) + return NULL; + + state->mxl_state = mxl_state; + state->cfg = cfg; + + memcpy(&fe->ops.tuner_ops, &mxl111sf_tuner_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = state; + return fe; +} +EXPORT_SYMBOL_GPL(mxl111sf_tuner_attach); + +MODULE_DESCRIPTION("MaxLinear MxL111SF CMOS tuner driver"); +MODULE_AUTHOR("Michael Krufky "); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.1"); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.h b/drivers/media/dvb/dvb-usb/mxl111sf-tuner.h new file mode 100644 index 0000000..ff33396 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/mxl111sf-tuner.h @@ -0,0 +1,89 @@ +/* + * mxl111sf-tuner.h - driver for the MaxLinear MXL111SF CMOS tuner + * + * Copyright (C) 2010 Michael Krufky + * + * 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 of the License, 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. + */ + +#ifndef __MXL111SF_TUNER_H__ +#define __MXL111SF_TUNER_H__ + +#include "dvb_frontend.h" + +#include "mxl111sf.h" + +enum mxl_if_freq { +#if 0 + MXL_IF_LO = 0x00, /* other IF < 9MHz */ +#endif + MXL_IF_4_0 = 0x01, /* 4.0 MHz */ + MXL_IF_4_5 = 0x02, /* 4.5 MHz */ + MXL_IF_4_57 = 0x03, /* 4.57 MHz */ + MXL_IF_5_0 = 0x04, /* 5.0 MHz */ + MXL_IF_5_38 = 0x05, /* 5.38 MHz */ + MXL_IF_6_0 = 0x06, /* 6.0 MHz */ + MXL_IF_6_28 = 0x07, /* 6.28 MHz */ + MXL_IF_7_2 = 0x08, /* 7.2 MHz */ + MXL_IF_35_25 = 0x09, /* 35.25 MHz */ + MXL_IF_36 = 0x0a, /* 36 MHz */ + MXL_IF_36_15 = 0x0b, /* 36.15 MHz */ + MXL_IF_44 = 0x0c, /* 44 MHz */ +#if 0 + MXL_IF_HI = 0x0f, /* other IF > 35 MHz and < 45 MHz */ +#endif +}; + +struct mxl111sf_tuner_config { + enum mxl_if_freq if_freq; + unsigned int invert_spectrum:1; + + int (*read_reg)(struct mxl111sf_state *state, u8 addr, u8 *data); + int (*write_reg)(struct mxl111sf_state *state, u8 addr, u8 data); + int (*program_regs)(struct mxl111sf_state *state, + struct mxl111sf_reg_ctrl_info *ctrl_reg_info); + int (*top_master_ctrl)(struct mxl111sf_state *state, int onoff); + int (*ant_hunt)(struct dvb_frontend *fe); +}; + +/* ------------------------------------------------------------------------ */ + +#if defined(CONFIG_DVB_USB_MXL111SF) || \ + (defined(CONFIG_DVB_USB_MXL111SF_MODULE) && defined(MODULE)) +extern +struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe, + struct mxl111sf_state *mxl_state, + struct mxl111sf_tuner_config *cfg); +#else +static inline +struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe, + struct mxl111sf_state *mxl_state + struct mxl111sf_tuner_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* __MXL111SF_TUNER_H__ */ + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ + diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.c b/drivers/media/dvb/dvb-usb/mxl111sf.c new file mode 100644 index 0000000..3da452a --- /dev/null +++ b/drivers/media/dvb/dvb-usb/mxl111sf.c @@ -0,0 +1,854 @@ +/* + * Copyright (C) 2010 Michael Krufky (mkrufky@kernellabs.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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ + +#include +#include + +#include "mxl111sf.h" +#include "mxl111sf-reg.h" +#include "mxl111sf-phy.h" +#include "mxl111sf-i2c.h" +#include "mxl111sf-gpio.h" + +#include "mxl111sf-tuner.h" + +#include "lgdt3305.h" + +int dvb_usb_mxl111sf_debug; +module_param_named(debug, dvb_usb_mxl111sf_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level " + "(1=info, 2=xfer, 4=i2c, 8=reg, 16=adv (or-able))."); + +int dvb_usb_mxl111sf_isoc; +module_param_named(isoc, dvb_usb_mxl111sf_isoc, int, 0644); +MODULE_PARM_DESC(isoc, "enable usb isoc xfer (0=bulk, 1=isoc)."); + +#define ANT_PATH_AUTO 0 +#define ANT_PATH_EXTERNAL 1 +#define ANT_PATH_INTERNAL 2 + +int dvb_usb_mxl111sf_rfswitch = +#if 0 + ANT_PATH_AUTO; +#else + ANT_PATH_EXTERNAL; +#endif + +module_param_named(rfswitch, dvb_usb_mxl111sf_rfswitch, int, 0644); +MODULE_PARM_DESC(rfswitch, "force rf switch position (0=auto, 1=ext, 2=int)."); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define deb_info(args...) dprintk(dvb_usb_mxl111sf_debug, 0x13, args) +#define deb_reg(args...) dprintk(dvb_usb_mxl111sf_debug, 0x08, args) +#define deb_adv(args...) dprintk(dvb_usb_mxl111sf_debug, MXL_ADV_DBG, args) + +int mxl111sf_ctrl_msg(struct dvb_usb_device *d, + u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen) +{ + int wo = (rbuf == NULL || rlen == 0); /* write-only */ + int ret; + u8 sndbuf[1+wlen]; + + deb_adv("%s(wlen = %d, rlen = %d)\n", __func__, wlen, rlen); + + memset(sndbuf, 0, 1+wlen); + + sndbuf[0] = cmd; + memcpy(&sndbuf[1], wbuf, wlen); + + ret = (wo) ? dvb_usb_generic_write(d, sndbuf, 1+wlen) : + dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0); + mxl_fail(ret); + + return ret; +} + +/* ------------------------------------------------------------------------ */ + +#define MXL_CMD_REG_READ 0xaa +#define MXL_CMD_REG_WRITE 0x55 + +int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data) +{ + u8 buf[2]; + int ret; + + ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_READ, &addr, 1, buf, 2); + if (mxl_fail(ret)) { + mxl_debug("error reading reg: 0x%02x", addr); + goto fail; + } + + if (buf[0] == addr) + *data = buf[1]; + else { + err("invalid response reading reg: 0x%02x != 0x%02x, 0x%02x", + addr, buf[0], buf[1]); + ret = -EINVAL; + } + + deb_reg("R: (0x%02x, 0x%02x)\n", addr, *data); +fail: + return ret; +} + +int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data) +{ + u8 buf[] = { addr, data }; + int ret; + + deb_reg("W: (0x%02x, 0x%02x)\n", addr, data); + + ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_WRITE, buf, 2, NULL, 0); + if (mxl_fail(ret)) + err("error writing reg: 0x%02x, val: 0x%02x", addr, data); + return ret; +} + +/* ------------------------------------------------------------------------ */ + +int mxl111sf_write_reg_mask(struct mxl111sf_state *state, + u8 addr, u8 mask, u8 data) +{ + int ret; + u8 val; + + if (mask != 0xff) { + ret = mxl111sf_read_reg(state, addr, &val); +#if 1 + /* dont know why this usually errors out on the first try */ + if (mxl_fail(ret)) + err("error writing addr: 0x%02x, mask: 0x%02x, " + "data: 0x%02x, retrying...", addr, mask, data); + + ret = mxl111sf_read_reg(state, addr, &val); +#endif + if (mxl_fail(ret)) + goto fail; + } + val &= ~mask; + val |= data; + + ret = mxl111sf_write_reg(state, addr, val); + mxl_fail(ret); +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state, + struct mxl111sf_reg_ctrl_info *ctrl_reg_info) +{ + int i, ret = 0; + + for (i = 0; ctrl_reg_info[i].addr | + ctrl_reg_info[i].mask | + ctrl_reg_info[i].data; i++) { + + ret = mxl111sf_write_reg_mask(state, + ctrl_reg_info[i].addr, + ctrl_reg_info[i].mask, + ctrl_reg_info[i].data); + if (mxl_fail(ret)) { + err("failed on reg #%d (0x%02x)", i, + ctrl_reg_info[i].addr); + break; + } + } + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static int mxl1x1sf_get_chip_info(struct mxl111sf_state *state) +{ + int ret; + u8 id, ver; + char *mxl_chip, *mxl_rev; + + if ((state->chip_id) && (state->chip_ver)) + return 0; + + ret = mxl111sf_read_reg(state, CHIP_ID_REG, &id); + if (mxl_fail(ret)) + goto fail; + state->chip_id = id; + + ret = mxl111sf_read_reg(state, TOP_CHIP_REV_ID_REG, &ver); + if (mxl_fail(ret)) + goto fail; + state->chip_ver = ver; + + switch (id) { + case 0x61: + mxl_chip = "MxL101SF"; + break; + case 0x63: + mxl_chip = "MxL111SF"; + break; + default: + mxl_chip = "UNKNOWN MxL1X1"; + break; + } + switch (ver) { + case 0x36: + state->chip_rev = MXL111SF_V6; + mxl_rev = "v6"; + break; + case 0x08: + state->chip_rev = MXL111SF_V8_100; + mxl_rev = "v8_100"; + break; + case 0x18: + state->chip_rev = MXL111SF_V8_200; + mxl_rev = "v8_200"; + break; + default: + state->chip_rev = 0; + mxl_rev = "UNKNOWN REVISION"; + break; + } + info("%s detected, %s (0x%x)", mxl_chip, mxl_rev, ver); +fail: + return ret; +} + +#define get_chip_info(state) \ +({ \ + int ___ret; \ + ___ret = mxl1x1sf_get_chip_info(state); \ + if (mxl_fail(___ret)) { \ + mxl_debug("failed to get chip info" \ + " on first probe attempt"); \ + ___ret = mxl1x1sf_get_chip_info(state); \ + if (mxl_fail(___ret)) \ + err("failed to get chip info during probe"); \ + else \ + mxl_debug("probe needed a retry " \ + "in order to succeed."); \ + } \ + ___ret; \ +}) + +/* ------------------------------------------------------------------------ */ + +static int mxl111sf_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + /* power control depends on which adapter is being woken: + * save this for init, instead, via mxl111sf_adap_fe_init */ + return 0; +} + +static int mxl111sf_adap_fe_init(struct dvb_frontend *fe) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dvb_usb_device *d = adap->dev; + struct mxl111sf_state *state = d->priv; + struct mxl111sf_adap_state *adap_state = adap->priv; + int err; + + /* exit if we didnt initialize the driver yet */ + if (!state->chip_id) { + mxl_debug("driver not yet initialized, exit."); + goto fail; + } + + deb_info("%s()\n", __func__); + + mutex_lock(&state->fe_lock); + + state->alt_mode = adap_state->alt_mode; + + if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0) + err("set interface failed"); + + err = mxl1x1sf_soft_reset(state); + mxl_fail(err); + err = mxl111sf_init_tuner_demod(state); + mxl_fail(err); + err = mxl1x1sf_set_device_mode(state, adap_state->device_mode); + + mxl_fail(err); + mxl111sf_enable_usb_output(state); + mxl_fail(err); + mxl1x1sf_top_master_ctrl(state, 1); + mxl_fail(err); + + if ((MXL111SF_GPIO_MOD_DVBT != adap_state->gpio_mode) && + (state->chip_rev > MXL111SF_V6)) { + mxl111sf_config_pin_mux_modes(state, + PIN_MUX_TS_SPI_IN_MODE_1); + mxl_fail(err); + } + err = mxl111sf_init_port_expander(state); + if (!mxl_fail(err)) { + state->gpio_mode = adap_state->gpio_mode; + err = mxl111sf_gpio_mode_switch(state, state->gpio_mode); + mxl_fail(err); +#if 0 + err = fe->ops.init(fe); +#endif + msleep(100); /* add short delay after enabling + * the demod before touching it */ + } + + return (adap_state->fe_init) ? adap_state->fe_init(fe) : 0; +fail: + return -ENODEV; +} + +static int mxl111sf_adap_fe_sleep(struct dvb_frontend *fe) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dvb_usb_device *d = adap->dev; + struct mxl111sf_state *state = d->priv; + struct mxl111sf_adap_state *adap_state = adap->priv; + int err; + + /* exit if we didnt initialize the driver yet */ + if (!state->chip_id) { + mxl_debug("driver not yet initialized, exit."); + goto fail; + } + + deb_info("%s()\n", __func__); + + err = (adap_state->fe_sleep) ? adap_state->fe_sleep(fe) : 0; + + mutex_unlock(&state->fe_lock); + + return err; +fail: + return -ENODEV; +} + + +static int mxl111sf_ep6_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + struct dvb_usb_device *d = adap->dev; + struct mxl111sf_state *state = d->priv; + struct mxl111sf_adap_state *adap_state = adap->priv; + int ret = 0; + u8 tmp; + + deb_info("%s(%d)\n", __func__, onoff); + + if (onoff) { + ret = mxl111sf_enable_usb_output(state); + mxl_fail(ret); + ret = mxl111sf_config_mpeg_in(state, 1, 1, + adap_state->ep6_clockphase, + 0, 0); + mxl_fail(ret); + } else { + ret = mxl111sf_disable_656_port(state); + mxl_fail(ret); + } + + mxl111sf_read_reg(state, 0x12, &tmp); + tmp &= ~0x04; + mxl111sf_write_reg(state, 0x12, tmp); + + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static struct lgdt3305_config hauppauge_lgdt3305_config = { + .i2c_addr = 0xb2 >> 1, + .mpeg_mode = LGDT3305_MPEG_SERIAL, + .tpclk_edge = LGDT3305_TPCLK_RISING_EDGE, + .tpvalid_polarity = LGDT3305_TP_VALID_HIGH, + .deny_i2c_rptr = 1, + .spectral_inversion = 0, + .qam_if_khz = 6000, + .vsb_if_khz = 6000, +}; + +static int mxl111sf_lgdt3305_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap->dev; + struct mxl111sf_state *state = d->priv; + struct mxl111sf_adap_state *adap_state = adap->priv; + int ret; + + deb_adv("%s()\n", __func__); + + /* save a pointer to the dvb_usb_device in device state */ + state->d = d; + adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1; + state->alt_mode = adap_state->alt_mode; + + if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0) + err("set interface failed"); + + state->gpio_mode = MXL111SF_GPIO_MOD_ATSC; + adap_state->gpio_mode = state->gpio_mode; + adap_state->device_mode = MXL_TUNER_MODE; + adap_state->ep6_clockphase = 1; + + ret = mxl1x1sf_soft_reset(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_init_tuner_demod(state); + if (mxl_fail(ret)) + goto fail; + + ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_enable_usb_output(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl1x1sf_top_master_ctrl(state, 1); + if (mxl_fail(ret)) + goto fail; + + ret = mxl111sf_init_port_expander(state); + if (mxl_fail(ret)) + goto fail; + ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode); + if (mxl_fail(ret)) + goto fail; + + adap->fe[0] = dvb_attach(lgdt3305_attach, + &hauppauge_lgdt3305_config, + &adap->dev->i2c_adap); + if (adap->fe[0]) { + adap_state->fe_init = adap->fe[0]->ops.init; + adap->fe[0]->ops.init = mxl111sf_adap_fe_init; + adap_state->fe_sleep = adap->fe[0]->ops.sleep; + adap->fe[0]->ops.sleep = mxl111sf_adap_fe_sleep; + return 0; + } + ret = -EIO; +fail: + return ret; +} + +static inline int mxl111sf_set_ant_path(struct mxl111sf_state *state, + int antpath) +{ + return mxl111sf_idac_config(state, 1, 1, + (antpath == ANT_PATH_INTERNAL) ? + 0x3f : 0x00, 0); +} + +#define DbgAntHunt(x, pwr0, pwr1, pwr2, pwr3) \ + err("%s(%d) FINAL input set to %s rxPwr:%d|%d|%d|%d\n", \ + __func__, __LINE__, \ + (ANT_PATH_EXTERNAL == x) ? "EXTERNAL" : "INTERNAL", \ + pwr0, pwr1, pwr2, pwr3) + +#define ANT_HUNT_SLEEP 90 +#define ANT_EXT_TWEAK 0 + +static int mxl111sf_ant_hunt(struct dvb_frontend *fe) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dvb_usb_device *d = adap->dev; + struct mxl111sf_state *state = d->priv; + + int antctrl = dvb_usb_mxl111sf_rfswitch; + + u16 rxPwrA, rxPwr0, rxPwr1, rxPwr2; + + /* FIXME: must force EXTERNAL for QAM - done elsewhere */ + mxl111sf_set_ant_path(state, antctrl == ANT_PATH_AUTO ? + ANT_PATH_EXTERNAL : antctrl); + + if (antctrl == ANT_PATH_AUTO) { +#if 0 + msleep(ANT_HUNT_SLEEP); +#endif + fe->ops.tuner_ops.get_rf_strength(fe, &rxPwrA); + + mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL); + msleep(ANT_HUNT_SLEEP); + fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr0); + + mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL); + msleep(ANT_HUNT_SLEEP); + fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr1); + + mxl111sf_set_ant_path(state, ANT_PATH_INTERNAL); + msleep(ANT_HUNT_SLEEP); + fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr2); + + if (rxPwr1+ANT_EXT_TWEAK >= rxPwr2) { + /* return with EXTERNAL enabled */ + mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL); + DbgAntHunt(ANT_PATH_EXTERNAL, rxPwrA, + rxPwr0, rxPwr1, rxPwr2); + } else { + /* return with INTERNAL enabled */ + DbgAntHunt(ANT_PATH_INTERNAL, rxPwrA, + rxPwr0, rxPwr1, rxPwr2); + } + } + return 0; +} + +static struct mxl111sf_tuner_config mxl_tuner_config = { + .if_freq = MXL_IF_6_0, /* applies to external IF output, only */ + .invert_spectrum = 0, + .read_reg = mxl111sf_read_reg, + .write_reg = mxl111sf_write_reg, + .program_regs = mxl111sf_ctrl_program_regs, + .top_master_ctrl = mxl1x1sf_top_master_ctrl, + .ant_hunt = mxl111sf_ant_hunt, +}; + +static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap->dev; + struct mxl111sf_state *state = d->priv; + + deb_adv("%s()\n", __func__); + + if (NULL != dvb_attach(mxl111sf_tuner_attach, adap->fe[0], state, + &mxl_tuner_config)) + return 0; + + return -EIO; +} + +static int mxl111sf_fe_ioctl_override(struct dvb_frontend *fe, + unsigned int cmd, void *parg, + unsigned int stage) +{ + int err = 0; + + switch (stage) { + case DVB_FE_IOCTL_PRE: + + switch (cmd) { + case FE_READ_SIGNAL_STRENGTH: + err = fe->ops.tuner_ops.get_rf_strength(fe, parg); + /* If no error occurs, prevent dvb-core from handling + * this IOCTL, otherwise return the error */ + if (0 == err) + err = 1; + break; + } + break; + + case DVB_FE_IOCTL_POST: + /* no post-ioctl handling required */ + break; + } + return err; +}; + +static u32 mxl111sf_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +struct i2c_algorithm mxl111sf_i2c_algo = { + .master_xfer = mxl111sf_i2c_xfer, + .functionality = mxl111sf_i2c_func, +#ifdef NEED_ALGO_CONTROL + .algo_control = dummy_algo_control, +#endif +}; + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties; +static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties; + +static int mxl111sf_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct dvb_usb_device *d = NULL; + + deb_adv("%s()\n", __func__); + + if (((dvb_usb_mxl111sf_isoc) && + (0 == dvb_usb_device_init(intf, + &mxl111sf_atsc_isoc_properties, + THIS_MODULE, &d, adapter_nr))) || + 0 == dvb_usb_device_init(intf, + &mxl111sf_atsc_bulk_properties, + THIS_MODULE, &d, adapter_nr) || 0) { + + struct mxl111sf_state *state = d->priv; + static u8 eeprom[256]; + struct i2c_client c; + int ret; + + ret = get_chip_info(state); + if (mxl_fail(ret)) + err("failed to get chip info during probe"); + + mutex_init(&state->fe_lock); + + if (state->chip_rev > MXL111SF_V6) + mxl111sf_config_pin_mux_modes(state, + PIN_MUX_TS_SPI_IN_MODE_1); + + c.adapter = &d->i2c_adap; + c.addr = 0xa0 >> 1; + + ret = tveeprom_read(&c, eeprom, sizeof(eeprom)); + if (mxl_fail(ret)) + return 0; + tveeprom_hauppauge_analog(&c, &state->tv, + (0x84 == eeprom[0xa0]) ? + eeprom + 0xa0 : eeprom + 0x80); +#if 0 + switch (state->tv.model) { + case 117001: + case 126001: + case 138001: + break; + default: + printk(KERN_WARNING "%s: warning: " + "unknown hauppauge model #%d\n", + __func__, state->tv.model); + } +#endif + return 0; + } + err("Your device is not yet supported by this driver. " + "See kernellabs.com for more info"); + return -EINVAL; +} + +static struct usb_device_id mxl111sf_table[] = { +/* 0 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc600) }, /* ATSC+ IR */ + { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc601) }, /* ATSC */ + { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc602) }, /* + */ + { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc603) }, /* ATSC+ */ + { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc604) }, /* DVBT */ +/* 5 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc609) }, /* ATSC IR */ + { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60a) }, /* + IR */ + { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60b) }, /* ATSC+ IR */ + { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60c) }, /* DVBT IR */ + { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc653) }, /* ATSC+ */ +/*10 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc65b) }, /* ATSC+ IR */ + { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb700) }, /* ATSC+ sw */ + { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb701) }, /* ATSC sw */ + { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb702) }, /* + sw */ + { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb703) }, /* ATSC+ sw */ +/*15 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb704) }, /* DVBT sw */ + { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb753) }, /* ATSC+ sw */ + { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb763) }, /* ATSC+ no */ + { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb764) }, /* DVBT no */ + { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd853) }, /* ATSC+ sw */ +/*20 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd854) }, /* DVBT sw */ + { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd863) }, /* ATSC+ no */ + { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd864) }, /* DVBT no */ + { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d3) }, /* ATSC+ sw */ + { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d4) }, /* DVBT sw */ +/*25 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e3) }, /* ATSC+ no */ + { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e4) }, /* DVBT no */ + { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8ff) }, /* ATSC+ */ + { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc612) }, /* + */ + { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc613) }, /* ATSC+ */ +/*30 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61a) }, /* + IR */ + { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61b) }, /* ATSC+ IR */ + { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb757) }, /* ATSC+DVBT sw */ + { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb767) }, /* ATSC+DVBT no */ + {} /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, mxl111sf_table); + + +#define MXL111SF_EP6_BULK_STREAMING_CONFIG \ + .streaming_ctrl = mxl111sf_ep6_streaming_ctrl, \ + .stream = { \ + .type = USB_BULK, \ + .count = 5, \ + .endpoint = 0x06, \ + .u = { \ + .bulk = { \ + .buffersize = 8192, \ + } \ + } \ + } + +/* FIXME */ +#define MXL111SF_EP6_ISOC_STREAMING_CONFIG \ + .streaming_ctrl = mxl111sf_ep6_streaming_ctrl, \ + .stream = { \ + .type = USB_ISOC, \ + .count = 5, \ + .endpoint = 0x06, \ + .u = { \ + .isoc = { \ + .framesperurb = 24, \ + .framesize = 3072, \ + .interval = 1, \ + } \ + } \ + } + +#define MXL111SF_DEFAULT_DEVICE_PROPERTIES \ + .caps = DVB_USB_IS_AN_I2C_ADAPTER, \ + .usb_ctrl = DEVICE_SPECIFIC, \ + /* use usb alt setting 1 for EP4 ISOC transfer (dvb-t), \ + EP6 BULK transfer (atsc/qam), \ + use usb alt setting 2 for EP4 BULK transfer (dvb-t), \ + EP6 ISOC transfer (atsc/qam), \ + */ \ + .power_ctrl = mxl111sf_power_ctrl, \ + .i2c_algo = &mxl111sf_i2c_algo, \ + .generic_bulk_ctrl_endpoint = MXL_EP2_REG_WRITE, \ + .generic_bulk_ctrl_endpoint_response = MXL_EP1_REG_READ, \ + .size_of_priv = sizeof(struct mxl111sf_state) + +static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = { + MXL111SF_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .size_of_priv = sizeof(struct mxl111sf_adap_state), + .fe_ioctl_override = mxl111sf_fe_ioctl_override, + + .frontend_attach = mxl111sf_lgdt3305_frontend_attach, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP6_BULK_STREAMING_CONFIG, + }, + }, + .num_device_descs = 6, + .devices = { + { "Hauppauge 126xxx ATSC (bulk)", + { NULL }, + { &mxl111sf_table[1], &mxl111sf_table[5], + NULL }, + }, + { "Hauppauge 117xxx ATSC (bulk)", + { NULL }, + { &mxl111sf_table[12], + NULL }, + }, + { "Hauppauge 126xxx ATSC+ (bulk)", + { NULL }, + { &mxl111sf_table[0], &mxl111sf_table[3], + &mxl111sf_table[7], &mxl111sf_table[9], + &mxl111sf_table[10], NULL }, + }, + { "Hauppauge 117xxx ATSC+ (bulk)", + { NULL }, + { &mxl111sf_table[11], &mxl111sf_table[14], + &mxl111sf_table[16], &mxl111sf_table[17], + &mxl111sf_table[32], &mxl111sf_table[33], + NULL }, + }, + { "Hauppauge Mercury (tp-bulk)", + { NULL }, + { &mxl111sf_table[19], &mxl111sf_table[21], + &mxl111sf_table[23], &mxl111sf_table[25], + &mxl111sf_table[27], NULL }, + }, + { "Hauppauge WinTV-Aero-M", + { NULL }, + { &mxl111sf_table[29], &mxl111sf_table[31], + NULL }, + }, + } +}; + +static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = { + MXL111SF_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .size_of_priv = sizeof(struct mxl111sf_adap_state), + .fe_ioctl_override = mxl111sf_fe_ioctl_override, + + .frontend_attach = mxl111sf_lgdt3305_frontend_attach, + .tuner_attach = mxl111sf_attach_tuner, + + MXL111SF_EP6_ISOC_STREAMING_CONFIG, + }, + }, + .num_device_descs = 6, + .devices = { + { "Hauppauge 126xxx ATSC (isoc)", + { NULL }, + { &mxl111sf_table[1], &mxl111sf_table[5], + NULL }, + }, + { "Hauppauge 117xxx ATSC (isoc)", + { NULL }, + { &mxl111sf_table[12], + NULL }, + }, + { "Hauppauge 126xxx ATSC+ (isoc)", + { NULL }, + { &mxl111sf_table[0], &mxl111sf_table[3], + &mxl111sf_table[7], &mxl111sf_table[9], + &mxl111sf_table[10], NULL }, + }, + { "Hauppauge 117xxx ATSC+ (isoc)", + { NULL }, + { &mxl111sf_table[11], &mxl111sf_table[14], + &mxl111sf_table[16], &mxl111sf_table[17], + &mxl111sf_table[32], &mxl111sf_table[33], + NULL }, + }, + { "Hauppauge Mercury (tp-isoc)", + { NULL }, + { &mxl111sf_table[19], &mxl111sf_table[21], + &mxl111sf_table[23], &mxl111sf_table[25], + &mxl111sf_table[27], NULL }, + }, + { "Hauppauge WinTV-Aero-M (tp-isoc)", + { NULL }, + { &mxl111sf_table[29], &mxl111sf_table[31], + NULL }, + }, + } +}; + +static struct usb_driver mxl111sf_driver = { + .name = "dvb_usb_mxl111sf", + .probe = mxl111sf_probe, + .disconnect = dvb_usb_device_exit, + .id_table = mxl111sf_table, +}; + +static int __init mxl111sf_module_init(void) +{ + int result = usb_register(&mxl111sf_driver); + if (result) { + err("usb_register failed. Error number %d", result); + return result; + } + + return 0; +} + +static void __exit mxl111sf_module_exit(void) +{ + usb_deregister(&mxl111sf_driver); +} + +module_init(mxl111sf_module_init); +module_exit(mxl111sf_module_exit); + +MODULE_AUTHOR("Michael Krufky "); +MODULE_DESCRIPTION("Driver for MaxLinear MxL111SF"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.h b/drivers/media/dvb/dvb-usb/mxl111sf.h new file mode 100644 index 0000000..5a2c7bb --- /dev/null +++ b/drivers/media/dvb/dvb-usb/mxl111sf.h @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2010 Michael Krufky (mkrufky@kernellabs.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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ + +#ifndef _DVB_USB_MXL111SF_H_ +#define _DVB_USB_MXL111SF_H_ + +#ifdef DVB_USB_LOG_PREFIX +#undef DVB_USB_LOG_PREFIX +#endif +#define DVB_USB_LOG_PREFIX "mxl111sf" +#include "dvb-usb.h" +#include + +#define MXL_EP1_REG_READ 1 +#define MXL_EP2_REG_WRITE 2 +#define MXL_EP3_INTERRUPT 3 +#define MXL_EP4_MPEG2 4 +#define MXL_EP5_I2S 5 +#define MXL_EP6_656 6 +#define MXL_EP6_MPEG2 6 + +#ifdef USING_ENUM_mxl111sf_current_mode +enum mxl111sf_current_mode { + mxl_mode_dvbt = MXL_EP4_MPEG2, + mxl_mode_mh = MXL_EP5_I2S, + mxl_mode_atsc = MXL_EP6_MPEG2, +}; +#endif + +enum mxl111sf_gpio_port_expander { + mxl111sf_gpio_hw, + mxl111sf_PCA9534, +}; + +struct mxl111sf_state { + struct dvb_usb_device *d; + + enum mxl111sf_gpio_port_expander gpio_port_expander; + u8 port_expander_addr; + + u8 chip_id; + u8 chip_ver; +#define MXL111SF_V6 1 +#define MXL111SF_V8_100 2 +#define MXL111SF_V8_200 3 + u8 chip_rev; + +#ifdef USING_ENUM_mxl111sf_current_mode + enum mxl111sf_current_mode current_mode; +#endif + +#define MXL_TUNER_MODE 0 +#define MXL_SOC_MODE 1 +#define MXL_DEV_MODE_MASK 0x01 +#if 1 + int device_mode; +#endif + /* use usb alt setting 1 for EP4 ISOC transfer (dvb-t), + EP5 BULK transfer (atsc-mh), + EP6 BULK transfer (atsc/qam), + use usb alt setting 2 for EP4 BULK transfer (dvb-t), + EP5 ISOC transfer (atsc-mh), + EP6 ISOC transfer (atsc/qam), + */ + int alt_mode; + int gpio_mode; + struct tveeprom tv; + + struct mutex fe_lock; +}; + +struct mxl111sf_adap_state { + int alt_mode; + int gpio_mode; + int device_mode; + int ep6_clockphase; + int (*fe_init)(struct dvb_frontend *); + int (*fe_sleep)(struct dvb_frontend *); +}; + +int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data); +int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data); + +struct mxl111sf_reg_ctrl_info { + u8 addr; + u8 mask; + u8 data; +}; + +int mxl111sf_write_reg_mask(struct mxl111sf_state *state, + u8 addr, u8 mask, u8 data); +int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state, + struct mxl111sf_reg_ctrl_info *ctrl_reg_info); + +/* needed for hardware i2c functions in mxl111sf-i2c.c: + * mxl111sf_i2c_send_data / mxl111sf_i2c_get_data */ +int mxl111sf_ctrl_msg(struct dvb_usb_device *d, + u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen); + +#define mxl_printk(kern, fmt, arg...) \ + printk(kern "%s: " fmt "\n", __func__, ##arg) + +#define mxl_info(fmt, arg...) \ + mxl_printk(KERN_INFO, fmt, ##arg) + +extern int dvb_usb_mxl111sf_debug; +#define mxl_debug(fmt, arg...) \ + if (dvb_usb_mxl111sf_debug) \ + mxl_printk(KERN_DEBUG, fmt, ##arg) + +#define MXL_I2C_DBG 0x04 +#define MXL_ADV_DBG 0x10 +#define mxl_debug_adv(fmt, arg...) \ + if (dvb_usb_mxl111sf_debug & MXL_ADV_DBG) \ + mxl_printk(KERN_DEBUG, fmt, ##arg) + +#define mxl_i2c(fmt, arg...) \ + if (dvb_usb_mxl111sf_debug & MXL_I2C_DBG) \ + mxl_printk(KERN_DEBUG, fmt, ##arg) + +#define mxl_i2c_adv(fmt, arg...) \ + if ((dvb_usb_mxl111sf_debug & (MXL_I2C_DBG | MXL_ADV_DBG)) == \ + (MXL_I2C_DBG | MXL_ADV_DBG)) \ + mxl_printk(KERN_DEBUG, fmt, ##arg) + +/* The following allows the mxl_fail() macro defined below to work + * in externel modules, such as mxl111sf-tuner.ko, even though + * dvb_usb_mxl111sf_debug is not defined within those modules */ +#ifdef __MXL111SF_TUNER_H__ +#define MXL_ADV_DEBUG_ENABLED MXL_ADV_DBG +#else +#define MXL_ADV_DEBUG_ENABLED dvb_usb_mxl111sf_debug +#endif + +#define mxl_fail(ret) \ +({ \ + int __ret; \ + __ret = (ret < 0); \ + if ((__ret) && (MXL_ADV_DEBUG_ENABLED & MXL_ADV_DBG)) \ + mxl_printk(KERN_ERR, "error %d on line %d", \ + ret, __LINE__); \ + __ret; \ +}) + +#endif /* _DVB_USB_MXL111SF_H_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ -- cgit v0.10.2 From 77eed219fed5a913f59329cc846420fdeab0150f Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 6 Sep 2011 09:31:57 -0300 Subject: [media] dvb-usb: refactor MFE code for individual streaming config per frontend refactor MFE code to allow for individual streaming configuration for each frontend Signed-off-by: Michael Krufky Reviewed-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c index b95a95e..2aef3c8 100644 --- a/drivers/media/dvb/dvb-usb/a800.c +++ b/drivers/media/dvb/dvb-usb/a800.c @@ -127,6 +127,8 @@ static struct dvb_usb_device_properties a800_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, .streaming_ctrl = dibusb2_0_streaming_ctrl, @@ -147,7 +149,7 @@ static struct dvb_usb_device_properties a800_properties = { } } }, - + }}, .size_of_priv = sizeof(struct dibusb_state), }, }, diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c index 753b86e..0cf692c 100644 --- a/drivers/media/dvb/dvb-usb/af9005.c +++ b/drivers/media/dvb/dvb-usb/af9005.c @@ -815,7 +815,7 @@ static int af9005_frontend_attach(struct dvb_usb_adapter *adap) debug_dump(buf, 8, printk); } } - adap->fe[0] = af9005_fe_attach(adap->dev); + adap->fe_adap[0].fe = af9005_fe_attach(adap->dev); return 0; } @@ -999,6 +999,8 @@ static struct dvb_usb_device_properties af9005_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, @@ -1018,6 +1020,7 @@ static struct dvb_usb_device_properties af9005_properties = { } } }, + }}, } }, .power_ctrl = af9005_power_ctrl, diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index b816600..c6c275b 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -861,13 +861,13 @@ static int af9015_read_config(struct usb_device *udev) for (i = 0; i < af9015_properties_count; i++) { /* USB1.1 set smaller buffersize and disable 2nd adapter */ if (udev->speed == USB_SPEED_FULL) { - af9015_properties[i].adapter[0].stream.u.bulk.buffersize + af9015_properties[i].adapter[0].fe[0].stream.u.bulk.buffersize = TS_USB11_FRAME_SIZE; /* disable 2nd adapter because we don't have PID-filters */ af9015_config.dual_mode = 0; } else { - af9015_properties[i].adapter[0].stream.u.bulk.buffersize + af9015_properties[i].adapter[0].fe[0].stream.u.bulk.buffersize = TS_USB20_FRAME_SIZE; } } @@ -1113,10 +1113,10 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) } /* attach demodulator */ - adap->fe[0] = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id], + adap->fe_adap[0].fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id], &adap->dev->i2c_adap); - return adap->fe[0] == NULL ? -ENODEV : 0; + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } static struct mt2060_config af9015_mt2060_config = { @@ -1190,49 +1190,49 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap) switch (af9015_af9013_config[adap->id].tuner) { case AF9013_TUNER_MT2060: case AF9013_TUNER_MT2060_2: - ret = dvb_attach(mt2060_attach, adap->fe[0], &adap->dev->i2c_adap, + ret = dvb_attach(mt2060_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, &af9015_mt2060_config, af9015_config.mt2060_if1[adap->id]) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_QT1010: case AF9013_TUNER_QT1010A: - ret = dvb_attach(qt1010_attach, adap->fe[0], &adap->dev->i2c_adap, + ret = dvb_attach(qt1010_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, &af9015_qt1010_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_TDA18271: - ret = dvb_attach(tda18271_attach, adap->fe[0], 0xc0, + ret = dvb_attach(tda18271_attach, adap->fe_adap[0].fe, 0xc0, &adap->dev->i2c_adap, &af9015_tda18271_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_TDA18218: - ret = dvb_attach(tda18218_attach, adap->fe[0], + ret = dvb_attach(tda18218_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, &af9015_tda18218_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5003D: - ret = dvb_attach(mxl5005s_attach, adap->fe[0], + ret = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, &af9015_mxl5003_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5005D: case AF9013_TUNER_MXL5005R: - ret = dvb_attach(mxl5005s_attach, adap->fe[0], + ret = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, &af9015_mxl5005_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_ENV77H11D5: - ret = dvb_attach(dvb_pll_attach, adap->fe[0], 0xc0, + ret = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0xc0, &adap->dev->i2c_adap, DVB_PLL_TDA665X) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MC44S803: - ret = dvb_attach(mc44s803_attach, adap->fe[0], + ret = dvb_attach(mc44s803_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, &af9015_mc44s803_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5007T: - ret = dvb_attach(mxl5007t_attach, adap->fe[0], + ret = dvb_attach(mxl5007t_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, 0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0; break; @@ -1306,6 +1306,8 @@ static struct dvb_usb_device_properties af9015_properties[] = { .num_adapters = 2, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, @@ -1321,8 +1323,11 @@ static struct dvb_usb_device_properties af9015_properties[] = { .count = 6, .endpoint = 0x84, }, + }}, }, { + .num_frontends = 1, + .fe = {{ .frontend_attach = af9015_af9013_frontend_attach, .tuner_attach = af9015_tuner_attach, @@ -1337,6 +1342,7 @@ static struct dvb_usb_device_properties af9015_properties[] = { } } }, + }}, } }, @@ -1434,6 +1440,8 @@ static struct dvb_usb_device_properties af9015_properties[] = { .num_adapters = 2, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, @@ -1449,8 +1457,11 @@ static struct dvb_usb_device_properties af9015_properties[] = { .count = 6, .endpoint = 0x84, }, + }}, }, { + .num_frontends = 1, + .fe = {{ .frontend_attach = af9015_af9013_frontend_attach, .tuner_attach = af9015_tuner_attach, @@ -1465,6 +1476,7 @@ static struct dvb_usb_device_properties af9015_properties[] = { } } }, + }}, } }, @@ -1551,6 +1563,8 @@ static struct dvb_usb_device_properties af9015_properties[] = { .num_adapters = 2, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, @@ -1566,8 +1580,11 @@ static struct dvb_usb_device_properties af9015_properties[] = { .count = 6, .endpoint = 0x84, }, + }}, }, { + .num_frontends = 1, + .fe = {{ .frontend_attach = af9015_af9013_frontend_attach, .tuner_attach = af9015_tuner_attach, @@ -1582,6 +1599,7 @@ static struct dvb_usb_device_properties af9015_properties[] = { } } }, + }}, } }, diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c index d4d2420..5f2278b 100644 --- a/drivers/media/dvb/dvb-usb/anysee.c +++ b/drivers/media/dvb/dvb-usb/anysee.c @@ -575,7 +575,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) }; /* detect hardware only once */ - if (adap->fe[0] == NULL) { + if (adap->fe_adap[0].fe == NULL) { /* Check which hardware we have. * We must do this call two times to get reliable values (hw bug). */ @@ -595,7 +595,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) } /* set current frondend ID for devices having two frondends */ - if (adap->fe[0]) + if (adap->fe_adap[0].fe) state->fe_id++; switch (state->hw) { @@ -606,13 +606,13 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) break; /* attach demod */ - adap->fe[0] = dvb_attach(mt352_attach, &anysee_mt352_config, + adap->fe_adap[0].fe = dvb_attach(mt352_attach, &anysee_mt352_config, &adap->dev->i2c_adap); - if (adap->fe[0]) + if (adap->fe_adap[0].fe) break; /* attach demod */ - adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_config, + adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &anysee_zl10353_config, &adap->dev->i2c_adap); break; @@ -633,7 +633,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) goto error; /* attach demod */ - adap->fe[0] = dvb_attach(zl10353_attach, + adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &anysee_zl10353_config, &adap->dev->i2c_adap); break; @@ -649,7 +649,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) goto error; /* attach demod */ - adap->fe[0] = dvb_attach(tda10023_attach, + adap->fe_adap[0].fe = dvb_attach(tda10023_attach, &anysee_tda10023_config, &adap->dev->i2c_adap, 0x48); break; @@ -665,7 +665,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) goto error; /* attach demod */ - adap->fe[0] = dvb_attach(cx24116_attach, &anysee_cx24116_config, + adap->fe_adap[0].fe = dvb_attach(cx24116_attach, &anysee_cx24116_config, &adap->dev->i2c_adap); break; @@ -707,13 +707,13 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) /* attach demod */ if (tmp == 0xc7) { /* TDA18212 config */ - adap->fe[state->fe_id] = dvb_attach( + adap->fe_adap[state->fe_id].fe = dvb_attach( tda10023_attach, &anysee_tda10023_tda18212_config, &adap->dev->i2c_adap, 0x48); } else { /* PLL config */ - adap->fe[state->fe_id] = dvb_attach( + adap->fe_adap[state->fe_id].fe = dvb_attach( tda10023_attach, &anysee_tda10023_config, &adap->dev->i2c_adap, 0x48); @@ -734,13 +734,13 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) /* attach demod */ if (tmp == 0xc7) { /* TDA18212 config */ - adap->fe[state->fe_id] = dvb_attach( + adap->fe_adap[state->fe_id].fe = dvb_attach( zl10353_attach, &anysee_zl10353_tda18212_config2, &adap->dev->i2c_adap); } else { /* PLL config */ - adap->fe[state->fe_id] = dvb_attach( + adap->fe_adap[state->fe_id].fe = dvb_attach( zl10353_attach, &anysee_zl10353_config, &adap->dev->i2c_adap); @@ -772,7 +772,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) goto error; /* attach demod */ - adap->fe[state->fe_id] = dvb_attach(tda10023_attach, + adap->fe_adap[state->fe_id].fe = dvb_attach(tda10023_attach, &anysee_tda10023_tda18212_config, &adap->dev->i2c_adap, 0x48); } else { @@ -789,7 +789,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) goto error; /* attach demod */ - adap->fe[state->fe_id] = dvb_attach(zl10353_attach, + adap->fe_adap[state->fe_id].fe = dvb_attach(zl10353_attach, &anysee_zl10353_tda18212_config, &adap->dev->i2c_adap); } @@ -814,13 +814,13 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) goto error; /* attach demod */ - adap->fe[0] = dvb_attach(stv0900_attach, &anysee_stv0900_config, + adap->fe_adap[0].fe = dvb_attach(stv0900_attach, &anysee_stv0900_config, &adap->dev->i2c_adap, 0); break; } - if (!adap->fe[0]) { + if (!adap->fe_adap[0].fe) { /* we have no frontend :-( */ ret = -ENODEV; err("Unsupported Anysee version. " \ @@ -842,7 +842,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E30 */ /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc2 >> 1), + fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, (0xc2 >> 1), NULL, DVB_PLL_THOMSON_DTT7579); break; @@ -850,7 +850,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E30 Plus */ /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc2 >> 1), + fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, (0xc2 >> 1), &adap->dev->i2c_adap, DVB_PLL_THOMSON_DTT7579); break; @@ -858,7 +858,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E30 C Plus */ /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1), + fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, (0xc0 >> 1), &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); break; @@ -866,7 +866,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E30 S2 Plus */ /* attach LNB controller */ - fe = dvb_attach(isl6423_attach, adap->fe[0], + fe = dvb_attach(isl6423_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, &anysee_isl6423_config); break; @@ -883,7 +883,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) goto error; /* attach tuner */ - fe = dvb_attach(tda18212_attach, adap->fe[state->fe_id], + fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe, &adap->dev->i2c_adap, &anysee_tda18212_config); if (fe) break; @@ -894,7 +894,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) goto error; /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe[state->fe_id], + fe = dvb_attach(dvb_pll_attach, adap->fe_adap[state->fe_id].fe, (0xc0 >> 1), &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); @@ -910,7 +910,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) goto error; /* attach tuner */ - fe = dvb_attach(tda18212_attach, adap->fe[state->fe_id], + fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe, &adap->dev->i2c_adap, &anysee_tda18212_config); break; @@ -920,12 +920,12 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E7 PS2 */ /* attach tuner */ - fe = dvb_attach(stv6110_attach, adap->fe[0], + fe = dvb_attach(stv6110_attach, adap->fe_adap[0].fe, &anysee_stv6110_config, &adap->dev->i2c_adap); if (fe) { /* attach LNB controller */ - fe = dvb_attach(isl6423_attach, adap->fe[0], + fe = dvb_attach(isl6423_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, &anysee_isl6423_config); } @@ -1027,8 +1027,9 @@ static struct dvb_usb_device_properties anysee_properties = { .num_adapters = 1, .adapter = { { - .num_frontends = 2, - .frontend_ctrl = anysee_frontend_ctrl, + .num_frontends = 2, + .frontend_ctrl = anysee_frontend_ctrl, + .fe = {{ .streaming_ctrl = anysee_streaming_ctrl, .frontend_attach = anysee_frontend_attach, .tuner_attach = anysee_tuner_attach, @@ -1042,6 +1043,21 @@ static struct dvb_usb_device_properties anysee_properties = { } } }, + }, { + .streaming_ctrl = anysee_streaming_ctrl, + .frontend_attach = anysee_frontend_attach, + .tuner_attach = anysee_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = (16*512), + } + } + }, + }}, } }, diff --git a/drivers/media/dvb/dvb-usb/au6610.c b/drivers/media/dvb/dvb-usb/au6610.c index ebe6e1f..b779949 100644 --- a/drivers/media/dvb/dvb-usb/au6610.c +++ b/drivers/media/dvb/dvb-usb/au6610.c @@ -140,9 +140,9 @@ static struct zl10353_config au6610_zl10353_config = { static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap) { - adap->fe[0] = dvb_attach(zl10353_attach, &au6610_zl10353_config, + adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &au6610_zl10353_config, &adap->dev->i2c_adap); - if (adap->fe[0] == NULL) + if (adap->fe_adap[0].fe == NULL) return -ENODEV; return 0; @@ -155,7 +155,7 @@ static struct qt1010_config au6610_qt1010_config = { static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap) { return dvb_attach(qt1010_attach, - adap->fe[0], &adap->dev->i2c_adap, + adap->fe_adap[0].fe, &adap->dev->i2c_adap, &au6610_qt1010_config) == NULL ? -ENODEV : 0; } @@ -204,6 +204,8 @@ static struct dvb_usb_device_properties au6610_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .frontend_attach = au6610_zl10353_frontend_attach, .tuner_attach = au6610_qt1010_tuner_attach, @@ -219,6 +221,7 @@ static struct dvb_usb_device_properties au6610_properties = { } } }, + }}, } }, diff --git a/drivers/media/dvb/dvb-usb/az6027.c b/drivers/media/dvb/dvb-usb/az6027.c index d59430c..82c5f45 100644 --- a/drivers/media/dvb/dvb-usb/az6027.c +++ b/drivers/media/dvb/dvb-usb/az6027.c @@ -910,16 +910,16 @@ static int az6027_frontend_attach(struct dvb_usb_adapter *adap) az6027_frontend_reset(adap); deb_info("adap = %p, dev = %p\n", adap, adap->dev); - adap->fe[0] = stb0899_attach(&az6027_stb0899_config, &adap->dev->i2c_adap); + adap->fe_adap[0].fe = stb0899_attach(&az6027_stb0899_config, &adap->dev->i2c_adap); - if (adap->fe[0]) { + if (adap->fe_adap[0].fe) { deb_info("found STB0899 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb0899_config.demod_address); - if (stb6100_attach(adap->fe[0], &az6027_stb6100_config, &adap->dev->i2c_adap)) { + if (stb6100_attach(adap->fe_adap[0].fe, &az6027_stb6100_config, &adap->dev->i2c_adap)) { deb_info("found STB6100 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb6100_config.tuner_address); - adap->fe[0]->ops.set_voltage = az6027_set_voltage; + adap->fe_adap[0].fe->ops.set_voltage = az6027_set_voltage; az6027_ci_init(adap); } else { - adap->fe[0] = NULL; + adap->fe_adap[0].fe = NULL; } } else warn("no front-end attached\n"); @@ -1106,6 +1106,8 @@ static struct dvb_usb_device_properties az6027_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .streaming_ctrl = az6027_streaming_ctrl, .frontend_attach = az6027_frontend_attach, @@ -1120,6 +1122,7 @@ static struct dvb_usb_device_properties az6027_properties = { } } }, + }}, } }, /* diff --git a/drivers/media/dvb/dvb-usb/ce6230.c b/drivers/media/dvb/dvb-usb/ce6230.c index 5655ce4..57afb5a 100644 --- a/drivers/media/dvb/dvb-usb/ce6230.c +++ b/drivers/media/dvb/dvb-usb/ce6230.c @@ -186,9 +186,9 @@ static struct zl10353_config ce6230_zl10353_config = { static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap) { deb_info("%s:\n", __func__); - adap->fe[0] = dvb_attach(zl10353_attach, &ce6230_zl10353_config, + adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &ce6230_zl10353_config, &adap->dev->i2c_adap); - if (adap->fe[0] == NULL) + if (adap->fe_adap[0].fe == NULL) return -ENODEV; return 0; } @@ -214,7 +214,7 @@ static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) { int ret; deb_info("%s:\n", __func__); - ret = dvb_attach(mxl5005s_attach, adap->fe[0], &adap->dev->i2c_adap, + ret = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, &ce6230_mxl5003s_config) == NULL ? -ENODEV : 0; return ret; } @@ -273,6 +273,8 @@ static struct dvb_usb_device_properties ce6230_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .frontend_attach = ce6230_zl10353_frontend_attach, .tuner_attach = ce6230_mxl5003s_tuner_attach, .stream = { @@ -285,6 +287,7 @@ static struct dvb_usb_device_properties ce6230_properties = { } } }, + }}, } }, diff --git a/drivers/media/dvb/dvb-usb/cinergyT2-core.c b/drivers/media/dvb/dvb-usb/cinergyT2-core.c index 0dd42bd..f9d9050 100644 --- a/drivers/media/dvb/dvb-usb/cinergyT2-core.c +++ b/drivers/media/dvb/dvb-usb/cinergyT2-core.c @@ -69,7 +69,7 @@ static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap) char state[3]; int ret; - adap->fe[0] = cinergyt2_fe_attach(adap->dev); + adap->fe_adap[0].fe = cinergyt2_fe_attach(adap->dev); ret = dvb_usb_generic_rw(adap->dev, query, sizeof(query), state, sizeof(state), 0); @@ -198,6 +198,8 @@ static struct dvb_usb_device_properties cinergyt2_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .streaming_ctrl = cinergyt2_streaming_ctrl, .frontend_attach = cinergyt2_frontend_attach, @@ -212,6 +214,7 @@ static struct dvb_usb_device_properties cinergyt2_properties = { } } }, + }}, } }, diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index a76f431..7f610da 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -347,7 +347,7 @@ static void cxusb_d680_dmb_drain_message(struct dvb_usb_device *d) static void cxusb_d680_dmb_drain_video(struct dvb_usb_device *d) { - struct usb_data_stream_properties *p = &d->props.adapter[0].stream; + struct usb_data_stream_properties *p = &d->props.adapter[0].fe[0].stream; const int timeout = 100; const int junk_len = p->u.bulk.buffersize; u8 *junk; @@ -725,7 +725,7 @@ static struct max2165_config mygica_d689_max2165_cfg = { /* Callbacks for DVB USB */ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(simple_tuner_attach, adap->fe[0], + dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, 0x61, TUNER_PHILIPS_FMD1216ME_MK3); return 0; @@ -733,27 +733,27 @@ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) static int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(dvb_pll_attach, adap->fe[0], 0x61, + dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, NULL, DVB_PLL_THOMSON_DTT7579); return 0; } static int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(dvb_pll_attach, adap->fe[0], 0x61, NULL, DVB_PLL_LG_Z201); + dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, NULL, DVB_PLL_LG_Z201); return 0; } static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, + dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, NULL, DVB_PLL_THOMSON_DTT7579); return 0; } static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(simple_tuner_attach, adap->fe[0], + dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, 0x61, TUNER_LG_TDVS_H06XF); return 0; } @@ -795,9 +795,9 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap) }; /* FIXME: generalize & move to common area */ - adap->fe[0]->callback = dvico_bluebird_xc2028_callback; + adap->fe_adap[0].fe->callback = dvico_bluebird_xc2028_callback; - fe = dvb_attach(xc2028_attach, adap->fe[0], &cfg); + fe = dvb_attach(xc2028_attach, adap->fe_adap[0].fe, &cfg); if (fe == NULL || fe->ops.tuner_ops.set_config == NULL) return -EIO; @@ -808,7 +808,7 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap) static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(mxl5005s_attach, adap->fe[0], + dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, &aver_a868r_tuner); return 0; } @@ -816,7 +816,7 @@ static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap) { struct dvb_frontend *fe; - fe = dvb_attach(mxl5005s_attach, adap->fe[0], + fe = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, &d680_dmb_tuner); return (fe == NULL) ? -EIO : 0; } @@ -824,7 +824,7 @@ static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap) static int cxusb_mygica_d689_tuner_attach(struct dvb_usb_adapter *adap) { struct dvb_frontend *fe; - fe = dvb_attach(max2165_attach, adap->fe[0], + fe = dvb_attach(max2165_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, &mygica_d689_max2165_cfg); return (fe == NULL) ? -EIO : 0; } @@ -837,7 +837,7 @@ static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap) cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, &b, 1); - if ((adap->fe[0] = dvb_attach(cx22702_attach, &cxusb_cx22702_config, + if ((adap->fe_adap[0].fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config, &adap->dev->i2c_adap)) != NULL) return 0; @@ -851,7 +851,7 @@ static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - if ((adap->fe[0] = dvb_attach(lgdt330x_attach, &cxusb_lgdt3303_config, + if ((adap->fe_adap[0].fe = dvb_attach(lgdt330x_attach, &cxusb_lgdt3303_config, &adap->dev->i2c_adap)) != NULL) return 0; @@ -860,9 +860,9 @@ static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) static int cxusb_aver_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) { - adap->fe[0] = dvb_attach(lgdt330x_attach, &cxusb_aver_lgdt3303_config, + adap->fe_adap[0].fe = dvb_attach(lgdt330x_attach, &cxusb_aver_lgdt3303_config, &adap->dev->i2c_adap); - if (adap->fe[0] != NULL) + if (adap->fe_adap[0].fe != NULL) return 0; return -EIO; @@ -876,7 +876,7 @@ static int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap) cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - if ((adap->fe[0] = dvb_attach(mt352_attach, &cxusb_mt352_config, + if ((adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_mt352_config, &adap->dev->i2c_adap)) != NULL) return 0; @@ -890,9 +890,9 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap) cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - if (((adap->fe[0] = dvb_attach(mt352_attach, &cxusb_dee1601_config, + if (((adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_dee1601_config, &adap->dev->i2c_adap)) != NULL) || - ((adap->fe[0] = dvb_attach(zl10353_attach, + ((adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &cxusb_zl10353_dee1601_config, &adap->dev->i2c_adap)) != NULL)) return 0; @@ -917,7 +917,7 @@ static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap) cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1); cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); - if ((adap->fe[0] = dvb_attach(zl10353_attach, + if ((adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &cxusb_zl10353_xc3028_config_no_i2c_gate, &adap->dev->i2c_adap)) == NULL) return -EIO; @@ -1031,9 +1031,9 @@ static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap) return -ENODEV; } - adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &cxusb_dualdig4_rev2_config); - if (adap->fe[0] == NULL) + if (adap->fe_adap[0].fe == NULL) return -EIO; return 0; @@ -1084,15 +1084,15 @@ static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; struct i2c_adapter *tun_i2c = - dib7000p_get_i2c_master(adap->fe[0], + dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); - if (dvb_attach(dib0070_attach, adap->fe[0], tun_i2c, + if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, &dib7070p_dib0070_config) == NULL) return -ENODEV; - st->set_param_save = adap->fe[0]->ops.tuner_ops.set_params; - adap->fe[0]->ops.tuner_ops.set_params = dib7070_set_param_override; + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7070_set_param_override; return 0; } @@ -1108,12 +1108,12 @@ static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap) cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1); cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); - if ((adap->fe[0] = dvb_attach(zl10353_attach, + if ((adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &cxusb_zl10353_xc3028_config, &adap->dev->i2c_adap)) != NULL) return 0; - if ((adap->fe[0] = dvb_attach(mt352_attach, + if ((adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_mt352_xc3028_config, &adap->dev->i2c_adap)) != NULL) return 0; @@ -1150,7 +1150,7 @@ static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap) usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, d->props.adapter[0].stream.endpoint)); + usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint)); /* Drain USB pipes to avoid hang after reboot */ for (n = 0; n < 5; n++) { @@ -1172,8 +1172,8 @@ static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap) msleep(100); /* Attach frontend */ - adap->fe[0] = dvb_attach(lgs8gxx_attach, &d680_lgs8gl5_cfg, &d->i2c_adap); - if (adap->fe[0] == NULL) + adap->fe_adap[0].fe = dvb_attach(lgs8gxx_attach, &d680_lgs8gl5_cfg, &d->i2c_adap); + if (adap->fe_adap[0].fe == NULL) return -EIO; return 0; @@ -1207,7 +1207,7 @@ static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap) usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, d->props.adapter[0].stream.endpoint)); + usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint)); /* Reset the tuner */ @@ -1223,9 +1223,9 @@ static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap) msleep(100); /* Attach frontend */ - adap->fe[0] = dvb_attach(atbm8830_attach, &mygica_d689_atbm8830_cfg, + adap->fe_adap[0].fe = dvb_attach(atbm8830_attach, &mygica_d689_atbm8830_cfg, &d->i2c_adap); - if (adap->fe[0] == NULL) + if (adap->fe_adap[0].fe == NULL) return -EIO; return 0; @@ -1383,6 +1383,8 @@ static struct dvb_usb_device_properties cxusb_medion_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .streaming_ctrl = cxusb_streaming_ctrl, .frontend_attach = cxusb_cx22702_frontend_attach, .tuner_attach = cxusb_fmd1216me_tuner_attach, @@ -1397,7 +1399,7 @@ static struct dvb_usb_device_properties cxusb_medion_properties = { } } }, - + }}, }, }, .power_ctrl = cxusb_power_ctrl, @@ -1429,6 +1431,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .streaming_ctrl = cxusb_streaming_ctrl, .frontend_attach = cxusb_lgdt3303_frontend_attach, .tuner_attach = cxusb_lgh064f_tuner_attach, @@ -1444,6 +1448,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = { } } }, + }}, }, }, @@ -1483,6 +1488,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .streaming_ctrl = cxusb_streaming_ctrl, .frontend_attach = cxusb_dee1601_frontend_attach, .tuner_attach = cxusb_dee1601_tuner_attach, @@ -1497,6 +1504,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = { } } }, + }}, }, }, @@ -1544,6 +1552,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = { .num_adapters = 2, .adapter = { { + .num_frontends = 1, + .fe = {{ .streaming_ctrl = cxusb_streaming_ctrl, .frontend_attach = cxusb_mt352_frontend_attach, .tuner_attach = cxusb_lgz201_tuner_attach, @@ -1559,6 +1569,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = { } } }, + }}, }, }, .power_ctrl = cxusb_bluebird_power_ctrl, @@ -1596,6 +1607,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .streaming_ctrl = cxusb_streaming_ctrl, .frontend_attach = cxusb_mt352_frontend_attach, .tuner_attach = cxusb_dtt7579_tuner_attach, @@ -1611,6 +1624,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = { } } }, + }}, }, }, .power_ctrl = cxusb_bluebird_power_ctrl, @@ -1645,6 +1659,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .streaming_ctrl = cxusb_streaming_ctrl, .frontend_attach = cxusb_dualdig4_frontend_attach, .tuner_attach = cxusb_dvico_xc3028_tuner_attach, @@ -1659,6 +1675,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = { } } }, + }}, }, }, @@ -1695,6 +1712,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .streaming_ctrl = cxusb_streaming_ctrl, .frontend_attach = cxusb_nano2_frontend_attach, .tuner_attach = cxusb_dvico_xc3028_tuner_attach, @@ -1709,6 +1728,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = { } } }, + }}, }, }, @@ -1747,6 +1767,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .streaming_ctrl = cxusb_streaming_ctrl, .frontend_attach = cxusb_nano2_frontend_attach, .tuner_attach = cxusb_dvico_xc3028_tuner_attach, @@ -1761,6 +1783,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope } } }, + }}, }, }, @@ -1796,6 +1819,8 @@ static struct dvb_usb_device_properties cxusb_aver_a868r_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .streaming_ctrl = cxusb_aver_streaming_ctrl, .frontend_attach = cxusb_aver_lgdt3303_frontend_attach, .tuner_attach = cxusb_mxl5003s_tuner_attach, @@ -1810,7 +1835,7 @@ static struct dvb_usb_device_properties cxusb_aver_a868r_properties = { } } }, - + }}, }, }, .power_ctrl = cxusb_aver_power_ctrl, @@ -1839,10 +1864,12 @@ struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = { .num_adapters = 1, .adapter = { { + .size_of_priv = sizeof(struct dib0700_adapter_state), + .num_frontends = 1, + .fe = {{ .streaming_ctrl = cxusb_streaming_ctrl, .frontend_attach = cxusb_dualdig4_rev2_frontend_attach, .tuner_attach = cxusb_dualdig4_rev2_tuner_attach, - .size_of_priv = sizeof(struct dib0700_adapter_state), /* parameter for the MPEG2-data transfer */ .stream = { .type = USB_BULK, @@ -1854,6 +1881,7 @@ struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = { } } }, + }}, }, }, @@ -1889,6 +1917,8 @@ static struct dvb_usb_device_properties cxusb_d680_dmb_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .streaming_ctrl = cxusb_d680_dmb_streaming_ctrl, .frontend_attach = cxusb_d680_dmb_frontend_attach, .tuner_attach = cxusb_d680_dmb_tuner_attach, @@ -1904,6 +1934,7 @@ static struct dvb_usb_device_properties cxusb_d680_dmb_properties = { } } }, + }}, }, }, @@ -1940,6 +1971,8 @@ static struct dvb_usb_device_properties cxusb_mygica_d689_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .streaming_ctrl = cxusb_d680_dmb_streaming_ctrl, .frontend_attach = cxusb_mygica_d689_frontend_attach, .tuner_attach = cxusb_mygica_d689_tuner_attach, @@ -1955,6 +1988,7 @@ static struct dvb_usb_device_properties cxusb_mygica_d689_properties = { } } }, + }}, }, }, diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index b693ed1..156cbfc 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -528,13 +528,13 @@ int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw for (adap_num = 0; adap_num < dib0700_devices[i].num_adapters; adap_num++) { if (fw_version >= 0x10201) { - dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = 188*nb_packet_buffer_size; + dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = 188*nb_packet_buffer_size; } else { /* for fw version older than 1.20.1, * the buffersize has to be n times 512 */ - dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = ((188*nb_packet_buffer_size+188/2)/512)*512; - if (dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize < 512) - dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = 512; + dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = ((188*nb_packet_buffer_size+188/2)/512)*512; + if (dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize < 512) + dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = 512; } } } @@ -579,18 +579,18 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id); st->channel_state &= ~0x3; - if ((adap->stream.props.endpoint != 2) - && (adap->stream.props.endpoint != 3)) { - deb_info("the endpoint number (%i) is not correct, use the adapter id instead", adap->stream.props.endpoint); + if ((adap->fe_adap[0].stream.props.endpoint != 2) + && (adap->fe_adap[0].stream.props.endpoint != 3)) { + deb_info("the endpoint number (%i) is not correct, use the adapter id instead", adap->fe_adap[0].stream.props.endpoint); if (onoff) st->channel_state |= 1 << (adap->id); else st->channel_state |= 1 << ~(adap->id); } else { if (onoff) - st->channel_state |= 1 << (adap->stream.props.endpoint-2); + st->channel_state |= 1 << (adap->fe_adap[0].stream.props.endpoint-2); else - st->channel_state |= 1 << (3-adap->stream.props.endpoint); + st->channel_state |= 1 << (3-adap->fe_adap[0].stream.props.endpoint); } st->buf[2] |= st->channel_state; diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 754f8ec..3ed6203 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -101,7 +101,7 @@ static int bristol_frontend_attach(struct dvb_usb_adapter *adap) } } st->mt2060_if1[adap->id] = 1220; - return (adap->fe[0] = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, + return (adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, (10 + adap->id) << 1, &bristol_dib3000mc_config[adap->id])) == NULL ? -ENODEV : 0; } @@ -118,14 +118,14 @@ static int eeprom_read(struct i2c_adapter *adap,u8 adrs,u8 *pval) static int bristol_tuner_attach(struct dvb_usb_adapter *adap) { struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap; - struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe[0], 1); + struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe_adap[0].fe, 1); s8 a; int if1=1220; if (adap->dev->udev->descriptor.idVendor == cpu_to_le16(USB_VID_HAUPPAUGE) && adap->dev->udev->descriptor.idProduct == cpu_to_le16(USB_PID_HAUPPAUGE_NOVA_T_500_2)) { if (!eeprom_read(prim_i2c,0x59 + adap->id,&a)) if1=1220+a; } - return dvb_attach(mt2060_attach,adap->fe[0], tun_i2c,&bristol_mt2060_config[adap->id], + return dvb_attach(mt2060_attach,adap->fe_adap[0].fe, tun_i2c,&bristol_mt2060_config[adap->id], if1) == NULL ? -ENODEV : 0; } @@ -279,10 +279,10 @@ static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap) } } - adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1), + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1), &stk7700d_dib7000p_mt2266_config[adap->id]); - return adap->fe[0] == NULL ? -ENODEV : 0; + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap) @@ -306,17 +306,17 @@ static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap) } } - adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1), + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1), &stk7700d_dib7000p_mt2266_config[adap->id]); - return adap->fe[0] == NULL ? -ENODEV : 0; + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap) { struct i2c_adapter *tun_i2c; - tun_i2c = dib7000p_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); - return dvb_attach(mt2266_attach, adap->fe[0], tun_i2c, + tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); + return dvb_attach(mt2266_attach, adap->fe_adap[0].fe, tun_i2c, &stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0; } @@ -396,8 +396,8 @@ static int stk7700ph_xc3028_callback(void *ptr, int component, switch (command) { case XC2028_TUNER_RESET: /* Send the tuner in then out of reset */ - dib7000p_set_gpio(adap->fe[0], 8, 0, 0); msleep(10); - dib7000p_set_gpio(adap->fe[0], 8, 0, 1); + dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 0); msleep(10); + dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); break; case XC2028_RESET_CLK: break; @@ -447,25 +447,25 @@ static int stk7700ph_frontend_attach(struct dvb_usb_adapter *adap) return -ENODEV; } - adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7700ph_dib7700_xc3028_config); - return adap->fe[0] == NULL ? -ENODEV : 0; + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap) { struct i2c_adapter *tun_i2c; - tun_i2c = dib7000p_get_i2c_master(adap->fe[0], + tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); stk7700ph_xc3028_config.i2c_adap = tun_i2c; /* FIXME: generalize & move to common area */ - adap->fe[0]->callback = stk7700ph_xc3028_callback; + adap->fe_adap[0].fe->callback = stk7700ph_xc3028_callback; - return dvb_attach(xc2028_attach, adap->fe[0], &stk7700ph_xc3028_config) + return dvb_attach(xc2028_attach, adap->fe_adap[0].fe, &stk7700ph_xc3028_config) == NULL ? -ENODEV : 0; } @@ -685,12 +685,12 @@ static int stk7700p_frontend_attach(struct dvb_usb_adapter *adap) st->mt2060_if1[0] = 1220; if (dib7000pc_detection(&adap->dev->i2c_adap)) { - adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000p_config); + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000p_config); st->is_dib7000pc = 1; } else - adap->fe[0] = dvb_attach(dib7000m_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000m_config); + adap->fe_adap[0].fe = dvb_attach(dib7000m_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000m_config); - return adap->fe[0] == NULL ? -ENODEV : 0; + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } static struct mt2060_config stk7700p_mt2060_config = { @@ -709,11 +709,11 @@ static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap) if (!eeprom_read(prim_i2c,0x58,&a)) if1=1220+a; } if (st->is_dib7000pc) - tun_i2c = dib7000p_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); + tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); else - tun_i2c = dib7000m_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); + tun_i2c = dib7000m_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); - return dvb_attach(mt2060_attach, adap->fe[0], tun_i2c, &stk7700p_mt2060_config, + return dvb_attach(mt2060_attach, adap->fe_adap[0].fe, tun_i2c, &stk7700p_mt2060_config, if1) == NULL ? -ENODEV : 0; } @@ -843,33 +843,33 @@ static int dib7770_set_param_override(struct dvb_frontend *fe, static int dib7770p_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe[0], + struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); - if (dvb_attach(dib0070_attach, adap->fe[0], tun_i2c, + if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, &dib7770p_dib0070_config) == NULL) return -ENODEV; - st->set_param_save = adap->fe[0]->ops.tuner_ops.set_params; - adap->fe[0]->ops.tuner_ops.set_params = dib7770_set_param_override; + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7770_set_param_override; return 0; } static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); + struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); if (adap->id == 0) { - if (dvb_attach(dib0070_attach, adap->fe[0], tun_i2c, &dib7070p_dib0070_config[0]) == NULL) + if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, &dib7070p_dib0070_config[0]) == NULL) return -ENODEV; } else { - if (dvb_attach(dib0070_attach, adap->fe[0], tun_i2c, &dib7070p_dib0070_config[1]) == NULL) + if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, &dib7070p_dib0070_config[1]) == NULL) return -ENODEV; } - st->set_param_save = adap->fe[0]->ops.tuner_ops.set_params; - adap->fe[0]->ops.tuner_ops.set_params = dib7070_set_param_override; + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7070_set_param_override; return 0; } @@ -878,26 +878,26 @@ static int stk7700p_pid_filter(struct dvb_usb_adapter *adapter, int index, { struct dib0700_state *st = adapter->dev->priv; if (st->is_dib7000pc) - return dib7000p_pid_filter(adapter->fe[0], index, pid, onoff); - return dib7000m_pid_filter(adapter->fe[0], index, pid, onoff); + return dib7000p_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff); + return dib7000m_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff); } static int stk7700p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) { struct dib0700_state *st = adapter->dev->priv; if (st->is_dib7000pc) - return dib7000p_pid_filter_ctrl(adapter->fe[0], onoff); - return dib7000m_pid_filter_ctrl(adapter->fe[0], onoff); + return dib7000p_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff); + return dib7000m_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff); } static int stk70x0p_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) { - return dib7000p_pid_filter(adapter->fe[0], index, pid, onoff); + return dib7000p_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff); } static int stk70x0p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) { - return dib7000p_pid_filter_ctrl(adapter->fe[0], onoff); + return dib7000p_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff); } static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = { @@ -955,9 +955,9 @@ static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap) return -ENODEV; } - adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &dib7070p_dib7000p_config); - return adap->fe[0] == NULL ? -ENODEV : 0; + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } /* STK7770P */ @@ -1007,9 +1007,9 @@ static int stk7770p_frontend_attach(struct dvb_usb_adapter *adap) return -ENODEV; } - adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &dib7770p_dib7000p_config); - return adap->fe[0] == NULL ? -ENODEV : 0; + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } /* DIB807x generic */ @@ -1225,34 +1225,34 @@ static int dib807x_set_param_override(struct dvb_frontend *fe, static int dib807x_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe[0], + struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); if (adap->id == 0) { - if (dvb_attach(dib0070_attach, adap->fe[0], tun_i2c, + if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, &dib807x_dib0070_config[0]) == NULL) return -ENODEV; } else { - if (dvb_attach(dib0070_attach, adap->fe[0], tun_i2c, + if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, &dib807x_dib0070_config[1]) == NULL) return -ENODEV; } - st->set_param_save = adap->fe[0]->ops.tuner_ops.set_params; - adap->fe[0]->ops.tuner_ops.set_params = dib807x_set_param_override; + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib807x_set_param_override; return 0; } static int stk80xx_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) { - return dib8000_pid_filter(adapter->fe[0], index, pid, onoff); + return dib8000_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff); } static int stk80xx_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) { - return dib8000_pid_filter_ctrl(adapter->fe[0], onoff); + return dib8000_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff); } /* STK807x */ @@ -1276,10 +1276,10 @@ static int stk807x_frontend_attach(struct dvb_usb_adapter *adap) dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80); - adap->fe[0] = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, + adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib807x_dib8000_config[0]); - return adap->fe[0] == NULL ? -ENODEV : 0; + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } /* STK807xPVR */ @@ -1305,10 +1305,10 @@ static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap) /* initialize IC 0 */ dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x80); - adap->fe[0] = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, + adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib807x_dib8000_config[0]); - return adap->fe[0] == NULL ? -ENODEV : 0; + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap) @@ -1316,10 +1316,10 @@ static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap) /* initialize IC 1 */ dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x82); - adap->fe[0] = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, + adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, &dib807x_dib8000_config[1]); - return adap->fe[0] == NULL ? -ENODEV : 0; + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } /* STK8096GP */ @@ -1546,13 +1546,13 @@ static int dib8096_set_param_override(struct dvb_frontend *fe, static int dib809x_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); + struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); - if (dvb_attach(dib0090_register, adap->fe[0], tun_i2c, &dib809x_dib0090_config) == NULL) + if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &dib809x_dib0090_config) == NULL) return -ENODEV; - st->set_param_save = adap->fe[0]->ops.tuner_ops.set_params; - adap->fe[0]->ops.tuner_ops.set_params = dib8096_set_param_override; + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib8096_set_param_override; return 0; } @@ -1575,30 +1575,30 @@ static int stk809x_frontend_attach(struct dvb_usb_adapter *adap) dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80); - adap->fe[0] = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); + adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); - return adap->fe[0] == NULL ? -ENODEV : 0; + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } static int nim8096md_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; struct i2c_adapter *tun_i2c; - struct dvb_frontend *fe_slave = dib8000_get_slave_frontend(adap->fe[0], 1); + struct dvb_frontend *fe_slave = dib8000_get_slave_frontend(adap->fe_adap[0].fe, 1); if (fe_slave) { tun_i2c = dib8000_get_i2c_master(fe_slave, DIBX000_I2C_INTERFACE_TUNER, 1); if (dvb_attach(dib0090_register, fe_slave, tun_i2c, &dib809x_dib0090_config) == NULL) return -ENODEV; - fe_slave->dvb = adap->fe[0]->dvb; + fe_slave->dvb = adap->fe_adap[0].fe->dvb; fe_slave->ops.tuner_ops.set_params = dib8096_set_param_override; } - tun_i2c = dib8000_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); - if (dvb_attach(dib0090_register, adap->fe[0], tun_i2c, &dib809x_dib0090_config) == NULL) + tun_i2c = dib8000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); + if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &dib809x_dib0090_config) == NULL) return -ENODEV; - st->set_param_save = adap->fe[0]->ops.tuner_ops.set_params; - adap->fe[0]->ops.tuner_ops.set_params = dib8096_set_param_override; + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib8096_set_param_override; return 0; } @@ -1626,12 +1626,12 @@ static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap) dib8000_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, 0x80); - adap->fe[0] = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); - if (adap->fe[0] == NULL) + adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); + if (adap->fe_adap[0].fe == NULL) return -ENODEV; fe_slave = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, &dib809x_dib8000_config[1]); - dib8000_set_slave_frontend(adap->fe[0], fe_slave); + dib8000_set_slave_frontend(adap->fe_adap[0].fe, fe_slave); return fe_slave == NULL ? -ENODEV : 0; } @@ -1639,12 +1639,12 @@ static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap) /* STK9090M */ static int dib90x0_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) { - return dib9000_fw_pid_filter(adapter->fe[0], index, pid, onoff); + return dib9000_fw_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff); } static int dib90x0_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) { - return dib9000_fw_pid_filter_ctrl(adapter->fe[0], onoff); + return dib9000_fw_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff); } static int dib90x0_tuner_reset(struct dvb_frontend *fe, int onoff) @@ -1856,15 +1856,15 @@ static int stk9090m_frontend_attach(struct dvb_usb_adapter *adap) stk9090m_config.microcode_B_fe_size = state->frontend_firmware->size; stk9090m_config.microcode_B_fe_buffer = state->frontend_firmware->data; - adap->fe[0] = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &stk9090m_config); + adap->fe_adap[0].fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &stk9090m_config); - return adap->fe[0] == NULL ? -ENODEV : 0; + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } static int dib9090_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *state = adap->priv; - struct i2c_adapter *i2c = dib9000_get_tuner_interface(adap->fe[0]); + struct i2c_adapter *i2c = dib9000_get_tuner_interface(adap->fe_adap[0].fe); u16 data_dib190[10] = { 1, 0x1374, 2, 0x01a2, @@ -1873,13 +1873,13 @@ static int dib9090_tuner_attach(struct dvb_usb_adapter *adap) 8, 0x0486, }; - if (dvb_attach(dib0090_fw_register, adap->fe[0], i2c, &dib9090_dib0090_config) == NULL) + if (dvb_attach(dib0090_fw_register, adap->fe_adap[0].fe, i2c, &dib9090_dib0090_config) == NULL) return -ENODEV; - i2c = dib9000_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_GPIO_1_2, 0); + i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0); if (dib01x0_pmu_update(i2c, data_dib190, 10) != 0) return -ENODEV; dib0700_set_i2c_speed(adap->dev, 2000); - if (dib9000_firmware_post_pll_init(adap->fe[0]) < 0) + if (dib9000_firmware_post_pll_init(adap->fe_adap[0].fe) < 0) return -ENODEV; release_firmware(state->frontend_firmware); return 0; @@ -1925,16 +1925,16 @@ static int nim9090md_frontend_attach(struct dvb_usb_adapter *adap) nim9090md_config[1].microcode_B_fe_buffer = state->frontend_firmware->data; dib9000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, 0x80); - adap->fe[0] = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &nim9090md_config[0]); + adap->fe_adap[0].fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &nim9090md_config[0]); - if (adap->fe[0] == NULL) + if (adap->fe_adap[0].fe == NULL) return -ENODEV; - i2c = dib9000_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_GPIO_3_4, 0); + i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_3_4, 0); dib9000_i2c_enumeration(i2c, 1, 0x12, 0x82); fe_slave = dvb_attach(dib9000_attach, i2c, 0x82, &nim9090md_config[1]); - dib9000_set_slave_frontend(adap->fe[0], fe_slave); + dib9000_set_slave_frontend(adap->fe_adap[0].fe, fe_slave); return fe_slave == NULL ? -ENODEV : 0; } @@ -1951,26 +1951,26 @@ static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap) 0, 0x00ef, 8, 0x0406, }; - i2c = dib9000_get_tuner_interface(adap->fe[0]); - if (dvb_attach(dib0090_fw_register, adap->fe[0], i2c, &nim9090md_dib0090_config[0]) == NULL) + i2c = dib9000_get_tuner_interface(adap->fe_adap[0].fe); + if (dvb_attach(dib0090_fw_register, adap->fe_adap[0].fe, i2c, &nim9090md_dib0090_config[0]) == NULL) return -ENODEV; - i2c = dib9000_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_GPIO_1_2, 0); + i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0); if (dib01x0_pmu_update(i2c, data_dib190, 10) < 0) return -ENODEV; dib0700_set_i2c_speed(adap->dev, 2000); - if (dib9000_firmware_post_pll_init(adap->fe[0]) < 0) + if (dib9000_firmware_post_pll_init(adap->fe_adap[0].fe) < 0) return -ENODEV; - fe_slave = dib9000_get_slave_frontend(adap->fe[0], 1); + fe_slave = dib9000_get_slave_frontend(adap->fe_adap[0].fe, 1); if (fe_slave != NULL) { - i2c = dib9000_get_component_bus_interface(adap->fe[0]); + i2c = dib9000_get_component_bus_interface(adap->fe_adap[0].fe); dib9000_set_i2c_adapter(fe_slave, i2c); i2c = dib9000_get_tuner_interface(fe_slave); if (dvb_attach(dib0090_fw_register, fe_slave, i2c, &nim9090md_dib0090_config[1]) == NULL) return -ENODEV; - fe_slave->dvb = adap->fe[0]->dvb; - dib9000_fw_set_component_bus_speed(adap->fe[0], 2000); + fe_slave->dvb = adap->fe_adap[0].fe->dvb; + dib9000_fw_set_component_bus_speed(adap->fe_adap[0].fe, 2000); if (dib9000_firmware_post_pll_init(fe_slave) < 0) return -ENODEV; } @@ -2393,23 +2393,23 @@ static int nim7090_frontend_attach(struct dvb_usb_adapter *adap) err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); return -ENODEV; } - adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &nim7090_dib7000p_config); + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &nim7090_dib7000p_config); - return adap->fe[0] == NULL ? -ENODEV : 0; + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } static int nim7090_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe[0]); + struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe_adap[0].fe); - if (dvb_attach(dib0090_register, adap->fe[0], tun_i2c, &nim7090_dib0090_config) == NULL) + if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &nim7090_dib0090_config) == NULL) return -ENODEV; - dib7000p_set_gpio(adap->fe[0], 8, 0, 1); + dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); - st->set_param_save = adap->fe[0]->ops.tuner_ops.set_params; - adap->fe[0]->ops.tuner_ops.set_params = dib7090_agc_startup; + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup; return 0; } @@ -2439,11 +2439,11 @@ static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap) } dib0700_set_i2c_speed(adap->dev, 340); - adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]); - if (adap->fe[0] == NULL) + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]); + if (adap->fe_adap[0].fe == NULL) return -ENODEV; - dib7090_slave_reset(adap->fe[0]); + dib7090_slave_reset(adap->fe_adap[0].fe); return 0; } @@ -2452,50 +2452,50 @@ static int tfe7090pvr_frontend1_attach(struct dvb_usb_adapter *adap) { struct i2c_adapter *i2c; - if (adap->dev->adapter[0].fe[0] == NULL) { + if (adap->dev->adapter[0].fe_adap[0].fe == NULL) { err("the master dib7090 has to be initialized first"); return -ENODEV; /* the master device has not been initialized */ } - i2c = dib7000p_get_i2c_master(adap->dev->adapter[0].fe[0], DIBX000_I2C_INTERFACE_GPIO_6_7, 1); + i2c = dib7000p_get_i2c_master(adap->dev->adapter[0].fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_6_7, 1); if (dib7000p_i2c_enumeration(i2c, 1, 0x10, &tfe7090pvr_dib7000p_config[1]) != 0) { err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); return -ENODEV; } - adap->fe[0] = dvb_attach(dib7000p_attach, i2c, 0x92, &tfe7090pvr_dib7000p_config[1]); + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, i2c, 0x92, &tfe7090pvr_dib7000p_config[1]); dib0700_set_i2c_speed(adap->dev, 200); - return adap->fe[0] == NULL ? -ENODEV : 0; + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } static int tfe7090pvr_tuner0_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe[0]); + struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe_adap[0].fe); - if (dvb_attach(dib0090_register, adap->fe[0], tun_i2c, &tfe7090pvr_dib0090_config[0]) == NULL) + if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &tfe7090pvr_dib0090_config[0]) == NULL) return -ENODEV; - dib7000p_set_gpio(adap->fe[0], 8, 0, 1); + dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); - st->set_param_save = adap->fe[0]->ops.tuner_ops.set_params; - adap->fe[0]->ops.tuner_ops.set_params = dib7090_agc_startup; + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup; return 0; } static int tfe7090pvr_tuner1_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe[0]); + struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe_adap[0].fe); - if (dvb_attach(dib0090_register, adap->fe[0], tun_i2c, &tfe7090pvr_dib0090_config[1]) == NULL) + if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &tfe7090pvr_dib0090_config[1]) == NULL) return -ENODEV; - dib7000p_set_gpio(adap->fe[0], 8, 0, 1); + dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); - st->set_param_save = adap->fe[0]->ops.tuner_ops.set_params; - adap->fe[0]->ops.tuner_ops.set_params = dib7090_agc_startup; + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup; return 0; } @@ -2555,14 +2555,14 @@ static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap) return -ENODEV; } - adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]); - return adap->fe[0] == NULL ? -ENODEV : 0; + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]); + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap) { - adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x82, &stk7070pd_dib7000p_config[1]); - return adap->fe[0] == NULL ? -ENODEV : 0; + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x82, &stk7070pd_dib7000p_config[1]); + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } /* S5H1411 */ @@ -2617,9 +2617,9 @@ static int s5h1411_frontend_attach(struct dvb_usb_adapter *adap) dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 1); /* GPIOs are initialized, do the attach */ - adap->fe[0] = dvb_attach(s5h1411_attach, &pinnacle_801e_config, + adap->fe_adap[0].fe = dvb_attach(s5h1411_attach, &pinnacle_801e_config, &adap->dev->i2c_adap); - return adap->fe[0] == NULL ? -ENODEV : 0; + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } static int dib0700_xc5000_tuner_callback(void *priv, int component, @@ -2649,9 +2649,9 @@ static struct xc5000_config s5h1411_xc5000_tunerconfig = { static int xc5000_tuner_attach(struct dvb_usb_adapter *adap) { /* FIXME: generalize & move to common area */ - adap->fe[0]->callback = dib0700_xc5000_tuner_callback; + adap->fe_adap[0].fe->callback = dib0700_xc5000_tuner_callback; - return dvb_attach(xc5000_attach, adap->fe[0], &adap->dev->i2c_adap, + return dvb_attach(xc5000_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, &s5h1411_xc5000_tunerconfig) == NULL ? -ENODEV : 0; } @@ -2663,9 +2663,9 @@ static int dib0700_xc4000_tuner_callback(void *priv, int component, if (command == XC4000_TUNER_RESET) { /* Reset the tuner */ - dib7000p_set_gpio(adap->fe[0], 8, 0, 0); + dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 0); msleep(10); - dib7000p_set_gpio(adap->fe[0], 8, 0, 1); + dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); } else { err("xc4000: unknown tuner callback command: %d\n", command); return -EINVAL; @@ -2771,11 +2771,11 @@ static int pctv340e_frontend_attach(struct dvb_usb_adapter *adap) return -ENODEV; } - adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x12, + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x12, &pctv_340e_config); st->is_dib7000pc = 1; - return adap->fe[0] == NULL ? -ENODEV : 0; + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } static struct xc4000_config dib7000p_xc4000_tunerconfig = { @@ -2791,7 +2791,7 @@ static int xc4000_tuner_attach(struct dvb_usb_adapter *adap) struct i2c_adapter *tun_i2c; /* The xc4000 is not on the main i2c bus */ - tun_i2c = dib7000p_get_i2c_master(adap->fe[0], + tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); if (tun_i2c == NULL) { printk(KERN_ERR "Could not reach tuner i2c bus\n"); @@ -2799,9 +2799,9 @@ static int xc4000_tuner_attach(struct dvb_usb_adapter *adap) } /* Setup the reset callback */ - adap->fe[0]->callback = dib0700_xc4000_tuner_callback; + adap->fe_adap[0].fe->callback = dib0700_xc4000_tuner_callback; - return dvb_attach(xc4000_attach, adap->fe[0], tun_i2c, + return dvb_attach(xc4000_attach, adap->fe_adap[0].fe, tun_i2c, &dib7000p_xc4000_tunerconfig) == NULL ? -ENODEV : 0; } @@ -2857,16 +2857,16 @@ static int lgdt3305_frontend_attach(struct dvb_usb_adapter *adap) dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(30); - adap->fe[0] = dvb_attach(lgdt3305_attach, + adap->fe_adap[0].fe = dvb_attach(lgdt3305_attach, &hcw_lgdt3305_config, &adap->dev->i2c_adap); - return adap->fe[0] == NULL ? -ENODEV : 0; + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } static int mxl5007t_tuner_attach(struct dvb_usb_adapter *adap) { - return dvb_attach(mxl5007t_attach, adap->fe[0], + return dvb_attach(mxl5007t_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, 0x60, &hcw_mxl5007t_config) == NULL ? -ENODEV : 0; } @@ -2989,6 +2989,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, .pid_filter = stk7700p_pid_filter, @@ -2997,6 +2999,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .tuner_attach = stk7700p_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }}, }, }, @@ -3050,15 +3053,21 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 2, .adapter = { { + .num_frontends = 1, + .fe = {{ .frontend_attach = bristol_frontend_attach, .tuner_attach = bristol_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }}, }, { + .num_frontends = 1, + .fe = {{ .frontend_attach = bristol_frontend_attach, .tuner_attach = bristol_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + }}, } }, @@ -3084,6 +3093,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 2, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, .pid_filter = stk70x0p_pid_filter, @@ -3092,7 +3103,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { .tuner_attach = stk7700d_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }}, }, { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, .pid_filter = stk70x0p_pid_filter, @@ -3101,6 +3115,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .tuner_attach = stk7700d_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + }}, } }, @@ -3143,6 +3158,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, .pid_filter = stk70x0p_pid_filter, @@ -3151,6 +3168,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .tuner_attach = stk7700d_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }}, }, }, @@ -3185,6 +3203,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, .pid_filter = stk70x0p_pid_filter, @@ -3193,7 +3213,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .tuner_attach = dib7070p_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - + }}, .size_of_priv = sizeof(struct dib0700_adapter_state), }, }, @@ -3261,6 +3281,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, .pid_filter = stk70x0p_pid_filter, @@ -3269,7 +3291,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .tuner_attach = dib7070p_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - + }}, .size_of_priv = sizeof(struct dib0700_adapter_state), }, }, @@ -3305,6 +3327,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 2, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, .pid_filter = stk70x0p_pid_filter, @@ -3313,9 +3337,11 @@ struct dvb_usb_device_properties dib0700_devices[] = { .tuner_attach = dib7070p_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - + }}, .size_of_priv = sizeof(struct dib0700_adapter_state), }, { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, .pid_filter = stk70x0p_pid_filter, @@ -3324,7 +3350,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .tuner_attach = dib7070p_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x03), - + }}, .size_of_priv = sizeof(struct dib0700_adapter_state), } }, @@ -3373,6 +3399,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 2, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, .pid_filter = stk70x0p_pid_filter, @@ -3381,9 +3409,11 @@ struct dvb_usb_device_properties dib0700_devices[] = { .tuner_attach = dib7070p_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - + }}, .size_of_priv = sizeof(struct dib0700_adapter_state), }, { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, .pid_filter = stk70x0p_pid_filter, @@ -3392,7 +3422,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .tuner_attach = dib7070p_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x03), - + }}, .size_of_priv = sizeof(struct dib0700_adapter_state), } }, @@ -3420,6 +3450,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, .pid_filter = stk70x0p_pid_filter, @@ -3428,7 +3460,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .tuner_attach = stk7700ph_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - + }}, .size_of_priv = sizeof(struct dib0700_adapter_state), }, @@ -3488,11 +3520,13 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .frontend_attach = s5h1411_frontend_attach, .tuner_attach = xc5000_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - + }}, .size_of_priv = sizeof(struct dib0700_adapter_state), }, @@ -3524,11 +3558,13 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .frontend_attach = lgdt3305_frontend_attach, .tuner_attach = mxl5007t_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - + }}, .size_of_priv = sizeof(struct dib0700_adapter_state), }, @@ -3550,6 +3586,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, .pid_filter = stk70x0p_pid_filter, @@ -3558,7 +3596,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .tuner_attach = dib7770p_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - + }}, .size_of_priv = sizeof(struct dib0700_adapter_state), }, @@ -3600,6 +3638,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, .pid_filter = stk80xx_pid_filter, @@ -3608,7 +3648,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .tuner_attach = dib807x_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - + }}, .size_of_priv = sizeof(struct dib0700_adapter_state), }, @@ -3644,6 +3684,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 2, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, .pid_filter = stk80xx_pid_filter, @@ -3652,11 +3694,13 @@ struct dvb_usb_device_properties dib0700_devices[] = { .tuner_attach = dib807x_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - + }}, .size_of_priv = sizeof(struct dib0700_adapter_state), }, { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, .pid_filter = stk80xx_pid_filter, @@ -3665,7 +3709,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .tuner_attach = dib807x_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x03), - + }}, .size_of_priv = sizeof(struct dib0700_adapter_state), }, @@ -3693,6 +3737,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, @@ -3702,7 +3748,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .tuner_attach = dib809x_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - + }}, .size_of_priv = sizeof(struct dib0700_adapter_state), }, @@ -3730,6 +3776,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, @@ -3739,7 +3787,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .tuner_attach = dib9090_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - + }}, .size_of_priv = sizeof(struct dib0700_adapter_state), }, @@ -3767,6 +3815,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, @@ -3776,7 +3826,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .tuner_attach = nim8096md_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - + }}, .size_of_priv = sizeof(struct dib0700_adapter_state), }, @@ -3804,6 +3854,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, @@ -3813,7 +3865,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .tuner_attach = nim9090md_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - + }}, .size_of_priv = sizeof(struct dib0700_adapter_state), }, @@ -3841,6 +3893,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, @@ -3850,7 +3904,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .tuner_attach = nim7090_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - + }}, .size_of_priv = sizeof(struct dib0700_adapter_state), }, @@ -3878,6 +3932,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 2, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, @@ -3887,11 +3943,13 @@ struct dvb_usb_device_properties dib0700_devices[] = { .tuner_attach = tfe7090pvr_tuner0_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x03), - + }}, .size_of_priv = sizeof(struct dib0700_adapter_state), }, { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, @@ -3901,7 +3959,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .tuner_attach = tfe7090pvr_tuner1_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - + }}, .size_of_priv = sizeof(struct dib0700_adapter_state), }, @@ -3929,11 +3987,13 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .frontend_attach = pctv340e_frontend_attach, .tuner_attach = xc4000_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - + }}, .size_of_priv = sizeof(struct dib0700_adapter_state), }, diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c index 263235e..735e914 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-common.c +++ b/drivers/media/dvb/dvb-usb/dibusb-common.c @@ -23,7 +23,7 @@ int dibusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) if (adap->priv != NULL) { struct dibusb_state *st = adap->priv; if (st->ops.fifo_ctrl != NULL) - if (st->ops.fifo_ctrl(adap->fe[0],onoff)) { + if (st->ops.fifo_ctrl(adap->fe_adap[0].fe,onoff)) { err("error while controlling the fifo of the demod."); return -ENODEV; } @@ -37,7 +37,7 @@ int dibusb_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onof if (adap->priv != NULL) { struct dibusb_state *st = adap->priv; if (st->ops.pid_ctrl != NULL) - st->ops.pid_ctrl(adap->fe[0],index,pid,onoff); + st->ops.pid_ctrl(adap->fe_adap[0].fe,index,pid,onoff); } return 0; } @@ -48,7 +48,7 @@ int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) if (adap->priv != NULL) { struct dibusb_state *st = adap->priv; if (st->ops.pid_parse != NULL) - if (st->ops.pid_parse(adap->fe[0],onoff) < 0) + if (st->ops.pid_parse(adap->fe_adap[0].fe,onoff) < 0) err("could not handle pid_parser"); } return 0; @@ -254,8 +254,8 @@ int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap) msleep(1000); } - if ((adap->fe[0] = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000P_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL || - (adap->fe[0] = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000MC_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL) { + if ((adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000P_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL || + (adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000MC_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL) { if (adap->priv != NULL) { struct dibusb_state *st = adap->priv; st->ops.pid_parse = dib3000mc_pid_parse; @@ -309,15 +309,15 @@ int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap) } } - tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe[0], 1); - if (dvb_attach(mt2060_attach, adap->fe[0], tun_i2c, &stk3000p_mt2060_config, if1) == NULL) { + tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe_adap[0].fe, 1); + if (dvb_attach(mt2060_attach, adap->fe_adap[0].fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) { /* not found - use panasonic pll parameters */ - if (dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL) + if (dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL) return -ENOMEM; } else { st->mt2060_present = 1; /* set the correct parameters for the dib3000p */ - dib3000mc_set_config(adap->fe[0], &stk3000p_dib3000p_config); + dib3000mc_set_config(adap->fe_adap[0].fe, &stk3000p_dib3000p_config); } return 0; } diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c index c653b32..f13b3a3 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mb.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c @@ -31,11 +31,11 @@ static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap) demod_cfg.demod_address = 0x8; - if ((adap->fe[0] = dvb_attach(dib3000mb_attach, &demod_cfg, + if ((adap->fe_adap[0].fe = dvb_attach(dib3000mb_attach, &demod_cfg, &adap->dev->i2c_adap, &st->ops)) == NULL) return -ENODEV; - adap->fe[0]->ops.i2c_gate_ctrl = dib3000mb_i2c_gate_ctrl; + adap->fe_adap[0].fe->ops.i2c_gate_ctrl = dib3000mb_i2c_gate_ctrl; return 0; } @@ -46,7 +46,7 @@ static int dibusb_thomson_tuner_attach(struct dvb_usb_adapter *adap) st->tuner_addr = 0x61; - dvb_attach(dvb_pll_attach, adap->fe[0], 0x61, &adap->dev->i2c_adap, + dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, &adap->dev->i2c_adap, DVB_PLL_TUA6010XS); return 0; } @@ -57,7 +57,7 @@ static int dibusb_panasonic_tuner_attach(struct dvb_usb_adapter *adap) st->tuner_addr = 0x60; - dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, &adap->dev->i2c_adap, + dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap, DVB_PLL_TDA665X); return 0; } @@ -78,16 +78,16 @@ static int dibusb_tuner_probe_and_attach(struct dvb_usb_adapter *adap) /* the Panasonic sits on I2C addrass 0x60, the Thomson on 0x61 */ msg[0].addr = msg[1].addr = st->tuner_addr = 0x60; - if (adap->fe[0]->ops.i2c_gate_ctrl) - adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0],1); + if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl) + adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe,1); if (i2c_transfer(&adap->dev->i2c_adap, msg, 2) != 2) { err("tuner i2c write failed."); ret = -EREMOTEIO; } - if (adap->fe[0]->ops.i2c_gate_ctrl) - adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0],0); + if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl) + adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe,0); if (b2[0] == 0xfe) { info("This device has the Thomson Cable onboard. Which is default."); @@ -185,6 +185,8 @@ static struct dvb_usb_device_properties dibusb1_1_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 16, @@ -205,6 +207,7 @@ static struct dvb_usb_device_properties dibusb1_1_properties = { } } }, + }}, .size_of_priv = sizeof(struct dibusb_state), } }, @@ -272,6 +275,8 @@ static struct dvb_usb_device_properties dibusb1_1_an2235_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_ADAP_HAS_PID_FILTER, .pid_filter_count = 16, @@ -292,6 +297,7 @@ static struct dvb_usb_device_properties dibusb1_1_an2235_properties = { } } }, + }}, .size_of_priv = sizeof(struct dibusb_state), }, }, @@ -338,6 +344,8 @@ static struct dvb_usb_device_properties dibusb2_0b_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 16, @@ -358,6 +366,7 @@ static struct dvb_usb_device_properties dibusb2_0b_properties = { } } }, + }}, .size_of_priv = sizeof(struct dibusb_state), } }, @@ -398,6 +407,8 @@ static struct dvb_usb_device_properties artec_t1_usb2_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 16, @@ -417,6 +428,7 @@ static struct dvb_usb_device_properties artec_t1_usb2_properties = { } } }, + }}, .size_of_priv = sizeof(struct dibusb_state), } }, diff --git a/drivers/media/dvb/dvb-usb/dibusb-mc.c b/drivers/media/dvb/dvb-usb/dibusb-mc.c index c1d9094..9c165e2 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mc.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mc.c @@ -57,6 +57,8 @@ static struct dvb_usb_device_properties dibusb_mc_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, .streaming_ctrl = dibusb2_0_streaming_ctrl, @@ -76,6 +78,7 @@ static struct dvb_usb_device_properties dibusb_mc_properties = { } } }, + }}, .size_of_priv = sizeof(struct dibusb_state), } }, diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c index 1e17d15..edabdae 100644 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -137,11 +137,11 @@ static int digitv_frontend_attach(struct dvb_usb_adapter *adap) { struct digitv_state *st = adap->dev->priv; - if ((adap->fe[0] = dvb_attach(mt352_attach, &digitv_mt352_config, &adap->dev->i2c_adap)) != NULL) { + if ((adap->fe_adap[0].fe = dvb_attach(mt352_attach, &digitv_mt352_config, &adap->dev->i2c_adap)) != NULL) { st->is_nxt6000 = 0; return 0; } - if ((adap->fe[0] = dvb_attach(nxt6000_attach, &digitv_nxt6000_config, &adap->dev->i2c_adap)) != NULL) { + if ((adap->fe_adap[0].fe = dvb_attach(nxt6000_attach, &digitv_nxt6000_config, &adap->dev->i2c_adap)) != NULL) { st->is_nxt6000 = 1; return 0; } @@ -152,11 +152,11 @@ static int digitv_tuner_attach(struct dvb_usb_adapter *adap) { struct digitv_state *st = adap->dev->priv; - if (!dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, NULL, DVB_PLL_TDED4)) + if (!dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, NULL, DVB_PLL_TDED4)) return -ENODEV; if (st->is_nxt6000) - adap->fe[0]->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params; return 0; } @@ -292,6 +292,8 @@ static struct dvb_usb_device_properties digitv_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .frontend_attach = digitv_frontend_attach, .tuner_attach = digitv_tuner_attach, @@ -306,6 +308,7 @@ static struct dvb_usb_device_properties digitv_properties = { } } }, + }}, } }, .identify_state = digitv_identify_state, diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c index ea2a46f..106dfd5 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u.c +++ b/drivers/media/dvb/dvb-usb/dtt200u.c @@ -90,7 +90,7 @@ static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state) static int dtt200u_frontend_attach(struct dvb_usb_adapter *adap) { - adap->fe[0] = dtt200u_fe_attach(adap->dev); + adap->fe_adap[0].fe = dtt200u_fe_attach(adap->dev); return 0; } @@ -140,6 +140,8 @@ static struct dvb_usb_device_properties dtt200u_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, .pid_filter_count = 15, @@ -157,6 +159,7 @@ static struct dvb_usb_device_properties dtt200u_properties = { } } }, + }}, } }, .power_ctrl = dtt200u_power_ctrl, @@ -187,6 +190,8 @@ static struct dvb_usb_device_properties wt220u_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, .pid_filter_count = 15, @@ -204,6 +209,7 @@ static struct dvb_usb_device_properties wt220u_properties = { } } }, + }}, } }, .power_ctrl = dtt200u_power_ctrl, @@ -234,6 +240,8 @@ static struct dvb_usb_device_properties wt220u_fc_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, .pid_filter_count = 15, @@ -251,6 +259,7 @@ static struct dvb_usb_device_properties wt220u_fc_properties = { } } }, + }}, } }, .power_ctrl = dtt200u_power_ctrl, @@ -281,6 +290,8 @@ static struct dvb_usb_device_properties wt220u_zl0353_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, .pid_filter_count = 15, @@ -298,6 +309,7 @@ static struct dvb_usb_device_properties wt220u_zl0353_properties = { } } }, + }}, } }, .power_ctrl = dtt200u_power_ctrl, diff --git a/drivers/media/dvb/dvb-usb/dtv5100.c b/drivers/media/dvb/dvb-usb/dtv5100.c index 75ed55c..7373132 100644 --- a/drivers/media/dvb/dvb-usb/dtv5100.c +++ b/drivers/media/dvb/dvb-usb/dtv5100.c @@ -115,13 +115,13 @@ static struct zl10353_config dtv5100_zl10353_config = { static int dtv5100_frontend_attach(struct dvb_usb_adapter *adap) { - adap->fe[0] = dvb_attach(zl10353_attach, &dtv5100_zl10353_config, + adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &dtv5100_zl10353_config, &adap->dev->i2c_adap); - if (adap->fe[0] == NULL) + if (adap->fe_adap[0].fe == NULL) return -EIO; /* disable i2c gate, or it won't work... is this safe? */ - adap->fe[0]->ops.i2c_gate_ctrl = NULL; + adap->fe_adap[0].fe->ops.i2c_gate_ctrl = NULL; return 0; } @@ -133,7 +133,7 @@ static struct qt1010_config dtv5100_qt1010_config = { static int dtv5100_tuner_attach(struct dvb_usb_adapter *adap) { return dvb_attach(qt1010_attach, - adap->fe[0], &adap->dev->i2c_adap, + adap->fe_adap[0].fe, &adap->dev->i2c_adap, &dtv5100_qt1010_config) == NULL ? -ENODEV : 0; } @@ -180,6 +180,8 @@ static struct dvb_usb_device_properties dtv5100_properties = { .num_adapters = 1, .adapter = {{ + .num_frontends = 1, + .fe = {{ .frontend_attach = dtv5100_frontend_attach, .tuner_attach = dtv5100_tuner_attach, @@ -193,6 +195,7 @@ static struct dvb_usb_device_properties dtv5100_properties = { } } }, + }}, } }, .i2c_algo = &dtv5100_i2c_algo, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c index 5e34df7..3f11159 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c @@ -17,15 +17,19 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) if (adap == NULL) return -ENODEV; + if (adap->active_fe < 0) { + return -EINVAL; + } + newfeedcount = adap->feedcount + (onoff ? 1 : -1); /* stop feed before setting a new pid if there will be no pid anymore */ if (newfeedcount == 0) { deb_ts("stop feeding\n"); - usb_urb_kill(&adap->stream); + usb_urb_kill(&adap->fe_adap[adap->active_fe].stream); - if (adap->props.streaming_ctrl != NULL) { - ret = adap->props.streaming_ctrl(adap, 0); + if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) { + ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 0); if (ret < 0) { err("error while stopping stream."); return ret; @@ -36,36 +40,36 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) adap->feedcount = newfeedcount; /* activate the pid on the device specific pid_filter */ - deb_ts("setting pid (%s): %5d %04x at index %d '%s'\n",adap->pid_filtering ? + deb_ts("setting pid (%s): %5d %04x at index %d '%s'\n",adap->fe_adap[adap->active_fe].pid_filtering ? "yes" : "no", dvbdmxfeed->pid,dvbdmxfeed->pid,dvbdmxfeed->index,onoff ? "on" : "off"); - if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER && - adap->pid_filtering && - adap->props.pid_filter != NULL) - adap->props.pid_filter(adap, dvbdmxfeed->index, dvbdmxfeed->pid,onoff); + if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER && + adap->fe_adap[adap->active_fe].pid_filtering && + adap->props.fe[adap->active_fe].pid_filter != NULL) + adap->props.fe[adap->active_fe].pid_filter(adap, dvbdmxfeed->index, dvbdmxfeed->pid, onoff); /* start the feed if this was the first feed and there is still a feed * for reception. */ if (adap->feedcount == onoff && adap->feedcount > 0) { deb_ts("submitting all URBs\n"); - usb_urb_submit(&adap->stream); + usb_urb_submit(&adap->fe_adap[adap->active_fe].stream); deb_ts("controlling pid parser\n"); - if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER && - adap->props.caps & + if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER && + adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF && - adap->props.pid_filter_ctrl != NULL) { - ret = adap->props.pid_filter_ctrl(adap, - adap->pid_filtering); + adap->props.fe[adap->active_fe].pid_filter_ctrl != NULL) { + ret = adap->props.fe[adap->active_fe].pid_filter_ctrl(adap, + adap->fe_adap[adap->active_fe].pid_filtering); if (ret < 0) { err("could not handle pid_parser"); return ret; } } deb_ts("start feeding\n"); - if (adap->props.streaming_ctrl != NULL) { - ret = adap->props.streaming_ctrl(adap, 1); + if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) { + ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 1); if (ret < 0) { err("error while enabling fifo."); return ret; @@ -73,6 +77,9 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) } } + if ((adap->feedcount == onoff) && (!onoff)) + adap->active_fe = -1; + return 0; } @@ -90,6 +97,7 @@ static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums) { + int i; int ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->desc->name, adap->dev->owner, &adap->dev->udev->dev, adapter_nums); @@ -112,7 +120,12 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums) adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; adap->demux.priv = adap; - adap->demux.feednum = adap->demux.filternum = adap->max_feed_count; + adap->demux.filternum = 0; + for (i = 0; i < adap->props.num_frontends; i++) { + if (adap->demux.filternum < adap->fe_adap[i].max_feed_count) + adap->demux.filternum = adap->fe_adap[i].max_feed_count; + } + adap->demux.feednum = adap->demux.filternum; adap->demux.start_feed = dvb_usb_start_feed; adap->demux.stop_feed = dvb_usb_stop_feed; adap->demux.write_to_decoder = NULL; @@ -156,17 +169,33 @@ int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap) return 0; } +static int dvb_usb_set_active_fe(struct dvb_frontend *fe, int onoff) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + + int ret = (adap->props.frontend_ctrl) ? + adap->props.frontend_ctrl(fe, onoff) : 0; + + if (ret < 0) { + err("frontend_ctrl request failed"); + return ret; + } + if (onoff) + adap->active_fe = fe->id; + + return 0; +} + static int dvb_usb_fe_wakeup(struct dvb_frontend *fe) { struct dvb_usb_adapter *adap = fe->dvb->priv; dvb_usb_device_power_ctrl(adap->dev, 1); - if (adap->props.frontend_ctrl) - adap->props.frontend_ctrl(fe, 1); + dvb_usb_set_active_fe(fe, 1); - if (adap->fe_init[fe->id]) - adap->fe_init[fe->id](fe); + if (adap->fe_adap[fe->id].fe_init) + adap->fe_adap[fe->id].fe_init(fe); return 0; } @@ -175,37 +204,31 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe) { struct dvb_usb_adapter *adap = fe->dvb->priv; - if (adap->fe_sleep[fe->id]) - adap->fe_sleep[fe->id](fe); + if (adap->fe_adap[fe->id].fe_sleep) + adap->fe_adap[fe->id].fe_sleep(fe); - if (adap->props.frontend_ctrl) - adap->props.frontend_ctrl(fe, 0); + dvb_usb_set_active_fe(fe, 0); return dvb_usb_device_power_ctrl(adap->dev, 0); } int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) { - int ret, i, x; + int ret, i; - memset(adap->fe, 0, sizeof(adap->fe)); + /* register all given adapter frontends */ + for (i = 0; i < adap->props.num_frontends; i++) { - if (adap->props.frontend_attach == NULL) { - err("strange: '%s' #%d doesn't want to attach a frontend.", - adap->dev->desc->name, adap->id); + if (adap->props.fe[i].frontend_attach == NULL) { + err("strange: '%s' #%d,%d " + "doesn't want to attach a frontend.", + adap->dev->desc->name, adap->id, i); - return 0; - } + return 0; + } - /* register all given adapter frontends */ - if (adap->props.num_frontends) - x = adap->props.num_frontends - 1; - else - x = 0; - - for (i = 0; i <= x; i++) { - ret = adap->props.frontend_attach(adap); - if (ret || adap->fe[i] == NULL) { + ret = adap->props.fe[i].frontend_attach(adap); + if (ret || adap->fe_adap[i].fe == NULL) { /* only print error when there is no FE at all */ if (i == 0) err("no frontend was attached by '%s'", @@ -214,18 +237,18 @@ int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) return 0; } - adap->fe[i]->id = i; + adap->fe_adap[i].fe->id = i; /* re-assign sleep and wakeup functions */ - adap->fe_init[i] = adap->fe[i]->ops.init; - adap->fe[i]->ops.init = dvb_usb_fe_wakeup; - adap->fe_sleep[i] = adap->fe[i]->ops.sleep; - adap->fe[i]->ops.sleep = dvb_usb_fe_sleep; + adap->fe_adap[i].fe_init = adap->fe_adap[i].fe->ops.init; + adap->fe_adap[i].fe->ops.init = dvb_usb_fe_wakeup; + adap->fe_adap[i].fe_sleep = adap->fe_adap[i].fe->ops.sleep; + adap->fe_adap[i].fe->ops.sleep = dvb_usb_fe_sleep; - if (dvb_register_frontend(&adap->dvb_adap, adap->fe[i])) { + if (dvb_register_frontend(&adap->dvb_adap, adap->fe_adap[i].fe)) { err("Frontend %d registration failed.", i); - dvb_frontend_detach(adap->fe[i]); - adap->fe[i] = NULL; + dvb_frontend_detach(adap->fe_adap[i].fe); + adap->fe_adap[i].fe = NULL; /* In error case, do not try register more FEs, * still leaving already registered FEs alive. */ if (i == 0) @@ -235,8 +258,10 @@ int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) } /* only attach the tuner if the demod is there */ - if (adap->props.tuner_attach != NULL) - adap->props.tuner_attach(adap); + if (adap->props.fe[i].tuner_attach != NULL) + adap->props.fe[i].tuner_attach(adap); + + adap->num_frontends_initialized++; } return 0; @@ -244,20 +269,16 @@ int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap) { - int i; + int i = adap->num_frontends_initialized - 1; /* unregister all given adapter frontends */ - if (adap->props.num_frontends) - i = adap->props.num_frontends - 1; - else - i = 0; - for (; i >= 0; i--) { - if (adap->fe[i] != NULL) { - dvb_unregister_frontend(adap->fe[i]); - dvb_frontend_detach(adap->fe[i]); + if (adap->fe_adap[i].fe != NULL) { + dvb_unregister_frontend(adap->fe_adap[i].fe); + dvb_frontend_detach(adap->fe_adap[i].fe); } } + adap->num_frontends_initialized = 0; return 0; } diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c index f9af348..169196e 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c @@ -29,7 +29,7 @@ MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a PID static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs) { struct dvb_usb_adapter *adap; - int ret, n; + int ret, n, o; for (n = 0; n < d->props.num_adapters; n++) { adap = &d->adapter[n]; @@ -38,31 +38,42 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs) memcpy(&adap->props, &d->props.adapter[n], sizeof(struct dvb_usb_adapter_properties)); + for (o = 0; o < adap->props.num_frontends; o++) { + struct dvb_usb_adapter_fe_properties *props = &adap->props.fe[o]; /* speed - when running at FULL speed we need a HW PID filter */ - if (d->udev->speed == USB_SPEED_FULL && !(adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER)) { + if (d->udev->speed == USB_SPEED_FULL && !(props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) { err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)"); return -ENODEV; } - if ((d->udev->speed == USB_SPEED_FULL && adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) || - (adap->props.caps & DVB_USB_ADAP_NEED_PID_FILTERING)) { - info("will use the device's hardware PID filter (table count: %d).", adap->props.pid_filter_count); - adap->pid_filtering = 1; - adap->max_feed_count = adap->props.pid_filter_count; + if ((d->udev->speed == USB_SPEED_FULL && props->caps & DVB_USB_ADAP_HAS_PID_FILTER) || + (props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) { + info("will use the device's hardware PID filter (table count: %d).", props->pid_filter_count); + adap->fe_adap[o].pid_filtering = 1; + adap->fe_adap[o].max_feed_count = props->pid_filter_count; } else { info("will pass the complete MPEG2 transport stream to the software demuxer."); - adap->pid_filtering = 0; - adap->max_feed_count = 255; + adap->fe_adap[o].pid_filtering = 0; + adap->fe_adap[o].max_feed_count = 255; } - if (!adap->pid_filtering && + if (!adap->fe_adap[o].pid_filtering && dvb_usb_force_pid_filter_usage && - adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) { + props->caps & DVB_USB_ADAP_HAS_PID_FILTER) { info("pid filter enabled by module option."); - adap->pid_filtering = 1; - adap->max_feed_count = adap->props.pid_filter_count; + adap->fe_adap[o].pid_filtering = 1; + adap->fe_adap[o].max_feed_count = props->pid_filter_count; } + if (props->size_of_priv > 0) { + adap->fe_adap[o].priv = kzalloc(props->size_of_priv, GFP_KERNEL); + if (adap->fe_adap[o].priv == NULL) { + err("no memory for priv for adapter %d fe %d.", n, o); + return -ENOMEM; + } + } + } + if (adap->props.size_of_priv > 0) { adap->priv = kzalloc(adap->props.size_of_priv, GFP_KERNEL); if (adap->priv == NULL) { @@ -78,7 +89,7 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs) } /* use exclusive FE lock if there is multiple shared FEs */ - if (adap->fe[1]) + if (adap->fe_adap[1].fe) adap->dvb_adap.mfe_shared = 1; d->num_adapters_initialized++; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c index bb46ba6..53a5c30 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c @@ -82,16 +82,28 @@ static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buffer int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap) { - adap->stream.udev = adap->dev->udev; - if (adap->props.caps & DVB_USB_ADAP_RECEIVES_204_BYTE_TS) - adap->stream.complete = dvb_usb_data_complete_204; - else - adap->stream.complete = dvb_usb_data_complete; - adap->stream.user_priv = adap; - return usb_urb_init(&adap->stream, &adap->props.stream); + int i, ret = 0; + for (i = 0; i < adap->props.num_frontends; i++) { + + adap->fe_adap[i].stream.udev = adap->dev->udev; + if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_204_BYTE_TS) + adap->fe_adap[i].stream.complete = + dvb_usb_data_complete_204; + else + adap->fe_adap[i].stream.complete = dvb_usb_data_complete; + adap->fe_adap[i].stream.user_priv = adap; + ret = usb_urb_init(&adap->fe_adap[i].stream, + &adap->props.fe[i].stream); + if (ret < 0) + break; + } + return ret; } int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap) { - return usb_urb_exit(&adap->stream); + int i; + for (i = 0; i < adap->props.num_frontends; i++) + usb_urb_exit(&adap->fe_adap[i].stream); + return 0; } diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h index a3e77b2..6d7d13f 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -136,16 +136,14 @@ struct usb_data_stream_properties { * pll_desc and pll_init_buf of struct dvb_usb_device). * @stream: configuration of the USB streaming */ -struct dvb_usb_adapter_properties { +struct dvb_usb_adapter_fe_properties { #define DVB_USB_ADAP_HAS_PID_FILTER 0x01 #define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02 #define DVB_USB_ADAP_NEED_PID_FILTERING 0x04 #define DVB_USB_ADAP_RECEIVES_204_BYTE_TS 0x08 int caps; int pid_filter_count; - int num_frontends; - int (*frontend_ctrl) (struct dvb_frontend *, int); int (*streaming_ctrl) (struct dvb_usb_adapter *, int); int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int); int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int); @@ -156,9 +154,18 @@ struct dvb_usb_adapter_properties { struct usb_data_stream_properties stream; int size_of_priv; +}; + +#define MAX_NO_OF_FE_PER_ADAP 2 +struct dvb_usb_adapter_properties { + int size_of_priv; + int (*frontend_ctrl) (struct dvb_frontend *, int); int (*fe_ioctl_override) (struct dvb_frontend *, unsigned int, void *, unsigned int); + + int num_frontends; + struct dvb_usb_adapter_fe_properties fe[MAX_NO_OF_FE_PER_ADAP]; }; /** @@ -349,7 +356,20 @@ struct usb_data_stream { * * @stream: the usb data stream. */ -#define MAX_NO_OF_FE_PER_ADAP 2 +struct dvb_usb_fe_adapter { + struct dvb_frontend *fe; + + int (*fe_init) (struct dvb_frontend *); + int (*fe_sleep) (struct dvb_frontend *); + + struct usb_data_stream stream; + + int pid_filtering; + int max_feed_count; + + void *priv; +}; + struct dvb_usb_adapter { struct dvb_usb_device *dev; struct dvb_usb_adapter_properties props; @@ -361,20 +381,16 @@ struct dvb_usb_adapter { u8 id; int feedcount; - int pid_filtering; /* dvb */ struct dvb_adapter dvb_adap; struct dmxdev dmxdev; struct dvb_demux demux; struct dvb_net dvb_net; - struct dvb_frontend *fe[MAX_NO_OF_FE_PER_ADAP]; - int max_feed_count; - - int (*fe_init[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *); - int (*fe_sleep[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *); - struct usb_data_stream stream; + struct dvb_usb_fe_adapter fe_adap[MAX_NO_OF_FE_PER_ADAP]; + int active_fe; + int num_frontends_initialized; void *priv; }; diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index eb5dff5..f103ec1 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -992,18 +992,18 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d) struct dvb_tuner_ops *tuner_ops = NULL; if (demod_probe & 4) { - d->fe[0] = dvb_attach(stv0900_attach, &dw2104a_stv0900_config, + d->fe_adap[0].fe = dvb_attach(stv0900_attach, &dw2104a_stv0900_config, &d->dev->i2c_adap, 0); - if (d->fe[0] != NULL) { - if (dvb_attach(stb6100_attach, d->fe[0], + if (d->fe_adap[0].fe != NULL) { + if (dvb_attach(stb6100_attach, d->fe_adap[0].fe, &dw2104a_stb6100_config, &d->dev->i2c_adap)) { - tuner_ops = &d->fe[0]->ops.tuner_ops; + tuner_ops = &d->fe_adap[0].fe->ops.tuner_ops; tuner_ops->set_frequency = stb6100_set_freq; tuner_ops->get_frequency = stb6100_get_freq; tuner_ops->set_bandwidth = stb6100_set_bandw; tuner_ops->get_bandwidth = stb6100_get_bandw; - d->fe[0]->ops.set_voltage = dw210x_set_voltage; + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; info("Attached STV0900+STB6100!\n"); return 0; } @@ -1011,13 +1011,13 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d) } if (demod_probe & 2) { - d->fe[0] = dvb_attach(stv0900_attach, &dw2104_stv0900_config, + d->fe_adap[0].fe = dvb_attach(stv0900_attach, &dw2104_stv0900_config, &d->dev->i2c_adap, 0); - if (d->fe[0] != NULL) { - if (dvb_attach(stv6110_attach, d->fe[0], + if (d->fe_adap[0].fe != NULL) { + if (dvb_attach(stv6110_attach, d->fe_adap[0].fe, &dw2104_stv6110_config, &d->dev->i2c_adap)) { - d->fe[0]->ops.set_voltage = dw210x_set_voltage; + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; info("Attached STV0900+STV6110A!\n"); return 0; } @@ -1025,19 +1025,19 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d) } if (demod_probe & 1) { - d->fe[0] = dvb_attach(cx24116_attach, &dw2104_config, + d->fe_adap[0].fe = dvb_attach(cx24116_attach, &dw2104_config, &d->dev->i2c_adap); - if (d->fe[0] != NULL) { - d->fe[0]->ops.set_voltage = dw210x_set_voltage; + if (d->fe_adap[0].fe != NULL) { + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; info("Attached cx24116!\n"); return 0; } } - d->fe[0] = dvb_attach(ds3000_attach, &dw2104_ds3000_config, + d->fe_adap[0].fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config, &d->dev->i2c_adap); - if (d->fe[0] != NULL) { - d->fe[0]->ops.set_voltage = dw210x_set_voltage; + if (d->fe_adap[0].fe != NULL) { + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; info("Attached DS3000!\n"); return 0; } @@ -1053,22 +1053,22 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d) { if (dw2102_properties.i2c_algo == &dw2102_serit_i2c_algo) { /*dw2102_properties.adapter->tuner_attach = NULL;*/ - d->fe[0] = dvb_attach(si21xx_attach, &serit_sp1511lhb_config, + d->fe_adap[0].fe = dvb_attach(si21xx_attach, &serit_sp1511lhb_config, &d->dev->i2c_adap); - if (d->fe[0] != NULL) { - d->fe[0]->ops.set_voltage = dw210x_set_voltage; + if (d->fe_adap[0].fe != NULL) { + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; info("Attached si21xx!\n"); return 0; } } if (dw2102_properties.i2c_algo == &dw2102_earda_i2c_algo) { - d->fe[0] = dvb_attach(stv0288_attach, &earda_config, + d->fe_adap[0].fe = dvb_attach(stv0288_attach, &earda_config, &d->dev->i2c_adap); - if (d->fe[0] != NULL) { - if (dvb_attach(stb6000_attach, d->fe[0], 0x61, + if (d->fe_adap[0].fe != NULL) { + if (dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61, &d->dev->i2c_adap)) { - d->fe[0]->ops.set_voltage = dw210x_set_voltage; + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; info("Attached stv0288!\n"); return 0; } @@ -1077,10 +1077,10 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d) if (dw2102_properties.i2c_algo == &dw2102_i2c_algo) { /*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/ - d->fe[0] = dvb_attach(stv0299_attach, &sharp_z0194a_config, + d->fe_adap[0].fe = dvb_attach(stv0299_attach, &sharp_z0194a_config, &d->dev->i2c_adap); - if (d->fe[0] != NULL) { - d->fe[0]->ops.set_voltage = dw210x_set_voltage; + if (d->fe_adap[0].fe != NULL) { + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; info("Attached stv0299!\n"); return 0; } @@ -1090,9 +1090,9 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d) static int dw3101_frontend_attach(struct dvb_usb_adapter *d) { - d->fe[0] = dvb_attach(tda10023_attach, &dw3101_tda10023_config, + d->fe_adap[0].fe = dvb_attach(tda10023_attach, &dw3101_tda10023_config, &d->dev->i2c_adap, 0x48); - if (d->fe[0] != NULL) { + if (d->fe_adap[0].fe != NULL) { info("Attached tda10023!\n"); return 0; } @@ -1101,12 +1101,12 @@ static int dw3101_frontend_attach(struct dvb_usb_adapter *d) static int zl100313_frontend_attach(struct dvb_usb_adapter *d) { - d->fe[0] = dvb_attach(mt312_attach, &zl313_config, + d->fe_adap[0].fe = dvb_attach(mt312_attach, &zl313_config, &d->dev->i2c_adap); - if (d->fe[0] != NULL) { - if (dvb_attach(zl10039_attach, d->fe[0], 0x60, + if (d->fe_adap[0].fe != NULL) { + if (dvb_attach(zl10039_attach, d->fe_adap[0].fe, 0x60, &d->dev->i2c_adap)) { - d->fe[0]->ops.set_voltage = dw210x_set_voltage; + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; info("Attached zl100313+zl10039!\n"); return 0; } @@ -1119,16 +1119,16 @@ static int stv0288_frontend_attach(struct dvb_usb_adapter *d) { u8 obuf[] = {7, 1}; - d->fe[0] = dvb_attach(stv0288_attach, &earda_config, + d->fe_adap[0].fe = dvb_attach(stv0288_attach, &earda_config, &d->dev->i2c_adap); - if (d->fe[0] == NULL) + if (d->fe_adap[0].fe == NULL) return -EIO; - if (NULL == dvb_attach(stb6000_attach, d->fe[0], 0x61, &d->dev->i2c_adap)) + if (NULL == dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61, &d->dev->i2c_adap)) return -EIO; - d->fe[0]->ops.set_voltage = dw210x_set_voltage; + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); @@ -1143,14 +1143,14 @@ static int ds3000_frontend_attach(struct dvb_usb_adapter *d) struct s6x0_state *st = (struct s6x0_state *)d->dev->priv; u8 obuf[] = {7, 1}; - d->fe[0] = dvb_attach(ds3000_attach, &dw2104_ds3000_config, + d->fe_adap[0].fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config, &d->dev->i2c_adap); - if (d->fe[0] == NULL) + if (d->fe_adap[0].fe == NULL) return -EIO; - st->old_set_voltage = d->fe[0]->ops.set_voltage; - d->fe[0]->ops.set_voltage = s660_set_voltage; + st->old_set_voltage = d->fe_adap[0].fe->ops.set_voltage; + d->fe_adap[0].fe->ops.set_voltage = s660_set_voltage; dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); @@ -1163,12 +1163,12 @@ static int prof_7500_frontend_attach(struct dvb_usb_adapter *d) { u8 obuf[] = {7, 1}; - d->fe[0] = dvb_attach(stv0900_attach, &prof_7500_stv0900_config, + d->fe_adap[0].fe = dvb_attach(stv0900_attach, &prof_7500_stv0900_config, &d->dev->i2c_adap, 0); - if (d->fe[0] == NULL) + if (d->fe_adap[0].fe == NULL) return -EIO; - d->fe[0]->ops.set_voltage = dw210x_set_voltage; + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); @@ -1204,9 +1204,9 @@ static int su3000_frontend_attach(struct dvb_usb_adapter *d) if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0) err("command 0x51 transfer failed."); - d->fe[0] = dvb_attach(ds3000_attach, &su3000_ds3000_config, + d->fe_adap[0].fe = dvb_attach(ds3000_attach, &su3000_ds3000_config, &d->dev->i2c_adap); - if (d->fe[0] == NULL) + if (d->fe_adap[0].fe == NULL) return -EIO; info("Attached DS3000!\n"); @@ -1216,14 +1216,14 @@ static int su3000_frontend_attach(struct dvb_usb_adapter *d) static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, + dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap, DVB_PLL_OPERA1); return 0; } static int dw3101_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, + dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap, DVB_PLL_TUA6034); return 0; @@ -1535,7 +1535,7 @@ static int dw2102_load_firmware(struct usb_device *dev, DW210X_READ_MSG); if ((reset16[0] == 0xa1) || (reset16[0] == 0x80)) { dw2102_properties.i2c_algo = &dw2102_i2c_algo; - dw2102_properties.adapter->tuner_attach = &dw2102_tuner_attach; + dw2102_properties.adapter->fe[0].tuner_attach = &dw2102_tuner_attach; break; } else { /* check STV0288 frontend */ @@ -1591,6 +1591,8 @@ static struct dvb_usb_device_properties dw2102_properties = { .read_mac_address = dw210x_read_mac_address, .adapter = { { + .num_frontends = 1, + .fe = {{ .frontend_attach = dw2102_frontend_attach, .stream = { .type = USB_BULK, @@ -1602,6 +1604,7 @@ static struct dvb_usb_device_properties dw2102_properties = { } } }, + }}, } }, .num_device_descs = 3, @@ -1642,6 +1645,8 @@ static struct dvb_usb_device_properties dw2104_properties = { .read_mac_address = dw210x_read_mac_address, .adapter = { { + .num_frontends = 1, + .fe = {{ .frontend_attach = dw2104_frontend_attach, .stream = { .type = USB_BULK, @@ -1653,6 +1658,7 @@ static struct dvb_usb_device_properties dw2104_properties = { } } }, + }}, } }, .num_device_descs = 2, @@ -1689,6 +1695,8 @@ static struct dvb_usb_device_properties dw3101_properties = { .read_mac_address = dw210x_read_mac_address, .adapter = { { + .num_frontends = 1, + .fe = {{ .frontend_attach = dw3101_frontend_attach, .tuner_attach = dw3101_tuner_attach, .stream = { @@ -1701,6 +1709,7 @@ static struct dvb_usb_device_properties dw3101_properties = { } } }, + }}, } }, .num_device_descs = 1, @@ -1733,6 +1742,8 @@ static struct dvb_usb_device_properties s6x0_properties = { .read_mac_address = s6x0_read_mac_address, .adapter = { { + .num_frontends = 1, + .fe = {{ .frontend_attach = zl100313_frontend_attach, .stream = { .type = USB_BULK, @@ -1744,6 +1755,7 @@ static struct dvb_usb_device_properties s6x0_properties = { } } }, + }}, } }, .num_device_descs = 1, @@ -1810,6 +1822,8 @@ static struct dvb_usb_device_properties su3000_properties = { .adapter = { { + .num_frontends = 1, + .fe = {{ .streaming_ctrl = su3000_streaming_ctrl, .frontend_attach = su3000_frontend_attach, .stream = { @@ -1822,6 +1836,7 @@ static struct dvb_usb_device_properties su3000_properties = { } } } + }}, } }, .num_device_descs = 3, @@ -1855,7 +1870,7 @@ static int dw2102_probe(struct usb_interface *intf, p1100->devices[0] = d1100; p1100->rc.legacy.rc_map_table = rc_map_tbs_table; p1100->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table); - p1100->adapter->frontend_attach = stv0288_frontend_attach; + p1100->adapter->fe[0].frontend_attach = stv0288_frontend_attach; s660 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL); if (!s660) { @@ -1869,7 +1884,7 @@ static int dw2102_probe(struct usb_interface *intf, s660->devices[0] = d660; s660->devices[1] = d480_1; s660->devices[2] = d480_2; - s660->adapter->frontend_attach = ds3000_frontend_attach; + s660->adapter->fe[0].frontend_attach = ds3000_frontend_attach; p7500 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL); if (!p7500) { @@ -1883,7 +1898,7 @@ static int dw2102_probe(struct usb_interface *intf, p7500->devices[0] = d7500; p7500->rc.legacy.rc_map_table = rc_map_tbs_table; p7500->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table); - p7500->adapter->frontend_attach = prof_7500_frontend_attach; + p7500->adapter->fe[0].frontend_attach = prof_7500_frontend_attach; if (0 == dvb_usb_device_init(intf, &dw2102_properties, THIS_MODULE, NULL, adapter_nr) || diff --git a/drivers/media/dvb/dvb-usb/ec168.c b/drivers/media/dvb/dvb-usb/ec168.c index 581bdfc..78442fe 100644 --- a/drivers/media/dvb/dvb-usb/ec168.c +++ b/drivers/media/dvb/dvb-usb/ec168.c @@ -200,9 +200,9 @@ static struct ec100_config ec168_ec100_config = { static int ec168_ec100_frontend_attach(struct dvb_usb_adapter *adap) { deb_info("%s:\n", __func__); - adap->fe[0] = dvb_attach(ec100_attach, &ec168_ec100_config, + adap->fe_adap[0].fe = dvb_attach(ec100_attach, &ec168_ec100_config, &adap->dev->i2c_adap); - if (adap->fe[0] == NULL) + if (adap->fe_adap[0].fe == NULL) return -ENODEV; return 0; @@ -228,7 +228,7 @@ static struct mxl5005s_config ec168_mxl5003s_config = { static int ec168_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) { deb_info("%s:\n", __func__); - return dvb_attach(mxl5005s_attach, adap->fe[0], &adap->dev->i2c_adap, + return dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, &ec168_mxl5003s_config) == NULL ? -ENODEV : 0; } @@ -382,6 +382,8 @@ static struct dvb_usb_device_properties ec168_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .streaming_ctrl = ec168_streaming_ctrl, .frontend_attach = ec168_ec100_frontend_attach, .tuner_attach = ec168_mxl5003s_tuner_attach, @@ -395,6 +397,7 @@ static struct dvb_usb_device_properties ec168_properties = { } } }, + }}, } }, diff --git a/drivers/media/dvb/dvb-usb/friio.c b/drivers/media/dvb/dvb-usb/friio.c index 0e4b559..b092dc2 100644 --- a/drivers/media/dvb/dvb-usb/friio.c +++ b/drivers/media/dvb/dvb-usb/friio.c @@ -403,8 +403,8 @@ static int friio_frontend_attach(struct dvb_usb_adapter *adap) if (friio_initialize(adap->dev) < 0) return -EIO; - adap->fe[0] = jdvbt90502_attach(adap->dev); - if (adap->fe[0] == NULL) + adap->fe_adap[0].fe = jdvbt90502_attach(adap->dev); + if (adap->fe_adap[0].fe == NULL) return -EIO; return 0; @@ -473,6 +473,8 @@ static struct dvb_usb_device_properties friio_properties = { /* caps:0 => no pid filter, 188B TS packet */ /* GL861 has a HW pid filter, but no info available. */ { + .num_frontends = 1, + .fe = {{ .caps = 0, .frontend_attach = friio_frontend_attach, @@ -490,6 +492,7 @@ static struct dvb_usb_device_properties friio_properties = { } } }, + }}, } }, .i2c_algo = &gl861_i2c_algo, diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c index fba24ed..63681df 100644 --- a/drivers/media/dvb/dvb-usb/gl861.c +++ b/drivers/media/dvb/dvb-usb/gl861.c @@ -103,9 +103,9 @@ static struct zl10353_config gl861_zl10353_config = { static int gl861_frontend_attach(struct dvb_usb_adapter *adap) { - adap->fe[0] = dvb_attach(zl10353_attach, &gl861_zl10353_config, + adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &gl861_zl10353_config, &adap->dev->i2c_adap); - if (adap->fe[0] == NULL) + if (adap->fe_adap[0].fe == NULL) return -EIO; return 0; @@ -118,7 +118,7 @@ static struct qt1010_config gl861_qt1010_config = { static int gl861_tuner_attach(struct dvb_usb_adapter *adap) { return dvb_attach(qt1010_attach, - adap->fe[0], &adap->dev->i2c_adap, + adap->fe_adap[0].fe, &adap->dev->i2c_adap, &gl861_qt1010_config) == NULL ? -ENODEV : 0; } @@ -167,6 +167,8 @@ static struct dvb_usb_device_properties gl861_properties = { .num_adapters = 1, .adapter = {{ + .num_frontends = 1, + .fe = {{ .frontend_attach = gl861_frontend_attach, .tuner_attach = gl861_tuner_attach, @@ -181,6 +183,7 @@ static struct dvb_usb_device_properties gl861_properties = { } } }, + }}, } }, .i2c_algo = &gl861_i2c_algo, diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c index f254e13..5f71284 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk.c +++ b/drivers/media/dvb/dvb-usb/gp8psk.c @@ -230,7 +230,7 @@ static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) static int gp8psk_frontend_attach(struct dvb_usb_adapter *adap) { - adap->fe[0] = gp8psk_fe_attach(adap->dev); + adap->fe_adap[0].fe = gp8psk_fe_attach(adap->dev); return 0; } @@ -268,6 +268,8 @@ static struct dvb_usb_device_properties gp8psk_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .streaming_ctrl = gp8psk_streaming_ctrl, .frontend_attach = gp8psk_frontend_attach, /* parameter for the MPEG2-data transfer */ @@ -281,6 +283,7 @@ static struct dvb_usb_device_properties gp8psk_properties = { } } }, + }}, } }, .power_ctrl = gp8psk_power_ctrl, diff --git a/drivers/media/dvb/dvb-usb/it913x.c b/drivers/media/dvb/dvb-usb/it913x.c index 3900068..6d2f281 100644 --- a/drivers/media/dvb/dvb-usb/it913x.c +++ b/drivers/media/dvb/dvb-usb/it913x.c @@ -436,7 +436,7 @@ static int it913x_name(struct dvb_usb_adapter *adap) { const char *desc = adap->dev->desc->name; char *fe_name[] = {"_1", "_2", "_3", "_4"}; - char *name = adap->fe[0]->ops.info.name; + char *name = adap->fe_adap[0].fe->ops.info.name; strlcpy(name, desc, 128); strlcat(name, fe_name[adap->id], 128); @@ -450,12 +450,12 @@ static int it913x_frontend_attach(struct dvb_usb_adapter *adap) int ret = 0; u8 adf = it913x_read_reg(udev, IO_MUX_POWER_CLK); u8 adap_addr = I2C_BASE_ADDR + (adap->id << 5); - u16 ep_size = adap->props.stream.u.bulk.buffersize; + u16 ep_size = adap->props.fe[0].stream.u.bulk.buffersize; - adap->fe[0] = dvb_attach(it913x_fe_attach, + adap->fe_adap[0].fe = dvb_attach(it913x_fe_attach, &adap->dev->i2c_adap, adap_addr, adf, IT9137); - if (adap->id == 0 && adap->fe[0]) { + if (adap->id == 0 && adap->fe_adap[0].fe) { ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2_SW_RST, 0x1); ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF2_SW_RST, 0x1); ret = it913x_wr_reg(udev, DEV_0, EP0_TX_EN, 0x0f); @@ -465,7 +465,7 @@ static int it913x_frontend_attach(struct dvb_usb_adapter *adap) ep_size & 0xff); ret = it913x_wr_reg(udev, DEV_0, EP4_TX_LEN_MSB, ep_size >> 8); ret = it913x_wr_reg(udev, DEV_0, EP4_MAX_PKT, 0x80); - } else if (adap->id == 1 && adap->fe[0]) { + } else if (adap->id == 1 && adap->fe_adap[0].fe) { ret = it913x_wr_reg(udev, DEV_0, EP0_TX_EN, 0x6f); ret = it913x_wr_reg(udev, DEV_0, EP5_TX_LEN_LSB, ep_size & 0xff); @@ -524,6 +524,8 @@ static struct dvb_usb_device_properties it913x_properties = { .num_adapters = 2, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER| DVB_USB_ADAP_NEED_PID_FILTERING| DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, @@ -544,8 +546,11 @@ static struct dvb_usb_device_properties it913x_properties = { } } } + }}, }, { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER| DVB_USB_ADAP_NEED_PID_FILTERING| DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, @@ -566,6 +571,7 @@ static struct dvb_usb_device_properties it913x_properties = { } } } + }}, } }, .identify_state = it913x_identify_state, diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c index ef5911a..55b25be 100644 --- a/drivers/media/dvb/dvb-usb/lmedm04.c +++ b/drivers/media/dvb/dvb-usb/lmedm04.c @@ -941,7 +941,7 @@ static int lme_name(struct dvb_usb_adapter *adap) const char *desc = adap->dev->desc->name; char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395", " SHARP:BS2F7HZ0194"}; - char *name = adap->fe[0]->ops.info.name; + char *name = adap->fe_adap[0].fe->ops.info.name; strlcpy(name, desc, 128); strlcat(name, fe_name[st->tuner_config], 128); @@ -958,10 +958,10 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) st->i2c_talk_onoff = 1; st->i2c_gate = 4; - adap->fe[0] = dvb_attach(tda10086_attach, &tda10086_config, + adap->fe_adap[0].fe = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap); - if (adap->fe[0]) { + if (adap->fe_adap[0].fe) { info("TUN Found Frontend TDA10086"); st->i2c_tuner_gate_w = 4; st->i2c_tuner_gate_r = 4; @@ -975,9 +975,9 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) } st->i2c_gate = 4; - adap->fe[0] = dvb_attach(stv0299_attach, &sharp_z0194_config, + adap->fe_adap[0].fe = dvb_attach(stv0299_attach, &sharp_z0194_config, &adap->dev->i2c_adap); - if (adap->fe[0]) { + if (adap->fe_adap[0].fe) { info("FE Found Stv0299"); st->i2c_tuner_gate_w = 4; st->i2c_tuner_gate_r = 5; @@ -991,9 +991,9 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) } st->i2c_gate = 5; - adap->fe[0] = dvb_attach(stv0288_attach, &lme_config, + adap->fe_adap[0].fe = dvb_attach(stv0288_attach, &lme_config, &adap->dev->i2c_adap); - if (adap->fe[0]) { + if (adap->fe_adap[0].fe) { info("FE Found Stv0288"); st->i2c_tuner_gate_w = 4; st->i2c_tuner_gate_r = 5; @@ -1010,15 +1010,15 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) end: if (ret) { - if (adap->fe[0]) { - dvb_frontend_detach(adap->fe[0]); - adap->fe[0] = NULL; + if (adap->fe_adap[0].fe) { + dvb_frontend_detach(adap->fe_adap[0].fe); + adap->fe_adap[0].fe = NULL; } adap->dev->props.rc.core.rc_codes = NULL; return -ENODEV; } - adap->fe[0]->ops.set_voltage = dm04_lme2510_set_voltage; + adap->fe_adap[0].fe->ops.set_voltage = dm04_lme2510_set_voltage; ret = lme_name(adap); return ret; } @@ -1031,17 +1031,17 @@ static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap) switch (st->tuner_config) { case TUNER_LG: - if (dvb_attach(tda826x_attach, adap->fe[0], 0xc0, + if (dvb_attach(tda826x_attach, adap->fe_adap[0].fe, 0xc0, &adap->dev->i2c_adap, 1)) ret = st->tuner_config; break; case TUNER_S7395: - if (dvb_attach(ix2505v_attach , adap->fe[0], &lme_tuner, + if (dvb_attach(ix2505v_attach , adap->fe_adap[0].fe, &lme_tuner, &adap->dev->i2c_adap)) ret = st->tuner_config; break; case TUNER_S0194: - if (dvb_attach(dvb_pll_attach , adap->fe[0], 0xc0, + if (dvb_attach(dvb_pll_attach , adap->fe_adap[0].fe, 0xc0, &adap->dev->i2c_adap, DVB_PLL_OPERA1)) ret = st->tuner_config; break; @@ -1145,6 +1145,8 @@ static struct dvb_usb_device_properties lme2510_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER| DVB_USB_ADAP_NEED_PID_FILTERING| DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, @@ -1166,6 +1168,7 @@ static struct dvb_usb_device_properties lme2510_properties = { } } } + }}, } }, .rc.core = { @@ -1193,6 +1196,8 @@ static struct dvb_usb_device_properties lme2510c_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER| DVB_USB_ADAP_NEED_PID_FILTERING| DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, @@ -1214,6 +1219,7 @@ static struct dvb_usb_device_properties lme2510c_properties = { } } } + }}, } }, .rc.core = { @@ -1241,7 +1247,7 @@ static void *lme2510_exit_int(struct dvb_usb_device *d) void *buffer = NULL; if (adap != NULL) { - lme2510_kill_urb(&adap->stream); + lme2510_kill_urb(&adap->fe_adap[0].stream); adap->feedcount = 0; } diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c index ed5c161..c3e461e 100644 --- a/drivers/media/dvb/dvb-usb/m920x.c +++ b/drivers/media/dvb/dvb-usb/m920x.c @@ -86,12 +86,12 @@ static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq) } for (i = 0; i < d->props.num_adapters; i++) - flags |= d->adapter[i].props.caps; + flags |= d->adapter[i].props.fe[0].caps; /* Some devices(Dposh) might crash if we attempt touch at all. */ if (flags & DVB_USB_ADAP_HAS_PID_FILTER) { for (i = 0; i < d->props.num_adapters; i++) { - epi = d->adapter[i].props.stream.endpoint - 0x81; + epi = d->adapter[i].props.fe[0].stream.endpoint - 0x81; if (epi < 0 || epi >= M9206_MAX_ADAPTERS) { printk(KERN_INFO "m920x: Unexpected adapter endpoint!\n"); @@ -292,7 +292,7 @@ static int m920x_update_filters(struct dvb_usb_adapter *adap) struct m920x_state *m = adap->dev->priv; int enabled = m->filtering_enabled[adap->id]; int i, ret = 0, filter = 0; - int ep = adap->props.stream.endpoint; + int ep = adap->props.fe[0].stream.endpoint; for (i = 0; i < M9206_MAX_FILTERS; i++) if (m->filters[adap->id][i] == 8192) @@ -501,7 +501,7 @@ static int m920x_mt352_frontend_attach(struct dvb_usb_adapter *adap) { deb("%s\n",__func__); - if ((adap->fe[0] = dvb_attach(mt352_attach, + if ((adap->fe_adap[0].fe = dvb_attach(mt352_attach, &m920x_mt352_config, &adap->dev->i2c_adap)) == NULL) return -EIO; @@ -513,7 +513,7 @@ static int m920x_tda10046_08_frontend_attach(struct dvb_usb_adapter *adap) { deb("%s\n",__func__); - if ((adap->fe[0] = dvb_attach(tda10046_attach, + if ((adap->fe_adap[0].fe = dvb_attach(tda10046_attach, &m920x_tda10046_08_config, &adap->dev->i2c_adap)) == NULL) return -EIO; @@ -525,7 +525,7 @@ static int m920x_tda10046_0b_frontend_attach(struct dvb_usb_adapter *adap) { deb("%s\n",__func__); - if ((adap->fe[0] = dvb_attach(tda10046_attach, + if ((adap->fe_adap[0].fe = dvb_attach(tda10046_attach, &m920x_tda10046_0b_config, &adap->dev->i2c_adap)) == NULL) return -EIO; @@ -537,7 +537,7 @@ static int m920x_qt1010_tuner_attach(struct dvb_usb_adapter *adap) { deb("%s\n",__func__); - if (dvb_attach(qt1010_attach, adap->fe[0], &adap->dev->i2c_adap, &m920x_qt1010_config) == NULL) + if (dvb_attach(qt1010_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, &m920x_qt1010_config) == NULL) return -ENODEV; return 0; @@ -547,7 +547,7 @@ static int m920x_tda8275_60_tuner_attach(struct dvb_usb_adapter *adap) { deb("%s\n",__func__); - if (dvb_attach(tda827x_attach, adap->fe[0], 0x60, &adap->dev->i2c_adap, NULL) == NULL) + if (dvb_attach(tda827x_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap, NULL) == NULL) return -ENODEV; return 0; @@ -557,7 +557,7 @@ static int m920x_tda8275_61_tuner_attach(struct dvb_usb_adapter *adap) { deb("%s\n",__func__); - if (dvb_attach(tda827x_attach, adap->fe[0], 0x61, &adap->dev->i2c_adap, NULL) == NULL) + if (dvb_attach(tda827x_attach, adap->fe_adap[0].fe, 0x61, &adap->dev->i2c_adap, NULL) == NULL) return -ENODEV; return 0; @@ -565,7 +565,7 @@ static int m920x_tda8275_61_tuner_attach(struct dvb_usb_adapter *adap) static int m920x_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(simple_tuner_attach, adap->fe[0], + dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, 0x61, TUNER_PHILIPS_FMD1216ME_MK3); return 0; @@ -807,6 +807,9 @@ static struct dvb_usb_device_properties megasky_properties = { .identify_state = m920x_identify_state, .num_adapters = 1, .adapter = {{ + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, @@ -827,6 +830,7 @@ static struct dvb_usb_device_properties megasky_properties = { } } }, + }}, }}, .i2c_algo = &m920x_i2c_algo, @@ -851,6 +855,9 @@ static struct dvb_usb_device_properties digivox_mini_ii_properties = { .identify_state = m920x_identify_state, .num_adapters = 1, .adapter = {{ + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, @@ -871,6 +878,7 @@ static struct dvb_usb_device_properties digivox_mini_ii_properties = { } } }, + }}, }}, .i2c_algo = &m920x_i2c_algo, @@ -910,6 +918,9 @@ static struct dvb_usb_device_properties tvwalkertwin_properties = { .identify_state = m920x_identify_state, .num_adapters = 2, .adapter = {{ + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, @@ -929,7 +940,11 @@ static struct dvb_usb_device_properties tvwalkertwin_properties = { .buffersize = 512, } } + }}, }},{ + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, @@ -949,6 +964,7 @@ static struct dvb_usb_device_properties tvwalkertwin_properties = { .buffersize = 512, } } + }}, }, }}, .i2c_algo = &m920x_i2c_algo, @@ -974,6 +990,8 @@ static struct dvb_usb_device_properties dposh_properties = { .identify_state = m920x_identify_state, .num_adapters = 1, .adapter = {{ + .num_frontends = 1, + .fe = {{ /* Hardware pid filters don't work with this device/firmware */ .frontend_attach = m920x_mt352_frontend_attach, @@ -989,6 +1007,7 @@ static struct dvb_usb_device_properties dposh_properties = { } } }, + }}, }}, .i2c_algo = &m920x_i2c_algo, @@ -1019,6 +1038,9 @@ static struct dvb_usb_device_properties pinnacle_pctv310e_properties = { .identify_state = m920x_identify_state, .num_adapters = 1, .adapter = {{ + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, @@ -1041,6 +1063,7 @@ static struct dvb_usb_device_properties pinnacle_pctv310e_properties = { } } }, + }}, } }, .i2c_algo = &m920x_i2c_algo, diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.c b/drivers/media/dvb/dvb-usb/mxl111sf.c index 3da452a..0c3f69a 100644 --- a/drivers/media/dvb/dvb-usb/mxl111sf.c +++ b/drivers/media/dvb/dvb-usb/mxl111sf.c @@ -253,7 +253,8 @@ static int mxl111sf_adap_fe_init(struct dvb_frontend *fe) struct dvb_usb_adapter *adap = fe->dvb->priv; struct dvb_usb_device *d = adap->dev; struct mxl111sf_state *state = d->priv; - struct mxl111sf_adap_state *adap_state = adap->priv; + struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe->id].priv; + int err; /* exit if we didnt initialize the driver yet */ @@ -311,7 +312,7 @@ static int mxl111sf_adap_fe_sleep(struct dvb_frontend *fe) struct dvb_usb_adapter *adap = fe->dvb->priv; struct dvb_usb_device *d = adap->dev; struct mxl111sf_state *state = d->priv; - struct mxl111sf_adap_state *adap_state = adap->priv; + struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe->id].priv; int err; /* exit if we didnt initialize the driver yet */ @@ -336,7 +337,7 @@ static int mxl111sf_ep6_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { struct dvb_usb_device *d = adap->dev; struct mxl111sf_state *state = d->priv; - struct mxl111sf_adap_state *adap_state = adap->priv; + struct mxl111sf_adap_state *adap_state = adap->fe_adap[adap->active_fe].priv; int ret = 0; u8 tmp; @@ -378,7 +379,7 @@ static int mxl111sf_lgdt3305_frontend_attach(struct dvb_usb_adapter *adap) { struct dvb_usb_device *d = adap->dev; struct mxl111sf_state *state = d->priv; - struct mxl111sf_adap_state *adap_state = adap->priv; + struct mxl111sf_adap_state *adap_state = adap->fe_adap[0].priv; int ret; deb_adv("%s()\n", __func__); @@ -421,14 +422,14 @@ static int mxl111sf_lgdt3305_frontend_attach(struct dvb_usb_adapter *adap) if (mxl_fail(ret)) goto fail; - adap->fe[0] = dvb_attach(lgdt3305_attach, + adap->fe_adap[0].fe = dvb_attach(lgdt3305_attach, &hauppauge_lgdt3305_config, &adap->dev->i2c_adap); - if (adap->fe[0]) { - adap_state->fe_init = adap->fe[0]->ops.init; - adap->fe[0]->ops.init = mxl111sf_adap_fe_init; - adap_state->fe_sleep = adap->fe[0]->ops.sleep; - adap->fe[0]->ops.sleep = mxl111sf_adap_fe_sleep; + if (adap->fe_adap[0].fe) { + adap_state->fe_init = adap->fe_adap[0].fe->ops.init; + adap->fe_adap[0].fe->ops.init = mxl111sf_adap_fe_init; + adap_state->fe_sleep = adap->fe_adap[0].fe->ops.sleep; + adap->fe_adap[0].fe->ops.sleep = mxl111sf_adap_fe_sleep; return 0; } ret = -EIO; @@ -516,7 +517,7 @@ static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap) deb_adv("%s()\n", __func__); - if (NULL != dvb_attach(mxl111sf_tuner_attach, adap->fe[0], state, + if (NULL != dvb_attach(mxl111sf_tuner_attach, adap->fe_adap[0].fe, state, &mxl_tuner_config)) return 0; @@ -714,13 +715,16 @@ static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = { .num_adapters = 1, .adapter = { { + .fe_ioctl_override = mxl111sf_fe_ioctl_override, + .num_frontends = 1, + .fe = {{ .size_of_priv = sizeof(struct mxl111sf_adap_state), - .fe_ioctl_override = mxl111sf_fe_ioctl_override, .frontend_attach = mxl111sf_lgdt3305_frontend_attach, .tuner_attach = mxl111sf_attach_tuner, MXL111SF_EP6_BULK_STREAMING_CONFIG, + }}, }, }, .num_device_descs = 6, @@ -768,13 +772,16 @@ static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = { .num_adapters = 1, .adapter = { { + .fe_ioctl_override = mxl111sf_fe_ioctl_override, + .num_frontends = 1, + .fe = {{ .size_of_priv = sizeof(struct mxl111sf_adap_state), - .fe_ioctl_override = mxl111sf_fe_ioctl_override, .frontend_attach = mxl111sf_lgdt3305_frontend_attach, .tuner_attach = mxl111sf_attach_tuner, MXL111SF_EP6_ISOC_STREAMING_CONFIG, + }}, }, }, .num_device_descs = 6, diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c index bc350e9..21384da 100644 --- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c +++ b/drivers/media/dvb/dvb-usb/nova-t-usb2.c @@ -166,6 +166,8 @@ static struct dvb_usb_device_properties nova_t_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, @@ -186,7 +188,7 @@ static struct dvb_usb_device_properties nova_t_properties = { } } }, - + }}, .size_of_priv = sizeof(struct dibusb_state), } }, diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c index 170b1ef..b6e12f9 100644 --- a/drivers/media/dvb/dvb-usb/opera1.c +++ b/drivers/media/dvb/dvb-usb/opera1.c @@ -263,10 +263,10 @@ static struct stv0299_config opera1_stv0299_config = { static int opera1_frontend_attach(struct dvb_usb_adapter *d) { - if ((d->fe[0] = + if ((d->fe_adap[0].fe = dvb_attach(stv0299_attach, &opera1_stv0299_config, &d->dev->i2c_adap)) != NULL) { - d->fe[0]->ops.set_voltage = opera1_set_voltage; + d->fe_adap[0].fe->ops.set_voltage = opera1_set_voltage; return 0; } info("not attached stv0299"); @@ -276,7 +276,7 @@ static int opera1_frontend_attach(struct dvb_usb_adapter *d) static int opera1_tuner_attach(struct dvb_usb_adapter *adap) { dvb_attach( - dvb_pll_attach, adap->fe[0], 0xc0>>1, + dvb_pll_attach, adap->fe_adap[0].fe, 0xc0>>1, &adap->dev->i2c_adap, DVB_PLL_OPERA1 ); return 0; @@ -516,6 +516,8 @@ static struct dvb_usb_device_properties opera1_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .frontend_attach = opera1_frontend_attach, .streaming_ctrl = opera1_streaming_ctrl, .tuner_attach = opera1_tuner_attach, @@ -535,6 +537,7 @@ static struct dvb_usb_device_properties opera1_properties = { } } }, + }}, } }, .num_device_descs = 1, diff --git a/drivers/media/dvb/dvb-usb/technisat-usb2.c b/drivers/media/dvb/dvb-usb/technisat-usb2.c index 2a89d1ef..0998fe9 100644 --- a/drivers/media/dvb/dvb-usb/technisat-usb2.c +++ b/drivers/media/dvb/dvb-usb/technisat-usb2.c @@ -292,7 +292,7 @@ static void technisat_usb2_green_led_control(struct work_struct *work) { struct technisat_usb2_state *state = container_of(work, struct technisat_usb2_state, green_led_work.work); - struct dvb_frontend *fe = state->dev->adapter[0].fe[0]; + struct dvb_frontend *fe = state->dev->adapter[0].fe_adap[0].fe; if (state->power_state == 0) goto schedule; @@ -505,14 +505,14 @@ static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a) struct usb_device *udev = a->dev->udev; int ret; - a->fe[0] = dvb_attach(stv090x_attach, &technisat_usb2_stv090x_config, + a->fe_adap[0].fe = dvb_attach(stv090x_attach, &technisat_usb2_stv090x_config, &a->dev->i2c_adap, STV090x_DEMODULATOR_0); - if (a->fe[0]) { + if (a->fe_adap[0].fe) { struct stv6110x_devctl *ctl; ctl = dvb_attach(stv6110x_attach, - a->fe[0], + a->fe_adap[0].fe, &technisat_usb2_stv6110x_config, &a->dev->i2c_adap); @@ -532,8 +532,8 @@ static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a) /* call the init function once to initialize tuner's clock output divider and demod's master clock */ - if (a->fe[0]->ops.init) - a->fe[0]->ops.init(a->fe[0]); + if (a->fe_adap[0].fe->ops.init) + a->fe_adap[0].fe->ops.init(a->fe_adap[0].fe); if (mutex_lock_interruptible(&a->dev->i2c_mutex) < 0) return -EAGAIN; @@ -548,20 +548,20 @@ static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a) if (ret != 0) err("could not set IF_CLK to external"); - a->fe[0]->ops.set_voltage = technisat_usb2_set_voltage; + a->fe_adap[0].fe->ops.set_voltage = technisat_usb2_set_voltage; /* if everything was successful assign a nice name to the frontend */ - strlcpy(a->fe[0]->ops.info.name, a->dev->desc->name, - sizeof(a->fe[0]->ops.info.name)); + strlcpy(a->fe_adap[0].fe->ops.info.name, a->dev->desc->name, + sizeof(a->fe_adap[0].fe->ops.info.name)); } else { - dvb_frontend_detach(a->fe[0]); - a->fe[0] = NULL; + dvb_frontend_detach(a->fe_adap[0].fe); + a->fe_adap[0].fe = NULL; } } technisat_usb2_set_led_timer(a->dev, 1, 1); - return a->fe[0] == NULL ? -ENODEV : 0; + return a->fe_adap[0].fe == NULL ? -ENODEV : 0; } /* Remote control */ @@ -697,6 +697,8 @@ static struct dvb_usb_device_properties technisat_usb2_devices = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .frontend_attach = technisat_usb2_frontend_attach, .stream = { @@ -711,7 +713,7 @@ static struct dvb_usb_device_properties technisat_usb2_devices = { } } }, - + }}, .size_of_priv = 0, }, }, diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c index bda37ce..130d296 100644 --- a/drivers/media/dvb/dvb-usb/ttusb2.c +++ b/drivers/media/dvb/dvb-usb/ttusb2.c @@ -222,7 +222,7 @@ static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap) if (usb_set_interface(adap->dev->udev,0,3) < 0) err("set interface to alts=3 failed"); - if ((adap->fe[0] = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap)) == NULL) { + if ((adap->fe_adap[0].fe = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap)) == NULL) { deb_info("TDA10086 attach failed\n"); return -ENODEV; } @@ -234,7 +234,7 @@ static int ttusb2_ct3650_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) { struct dvb_usb_adapter *adap = fe->dvb->priv; - return adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0], enable); + return adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, enable); } static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap) @@ -242,26 +242,26 @@ static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap) if (usb_set_interface(adap->dev->udev, 0, 3) < 0) err("set interface to alts=3 failed"); - if (adap->fe[0] == NULL) { + if (adap->fe_adap[0].fe == NULL) { /* FE 0 DVB-C */ - adap->fe[0] = dvb_attach(tda10023_attach, + adap->fe_adap[0].fe = dvb_attach(tda10023_attach, &tda10023_config, &adap->dev->i2c_adap, 0x48); - if (adap->fe[0] == NULL) { + if (adap->fe_adap[0].fe == NULL) { deb_info("TDA10023 attach failed\n"); return -ENODEV; } } else { - adap->fe[1] = dvb_attach(tda10048_attach, + adap->fe_adap[1].fe = dvb_attach(tda10048_attach, &tda10048_config, &adap->dev->i2c_adap); - if (adap->fe[1] == NULL) { + if (adap->fe_adap[1].fe == NULL) { deb_info("TDA10048 attach failed\n"); return -ENODEV; } /* tuner is behind TDA10023 I2C-gate */ - adap->fe[1]->ops.i2c_gate_ctrl = ttusb2_ct3650_i2c_gate_ctrl; + adap->fe_adap[1].fe->ops.i2c_gate_ctrl = ttusb2_ct3650_i2c_gate_ctrl; } @@ -273,10 +273,10 @@ static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap) struct dvb_frontend *fe; /* MFE: select correct FE to attach tuner since that's called twice */ - if (adap->fe[1] == NULL) - fe = adap->fe[0]; + if (adap->fe_adap[1].fe == NULL) + fe = adap->fe_adap[0].fe; else - fe = adap->fe[1]; + fe = adap->fe_adap[1].fe; /* attach tuner */ if (dvb_attach(tda827x_attach, fe, 0x61, &adap->dev->i2c_adap, &tda827x_config) == NULL) { @@ -288,12 +288,12 @@ static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap) static int ttusb2_tuner_tda826x_attach(struct dvb_usb_adapter *adap) { - if (dvb_attach(tda826x_attach, adap->fe[0], 0x60, &adap->dev->i2c_adap, 0) == NULL) { + if (dvb_attach(tda826x_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) { deb_info("TDA8263 attach failed\n"); return -ENODEV; } - if (dvb_attach(lnbp21_attach, adap->fe[0], &adap->dev->i2c_adap, 0, 0) == NULL) { + if (dvb_attach(lnbp21_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, 0, 0) == NULL) { deb_info("LNBP21 attach failed\n"); return -ENODEV; } @@ -340,6 +340,8 @@ static struct dvb_usb_device_properties ttusb2_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .streaming_ctrl = NULL, // ttusb2_streaming_ctrl, .frontend_attach = ttusb2_frontend_tda10086_attach, @@ -358,6 +360,7 @@ static struct dvb_usb_device_properties ttusb2_properties = { } } } + }}, } }, @@ -392,6 +395,8 @@ static struct dvb_usb_device_properties ttusb2_properties_s2400 = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .streaming_ctrl = NULL, .frontend_attach = ttusb2_frontend_tda10086_attach, @@ -410,6 +415,7 @@ static struct dvb_usb_device_properties ttusb2_properties_s2400 = { } } } + }}, } }, @@ -446,9 +452,10 @@ static struct dvb_usb_device_properties ttusb2_properties_ct3650 = { .num_adapters = 1, .adapter = { { + .num_frontends = 2, + .fe = {{ .streaming_ctrl = NULL, - .num_frontends = 2, .frontend_attach = ttusb2_frontend_tda10023_attach, .tuner_attach = ttusb2_tuner_tda827x_attach, @@ -465,6 +472,26 @@ static struct dvb_usb_device_properties ttusb2_properties_ct3650 = { } } } + },{ + .streaming_ctrl = NULL, + + .frontend_attach = ttusb2_frontend_tda10023_attach, + .tuner_attach = ttusb2_tuner_tda827x_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_ISOC, + .count = 5, + .endpoint = 0x02, + .u = { + .isoc = { + .framesperurb = 4, + .framesize = 940, + .interval = 1, + } + } + } + }}, }, }, diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c index ed4765a..463673a 100644 --- a/drivers/media/dvb/dvb-usb/umt-010.c +++ b/drivers/media/dvb/dvb-usb/umt-010.c @@ -60,14 +60,14 @@ static int umt_mt352_frontend_attach(struct dvb_usb_adapter *adap) umt_config.demod_init = umt_mt352_demod_init; umt_config.demod_address = 0xf; - adap->fe[0] = dvb_attach(mt352_attach, &umt_config, &adap->dev->i2c_adap); + adap->fe_adap[0].fe = dvb_attach(mt352_attach, &umt_config, &adap->dev->i2c_adap); return 0; } static int umt_tuner_attach (struct dvb_usb_adapter *adap) { - dvb_attach(dvb_pll_attach, adap->fe[0], 0x61, NULL, DVB_PLL_TUA6034); + dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, NULL, DVB_PLL_TUA6034); return 0; } @@ -100,6 +100,8 @@ static struct dvb_usb_device_properties umt_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .streaming_ctrl = dibusb2_0_streaming_ctrl, .frontend_attach = umt_mt352_frontend_attach, .tuner_attach = umt_tuner_attach, @@ -115,7 +117,7 @@ static struct dvb_usb_device_properties umt_properties = { } } }, - + }}, .size_of_priv = sizeof(struct dibusb_state), } }, diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c index 47b3462..45e31f2 100644 --- a/drivers/media/dvb/dvb-usb/vp702x.c +++ b/drivers/media/dvb/dvb-usb/vp702x.c @@ -320,7 +320,7 @@ static int vp702x_frontend_attach(struct dvb_usb_adapter *adap) vp702x_init_pid_filter(adap); - adap->fe[0] = vp702x_fe_attach(adap->dev); + adap->fe_adap[0].fe = vp702x_fe_attach(adap->dev); vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 1, 7, NULL, 0); return 0; @@ -383,6 +383,8 @@ static struct dvb_usb_device_properties vp702x_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .caps = DVB_USB_ADAP_RECEIVES_204_BYTE_TS, .streaming_ctrl = vp702x_streaming_ctrl, @@ -399,6 +401,7 @@ static struct dvb_usb_device_properties vp702x_properties = { } } }, + }}, .size_of_priv = sizeof(struct vp702x_adapter_state), } }, diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index 4264523..498024c 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -214,7 +214,7 @@ static int vp7045_frontend_attach(struct dvb_usb_adapter *adap) /* Dump the EEPROM */ /* vp7045_read_eeprom(d,buf, 255, FX2_ID_ADDR); */ - adap->fe[0] = vp7045_fe_attach(adap->dev); + adap->fe_adap[0].fe = vp7045_fe_attach(adap->dev); return 0; } @@ -263,6 +263,8 @@ static struct dvb_usb_device_properties vp7045_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 1, + .fe = {{ .frontend_attach = vp7045_frontend_attach, /* parameter for the MPEG2-data transfer */ .stream = { @@ -275,6 +277,7 @@ static struct dvb_usb_device_properties vp7045_properties = { } } }, + }}, } }, .power_ctrl = vp7045_power_ctrl, -- cgit v0.10.2 From 398b0d1f058636f3950296ca07346577c02b94d6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 25 Aug 2011 09:14:57 -0300 Subject: [media] radio-si4713.c: fix compiler warning Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index 444b4cf..d1fab58 100644 --- a/drivers/media/radio/radio-si4713.c +++ b/drivers/media/radio/radio-si4713.c @@ -92,10 +92,6 @@ static int radio_si4713_s_audout(struct file *file, void *priv, static int radio_si4713_querycap(struct file *file, void *priv, struct v4l2_capability *capability) { - struct radio_si4713_device *rsdev; - - rsdev = video_get_drvdata(video_devdata(file)); - strlcpy(capability->driver, "radio-si4713", sizeof(capability->driver)); strlcpy(capability->card, "Silicon Labs Si4713 Modulator", sizeof(capability->card)); -- cgit v0.10.2 From f68afe5d45198bfe7040cf751033c6208577468c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 25 Aug 2011 09:36:42 -0300 Subject: [media] mt20xx.c: fix compiler warnings Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/common/tuners/mt20xx.c b/drivers/media/common/tuners/mt20xx.c index d0e70e1..0e74e97 100644 --- a/drivers/media/common/tuners/mt20xx.c +++ b/drivers/media/common/tuners/mt20xx.c @@ -430,11 +430,10 @@ static void mt2050_set_antenna(struct dvb_frontend *fe, unsigned char antenna) { struct microtune_priv *priv = fe->tuner_priv; unsigned char buf[2]; - int ret; buf[0] = 6; buf[1] = antenna ? 0x11 : 0x10; - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); + tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); tuner_dbg("mt2050: enabled antenna connector %d\n", antenna); } @@ -574,21 +573,20 @@ static int mt2050_init(struct dvb_frontend *fe) { struct microtune_priv *priv = fe->tuner_priv; unsigned char buf[2]; - int ret; - buf[0]=6; - buf[1]=0x10; - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); // power + buf[0] = 6; + buf[1] = 0x10; + tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); /* power */ - buf[0]=0x0f; - buf[1]=0x0f; - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); // m1lo + buf[0] = 0x0f; + buf[1] = 0x0f; + tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); /* m1lo */ - buf[0]=0x0d; - ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1); - tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); + buf[0] = 0x0d; + tuner_i2c_xfer_send(&priv->i2c_props, buf, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, buf, 1); - tuner_dbg("mt2050: sro is %x\n",buf[0]); + tuner_dbg("mt2050: sro is %x\n", buf[0]); memcpy(&fe->ops.tuner_ops, &mt2050_tuner_ops, sizeof(struct dvb_tuner_ops)); -- cgit v0.10.2 From eb70ac1b1e457537a056cb714ccddbb1fd56f9ed Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 25 Aug 2011 09:43:49 -0300 Subject: [media] wl128x: fix compiler warning + wrong write() return The fix is to check for ret and return -EFAULT if non-zero. I also noticed that write() didn't return the number of bytes written. Fixed as well. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c index 8c0e192..478d1e9 100644 --- a/drivers/media/radio/wl128x/fmdrv_v4l2.c +++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c @@ -84,12 +84,14 @@ static ssize_t fm_v4l2_fops_write(struct file *file, const char __user * buf, ret = copy_from_user(&rds, buf, sizeof(rds)); fmdbg("(%d)type: %d, text %s, af %d\n", ret, rds.text_type, rds.text, rds.af_freq); + if (ret) + return -EFAULT; fmdev = video_drvdata(file); fm_tx_set_radio_text(fmdev, rds.text, rds.text_type); fm_tx_set_af(fmdev, rds.af_freq); - return 0; + return sizeof(rds); } static u32 fm_v4l2_fops_poll(struct file *file, struct poll_table_struct *pts) -- cgit v0.10.2 From 7b4668efc4a8f75d12337cf8013307a7ec437878 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 25 Aug 2011 09:54:30 -0300 Subject: [media] saa7146: fix compiler warning Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c index fcdf4a0..384b358 100644 --- a/drivers/media/common/saa7146_video.c +++ b/drivers/media/common/saa7146_video.c @@ -1356,18 +1356,14 @@ static void video_close(struct saa7146_dev *dev, struct file *file) struct saa7146_fh *fh = file->private_data; struct saa7146_vv *vv = dev->vv_data; struct videobuf_queue *q = &fh->video_q; - int err; - if (IS_CAPTURE_ACTIVE(fh) != 0) { - err = video_end(fh, file); - } else if (IS_OVERLAY_ACTIVE(fh) != 0) { - err = saa7146_stop_preview(fh); - } + if (IS_CAPTURE_ACTIVE(fh) != 0) + video_end(fh, file); + else if (IS_OVERLAY_ACTIVE(fh) != 0) + saa7146_stop_preview(fh); videobuf_stop(q); - /* hmm, why is this function declared void? */ - /* return err */ } -- cgit v0.10.2 From 2122eaf64acd9ca42645b4bf8f222c7d452313f1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 25 Aug 2011 09:59:16 -0300 Subject: [media] ddbridge: fix compiler warnings 'off' was unused and 'ret' really had to be used to return -EFAULT. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/ddbridge/ddbridge-core.c b/drivers/media/dvb/ddbridge/ddbridge-core.c index fe56703..ba9a643 100644 --- a/drivers/media/dvb/ddbridge/ddbridge-core.c +++ b/drivers/media/dvb/ddbridge/ddbridge-core.c @@ -507,15 +507,14 @@ static u32 ddb_input_avail(struct ddb_input *input) return 0; } -static size_t ddb_input_read(struct ddb_input *input, u8 *buf, size_t count) +static ssize_t ddb_input_read(struct ddb_input *input, u8 *buf, size_t count) { struct ddb *dev = input->port->dev; u32 left = count; - u32 idx, off, free, stat = input->stat; + u32 idx, free, stat = input->stat; int ret; idx = (stat >> 11) & 0x1f; - off = (stat & 0x7ff) << 7; while (left) { if (input->cbuf == idx) @@ -525,6 +524,8 @@ static size_t ddb_input_read(struct ddb_input *input, u8 *buf, size_t count) free = left; ret = copy_to_user(buf, input->vbuf[input->cbuf] + input->coff, free); + if (ret) + return -EFAULT; input->coff += free; if (input->coff == input->dma_buf_size) { input->coff = 0; @@ -939,6 +940,8 @@ static ssize_t ts_read(struct file *file, char *buf, break; } read = ddb_input_read(input, buf, left); + if (read < 0) + return read; left -= read; buf += read; } -- cgit v0.10.2 From d3bcaf083bb7a081b280a04898f7c9f68e1253d4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 25 Aug 2011 10:10:32 -0300 Subject: [media] mxl5005s: fix compiler warning Removed the unused Xtal_Int variable. That made it also possible to remove a related function. However, the code of that function has been preserved in a comment describing an equation. Without that function that comment would have been hard to understand. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/common/tuners/mxl5005s.c b/drivers/media/common/tuners/mxl5005s.c index 56fe75c..54be9e6 100644 --- a/drivers/media/common/tuners/mxl5005s.c +++ b/drivers/media/common/tuners/mxl5005s.c @@ -309,7 +309,6 @@ static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum, static u16 MXL_SetGPIO(struct dvb_frontend *fe, u8 GPIO_Num, u8 GPIO_Val); static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum, u8 *RegVal, int *count); -static u32 MXL_GetXtalInt(u32 Xtal_Freq); static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq); static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe); static void MXL_SynthRFTGLO_Calc(struct dvb_frontend *fe); @@ -2307,14 +2306,6 @@ static u16 MXL_IFSynthInit(struct dvb_frontend *fe) return status ; } -static u32 MXL_GetXtalInt(u32 Xtal_Freq) -{ - if ((Xtal_Freq % 1000000) == 0) - return (Xtal_Freq / 10000); - else - return (((Xtal_Freq / 1000000) + 1)*100); -} - static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq) { struct mxl5005s_state *state = fe->tuner_priv; @@ -2324,13 +2315,10 @@ static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq) u32 Kdbl_RF = 2; u32 tg_divval; u32 tg_lo; - u32 Xtal_Int; u32 Fref_TG; u32 Fvco; - Xtal_Int = MXL_GetXtalInt(state->Fxtal); - state->RF_IN = RF_Freq; MXL_SynthRFTGLO_Calc(fe); @@ -2779,6 +2767,16 @@ static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq) tg_lo = (((Fmax/10 - Fvco)/100)*32) / ((Fmax-Fmin)/1000)+8; /* below equation is same as above but much harder to debug. + * + * static u32 MXL_GetXtalInt(u32 Xtal_Freq) + * { + * if ((Xtal_Freq % 1000000) == 0) + * return (Xtal_Freq / 10000); + * else + * return (((Xtal_Freq / 1000000) + 1)*100); + * } + * + * u32 Xtal_Int = MXL_GetXtalInt(state->Fxtal); * tg_lo = ( ((Fmax/10000 * Xtal_Int)/100) - * ((state->TG_LO/10000)*divider_val * * (state->Fxtal/10000)/100) )*32/((Fmax-Fmin)/10000 * -- cgit v0.10.2 From 4c04b7a1ada742aace5023aca57e537bf75b59ff Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 25 Aug 2011 10:17:39 -0300 Subject: [media] af9005-fe: fix compiler warning Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/af9005-fe.c b/drivers/media/dvb/dvb-usb/af9005-fe.c index 6ad9474..3263e97 100644 --- a/drivers/media/dvb/dvb-usb/af9005-fe.c +++ b/drivers/media/dvb/dvb-usb/af9005-fe.c @@ -63,11 +63,9 @@ static int af9005_write_word_agc(struct dvb_usb_device *d, u16 reghi, u16 reglo, u8 pos, u8 len, u16 value) { int ret; - u8 temp; if ((ret = af9005_write_ofdm_register(d, reglo, (u8) (value & 0xff)))) return ret; - temp = (u8) ((value & 0x0300) >> 8); return af9005_write_register_bits(d, reghi, pos, len, (u8) ((value & 0x300) >> 8)); } -- cgit v0.10.2 From 88af83048d3bdfe3de7aee54e7117afbc2f8dd58 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 25 Aug 2011 10:24:16 -0300 Subject: [media] tvaudio: fix compiler warnings This is indeed a bug: balance and volume must be used to set the left and right channel volume. Fixed. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index c46a3bb..f22dbef 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -1695,14 +1695,17 @@ static int tvaudio_s_ctrl(struct v4l2_subdev *sd, case V4L2_CID_AUDIO_BALANCE: { int volume, balance; + if (!(desc->flags & CHIP_HAS_VOLUME)) break; - volume = max(chip->left,chip->right); + volume = max(chip->left, chip->right); balance = ctrl->value; + chip->left = (min(65536 - balance, 32768) * volume) / 32768; + chip->right = (min(balance, volume * (__u16)32768)) / 32768; - chip_write(chip,desc->leftreg,desc->volfunc(chip->left)); - chip_write(chip,desc->rightreg,desc->volfunc(chip->right)); + chip_write(chip, desc->leftreg, desc->volfunc(chip->left)); + chip_write(chip, desc->rightreg, desc->volfunc(chip->right)); return 0; } -- cgit v0.10.2 From db3ca1d5f118ef5ab5717068ee02c1e44e011e64 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 25 Aug 2011 10:36:59 -0300 Subject: [media] az6027: fix compiler warnings Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/az6027.c b/drivers/media/dvb/dvb-usb/az6027.c index 82c5f45..2f42a81 100644 --- a/drivers/media/dvb/dvb-usb/az6027.c +++ b/drivers/media/dvb/dvb-usb/az6027.c @@ -782,7 +782,6 @@ static int az6027_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) { u8 buf; - int ret; struct dvb_usb_adapter *adap = fe->dvb->priv; struct i2c_msg i2c_msg = { @@ -800,17 +799,17 @@ static int az6027_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) switch (voltage) { case SEC_VOLTAGE_13: buf = 1; - ret = i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1); + i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1); break; case SEC_VOLTAGE_18: buf = 2; - ret = i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1); + i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1); break; case SEC_VOLTAGE_OFF: buf = 0; - ret = i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1); + i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1); break; default: @@ -954,7 +953,6 @@ static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int n { struct dvb_usb_device *d = i2c_get_adapdata(adap); int i = 0, j = 0, len = 0; - int ret; u16 index; u16 value; int length; @@ -990,7 +988,7 @@ static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int n index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff)); value = msg[i].addr + (msg[i].len << 8); length = msg[i + 1].len + 6; - ret = az6027_usb_in_op(d, req, value, index, data, length); + az6027_usb_in_op(d, req, value, index, data, length); len = msg[i + 1].len; for (j = 0; j < len; j++) msg[i + 1].buf[j] = data[j + 5]; @@ -1017,7 +1015,7 @@ static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int n index = 0x0; value = msg[i].addr; length = msg[i].len + 6; - ret = az6027_usb_in_op(d, req, value, index, data, length); + az6027_usb_in_op(d, req, value, index, data, length); len = msg[i].len; for (j = 0; j < len; j++) msg[i].buf[j] = data[j + 5]; -- cgit v0.10.2 From 7ed67f15f4d659b1fd2ad82fdea4746f4a1cdf94 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 25 Aug 2011 10:40:07 -0300 Subject: [media] mantis: fix compiler warnings Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/mantis/hopper_cards.c b/drivers/media/dvb/mantis/hopper_cards.c index 1402062..8bbeebc 100644 --- a/drivers/media/dvb/mantis/hopper_cards.c +++ b/drivers/media/dvb/mantis/hopper_cards.c @@ -65,7 +65,7 @@ static int devs; static irqreturn_t hopper_irq_handler(int irq, void *dev_id) { - u32 stat = 0, mask = 0, lstat = 0, mstat = 0; + u32 stat = 0, mask = 0, lstat = 0; u32 rst_stat = 0, rst_mask = 0; struct mantis_pci *mantis; @@ -80,7 +80,7 @@ static irqreturn_t hopper_irq_handler(int irq, void *dev_id) stat = mmread(MANTIS_INT_STAT); mask = mmread(MANTIS_INT_MASK); - mstat = lstat = stat & ~MANTIS_INT_RISCSTAT; + lstat = stat & ~MANTIS_INT_RISCSTAT; if (!(stat & mask)) return IRQ_NONE; diff --git a/drivers/media/dvb/mantis/mantis_cards.c b/drivers/media/dvb/mantis/mantis_cards.c index 05cbb9d..e6c8368 100644 --- a/drivers/media/dvb/mantis/mantis_cards.c +++ b/drivers/media/dvb/mantis/mantis_cards.c @@ -73,7 +73,7 @@ static char *label[10] = { static irqreturn_t mantis_irq_handler(int irq, void *dev_id) { - u32 stat = 0, mask = 0, lstat = 0, mstat = 0; + u32 stat = 0, mask = 0, lstat = 0; u32 rst_stat = 0, rst_mask = 0; struct mantis_pci *mantis; @@ -88,7 +88,7 @@ static irqreturn_t mantis_irq_handler(int irq, void *dev_id) stat = mmread(MANTIS_INT_STAT); mask = mmread(MANTIS_INT_MASK); - mstat = lstat = stat & ~MANTIS_INT_RISCSTAT; + lstat = stat & ~MANTIS_INT_RISCSTAT; if (!(stat & mask)) return IRQ_NONE; -- cgit v0.10.2 From 23aefb7e0e5e8b3766545af51b88fc3eb07532ba Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 25 Aug 2011 10:47:15 -0300 Subject: [media] drxd_hard: fix compiler warnings Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/frontends/drxd_hard.c b/drivers/media/dvb/frontends/drxd_hard.c index bcad01c..88e46f4 100644 --- a/drivers/media/dvb/frontends/drxd_hard.c +++ b/drivers/media/dvb/frontends/drxd_hard.c @@ -931,16 +931,15 @@ static int DownloadMicrocode(struct drxd_state *state, const u8 *pMCImage, u32 Length) { u8 *pSrc; - u16 Flags; u32 Address; u16 nBlocks; u16 BlockSize; - u16 BlockCRC; u32 offset = 0; int i, status = 0; pSrc = (u8 *) pMCImage; - Flags = (pSrc[0] << 8) | pSrc[1]; + /* We're not using Flags */ + /* Flags = (pSrc[0] << 8) | pSrc[1]; */ pSrc += sizeof(u16); offset += sizeof(u16); nBlocks = (pSrc[0] << 8) | pSrc[1]; @@ -957,11 +956,13 @@ static int DownloadMicrocode(struct drxd_state *state, pSrc += sizeof(u16); offset += sizeof(u16); - Flags = (pSrc[0] << 8) | pSrc[1]; + /* We're not using Flags */ + /* u16 Flags = (pSrc[0] << 8) | pSrc[1]; */ pSrc += sizeof(u16); offset += sizeof(u16); - BlockCRC = (pSrc[0] << 8) | pSrc[1]; + /* We're not using BlockCRC */ + /* u16 BlockCRC = (pSrc[0] << 8) | pSrc[1]; */ pSrc += sizeof(u16); offset += sizeof(u16); -- cgit v0.10.2 From ba08831b84211e48ae4ce6272eebeade8d41cff4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 25 Aug 2011 10:52:53 -0300 Subject: [media] vpx3220, bt819: fix compiler warnings Same status/res mixup. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c index f872044..859eabf 100644 --- a/drivers/media/video/bt819.c +++ b/drivers/media/video/bt819.c @@ -229,7 +229,7 @@ static int bt819_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd) if (pstd) *pstd = std; if (pstatus) - *pstatus = status; + *pstatus = res; v4l2_dbg(1, debug, sd, "get status %x\n", status); return 0; diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c index ca372eb..e5cad6f 100644 --- a/drivers/media/video/vpx3220.c +++ b/drivers/media/video/vpx3220.c @@ -331,7 +331,7 @@ static int vpx3220_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pst if (pstd) *pstd = std; if (pstatus) - *pstatus = status; + *pstatus = res; return 0; } -- cgit v0.10.2 From 1d3726ae84c3ff499be4f6bcbb805aeab8d812c6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 27 Aug 2011 11:25:31 -0300 Subject: [media] si470x: fix compile warning Tobias Lorenz has looked at this and agreed that the 'buf' variable could be removed. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c index 4cf5370..a6ad707 100644 --- a/drivers/media/radio/si470x/radio-si470x-usb.c +++ b/drivers/media/radio/si470x/radio-si470x-usb.c @@ -395,7 +395,6 @@ int si470x_disconnect_check(struct si470x_device *radio) static void si470x_int_in_callback(struct urb *urb) { struct si470x_device *radio = urb->context; - unsigned char buf[RDS_REPORT_SIZE]; int retval; unsigned char regnr; unsigned char blocknum; @@ -423,7 +422,6 @@ static void si470x_int_in_callback(struct urb *urb) if (urb->actual_length > 0) { /* Update RDS registers with URB data */ - buf[0] = RDS_REPORT; for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++) radio->registers[STATUSRSSI + regnr] = get_unaligned_be16(&radio->int_in_buffer[ -- cgit v0.10.2 From 94238e9b1946a300b7aeb8bc1ab7f55f6f27e225 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 27 Aug 2011 11:30:25 -0300 Subject: [media] dvb_frontend: fix compile warning Andreas Oberritter has looked at this and agreed that it is safe to remove the 'timeout' variable. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 4b05931..2c0acdb 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -537,7 +537,6 @@ static int dvb_frontend_thread(void *data) { struct dvb_frontend *fe = data; struct dvb_frontend_private *fepriv = fe->frontend_priv; - unsigned long timeout; fe_status_t s; enum dvbfe_algo algo; @@ -558,7 +557,7 @@ static int dvb_frontend_thread(void *data) while (1) { up(&fepriv->sem); /* is locked when we enter the thread... */ restart: - timeout = wait_event_interruptible_timeout(fepriv->wait_queue, + wait_event_interruptible_timeout(fepriv->wait_queue, dvb_frontend_should_wakeup(fe) || kthread_should_stop() || freezing(current), fepriv->delay); -- cgit v0.10.2 From 8c79eecebb730de8c0610d2b79a6a10e51106ba4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 29 Jul 2011 07:19:46 -0300 Subject: [media] vivi: fill in colorspace The colorspace was never filled in, causing complaints from v4l2-compliance. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index a848bd2..b3ae1ba 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -852,6 +852,11 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, (f->fmt.pix.width * dev->fmt->depth) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + if (dev->fmt->fourcc == V4L2_PIX_FMT_YUYV || + dev->fmt->fourcc == V4L2_PIX_FMT_UYVY) + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + else + f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; return 0; } @@ -885,6 +890,11 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, (f->fmt.pix.width * fmt->depth) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + if (fmt->fourcc == V4L2_PIX_FMT_YUYV || + fmt->fourcc == V4L2_PIX_FMT_UYVY) + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + else + f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; return 0; } -- cgit v0.10.2 From 2b5d948040dedaa765c9046f634212a2757f5442 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 29 Jul 2011 07:21:33 -0300 Subject: [media] ivtv: fill in service_set The service_set field of struct v4l2_sliced_vbi_cap was never filled in. The v4l2-compliance tool complained about this, so this is now fixed. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 3e5c090..ecafa69 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1203,9 +1203,7 @@ static int ivtv_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced cap->service_lines[f][l] = set; } } - return 0; - } - if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) { + } else if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) { if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT)) return -EINVAL; if (itv->is_60hz) { @@ -1215,9 +1213,16 @@ static int ivtv_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced cap->service_lines[0][23] = V4L2_SLICED_WSS_625; cap->service_lines[0][16] = V4L2_SLICED_VPS; } - return 0; + } else { + return -EINVAL; } - return -EINVAL; + + set = 0; + for (f = 0; f < 2; f++) + for (l = 0; l < 24; l++) + set |= cap->service_lines[f][l]; + cap->service_set = set; + return 0; } static int ivtv_g_enc_index(struct file *file, void *fh, struct v4l2_enc_idx *idx) -- cgit v0.10.2 From 93d5a30bcabb49a3179d68f5714d43ae1560ede8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 9 Aug 2011 09:32:06 -0300 Subject: [media] v4l2-ioctl: more -ENOTTY fixes explicitly instead of using a macro. ioctls and the ENUMSTD, S_STD and G_PARM ioctls. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index 9f80e9d..a0089bf 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -55,13 +55,18 @@ memset((u8 *)(p) + offsetof(typeof(*(p)), field) + sizeof((p)->field), \ 0, sizeof(*(p)) - offsetof(typeof(*(p)), field) - sizeof((p)->field)) -#define no_ioctl_err(foo) ( ( \ +#define have_fmt_ops(foo) ( \ ops->vidioc_##foo##_fmt_vid_cap || \ ops->vidioc_##foo##_fmt_vid_out || \ ops->vidioc_##foo##_fmt_vid_cap_mplane || \ ops->vidioc_##foo##_fmt_vid_out_mplane || \ ops->vidioc_##foo##_fmt_vid_overlay || \ - ops->vidioc_##foo##_fmt_type_private) ? -EINVAL : -ENOTTY) + ops->vidioc_##foo##_fmt_vbi_cap || \ + ops->vidioc_##foo##_fmt_vid_out_overlay || \ + ops->vidioc_##foo##_fmt_vbi_out || \ + ops->vidioc_##foo##_fmt_sliced_vbi_cap || \ + ops->vidioc_##foo##_fmt_sliced_vbi_out || \ + ops->vidioc_##foo##_fmt_type_private) struct std_descr { v4l2_std_id std; @@ -551,6 +556,7 @@ static long __video_do_ioctl(struct file *file, struct v4l2_fh *vfh = NULL; struct v4l2_format f_copy; int use_fh_prio = 0; + long ret_prio = 0; long ret = -ENOTTY; if (ops == NULL) { @@ -570,39 +576,8 @@ static long __video_do_ioctl(struct file *file, use_fh_prio = test_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); } - if (use_fh_prio) { - switch (cmd) { - case VIDIOC_S_CTRL: - case VIDIOC_S_STD: - case VIDIOC_S_INPUT: - case VIDIOC_S_OUTPUT: - case VIDIOC_S_TUNER: - case VIDIOC_S_FREQUENCY: - case VIDIOC_S_FMT: - case VIDIOC_S_CROP: - case VIDIOC_S_AUDIO: - case VIDIOC_S_AUDOUT: - case VIDIOC_S_EXT_CTRLS: - case VIDIOC_S_FBUF: - case VIDIOC_S_PRIORITY: - case VIDIOC_S_DV_PRESET: - case VIDIOC_S_DV_TIMINGS: - case VIDIOC_S_JPEGCOMP: - case VIDIOC_S_MODULATOR: - case VIDIOC_S_PARM: - case VIDIOC_S_HW_FREQ_SEEK: - case VIDIOC_ENCODER_CMD: - case VIDIOC_OVERLAY: - case VIDIOC_REQBUFS: - case VIDIOC_STREAMON: - case VIDIOC_STREAMOFF: - ret = v4l2_prio_check(vfd->prio, vfh->prio); - if (ret) - goto exit_prio; - ret = -ENOTTY; - break; - } - } + if (use_fh_prio) + ret_prio = v4l2_prio_check(vfd->prio, vfh->prio); switch (cmd) { @@ -651,7 +626,9 @@ static long __video_do_ioctl(struct file *file, if (ops->vidioc_s_priority) ret = ops->vidioc_s_priority(file, fh, *p); else - ret = v4l2_prio_change(&vfd->v4l2_dev->prio, &vfh->prio, *p); + ret = ret_prio ? ret_prio : + v4l2_prio_change(&vfd->v4l2_dev->prio, + &vfh->prio, *p); break; } @@ -701,8 +678,14 @@ static long __video_do_ioctl(struct file *file, (f->pixelformat >> 16) & 0xff, (f->pixelformat >> 24) & 0xff, f->description); - else if (ret == -ENOTTY) - ret = no_ioctl_err(enum); + else if (ret == -ENOTTY && + (ops->vidioc_enum_fmt_vid_cap || + ops->vidioc_enum_fmt_vid_out || + ops->vidioc_enum_fmt_vid_cap_mplane || + ops->vidioc_enum_fmt_vid_out_mplane || + ops->vidioc_enum_fmt_vid_overlay || + ops->vidioc_enum_fmt_type_private)) + ret = -EINVAL; break; } case VIDIOC_G_FMT: @@ -827,8 +810,8 @@ static long __video_do_ioctl(struct file *file, fh, f); break; } - if (unlikely(ret == -ENOTTY)) - ret = no_ioctl_err(g); + if (unlikely(ret == -ENOTTY && have_fmt_ops(g))) + ret = -EINVAL; break; } @@ -836,6 +819,14 @@ static long __video_do_ioctl(struct file *file, { struct v4l2_format *f = (struct v4l2_format *)arg; + if (!have_fmt_ops(s)) + break; + if (ret_prio) { + ret = ret_prio; + break; + } + ret = -EINVAL; + /* FIXME: Should be one dump per type */ dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names)); @@ -966,8 +957,6 @@ static long __video_do_ioctl(struct file *file, fh, f); break; } - if (unlikely(ret == -ENOTTY)) - ret = no_ioctl_err(g); break; } case VIDIOC_TRY_FMT: @@ -1097,8 +1086,6 @@ static long __video_do_ioctl(struct file *file, if (likely(ops->vidioc_try_fmt_sliced_vbi_out)) ret = ops->vidioc_try_fmt_sliced_vbi_out(file, fh, f); - else - ret = no_ioctl_err(try); break; case V4L2_BUF_TYPE_PRIVATE: /* CLEAR_AFTER_FIELD(f, fmt.raw_data); <- does nothing */ @@ -1107,8 +1094,8 @@ static long __video_do_ioctl(struct file *file, fh, f); break; } - if (unlikely(ret == -ENOTTY)) - ret = no_ioctl_err(g); + if (unlikely(ret == -ENOTTY && have_fmt_ops(try))) + ret = -EINVAL; break; } /* FIXME: Those buf reqs could be handled here, @@ -1121,6 +1108,10 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_reqbufs) break; + if (ret_prio) { + ret = ret_prio; + break; + } ret = check_fmt(ops, p->type); if (ret) break; @@ -1186,6 +1177,10 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_overlay) break; + if (ret_prio) { + ret = ret_prio; + break; + } dbgarg(cmd, "value=%d\n", *i); ret = ops->vidioc_overlay(file, fh, *i); break; @@ -1211,6 +1206,10 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_s_fbuf) break; + if (ret_prio) { + ret = ret_prio; + break; + } dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n", p->capability, p->flags, (unsigned long)p->base); v4l_print_pix_fmt(vfd, &p->fmt); @@ -1223,6 +1222,10 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_streamon) break; + if (ret_prio) { + ret = ret_prio; + break; + } dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names)); ret = ops->vidioc_streamon(file, fh, i); break; @@ -1233,6 +1236,10 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_streamoff) break; + if (ret_prio) { + ret = ret_prio; + break; + } dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names)); ret = ops->vidioc_streamoff(file, fh, i); break; @@ -1245,6 +1252,10 @@ static long __video_do_ioctl(struct file *file, unsigned int index = p->index, i, j = 0; const char *descr = ""; + if (id == 0) + break; + ret = -EINVAL; + /* Return norm array in a canonical way */ for (i = 0; i <= index && id; i++) { /* last std value in the standards array is 0, so this @@ -1298,13 +1309,20 @@ static long __video_do_ioctl(struct file *file, dbgarg(cmd, "std=%08Lx\n", (long long unsigned)*id); + if (!ops->vidioc_s_std) + break; + + if (ret_prio) { + ret = ret_prio; + break; + } + ret = -EINVAL; norm = (*id) & vfd->tvnorms; if (vfd->tvnorms && !norm) /* Check if std is supported */ break; /* Calls the specific handler */ - if (ops->vidioc_s_std) - ret = ops->vidioc_s_std(file, fh, &norm); + ret = ops->vidioc_s_std(file, fh, &norm); /* Updates standard information */ if (ret >= 0) @@ -1373,6 +1391,10 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_s_input) break; + if (ret_prio) { + ret = ret_prio; + break; + } dbgarg(cmd, "value=%d\n", *i); ret = ops->vidioc_s_input(file, fh, *i); break; @@ -1425,6 +1447,10 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_s_output) break; + if (ret_prio) { + ret = ret_prio; + break; + } dbgarg(cmd, "value=%d\n", *i); ret = ops->vidioc_s_output(file, fh, *i); break; @@ -1494,6 +1520,10 @@ static long __video_do_ioctl(struct file *file, if (!(vfh && vfh->ctrl_handler) && !vfd->ctrl_handler && !ops->vidioc_s_ctrl && !ops->vidioc_s_ext_ctrls) break; + if (ret_prio) { + ret = ret_prio; + break; + } dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value); @@ -1519,6 +1549,8 @@ static long __video_do_ioctl(struct file *file, ctrl.value = p->value; if (check_ext_ctrls(&ctrls, 1)) ret = ops->vidioc_s_ext_ctrls(file, fh, &ctrls); + else + ret = -EINVAL; break; } case VIDIOC_G_EXT_CTRLS: @@ -1530,8 +1562,10 @@ static long __video_do_ioctl(struct file *file, ret = v4l2_g_ext_ctrls(vfh->ctrl_handler, p); else if (vfd->ctrl_handler) ret = v4l2_g_ext_ctrls(vfd->ctrl_handler, p); - else if (ops->vidioc_g_ext_ctrls && check_ext_ctrls(p, 0)) - ret = ops->vidioc_g_ext_ctrls(file, fh, p); + else if (ops->vidioc_g_ext_ctrls) + ret = check_ext_ctrls(p, 0) ? + ops->vidioc_g_ext_ctrls(file, fh, p) : + -EINVAL; else break; v4l_print_ext_ctrls(cmd, vfd, p, !ret); @@ -1545,6 +1579,10 @@ static long __video_do_ioctl(struct file *file, if (!(vfh && vfh->ctrl_handler) && !vfd->ctrl_handler && !ops->vidioc_s_ext_ctrls) break; + if (ret_prio) { + ret = ret_prio; + break; + } v4l_print_ext_ctrls(cmd, vfd, p, 1); if (vfh && vfh->ctrl_handler) ret = v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, p); @@ -1552,6 +1590,8 @@ static long __video_do_ioctl(struct file *file, ret = v4l2_s_ext_ctrls(NULL, vfd->ctrl_handler, p); else if (check_ext_ctrls(p, 0)) ret = ops->vidioc_s_ext_ctrls(file, fh, p); + else + ret = -EINVAL; break; } case VIDIOC_TRY_EXT_CTRLS: @@ -1569,6 +1609,8 @@ static long __video_do_ioctl(struct file *file, ret = v4l2_try_ext_ctrls(vfd->ctrl_handler, p); else if (check_ext_ctrls(p, 0)) ret = ops->vidioc_try_ext_ctrls(file, fh, p); + else + ret = -EINVAL; break; } case VIDIOC_QUERYMENU: @@ -1629,6 +1671,10 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_s_audio) break; + if (ret_prio) { + ret = ret_prio; + break; + } dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " "mode=0x%x\n", p->index, p->name, p->capability, p->mode); @@ -1669,6 +1715,10 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_s_audout) break; + if (ret_prio) { + ret = ret_prio; + break; + } dbgarg(cmd, "index=%d, name=%s, capability=%d, " "mode=%d\n", p->index, p->name, p->capability, p->mode); @@ -1698,6 +1748,10 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_s_modulator) break; + if (ret_prio) { + ret = ret_prio; + break; + } dbgarg(cmd, "index=%d, name=%s, capability=%d, " "rangelow=%d, rangehigh=%d, txsubchans=%d\n", p->index, p->name, p->capability, p->rangelow, @@ -1724,6 +1778,10 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_s_crop) break; + if (ret_prio) { + ret = ret_prio; + break; + } dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); dbgrect(vfd, "", &p->c); ret = ops->vidioc_s_crop(file, fh, p); @@ -1767,11 +1825,15 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_g_jpegcomp) break; + if (ret_prio) { + ret = ret_prio; + break; + } dbgarg(cmd, "quality=%d, APPn=%d, APP_len=%d, " "COM_len=%d, jpeg_markers=%d\n", p->quality, p->APPn, p->APP_len, p->COM_len, p->jpeg_markers); - ret = ops->vidioc_s_jpegcomp(file, fh, p); + ret = ops->vidioc_s_jpegcomp(file, fh, p); break; } case VIDIOC_G_ENC_INDEX: @@ -1792,6 +1854,10 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_encoder_cmd) break; + if (ret_prio) { + ret = ret_prio; + break; + } ret = ops->vidioc_encoder_cmd(file, fh, p); if (!ret) dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); @@ -1812,6 +1878,8 @@ static long __video_do_ioctl(struct file *file, { struct v4l2_streamparm *p = arg; + if (!ops->vidioc_g_parm && !vfd->current_norm) + break; if (ops->vidioc_g_parm) { ret = check_fmt(ops, p->type); if (ret) @@ -1820,14 +1888,13 @@ static long __video_do_ioctl(struct file *file, } else { v4l2_std_id std = vfd->current_norm; + ret = -EINVAL; if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) break; ret = 0; if (ops->vidioc_g_std) ret = ops->vidioc_g_std(file, fh, &std); - else if (std == 0) - ret = -ENOTTY; if (ret == 0) v4l2_video_std_frame_period(std, &p->parm.capture.timeperframe); @@ -1842,6 +1909,10 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_s_parm) break; + if (ret_prio) { + ret = ret_prio; + break; + } ret = check_fmt(ops, p->type); if (ret) break; @@ -1877,6 +1948,10 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_s_tuner) break; + if (ret_prio) { + ret = ret_prio; + break; + } p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; dbgarg(cmd, "index=%d, name=%s, type=%d, " @@ -1911,6 +1986,10 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_s_frequency) break; + if (ret_prio) { + ret = ret_prio; + break; + } dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n", p->tuner, p->type, p->frequency); ret = ops->vidioc_s_frequency(file, fh, p); @@ -1985,6 +2064,10 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_s_hw_freq_seek) break; + if (ret_prio) { + ret = ret_prio; + break; + } type = (vfd->vfl_type == VFL_TYPE_RADIO) ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; dbgarg(cmd, @@ -2089,6 +2172,10 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_s_dv_preset) break; + if (ret_prio) { + ret = ret_prio; + break; + } dbgarg(cmd, "preset=%d\n", p->preset); ret = ops->vidioc_s_dv_preset(file, fh, p); @@ -2124,6 +2211,10 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_s_dv_timings) break; + if (ret_prio) { + ret = ret_prio; + break; + } switch (p->type) { case V4L2_DV_BT_656_1120: @@ -2232,19 +2323,12 @@ static long __video_do_ioctl(struct file *file, break; } default: - { - bool valid_prio = true; - if (!ops->vidioc_default) break; - if (use_fh_prio) - valid_prio = v4l2_prio_check(vfd->prio, vfh->prio) >= 0; - ret = ops->vidioc_default(file, fh, valid_prio, cmd, arg); + ret = ops->vidioc_default(file, fh, ret_prio >= 0, cmd, arg); break; - } } /* switch */ -exit_prio: if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { if (ret < 0) { v4l_print_ioctl(vfd->name, cmd); -- cgit v0.10.2 From 1d0c86cad38678fa42f6d048a7b9e4057c8c16fc Mon Sep 17 00:00:00 2001 From: Tomasz Stanislawski Date: Fri, 1 Jul 2011 06:25:46 -0300 Subject: [media] media: v4l: remove single to multiplane conversion This patch removes an implicit conversion between multi and single plane formats from V4L2 framework. The conversion is to be performed by libv4l2. Signed-off-by: Tomasz Stanislawski Signed-off-by: Kyungmin Park Signed-off-by: Marek Szyprowski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index a0089bf..21c49dc 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -490,63 +490,6 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type) return -EINVAL; } -/** - * fmt_sp_to_mp() - Convert a single-plane format to its multi-planar 1-plane - * equivalent - */ -static int fmt_sp_to_mp(const struct v4l2_format *f_sp, - struct v4l2_format *f_mp) -{ - struct v4l2_pix_format_mplane *pix_mp = &f_mp->fmt.pix_mp; - const struct v4l2_pix_format *pix = &f_sp->fmt.pix; - - if (f_sp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - f_mp->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - else if (f_sp->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - f_mp->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - else - return -EINVAL; - - pix_mp->width = pix->width; - pix_mp->height = pix->height; - pix_mp->pixelformat = pix->pixelformat; - pix_mp->field = pix->field; - pix_mp->colorspace = pix->colorspace; - pix_mp->num_planes = 1; - pix_mp->plane_fmt[0].sizeimage = pix->sizeimage; - pix_mp->plane_fmt[0].bytesperline = pix->bytesperline; - - return 0; -} - -/** - * fmt_mp_to_sp() - Convert a multi-planar 1-plane format to its single-planar - * equivalent - */ -static int fmt_mp_to_sp(const struct v4l2_format *f_mp, - struct v4l2_format *f_sp) -{ - const struct v4l2_pix_format_mplane *pix_mp = &f_mp->fmt.pix_mp; - struct v4l2_pix_format *pix = &f_sp->fmt.pix; - - if (f_mp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - f_sp->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - else if (f_mp->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - f_sp->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - else - return -EINVAL; - - pix->width = pix_mp->width; - pix->height = pix_mp->height; - pix->pixelformat = pix_mp->pixelformat; - pix->field = pix_mp->field; - pix->colorspace = pix_mp->colorspace; - pix->sizeimage = pix_mp->plane_fmt[0].sizeimage; - pix->bytesperline = pix_mp->plane_fmt[0].bytesperline; - - return 0; -} - static long __video_do_ioctl(struct file *file, unsigned int cmd, void *arg) { @@ -554,7 +497,6 @@ static long __video_do_ioctl(struct file *file, const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; void *fh = file->private_data; struct v4l2_fh *vfh = NULL; - struct v4l2_format f_copy; int use_fh_prio = 0; long ret_prio = 0; long ret = -ENOTTY; @@ -697,42 +639,15 @@ static long __video_do_ioctl(struct file *file, switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (ops->vidioc_g_fmt_vid_cap) { + if (ops->vidioc_g_fmt_vid_cap) ret = ops->vidioc_g_fmt_vid_cap(file, fh, f); - } else if (ops->vidioc_g_fmt_vid_cap_mplane) { - if (fmt_sp_to_mp(f, &f_copy)) - break; - ret = ops->vidioc_g_fmt_vid_cap_mplane(file, fh, - &f_copy); - if (ret) - break; - - /* Driver is currently in multi-planar format, - * we can't return it in single-planar API*/ - if (f_copy.fmt.pix_mp.num_planes > 1) { - ret = -EBUSY; - break; - } - - ret = fmt_mp_to_sp(&f_copy, f); - } if (!ret) v4l_print_pix_fmt(vfd, &f->fmt.pix); break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - if (ops->vidioc_g_fmt_vid_cap_mplane) { + if (ops->vidioc_g_fmt_vid_cap_mplane) ret = ops->vidioc_g_fmt_vid_cap_mplane(file, fh, f); - } else if (ops->vidioc_g_fmt_vid_cap) { - if (fmt_mp_to_sp(f, &f_copy)) - break; - ret = ops->vidioc_g_fmt_vid_cap(file, - fh, &f_copy); - if (ret) - break; - - ret = fmt_sp_to_mp(&f_copy, f); - } if (!ret) v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); break; @@ -742,42 +657,15 @@ static long __video_do_ioctl(struct file *file, fh, f); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (ops->vidioc_g_fmt_vid_out) { + if (ops->vidioc_g_fmt_vid_out) ret = ops->vidioc_g_fmt_vid_out(file, fh, f); - } else if (ops->vidioc_g_fmt_vid_out_mplane) { - if (fmt_sp_to_mp(f, &f_copy)) - break; - ret = ops->vidioc_g_fmt_vid_out_mplane(file, fh, - &f_copy); - if (ret) - break; - - /* Driver is currently in multi-planar format, - * we can't return it in single-planar API*/ - if (f_copy.fmt.pix_mp.num_planes > 1) { - ret = -EBUSY; - break; - } - - ret = fmt_mp_to_sp(&f_copy, f); - } if (!ret) v4l_print_pix_fmt(vfd, &f->fmt.pix); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (ops->vidioc_g_fmt_vid_out_mplane) { + if (ops->vidioc_g_fmt_vid_out_mplane) ret = ops->vidioc_g_fmt_vid_out_mplane(file, fh, f); - } else if (ops->vidioc_g_fmt_vid_out) { - if (fmt_mp_to_sp(f, &f_copy)) - break; - ret = ops->vidioc_g_fmt_vid_out(file, - fh, &f_copy); - if (ret) - break; - - ret = fmt_sp_to_mp(&f_copy, f); - } if (!ret) v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); break; @@ -834,44 +722,15 @@ static long __video_do_ioctl(struct file *file, case V4L2_BUF_TYPE_VIDEO_CAPTURE: CLEAR_AFTER_FIELD(f, fmt.pix); v4l_print_pix_fmt(vfd, &f->fmt.pix); - if (ops->vidioc_s_fmt_vid_cap) { + if (ops->vidioc_s_fmt_vid_cap) ret = ops->vidioc_s_fmt_vid_cap(file, fh, f); - } else if (ops->vidioc_s_fmt_vid_cap_mplane) { - if (fmt_sp_to_mp(f, &f_copy)) - break; - ret = ops->vidioc_s_fmt_vid_cap_mplane(file, fh, - &f_copy); - if (ret) - break; - - if (f_copy.fmt.pix_mp.num_planes > 1) { - /* Drivers shouldn't adjust from 1-plane - * to more than 1-plane formats */ - ret = -EBUSY; - WARN_ON(1); - break; - } - - ret = fmt_mp_to_sp(&f_copy, f); - } break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: CLEAR_AFTER_FIELD(f, fmt.pix_mp); v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); - if (ops->vidioc_s_fmt_vid_cap_mplane) { + if (ops->vidioc_s_fmt_vid_cap_mplane) ret = ops->vidioc_s_fmt_vid_cap_mplane(file, fh, f); - } else if (ops->vidioc_s_fmt_vid_cap && - f->fmt.pix_mp.num_planes == 1) { - if (fmt_mp_to_sp(f, &f_copy)) - break; - ret = ops->vidioc_s_fmt_vid_cap(file, - fh, &f_copy); - if (ret) - break; - - ret = fmt_sp_to_mp(&f_copy, f); - } break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: CLEAR_AFTER_FIELD(f, fmt.win); @@ -882,44 +741,15 @@ static long __video_do_ioctl(struct file *file, case V4L2_BUF_TYPE_VIDEO_OUTPUT: CLEAR_AFTER_FIELD(f, fmt.pix); v4l_print_pix_fmt(vfd, &f->fmt.pix); - if (ops->vidioc_s_fmt_vid_out) { + if (ops->vidioc_s_fmt_vid_out) ret = ops->vidioc_s_fmt_vid_out(file, fh, f); - } else if (ops->vidioc_s_fmt_vid_out_mplane) { - if (fmt_sp_to_mp(f, &f_copy)) - break; - ret = ops->vidioc_s_fmt_vid_out_mplane(file, fh, - &f_copy); - if (ret) - break; - - if (f_copy.fmt.pix_mp.num_planes > 1) { - /* Drivers shouldn't adjust from 1-plane - * to more than 1-plane formats */ - ret = -EBUSY; - WARN_ON(1); - break; - } - - ret = fmt_mp_to_sp(&f_copy, f); - } break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: CLEAR_AFTER_FIELD(f, fmt.pix_mp); v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); - if (ops->vidioc_s_fmt_vid_out_mplane) { + if (ops->vidioc_s_fmt_vid_out_mplane) ret = ops->vidioc_s_fmt_vid_out_mplane(file, fh, f); - } else if (ops->vidioc_s_fmt_vid_out && - f->fmt.pix_mp.num_planes == 1) { - if (fmt_mp_to_sp(f, &f_copy)) - break; - ret = ops->vidioc_s_fmt_vid_out(file, - fh, &f_copy); - if (ret) - break; - - ret = fmt_mp_to_sp(&f_copy, f); - } break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: CLEAR_AFTER_FIELD(f, fmt.win); @@ -969,44 +799,16 @@ static long __video_do_ioctl(struct file *file, switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: CLEAR_AFTER_FIELD(f, fmt.pix); - if (ops->vidioc_try_fmt_vid_cap) { + if (ops->vidioc_try_fmt_vid_cap) ret = ops->vidioc_try_fmt_vid_cap(file, fh, f); - } else if (ops->vidioc_try_fmt_vid_cap_mplane) { - if (fmt_sp_to_mp(f, &f_copy)) - break; - ret = ops->vidioc_try_fmt_vid_cap_mplane(file, - fh, &f_copy); - if (ret) - break; - - if (f_copy.fmt.pix_mp.num_planes > 1) { - /* Drivers shouldn't adjust from 1-plane - * to more than 1-plane formats */ - ret = -EBUSY; - WARN_ON(1); - break; - } - ret = fmt_mp_to_sp(&f_copy, f); - } if (!ret) v4l_print_pix_fmt(vfd, &f->fmt.pix); break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: CLEAR_AFTER_FIELD(f, fmt.pix_mp); - if (ops->vidioc_try_fmt_vid_cap_mplane) { + if (ops->vidioc_try_fmt_vid_cap_mplane) ret = ops->vidioc_try_fmt_vid_cap_mplane(file, fh, f); - } else if (ops->vidioc_try_fmt_vid_cap && - f->fmt.pix_mp.num_planes == 1) { - if (fmt_mp_to_sp(f, &f_copy)) - break; - ret = ops->vidioc_try_fmt_vid_cap(file, - fh, &f_copy); - if (ret) - break; - - ret = fmt_sp_to_mp(&f_copy, f); - } if (!ret) v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); break; @@ -1018,44 +820,16 @@ static long __video_do_ioctl(struct file *file, break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: CLEAR_AFTER_FIELD(f, fmt.pix); - if (ops->vidioc_try_fmt_vid_out) { + if (ops->vidioc_try_fmt_vid_out) ret = ops->vidioc_try_fmt_vid_out(file, fh, f); - } else if (ops->vidioc_try_fmt_vid_out_mplane) { - if (fmt_sp_to_mp(f, &f_copy)) - break; - ret = ops->vidioc_try_fmt_vid_out_mplane(file, - fh, &f_copy); - if (ret) - break; - - if (f_copy.fmt.pix_mp.num_planes > 1) { - /* Drivers shouldn't adjust from 1-plane - * to more than 1-plane formats */ - ret = -EBUSY; - WARN_ON(1); - break; - } - ret = fmt_mp_to_sp(&f_copy, f); - } if (!ret) v4l_print_pix_fmt(vfd, &f->fmt.pix); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: CLEAR_AFTER_FIELD(f, fmt.pix_mp); - if (ops->vidioc_try_fmt_vid_out_mplane) { + if (ops->vidioc_try_fmt_vid_out_mplane) ret = ops->vidioc_try_fmt_vid_out_mplane(file, fh, f); - } else if (ops->vidioc_try_fmt_vid_out && - f->fmt.pix_mp.num_planes == 1) { - if (fmt_mp_to_sp(f, &f_copy)) - break; - ret = ops->vidioc_try_fmt_vid_out(file, - fh, &f_copy); - if (ret) - break; - - ret = fmt_sp_to_mp(&f_copy, f); - } if (!ret) v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); break; -- cgit v0.10.2 From a6bd62be5a3e3a2eee9c0c1d7c04cb52cff3e073 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 25 Aug 2011 07:21:21 -0300 Subject: [media] media: mem2mem: eliminate possible NULL pointer dereference This patch removes the possible NULL pointer dereference in mem2mem code. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Marek Szyprowski CC: Pawel Osciak Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/v4l2-mem2mem.c b/drivers/media/video/v4l2-mem2mem.c index 3b15bf5..975d0fa 100644 --- a/drivers/media/video/v4l2-mem2mem.c +++ b/drivers/media/video/v4l2-mem2mem.c @@ -97,11 +97,12 @@ void *v4l2_m2m_next_buf(struct v4l2_m2m_queue_ctx *q_ctx) spin_lock_irqsave(&q_ctx->rdy_spinlock, flags); - if (list_empty(&q_ctx->rdy_queue)) - goto end; + if (list_empty(&q_ctx->rdy_queue)) { + spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags); + return NULL; + } b = list_entry(q_ctx->rdy_queue.next, struct v4l2_m2m_buffer, list); -end: spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags); return &b->vb; } @@ -117,12 +118,13 @@ void *v4l2_m2m_buf_remove(struct v4l2_m2m_queue_ctx *q_ctx) unsigned long flags; spin_lock_irqsave(&q_ctx->rdy_spinlock, flags); - if (!list_empty(&q_ctx->rdy_queue)) { - b = list_entry(q_ctx->rdy_queue.next, struct v4l2_m2m_buffer, - list); - list_del(&b->list); - q_ctx->num_rdy--; + if (list_empty(&q_ctx->rdy_queue)) { + spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags); + return NULL; } + b = list_entry(q_ctx->rdy_queue.next, struct v4l2_m2m_buffer, list); + list_del(&b->list); + q_ctx->num_rdy--; spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags); return &b->vb; -- cgit v0.10.2 From c1426bc727b78808fb956f7402b689144c1506ee Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 24 Aug 2011 06:36:26 -0300 Subject: [media] media: vb2: add a check if queued userptr buffer is large enough Videobuf2 accepted any userptr buffer without verifying if its size is large enough to store the video data from the driver. The driver reports the minimal size of video data once in queue_setup and expects that videobuf2 provides buffers that match these requirements. This patch adds the required check. Reported-by: Laurent Pinchart Signed-off-by: Marek Szyprowski Signed-off-by: Kyungmin Park CC: Pawel Osciak Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 3015e60..c360627 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -43,8 +43,7 @@ module_param(debug, int, 0644); /** * __vb2_buf_mem_alloc() - allocate video memory for the given buffer */ -static int __vb2_buf_mem_alloc(struct vb2_buffer *vb, - unsigned long *plane_sizes) +static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) { struct vb2_queue *q = vb->vb2_queue; void *mem_priv; @@ -53,13 +52,13 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb, /* Allocate memory for all planes in this buffer */ for (plane = 0; plane < vb->num_planes; ++plane) { mem_priv = call_memop(q, plane, alloc, q->alloc_ctx[plane], - plane_sizes[plane]); + q->plane_sizes[plane]); if (IS_ERR_OR_NULL(mem_priv)) goto free; /* Associate allocator private data with this plane */ vb->planes[plane].mem_priv = mem_priv; - vb->v4l2_planes[plane].length = plane_sizes[plane]; + vb->v4l2_planes[plane].length = q->plane_sizes[plane]; } return 0; @@ -141,8 +140,7 @@ static void __setup_offsets(struct vb2_queue *q) * Returns the number of buffers successfully allocated. */ static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory, - unsigned int num_buffers, unsigned int num_planes, - unsigned long plane_sizes[]) + unsigned int num_buffers, unsigned int num_planes) { unsigned int buffer; struct vb2_buffer *vb; @@ -169,7 +167,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory, /* Allocate video buffer memory for the MMAP type */ if (memory == V4L2_MEMORY_MMAP) { - ret = __vb2_buf_mem_alloc(vb, plane_sizes); + ret = __vb2_buf_mem_alloc(vb); if (ret) { dprintk(1, "Failed allocating memory for " "buffer %d\n", buffer); @@ -454,7 +452,6 @@ static bool __buffers_in_use(struct vb2_queue *q) int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) { unsigned int num_buffers, num_planes; - unsigned long plane_sizes[VIDEO_MAX_PLANES]; int ret = 0; if (q->fileio) { @@ -516,7 +513,7 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) * Make sure the requested values and current defaults are sane. */ num_buffers = min_t(unsigned int, req->count, VIDEO_MAX_FRAME); - memset(plane_sizes, 0, sizeof(plane_sizes)); + memset(q->plane_sizes, 0, sizeof(q->plane_sizes)); memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx)); q->memory = req->memory; @@ -525,13 +522,12 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) * Driver also sets the size and allocator context for each plane. */ ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes, - plane_sizes, q->alloc_ctx); + q->plane_sizes, q->alloc_ctx); if (ret) return ret; /* Finally, allocate buffers and video memory */ - ret = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes, - plane_sizes); + ret = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes); if (ret == 0) { dprintk(1, "Memory allocation failed\n"); return -ENOMEM; @@ -545,7 +541,7 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) orig_num_buffers = num_buffers = ret; ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes, - plane_sizes, q->alloc_ctx); + q->plane_sizes, q->alloc_ctx); if (ret) goto free_mem; @@ -745,12 +741,20 @@ static int __qbuf_userptr(struct vb2_buffer *vb, struct v4l2_buffer *b) dprintk(3, "qbuf: userspace address for plane %d changed, " "reacquiring memory\n", plane); + /* Check if the provided plane buffer is large enough */ + if (planes[plane].length < q->plane_sizes[plane]) { + ret = EINVAL; + goto err; + } + /* Release previously acquired memory if present */ if (vb->planes[plane].mem_priv) call_memop(q, plane, put_userptr, vb->planes[plane].mem_priv); vb->planes[plane].mem_priv = NULL; + vb->v4l2_planes[plane].m.userptr = 0; + vb->v4l2_planes[plane].length = 0; /* Acquire each plane's memory */ if (q->mem_ops->get_userptr) { @@ -788,10 +792,13 @@ static int __qbuf_userptr(struct vb2_buffer *vb, struct v4l2_buffer *b) return 0; err: /* In case of errors, release planes that were already acquired */ - for (; plane > 0; --plane) { - call_memop(q, plane, put_userptr, - vb->planes[plane - 1].mem_priv); - vb->planes[plane - 1].mem_priv = NULL; + for (plane = 0; plane < vb->num_planes; ++plane) { + if (vb->planes[plane].mem_priv) + call_memop(q, plane, put_userptr, + vb->planes[plane].mem_priv); + vb->planes[plane].mem_priv = NULL; + vb->v4l2_planes[plane].m.userptr = 0; + vb->v4l2_planes[plane].length = 0; } return ret; diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index f87472a..496d6e5 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -276,6 +276,7 @@ struct vb2_queue { wait_queue_head_t done_wq; void *alloc_ctx[VIDEO_MAX_PLANES]; + unsigned long plane_sizes[VIDEO_MAX_PLANES]; unsigned int streaming:1; -- cgit v0.10.2 From 25a27d91006091e28532053c95fa36b70b79d3ad Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 24 Aug 2011 06:49:35 -0300 Subject: [media] media: vb2: fix handling MAPPED buffer flag MAPPED flag was set for the buffer only if all it's planes were mapped and relied on a simple mapping counter. This assumption is really bogus, especially because the buffers may be mapped multiple times. Also the meaning of this flag for muliplane buffers was not really useful. This patch fixes this issue by setting the MAPPED flag for the buffer if any of it's planes is in use (what means that has been mapped at least once), so MAPPED flag can be used as 'in_use' indicator. Reported-by: Hans Verkuil Signed-off-by: Marek Szyprowski Signed-off-by: Kyungmin Park CC: Pawel Osciak Tested-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index c360627..e89fd53 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -277,6 +277,41 @@ static int __verify_planes_array(struct vb2_buffer *vb, struct v4l2_buffer *b) } /** + * __buffer_in_use() - return true if the buffer is in use and + * the queue cannot be freed (by the means of REQBUFS(0)) call + */ +static bool __buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb) +{ + unsigned int plane; + for (plane = 0; plane < vb->num_planes; ++plane) { + /* + * If num_users() has not been provided, call_memop + * will return 0, apparently nobody cares about this + * case anyway. If num_users() returns more than 1, + * we are not the only user of the plane's memory. + */ + if (call_memop(q, plane, num_users, + vb->planes[plane].mem_priv) > 1) + return true; + } + return false; +} + +/** + * __buffers_in_use() - return true if any buffers on the queue are in use and + * the queue cannot be freed (by the means of REQBUFS(0)) call + */ +static bool __buffers_in_use(struct vb2_queue *q) +{ + unsigned int buffer; + for (buffer = 0; buffer < q->num_buffers; ++buffer) { + if (__buffer_in_use(q, q->bufs[buffer])) + return true; + } + return false; +} + +/** * __fill_v4l2_buffer() - fill in a struct v4l2_buffer with information to be * returned to userspace */ @@ -335,7 +370,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) break; } - if (vb->num_planes_mapped == vb->num_planes) + if (__buffer_in_use(q, vb)) b->flags |= V4L2_BUF_FLAG_MAPPED; return ret; @@ -400,33 +435,6 @@ static int __verify_mmap_ops(struct vb2_queue *q) } /** - * __buffers_in_use() - return true if any buffers on the queue are in use and - * the queue cannot be freed (by the means of REQBUFS(0)) call - */ -static bool __buffers_in_use(struct vb2_queue *q) -{ - unsigned int buffer, plane; - struct vb2_buffer *vb; - - for (buffer = 0; buffer < q->num_buffers; ++buffer) { - vb = q->bufs[buffer]; - for (plane = 0; plane < vb->num_planes; ++plane) { - /* - * If num_users() has not been provided, call_memop - * will return 0, apparently nobody cares about this - * case anyway. If num_users() returns more than 1, - * we are not the only user of the plane's memory. - */ - if (call_memop(q, plane, num_users, - vb->planes[plane].mem_priv) > 1) - return true; - } - } - - return false; -} - -/** * vb2_reqbufs() - Initiate streaming * @q: videobuf2 queue * @req: struct passed from userspace to vidioc_reqbufs handler in driver @@ -1343,9 +1351,6 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) if (ret) return ret; - vb_plane->mapped = 1; - vb->num_planes_mapped++; - dprintk(3, "Buffer %d, plane %d successfully mapped\n", buffer, plane); return 0; } diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 496d6e5..984f2ba 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -75,7 +75,6 @@ struct vb2_mem_ops { struct vb2_plane { void *mem_priv; - int mapped:1; }; /** @@ -147,7 +146,6 @@ struct vb2_queue; * @done_entry: entry on the list that stores all buffers ready to * be dequeued to userspace * @planes: private per-plane information; do not change - * @num_planes_mapped: number of mapped planes; do not change */ struct vb2_buffer { struct v4l2_buffer v4l2_buf; @@ -164,7 +162,6 @@ struct vb2_buffer { struct list_head done_entry; struct vb2_plane planes[VIDEO_MAX_PLANES]; - unsigned int num_planes_mapped; }; /** -- cgit v0.10.2 From 035aa1475d6e4afdf97dccf6c6d6059063398b57 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 24 Aug 2011 06:43:36 -0300 Subject: [media] media: vb2: change plane sizes array to unsigned int[] Plane sizes array was declared as unsigned long[], while unsigned int is more than enough for storing size of the video buffer. This patch reduces the size of the array by definiting it as unsigned int[]. Reported-by: Laurent Pinchart Signed-off-by: Marek Szyprowski Signed-off-by: Kyungmin Park CC: Pawel Osciak Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/video/atmel-isi.c index 7b89f00..5a4b2d7 100644 --- a/drivers/media/video/atmel-isi.c +++ b/drivers/media/video/atmel-isi.c @@ -249,7 +249,7 @@ static int atmel_isi_wait_status(struct atmel_isi *isi, int wait_reset) Videobuf operations ------------------------------------------------------------------*/ static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, - unsigned int *nplanes, unsigned long sizes[], + unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { struct soc_camera_device *icd = soc_camera_from_vb2q(vq); diff --git a/drivers/media/video/marvell-ccic/mcam-core.c b/drivers/media/video/marvell-ccic/mcam-core.c index 83c1451..744cf37 100644 --- a/drivers/media/video/marvell-ccic/mcam-core.c +++ b/drivers/media/video/marvell-ccic/mcam-core.c @@ -884,7 +884,7 @@ static int mcam_read_setup(struct mcam_camera *cam) */ static int mcam_vb_queue_setup(struct vb2_queue *vq, unsigned int *nbufs, - unsigned int *num_planes, unsigned long sizes[], + unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { struct mcam_camera *cam = vb2_get_drv_priv(vq); diff --git a/drivers/media/video/mem2mem_testdev.c b/drivers/media/video/mem2mem_testdev.c index 166bf93..0d0c0d5 100644 --- a/drivers/media/video/mem2mem_testdev.c +++ b/drivers/media/video/mem2mem_testdev.c @@ -739,7 +739,7 @@ static const struct v4l2_ioctl_ops m2mtest_ioctl_ops = { */ static int m2mtest_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, - unsigned int *nplanes, unsigned long sizes[], + unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { struct m2mtest_ctx *ctx = vb2_get_drv_priv(vq); diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index c045b47..9ae7785 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c @@ -191,7 +191,7 @@ static void mx3_cam_dma_done(void *arg) */ static int mx3_videobuf_setup(struct vb2_queue *vq, unsigned int *count, unsigned int *num_planes, - unsigned long sizes[], void *alloc_ctxs[]) + unsigned int sizes[], void *alloc_ctxs[]) { struct soc_camera_device *icd = soc_camera_from_vb2q(vq); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 51ca358..a7e4f56 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -745,7 +745,7 @@ static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) /* Videobuf2 operations */ static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, - unsigned int *nplanes, unsigned long sizes[], + unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { struct pwc_device *pdev = vb2_get_drv_priv(vq); diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 0d730e5..e6afe5f 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -265,7 +265,7 @@ static unsigned int get_plane_size(struct fimc_frame *fr, unsigned int plane) } static int queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, - unsigned int *num_planes, unsigned long sizes[], + unsigned int *num_planes, unsigned int sizes[], void *allocators[]) { struct fimc_ctx *ctx = vq->drv_priv; diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index aa55066..36d127f 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -692,7 +692,7 @@ static void fimc_job_abort(void *priv) } static int fimc_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, - unsigned int *num_planes, unsigned long sizes[], + unsigned int *num_planes, unsigned int sizes[], void *allocators[]) { struct fimc_ctx *ctx = vb2_get_drv_priv(vq); diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c index b2c5052..dbc94b8 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c @@ -745,7 +745,7 @@ static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = { }; static int s5p_mfc_queue_setup(struct vb2_queue *vq, unsigned int *buf_count, - unsigned int *plane_count, unsigned long psize[], + unsigned int *plane_count, unsigned int psize[], void *allocators[]) { struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c index fee094a..019a9e7 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c @@ -1514,7 +1514,7 @@ static int check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb) static int s5p_mfc_queue_setup(struct vb2_queue *vq, unsigned int *buf_count, unsigned int *plane_count, - unsigned long psize[], void *allocators[]) + unsigned int psize[], void *allocators[]) { struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); diff --git a/drivers/media/video/s5p-tv/mixer_video.c b/drivers/media/video/s5p-tv/mixer_video.c index 43ac22f..8bea0f3 100644 --- a/drivers/media/video/s5p-tv/mixer_video.c +++ b/drivers/media/video/s5p-tv/mixer_video.c @@ -728,7 +728,7 @@ static const struct v4l2_file_operations mxr_fops = { }; static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, - unsigned int *nplanes, unsigned long sizes[], + unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { struct mxr_layer *layer = vb2_get_drv_priv(vq); diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index e540898..8298c89 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -218,7 +218,7 @@ static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev) */ static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq, unsigned int *count, unsigned int *num_planes, - unsigned long sizes[], void *alloc_ctxs[]) + unsigned int sizes[], void *alloc_ctxs[]) { struct soc_camera_device *icd = container_of(vq, struct soc_camera_device, vb2_vidq); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); @@ -243,7 +243,7 @@ static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq, *count = pcdev->video_limit / PAGE_ALIGN(sizes[0]); } - dev_dbg(icd->parent, "count=%d, size=%lu\n", *count, sizes[0]); + dev_dbg(icd->parent, "count=%d, size=%u\n", *count, sizes[0]); return 0; } diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index b3ae1ba..cfe6832 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -651,7 +651,7 @@ static void vivi_stop_generating(struct vivi_dev *dev) Videobuf operations ------------------------------------------------------------------*/ static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, - unsigned int *nplanes, unsigned long sizes[], + unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { struct vivi_dev *dev = vb2_get_drv_priv(vq); diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 984f2ba..5287e90 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -208,7 +208,7 @@ struct vb2_buffer { */ struct vb2_ops { int (*queue_setup)(struct vb2_queue *q, unsigned int *num_buffers, - unsigned int *num_planes, unsigned long sizes[], + unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]); void (*wait_prepare)(struct vb2_queue *q); @@ -273,7 +273,7 @@ struct vb2_queue { wait_queue_head_t done_wq; void *alloc_ctx[VIDEO_MAX_PLANES]; - unsigned long plane_sizes[VIDEO_MAX_PLANES]; + unsigned int plane_sizes[VIDEO_MAX_PLANES]; unsigned int streaming:1; -- cgit v0.10.2 From ba7fcb0c954921534707f08ebc4d8beeb2eb17e7 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 29 Aug 2011 03:20:56 -0300 Subject: [media] media: vb2: dma contig allocator: use dma_addr instread of paddr Use the correct 'dma_addr' name for the buffer address. 'paddr' suggested that this is the physical address in system memory. For most ARM platforms these two are the same, but this is not a generic rule. 'dma_addr' will also point better to dma-mapping api. Signed-off-by: Marek Szyprowski Signed-off-by: Kyungmin Park CC: Pawel Osciak Acked-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/video/atmel-isi.c index 5a4b2d7..7e1d789 100644 --- a/drivers/media/video/atmel-isi.c +++ b/drivers/media/video/atmel-isi.c @@ -341,7 +341,7 @@ static int buffer_prepare(struct vb2_buffer *vb) /* Initialize the dma descriptor */ desc->p_fbd->fb_address = - vb2_dma_contig_plane_paddr(vb, 0); + vb2_dma_contig_plane_dma_addr(vb, 0); desc->p_fbd->next_fbd_address = 0; set_dma_ctrl(desc->p_fbd, ISI_DMA_CTRL_WB); diff --git a/drivers/media/video/marvell-ccic/mcam-core.c b/drivers/media/video/marvell-ccic/mcam-core.c index 744cf37..7abe503 100644 --- a/drivers/media/video/marvell-ccic/mcam-core.c +++ b/drivers/media/video/marvell-ccic/mcam-core.c @@ -450,7 +450,7 @@ static void mcam_set_contig_buffer(struct mcam_camera *cam, int frame) buf = cam->vb_bufs[frame ^ 0x1]; cam->vb_bufs[frame] = buf; mcam_reg_write(cam, frame == 0 ? REG_Y0BAR : REG_Y1BAR, - vb2_dma_contig_plane_paddr(&buf->vb_buf, 0)); + vb2_dma_contig_plane_dma_addr(&buf->vb_buf, 0)); set_bit(CF_SINGLE_BUFFER, &cam->flags); singles++; return; @@ -461,7 +461,7 @@ static void mcam_set_contig_buffer(struct mcam_camera *cam, int frame) buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue); list_del_init(&buf->queue); mcam_reg_write(cam, frame == 0 ? REG_Y0BAR : REG_Y1BAR, - vb2_dma_contig_plane_paddr(&buf->vb_buf, 0)); + vb2_dma_contig_plane_dma_addr(&buf->vb_buf, 0)); cam->vb_bufs[frame] = buf; clear_bit(CF_SINGLE_BUFFER, &cam->flags); } diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index 9ae7785..c8e958a 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c @@ -247,7 +247,7 @@ static int mx3_videobuf_prepare(struct vb2_buffer *vb) } if (buf->state == CSI_BUF_NEEDS_INIT) { - sg_dma_address(sg) = vb2_dma_contig_plane_paddr(vb, 0); + sg_dma_address(sg) = vb2_dma_contig_plane_dma_addr(vb, 0); sg_dma_len(sg) = new_size; buf->txd = ichan->dma_chan.device->device_prep_slave_sg( diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 36d127f..6e3f416 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -457,7 +457,7 @@ int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, dbg("memplanes= %d, colplanes= %d, pix_size= %d", frame->fmt->memplanes, frame->fmt->colplanes, pix_size); - paddr->y = vb2_dma_contig_plane_paddr(vb, 0); + paddr->y = vb2_dma_contig_plane_dma_addr(vb, 0); if (frame->fmt->memplanes == 1) { switch (frame->fmt->colplanes) { @@ -485,10 +485,10 @@ int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, } } else { if (frame->fmt->memplanes >= 2) - paddr->cb = vb2_dma_contig_plane_paddr(vb, 1); + paddr->cb = vb2_dma_contig_plane_dma_addr(vb, 1); if (frame->fmt->memplanes == 3) - paddr->cr = vb2_dma_contig_plane_paddr(vb, 2); + paddr->cr = vb2_dma_contig_plane_dma_addr(vb, 2); } dbg("PHYS_ADDR: y= 0x%X cb= 0x%X cr= 0x%X ret= %d", diff --git a/drivers/media/video/s5p-mfc/s5p_mfc.c b/drivers/media/video/s5p-mfc/s5p_mfc.c index 7dc7eab..af32e02 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc.c @@ -202,7 +202,7 @@ static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx) appropraite flags */ src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); list_for_each_entry(dst_buf, &ctx->dst_queue, list) { - if (vb2_dma_contig_plane_paddr(dst_buf->b, 0) == dec_y_addr) { + if (vb2_dma_contig_plane_dma_addr(dst_buf->b, 0) == dec_y_addr) { memcpy(&dst_buf->b->v4l2_buf.timecode, &src_buf->b->v4l2_buf.timecode, sizeof(struct v4l2_timecode)); @@ -248,7 +248,7 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err) * check which videobuf does it correspond to */ list_for_each_entry(dst_buf, &ctx->dst_queue, list) { /* Check if this is the buffer we're looking for */ - if (vb2_dma_contig_plane_paddr(dst_buf->b, 0) == dspl_y_addr) { + if (vb2_dma_contig_plane_dma_addr(dst_buf->b, 0) == dspl_y_addr) { list_del(&dst_buf->list); ctx->dst_queue_cnt--; dst_buf->b->v4l2_buf.sequence = ctx->sequence; diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c index dbc94b8..4540dc2 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c @@ -824,7 +824,7 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb) return 0; for (i = 0; i <= ctx->src_fmt->num_planes ; i++) { if (IS_ERR_OR_NULL(ERR_PTR( - vb2_dma_contig_plane_paddr(vb, i)))) { + vb2_dma_contig_plane_dma_addr(vb, i)))) { mfc_err("Plane mem not allocated\n"); return -EINVAL; } @@ -837,13 +837,13 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb) i = vb->v4l2_buf.index; ctx->dst_bufs[i].b = vb; ctx->dst_bufs[i].cookie.raw.luma = - vb2_dma_contig_plane_paddr(vb, 0); + vb2_dma_contig_plane_dma_addr(vb, 0); ctx->dst_bufs[i].cookie.raw.chroma = - vb2_dma_contig_plane_paddr(vb, 1); + vb2_dma_contig_plane_dma_addr(vb, 1); ctx->dst_bufs_cnt++; } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { if (IS_ERR_OR_NULL(ERR_PTR( - vb2_dma_contig_plane_paddr(vb, 0)))) { + vb2_dma_contig_plane_dma_addr(vb, 0)))) { mfc_err("Plane memory not allocated\n"); return -EINVAL; } @@ -855,7 +855,7 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb) i = vb->v4l2_buf.index; ctx->src_bufs[i].b = vb; ctx->src_bufs[i].cookie.stream = - vb2_dma_contig_plane_paddr(vb, 0); + vb2_dma_contig_plane_dma_addr(vb, 0); ctx->src_bufs_cnt++; } else { mfc_err("s5p_mfc_buf_init: unknown queue type\n"); diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c index 019a9e7..e11b19a 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c @@ -599,8 +599,8 @@ static void cleanup_ref_queue(struct s5p_mfc_ctx *ctx) while (!list_empty(&ctx->ref_queue)) { mb_entry = list_entry((&ctx->ref_queue)->next, struct s5p_mfc_buf, list); - mb_y_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 0); - mb_c_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 1); + mb_y_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 0); + mb_c_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 1); list_del(&mb_entry->list); ctx->ref_queue_cnt--; list_add_tail(&mb_entry->list, &ctx->src_queue); @@ -622,7 +622,7 @@ static int enc_pre_seq_start(struct s5p_mfc_ctx *ctx) spin_lock_irqsave(&dev->irqlock, flags); dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); - dst_addr = vb2_dma_contig_plane_paddr(dst_mb->b, 0); + dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); dst_size = vb2_plane_size(dst_mb->b, 0); s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size); spin_unlock_irqrestore(&dev->irqlock, flags); @@ -668,14 +668,14 @@ static int enc_pre_frame_start(struct s5p_mfc_ctx *ctx) spin_lock_irqsave(&dev->irqlock, flags); src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); - src_y_addr = vb2_dma_contig_plane_paddr(src_mb->b, 0); - src_c_addr = vb2_dma_contig_plane_paddr(src_mb->b, 1); + src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 0); + src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 1); s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, src_c_addr); spin_unlock_irqrestore(&dev->irqlock, flags); spin_lock_irqsave(&dev->irqlock, flags); dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); - dst_addr = vb2_dma_contig_plane_paddr(dst_mb->b, 0); + dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); dst_size = vb2_plane_size(dst_mb->b, 0); s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size); spin_unlock_irqrestore(&dev->irqlock, flags); @@ -703,8 +703,8 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx) if (slice_type >= 0) { s5p_mfc_get_enc_frame_buffer(ctx, &enc_y_addr, &enc_c_addr); list_for_each_entry(mb_entry, &ctx->src_queue, list) { - mb_y_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 0); - mb_c_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 1); + mb_y_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 0); + mb_c_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 1); if ((enc_y_addr == mb_y_addr) && (enc_c_addr == mb_c_addr)) { list_del(&mb_entry->list); @@ -715,8 +715,8 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx) } } list_for_each_entry(mb_entry, &ctx->ref_queue, list) { - mb_y_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 0); - mb_c_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 1); + mb_y_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 0); + mb_c_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 1); if ((enc_y_addr == mb_y_addr) && (enc_c_addr == mb_c_addr)) { list_del(&mb_entry->list); @@ -1501,13 +1501,13 @@ static int check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb) return -EINVAL; } for (i = 0; i < fmt->num_planes; i++) { - if (!vb2_dma_contig_plane_paddr(vb, i)) { + if (!vb2_dma_contig_plane_dma_addr(vb, i)) { mfc_err("failed to get plane cookie\n"); return -EINVAL; } mfc_debug(2, "index: %d, plane[%d] cookie: 0x%08zx", vb->v4l2_buf.index, i, - vb2_dma_contig_plane_paddr(vb, i)); + vb2_dma_contig_plane_dma_addr(vb, i)); } return 0; } @@ -1584,7 +1584,7 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb) i = vb->v4l2_buf.index; ctx->dst_bufs[i].b = vb; ctx->dst_bufs[i].cookie.stream = - vb2_dma_contig_plane_paddr(vb, 0); + vb2_dma_contig_plane_dma_addr(vb, 0); ctx->dst_bufs_cnt++; } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { ret = check_vb_with_fmt(ctx->src_fmt, vb); @@ -1593,9 +1593,9 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb) i = vb->v4l2_buf.index; ctx->src_bufs[i].b = vb; ctx->src_bufs[i].cookie.raw.luma = - vb2_dma_contig_plane_paddr(vb, 0); + vb2_dma_contig_plane_dma_addr(vb, 0); ctx->src_bufs[i].cookie.raw.chroma = - vb2_dma_contig_plane_paddr(vb, 1); + vb2_dma_contig_plane_dma_addr(vb, 1); ctx->src_bufs_cnt++; } else { mfc_err("inavlid queue type: %d\n", vq->type); diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_opr.c b/drivers/media/video/s5p-mfc/s5p_mfc_opr.c index 7b23916..e08b21c 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc_opr.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc_opr.c @@ -1135,7 +1135,7 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame) temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); temp_vb->used = 1; s5p_mfc_set_dec_stream_buffer(ctx, - vb2_dma_contig_plane_paddr(temp_vb->b, 0), ctx->consumed_stream, + vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), ctx->consumed_stream, temp_vb->b->v4l2_planes[0].bytesused); spin_unlock_irqrestore(&dev->irqlock, flags); index = temp_vb->b->v4l2_buf.index; @@ -1172,12 +1172,12 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) } src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); src_mb->used = 1; - src_y_addr = vb2_dma_contig_plane_paddr(src_mb->b, 0); - src_c_addr = vb2_dma_contig_plane_paddr(src_mb->b, 1); + src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 0); + src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 1); s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, src_c_addr); dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); dst_mb->used = 1; - dst_addr = vb2_dma_contig_plane_paddr(dst_mb->b, 0); + dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); dst_size = vb2_plane_size(dst_mb->b, 0); s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size); spin_unlock_irqrestore(&dev->irqlock, flags); @@ -1200,7 +1200,7 @@ static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx) s5p_mfc_set_dec_desc_buffer(ctx); mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused); s5p_mfc_set_dec_stream_buffer(ctx, - vb2_dma_contig_plane_paddr(temp_vb->b, 0), + vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), 0, temp_vb->b->v4l2_planes[0].bytesused); spin_unlock_irqrestore(&dev->irqlock, flags); dev->curr_ctx = ctx->num; @@ -1219,7 +1219,7 @@ static void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx) s5p_mfc_set_enc_ref_buffer(ctx); spin_lock_irqsave(&dev->irqlock, flags); dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); - dst_addr = vb2_dma_contig_plane_paddr(dst_mb->b, 0); + dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); dst_size = vb2_plane_size(dst_mb->b, 0); s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size); spin_unlock_irqrestore(&dev->irqlock, flags); @@ -1255,7 +1255,7 @@ static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused); s5p_mfc_set_dec_stream_buffer(ctx, - vb2_dma_contig_plane_paddr(temp_vb->b, 0), + vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), 0, temp_vb->b->v4l2_planes[0].bytesused); spin_unlock_irqrestore(&dev->irqlock, flags); dev->curr_ctx = ctx->num; diff --git a/drivers/media/video/s5p-tv/mixer_grp_layer.c b/drivers/media/video/s5p-tv/mixer_grp_layer.c index 58f0ba4..de8270c 100644 --- a/drivers/media/video/s5p-tv/mixer_grp_layer.c +++ b/drivers/media/video/s5p-tv/mixer_grp_layer.c @@ -86,7 +86,7 @@ static void mxr_graph_buffer_set(struct mxr_layer *layer, dma_addr_t addr = 0; if (buf) - addr = vb2_dma_contig_plane_paddr(&buf->vb, 0); + addr = vb2_dma_contig_plane_dma_addr(&buf->vb, 0); mxr_reg_graph_buffer(layer->mdev, layer->idx, addr); } diff --git a/drivers/media/video/s5p-tv/mixer_vp_layer.c b/drivers/media/video/s5p-tv/mixer_vp_layer.c index 6950ed8..f3bb2e3 100644 --- a/drivers/media/video/s5p-tv/mixer_vp_layer.c +++ b/drivers/media/video/s5p-tv/mixer_vp_layer.c @@ -97,9 +97,9 @@ static void mxr_vp_buffer_set(struct mxr_layer *layer, mxr_reg_vp_buffer(layer->mdev, luma_addr, chroma_addr); return; } - luma_addr[0] = vb2_dma_contig_plane_paddr(&buf->vb, 0); + luma_addr[0] = vb2_dma_contig_plane_dma_addr(&buf->vb, 0); if (layer->fmt->num_subframes == 2) { - chroma_addr[0] = vb2_dma_contig_plane_paddr(&buf->vb, 1); + chroma_addr[0] = vb2_dma_contig_plane_dma_addr(&buf->vb, 1); } else { /* FIXME: mxr_get_plane_size compute integer division, * which is slow and should not be performed in interrupt */ diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 8298c89..8615fb8 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -312,7 +312,7 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) bottom2 = CDBCR; } - phys_addr_top = vb2_dma_contig_plane_paddr(pcdev->active, 0); + phys_addr_top = vb2_dma_contig_plane_dma_addr(pcdev->active, 0); ceu_write(pcdev, top1, phys_addr_top); if (V4L2_FIELD_NONE != pcdev->field) { diff --git a/drivers/media/video/videobuf2-dma-contig.c b/drivers/media/video/videobuf2-dma-contig.c index a790a5f..f17ad98 100644 --- a/drivers/media/video/videobuf2-dma-contig.c +++ b/drivers/media/video/videobuf2-dma-contig.c @@ -24,7 +24,7 @@ struct vb2_dc_conf { struct vb2_dc_buf { struct vb2_dc_conf *conf; void *vaddr; - dma_addr_t paddr; + dma_addr_t dma_addr; unsigned long size; struct vm_area_struct *vma; atomic_t refcount; @@ -42,7 +42,7 @@ static void *vb2_dma_contig_alloc(void *alloc_ctx, unsigned long size) if (!buf) return ERR_PTR(-ENOMEM); - buf->vaddr = dma_alloc_coherent(conf->dev, size, &buf->paddr, + buf->vaddr = dma_alloc_coherent(conf->dev, size, &buf->dma_addr, GFP_KERNEL); if (!buf->vaddr) { dev_err(conf->dev, "dma_alloc_coherent of size %ld failed\n", @@ -69,7 +69,7 @@ static void vb2_dma_contig_put(void *buf_priv) if (atomic_dec_and_test(&buf->refcount)) { dma_free_coherent(buf->conf->dev, buf->size, buf->vaddr, - buf->paddr); + buf->dma_addr); kfree(buf); } } @@ -78,7 +78,7 @@ static void *vb2_dma_contig_cookie(void *buf_priv) { struct vb2_dc_buf *buf = buf_priv; - return &buf->paddr; + return &buf->dma_addr; } static void *vb2_dma_contig_vaddr(void *buf_priv) @@ -106,7 +106,7 @@ static int vb2_dma_contig_mmap(void *buf_priv, struct vm_area_struct *vma) return -EINVAL; } - return vb2_mmap_pfn_range(vma, buf->paddr, buf->size, + return vb2_mmap_pfn_range(vma, buf->dma_addr, buf->size, &vb2_common_vm_ops, &buf->handler); } @@ -115,14 +115,14 @@ static void *vb2_dma_contig_get_userptr(void *alloc_ctx, unsigned long vaddr, { struct vb2_dc_buf *buf; struct vm_area_struct *vma; - dma_addr_t paddr = 0; + dma_addr_t dma_addr = 0; int ret; buf = kzalloc(sizeof *buf, GFP_KERNEL); if (!buf) return ERR_PTR(-ENOMEM); - ret = vb2_get_contig_userptr(vaddr, size, &vma, &paddr); + ret = vb2_get_contig_userptr(vaddr, size, &vma, &dma_addr); if (ret) { printk(KERN_ERR "Failed acquiring VMA for vaddr 0x%08lx\n", vaddr); @@ -131,7 +131,7 @@ static void *vb2_dma_contig_get_userptr(void *alloc_ctx, unsigned long vaddr, } buf->size = size; - buf->paddr = paddr; + buf->dma_addr = dma_addr; buf->vma = vma; return buf; diff --git a/include/media/videobuf2-dma-contig.h b/include/media/videobuf2-dma-contig.h index 7e6c68b..19ae1e3 100644 --- a/include/media/videobuf2-dma-contig.h +++ b/include/media/videobuf2-dma-contig.h @@ -17,11 +17,11 @@ #include static inline dma_addr_t -vb2_dma_contig_plane_paddr(struct vb2_buffer *vb, unsigned int plane_no) +vb2_dma_contig_plane_dma_addr(struct vb2_buffer *vb, unsigned int plane_no) { - dma_addr_t *paddr = vb2_plane_cookie(vb, plane_no); + dma_addr_t *addr = vb2_plane_cookie(vb, plane_no); - return *paddr; + return *addr; } void *vb2_dma_contig_init_ctx(struct device *dev); -- cgit v0.10.2 From 8607c42540d0aa61ab562506681d34c245b91fae Mon Sep 17 00:00:00 2001 From: Yu Tang Date: Tue, 30 Aug 2011 02:31:54 -0300 Subject: [media] media: vb2: fix userptr VMA release seq Align vb2 user pointer VMA release sequence with munmap. Do vm_ops->vm_close before release file. Signed-off-by: Yu Tang Signed-off-by: Marek Szyprowski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/videobuf2-memops.c b/drivers/media/video/videobuf2-memops.c index 569eeb3..71a7a78 100644 --- a/drivers/media/video/videobuf2-memops.c +++ b/drivers/media/video/videobuf2-memops.c @@ -68,12 +68,12 @@ void vb2_put_vma(struct vm_area_struct *vma) if (!vma) return; - if (vma->vm_file) - fput(vma->vm_file); - if (vma->vm_ops && vma->vm_ops->close) vma->vm_ops->close(vma); + if (vma->vm_file) + fput(vma->vm_file); + kfree(vma); } EXPORT_SYMBOL_GPL(vb2_put_vma); -- cgit v0.10.2 From bd323e28bd82dfd4b72c50ddc4d5fc24e3678b99 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 29 Aug 2011 08:51:49 -0300 Subject: [media] media: vb2: change queue initialization order This patch changes the order of operations during stream on call. Now the buffers are first queued to the driver and then the start_streaming method is called. This resolves the most common case when the driver needs to know buffer addresses to enable dma engine and start streaming. Additional parameter to start_streaming method have been added to simplify drivers code. The driver are now obliged to check if the number of queued buffers is high enough to enable hardware streaming. If not - it can return an error. In such case all the buffers that have been pre-queued are invalidated. This patch also updates all videobuf2 clients to work properly with the changed order of operations. Signed-off-by: Marek Szyprowski Signed-off-by: Kyungmin Park CC: Pawel Osciak CC: Guennadi Liakhovetski CC: Hans Verkuil CC: Tomasz Stanislawski CC: Sylwester Nawrocki CC: Kamil Debski CC: Jonathan Corbet CC: Josh Wu CC: Hans de Goede CC: Paul Mundt Tested-by: Josh Wu Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/video/atmel-isi.c index 7e1d789..774715d 100644 --- a/drivers/media/video/atmel-isi.c +++ b/drivers/media/video/atmel-isi.c @@ -404,12 +404,13 @@ static void buffer_queue(struct vb2_buffer *vb) if (isi->active == NULL) { isi->active = buf; - start_dma(isi, buf); + if (vb2_is_streaming(vb->vb2_queue)) + start_dma(isi, buf); } spin_unlock_irqrestore(&isi->lock, flags); } -static int start_streaming(struct vb2_queue *vq) +static int start_streaming(struct vb2_queue *vq, unsigned int count) { struct soc_camera_device *icd = soc_camera_from_vb2q(vq); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); @@ -431,17 +432,26 @@ static int start_streaming(struct vb2_queue *vq) ret = wait_event_interruptible(isi->vsync_wq, isi->state != ISI_STATE_IDLE); if (ret) - return ret; + goto err; - if (isi->state != ISI_STATE_READY) - return -EIO; + if (isi->state != ISI_STATE_READY) { + ret = -EIO; + goto err; + } spin_lock_irq(&isi->lock); isi->state = ISI_STATE_WAIT_SOF; isi_writel(isi, ISI_INTDIS, ISI_SR_VSYNC); + if (count) + start_dma(isi, isi->active); spin_unlock_irq(&isi->lock); return 0; +err: + isi->active = NULL; + isi->sequence = 0; + INIT_LIST_HEAD(&isi->video_buffer_list); + return ret; } /* abort streaming and wait for last buffer */ diff --git a/drivers/media/video/marvell-ccic/mcam-core.c b/drivers/media/video/marvell-ccic/mcam-core.c index 7abe503..1141b97 100644 --- a/drivers/media/video/marvell-ccic/mcam-core.c +++ b/drivers/media/video/marvell-ccic/mcam-core.c @@ -940,12 +940,14 @@ static void mcam_vb_wait_finish(struct vb2_queue *vq) /* * These need to be called with the mutex held from vb2 */ -static int mcam_vb_start_streaming(struct vb2_queue *vq) +static int mcam_vb_start_streaming(struct vb2_queue *vq, unsigned int count) { struct mcam_camera *cam = vb2_get_drv_priv(vq); - if (cam->state != S_IDLE) + if (cam->state != S_IDLE) { + INIT_LIST_HEAD(&cam->buffers); return -EINVAL; + } cam->sequence = 0; /* * Videobuf2 sneakily hoards all the buffers and won't diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index a7e4f56..360be22 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -816,7 +816,7 @@ static void buffer_queue(struct vb2_buffer *vb) spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags); } -static int start_streaming(struct vb2_queue *vq) +static int start_streaming(struct vb2_queue *vq, unsigned int count) { struct pwc_device *pdev = vb2_get_drv_priv(vq); diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index e6afe5f..287d099 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -151,27 +151,11 @@ static int fimc_isp_subdev_init(struct fimc_dev *fimc, unsigned int index) return ret; } -static int fimc_stop_capture(struct fimc_dev *fimc) +static void fimc_capture_state_cleanup(struct fimc_dev *fimc) { - unsigned long flags; - struct fimc_vid_cap *cap; + struct fimc_vid_cap *cap = &fimc->vid_cap; struct fimc_vid_buffer *buf; - - cap = &fimc->vid_cap; - - if (!fimc_capture_active(fimc)) - return 0; - - spin_lock_irqsave(&fimc->slock, flags); - set_bit(ST_CAPT_SHUT, &fimc->state); - fimc_deactivate_capture(fimc); - spin_unlock_irqrestore(&fimc->slock, flags); - - wait_event_timeout(fimc->irq_queue, - !test_bit(ST_CAPT_SHUT, &fimc->state), - FIMC_SHUTDOWN_TIMEOUT); - - v4l2_subdev_call(cap->sd, video, s_stream, 0); + unsigned long flags; spin_lock_irqsave(&fimc->slock, flags); fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_PEND | @@ -191,27 +175,50 @@ static int fimc_stop_capture(struct fimc_dev *fimc) } spin_unlock_irqrestore(&fimc->slock, flags); +} + +static int fimc_stop_capture(struct fimc_dev *fimc) +{ + struct fimc_vid_cap *cap = &fimc->vid_cap; + unsigned long flags; + + if (!fimc_capture_active(fimc)) + return 0; + + spin_lock_irqsave(&fimc->slock, flags); + set_bit(ST_CAPT_SHUT, &fimc->state); + fimc_deactivate_capture(fimc); + spin_unlock_irqrestore(&fimc->slock, flags); + + wait_event_timeout(fimc->irq_queue, + !test_bit(ST_CAPT_SHUT, &fimc->state), + FIMC_SHUTDOWN_TIMEOUT); + v4l2_subdev_call(cap->sd, video, s_stream, 0); + + fimc_capture_state_cleanup(fimc); dbg("state: 0x%lx", fimc->state); return 0; } -static int start_streaming(struct vb2_queue *q) + +static int start_streaming(struct vb2_queue *q, unsigned int count) { struct fimc_ctx *ctx = q->drv_priv; struct fimc_dev *fimc = ctx->fimc_dev; struct s5p_fimc_isp_info *isp_info; + int min_bufs; int ret; fimc_hw_reset(fimc); ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_stream, 1); if (ret && ret != -ENOIOCTLCMD) - return ret; + goto error; ret = fimc_prepare_config(ctx, ctx->state); if (ret) - return ret; + goto error; isp_info = &fimc->pdata->isp_info[fimc->vid_cap.input_index]; fimc_hw_set_camera_type(fimc, isp_info); @@ -222,7 +229,7 @@ static int start_streaming(struct vb2_queue *q) ret = fimc_set_scaler_info(ctx); if (ret) { err("Scaler setup error"); - return ret; + goto error; } fimc_hw_set_input_path(ctx); fimc_hw_set_prescaler(ctx); @@ -237,13 +244,20 @@ static int start_streaming(struct vb2_queue *q) INIT_LIST_HEAD(&fimc->vid_cap.pending_buf_q); INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q); - fimc->vid_cap.active_buf_cnt = 0; fimc->vid_cap.frame_count = 0; fimc->vid_cap.buf_index = 0; set_bit(ST_CAPT_PEND, &fimc->state); + min_bufs = fimc->vid_cap.reqbufs_count > 1 ? 2 : 1; + + if (fimc->vid_cap.active_buf_cnt >= min_bufs) + fimc_activate_capture(ctx); + return 0; +error: + fimc_capture_state_cleanup(fimc); + return ret; } static int stop_streaming(struct vb2_queue *q) @@ -341,7 +355,8 @@ static void buffer_queue(struct vb2_buffer *vb) min_bufs = vid_cap->reqbufs_count > 1 ? 2 : 1; - if (vid_cap->active_buf_cnt >= min_bufs && + if (vb2_is_streaming(&vid_cap->vbq) && + vid_cap->active_buf_cnt >= min_bufs && !test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) fimc_activate_capture(ctx); diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c index 4540dc2..32f8989 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c @@ -864,7 +864,7 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb) return 0; } -static int s5p_mfc_start_streaming(struct vb2_queue *q) +static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) { struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); struct s5p_mfc_dev *dev = ctx->dev; diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c index e11b19a..14ddbd2 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c @@ -1640,7 +1640,7 @@ static int s5p_mfc_buf_prepare(struct vb2_buffer *vb) return 0; } -static int s5p_mfc_start_streaming(struct vb2_queue *q) +static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) { struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); struct s5p_mfc_dev *dev = ctx->dev; diff --git a/drivers/media/video/s5p-tv/mixer.h b/drivers/media/video/s5p-tv/mixer.h index e224224..51ad59b3 100644 --- a/drivers/media/video/s5p-tv/mixer.h +++ b/drivers/media/video/s5p-tv/mixer.h @@ -111,8 +111,6 @@ struct mxr_buffer { enum mxr_layer_state { /** layers is not shown */ MXR_LAYER_IDLE = 0, - /** state between STREAMON and hardware start */ - MXR_LAYER_STREAMING_START, /** layer is shown */ MXR_LAYER_STREAMING, /** state before STREAMOFF is finished */ diff --git a/drivers/media/video/s5p-tv/mixer_video.c b/drivers/media/video/s5p-tv/mixer_video.c index 8bea0f3..4917e2c 100644 --- a/drivers/media/video/s5p-tv/mixer_video.c +++ b/drivers/media/video/s5p-tv/mixer_video.c @@ -764,19 +764,10 @@ static void buf_queue(struct vb2_buffer *vb) struct mxr_layer *layer = vb2_get_drv_priv(vb->vb2_queue); struct mxr_device *mdev = layer->mdev; unsigned long flags; - int must_start = 0; spin_lock_irqsave(&layer->enq_slock, flags); - if (layer->state == MXR_LAYER_STREAMING_START) { - layer->state = MXR_LAYER_STREAMING; - must_start = 1; - } list_add_tail(&buffer->list, &layer->enq_list); spin_unlock_irqrestore(&layer->enq_slock, flags); - if (must_start) { - layer->ops.stream_set(layer, MXR_ENABLE); - mxr_streamer_get(mdev); - } mxr_dbg(mdev, "queuing buffer\n"); } @@ -797,13 +788,19 @@ static void wait_unlock(struct vb2_queue *vq) mutex_unlock(&layer->mutex); } -static int start_streaming(struct vb2_queue *vq) +static int start_streaming(struct vb2_queue *vq, unsigned int count) { struct mxr_layer *layer = vb2_get_drv_priv(vq); struct mxr_device *mdev = layer->mdev; unsigned long flags; mxr_dbg(mdev, "%s\n", __func__); + + if (count == 0) { + mxr_dbg(mdev, "no output buffers queued\n"); + return -EINVAL; + } + /* block any changes in output configuration */ mxr_output_get(mdev); @@ -814,9 +811,12 @@ static int start_streaming(struct vb2_queue *vq) layer->ops.format_set(layer); /* enabling layer in hardware */ spin_lock_irqsave(&layer->enq_slock, flags); - layer->state = MXR_LAYER_STREAMING_START; + layer->state = MXR_LAYER_STREAMING; spin_unlock_irqrestore(&layer->enq_slock, flags); + layer->ops.stream_set(layer, MXR_ENABLE); + mxr_streamer_get(mdev); + return 0; } diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index e89fd53..6687ac3 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -1111,6 +1111,43 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking) EXPORT_SYMBOL_GPL(vb2_dqbuf); /** + * __vb2_queue_cancel() - cancel and stop (pause) streaming + * + * Removes all queued buffers from driver's queue and all buffers queued by + * userspace from videobuf's queue. Returns to state after reqbufs. + */ +static void __vb2_queue_cancel(struct vb2_queue *q) +{ + unsigned int i; + + /* + * Tell driver to stop all transactions and release all queued + * buffers. + */ + if (q->streaming) + call_qop(q, stop_streaming, q); + q->streaming = 0; + + /* + * Remove all buffers from videobuf's list... + */ + INIT_LIST_HEAD(&q->queued_list); + /* + * ...and done list; userspace will not receive any buffers it + * has not already dequeued before initiating cancel. + */ + INIT_LIST_HEAD(&q->done_list); + atomic_set(&q->queued_count, 0); + wake_up_all(&q->done_wq); + + /* + * Reinitialize all buffers for next use. + */ + for (i = 0; i < q->num_buffers; ++i) + q->bufs[i]->state = VB2_BUF_STATE_DEQUEUED; +} + +/** * vb2_streamon - start streaming * @q: videobuf2 queue * @type: type argument passed from userspace to vidioc_streamon handler @@ -1118,7 +1155,7 @@ EXPORT_SYMBOL_GPL(vb2_dqbuf); * Should be called from vidioc_streamon handler of a driver. * This function: * 1) verifies current state - * 2) starts streaming and passes any previously queued buffers to the driver + * 2) passes any previously queued buffers to the driver and starts streaming * * The return values from this function are intended to be directly returned * from vidioc_streamon handler in the driver. @@ -1144,75 +1181,29 @@ int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type) } /* - * Cannot start streaming on an OUTPUT device if no buffers have - * been queued yet. + * If any buffers were queued before streamon, + * we can now pass them to driver for processing. */ - if (V4L2_TYPE_IS_OUTPUT(q->type)) { - if (list_empty(&q->queued_list)) { - dprintk(1, "streamon: no output buffers queued\n"); - return -EINVAL; - } - } + list_for_each_entry(vb, &q->queued_list, queued_entry) + __enqueue_in_driver(vb); /* * Let driver notice that streaming state has been enabled. */ - ret = call_qop(q, start_streaming, q); + ret = call_qop(q, start_streaming, q, atomic_read(&q->queued_count)); if (ret) { dprintk(1, "streamon: driver refused to start streaming\n"); + __vb2_queue_cancel(q); return ret; } q->streaming = 1; - /* - * If any buffers were queued before streamon, - * we can now pass them to driver for processing. - */ - list_for_each_entry(vb, &q->queued_list, queued_entry) - __enqueue_in_driver(vb); - dprintk(3, "Streamon successful\n"); return 0; } EXPORT_SYMBOL_GPL(vb2_streamon); -/** - * __vb2_queue_cancel() - cancel and stop (pause) streaming - * - * Removes all queued buffers from driver's queue and all buffers queued by - * userspace from videobuf's queue. Returns to state after reqbufs. - */ -static void __vb2_queue_cancel(struct vb2_queue *q) -{ - unsigned int i; - - /* - * Tell driver to stop all transactions and release all queued - * buffers. - */ - if (q->streaming) - call_qop(q, stop_streaming, q); - q->streaming = 0; - - /* - * Remove all buffers from videobuf's list... - */ - INIT_LIST_HEAD(&q->queued_list); - /* - * ...and done list; userspace will not receive any buffers it - * has not already dequeued before initiating cancel. - */ - INIT_LIST_HEAD(&q->done_list); - atomic_set(&q->queued_count, 0); - wake_up_all(&q->done_wq); - - /* - * Reinitialize all buffers for next use. - */ - for (i = 0; i < q->num_buffers; ++i) - q->bufs[i]->state = VB2_BUF_STATE_DEQUEUED; -} /** * vb2_streamoff - stop streaming diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index cfe6832..21bb324 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -766,7 +766,7 @@ static void buffer_queue(struct vb2_buffer *vb) spin_unlock_irqrestore(&dev->slock, flags); } -static int start_streaming(struct vb2_queue *vq) +static int start_streaming(struct vb2_queue *vq, unsigned int count) { struct vivi_dev *dev = vb2_get_drv_priv(vq); dprintk(dev, 1, "%s\n", __func__); diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 5287e90..ea55c08 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -196,15 +196,24 @@ struct vb2_buffer { * before userspace accesses the buffer; optional * @buf_cleanup: called once before the buffer is freed; drivers may * perform any additional cleanup; optional - * @start_streaming: called once before entering 'streaming' state; enables - * driver to receive buffers over buf_queue() callback + * @start_streaming: called once to enter 'streaming' state; the driver may + * receive buffers with @buf_queue callback before + * @start_streaming is called; the driver gets the number + * of already queued buffers in count parameter; driver + * can return an error if hardware fails or not enough + * buffers has been queued, in such case all buffers that + * have been already given by the @buf_queue callback are + * invalidated. * @stop_streaming: called when 'streaming' state must be disabled; driver * should stop any DMA transactions or wait until they * finish and give back all buffers it got from buf_queue() * callback; may use vb2_wait_for_all_buffers() function * @buf_queue: passes buffer vb to the driver; driver may start * hardware operation on this buffer; driver should give - * the buffer back by calling vb2_buffer_done() function + * the buffer back by calling vb2_buffer_done() function; + * it is allways called after calling STREAMON ioctl; + * might be called before start_streaming callback if user + * pre-queued buffers before calling STREAMON */ struct vb2_ops { int (*queue_setup)(struct vb2_queue *q, unsigned int *num_buffers, @@ -219,7 +228,7 @@ struct vb2_ops { int (*buf_finish)(struct vb2_buffer *vb); void (*buf_cleanup)(struct vb2_buffer *vb); - int (*start_streaming)(struct vb2_queue *q); + int (*start_streaming)(struct vb2_queue *q, unsigned int count); int (*stop_streaming)(struct vb2_queue *q); void (*buf_queue)(struct vb2_buffer *vb); -- cgit v0.10.2 From e9e21083ef9361f89e19bb709eac441edc24ba02 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 2 Sep 2011 06:25:32 -0300 Subject: [media] s5p-fimc: Add runtime PM support in the mem-to-mem driver Add runtime PM and system sleep support in the memory-to-memory driver. It's required to enable the FIMC operation on Exynos4 SoCs. This patch prevents system boot failure when the driver is compiled in, as it now tries to access its I/O memory without first enabling the corresponding power domain. The camera capture device suspend/resume is not fully covered, the capture device is just powered on/off during the video node open/close. However this enables it's normal operation on Exynos4 SoCs. [mchehab@redhat.com: fix a small checkpatch error] Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index f574dc0..14326d7 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -950,7 +950,7 @@ config VIDEO_MX2 config VIDEO_SAMSUNG_S5P_FIMC tristate "Samsung S5P and EXYNOS4 camera host interface driver" - depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P + depends on VIDEO_V4L2 && PLAT_S5P && PM_RUNTIME select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV ---help--- diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 287d099..a2f7da9 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -271,6 +272,16 @@ static int stop_streaming(struct vb2_queue *q) return fimc_stop_capture(fimc); } +int fimc_capture_suspend(struct fimc_dev *fimc) +{ + return -EBUSY; +} + +int fimc_capture_resume(struct fimc_dev *fimc) +{ + return 0; +} + static unsigned int get_plane_size(struct fimc_frame *fr, unsigned int plane) { if (!fr || plane >= fr->fmt->memplanes) @@ -396,9 +407,14 @@ static int fimc_capture_open(struct file *file) if (fimc_m2m_active(fimc)) return -EBUSY; + ret = pm_runtime_get_sync(&fimc->pdev->dev); + if (ret) + return ret; + if (++fimc->vid_cap.refcnt == 1) { ret = fimc_isp_subdev_init(fimc, 0); if (ret) { + pm_runtime_put_sync(&fimc->pdev->dev); fimc->vid_cap.refcnt--; return -EIO; } @@ -426,6 +442,8 @@ static int fimc_capture_close(struct file *file) fimc_subdev_unregister(fimc); } + pm_runtime_put(&fimc->pdev->dev); + return 0; } diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 6e3f416..a9f321b 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -301,7 +302,6 @@ int fimc_set_scaler_info(struct fimc_ctx *ctx) static void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state) { struct vb2_buffer *src_vb, *dst_vb; - struct fimc_dev *fimc = ctx->fimc_dev; if (!ctx || !ctx->m2m_ctx) return; @@ -312,39 +312,48 @@ static void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state) if (src_vb && dst_vb) { v4l2_m2m_buf_done(src_vb, vb_state); v4l2_m2m_buf_done(dst_vb, vb_state); - v4l2_m2m_job_finish(fimc->m2m.m2m_dev, ctx->m2m_ctx); + v4l2_m2m_job_finish(ctx->fimc_dev->m2m.m2m_dev, + ctx->m2m_ctx); } } /* Complete the transaction which has been scheduled for execution. */ -static void fimc_m2m_shutdown(struct fimc_ctx *ctx) +static int fimc_m2m_shutdown(struct fimc_ctx *ctx) { struct fimc_dev *fimc = ctx->fimc_dev; int ret; if (!fimc_m2m_pending(fimc)) - return; + return 0; fimc_ctx_state_lock_set(FIMC_CTX_SHUT, ctx); ret = wait_event_timeout(fimc->irq_queue, !fimc_ctx_state_is_set(FIMC_CTX_SHUT, ctx), FIMC_SHUTDOWN_TIMEOUT); - /* - * In case of a timeout the buffers are not released in the interrupt - * handler so return them here with the error flag set, if there are - * any on the queue. - */ - if (ret == 0) - fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR); + + return ret == 0 ? -ETIMEDOUT : ret; +} + +static int start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct fimc_ctx *ctx = q->drv_priv; + int ret; + + ret = pm_runtime_get_sync(&ctx->fimc_dev->pdev->dev); + return ret > 0 ? 0 : ret; } static int stop_streaming(struct vb2_queue *q) { struct fimc_ctx *ctx = q->drv_priv; + int ret; - fimc_m2m_shutdown(ctx); + ret = fimc_m2m_shutdown(ctx); + if (ret == -ETIMEDOUT) + fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR); + pm_runtime_put(&ctx->fimc_dev->pdev->dev); return 0; } @@ -403,7 +412,7 @@ static void fimc_capture_irq_handler(struct fimc_dev *fimc) fimc_hw_get_frame_index(fimc), cap->active_buf_cnt); } -static irqreturn_t fimc_isr(int irq, void *priv) +static irqreturn_t fimc_irq_handler(int irq, void *priv) { struct fimc_dev *fimc = priv; struct fimc_vid_cap *cap = &fimc->vid_cap; @@ -411,9 +420,17 @@ static irqreturn_t fimc_isr(int irq, void *priv) fimc_hw_clear_irq(fimc); + spin_lock(&fimc->slock); + if (test_and_clear_bit(ST_M2M_PEND, &fimc->state)) { + if (test_and_clear_bit(ST_M2M_SUSPENDING, &fimc->state)) { + set_bit(ST_M2M_SUSPENDED, &fimc->state); + wake_up(&fimc->irq_queue); + goto out; + } ctx = v4l2_m2m_get_curr_priv(fimc->m2m.m2m_dev); if (ctx != NULL) { + spin_unlock(&fimc->slock); fimc_m2m_job_finish(ctx, VB2_BUF_STATE_DONE); spin_lock(&ctx->slock); @@ -423,21 +440,18 @@ static irqreturn_t fimc_isr(int irq, void *priv) } spin_unlock(&ctx->slock); } - return IRQ_HANDLED; - } - - spin_lock(&fimc->slock); - - if (test_bit(ST_CAPT_PEND, &fimc->state)) { - fimc_capture_irq_handler(fimc); + } else { + if (test_bit(ST_CAPT_PEND, &fimc->state)) { + fimc_capture_irq_handler(fimc); - if (cap->active_buf_cnt == 1) { - fimc_deactivate_capture(fimc); - clear_bit(ST_CAPT_STREAM, &fimc->state); + if (cap->active_buf_cnt == 1) { + fimc_deactivate_capture(fimc); + clear_bit(ST_CAPT_STREAM, &fimc->state); + } } } - +out: spin_unlock(&fimc->slock); return IRQ_HANDLED; } @@ -635,10 +649,10 @@ static void fimc_dma_run(void *priv) return; fimc = ctx->fimc_dev; - - spin_lock_irqsave(&ctx->slock, flags); + spin_lock_irqsave(&fimc->slock, flags); set_bit(ST_M2M_PEND, &fimc->state); + spin_lock(&ctx->slock); ctx->state |= (FIMC_SRC_ADDR | FIMC_DST_ADDR); ret = fimc_prepare_config(ctx, ctx->state); if (ret) @@ -649,8 +663,6 @@ static void fimc_dma_run(void *priv) ctx->state |= FIMC_PARAMS; fimc->m2m.ctx = ctx; } - - spin_lock(&fimc->slock); fimc_hw_set_input_addr(fimc, &ctx->s_frame.paddr); if (ctx->state & FIMC_PARAMS) { @@ -680,10 +692,9 @@ static void fimc_dma_run(void *priv) ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP | FIMC_SRC_FMT | FIMC_DST_FMT); fimc_hw_activate_input_dma(fimc, true); - spin_unlock(&fimc->slock); - dma_unlock: - spin_unlock_irqrestore(&ctx->slock, flags); + spin_unlock(&ctx->slock); + spin_unlock_irqrestore(&fimc->slock, flags); } static void fimc_job_abort(void *priv) @@ -762,6 +773,7 @@ static struct vb2_ops fimc_qops = { .wait_prepare = fimc_unlock, .wait_finish = fimc_lock, .stop_streaming = stop_streaming, + .start_streaming = start_streaming, }; static int fimc_m2m_querycap(struct file *file, void *priv, @@ -873,7 +885,6 @@ int fimc_vidioc_try_fmt_mplane(struct file *file, void *priv, u32 max_width, mod_x, mod_y, mask; int i, is_output = 0; - if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { if (fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx)) return -EINVAL; @@ -1408,9 +1419,6 @@ static int fimc_m2m_open(struct file *file) if (fimc->vid_cap.refcnt > 0) return -EBUSY; - fimc->m2m.refcnt++; - set_bit(ST_OUTDMA_RUN, &fimc->state); - ctx = kzalloc(sizeof *ctx, GFP_KERNEL); if (!ctx) return -ENOMEM; @@ -1434,6 +1442,9 @@ static int fimc_m2m_open(struct file *file) return err; } + if (fimc->m2m.refcnt++ == 0) + set_bit(ST_M2M_RUN, &fimc->state); + return 0; } @@ -1446,10 +1457,10 @@ static int fimc_m2m_release(struct file *file) task_pid_nr(current), fimc->state, fimc->m2m.refcnt); v4l2_m2m_ctx_release(ctx->m2m_ctx); - kfree(ctx); - if (--fimc->m2m.refcnt <= 0) - clear_bit(ST_OUTDMA_RUN, &fimc->state); + if (--fimc->m2m.refcnt <= 0) + clear_bit(ST_M2M_RUN, &fimc->state); + kfree(ctx); return 0; } @@ -1561,14 +1572,12 @@ static void fimc_unregister_m2m_device(struct fimc_dev *fimc) } } -static void fimc_clk_release(struct fimc_dev *fimc) +static void fimc_clk_put(struct fimc_dev *fimc) { int i; for (i = 0; i < fimc->num_clocks; i++) { - if (fimc->clock[i]) { - clk_disable(fimc->clock[i]); + if (fimc->clock[i]) clk_put(fimc->clock[i]); - } } } @@ -1577,15 +1586,50 @@ static int fimc_clk_get(struct fimc_dev *fimc) int i; for (i = 0; i < fimc->num_clocks; i++) { fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clocks[i]); - - if (!IS_ERR_OR_NULL(fimc->clock[i])) { - clk_enable(fimc->clock[i]); + if (!IS_ERR_OR_NULL(fimc->clock[i])) continue; - } dev_err(&fimc->pdev->dev, "failed to get fimc clock: %s\n", fimc_clocks[i]); return -ENXIO; } + + return 0; +} + +static int fimc_m2m_suspend(struct fimc_dev *fimc) +{ + unsigned long flags; + int timeout; + + spin_lock_irqsave(&fimc->slock, flags); + if (!fimc_m2m_pending(fimc)) { + spin_unlock_irqrestore(&fimc->slock, flags); + return 0; + } + clear_bit(ST_M2M_SUSPENDED, &fimc->state); + set_bit(ST_M2M_SUSPENDING, &fimc->state); + spin_unlock_irqrestore(&fimc->slock, flags); + + timeout = wait_event_timeout(fimc->irq_queue, + test_bit(ST_M2M_SUSPENDED, &fimc->state), + FIMC_SHUTDOWN_TIMEOUT); + + clear_bit(ST_M2M_SUSPENDING, &fimc->state); + return timeout == 0 ? -EAGAIN : 0; +} + +static int fimc_m2m_resume(struct fimc_dev *fimc) +{ + unsigned long flags; + + spin_lock_irqsave(&fimc->slock, flags); + /* Clear for full H/W setup in first run after resume */ + fimc->m2m.ctx = NULL; + spin_unlock_irqrestore(&fimc->slock, flags); + + if (test_and_clear_bit(ST_M2M_SUSPENDED, &fimc->state)) + fimc_m2m_job_finish(fimc->m2m.ctx, + VB2_BUF_STATE_ERROR); return 0; } @@ -1614,11 +1658,13 @@ static int fimc_probe(struct platform_device *pdev) return -ENOMEM; fimc->id = pdev->id; + fimc->variant = drv_data->variant[fimc->id]; fimc->pdev = pdev; pdata = pdev->dev.platform_data; fimc->pdata = pdata; - fimc->state = ST_IDLE; + + set_bit(ST_LPM, &fimc->state); init_waitqueue_head(&fimc->irq_queue); spin_lock_init(&fimc->slock); @@ -1655,63 +1701,66 @@ static int fimc_probe(struct platform_device *pdev) fimc->num_clocks++; } - ret = fimc_clk_get(fimc); - if (ret) - goto err_regs_unmap; - clk_set_rate(fimc->clock[CLK_BUS], drv_data->lclk_frequency); - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res) { dev_err(&pdev->dev, "failed to get IRQ resource\n"); ret = -ENXIO; - goto err_clk; + goto err_regs_unmap; } fimc->irq = res->start; - fimc_hw_reset(fimc); + ret = fimc_clk_get(fimc); + if (ret) + goto err_regs_unmap; + clk_set_rate(fimc->clock[CLK_BUS], drv_data->lclk_frequency); + clk_enable(fimc->clock[CLK_BUS]); + + platform_set_drvdata(pdev, fimc); - ret = request_irq(fimc->irq, fimc_isr, 0, pdev->name, fimc); + ret = request_irq(fimc->irq, fimc_irq_handler, 0, pdev->name, fimc); if (ret) { dev_err(&pdev->dev, "failed to install irq (%d)\n", ret); goto err_clk; } + pm_runtime_enable(&pdev->dev); + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) + goto err_irq; /* Initialize contiguous memory allocator */ - fimc->alloc_ctx = vb2_dma_contig_init_ctx(&fimc->pdev->dev); + fimc->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); if (IS_ERR(fimc->alloc_ctx)) { ret = PTR_ERR(fimc->alloc_ctx); - goto err_irq; + goto err_pm; } ret = fimc_register_m2m_device(fimc); if (ret) - goto err_irq; + goto err_alloc; /* At least one camera sensor is required to register capture node */ if (cap_input_index >= 0) { ret = fimc_register_capture_device(fimc); if (ret) goto err_m2m; - clk_disable(fimc->clock[CLK_CAM]); } - /* - * Exclude the additional output DMA address registers by masking - * them out on HW revisions that provide extended capabilites. - */ - if (fimc->variant->out_buf_count > 4) - fimc_hw_set_dma_seq(fimc, 0xF); dev_dbg(&pdev->dev, "%s(): fimc-%d registered successfully\n", __func__, fimc->id); + pm_runtime_put(&pdev->dev); return 0; err_m2m: fimc_unregister_m2m_device(fimc); +err_alloc: + vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx); +err_pm: + pm_runtime_put(&pdev->dev); err_irq: free_irq(fimc->irq, fimc); err_clk: - fimc_clk_release(fimc); + fimc_clk_put(fimc); err_regs_unmap: iounmap(fimc->regs); err_req_region: @@ -1723,27 +1772,105 @@ err_info: return ret; } -static int __devexit fimc_remove(struct platform_device *pdev) +static int fimc_runtime_resume(struct device *dev) { - struct fimc_dev *fimc = - (struct fimc_dev *)platform_get_drvdata(pdev); + struct fimc_dev *fimc = dev_get_drvdata(dev); - free_irq(fimc->irq, fimc); + dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state); + + /* Enable clocks and perform basic initalization */ + clk_enable(fimc->clock[CLK_GATE]); fimc_hw_reset(fimc); + if (fimc->variant->out_buf_count > 4) + fimc_hw_set_dma_seq(fimc, 0xF); + + /* Resume the capture or mem-to-mem device */ + if (fimc_capture_busy(fimc)) + return fimc_capture_resume(fimc); + else if (fimc_m2m_pending(fimc)) + return fimc_m2m_resume(fimc); + return 0; +} + +static int fimc_runtime_suspend(struct device *dev) +{ + struct fimc_dev *fimc = dev_get_drvdata(dev); + int ret = 0; + + if (fimc_capture_busy(fimc)) + ret = fimc_capture_suspend(fimc); + else + ret = fimc_m2m_suspend(fimc); + if (!ret) + clk_disable(fimc->clock[CLK_GATE]); + + dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state); + return ret; +} + +#ifdef CONFIG_PM_SLEEP +static int fimc_resume(struct device *dev) +{ + struct fimc_dev *fimc = dev_get_drvdata(dev); + unsigned long flags; + + dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state); + + /* Do not resume if the device was idle before system suspend */ + spin_lock_irqsave(&fimc->slock, flags); + if (!test_and_clear_bit(ST_LPM, &fimc->state) || + (!fimc_m2m_active(fimc) && !fimc_capture_busy(fimc))) { + spin_unlock_irqrestore(&fimc->slock, flags); + return 0; + } + fimc_hw_reset(fimc); + if (fimc->variant->out_buf_count > 4) + fimc_hw_set_dma_seq(fimc, 0xF); + spin_unlock_irqrestore(&fimc->slock, flags); + + if (fimc_capture_busy(fimc)) + return fimc_capture_resume(fimc); + + return fimc_m2m_resume(fimc); +} + +static int fimc_suspend(struct device *dev) +{ + struct fimc_dev *fimc = dev_get_drvdata(dev); + + dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state); + + if (test_and_set_bit(ST_LPM, &fimc->state)) + return 0; + if (fimc_capture_busy(fimc)) + return fimc_capture_suspend(fimc); + + return fimc_m2m_suspend(fimc); +} +#endif /* CONFIG_PM_SLEEP */ + +static int __devexit fimc_remove(struct platform_device *pdev) +{ + struct fimc_dev *fimc = platform_get_drvdata(pdev); + + pm_runtime_disable(&pdev->dev); + fimc_runtime_suspend(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); fimc_unregister_m2m_device(fimc); fimc_unregister_capture_device(fimc); - fimc_clk_release(fimc); - vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx); + clk_disable(fimc->clock[CLK_BUS]); + fimc_clk_put(fimc); + free_irq(fimc->irq, fimc); iounmap(fimc->regs); release_resource(fimc->regs_res); kfree(fimc->regs_res); kfree(fimc); - dev_info(&pdev->dev, "%s driver unloaded\n", pdev->name); + dev_info(&pdev->dev, "driver unloaded\n"); return 0; } @@ -1906,6 +2033,11 @@ static struct platform_device_id fimc_driver_ids[] = { }; MODULE_DEVICE_TABLE(platform, fimc_driver_ids); +static const struct dev_pm_ops fimc_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(fimc_suspend, fimc_resume) + SET_RUNTIME_PM_OPS(fimc_runtime_suspend, fimc_runtime_resume, NULL) +}; + static struct platform_driver fimc_driver = { .probe = fimc_probe, .remove = __devexit_p(fimc_remove), @@ -1913,6 +2045,7 @@ static struct platform_driver fimc_driver = { .driver = { .name = MODULE_NAME, .owner = THIS_MODULE, + .pm = &fimc_pm_ops, } }; diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 1f70772..e34cf3b 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -48,22 +48,26 @@ enum { }; enum fimc_dev_flags { - /* for m2m node */ - ST_IDLE, - ST_OUTDMA_RUN, + ST_LPM, + /* m2m node */ + ST_M2M_RUN, ST_M2M_PEND, - /* for capture node */ + ST_M2M_SUSPENDING, + ST_M2M_SUSPENDED, + /* capture node */ ST_CAPT_PEND, ST_CAPT_RUN, ST_CAPT_STREAM, ST_CAPT_SHUT, + ST_CAPT_BUSY, }; -#define fimc_m2m_active(dev) test_bit(ST_OUTDMA_RUN, &(dev)->state) +#define fimc_m2m_active(dev) test_bit(ST_M2M_RUN, &(dev)->state) #define fimc_m2m_pending(dev) test_bit(ST_M2M_PEND, &(dev)->state) #define fimc_capture_running(dev) test_bit(ST_CAPT_RUN, &(dev)->state) #define fimc_capture_pending(dev) test_bit(ST_CAPT_PEND, &(dev)->state) +#define fimc_capture_busy(dev) test_bit(ST_CAPT_BUSY, &(dev)->state) enum fimc_datapath { FIMC_CAMERA, @@ -644,6 +648,8 @@ void fimc_unregister_capture_device(struct fimc_dev *fimc); int fimc_sensor_sd_init(struct fimc_dev *fimc, int index); int fimc_vid_cap_buf_queue(struct fimc_dev *fimc, struct fimc_vid_buffer *fimc_vb); +int fimc_capture_suspend(struct fimc_dev *fimc); +int fimc_capture_resume(struct fimc_dev *fimc); /* Locking: the caller holds fimc->slock */ static inline void fimc_activate_capture(struct fimc_ctx *ctx) diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c index 4893b2d..938dadf 100644 --- a/drivers/media/video/s5p-fimc/fimc-reg.c +++ b/drivers/media/video/s5p-fimc/fimc-reg.c @@ -30,7 +30,7 @@ void fimc_hw_reset(struct fimc_dev *dev) cfg = readl(dev->regs + S5P_CIGCTRL); cfg |= (S5P_CIGCTRL_SWRST | S5P_CIGCTRL_IRQ_LEVEL); writel(cfg, dev->regs + S5P_CIGCTRL); - udelay(1000); + udelay(10); cfg = readl(dev->regs + S5P_CIGCTRL); cfg &= ~S5P_CIGCTRL_SWRST; -- cgit v0.10.2 From 438df3ebe5f0ce408490a777a758d5905f0dd58f Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 29 Jun 2011 13:08:49 -0300 Subject: [media] s5p-csis: Handle all available power supplies On the SoCs this driver is intended to support the are three separate pins to supply the MIPI-CSIS subsystem: 1.1V or 1.2V, 1.8V and power supply for an internal PLL. This patch adds support for two separate voltage supplies to cover properly board configurations where PMIC requires to configure independently each external supply of the MIPI-CSI device. The 1.8V and PLL supply are assigned a single "vdd18" regulator supply name as it seems more reasonable than creating separate regulator supplies for them. While at here stop using the 'fixed_phy_vdd' platform_data field. It has been introduced for boards where the MIPI-CSIS supplies are not controllable. However it is not needed as those boards can use the dummy regulator. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-fimc/mipi-csis.c b/drivers/media/video/s5p-fimc/mipi-csis.c index ef056d6..e34d4ba 100644 --- a/drivers/media/video/s5p-fimc/mipi-csis.c +++ b/drivers/media/video/s5p-fimc/mipi-csis.c @@ -81,6 +81,12 @@ static char *csi_clock_name[] = { }; #define NUM_CSIS_CLOCKS ARRAY_SIZE(csi_clock_name) +static const char * const csis_supply_name[] = { + "vdd11", /* 1.1V or 1.2V (s5pc100) MIPI CSI suppply */ + "vdd18", /* VDD 1.8V and MIPI CSI PLL supply */ +}; +#define CSIS_NUM_SUPPLIES ARRAY_SIZE(csis_supply_name) + enum { ST_POWERED = 1, ST_STREAMING = 2, @@ -109,9 +115,9 @@ struct csis_state { struct platform_device *pdev; struct resource *regs_res; void __iomem *regs; + struct regulator_bulk_data supplies[CSIS_NUM_SUPPLIES]; struct clk *clock[NUM_CSIS_CLOCKS]; int irq; - struct regulator *supply; u32 flags; const struct csis_pix_format *csis_fmt; struct v4l2_mbus_framefmt format; @@ -460,6 +466,7 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev) struct resource *regs_res; struct csis_state *state; int ret = -ENOMEM; + int i; state = kzalloc(sizeof(*state), GFP_KERNEL); if (!state) @@ -519,14 +526,13 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev) goto e_clkput; } - if (!pdata->fixed_phy_vdd) { - state->supply = regulator_get(&pdev->dev, "vdd"); - if (IS_ERR(state->supply)) { - ret = PTR_ERR(state->supply); - state->supply = NULL; - goto e_clkput; - } - } + for (i = 0; i < CSIS_NUM_SUPPLIES; i++) + state->supplies[i].supply = csis_supply_name[i]; + + ret = regulator_bulk_get(&pdev->dev, CSIS_NUM_SUPPLIES, + state->supplies); + if (ret) + goto e_clkput; ret = request_irq(state->irq, s5pcsis_irq_handler, 0, dev_name(&pdev->dev), state); @@ -561,8 +567,7 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev) e_irqfree: free_irq(state->irq, state); e_regput: - if (state->supply) - regulator_put(state->supply); + regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies); e_clkput: clk_disable(state->clock[CSIS_CLK_MUX]); s5pcsis_clk_put(state); @@ -592,11 +597,10 @@ static int s5pcsis_suspend(struct device *dev) ret = pdata->phy_enable(state->pdev, false); if (ret) goto unlock; - if (state->supply) { - ret = regulator_disable(state->supply); - if (ret) - goto unlock; - } + ret = regulator_bulk_disable(CSIS_NUM_SUPPLIES, + state->supplies); + if (ret) + goto unlock; clk_disable(state->clock[CSIS_CLK_GATE]); state->flags &= ~ST_POWERED; } @@ -622,16 +626,16 @@ static int s5pcsis_resume(struct device *dev) goto unlock; if (!(state->flags & ST_POWERED)) { - if (state->supply) - ret = regulator_enable(state->supply); + ret = regulator_bulk_enable(CSIS_NUM_SUPPLIES, + state->supplies); if (ret) goto unlock; - ret = pdata->phy_enable(state->pdev, true); if (!ret) { state->flags |= ST_POWERED; - } else if (state->supply) { - regulator_disable(state->supply); + } else { + regulator_bulk_disable(CSIS_NUM_SUPPLIES, + state->supplies); goto unlock; } clk_enable(state->clock[CSIS_CLK_GATE]); @@ -679,8 +683,7 @@ static int __devexit s5pcsis_remove(struct platform_device *pdev) pm_runtime_set_suspended(&pdev->dev); s5pcsis_clk_put(state); - if (state->supply) - regulator_put(state->supply); + regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies); media_entity_cleanup(&state->sd.entity); free_irq(state->irq, state); -- cgit v0.10.2 From d4d4e3c97211f20d4fde5d82878561adaa42b578 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 7 Jul 2011 12:13:25 -0300 Subject: [media] s5p-csis: Rework the system suspend/resume helpers Do not resume the device during system resume if it was idle before system suspend, as this causes resume from suspend to RAM failures on Exynos4. For this purpose runtime PM and system sleep helpers are separated. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-fimc/mipi-csis.c b/drivers/media/video/s5p-fimc/mipi-csis.c index e34d4ba..59d79bc 100644 --- a/drivers/media/video/s5p-fimc/mipi-csis.c +++ b/drivers/media/video/s5p-fimc/mipi-csis.c @@ -559,7 +559,6 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev) /* .. and a pointer to the subdev. */ platform_set_drvdata(pdev, &state->sd); - state->flags = ST_SUSPENDED; pm_runtime_enable(&pdev->dev); return 0; @@ -580,7 +579,7 @@ e_free: return ret; } -static int s5pcsis_suspend(struct device *dev) +static int s5pcsis_pm_suspend(struct device *dev, bool runtime) { struct s5p_platform_mipi_csis *pdata = dev->platform_data; struct platform_device *pdev = to_platform_device(dev); @@ -603,14 +602,15 @@ static int s5pcsis_suspend(struct device *dev) goto unlock; clk_disable(state->clock[CSIS_CLK_GATE]); state->flags &= ~ST_POWERED; + if (!runtime) + state->flags |= ST_SUSPENDED; } - state->flags |= ST_SUSPENDED; unlock: mutex_unlock(&state->lock); return ret ? -EAGAIN : 0; } -static int s5pcsis_resume(struct device *dev) +static int s5pcsis_pm_resume(struct device *dev, bool runtime) { struct s5p_platform_mipi_csis *pdata = dev->platform_data; struct platform_device *pdev = to_platform_device(dev); @@ -622,7 +622,7 @@ static int s5pcsis_resume(struct device *dev) __func__, state->flags); mutex_lock(&state->lock); - if (!(state->flags & ST_SUSPENDED)) + if (!runtime && !(state->flags & ST_SUSPENDED)) goto unlock; if (!(state->flags & ST_POWERED)) { @@ -650,24 +650,26 @@ static int s5pcsis_resume(struct device *dev) } #ifdef CONFIG_PM_SLEEP -static int s5pcsis_pm_suspend(struct device *dev) +static int s5pcsis_suspend(struct device *dev) { - return s5pcsis_suspend(dev); + return s5pcsis_pm_suspend(dev, false); } -static int s5pcsis_pm_resume(struct device *dev) +static int s5pcsis_resume(struct device *dev) { - int ret; - - ret = s5pcsis_resume(dev); + return s5pcsis_pm_resume(dev, false); +} +#endif - if (!ret) { - pm_runtime_disable(dev); - ret = pm_runtime_set_active(dev); - pm_runtime_enable(dev); - } +#ifdef CONFIG_PM_RUNTIME +static int s5pcsis_runtime_suspend(struct device *dev) +{ + return s5pcsis_pm_suspend(dev, true); +} - return ret; +static int s5pcsis_runtime_resume(struct device *dev) +{ + return s5pcsis_pm_resume(dev, true); } #endif @@ -695,8 +697,9 @@ static int __devexit s5pcsis_remove(struct platform_device *pdev) } static const struct dev_pm_ops s5pcsis_pm_ops = { - SET_RUNTIME_PM_OPS(s5pcsis_suspend, s5pcsis_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(s5pcsis_pm_suspend, s5pcsis_pm_resume) + SET_RUNTIME_PM_OPS(s5pcsis_runtime_suspend, s5pcsis_runtime_resume, + NULL) + SET_SYSTEM_SLEEP_PM_OPS(s5pcsis_suspend, s5pcsis_resume) }; static struct platform_driver s5pcsis_driver = { -- cgit v0.10.2 From 574e171788ce84366e77dea5ba3db2a3a9912d34 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 26 Jul 2011 18:08:21 -0300 Subject: [media] s5p-fimc: Add media entity initialization Add intialization of the media entities for video capture and mem-to-mem video nodes. The mem-to-mem entity has no pads whereas the capture entity has single sink pad. Also clean up the video node naming for consistency. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index a2f7da9..19d398b 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -853,9 +853,8 @@ int fimc_register_capture_device(struct fimc_dev *fimc) fr->width = fr->f_width = fr->o_width = 640; fr->height = fr->f_height = fr->o_height = 480; - if (!v4l2_dev->name[0]) - snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), - "%s.capture", dev_name(&fimc->pdev->dev)); + snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), + "%s.capture", dev_name(&fimc->pdev->dev)); ret = v4l2_device_register(NULL, v4l2_dev); if (ret) @@ -867,11 +866,11 @@ int fimc_register_capture_device(struct fimc_dev *fimc) goto err_v4l2_reg; } - snprintf(vfd->name, sizeof(vfd->name), "%s:cap", - dev_name(&fimc->pdev->dev)); + strlcpy(vfd->name, v4l2_dev->name, sizeof(vfd->name)); vfd->fops = &fimc_capture_fops; vfd->ioctl_ops = &fimc_capture_ioctl_ops; + vfd->v4l2_dev = v4l2_dev; vfd->minor = -1; vfd->release = video_device_release; vfd->lock = &fimc->lock; @@ -901,6 +900,11 @@ int fimc_register_capture_device(struct fimc_dev *fimc) vb2_queue_init(q); + fimc->vid_cap.vd_pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_init(&vfd->entity, 1, &fimc->vid_cap.vd_pad, 0); + if (ret) + goto err_ent; + ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); if (ret) { v4l2_err(v4l2_dev, "Failed to register video device\n"); @@ -910,10 +914,11 @@ int fimc_register_capture_device(struct fimc_dev *fimc) v4l2_info(v4l2_dev, "FIMC capture driver registered as /dev/video%d\n", vfd->num); - return 0; err_vd_reg: + media_entity_cleanup(&vfd->entity); +err_ent: video_device_release(vfd); err_v4l2_reg: v4l2_device_unregister(v4l2_dev); @@ -925,10 +930,11 @@ err_info: void fimc_unregister_capture_device(struct fimc_dev *fimc) { - struct fimc_vid_cap *capture = &fimc->vid_cap; + struct video_device *vfd = fimc->vid_cap.vfd; - if (capture->vfd) - video_unregister_device(capture->vfd); - - kfree(capture->ctx); + if (vfd) { + media_entity_cleanup(&vfd->entity); + video_unregister_device(vfd); + } + kfree(fimc->vid_cap.ctx); } diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index a9f321b..1ae2206 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -1507,10 +1507,8 @@ static int fimc_register_m2m_device(struct fimc_dev *fimc) pdev = fimc->pdev; v4l2_dev = &fimc->m2m.v4l2_dev; - /* set name if it is empty */ - if (!v4l2_dev->name[0]) - snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), - "%s.m2m", dev_name(&pdev->dev)); + snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), + "%s.m2m", dev_name(&pdev->dev)); ret = v4l2_device_register(&pdev->dev, v4l2_dev); if (ret) @@ -1524,6 +1522,7 @@ static int fimc_register_m2m_device(struct fimc_dev *fimc) vfd->fops = &fimc_m2m_fops; vfd->ioctl_ops = &fimc_m2m_ioctl_ops; + vfd->v4l2_dev = v4l2_dev; vfd->minor = -1; vfd->release = video_device_release; vfd->lock = &fimc->lock; @@ -1541,17 +1540,22 @@ static int fimc_register_m2m_device(struct fimc_dev *fimc) goto err_m2m_r2; } + ret = media_entity_init(&vfd->entity, 0, NULL, 0); + if (ret) + goto err_m2m_r3; + ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); if (ret) { v4l2_err(v4l2_dev, "%s(): failed to register video device\n", __func__); - goto err_m2m_r3; + goto err_m2m_r4; } v4l2_info(v4l2_dev, "FIMC m2m driver registered as /dev/video%d\n", vfd->num); return 0; - +err_m2m_r4: + media_entity_cleanup(&vfd->entity); err_m2m_r3: v4l2_m2m_release(fimc->m2m.m2m_dev); err_m2m_r2: @@ -1564,12 +1568,13 @@ err_m2m_r1: static void fimc_unregister_m2m_device(struct fimc_dev *fimc) { - if (fimc) { - v4l2_m2m_release(fimc->m2m.m2m_dev); - video_unregister_device(fimc->m2m.vfd); + if (fimc == NULL) + return; - v4l2_device_unregister(&fimc->m2m.v4l2_dev); - } + v4l2_m2m_release(fimc->m2m.m2m_dev); + v4l2_device_unregister(&fimc->m2m.v4l2_dev); + media_entity_cleanup(&fimc->m2m.vfd->entity); + video_unregister_device(fimc->m2m.vfd); } static void fimc_clk_put(struct fimc_dev *fimc) diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index e34cf3b..fc99824f 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -16,6 +16,8 @@ #include #include #include + +#include #include #include #include @@ -298,6 +300,7 @@ struct fimc_m2m_device { * @vfd: video device node for camera capture mode * @v4l2_dev: v4l2_device struct to manage subdevs * @sd: pointer to camera sensor subdevice currently in use + * @vd_pad: fimc video capture node pad * @fmt: Media Bus format configured at selected image sensor * @pending_buf_q: the pending buffer queue head * @active_buf_q: the queue head of buffers scheduled in hardware @@ -315,6 +318,7 @@ struct fimc_vid_cap { struct video_device *vfd; struct v4l2_device v4l2_dev; struct v4l2_subdev *sd;; + struct media_pad vd_pad; struct v4l2_mbus_framefmt fmt; struct list_head pending_buf_q; struct list_head active_buf_q; -- cgit v0.10.2 From 96a857421a9d212696364d210bd85a2162e73966 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 26 Aug 2011 15:40:36 -0300 Subject: [media] s5p-fimc: Remove registration of video nodes from probe() Do not register video nodes during FIMC device probe. Also make fimc_register_m2m_device() public for use by the media device driver. The video nodes are to be registered during the media device driver initialization, altogether with the subdev devnodes. The video capture nodes need to be registered as last ones when the remaining pipeline elements are already initialized. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 19d398b..6efd952 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -905,19 +905,8 @@ int fimc_register_capture_device(struct fimc_dev *fimc) if (ret) goto err_ent; - ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); - if (ret) { - v4l2_err(v4l2_dev, "Failed to register video device\n"); - goto err_vd_reg; - } - - v4l2_info(v4l2_dev, - "FIMC capture driver registered as /dev/video%d\n", - vfd->num); return 0; -err_vd_reg: - media_entity_cleanup(&vfd->entity); err_ent: video_device_release(vfd); err_v4l2_reg: @@ -934,7 +923,10 @@ void fimc_unregister_capture_device(struct fimc_dev *fimc) if (vfd) { media_entity_cleanup(&vfd->entity); + /* Can also be called if video device was + not registered */ video_unregister_device(vfd); } kfree(fimc->vid_cap.ctx); + fimc->vid_cap.ctx = NULL; } diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 1ae2206..93c4e1a 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -1494,7 +1494,7 @@ static struct v4l2_m2m_ops m2m_ops = { .job_abort = fimc_job_abort, }; -static int fimc_register_m2m_device(struct fimc_dev *fimc) +int fimc_register_m2m_device(struct fimc_dev *fimc) { struct video_device *vfd; struct platform_device *pdev; @@ -1541,22 +1541,9 @@ static int fimc_register_m2m_device(struct fimc_dev *fimc) } ret = media_entity_init(&vfd->entity, 0, NULL, 0); - if (ret) - goto err_m2m_r3; - - ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); - if (ret) { - v4l2_err(v4l2_dev, - "%s(): failed to register video device\n", __func__); - goto err_m2m_r4; - } - v4l2_info(v4l2_dev, - "FIMC m2m driver registered as /dev/video%d\n", vfd->num); + if (!ret) + return 0; - return 0; -err_m2m_r4: - media_entity_cleanup(&vfd->entity); -err_m2m_r3: v4l2_m2m_release(fimc->m2m.m2m_dev); err_m2m_r2: video_device_release(fimc->m2m.vfd); @@ -1566,15 +1553,19 @@ err_m2m_r1: return ret; } -static void fimc_unregister_m2m_device(struct fimc_dev *fimc) +void fimc_unregister_m2m_device(struct fimc_dev *fimc) { - if (fimc == NULL) + if (!fimc) return; - v4l2_m2m_release(fimc->m2m.m2m_dev); + if (fimc->m2m.m2m_dev) + v4l2_m2m_release(fimc->m2m.m2m_dev); v4l2_device_unregister(&fimc->m2m.v4l2_dev); - media_entity_cleanup(&fimc->m2m.vfd->entity); - video_unregister_device(fimc->m2m.vfd); + if (fimc->m2m.vfd) { + media_entity_cleanup(&fimc->m2m.vfd->entity); + /* Can also be called if video device wasn't registered */ + video_unregister_device(fimc->m2m.vfd); + } } static void fimc_clk_put(struct fimc_dev *fimc) @@ -1739,27 +1730,11 @@ static int fimc_probe(struct platform_device *pdev) goto err_pm; } - ret = fimc_register_m2m_device(fimc); - if (ret) - goto err_alloc; - - /* At least one camera sensor is required to register capture node */ - if (cap_input_index >= 0) { - ret = fimc_register_capture_device(fimc); - if (ret) - goto err_m2m; - } - - dev_dbg(&pdev->dev, "%s(): fimc-%d registered successfully\n", - __func__, fimc->id); + dev_dbg(&pdev->dev, "FIMC.%d registered successfully\n", fimc->id); pm_runtime_put(&pdev->dev); return 0; -err_m2m: - fimc_unregister_m2m_device(fimc); -err_alloc: - vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx); err_pm: pm_runtime_put(&pdev->dev); err_irq: @@ -1773,7 +1748,6 @@ err_req_region: kfree(fimc->regs_res); err_info: kfree(fimc); - return ret; } @@ -1862,9 +1836,6 @@ static int __devexit fimc_remove(struct platform_device *pdev) fimc_runtime_suspend(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); - fimc_unregister_m2m_device(fimc); - fimc_unregister_capture_device(fimc); - vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx); clk_disable(fimc->clock[CLK_BUS]); diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index fc99824f..c8a2bab 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -644,6 +644,7 @@ int fimc_set_scaler_info(struct fimc_ctx *ctx); int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags); int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, struct fimc_frame *frame, struct fimc_addr *paddr); +int fimc_register_m2m_device(struct fimc_dev *fimc); /* -----------------------------------------------------*/ /* fimc-capture.c */ -- cgit v0.10.2 From ebdfea810ec21744840f647341a1e74b8c762586 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 10 Jun 2011 15:36:45 -0300 Subject: [media] s5p-fimc: Remove sclk_cam clock handling There are 2 separate clock outputs available in the SoC for external sensors. These two clocks can be shared among all FIMC entities and there is currently no any arbitration of the clocks in the driver. So make the capture driver not touching these clocks and let them be be properly handled at the media device driver level, enabling proper arbitration between FIMC entities. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 93c4e1a..9809764 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -30,7 +30,7 @@ #include "fimc-core.h" static char *fimc_clocks[MAX_FIMC_CLOCKS] = { - "sclk_fimc", "fimc", "sclk_cam" + "sclk_fimc", "fimc" }; static struct fimc_fmt fimc_formats[] = { @@ -1636,7 +1636,6 @@ static int fimc_probe(struct platform_device *pdev) struct samsung_fimc_driverdata *drv_data; struct s5p_platform_fimc *pdata; int ret = 0; - int cap_input_index = -1; dev_dbg(&pdev->dev, "%s():\n", __func__); @@ -1689,14 +1688,6 @@ static int fimc_probe(struct platform_device *pdev) goto err_req_region; } - fimc->num_clocks = MAX_FIMC_CLOCKS - 1; - - /* Check if a video capture node needs to be registered. */ - if (pdata && pdata->num_clients > 0) { - cap_input_index = 0; - fimc->num_clocks++; - } - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res) { dev_err(&pdev->dev, "failed to get IRQ resource\n"); @@ -1705,6 +1696,7 @@ static int fimc_probe(struct platform_device *pdev) } fimc->irq = res->start; + fimc->num_clocks = MAX_FIMC_CLOCKS; ret = fimc_clk_get(fimc); if (ret) goto err_regs_unmap; diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index c8a2bab..d82bff8 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -34,7 +34,7 @@ /* Time to wait for next frame VSYNC interrupt while stopping operation. */ #define FIMC_SHUTDOWN_TIMEOUT ((100*HZ)/1000) -#define MAX_FIMC_CLOCKS 3 +#define MAX_FIMC_CLOCKS 2 #define MODULE_NAME "s5p-fimc" #define FIMC_MAX_DEVS 4 #define FIMC_MAX_OUT_BUFS 4 @@ -46,7 +46,6 @@ enum { CLK_BUS, CLK_GATE, - CLK_CAM, }; enum fimc_dev_flags { -- cgit v0.10.2 From 3e00218207a22e10c205e15a47b8d71c822fedec Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 26 Jul 2011 18:27:59 -0300 Subject: [media] s5p-fimc: Limit number of available inputs to one The current driver allowed camera sensors to be used only with single FIMC H/W instance, FIMC0..FIMC2/3, designated at compile time. Remaining FIMC entities could be used for video processing only, as mem-to-mem devices. Required camera could be selected with S_INPUT ioctl at one devnode only. However in that case it was not possible to use both cameras independently at the same time, as all sensors were registered to single FIMC capture driver. In most recent S5P SoC version there is enough FIMC H/W instances to cover all physical camera interfaces. Each FIMC instance exports its own video devnode. Thus we distribute the camera sensors one per each /dev/video? by default. It will allow to use both camera simultaneously by opening different video node. The camera sensors at FIMC are now not selected with S_INPUT ioctl, there is one input only available per /dev/video?. By default a single sensor is connected at FIMC input as specified by the media device platform data subdev description table. This assignment can be changed at runtime through the pipeline reconfiguration at the media device level. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 6efd952..b786c2c 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -577,57 +577,26 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, } static int fimc_cap_enum_input(struct file *file, void *priv, - struct v4l2_input *i) + struct v4l2_input *i) { struct fimc_ctx *ctx = priv; - struct s5p_platform_fimc *pldata = ctx->fimc_dev->pdata; - struct s5p_fimc_isp_info *isp_info; - if (i->index >= pldata->num_clients) + if (i->index != 0) return -EINVAL; - isp_info = &pldata->isp_info[i->index]; i->type = V4L2_INPUT_TYPE_CAMERA; - strncpy(i->name, isp_info->board_info->type, 32); return 0; } -static int fimc_cap_s_input(struct file *file, void *priv, - unsigned int i) +static int fimc_cap_s_input(struct file *file, void *priv, unsigned int i) { - struct fimc_ctx *ctx = priv; - struct fimc_dev *fimc = ctx->fimc_dev; - struct s5p_platform_fimc *pdata = fimc->pdata; - - if (fimc_capture_active(ctx->fimc_dev)) - return -EBUSY; - - if (i >= pdata->num_clients) - return -EINVAL; - - - if (fimc->vid_cap.sd) { - int ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0); - if (ret) - err("s_power failed: %d", ret); - - clk_disable(fimc->clock[CLK_CAM]); - } - - /* Release the attached sensor subdevice. */ - fimc_subdev_unregister(fimc); - - return fimc_isp_subdev_init(fimc, i); + return i == 0 ? i : -EINVAL; } -static int fimc_cap_g_input(struct file *file, void *priv, - unsigned int *i) +static int fimc_cap_g_input(struct file *file, void *priv, unsigned int *i) { - struct fimc_ctx *ctx = priv; - struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap; - - *i = cap->input_index; + *i = 0; return 0; } -- cgit v0.10.2 From 2319c539e39b9e74f0477887bb8ff45816cb38d9 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 26 Jul 2011 18:29:50 -0300 Subject: [media] s5p-fimc: Remove sensor management code from FIMC capture driver The sensor subdevs need to be shared between all available FIMC instances. Remove their registration from FIMC capture driver so they can then be registered to the media device driver. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index b786c2c..40f3330 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -16,12 +16,9 @@ #include #include #include -#include #include #include #include -#include -#include #include #include @@ -32,126 +29,6 @@ #include "fimc-core.h" -static struct v4l2_subdev *fimc_subdev_register(struct fimc_dev *fimc, - struct s5p_fimc_isp_info *isp_info) -{ - struct i2c_adapter *i2c_adap; - struct fimc_vid_cap *vid_cap = &fimc->vid_cap; - struct v4l2_subdev *sd = NULL; - - i2c_adap = i2c_get_adapter(isp_info->i2c_bus_num); - if (!i2c_adap) - return ERR_PTR(-ENOMEM); - - sd = v4l2_i2c_new_subdev_board(&vid_cap->v4l2_dev, i2c_adap, - isp_info->board_info, NULL); - if (!sd) { - v4l2_err(&vid_cap->v4l2_dev, "failed to acquire subdev\n"); - return NULL; - } - - v4l2_info(&vid_cap->v4l2_dev, "subdevice %s registered successfuly\n", - isp_info->board_info->type); - - return sd; -} - -static void fimc_subdev_unregister(struct fimc_dev *fimc) -{ - struct fimc_vid_cap *vid_cap = &fimc->vid_cap; - struct i2c_client *client; - - if (vid_cap->input_index < 0) - return; /* Subdevice already released or not registered. */ - - if (vid_cap->sd) { - v4l2_device_unregister_subdev(vid_cap->sd); - client = v4l2_get_subdevdata(vid_cap->sd); - i2c_unregister_device(client); - i2c_put_adapter(client->adapter); - vid_cap->sd = NULL; - } - - vid_cap->input_index = -1; -} - -/** - * fimc_subdev_attach - attach v4l2_subdev to camera host interface - * - * @fimc: FIMC device information - * @index: index to the array of available subdevices, - * -1 for full array search or non negative value - * to select specific subdevice - */ -static int fimc_subdev_attach(struct fimc_dev *fimc, int index) -{ - struct fimc_vid_cap *vid_cap = &fimc->vid_cap; - struct s5p_platform_fimc *pdata = fimc->pdata; - struct s5p_fimc_isp_info *isp_info; - struct v4l2_subdev *sd; - int i; - - for (i = 0; i < pdata->num_clients; ++i) { - isp_info = &pdata->isp_info[i]; - - if (index >= 0 && i != index) - continue; - - sd = fimc_subdev_register(fimc, isp_info); - if (!IS_ERR_OR_NULL(sd)) { - vid_cap->sd = sd; - vid_cap->input_index = i; - - return 0; - } - } - - vid_cap->input_index = -1; - vid_cap->sd = NULL; - v4l2_err(&vid_cap->v4l2_dev, "fimc%d: sensor attach failed\n", - fimc->id); - return -ENODEV; -} - -static int fimc_isp_subdev_init(struct fimc_dev *fimc, unsigned int index) -{ - struct s5p_fimc_isp_info *isp_info; - struct s5p_platform_fimc *pdata = fimc->pdata; - int ret; - - if (index >= pdata->num_clients) - return -EINVAL; - - isp_info = &pdata->isp_info[index]; - - if (isp_info->clk_frequency) - clk_set_rate(fimc->clock[CLK_CAM], isp_info->clk_frequency); - - ret = clk_enable(fimc->clock[CLK_CAM]); - if (ret) - return ret; - - ret = fimc_subdev_attach(fimc, index); - if (ret) - return ret; - - ret = fimc_hw_set_camera_polarity(fimc, isp_info); - if (ret) - return ret; - - ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 1); - if (!ret) - return ret; - - /* enabling power failed so unregister subdev */ - fimc_subdev_unregister(fimc); - - v4l2_err(&fimc->vid_cap.v4l2_dev, "ISP initialization failed: %d\n", - ret); - - return ret; -} - static void fimc_capture_state_cleanup(struct fimc_dev *fimc) { struct fimc_vid_cap *cap = &fimc->vid_cap; @@ -411,15 +288,7 @@ static int fimc_capture_open(struct file *file) if (ret) return ret; - if (++fimc->vid_cap.refcnt == 1) { - ret = fimc_isp_subdev_init(fimc, 0); - if (ret) { - pm_runtime_put_sync(&fimc->pdev->dev); - fimc->vid_cap.refcnt--; - return -EIO; - } - } - + ++fimc->vid_cap.refcnt; file->private_data = fimc->vid_cap.ctx; return 0; @@ -434,12 +303,6 @@ static int fimc_capture_close(struct file *file) if (--fimc->vid_cap.refcnt == 0) { fimc_stop_capture(fimc); vb2_queue_release(&fimc->vid_cap.vbq); - - v4l2_err(&fimc->vid_cap.v4l2_dev, "releasing ISP\n"); - - v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0); - clk_disable(fimc->clock[CLK_CAM]); - fimc_subdev_unregister(fimc); } pm_runtime_put(&fimc->pdev->dev); diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index d82bff8..a0d6f81 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -11,6 +11,7 @@ /*#define DEBUG*/ +#include #include #include #include @@ -649,7 +650,6 @@ int fimc_register_m2m_device(struct fimc_dev *fimc); /* fimc-capture.c */ int fimc_register_capture_device(struct fimc_dev *fimc); void fimc_unregister_capture_device(struct fimc_dev *fimc); -int fimc_sensor_sd_init(struct fimc_dev *fimc, int index); int fimc_vid_cap_buf_queue(struct fimc_dev *fimc, struct fimc_vid_buffer *fimc_vb); int fimc_capture_suspend(struct fimc_dev *fimc); -- cgit v0.10.2 From 30c9939d79d6edf64092148842835893d156b672 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 10 Jun 2011 15:36:48 -0300 Subject: [media] s5p-fimc: Remove v4l2_device from video capture and m2m driver Currently there is a v4l2_device instance being registered per each (capture and memory-to-memory) video node created per FIMC H/W instance. This patch is a prerequisite for using the top level v4l2_device instantiated by the media device driver. To retain current debug trace semantic (so it's possible to distinguish between the capture and m2m FIMC) the video_device is used in place of v4l2_device where appropriate. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 40f3330..a1ac986 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -191,7 +191,6 @@ static int buffer_prepare(struct vb2_buffer *vb) { struct vb2_queue *vq = vb->vb2_queue; struct fimc_ctx *ctx = vq->drv_priv; - struct v4l2_device *v4l2_dev = &ctx->fimc_dev->m2m.v4l2_dev; int i; if (!ctx->d_frame.fmt || vq->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) @@ -201,7 +200,8 @@ static int buffer_prepare(struct vb2_buffer *vb) unsigned long size = get_plane_size(&ctx->d_frame, i); if (vb2_plane_size(vb, i) < size) { - v4l2_err(v4l2_dev, "User buffer too small (%ld < %ld)\n", + v4l2_err(ctx->fimc_dev->vid_cap.vfd, + "User buffer too small (%ld < %ld)\n", vb2_plane_size(vb, i), size); return -EINVAL; } @@ -413,7 +413,8 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, pix = &f->fmt.pix_mp; frame->fmt = find_format(f, FMT_FLAGS_M2M | FMT_FLAGS_CAM); if (!frame->fmt) { - err("fimc target format not found\n"); + v4l2_err(fimc->vid_cap.vfd, + "Not supported capture (FIMC target) color format\n"); return -EINVAL; } @@ -473,7 +474,7 @@ static int fimc_cap_streamon(struct file *file, void *priv, return -EBUSY; if (!(ctx->state & FIMC_DST_FMT)) { - v4l2_err(&fimc->vid_cap.v4l2_dev, "Format is not set\n"); + v4l2_err(fimc->vid_cap.vfd, "Format is not set\n"); return -EINVAL; } @@ -603,9 +604,8 @@ static int fimc_cap_s_crop(struct file *file, void *fh, return ret; if (!(ctx->state & FIMC_DST_FMT)) { - v4l2_err(&fimc->vid_cap.v4l2_dev, - "Capture color format not set\n"); - return -EINVAL; /* TODO: make sure this is the right value */ + v4l2_err(fimc->vid_cap.vfd, "Capture format is not set\n"); + return -EINVAL; } f = &ctx->s_frame; @@ -614,7 +614,7 @@ static int fimc_cap_s_crop(struct file *file, void *fh, ctx->d_frame.width, ctx->d_frame.height, ctx->rotation); if (ret) { - v4l2_err(&fimc->vid_cap.v4l2_dev, "Out of the scaler range\n"); + v4l2_err(fimc->vid_cap.vfd, "Out of the scaler range\n"); return ret; } @@ -658,16 +658,16 @@ static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = { }; /* fimc->lock must be already initialized */ -int fimc_register_capture_device(struct fimc_dev *fimc) +int fimc_register_capture_device(struct fimc_dev *fimc, + struct v4l2_device *v4l2_dev) { - struct v4l2_device *v4l2_dev = &fimc->vid_cap.v4l2_dev; struct video_device *vfd; struct fimc_vid_cap *vid_cap; struct fimc_ctx *ctx; struct v4l2_format f; struct fimc_frame *fr; struct vb2_queue *q; - int ret; + int ret = -ENOMEM; ctx = kzalloc(sizeof *ctx, GFP_KERNEL); if (!ctx) @@ -685,20 +685,14 @@ int fimc_register_capture_device(struct fimc_dev *fimc) fr->width = fr->f_width = fr->o_width = 640; fr->height = fr->f_height = fr->o_height = 480; - snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), - "%s.capture", dev_name(&fimc->pdev->dev)); - - ret = v4l2_device_register(NULL, v4l2_dev); - if (ret) - goto err_info; - vfd = video_device_alloc(); if (!vfd) { v4l2_err(v4l2_dev, "Failed to allocate video device\n"); - goto err_v4l2_reg; + goto err_vd_alloc; } - strlcpy(vfd->name, v4l2_dev->name, sizeof(vfd->name)); + snprintf(vfd->name, sizeof(vfd->name), "%s.capture", + dev_name(&fimc->pdev->dev)); vfd->fops = &fimc_capture_fops; vfd->ioctl_ops = &fimc_capture_ioctl_ops; @@ -741,11 +735,8 @@ int fimc_register_capture_device(struct fimc_dev *fimc) err_ent: video_device_release(vfd); -err_v4l2_reg: - v4l2_device_unregister(v4l2_dev); -err_info: +err_vd_alloc: kfree(ctx); - dev_err(&fimc->pdev->dev, "failed to install\n"); return ret; } diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 9809764..3e2143d 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -236,10 +236,11 @@ static int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift) int fimc_set_scaler_info(struct fimc_ctx *ctx) { + struct samsung_fimc_variant *variant = ctx->fimc_dev->variant; + struct device *dev = &ctx->fimc_dev->pdev->dev; struct fimc_scaler *sc = &ctx->scaler; struct fimc_frame *s_frame = &ctx->s_frame; struct fimc_frame *d_frame = &ctx->d_frame; - struct samsung_fimc_variant *variant = ctx->fimc_dev->variant; int tx, ty, sx, sy; int ret; @@ -251,15 +252,14 @@ int fimc_set_scaler_info(struct fimc_ctx *ctx) ty = d_frame->height; } if (tx <= 0 || ty <= 0) { - v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev, - "invalid target size: %d x %d", tx, ty); + dev_err(dev, "Invalid target size: %dx%d", tx, ty); return -EINVAL; } sx = s_frame->width; sy = s_frame->height; if (sx <= 0 || sy <= 0) { - err("invalid source size: %d x %d", sx, sy); + dev_err(dev, "Invalid source size: %dx%d", sx, sy); return -EINVAL; } sc->real_width = sx; @@ -898,7 +898,7 @@ int fimc_vidioc_try_fmt_mplane(struct file *file, void *priv, mask = is_output ? FMT_FLAGS_M2M : FMT_FLAGS_M2M | FMT_FLAGS_CAM; fmt = find_format(f, mask); if (!fmt) { - v4l2_err(&fimc->m2m.v4l2_dev, "Fourcc format (0x%X) invalid.\n", + v4l2_err(fimc->v4l2_dev, "Fourcc format (0x%X) invalid.\n", pix->pixelformat); return -EINVAL; } @@ -973,7 +973,7 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv, vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); if (vb2_is_busy(vq)) { - v4l2_err(&fimc->m2m.v4l2_dev, "queue (%d) busy\n", f->type); + v4l2_err(fimc->m2m.vfd, "queue (%d) busy\n", f->type); return -EBUSY; } @@ -982,7 +982,7 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv, } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { frame = &ctx->d_frame; } else { - v4l2_err(&fimc->m2m.v4l2_dev, + v4l2_err(fimc->m2m.vfd, "Wrong buffer/video queue type (%d)\n", f->type); return -EINVAL; } @@ -1110,7 +1110,7 @@ int fimc_vidioc_g_ctrl(struct file *file, void *priv, return v4l2_subdev_call(fimc->vid_cap.sd, core, g_ctrl, ctrl); } else { - v4l2_err(&fimc->m2m.v4l2_dev, "Invalid control\n"); + v4l2_err(fimc->m2m.vfd, "Invalid control\n"); return -EINVAL; } } @@ -1128,8 +1128,7 @@ int check_ctrl_val(struct fimc_ctx *ctx, struct v4l2_control *ctrl) if (ctrl->value < c->minimum || ctrl->value > c->maximum || (c->step != 0 && ctrl->value % c->step != 0)) { - v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev, - "Invalid control value\n"); + v4l2_err(ctx->fimc_dev->m2m.vfd, "Invalid control value\n"); return -ERANGE; } @@ -1165,7 +1164,7 @@ int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl) } if (ret) { - v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range\n"); + v4l2_err(fimc->m2m.vfd, "Out of scaler range\n"); return -EINVAL; } @@ -1177,7 +1176,7 @@ int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl) break; default: - v4l2_err(&fimc->m2m.v4l2_dev, "Invalid control\n"); + v4l2_err(fimc->v4l2_dev, "Invalid control\n"); return -EINVAL; } @@ -1245,7 +1244,7 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) int i; if (cr->c.top < 0 || cr->c.left < 0) { - v4l2_err(&fimc->m2m.v4l2_dev, + v4l2_err(fimc->m2m.vfd, "doesn't support negative values for top & left\n"); return -EINVAL; } @@ -1326,7 +1325,7 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) ctx->rotation); } if (ret) { - v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range\n"); + v4l2_err(fimc->m2m.vfd, "Out of scaler range\n"); return -EINVAL; } } @@ -1494,30 +1493,23 @@ static struct v4l2_m2m_ops m2m_ops = { .job_abort = fimc_job_abort, }; -int fimc_register_m2m_device(struct fimc_dev *fimc) +int fimc_register_m2m_device(struct fimc_dev *fimc, + struct v4l2_device *v4l2_dev) { struct video_device *vfd; struct platform_device *pdev; - struct v4l2_device *v4l2_dev; int ret = 0; if (!fimc) return -ENODEV; pdev = fimc->pdev; - v4l2_dev = &fimc->m2m.v4l2_dev; - - snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), - "%s.m2m", dev_name(&pdev->dev)); - - ret = v4l2_device_register(&pdev->dev, v4l2_dev); - if (ret) - goto err_m2m_r1; + fimc->v4l2_dev = v4l2_dev; vfd = video_device_alloc(); if (!vfd) { v4l2_err(v4l2_dev, "Failed to allocate video device\n"); - goto err_m2m_r1; + return -ENOMEM; } vfd->fops = &fimc_m2m_fops; @@ -1527,17 +1519,15 @@ int fimc_register_m2m_device(struct fimc_dev *fimc) vfd->release = video_device_release; vfd->lock = &fimc->lock; - snprintf(vfd->name, sizeof(vfd->name), "%s:m2m", dev_name(&pdev->dev)); - + snprintf(vfd->name, sizeof(vfd->name), "%s.m2m", dev_name(&pdev->dev)); video_set_drvdata(vfd, fimc); - platform_set_drvdata(pdev, fimc); fimc->m2m.vfd = vfd; fimc->m2m.m2m_dev = v4l2_m2m_init(&m2m_ops); if (IS_ERR(fimc->m2m.m2m_dev)) { v4l2_err(v4l2_dev, "failed to initialize v4l2-m2m device\n"); ret = PTR_ERR(fimc->m2m.m2m_dev); - goto err_m2m_r2; + goto err_init; } ret = media_entity_init(&vfd->entity, 0, NULL, 0); @@ -1545,11 +1535,8 @@ int fimc_register_m2m_device(struct fimc_dev *fimc) return 0; v4l2_m2m_release(fimc->m2m.m2m_dev); -err_m2m_r2: +err_init: video_device_release(fimc->m2m.vfd); -err_m2m_r1: - v4l2_device_unregister(v4l2_dev); - return ret; } @@ -1560,7 +1547,6 @@ void fimc_unregister_m2m_device(struct fimc_dev *fimc) if (fimc->m2m.m2m_dev) v4l2_m2m_release(fimc->m2m.m2m_dev); - v4l2_device_unregister(&fimc->m2m.v4l2_dev); if (fimc->m2m.vfd) { media_entity_cleanup(&fimc->m2m.vfd->entity); /* Can also be called if video device wasn't registered */ diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index a0d6f81..ec2e83b 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -281,14 +281,12 @@ struct fimc_frame { /** * struct fimc_m2m_device - v4l2 memory-to-memory device data * @vfd: the video device node for v4l2 m2m mode - * @v4l2_dev: v4l2 device for m2m mode * @m2m_dev: v4l2 memory-to-memory device data * @ctx: hardware context data * @refcnt: the reference counter */ struct fimc_m2m_device { struct video_device *vfd; - struct v4l2_device v4l2_dev; struct v4l2_m2m_dev *m2m_dev; struct fimc_ctx *ctx; int refcnt; @@ -298,7 +296,6 @@ struct fimc_m2m_device { * struct fimc_vid_cap - camera capture device information * @ctx: hardware context data * @vfd: video device node for camera capture mode - * @v4l2_dev: v4l2_device struct to manage subdevs * @sd: pointer to camera sensor subdevice currently in use * @vd_pad: fimc video capture node pad * @fmt: Media Bus format configured at selected image sensor @@ -316,7 +313,6 @@ struct fimc_vid_cap { struct fimc_ctx *ctx; struct vb2_alloc_ctx *alloc_ctx; struct video_device *vfd; - struct v4l2_device v4l2_dev; struct v4l2_subdev *sd;; struct media_pad vd_pad; struct v4l2_mbus_framefmt fmt; @@ -407,6 +403,7 @@ struct fimc_ctx; * @regs_res: the resource claimed for IO registers * @irq: FIMC interrupt number * @irq_queue: interrupt handler waitqueue + * @v4l2_dev: root v4l2_device * @m2m: memory-to-memory V4L2 device information * @vid_cap: camera capture device information * @state: flags used to synchronize m2m and capture mode operation @@ -425,6 +422,7 @@ struct fimc_dev { struct resource *regs_res; int irq; wait_queue_head_t irq_queue; + struct v4l2_device *v4l2_dev; struct fimc_m2m_device m2m; struct fimc_vid_cap vid_cap; unsigned long state; @@ -569,7 +567,7 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx, } else if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type) { frame = &ctx->d_frame; } else { - v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev, + v4l2_err(ctx->fimc_dev->v4l2_dev, "Wrong buffer/video queue type (%d)\n", type); return ERR_PTR(-EINVAL); } @@ -644,11 +642,14 @@ int fimc_set_scaler_info(struct fimc_ctx *ctx); int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags); int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, struct fimc_frame *frame, struct fimc_addr *paddr); -int fimc_register_m2m_device(struct fimc_dev *fimc); +int fimc_register_m2m_device(struct fimc_dev *fimc, + struct v4l2_device *v4l2_dev); +void fimc_unregister_m2m_device(struct fimc_dev *fimc); /* -----------------------------------------------------*/ /* fimc-capture.c */ -int fimc_register_capture_device(struct fimc_dev *fimc); +int fimc_register_capture_device(struct fimc_dev *fimc, + struct v4l2_device *v4l2_dev); void fimc_unregister_capture_device(struct fimc_dev *fimc); int fimc_vid_cap_buf_queue(struct fimc_dev *fimc, struct fimc_vid_buffer *fimc_vb); diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c index 938dadf..c688263 100644 --- a/drivers/media/video/s5p-fimc/fimc-reg.c +++ b/drivers/media/video/s5p-fimc/fimc-reg.c @@ -596,7 +596,7 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc, } if (i == ARRAY_SIZE(pix_desc)) { - v4l2_err(&fimc->vid_cap.v4l2_dev, + v4l2_err(fimc->vid_cap.vfd, "Camera color format not supported: %d\n", fimc->vid_cap.fmt.code); return -EINVAL; @@ -661,8 +661,9 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc, if (vid_cap->fmt.code == V4L2_MBUS_FMT_VYUY8_2X8) { tmp = S5P_CSIIMGFMT_YCBCR422_8BIT; } else { - err("camera image format not supported: %d", - vid_cap->fmt.code); + v4l2_err(fimc->vid_cap.vfd, + "Not supported camera pixel format: %d", + vid_cap->fmt.code); return -EINVAL; } tmp |= (cam->csi_data_align == 32) << 8; -- cgit v0.10.2 From d3953223b0905437fef7ce60506b5fdfaf98dda6 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 1 Sep 2011 06:01:08 -0300 Subject: [media] s5p-fimc: Add the media device driver Add a top level media device driver aggregating FIMC video devnodes, MIPI-CSIS and sensor subdevs. This driver gathers all media entities and creates the possible links between them during initialization. By default some links will be activated to enable access to all available sensors in the system. For example if there are sensors S0, S1 listed in the media device platform data definition they will be by default assigned to FIMC0, FIMC1 respectively, which in turn will corresponds to separate /dev/video?. There is enough FIMC H/W entities to cover all available physical camera interfaces in the system. The fimc media device driver is bound to the "s5p-fimc-md" platform device. Such platform device should be created by board initialization code and camera sensors description array need to be specified as its platform data. The media device driver also implements various video pipeline operations, for enabling subdevs power, streaming, etc., which will be used by the capture video node driver. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 14326d7..6279663 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -949,8 +949,9 @@ config VIDEO_MX2 Interface config VIDEO_SAMSUNG_S5P_FIMC - tristate "Samsung S5P and EXYNOS4 camera host interface driver" - depends on VIDEO_V4L2 && PLAT_S5P && PM_RUNTIME + tristate "Samsung S5P and EXYNOS4 camera interface driver (EXPERIMENTAL)" + depends on VIDEO_V4L2 && I2C && PLAT_S5P && PM_RUNTIME && \ + VIDEO_V4L2_SUBDEV_API && EXPERIMENTAL select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV ---help--- diff --git a/drivers/media/video/s5p-fimc/Makefile b/drivers/media/video/s5p-fimc/Makefile index df6954a..33dec7f 100644 --- a/drivers/media/video/s5p-fimc/Makefile +++ b/drivers/media/video/s5p-fimc/Makefile @@ -1,4 +1,4 @@ -s5p-fimc-objs := fimc-core.o fimc-reg.o fimc-capture.o +s5p-fimc-objs := fimc-core.o fimc-reg.o fimc-capture.o fimc-mdevice.o s5p-csis-objs := mipi-csis.o obj-$(CONFIG_VIDEO_S5P_MIPI_CSIS) += s5p-csis.o diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 3e2143d..16314c9 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -28,6 +28,7 @@ #include #include "fimc-core.h" +#include "fimc-mdevice.h" static char *fimc_clocks[MAX_FIMC_CLOCKS] = { "sclk_fimc", "fimc" @@ -1867,6 +1868,7 @@ static struct fimc_pix_limit s5p_pix_limit[4] = { static struct samsung_fimc_variant fimc0_variant_s5p = { .has_inp_rot = 1, .has_out_rot = 1, + .has_cam_if = 1, .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 8, @@ -1875,6 +1877,7 @@ static struct samsung_fimc_variant fimc0_variant_s5p = { }; static struct samsung_fimc_variant fimc2_variant_s5p = { + .has_cam_if = 1, .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 8, @@ -1886,6 +1889,7 @@ static struct samsung_fimc_variant fimc0_variant_s5pv210 = { .pix_hoff = 1, .has_inp_rot = 1, .has_out_rot = 1, + .has_cam_if = 1, .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 8, @@ -1897,6 +1901,7 @@ static struct samsung_fimc_variant fimc1_variant_s5pv210 = { .pix_hoff = 1, .has_inp_rot = 1, .has_out_rot = 1, + .has_cam_if = 1, .has_mainscaler_ext = 1, .min_inp_pixsize = 16, .min_out_pixsize = 16, @@ -1906,6 +1911,7 @@ static struct samsung_fimc_variant fimc1_variant_s5pv210 = { }; static struct samsung_fimc_variant fimc2_variant_s5pv210 = { + .has_cam_if = 1, .pix_hoff = 1, .min_inp_pixsize = 16, .min_out_pixsize = 16, @@ -1918,6 +1924,7 @@ static struct samsung_fimc_variant fimc0_variant_exynos4 = { .pix_hoff = 1, .has_inp_rot = 1, .has_out_rot = 1, + .has_cam_if = 1, .has_cistatus2 = 1, .has_mainscaler_ext = 1, .min_inp_pixsize = 16, @@ -1927,8 +1934,9 @@ static struct samsung_fimc_variant fimc0_variant_exynos4 = { .pix_limit = &s5p_pix_limit[1], }; -static struct samsung_fimc_variant fimc2_variant_exynos4 = { +static struct samsung_fimc_variant fimc3_variant_exynos4 = { .pix_hoff = 1, + .has_cam_if = 1, .has_cistatus2 = 1, .has_mainscaler_ext = 1, .min_inp_pixsize = 16, @@ -1966,7 +1974,7 @@ static struct samsung_fimc_driverdata fimc_drvdata_exynos4 = { [0] = &fimc0_variant_exynos4, [1] = &fimc0_variant_exynos4, [2] = &fimc0_variant_exynos4, - [3] = &fimc2_variant_exynos4, + [3] = &fimc3_variant_exynos4, }, .num_entities = 4, .lclk_frequency = 166000000UL, @@ -1994,32 +2002,21 @@ static const struct dev_pm_ops fimc_pm_ops = { static struct platform_driver fimc_driver = { .probe = fimc_probe, - .remove = __devexit_p(fimc_remove), + .remove = __devexit_p(fimc_remove), .id_table = fimc_driver_ids, .driver = { - .name = MODULE_NAME, + .name = FIMC_MODULE_NAME, .owner = THIS_MODULE, .pm = &fimc_pm_ops, } }; -static int __init fimc_init(void) +int __init fimc_register_driver(void) { - int ret = platform_driver_register(&fimc_driver); - if (ret) - err("platform_driver_register failed: %d\n", ret); - return ret; + return platform_driver_probe(&fimc_driver, fimc_probe); } -static void __exit fimc_exit(void) +void __exit fimc_unregister_driver(void) { platform_driver_unregister(&fimc_driver); } - -module_init(fimc_init); -module_exit(fimc_exit); - -MODULE_AUTHOR("Sylwester Nawrocki "); -MODULE_DESCRIPTION("S5P FIMC camera host interface/video postprocessor driver"); -MODULE_LICENSE("GPL"); -MODULE_VERSION("1.0.1"); diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index ec2e83b..5a62349 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -36,7 +36,7 @@ /* Time to wait for next frame VSYNC interrupt while stopping operation. */ #define FIMC_SHUTDOWN_TIMEOUT ((100*HZ)/1000) #define MAX_FIMC_CLOCKS 2 -#define MODULE_NAME "s5p-fimc" +#define FIMC_MODULE_NAME "s5p-fimc" #define FIMC_MAX_DEVS 4 #define FIMC_MAX_OUT_BUFS 4 #define SCALER_MAX_HRATIO 64 @@ -308,6 +308,7 @@ struct fimc_m2m_device { * @reqbufs_count: the number of buffers requested in REQBUFS ioctl * @input_index: input (camera sensor) index * @refcnt: driver's private reference counter + * @user_subdev_api: true if subdevs are not configured by the host driver */ struct fimc_vid_cap { struct fimc_ctx *ctx; @@ -325,6 +326,7 @@ struct fimc_vid_cap { unsigned int reqbufs_count; int input_index; int refcnt; + bool user_subdev_api; }; /** @@ -355,6 +357,7 @@ struct fimc_pix_limit { * @has_cistatus2: 1 if CISTATUS2 register is present in this IP revision * @has_mainscaler_ext: 1 if extended mainscaler ratios in CIEXTEN register * are present in this IP revision + * @has_cam_if: set if this instance has a camera input interface * @pix_limit: pixel size constraints for the scaler * @min_inp_pixsize: minimum input pixel size * @min_out_pixsize: minimum output pixel size @@ -367,6 +370,7 @@ struct samsung_fimc_variant { unsigned int has_out_rot:1; unsigned int has_cistatus2:1; unsigned int has_mainscaler_ext:1; + unsigned int has_cam_if:1; struct fimc_pix_limit *pix_limit; u16 min_inp_pixsize; u16 min_out_pixsize; @@ -387,6 +391,12 @@ struct samsung_fimc_driverdata { int num_entities; }; +struct fimc_pipeline { + struct media_pipeline *pipe; + struct v4l2_subdev *sensor; + struct v4l2_subdev *csis; +}; + struct fimc_ctx; /** @@ -408,6 +418,7 @@ struct fimc_ctx; * @vid_cap: camera capture device information * @state: flags used to synchronize m2m and capture mode operation * @alloc_ctx: videobuf2 memory allocator context + * @pipeline: fimc video capture pipeline data structure */ struct fimc_dev { spinlock_t slock; @@ -427,6 +438,7 @@ struct fimc_dev { struct fimc_vid_cap vid_cap; unsigned long state; struct vb2_alloc_ctx *alloc_ctx; + struct fimc_pipeline pipeline; }; /** @@ -645,6 +657,8 @@ int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, int fimc_register_m2m_device(struct fimc_dev *fimc, struct v4l2_device *v4l2_dev); void fimc_unregister_m2m_device(struct fimc_dev *fimc); +int fimc_register_driver(void); +void fimc_unregister_driver(void); /* -----------------------------------------------------*/ /* fimc-capture.c */ diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.c b/drivers/media/video/s5p-fimc/fimc-mdevice.c new file mode 100644 index 0000000..50f3fca --- /dev/null +++ b/drivers/media/video/s5p-fimc/fimc-mdevice.c @@ -0,0 +1,829 @@ +/* + * S5P/EXYNOS4 SoC series camera host interface media device driver + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * Contact: Sylwester Nawrocki, + * + * 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 of the License, + * or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fimc-core.h" +#include "fimc-mdevice.h" +#include "mipi-csis.h" + +static int __fimc_md_set_camclk(struct fimc_md *fmd, + struct fimc_sensor_info *s_info, + bool on); +/** + * fimc_pipeline_prepare - update pipeline information with subdevice pointers + * @fimc: fimc device terminating the pipeline + * + * Caller holds the graph mutex. + */ +void fimc_pipeline_prepare(struct fimc_dev *fimc, struct media_entity *me) +{ + struct media_entity_graph graph; + struct v4l2_subdev *sd; + + media_entity_graph_walk_start(&graph, me); + + while ((me = media_entity_graph_walk_next(&graph))) { + if (media_entity_type(me) != MEDIA_ENT_T_V4L2_SUBDEV) + continue; + sd = media_entity_to_v4l2_subdev(me); + + if (sd->grp_id == SENSOR_GROUP_ID) + fimc->pipeline.sensor = sd; + else if (sd->grp_id == CSIS_GROUP_ID) + fimc->pipeline.csis = sd; + } +} + +/** + * __subdev_set_power - change power state of a single subdev + * @sd: subdevice to change power state for + * @on: 1 to enable power or 0 to disable + * + * Return result of s_power subdev operation or -ENXIO if sd argument + * is NULL. Return 0 if the subdevice does not implement s_power. + */ +static int __subdev_set_power(struct v4l2_subdev *sd, int on) +{ + int *use_count; + int ret; + + if (sd == NULL) + return -ENXIO; + + use_count = &sd->entity.use_count; + if (on && (*use_count)++ > 0) + return 0; + else if (!on && (*use_count == 0 || --(*use_count) > 0)) + return 0; + ret = v4l2_subdev_call(sd, core, s_power, on); + + return ret != -ENOIOCTLCMD ? ret : 0; +} + +/** + * fimc_pipeline_s_power - change power state of all pipeline subdevs + * @fimc: fimc device terminating the pipeline + * @state: 1 to enable power or 0 for power down + * + * Need to be called with the graph mutex held. + */ +int fimc_pipeline_s_power(struct fimc_dev *fimc, int state) +{ + int ret = 0; + + if (fimc->pipeline.sensor == NULL) + return -ENXIO; + + if (state) { + ret = __subdev_set_power(fimc->pipeline.csis, 1); + if (ret && ret != -ENXIO) + return ret; + return __subdev_set_power(fimc->pipeline.sensor, 1); + } + + ret = __subdev_set_power(fimc->pipeline.sensor, 0); + if (ret) + return ret; + ret = __subdev_set_power(fimc->pipeline.csis, 0); + + return ret == -ENXIO ? 0 : ret; +} + +/** + * __fimc_pipeline_initialize - update the pipeline information, enable power + * of all pipeline subdevs and the sensor clock + * @me: media entity to start graph walk with + * @prep: true to acquire sensor (and csis) subdevs + * + * This function must be called with the graph mutex held. + */ +static int __fimc_pipeline_initialize(struct fimc_dev *fimc, + struct media_entity *me, bool prep) +{ + int ret; + + if (prep) + fimc_pipeline_prepare(fimc, me); + if (fimc->pipeline.sensor == NULL) + return -EINVAL; + ret = fimc_md_set_camclk(fimc->pipeline.sensor, true); + if (ret) + return ret; + return fimc_pipeline_s_power(fimc, 1); +} + +int fimc_pipeline_initialize(struct fimc_dev *fimc, struct media_entity *me, + bool prep) +{ + int ret; + + mutex_lock(&me->parent->graph_mutex); + ret = __fimc_pipeline_initialize(fimc, me, prep); + mutex_unlock(&me->parent->graph_mutex); + + return ret; +} + +/** + * __fimc_pipeline_shutdown - disable the sensor clock and pipeline power + * @fimc: fimc device terminating the pipeline + * + * Disable power of all subdevs in the pipeline and turn off the external + * sensor clock. + * Called with the graph mutex held. + */ +int __fimc_pipeline_shutdown(struct fimc_dev *fimc) +{ + int ret = 0; + + if (fimc->pipeline.sensor) { + ret = fimc_pipeline_s_power(fimc, 0); + fimc_md_set_camclk(fimc->pipeline.sensor, false); + } + return ret == -ENXIO ? 0 : ret; +} + +int fimc_pipeline_shutdown(struct fimc_dev *fimc) +{ + struct media_entity *me = &fimc->vid_cap.vfd->entity; + int ret; + + mutex_lock(&me->parent->graph_mutex); + ret = __fimc_pipeline_shutdown(fimc); + mutex_unlock(&me->parent->graph_mutex); + + return ret; +} + +/** + * fimc_pipeline_s_stream - invoke s_stream on pipeline subdevs + * @fimc: fimc device terminating the pipeline + * @on: passed as the s_stream call argument + */ +int fimc_pipeline_s_stream(struct fimc_dev *fimc, int on) +{ + struct fimc_pipeline *p = &fimc->pipeline; + int ret = 0; + + if (p->sensor == NULL) + return -ENODEV; + + if ((on && p->csis) || !on) + ret = v4l2_subdev_call(on ? p->csis : p->sensor, + video, s_stream, on); + if (ret && ret != -ENOIOCTLCMD) + return ret; + if ((!on && p->csis) || on) + ret = v4l2_subdev_call(on ? p->sensor : p->csis, + video, s_stream, on); + return ret == -ENOIOCTLCMD ? 0 : ret; +} + +/* + * Sensor subdevice helper functions + */ +static struct v4l2_subdev *fimc_md_register_sensor(struct fimc_md *fmd, + struct fimc_sensor_info *s_info) +{ + struct i2c_adapter *adapter; + struct v4l2_subdev *sd = NULL; + + if (!s_info || !fmd) + return NULL; + + adapter = i2c_get_adapter(s_info->pdata->i2c_bus_num); + if (!adapter) + return NULL; + sd = v4l2_i2c_new_subdev_board(&fmd->v4l2_dev, adapter, + s_info->pdata->board_info, NULL); + if (IS_ERR_OR_NULL(sd)) { + v4l2_err(&fmd->v4l2_dev, "Failed to acquire subdev\n"); + return NULL; + } + v4l2_set_subdev_hostdata(sd, s_info); + sd->grp_id = SENSOR_GROUP_ID; + + v4l2_info(&fmd->v4l2_dev, "Registered sensor subdevice %s\n", + s_info->pdata->board_info->type); + return sd; +} + +static void fimc_md_unregister_sensor(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!client) + return; + v4l2_device_unregister_subdev(sd); + i2c_unregister_device(client); + i2c_put_adapter(client->adapter); +} + +static int fimc_md_register_sensor_entities(struct fimc_md *fmd) +{ + struct s5p_platform_fimc *pdata = fmd->pdev->dev.platform_data; + struct fimc_dev *fd = NULL; + int num_clients, ret, i; + + /* + * Runtime resume one of the FIMC entities to make sure + * the sclk_cam clocks are not globally disabled. + */ + for (i = 0; !fd && i < ARRAY_SIZE(fmd->fimc); i++) + if (fmd->fimc[i]) + fd = fmd->fimc[i]; + if (!fd) + return -ENXIO; + ret = pm_runtime_get_sync(&fd->pdev->dev); + if (ret < 0) + return ret; + + WARN_ON(pdata->num_clients > ARRAY_SIZE(fmd->sensor)); + num_clients = min_t(u32, pdata->num_clients, ARRAY_SIZE(fmd->sensor)); + + fmd->num_sensors = num_clients; + for (i = 0; i < num_clients; i++) { + fmd->sensor[i].pdata = &pdata->isp_info[i]; + ret = __fimc_md_set_camclk(fmd, &fmd->sensor[i], true); + if (ret) + break; + fmd->sensor[i].subdev = + fimc_md_register_sensor(fmd, &fmd->sensor[i]); + ret = __fimc_md_set_camclk(fmd, &fmd->sensor[i], false); + if (ret) + break; + } + pm_runtime_put(&fd->pdev->dev); + return ret; +} + +/* + * MIPI CSIS and FIMC platform devices registration. + */ +static int fimc_register_callback(struct device *dev, void *p) +{ + struct fimc_dev *fimc = dev_get_drvdata(dev); + struct fimc_md *fmd = p; + int ret; + + if (!fimc || !fimc->pdev) + return 0; + if (fimc->pdev->id < 0 || fimc->pdev->id >= FIMC_MAX_DEVS) + return 0; + + fmd->fimc[fimc->pdev->id] = fimc; + ret = fimc_register_m2m_device(fimc, &fmd->v4l2_dev); + if (ret) + return ret; + ret = fimc_register_capture_device(fimc, &fmd->v4l2_dev); + if (!ret) + fimc->vid_cap.user_subdev_api = fmd->user_subdev_api; + return ret; +} + +static int csis_register_callback(struct device *dev, void *p) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct platform_device *pdev; + struct fimc_md *fmd = p; + int id, ret; + + if (!sd) + return 0; + pdev = v4l2_get_subdevdata(sd); + if (!pdev || pdev->id < 0 || pdev->id >= CSIS_MAX_ENTITIES) + return 0; + v4l2_info(sd, "csis%d sd: %s\n", pdev->id, sd->name); + + id = pdev->id < 0 ? 0 : pdev->id; + fmd->csis[id].sd = sd; + sd->grp_id = CSIS_GROUP_ID; + ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); + if (ret) + v4l2_err(&fmd->v4l2_dev, + "Failed to register CSIS subdevice: %d\n", ret); + return ret; +} + +/** + * fimc_md_register_platform_entities - register FIMC and CSIS media entities + */ +static int fimc_md_register_platform_entities(struct fimc_md *fmd) +{ + struct device_driver *driver; + int ret; + + driver = driver_find(FIMC_MODULE_NAME, &platform_bus_type); + if (!driver) + return -ENODEV; + ret = driver_for_each_device(driver, NULL, fmd, + fimc_register_callback); + put_driver(driver); + if (ret) + return ret; + + driver = driver_find(CSIS_DRIVER_NAME, &platform_bus_type); + if (driver) { + ret = driver_for_each_device(driver, NULL, fmd, + csis_register_callback); + put_driver(driver); + } + return ret; +} + +static void fimc_md_unregister_entities(struct fimc_md *fmd) +{ + int i; + + for (i = 0; i < FIMC_MAX_DEVS; i++) { + if (fmd->fimc[i] == NULL) + continue; + fimc_unregister_m2m_device(fmd->fimc[i]); + fimc_unregister_capture_device(fmd->fimc[i]); + fmd->fimc[i] = NULL; + } + for (i = 0; i < CSIS_MAX_ENTITIES; i++) { + if (fmd->csis[i].sd == NULL) + continue; + v4l2_device_unregister_subdev(fmd->csis[i].sd); + fmd->csis[i].sd = NULL; + } + for (i = 0; i < fmd->num_sensors; i++) { + if (fmd->sensor[i].subdev == NULL) + continue; + fimc_md_unregister_sensor(fmd->sensor[i].subdev); + fmd->sensor[i].subdev = NULL; + } +} + +static int fimc_md_register_video_nodes(struct fimc_md *fmd) +{ + int i, ret = 0; + + for (i = 0; i < FIMC_MAX_DEVS && !ret; i++) { + if (!fmd->fimc[i]) + continue; + + if (fmd->fimc[i]->m2m.vfd) + ret = video_register_device(fmd->fimc[i]->m2m.vfd, + VFL_TYPE_GRABBER, -1); + if (ret) + break; + if (fmd->fimc[i]->vid_cap.vfd) + ret = video_register_device(fmd->fimc[i]->vid_cap.vfd, + VFL_TYPE_GRABBER, -1); + } + + return ret; +} + +/** + * __fimc_md_create_fimc_links - create links to all FIMC entities + * @fmd: fimc media device + * @source: the source entity to create links to all fimc entities from + * @sensor: sensor subdev linked to FIMC[fimc_id] entity, may be null + * @pad: the source entity pad index + * @fimc_id: index of the fimc device for which link should be enabled + */ +static int __fimc_md_create_fimc_links(struct fimc_md *fmd, + struct media_entity *source, + struct v4l2_subdev *sensor, + int pad, int fimc_id) +{ + struct fimc_sensor_info *s_info; + struct media_entity *sink; + unsigned int flags; + int ret, i, src_pad; + + for (i = 0; i < FIMC_MAX_DEVS; i++) { + if (!fmd->fimc[i]) + break; + /* + * Some FIMC variants are not fitted with camera capture + * interface. Skip creating a link from sensor for those. + */ + if (sensor && sensor->grp_id == SENSOR_GROUP_ID && + !fmd->fimc[i]->variant->has_cam_if) + continue; + + flags = (i == fimc_id) ? MEDIA_LNK_FL_ENABLED : 0; + sink = &fmd->fimc[i]->vid_cap.vfd->entity; + ret = media_entity_create_link(source, 0, sink, 0, flags); + if (ret) + return ret; + + v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]", + source->name, flags ? '=' : '-', sink->name); + + if (flags == 0 || sensor == NULL) + continue; + s_info = v4l2_get_subdev_hostdata(sensor); + if (!WARN_ON(s_info == NULL)) { + unsigned long irq_flags; + spin_lock_irqsave(&fmd->slock, irq_flags); + s_info->host = fmd->fimc[i]; + spin_unlock_irqrestore(&fmd->slock, irq_flags); + } + } + return 0; +} + +/** + * fimc_md_create_links - create default links between registered entities + * + * Parallel interface sensor entities are connected directly to FIMC capture + * entities. The sensors using MIPI CSIS bus are connected through immutable + * link with CSI receiver entity specified by mux_id. Any registered CSIS + * entity has a link to each registered FIMC capture entity. Enabled links + * are created by default between each subsequent registered sensor and + * subsequent FIMC capture entity. The number of default active links is + * determined by the number of available sensors or FIMC entities, + * whichever is less. + */ +static int fimc_md_create_links(struct fimc_md *fmd) +{ + struct v4l2_subdev *sensor, *csis; + struct s5p_fimc_isp_info *pdata; + struct fimc_sensor_info *s_info; + struct media_entity *source; + int fimc_id = 0; + int i, pad; + int ret = 0; + + for (i = 0; i < fmd->num_sensors; i++) { + if (fmd->sensor[i].subdev == NULL) + continue; + + sensor = fmd->sensor[i].subdev; + s_info = v4l2_get_subdev_hostdata(sensor); + if (!s_info || !s_info->pdata) + continue; + + source = NULL; + pdata = s_info->pdata; + + switch (pdata->bus_type) { + case FIMC_MIPI_CSI2: + if (WARN(pdata->mux_id >= CSIS_MAX_ENTITIES, + "Wrong CSI channel id: %d\n", pdata->mux_id)) + return -EINVAL; + + csis = fmd->csis[pdata->mux_id].sd; + if (WARN(csis == NULL, + "MIPI-CSI interface specified " + "but s5p-csis module is not loaded!\n")) + continue; + + ret = media_entity_create_link(&sensor->entity, 0, + &csis->entity, CSIS_PAD_SINK, + MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + if (ret) + return ret; + + v4l2_info(&fmd->v4l2_dev, "created link [%s] => [%s]", + sensor->entity.name, csis->entity.name); + + sensor = NULL; + source = &csis->entity; + pad = CSIS_PAD_SOURCE; + break; + + case FIMC_ITU_601...FIMC_ITU_656: + source = &sensor->entity; + pad = 0; + break; + + default: + v4l2_err(&fmd->v4l2_dev, "Wrong bus_type: %x\n", + pdata->bus_type); + return -EINVAL; + } + if (source == NULL) + continue; + + ret = __fimc_md_create_fimc_links(fmd, source, sensor, pad, + fimc_id++); + } + return ret; +} + +/* + * The peripheral sensor clock management. + */ +static int fimc_md_get_clocks(struct fimc_md *fmd) +{ + char clk_name[32]; + struct clk *clock; + int i; + + for (i = 0; i < FIMC_MAX_CAMCLKS; i++) { + snprintf(clk_name, sizeof(clk_name), "sclk_cam%u", i); + clock = clk_get(NULL, clk_name); + if (IS_ERR_OR_NULL(clock)) { + v4l2_err(&fmd->v4l2_dev, "Failed to get clock: %s", + clk_name); + return -ENXIO; + } + fmd->camclk[i].clock = clock; + } + return 0; +} + +static void fimc_md_put_clocks(struct fimc_md *fmd) +{ + int i = FIMC_MAX_CAMCLKS; + + while (--i >= 0) { + if (IS_ERR_OR_NULL(fmd->camclk[i].clock)) + continue; + clk_put(fmd->camclk[i].clock); + fmd->camclk[i].clock = NULL; + } +} + +static int __fimc_md_set_camclk(struct fimc_md *fmd, + struct fimc_sensor_info *s_info, + bool on) +{ + struct s5p_fimc_isp_info *pdata = s_info->pdata; + struct fimc_camclk_info *camclk; + int ret = 0; + + if (WARN_ON(pdata->clk_id >= FIMC_MAX_CAMCLKS) || fmd == NULL) + return -EINVAL; + + if (s_info->clk_on == on) + return 0; + camclk = &fmd->camclk[pdata->clk_id]; + + dbg("camclk %d, f: %lu, clk: %p, on: %d", + pdata->clk_id, pdata->clk_frequency, camclk, on); + + if (on) { + if (camclk->use_count > 0 && + camclk->frequency != pdata->clk_frequency) + return -EINVAL; + + if (camclk->use_count++ == 0) { + clk_set_rate(camclk->clock, pdata->clk_frequency); + camclk->frequency = pdata->clk_frequency; + ret = clk_enable(camclk->clock); + } + s_info->clk_on = 1; + dbg("Enabled camclk %d: f: %lu", pdata->clk_id, + clk_get_rate(camclk->clock)); + + return ret; + } + + if (WARN_ON(camclk->use_count == 0)) + return 0; + + if (--camclk->use_count == 0) { + clk_disable(camclk->clock); + s_info->clk_on = 0; + dbg("Disabled camclk %d", pdata->clk_id); + } + return ret; +} + +/** + * fimc_md_set_camclk - peripheral sensor clock setup + * @sd: sensor subdev to configure sclk_cam clock for + * @on: 1 to enable or 0 to disable the clock + * + * There are 2 separate clock outputs available in the SoC for external + * image processors. These clocks are shared between all registered FIMC + * devices to which sensors can be attached, either directly or through + * the MIPI CSI receiver. The clock is allowed here to be used by + * multiple sensors concurrently if they use same frequency. + * The per sensor subdev clk_on attribute helps to synchronize accesses + * to the sclk_cam clocks from the video and media device nodes. + * This function should only be called when the graph mutex is held. + */ +int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on) +{ + struct fimc_sensor_info *s_info = v4l2_get_subdev_hostdata(sd); + struct fimc_md *fmd = entity_to_fimc_mdev(&sd->entity); + + return __fimc_md_set_camclk(fmd, s_info, on); +} + +static int fimc_md_link_notify(struct media_pad *source, + struct media_pad *sink, u32 flags) +{ + struct video_device *vid_dev; + struct fimc_dev *fimc; + int ret = 0; + + if (WARN_ON(media_entity_type(sink->entity) != MEDIA_ENT_T_DEVNODE)) + return 0; + + vid_dev = media_entity_to_video_device(sink->entity); + fimc = video_get_drvdata(vid_dev); + + if (!(flags & MEDIA_LNK_FL_ENABLED)) { + ret = __fimc_pipeline_shutdown(fimc); + fimc->pipeline.sensor = NULL; + fimc->pipeline.csis = NULL; + return ret; + } + /* + * Link activation. Enable power of pipeline elements only if the + * pipeline is already in use, i.e. its video node is opened. + */ + mutex_lock(&fimc->lock); + if (fimc->vid_cap.refcnt > 0) + ret = __fimc_pipeline_initialize(fimc, source->entity, true); + mutex_unlock(&fimc->lock); + + return ret ? -EPIPE : ret; +} + +static ssize_t fimc_md_sysfs_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct fimc_md *fmd = platform_get_drvdata(pdev); + + if (fmd->user_subdev_api) + return strlcpy(buf, "Sub-device API (sub-dev)\n", PAGE_SIZE); + + return strlcpy(buf, "V4L2 video node only API (vid-dev)\n", PAGE_SIZE); +} + +static ssize_t fimc_md_sysfs_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct platform_device *pdev = to_platform_device(dev); + struct fimc_md *fmd = platform_get_drvdata(pdev); + bool subdev_api; + int i; + + if (!strcmp(buf, "vid-dev\n")) + subdev_api = false; + else if (!strcmp(buf, "sub-dev\n")) + subdev_api = true; + else + return count; + + fmd->user_subdev_api = subdev_api; + for (i = 0; i < FIMC_MAX_DEVS; i++) + if (fmd->fimc[i]) + fmd->fimc[i]->vid_cap.user_subdev_api = subdev_api; + return count; +} +/* + * This device attribute is to select video pipeline configuration method. + * There are following valid values: + * vid-dev - for V4L2 video node API only, subdevice will be configured + * by the host driver. + * sub-dev - for media controller API, subdevs must be configured in user + * space before starting streaming. + */ +static DEVICE_ATTR(subdev_conf_mode, S_IWUSR | S_IRUGO, + fimc_md_sysfs_show, fimc_md_sysfs_store); + +static int __devinit fimc_md_probe(struct platform_device *pdev) +{ + struct v4l2_device *v4l2_dev; + struct fimc_md *fmd; + int ret; + + if (WARN(!pdev->dev.platform_data, "Platform data not specified!\n")) + return -EINVAL; + + fmd = kzalloc(sizeof(struct fimc_md), GFP_KERNEL); + if (!fmd) + return -ENOMEM; + + spin_lock_init(&fmd->slock); + fmd->pdev = pdev; + + strlcpy(fmd->media_dev.model, "SAMSUNG S5P FIMC", + sizeof(fmd->media_dev.model)); + fmd->media_dev.link_notify = fimc_md_link_notify; + fmd->media_dev.dev = &pdev->dev; + + v4l2_dev = &fmd->v4l2_dev; + v4l2_dev->mdev = &fmd->media_dev; + snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s", + dev_name(&pdev->dev)); + + ret = v4l2_device_register(&pdev->dev, &fmd->v4l2_dev); + if (ret < 0) { + v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret); + goto err1; + } + ret = media_device_register(&fmd->media_dev); + if (ret < 0) { + v4l2_err(v4l2_dev, "Failed to register media device: %d\n", ret); + goto err2; + } + ret = fimc_md_get_clocks(fmd); + if (ret) + goto err3; + + fmd->user_subdev_api = false; + ret = fimc_md_register_platform_entities(fmd); + if (ret) + goto err3; + + ret = fimc_md_register_sensor_entities(fmd); + if (ret) + goto err3; + ret = fimc_md_create_links(fmd); + if (ret) + goto err3; + ret = v4l2_device_register_subdev_nodes(&fmd->v4l2_dev); + if (ret) + goto err3; + ret = fimc_md_register_video_nodes(fmd); + if (ret) + goto err3; + + ret = device_create_file(&pdev->dev, &dev_attr_subdev_conf_mode); + if (!ret) { + platform_set_drvdata(pdev, fmd); + return 0; + } +err3: + media_device_unregister(&fmd->media_dev); + fimc_md_put_clocks(fmd); + fimc_md_unregister_entities(fmd); +err2: + v4l2_device_unregister(&fmd->v4l2_dev); +err1: + kfree(fmd); + return ret; +} + +static int __devexit fimc_md_remove(struct platform_device *pdev) +{ + struct fimc_md *fmd = platform_get_drvdata(pdev); + + if (!fmd) + return 0; + device_remove_file(&pdev->dev, &dev_attr_subdev_conf_mode); + fimc_md_unregister_entities(fmd); + media_device_unregister(&fmd->media_dev); + fimc_md_put_clocks(fmd); + kfree(fmd); + return 0; +} + +static struct platform_driver fimc_md_driver = { + .probe = fimc_md_probe, + .remove = __devexit_p(fimc_md_remove), + .driver = { + .name = "s5p-fimc-md", + .owner = THIS_MODULE, + } +}; + +int __init fimc_md_init(void) +{ + int ret; + request_module("s5p-csis"); + ret = fimc_register_driver(); + if (ret) + return ret; + return platform_driver_register(&fimc_md_driver); +} +void __exit fimc_md_exit(void) +{ + platform_driver_unregister(&fimc_md_driver); + fimc_unregister_driver(); +} + +module_init(fimc_md_init); +module_exit(fimc_md_exit); + +MODULE_AUTHOR("Sylwester Nawrocki "); +MODULE_DESCRIPTION("S5P FIMC camera host interface/video postprocessor driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("2.0.1"); diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.h b/drivers/media/video/s5p-fimc/fimc-mdevice.h new file mode 100644 index 0000000..da37808 --- /dev/null +++ b/drivers/media/video/s5p-fimc/fimc-mdevice.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef FIMC_MDEVICE_H_ +#define FIMC_MDEVICE_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "fimc-core.h" +#include "mipi-csis.h" + +/* Group IDs of sensor, MIPI CSIS and the writeback subdevs. */ +#define SENSOR_GROUP_ID (1 << 8) +#define CSIS_GROUP_ID (1 << 9) +#define WRITEBACK_GROUP_ID (1 << 10) + +#define FIMC_MAX_SENSORS 8 +#define FIMC_MAX_CAMCLKS 2 + +struct fimc_csis_info { + struct v4l2_subdev *sd; + int id; +}; + +struct fimc_camclk_info { + struct clk *clock; + int use_count; + unsigned long frequency; +}; + +/** + * struct fimc_sensor_info - image data source subdev information + * @pdata: sensor's atrributes passed as media device's platform data + * @subdev: image sensor v4l2 subdev + * @host: fimc device the sensor is currently linked to + * @clk_on: sclk_cam clock's state associated with this subdev + * + * This data structure applies to image sensor and the writeback subdevs. + */ +struct fimc_sensor_info { + struct s5p_fimc_isp_info *pdata; + struct v4l2_subdev *subdev; + struct fimc_dev *host; + bool clk_on; +}; + +/** + * struct fimc_md - fimc media device information + * @csis: MIPI CSIS subdevs data + * @sensor: array of registered sensor subdevs + * @num_sensors: actual number of registered sensors + * @camclk: external sensor clock information + * @fimc: array of registered fimc devices + * @media_dev: top level media device + * @v4l2_dev: top level v4l2_device holding up the subdevs + * @pdev: platform device this media device is hooked up into + * @user_subdev_api: true if subdevs are not configured by the host driver + * @slock: spinlock protecting @sensor array + */ +struct fimc_md { + struct fimc_csis_info csis[CSIS_MAX_ENTITIES]; + struct fimc_sensor_info sensor[FIMC_MAX_SENSORS]; + int num_sensors; + struct fimc_camclk_info camclk[FIMC_MAX_CAMCLKS]; + struct fimc_dev *fimc[FIMC_MAX_DEVS]; + struct media_device media_dev; + struct v4l2_device v4l2_dev; + struct platform_device *pdev; + bool user_subdev_api; + spinlock_t slock; +}; + +#define is_subdev_pad(pad) (pad == NULL || \ + media_entity_type(pad->entity) == MEDIA_ENT_T_V4L2_SUBDEV) + +#define me_subtype(me) \ + ((me->type) & (MEDIA_ENT_TYPE_MASK | MEDIA_ENT_SUBTYPE_MASK)) + +#define subdev_has_devnode(__sd) (__sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE) + +static inline struct fimc_md *entity_to_fimc_mdev(struct media_entity *me) +{ + return me->parent == NULL ? NULL : + container_of(me->parent, struct fimc_md, media_dev); +} + +static inline void fimc_md_graph_lock(struct fimc_dev *fimc) +{ + BUG_ON(fimc->vid_cap.vfd == NULL); + mutex_lock(&fimc->vid_cap.vfd->entity.parent->graph_mutex); +} + +static inline void fimc_md_graph_unlock(struct fimc_dev *fimc) +{ + BUG_ON(fimc->vid_cap.vfd == NULL); + mutex_unlock(&fimc->vid_cap.vfd->entity.parent->graph_mutex); +} + +int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on); +void fimc_pipeline_prepare(struct fimc_dev *fimc, struct media_entity *me); +int fimc_pipeline_initialize(struct fimc_dev *fimc, struct media_entity *me, + bool resume); +int fimc_pipeline_shutdown(struct fimc_dev *fimc); +int fimc_pipeline_s_power(struct fimc_dev *fimc, int state); +int fimc_pipeline_s_stream(struct fimc_dev *fimc, int state); + +#endif diff --git a/include/media/s5p_fimc.h b/include/media/s5p_fimc.h index 9fdff8a4..086a7aa 100644 --- a/include/media/s5p_fimc.h +++ b/include/media/s5p_fimc.h @@ -36,6 +36,7 @@ struct i2c_board_info; * @csi_data_align: MIPI-CSI interface data alignment in bits * @i2c_bus_num: i2c control bus id the sensor is attached to * @mux_id: FIMC camera interface multiplexer index (separate for MIPI and ITU) + * @clk_id: index of the SoC peripheral clock for sensors * @flags: flags defining bus signals polarity inversion (High by default) */ struct s5p_fimc_isp_info { @@ -46,6 +47,7 @@ struct s5p_fimc_isp_info { u16 i2c_bus_num; u16 mux_id; u16 flags; + u8 clk_id; }; /** -- cgit v0.10.2 From e578588eb01d9493513ca1527f464715cfd3f47f Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 10 Jun 2011 15:36:50 -0300 Subject: [media] s5p-fimc: Conversion to use struct v4l2_fh This is a prerequisite for the patch converting the driver to use the control framework. As the capture driver does not use per file handle contexts, two separate ioctl handlers are created for it (vidioc_try_fmt_mplane, and vidioc_g_fmt_mplane) so there is no handlers shared between the memory-to-memory and capture video node. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index a1ac986..562b23c 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -276,7 +276,10 @@ static struct vb2_ops fimc_capture_qops = { static int fimc_capture_open(struct file *file) { struct fimc_dev *fimc = video_drvdata(file); - int ret = 0; + int ret = v4l2_fh_open(file); + + if (ret) + return ret; dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state); @@ -285,11 +288,12 @@ static int fimc_capture_open(struct file *file) return -EBUSY; ret = pm_runtime_get_sync(&fimc->pdev->dev); - if (ret) + if (ret < 0) { + v4l2_fh_release(file); return ret; + } ++fimc->vid_cap.refcnt; - file->private_data = fimc->vid_cap.ctx; return 0; } @@ -307,22 +311,20 @@ static int fimc_capture_close(struct file *file) pm_runtime_put(&fimc->pdev->dev); - return 0; + return v4l2_fh_release(file); } static unsigned int fimc_capture_poll(struct file *file, struct poll_table_struct *wait) { - struct fimc_ctx *ctx = file->private_data; - struct fimc_dev *fimc = ctx->fimc_dev; + struct fimc_dev *fimc = video_drvdata(file); return vb2_poll(&fimc->vid_cap.vbq, file, wait); } static int fimc_capture_mmap(struct file *file, struct vm_area_struct *vma) { - struct fimc_ctx *ctx = file->private_data; - struct fimc_dev *fimc = ctx->fimc_dev; + struct fimc_dev *fimc = video_drvdata(file); return vb2_mmap(&fimc->vid_cap.vbq, vma); } @@ -340,8 +342,7 @@ static const struct v4l2_file_operations fimc_capture_fops = { static int fimc_vidioc_querycap_capture(struct file *file, void *priv, struct v4l2_capability *cap) { - struct fimc_ctx *ctx = file->private_data; - struct fimc_dev *fimc = ctx->fimc_dev; + struct fimc_dev *fimc = video_drvdata(file); strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1); strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1); @@ -388,20 +389,41 @@ static int sync_capture_fmt(struct fimc_ctx *ctx) return 0; } +static int fimc_cap_g_fmt_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct fimc_dev *fimc = video_drvdata(file); + struct fimc_ctx *ctx = fimc->vid_cap.ctx; + + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + return fimc_fill_format(&ctx->d_frame, f); +} + +static int fimc_cap_try_fmt_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct fimc_dev *fimc = video_drvdata(file); + struct fimc_ctx *ctx = fimc->vid_cap.ctx; + + return fimc_try_fmt_mplane(ctx, f); +} + static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, struct v4l2_format *f) { - struct fimc_ctx *ctx = priv; - struct fimc_dev *fimc = ctx->fimc_dev; - struct fimc_frame *frame; + struct fimc_dev *fimc = video_drvdata(file); + struct fimc_ctx *ctx = fimc->vid_cap.ctx; struct v4l2_pix_format_mplane *pix; + struct fimc_frame *frame; int ret; int i; if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) return -EINVAL; - ret = fimc_vidioc_try_fmt_mplane(file, priv, f); + ret = fimc_try_fmt_mplane(ctx, f); if (ret) return ret; @@ -443,7 +465,7 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, static int fimc_cap_enum_input(struct file *file, void *priv, struct v4l2_input *i) { - struct fimc_ctx *ctx = priv; + struct fimc_dev *fimc = video_drvdata(file); if (i->index != 0) return -EINVAL; @@ -467,8 +489,8 @@ static int fimc_cap_g_input(struct file *file, void *priv, unsigned int *i) static int fimc_cap_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { - struct fimc_ctx *ctx = priv; - struct fimc_dev *fimc = ctx->fimc_dev; + struct fimc_dev *fimc = video_drvdata(file); + struct fimc_ctx *ctx = fimc->vid_cap.ctx; if (fimc_capture_active(fimc) || !fimc->vid_cap.sd) return -EBUSY; @@ -484,8 +506,7 @@ static int fimc_cap_streamon(struct file *file, void *priv, static int fimc_cap_streamoff(struct file *file, void *priv, enum v4l2_buf_type type) { - struct fimc_ctx *ctx = priv; - struct fimc_dev *fimc = ctx->fimc_dev; + struct fimc_dev *fimc = video_drvdata(file); return vb2_streamoff(&fimc->vid_cap.vbq, type); } @@ -493,47 +514,43 @@ static int fimc_cap_streamoff(struct file *file, void *priv, static int fimc_cap_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *reqbufs) { - struct fimc_ctx *ctx = priv; - struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap; - int ret; - + struct fimc_dev *fimc = video_drvdata(file); + int ret = vb2_reqbufs(&fimc->vid_cap.vbq, reqbufs); - ret = vb2_reqbufs(&cap->vbq, reqbufs); if (!ret) - cap->reqbufs_count = reqbufs->count; - + fimc->vid_cap.reqbufs_count = reqbufs->count; return ret; } static int fimc_cap_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct fimc_ctx *ctx = priv; - struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap; + struct fimc_dev *fimc = video_drvdata(file); - return vb2_querybuf(&cap->vbq, buf); + return vb2_querybuf(&fimc->vid_cap.vbq, buf); } static int fimc_cap_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct fimc_ctx *ctx = priv; - struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap; - return vb2_qbuf(&cap->vbq, buf); + struct fimc_dev *fimc = video_drvdata(file); + + return vb2_qbuf(&fimc->vid_cap.vbq, buf); } static int fimc_cap_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct fimc_ctx *ctx = priv; - return vb2_dqbuf(&ctx->fimc_dev->vid_cap.vbq, buf, - file->f_flags & O_NONBLOCK); + struct fimc_dev *fimc = video_drvdata(file); + + return vb2_dqbuf(&fimc->vid_cap.vbq, buf, file->f_flags & O_NONBLOCK); } static int fimc_cap_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) + struct v4l2_control *ctrl) { - struct fimc_ctx *ctx = priv; + struct fimc_dev *fimc = video_drvdata(file); + struct fimc_ctx *ctx = fimc->vid_cap.ctx; int ret = -EINVAL; /* Allow any controls but 90/270 rotation while streaming */ @@ -556,14 +573,12 @@ static int fimc_cap_s_ctrl(struct file *file, void *priv, static int fimc_cap_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cr) { - struct fimc_frame *f; - struct fimc_ctx *ctx = fh; + struct fimc_dev *fimc = video_drvdata(file); + struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame; if (cr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) return -EINVAL; - f = &ctx->s_frame; - cr->bounds.left = 0; cr->bounds.top = 0; cr->bounds.width = f->o_width; @@ -575,10 +590,8 @@ static int fimc_cap_cropcap(struct file *file, void *fh, static int fimc_cap_g_crop(struct file *file, void *fh, struct v4l2_crop *cr) { - struct fimc_frame *f; - struct fimc_ctx *ctx = file->private_data; - - f = &ctx->s_frame; + struct fimc_dev *fimc = video_drvdata(file); + struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame; cr->c.left = f->offs_h; cr->c.top = f->offs_v; @@ -588,12 +601,11 @@ static int fimc_cap_g_crop(struct file *file, void *fh, struct v4l2_crop *cr) return 0; } -static int fimc_cap_s_crop(struct file *file, void *fh, - struct v4l2_crop *cr) +static int fimc_cap_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) { + struct fimc_dev *fimc = video_drvdata(file); + struct fimc_ctx *ctx = fimc->vid_cap.ctx; struct fimc_frame *f; - struct fimc_ctx *ctx = file->private_data; - struct fimc_dev *fimc = ctx->fimc_dev; int ret = -EINVAL; if (fimc_capture_active(fimc)) @@ -631,9 +643,9 @@ static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = { .vidioc_querycap = fimc_vidioc_querycap_capture, .vidioc_enum_fmt_vid_cap_mplane = fimc_vidioc_enum_fmt_mplane, - .vidioc_try_fmt_vid_cap_mplane = fimc_vidioc_try_fmt_mplane, + .vidioc_try_fmt_vid_cap_mplane = fimc_cap_try_fmt_mplane, .vidioc_s_fmt_vid_cap_mplane = fimc_cap_s_fmt_mplane, - .vidioc_g_fmt_vid_cap_mplane = fimc_vidioc_g_fmt_mplane, + .vidioc_g_fmt_vid_cap_mplane = fimc_cap_g_fmt_mplane, .vidioc_reqbufs = fimc_cap_reqbufs, .vidioc_querybuf = fimc_cap_querybuf, diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 16314c9..3dab803 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -777,10 +777,10 @@ static struct vb2_ops fimc_qops = { .start_streaming = start_streaming, }; -static int fimc_m2m_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) +static int fimc_m2m_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) { - struct fimc_ctx *ctx = file->private_data; + struct fimc_ctx *ctx = fh_to_ctx(fh); struct fimc_dev *fimc = ctx->fimc_dev; strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1); @@ -808,42 +808,41 @@ int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv, return 0; } -int fimc_vidioc_g_fmt_mplane(struct file *file, void *priv, - struct v4l2_format *f) +int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f) { - struct fimc_ctx *ctx = priv; - struct fimc_frame *frame; - struct v4l2_pix_format_mplane *pixm; + struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp; int i; - frame = ctx_get_frame(ctx, f->type); - if (IS_ERR(frame)) - return PTR_ERR(frame); - - pixm = &f->fmt.pix_mp; - - pixm->width = frame->width; - pixm->height = frame->height; - pixm->field = V4L2_FIELD_NONE; - pixm->pixelformat = frame->fmt->fourcc; - pixm->colorspace = V4L2_COLORSPACE_JPEG; - pixm->num_planes = frame->fmt->memplanes; + pixm->width = frame->o_width; + pixm->height = frame->o_height; + pixm->field = V4L2_FIELD_NONE; + pixm->pixelformat = frame->fmt->fourcc; + pixm->colorspace = V4L2_COLORSPACE_JPEG; + pixm->num_planes = frame->fmt->memplanes; for (i = 0; i < pixm->num_planes; ++i) { - int bpl = frame->o_width; - + int bpl = frame->f_width; if (frame->fmt->colplanes == 1) /* packed formats */ bpl = (bpl * frame->fmt->depth[0]) / 8; - pixm->plane_fmt[i].bytesperline = bpl; - pixm->plane_fmt[i].sizeimage = (frame->o_width * frame->o_height * frame->fmt->depth[i]) / 8; } - return 0; } +static int fimc_m2m_g_fmt_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct fimc_ctx *ctx = fh_to_ctx(fh); + struct fimc_frame *frame = ctx_get_frame(ctx, f->type); + + if (IS_ERR(frame)) + return PTR_ERR(frame); + + return fimc_fill_format(frame, f); +} + struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask) { struct fimc_fmt *fmt; @@ -874,11 +873,8 @@ struct fimc_fmt *find_mbus_format(struct v4l2_mbus_framefmt *f, return (i == ARRAY_SIZE(fimc_formats)) ? NULL : fmt; } - -int fimc_vidioc_try_fmt_mplane(struct file *file, void *priv, - struct v4l2_format *f) +int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f) { - struct fimc_ctx *ctx = priv; struct fimc_dev *fimc = ctx->fimc_dev; struct samsung_fimc_variant *variant = fimc->variant; struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; @@ -957,17 +953,25 @@ int fimc_vidioc_try_fmt_mplane(struct file *file, void *priv, return 0; } -static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv, +static int fimc_m2m_try_fmt_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct fimc_ctx *ctx = fh_to_ctx(fh); + + return fimc_try_fmt_mplane(ctx, f); +} + +static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { - struct fimc_ctx *ctx = priv; + struct fimc_ctx *ctx = fh_to_ctx(fh); struct fimc_dev *fimc = ctx->fimc_dev; struct vb2_queue *vq; struct fimc_frame *frame; struct v4l2_pix_format_mplane *pix; int i, ret = 0; - ret = fimc_vidioc_try_fmt_mplane(file, priv, f); + ret = fimc_try_fmt_mplane(ctx, f); if (ret) return ret; @@ -978,15 +982,10 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv, return -EBUSY; } - if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) frame = &ctx->s_frame; - } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + else frame = &ctx->d_frame; - } else { - v4l2_err(fimc->m2m.vfd, - "Wrong buffer/video queue type (%d)\n", f->type); - return -EINVAL; - } pix = &f->fmt.pix_mp; frame->fmt = find_format(f, FMT_FLAGS_M2M); @@ -1018,39 +1017,42 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv, return 0; } -static int fimc_m2m_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *reqbufs) +static int fimc_m2m_reqbufs(struct file *file, void *fh, + struct v4l2_requestbuffers *reqbufs) { - struct fimc_ctx *ctx = priv; + struct fimc_ctx *ctx = fh_to_ctx(fh); + return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); } -static int fimc_m2m_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) +static int fimc_m2m_querybuf(struct file *file, void *fh, + struct v4l2_buffer *buf) { - struct fimc_ctx *ctx = priv; + struct fimc_ctx *ctx = fh_to_ctx(fh); + return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); } -static int fimc_m2m_qbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) +static int fimc_m2m_qbuf(struct file *file, void *fh, + struct v4l2_buffer *buf) { - struct fimc_ctx *ctx = priv; + struct fimc_ctx *ctx = fh_to_ctx(fh); return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); } -static int fimc_m2m_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) +static int fimc_m2m_dqbuf(struct file *file, void *fh, + struct v4l2_buffer *buf) { - struct fimc_ctx *ctx = priv; + struct fimc_ctx *ctx = fh_to_ctx(fh); + return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); } -static int fimc_m2m_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) +static int fimc_m2m_streamon(struct file *file, void *fh, + enum v4l2_buf_type type) { - struct fimc_ctx *ctx = priv; + struct fimc_ctx *ctx = fh_to_ctx(fh); /* The source and target color format need to be set */ if (V4L2_TYPE_IS_OUTPUT(type)) { @@ -1063,17 +1065,19 @@ static int fimc_m2m_streamon(struct file *file, void *priv, return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); } -static int fimc_m2m_streamoff(struct file *file, void *priv, +static int fimc_m2m_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) { - struct fimc_ctx *ctx = priv; + struct fimc_ctx *ctx = fh_to_ctx(fh); + return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); } -int fimc_vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) +int fimc_vidioc_queryctrl(struct file *file, void *fh, + struct v4l2_queryctrl *qc) { - struct fimc_ctx *ctx = priv; + struct fimc_ctx *ctx = fh_to_ctx(fh); + struct fimc_dev *fimc = ctx->fimc_dev; struct v4l2_queryctrl *c; int ret = -EINVAL; @@ -1090,10 +1094,9 @@ int fimc_vidioc_queryctrl(struct file *file, void *priv, return ret; } -int fimc_vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) +int fimc_vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *ctrl) { - struct fimc_ctx *ctx = priv; + struct fimc_ctx *ctx = fh_to_ctx(fh); struct fimc_dev *fimc = ctx->fimc_dev; switch (ctrl->id) { @@ -1186,10 +1189,10 @@ int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl) return 0; } -static int fimc_m2m_s_ctrl(struct file *file, void *priv, +static int fimc_m2m_s_ctrl(struct file *file, void *fh, struct v4l2_control *ctrl) { - struct fimc_ctx *ctx = priv; + struct fimc_ctx *ctx = fh_to_ctx(fh); int ret = 0; ret = check_ctrl_val(ctx, ctrl); @@ -1201,10 +1204,10 @@ static int fimc_m2m_s_ctrl(struct file *file, void *priv, } static int fimc_m2m_cropcap(struct file *file, void *fh, - struct v4l2_cropcap *cr) + struct v4l2_cropcap *cr) { + struct fimc_ctx *ctx = fh_to_ctx(fh); struct fimc_frame *frame; - struct fimc_ctx *ctx = fh; frame = ctx_get_frame(ctx, cr->type); if (IS_ERR(frame)) @@ -1221,8 +1224,8 @@ static int fimc_m2m_cropcap(struct file *file, void *fh, static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr) { + struct fimc_ctx *ctx = fh_to_ctx(fh); struct fimc_frame *frame; - struct fimc_ctx *ctx = file->private_data; frame = ctx_get_frame(ctx, cr->type); if (IS_ERR(frame)) @@ -1300,7 +1303,7 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) { - struct fimc_ctx *ctx = file->private_data; + struct fimc_ctx *ctx = fh_to_ctx(fh); struct fimc_dev *fimc = ctx->fimc_dev; struct fimc_frame *f; int ret; @@ -1347,11 +1350,11 @@ static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = { .vidioc_enum_fmt_vid_cap_mplane = fimc_vidioc_enum_fmt_mplane, .vidioc_enum_fmt_vid_out_mplane = fimc_vidioc_enum_fmt_mplane, - .vidioc_g_fmt_vid_cap_mplane = fimc_vidioc_g_fmt_mplane, - .vidioc_g_fmt_vid_out_mplane = fimc_vidioc_g_fmt_mplane, + .vidioc_g_fmt_vid_cap_mplane = fimc_m2m_g_fmt_mplane, + .vidioc_g_fmt_vid_out_mplane = fimc_m2m_g_fmt_mplane, - .vidioc_try_fmt_vid_cap_mplane = fimc_vidioc_try_fmt_mplane, - .vidioc_try_fmt_vid_out_mplane = fimc_vidioc_try_fmt_mplane, + .vidioc_try_fmt_vid_cap_mplane = fimc_m2m_try_fmt_mplane, + .vidioc_try_fmt_vid_out_mplane = fimc_m2m_try_fmt_mplane, .vidioc_s_fmt_vid_cap_mplane = fimc_m2m_s_fmt_mplane, .vidioc_s_fmt_vid_out_mplane = fimc_m2m_s_fmt_mplane, @@ -1407,7 +1410,8 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, static int fimc_m2m_open(struct file *file) { struct fimc_dev *fimc = video_drvdata(file); - struct fimc_ctx *ctx = NULL; + struct fimc_ctx *ctx; + int ret; dbg("pid: %d, state: 0x%lx, refcnt: %d", task_pid_nr(current), fimc->state, fimc->vid_cap.refcnt); @@ -1422,13 +1426,16 @@ static int fimc_m2m_open(struct file *file) ctx = kzalloc(sizeof *ctx, GFP_KERNEL); if (!ctx) return -ENOMEM; + v4l2_fh_init(&ctx->fh, fimc->m2m.vfd); + + file->private_data = &ctx->fh; + v4l2_fh_add(&ctx->fh); - file->private_data = ctx; ctx->fimc_dev = fimc; /* Default color format */ ctx->s_frame.fmt = &fimc_formats[0]; ctx->d_frame.fmt = &fimc_formats[0]; - /* Setup the device context for mem2mem mode. */ + /* Setup the device context for memory-to-memory mode */ ctx->state = FIMC_CTX_M2M; ctx->flags = 0; ctx->in_path = FIMC_DMA; @@ -1437,26 +1444,32 @@ static int fimc_m2m_open(struct file *file) ctx->m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init); if (IS_ERR(ctx->m2m_ctx)) { - int err = PTR_ERR(ctx->m2m_ctx); - kfree(ctx); - return err; + ret = PTR_ERR(ctx->m2m_ctx); + goto error_fh; } if (fimc->m2m.refcnt++ == 0) set_bit(ST_M2M_RUN, &fimc->state); - return 0; + +error_fh: + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + kfree(ctx); + return ret; } static int fimc_m2m_release(struct file *file) { - struct fimc_ctx *ctx = file->private_data; + struct fimc_ctx *ctx = fh_to_ctx(file->private_data); struct fimc_dev *fimc = ctx->fimc_dev; dbg("pid: %d, state: 0x%lx, refcnt= %d", task_pid_nr(current), fimc->state, fimc->m2m.refcnt); v4l2_m2m_ctx_release(ctx->m2m_ctx); + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); if (--fimc->m2m.refcnt <= 0) clear_bit(ST_M2M_RUN, &fimc->state); @@ -1465,9 +1478,9 @@ static int fimc_m2m_release(struct file *file) } static unsigned int fimc_m2m_poll(struct file *file, - struct poll_table_struct *wait) + struct poll_table_struct *wait) { - struct fimc_ctx *ctx = file->private_data; + struct fimc_ctx *ctx = fh_to_ctx(file->private_data); return v4l2_m2m_poll(file, ctx->m2m_ctx, wait); } @@ -1475,7 +1488,7 @@ static unsigned int fimc_m2m_poll(struct file *file, static int fimc_m2m_mmap(struct file *file, struct vm_area_struct *vma) { - struct fimc_ctx *ctx = file->private_data; + struct fimc_ctx *ctx = fh_to_ctx(file->private_data); return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); } diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 5a62349..22009fe 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -460,6 +460,7 @@ struct fimc_dev { * @state: flags to keep track of user configuration * @fimc_dev: the FIMC device this context applies to * @m2m_ctx: memory-to-memory device context + * @fh: v4l2 file handle */ struct fimc_ctx { spinlock_t slock; @@ -479,8 +480,11 @@ struct fimc_ctx { u32 state; struct fimc_dev *fimc_dev; struct v4l2_m2m_ctx *m2m_ctx; + struct v4l2_fh fh; }; +#define fh_to_ctx(__fh) container_of(__fh, struct fimc_ctx, fh) + static inline bool fimc_capture_active(struct fimc_dev *fimc) { unsigned long flags; @@ -632,18 +636,16 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc, /* fimc-core.c */ int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv, struct v4l2_fmtdesc *f); -int fimc_vidioc_g_fmt_mplane(struct file *file, void *priv, - struct v4l2_format *f); -int fimc_vidioc_try_fmt_mplane(struct file *file, void *priv, - struct v4l2_format *f); int fimc_vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *qc); int fimc_vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl); +int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f); int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr); int check_ctrl_val(struct fimc_ctx *ctx, struct v4l2_control *ctrl); int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl); +int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f); struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask); struct fimc_fmt *find_mbus_format(struct v4l2_mbus_framefmt *f, -- cgit v0.10.2 From 131b6c619758ed8fd16d26b06a423801a497b867 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 24 Aug 2011 19:25:10 -0300 Subject: [media] s5p-fimc: Convert to the new control framework Convert the v4l controls code to use the new control framework. fimc_ctrls_activate/deactivate functions are introduced for the transparent DMA transfer mode (JPEG), where the rotation and flipping controls are not supported. The capture video node does not inherit sensors' controls when the subdevs are configured by the user space (user_subdev_api == true). However by default after the driver's initialization the 'user-subdev_api' flag is false and any sensor controls will also be available at the video node. When the pipeline links are disconnected through the media device the FIMC and any sensor inherited controls are destroyed and then again created when the pipeline connection completes. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 562b23c..0c237a7 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -27,6 +27,7 @@ #include #include +#include "fimc-mdevice.h" #include "fimc-core.h" static void fimc_capture_state_cleanup(struct fimc_dev *fimc) @@ -273,6 +274,31 @@ static struct vb2_ops fimc_capture_qops = { .stop_streaming = stop_streaming, }; +/** + * fimc_capture_ctrls_create - initialize the control handler + * Initialize the capture video node control handler and fill it + * with the FIMC controls. Inherit any sensor's controls if the + * 'user_subdev_api' flag is false (default behaviour). + * This function need to be called with the graph mutex held. + */ +int fimc_capture_ctrls_create(struct fimc_dev *fimc) +{ + struct fimc_vid_cap *vid_cap = &fimc->vid_cap; + int ret; + + if (WARN_ON(vid_cap->ctx == NULL)) + return -ENXIO; + if (vid_cap->ctx->ctrls_rdy) + return 0; + + ret = fimc_ctrls_create(vid_cap->ctx); + if (ret || vid_cap->user_subdev_api) + return ret; + + return v4l2_ctrl_add_handler(&vid_cap->ctx->ctrl_handler, + fimc->pipeline.sensor->ctrl_handler); +} + static int fimc_capture_open(struct file *file) { struct fimc_dev *fimc = video_drvdata(file); @@ -293,9 +319,10 @@ static int fimc_capture_open(struct file *file) return ret; } - ++fimc->vid_cap.refcnt; + if (++fimc->vid_cap.refcnt == 1) + ret = fimc_capture_ctrls_create(fimc); - return 0; + return ret; } static int fimc_capture_close(struct file *file) @@ -306,6 +333,7 @@ static int fimc_capture_close(struct file *file) if (--fimc->vid_cap.refcnt == 0) { fimc_stop_capture(fimc); + fimc_ctrls_delete(fimc->vid_cap.ctx); vb2_queue_release(&fimc->vid_cap.vbq); } @@ -546,30 +574,6 @@ static int fimc_cap_dqbuf(struct file *file, void *priv, return vb2_dqbuf(&fimc->vid_cap.vbq, buf, file->f_flags & O_NONBLOCK); } -static int fimc_cap_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct fimc_dev *fimc = video_drvdata(file); - struct fimc_ctx *ctx = fimc->vid_cap.ctx; - int ret = -EINVAL; - - /* Allow any controls but 90/270 rotation while streaming */ - if (!fimc_capture_active(ctx->fimc_dev) || - ctrl->id != V4L2_CID_ROTATE || - (ctrl->value != 90 && ctrl->value != 270)) { - ret = check_ctrl_val(ctx, ctrl); - if (!ret) { - ret = fimc_s_ctrl(ctx, ctrl); - if (!ret) - ctx->state |= FIMC_PARAMS; - } - } - if (ret == -EINVAL) - ret = v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd, - core, s_ctrl, ctrl); - return ret; -} - static int fimc_cap_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cr) { @@ -656,10 +660,6 @@ static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = { .vidioc_streamon = fimc_cap_streamon, .vidioc_streamoff = fimc_cap_streamoff, - .vidioc_queryctrl = fimc_vidioc_queryctrl, - .vidioc_g_ctrl = fimc_vidioc_g_ctrl, - .vidioc_s_ctrl = fimc_cap_s_ctrl, - .vidioc_g_crop = fimc_cap_g_crop, .vidioc_s_crop = fimc_cap_s_crop, .vidioc_cropcap = fimc_cap_cropcap, @@ -743,6 +743,7 @@ int fimc_register_capture_device(struct fimc_dev *fimc, if (ret) goto err_ent; + vfd->ctrl_handler = &ctx->ctrl_handler; return 0; err_ent: diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 3dab803..c7ce934 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -162,43 +162,6 @@ static struct fimc_fmt fimc_formats[] = { }, }; -static struct v4l2_queryctrl fimc_ctrls[] = { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Horizontal flip", - .minimum = 0, - .maximum = 1, - .default_value = 0, - }, { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Vertical flip", - .minimum = 0, - .maximum = 1, - .default_value = 0, - }, { - .id = V4L2_CID_ROTATE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Rotation (CCW)", - .minimum = 0, - .maximum = 270, - .step = 90, - .default_value = 0, - }, -}; - - -static struct v4l2_queryctrl *get_ctrl(int id) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(fimc_ctrls); ++i) - if (id == fimc_ctrls[i].id) - return &fimc_ctrls[i]; - return NULL; -} - int fimc_check_scaler_ratio(int sw, int sh, int dw, int dh, int rot) { int tx, ty; @@ -777,6 +740,116 @@ static struct vb2_ops fimc_qops = { .start_streaming = start_streaming, }; +/* + * V4L2 controls handling + */ +#define ctrl_to_ctx(__ctrl) \ + container_of((__ctrl)->handler, struct fimc_ctx, ctrl_handler) + +static int fimc_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct fimc_ctx *ctx = ctrl_to_ctx(ctrl); + struct fimc_dev *fimc = ctx->fimc_dev; + struct samsung_fimc_variant *variant = fimc->variant; + unsigned long flags; + int ret = 0; + + if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) + return 0; + + switch (ctrl->id) { + case V4L2_CID_HFLIP: + spin_lock_irqsave(&ctx->slock, flags); + ctx->hflip = ctrl->val; + break; + + case V4L2_CID_VFLIP: + spin_lock_irqsave(&ctx->slock, flags); + ctx->vflip = ctrl->val; + break; + + case V4L2_CID_ROTATE: + if (fimc_capture_pending(fimc) || + fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) { + ret = fimc_check_scaler_ratio(ctx->s_frame.width, + ctx->s_frame.height, ctx->d_frame.width, + ctx->d_frame.height, ctrl->val); + } + if (ret) { + v4l2_err(fimc->m2m.vfd, "Out of scaler range\n"); + return -EINVAL; + } + if ((ctrl->val == 90 || ctrl->val == 270) && + !variant->has_out_rot) + return -EINVAL; + spin_lock_irqsave(&ctx->slock, flags); + ctx->rotation = ctrl->val; + break; + + default: + v4l2_err(fimc->v4l2_dev, "Invalid control: 0x%X\n", ctrl->id); + return -EINVAL; + } + ctx->state |= FIMC_PARAMS; + set_bit(ST_CAPT_APPLY_CFG, &fimc->state); + spin_unlock_irqrestore(&ctx->slock, flags); + return 0; +} + +static const struct v4l2_ctrl_ops fimc_ctrl_ops = { + .s_ctrl = fimc_s_ctrl, +}; + +int fimc_ctrls_create(struct fimc_ctx *ctx) +{ + if (ctx->ctrls_rdy) + return 0; + v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3); + + ctx->ctrl_rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + ctx->ctrl_hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + ctx->ctrl_vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops, + V4L2_CID_ROTATE, 0, 270, 90, 0); + ctx->ctrls_rdy = ctx->ctrl_handler.error == 0; + + return ctx->ctrl_handler.error; +} + +void fimc_ctrls_delete(struct fimc_ctx *ctx) +{ + if (ctx->ctrls_rdy) { + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + ctx->ctrls_rdy = false; + } +} + +void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active) +{ + if (!ctx->ctrls_rdy) + return; + + mutex_lock(&ctx->ctrl_handler.lock); + v4l2_ctrl_activate(ctx->ctrl_rotate, active); + v4l2_ctrl_activate(ctx->ctrl_hflip, active); + v4l2_ctrl_activate(ctx->ctrl_vflip, active); + + if (active) { + ctx->rotation = ctx->ctrl_rotate->val; + ctx->hflip = ctx->ctrl_hflip->val; + ctx->vflip = ctx->ctrl_vflip->val; + } else { + ctx->rotation = 0; + ctx->hflip = 0; + ctx->vflip = 0; + } + mutex_unlock(&ctx->ctrl_handler.lock); +} + +/* + * V4L2 ioctl handlers + */ static int fimc_m2m_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { @@ -1073,136 +1146,6 @@ static int fimc_m2m_streamoff(struct file *file, void *fh, return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); } -int fimc_vidioc_queryctrl(struct file *file, void *fh, - struct v4l2_queryctrl *qc) -{ - struct fimc_ctx *ctx = fh_to_ctx(fh); - struct fimc_dev *fimc = ctx->fimc_dev; - struct v4l2_queryctrl *c; - int ret = -EINVAL; - - c = get_ctrl(qc->id); - if (c) { - *qc = *c; - return 0; - } - - if (fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx)) { - return v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd, - core, queryctrl, qc); - } - return ret; -} - -int fimc_vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *ctrl) -{ - struct fimc_ctx *ctx = fh_to_ctx(fh); - struct fimc_dev *fimc = ctx->fimc_dev; - - switch (ctrl->id) { - case V4L2_CID_HFLIP: - ctrl->value = (FLIP_X_AXIS & ctx->flip) ? 1 : 0; - break; - case V4L2_CID_VFLIP: - ctrl->value = (FLIP_Y_AXIS & ctx->flip) ? 1 : 0; - break; - case V4L2_CID_ROTATE: - ctrl->value = ctx->rotation; - break; - default: - if (fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx)) { - return v4l2_subdev_call(fimc->vid_cap.sd, core, - g_ctrl, ctrl); - } else { - v4l2_err(fimc->m2m.vfd, "Invalid control\n"); - return -EINVAL; - } - } - dbg("ctrl->value= %d", ctrl->value); - - return 0; -} - -int check_ctrl_val(struct fimc_ctx *ctx, struct v4l2_control *ctrl) -{ - struct v4l2_queryctrl *c; - c = get_ctrl(ctrl->id); - if (!c) - return -EINVAL; - - if (ctrl->value < c->minimum || ctrl->value > c->maximum - || (c->step != 0 && ctrl->value % c->step != 0)) { - v4l2_err(ctx->fimc_dev->m2m.vfd, "Invalid control value\n"); - return -ERANGE; - } - - return 0; -} - -int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl) -{ - struct samsung_fimc_variant *variant = ctx->fimc_dev->variant; - struct fimc_dev *fimc = ctx->fimc_dev; - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_HFLIP: - if (ctrl->value) - ctx->flip |= FLIP_X_AXIS; - else - ctx->flip &= ~FLIP_X_AXIS; - break; - - case V4L2_CID_VFLIP: - if (ctrl->value) - ctx->flip |= FLIP_Y_AXIS; - else - ctx->flip &= ~FLIP_Y_AXIS; - break; - - case V4L2_CID_ROTATE: - if (fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) { - ret = fimc_check_scaler_ratio(ctx->s_frame.width, - ctx->s_frame.height, ctx->d_frame.width, - ctx->d_frame.height, ctrl->value); - } - - if (ret) { - v4l2_err(fimc->m2m.vfd, "Out of scaler range\n"); - return -EINVAL; - } - - /* Check for the output rotator availability */ - if ((ctrl->value == 90 || ctrl->value == 270) && - (ctx->in_path == FIMC_DMA && !variant->has_out_rot)) - return -EINVAL; - ctx->rotation = ctrl->value; - break; - - default: - v4l2_err(fimc->v4l2_dev, "Invalid control\n"); - return -EINVAL; - } - - fimc_ctx_state_lock_set(FIMC_PARAMS, ctx); - - return 0; -} - -static int fimc_m2m_s_ctrl(struct file *file, void *fh, - struct v4l2_control *ctrl) -{ - struct fimc_ctx *ctx = fh_to_ctx(fh); - int ret = 0; - - ret = check_ctrl_val(ctx, ctrl); - if (ret) - return ret; - - ret = fimc_s_ctrl(ctx, ctrl); - return 0; -} - static int fimc_m2m_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cr) { @@ -1368,10 +1311,6 @@ static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = { .vidioc_streamon = fimc_m2m_streamon, .vidioc_streamoff = fimc_m2m_streamoff, - .vidioc_queryctrl = fimc_vidioc_queryctrl, - .vidioc_g_ctrl = fimc_vidioc_g_ctrl, - .vidioc_s_ctrl = fimc_m2m_s_ctrl, - .vidioc_g_crop = fimc_m2m_g_crop, .vidioc_s_crop = fimc_m2m_s_crop, .vidioc_cropcap = fimc_m2m_cropcap @@ -1427,7 +1366,12 @@ static int fimc_m2m_open(struct file *file) if (!ctx) return -ENOMEM; v4l2_fh_init(&ctx->fh, fimc->m2m.vfd); + ret = fimc_ctrls_create(ctx); + if (ret) + goto error_fh; + /* Use separate control handler per file handle */ + ctx->fh.ctrl_handler = &ctx->ctrl_handler; file->private_data = &ctx->fh; v4l2_fh_add(&ctx->fh); @@ -1445,13 +1389,15 @@ static int fimc_m2m_open(struct file *file) ctx->m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init); if (IS_ERR(ctx->m2m_ctx)) { ret = PTR_ERR(ctx->m2m_ctx); - goto error_fh; + goto error_c; } if (fimc->m2m.refcnt++ == 0) set_bit(ST_M2M_RUN, &fimc->state); return 0; +error_c: + fimc_ctrls_delete(ctx); error_fh: v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); @@ -1468,6 +1414,7 @@ static int fimc_m2m_release(struct file *file) task_pid_nr(current), fimc->state, fimc->m2m.refcnt); v4l2_m2m_ctx_release(ctx->m2m_ctx); + fimc_ctrls_delete(ctx); v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 22009fe..1825e33 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -62,6 +63,7 @@ enum fimc_dev_flags { ST_CAPT_STREAM, ST_CAPT_SHUT, ST_CAPT_BUSY, + ST_CAPT_APPLY_CFG, }; #define fimc_m2m_active(dev) test_bit(ST_M2M_RUN, &(dev)->state) @@ -128,11 +130,6 @@ enum fimc_color_fmt { /* Y (16 ~ 235), Cb/Cr (16 ~ 240) */ #define FIMC_COLOR_RANGE_NARROW (1 << 3) -#define FLIP_NONE 0 -#define FLIP_X_AXIS 1 -#define FLIP_Y_AXIS 2 -#define FLIP_XY_AXIS (FLIP_X_AXIS | FLIP_Y_AXIS) - /** * struct fimc_fmt - the driver's internal color format data * @mbus_code: Media Bus pixel code, -1 if not applicable @@ -455,12 +452,18 @@ struct fimc_dev { * @scaler: image scaler properties * @effect: image effect * @rotation: image clockwise rotation in degrees - * @flip: image flip mode + * @hflip: indicates image horizontal flip if set + * @vflip: indicates image vertical flip if set * @flags: additional flags for image conversion * @state: flags to keep track of user configuration * @fimc_dev: the FIMC device this context applies to * @m2m_ctx: memory-to-memory device context * @fh: v4l2 file handle + * @ctrl_handler: v4l2 controls handler + * @ctrl_rotate image rotation control + * @ctrl_hflip horizontal flip control + * @ctrl_vflip vartical flip control + * @ctrls_rdy: true if the control handler is initialized */ struct fimc_ctx { spinlock_t slock; @@ -475,12 +478,18 @@ struct fimc_ctx { struct fimc_scaler scaler; struct fimc_effect effect; int rotation; - u32 flip; + unsigned int hflip:1; + unsigned int vflip:1; u32 flags; u32 state; struct fimc_dev *fimc_dev; struct v4l2_m2m_ctx *m2m_ctx; struct v4l2_fh fh; + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl *ctrl_rotate; + struct v4l2_ctrl *ctrl_hflip; + struct v4l2_ctrl *ctrl_vflip; + bool ctrls_rdy; }; #define fh_to_ctx(__fh) container_of(__fh, struct fimc_ctx, fh) @@ -636,15 +645,11 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc, /* fimc-core.c */ int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv, struct v4l2_fmtdesc *f); -int fimc_vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc); -int fimc_vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl); - int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f); int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr); -int check_ctrl_val(struct fimc_ctx *ctx, struct v4l2_control *ctrl); -int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl); +int fimc_ctrls_create(struct fimc_ctx *ctx); +void fimc_ctrls_delete(struct fimc_ctx *ctx); +void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active); int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f); struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask); @@ -667,6 +672,7 @@ void fimc_unregister_driver(void); int fimc_register_capture_device(struct fimc_dev *fimc, struct v4l2_device *v4l2_dev); void fimc_unregister_capture_device(struct fimc_dev *fimc); +int fimc_capture_ctrls_create(struct fimc_dev *fimc); int fimc_vid_cap_buf_queue(struct fimc_dev *fimc, struct fimc_vid_buffer *fimc_vb); int fimc_capture_suspend(struct fimc_dev *fimc); diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.c b/drivers/media/video/s5p-fimc/fimc-mdevice.c index 50f3fca..13ce2a4 100644 --- a/drivers/media/video/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/video/s5p-fimc/fimc-mdevice.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "fimc-core.h" @@ -649,15 +650,23 @@ static int fimc_md_link_notify(struct media_pad *source, ret = __fimc_pipeline_shutdown(fimc); fimc->pipeline.sensor = NULL; fimc->pipeline.csis = NULL; + + mutex_lock(&fimc->lock); + fimc_ctrls_delete(fimc->vid_cap.ctx); + mutex_unlock(&fimc->lock); return ret; } /* * Link activation. Enable power of pipeline elements only if the * pipeline is already in use, i.e. its video node is opened. + * Recreate the controls destroyed during the link deactivation. */ mutex_lock(&fimc->lock); - if (fimc->vid_cap.refcnt > 0) + if (fimc->vid_cap.refcnt > 0) { ret = __fimc_pipeline_initialize(fimc, source->entity, true); + if (!ret) + ret = fimc_capture_ctrls_create(fimc); + } mutex_unlock(&fimc->lock); return ret ? -EPIPE : ret; diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c index c688263..50937b4 100644 --- a/drivers/media/video/s5p-fimc/fimc-reg.c +++ b/drivers/media/video/s5p-fimc/fimc-reg.c @@ -41,19 +41,11 @@ static u32 fimc_hw_get_in_flip(struct fimc_ctx *ctx) { u32 flip = S5P_MSCTRL_FLIP_NORMAL; - switch (ctx->flip) { - case FLIP_X_AXIS: + if (ctx->hflip) flip = S5P_MSCTRL_FLIP_X_MIRROR; - break; - case FLIP_Y_AXIS: + if (ctx->vflip) flip = S5P_MSCTRL_FLIP_Y_MIRROR; - break; - case FLIP_XY_AXIS: - flip = S5P_MSCTRL_FLIP_180; - break; - default: - break; - } + if (ctx->rotation <= 90) return flip; @@ -64,19 +56,11 @@ static u32 fimc_hw_get_target_flip(struct fimc_ctx *ctx) { u32 flip = S5P_CITRGFMT_FLIP_NORMAL; - switch (ctx->flip) { - case FLIP_X_AXIS: - flip = S5P_CITRGFMT_FLIP_X_MIRROR; - break; - case FLIP_Y_AXIS: - flip = S5P_CITRGFMT_FLIP_Y_MIRROR; - break; - case FLIP_XY_AXIS: - flip = S5P_CITRGFMT_FLIP_180; - break; - default: - break; - } + if (ctx->hflip) + flip |= S5P_CITRGFMT_FLIP_X_MIRROR; + if (ctx->vflip) + flip |= S5P_CITRGFMT_FLIP_Y_MIRROR; + if (ctx->rotation <= 90) return flip; -- cgit v0.10.2 From d09a7dc887275564ea226b3b089b51c2c8b07bee Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 24 Aug 2011 19:28:18 -0300 Subject: [media] s5p-fimc: Add media operations in the capture entity driver Add the link_setup handler for the camera capture video node. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 0c237a7..95996fb 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -669,6 +669,37 @@ static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = { .vidioc_g_input = fimc_cap_g_input, }; +/* Media operations */ +static int fimc_link_setup(struct media_entity *entity, + const struct media_pad *local, + const struct media_pad *remote, u32 flags) +{ + struct video_device *vd = media_entity_to_video_device(entity); + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(remote->entity); + struct fimc_dev *fimc = video_get_drvdata(vd); + + if (WARN_ON(fimc == NULL)) + return 0; + + dbg("%s --> %s, flags: 0x%x. input: 0x%x", + local->entity->name, remote->entity->name, flags, + fimc->vid_cap.input); + + if (flags & MEDIA_LNK_FL_ENABLED) { + if (fimc->vid_cap.input != 0) + return -EBUSY; + fimc->vid_cap.input = sd->grp_id; + return 0; + } + + fimc->vid_cap.input = 0; + return 0; +} + +static const struct media_entity_operations fimc_media_ops = { + .link_setup = fimc_link_setup, +}; + /* fimc->lock must be already initialized */ int fimc_register_capture_device(struct fimc_dev *fimc, struct v4l2_device *v4l2_dev) @@ -743,6 +774,7 @@ int fimc_register_capture_device(struct fimc_dev *fimc, if (ret) goto err_ent; + vfd->entity.ops = &fimc_media_ops; vfd->ctrl_handler = &ctx->ctrl_handler; return 0; diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 1825e33..87a89f1 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -305,6 +305,7 @@ struct fimc_m2m_device { * @reqbufs_count: the number of buffers requested in REQBUFS ioctl * @input_index: input (camera sensor) index * @refcnt: driver's private reference counter + * @input: capture input type, grp_id of the attached subdev * @user_subdev_api: true if subdevs are not configured by the host driver */ struct fimc_vid_cap { @@ -323,6 +324,7 @@ struct fimc_vid_cap { unsigned int reqbufs_count; int input_index; int refcnt; + u32 input; bool user_subdev_api; }; -- cgit v0.10.2 From 9e803a0450a5973d1c252980ea69e5b171d7f0ca Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 10 Jun 2011 15:36:53 -0300 Subject: [media] s5p-fimc: Add PM helper function for streaming control Move the camera capture H/W initialization sequence to a separate function. This is needed for reuse in the following runtime PM code. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 95996fb..6c4dca0 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -30,6 +30,44 @@ #include "fimc-mdevice.h" #include "fimc-core.h" +static int fimc_init_capture(struct fimc_dev *fimc) +{ + struct fimc_ctx *ctx = fimc->vid_cap.ctx; + struct fimc_sensor_info *sensor; + unsigned long flags; + int ret = 0; + + if (fimc->pipeline.sensor == NULL || ctx == NULL) + return -ENXIO; + if (ctx->s_frame.fmt == NULL) + return -EINVAL; + + sensor = v4l2_get_subdev_hostdata(fimc->pipeline.sensor); + + spin_lock_irqsave(&fimc->slock, flags); + fimc_prepare_dma_offset(ctx, &ctx->d_frame); + fimc_set_yuv_order(ctx); + + fimc_hw_set_camera_polarity(fimc, sensor->pdata); + fimc_hw_set_camera_type(fimc, sensor->pdata); + fimc_hw_set_camera_source(fimc, sensor->pdata); + fimc_hw_set_camera_offset(fimc, &ctx->s_frame); + + ret = fimc_set_scaler_info(ctx); + if (!ret) { + fimc_hw_set_input_path(ctx); + fimc_hw_set_prescaler(ctx); + fimc_hw_set_mainscaler(ctx); + fimc_hw_set_target_format(ctx); + fimc_hw_set_rotation(ctx); + fimc_hw_set_effect(ctx); + fimc_hw_set_output_path(ctx); + fimc_hw_set_out_dma(ctx); + } + spin_unlock_irqrestore(&fimc->slock, flags); + return ret; +} + static void fimc_capture_state_cleanup(struct fimc_dev *fimc) { struct fimc_vid_cap *cap = &fimc->vid_cap; @@ -85,47 +123,17 @@ static int start_streaming(struct vb2_queue *q, unsigned int count) { struct fimc_ctx *ctx = q->drv_priv; struct fimc_dev *fimc = ctx->fimc_dev; - struct s5p_fimc_isp_info *isp_info; + struct fimc_vid_cap *vid_cap = &fimc->vid_cap; int min_bufs; int ret; fimc_hw_reset(fimc); + vid_cap->frame_count = 0; - ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_stream, 1); - if (ret && ret != -ENOIOCTLCMD) - goto error; - - ret = fimc_prepare_config(ctx, ctx->state); + ret = fimc_init_capture(fimc); if (ret) goto error; - isp_info = &fimc->pdata->isp_info[fimc->vid_cap.input_index]; - fimc_hw_set_camera_type(fimc, isp_info); - fimc_hw_set_camera_source(fimc, isp_info); - fimc_hw_set_camera_offset(fimc, &ctx->s_frame); - - if (ctx->state & FIMC_PARAMS) { - ret = fimc_set_scaler_info(ctx); - if (ret) { - err("Scaler setup error"); - goto error; - } - fimc_hw_set_input_path(ctx); - fimc_hw_set_prescaler(ctx); - fimc_hw_set_mainscaler(ctx); - fimc_hw_set_target_format(ctx); - fimc_hw_set_rotation(ctx); - fimc_hw_set_effect(ctx); - } - - fimc_hw_set_output_path(ctx); - fimc_hw_set_out_dma(ctx); - - INIT_LIST_HEAD(&fimc->vid_cap.pending_buf_q); - INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q); - fimc->vid_cap.frame_count = 0; - fimc->vid_cap.buf_index = 0; - set_bit(ST_CAPT_PEND, &fimc->state); min_bufs = fimc->vid_cap.reqbufs_count > 1 ? 2 : 1; diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index c7ce934..c5e4135 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -476,7 +476,7 @@ int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, } /* Set order for 1 and 2 plane YCBCR 4:2:2 formats. */ -static void fimc_set_yuv_order(struct fimc_ctx *ctx) +void fimc_set_yuv_order(struct fimc_ctx *ctx) { /* The one only mode supported in SoC. */ ctx->in_order_2p = S5P_FIMC_LSB_CRCB; @@ -518,7 +518,7 @@ static void fimc_set_yuv_order(struct fimc_ctx *ctx) dbg("ctx->out_order_1p= %d", ctx->out_order_1p); } -static void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f) +void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f) { struct samsung_fimc_variant *variant = ctx->fimc_dev->variant; u32 i, depth = 0; diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 87a89f1..1d2cfda 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -663,6 +663,9 @@ int fimc_set_scaler_info(struct fimc_ctx *ctx); int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags); int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, struct fimc_frame *frame, struct fimc_addr *paddr); +void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f); +void fimc_set_yuv_order(struct fimc_ctx *ctx); + int fimc_register_m2m_device(struct fimc_dev *fimc, struct v4l2_device *v4l2_dev); void fimc_unregister_m2m_device(struct fimc_dev *fimc); -- cgit v0.10.2 From cf52df8acfda9442d64ab4d3d6085877f6d88d46 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 13 Jun 2011 11:09:40 -0300 Subject: [media] s5p-fimc: Correct color format enumeration Replace fimc_find_format() and find_mbus_format() with single function that can return a pointer to the private format description based on fourcc, media bus code or index in the table. Create separate VIDIOC_ENUM_FMT ioctl handlers for video capture and mem-to-mem video node. This is needed because some formats are valid only for the video capture and some only for the mem-to-mem video node. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 6c4dca0..32c2854 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -389,6 +389,22 @@ static int fimc_vidioc_querycap_capture(struct file *file, void *priv, return 0; } +static int fimc_cap_enum_fmt_mplane(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct fimc_fmt *fmt; + + fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM | FMT_FLAGS_M2M, + f->index); + if (!fmt) + return -EINVAL; + strncpy(f->description, fmt->name, sizeof(f->description) - 1); + f->pixelformat = fmt->fourcc; + if (fmt->fourcc == V4L2_MBUS_FMT_JPEG_1X8) + f->flags |= V4L2_FMT_FLAG_COMPRESSED; + return 0; +} + /* Synchronize formats of the camera interface input and attached sensor. */ static int sync_capture_fmt(struct fimc_ctx *ctx) { @@ -407,7 +423,7 @@ static int sync_capture_fmt(struct fimc_ctx *ctx) } dbg("w: %d, h: %d, code= %d", fmt->width, fmt->height, fmt->code); - frame->fmt = find_mbus_format(fmt, FMT_FLAGS_CAM); + frame->fmt = fimc_find_format(NULL, &fmt->code, FMT_FLAGS_CAM, -1); if (!frame->fmt) { err("fimc source format not found\n"); return -EINVAL; @@ -469,12 +485,10 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, frame = &ctx->d_frame; pix = &f->fmt.pix_mp; - frame->fmt = find_format(f, FMT_FLAGS_M2M | FMT_FLAGS_CAM); - if (!frame->fmt) { - v4l2_err(fimc->vid_cap.vfd, - "Not supported capture (FIMC target) color format\n"); + frame->fmt = fimc_find_format(&pix->pixelformat, NULL, + FMT_FLAGS_M2M | FMT_FLAGS_CAM, 0); + if (WARN(frame->fmt == NULL, "Pixel format lookup failed\n")) return -EINVAL; - } for (i = 0; i < frame->fmt->colplanes; i++) { frame->payload[i] = @@ -654,7 +668,7 @@ static int fimc_cap_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = { .vidioc_querycap = fimc_vidioc_querycap_capture, - .vidioc_enum_fmt_vid_cap_mplane = fimc_vidioc_enum_fmt_mplane, + .vidioc_enum_fmt_vid_cap_mplane = fimc_cap_enum_fmt_mplane, .vidioc_try_fmt_vid_cap_mplane = fimc_cap_try_fmt_mplane, .vidioc_s_fmt_vid_cap_mplane = fimc_cap_s_fmt_mplane, .vidioc_g_fmt_vid_cap_mplane = fimc_cap_g_fmt_mplane, @@ -715,7 +729,6 @@ int fimc_register_capture_device(struct fimc_dev *fimc, struct video_device *vfd; struct fimc_vid_cap *vid_cap; struct fimc_ctx *ctx; - struct v4l2_format f; struct fimc_frame *fr; struct vb2_queue *q; int ret = -ENOMEM; @@ -730,9 +743,8 @@ int fimc_register_capture_device(struct fimc_dev *fimc, ctx->state = FIMC_CTX_CAP; /* Default format of the output frames */ - f.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32; fr = &ctx->d_frame; - fr->fmt = find_format(&f, FMT_FLAGS_M2M); + fr->fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, 0); fr->width = fr->f_width = fr->o_width = 640; fr->height = fr->f_height = fr->o_height = 480; diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index c5e4135..af808bb 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -866,18 +866,17 @@ static int fimc_m2m_querycap(struct file *file, void *fh, return 0; } -int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +static int fimc_m2m_enum_fmt_mplane(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { struct fimc_fmt *fmt; - if (f->index >= ARRAY_SIZE(fimc_formats)) + fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_M2M, f->index); + if (!fmt) return -EINVAL; - fmt = &fimc_formats[f->index]; strncpy(f->description, fmt->name, sizeof(f->description) - 1); f->pixelformat = fmt->fourcc; - return 0; } @@ -916,34 +915,36 @@ static int fimc_m2m_g_fmt_mplane(struct file *file, void *fh, return fimc_fill_format(frame, f); } -struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask) +/** + * fimc_find_format - lookup fimc color format by fourcc or media bus format + * @pixelformat: fourcc to match, ignored if null + * @mbus_code: media bus code to match, ignored if null + * @mask: the color flags to match + * @index: offset in the fimc_formats array, ignored if negative + */ +struct fimc_fmt *fimc_find_format(u32 *pixelformat, u32 *mbus_code, + unsigned int mask, int index) { - struct fimc_fmt *fmt; + struct fimc_fmt *fmt, *def_fmt = NULL; unsigned int i; + int id = 0; - for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) { - fmt = &fimc_formats[i]; - if (fmt->fourcc == f->fmt.pix_mp.pixelformat && - (fmt->flags & mask)) - break; - } - - return (i == ARRAY_SIZE(fimc_formats)) ? NULL : fmt; -} - -struct fimc_fmt *find_mbus_format(struct v4l2_mbus_framefmt *f, - unsigned int mask) -{ - struct fimc_fmt *fmt; - unsigned int i; + if (index >= ARRAY_SIZE(fimc_formats)) + return NULL; for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) { fmt = &fimc_formats[i]; - if (fmt->mbus_code == f->code && (fmt->flags & mask)) - break; + if (!(fmt->flags & mask)) + continue; + if (pixelformat && fmt->fourcc == *pixelformat) + return fmt; + if (mbus_code && fmt->mbus_code == *mbus_code) + return fmt; + if (index == id) + def_fmt = fmt; + id++; } - - return (i == ARRAY_SIZE(fimc_formats)) ? NULL : fmt; + return def_fmt; } int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f) @@ -966,7 +967,7 @@ int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f) dbg("w: %d, h: %d", pix->width, pix->height); mask = is_output ? FMT_FLAGS_M2M : FMT_FLAGS_M2M | FMT_FLAGS_CAM; - fmt = find_format(f, mask); + fmt = fimc_find_format(&pix->pixelformat, NULL, mask, -1); if (!fmt) { v4l2_err(fimc->v4l2_dev, "Fourcc format (0x%X) invalid.\n", pix->pixelformat); @@ -1061,7 +1062,8 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh, frame = &ctx->d_frame; pix = &f->fmt.pix_mp; - frame->fmt = find_format(f, FMT_FLAGS_M2M); + frame->fmt = fimc_find_format(&pix->pixelformat, NULL, + FMT_FLAGS_M2M, 0); if (!frame->fmt) return -EINVAL; @@ -1290,8 +1292,8 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = { .vidioc_querycap = fimc_m2m_querycap, - .vidioc_enum_fmt_vid_cap_mplane = fimc_vidioc_enum_fmt_mplane, - .vidioc_enum_fmt_vid_out_mplane = fimc_vidioc_enum_fmt_mplane, + .vidioc_enum_fmt_vid_cap_mplane = fimc_m2m_enum_fmt_mplane, + .vidioc_enum_fmt_vid_out_mplane = fimc_m2m_enum_fmt_mplane, .vidioc_g_fmt_vid_cap_mplane = fimc_m2m_g_fmt_mplane, .vidioc_g_fmt_vid_out_mplane = fimc_m2m_g_fmt_mplane, diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 1d2cfda..f107485 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -654,9 +654,8 @@ void fimc_ctrls_delete(struct fimc_ctx *ctx); void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active); int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f); -struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask); -struct fimc_fmt *find_mbus_format(struct v4l2_mbus_framefmt *f, - unsigned int mask); +struct fimc_fmt *fimc_find_format(u32 *pixelformat, u32 *mbus_code, + unsigned int mask, int index); int fimc_check_scaler_ratio(int sw, int sh, int dw, int dh, int rot); int fimc_set_scaler_info(struct fimc_ctx *ctx); diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.c b/drivers/media/video/s5p-fimc/fimc-mdevice.c index 13ce2a4..5bb2c0d 100644 --- a/drivers/media/video/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/video/s5p-fimc/fimc-mdevice.c @@ -194,7 +194,7 @@ int fimc_pipeline_s_stream(struct fimc_dev *fimc, int on) if ((on && p->csis) || !on) ret = v4l2_subdev_call(on ? p->csis : p->sensor, video, s_stream, on); - if (ret && ret != -ENOIOCTLCMD) + if (ret < 0 && ret != -ENOIOCTLCMD) return ret; if ((!on && p->csis) || on) ret = v4l2_subdev_call(on ? p->sensor : p->csis, -- cgit v0.10.2 From 4db5e27ed9401a635b3c10994f2971c0441e3c90 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 26 Aug 2011 14:51:00 -0300 Subject: [media] s5p-fimc: Convert to use media pipeline operations In the camera capture driver use fimc_pipeline_* calls provided by the media device driver part, in place where v4l2_subdev_call() were used. This way the capture driver don't need to differentiate between various H/W pipeline setups, i.e. if the MIPI-CSI receiver subdev is used or not. Remove the sync_capture_fmt() function instead of which fimc_pipeline_try_format() is introduced in the following patch adding the FIMC capture subdev. The TRY_FMT ioctl function is completed by a subsequent patch adding the capture subdev, so the try_fmt routines can be reused in the subdev and the video node ioctl handlers. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 32c2854..f0fed61 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -68,7 +68,7 @@ static int fimc_init_capture(struct fimc_dev *fimc) return ret; } -static void fimc_capture_state_cleanup(struct fimc_dev *fimc) +static int fimc_capture_state_cleanup(struct fimc_dev *fimc) { struct fimc_vid_cap *cap = &fimc->vid_cap; struct fimc_vid_buffer *buf; @@ -76,7 +76,8 @@ static void fimc_capture_state_cleanup(struct fimc_dev *fimc) spin_lock_irqsave(&fimc->slock, flags); fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_PEND | - 1 << ST_CAPT_SHUT | 1 << ST_CAPT_STREAM); + 1 << ST_CAPT_SHUT | 1 << ST_CAPT_STREAM | + 1 << ST_CAPT_ISP_STREAM); fimc->vid_cap.active_buf_cnt = 0; @@ -92,6 +93,11 @@ static void fimc_capture_state_cleanup(struct fimc_dev *fimc) } spin_unlock_irqrestore(&fimc->slock, flags); + + if (test_bit(ST_CAPT_ISP_STREAM, &fimc->state)) + return fimc_pipeline_s_stream(fimc, 0); + else + return 0; } static int fimc_stop_capture(struct fimc_dev *fimc) @@ -111,11 +117,7 @@ static int fimc_stop_capture(struct fimc_dev *fimc) !test_bit(ST_CAPT_SHUT, &fimc->state), FIMC_SHUTDOWN_TIMEOUT); - v4l2_subdev_call(cap->sd, video, s_stream, 0); - - fimc_capture_state_cleanup(fimc); - dbg("state: 0x%lx", fimc->state); - return 0; + return fimc_capture_state_cleanup(fimc); } @@ -138,9 +140,14 @@ static int start_streaming(struct vb2_queue *q, unsigned int count) min_bufs = fimc->vid_cap.reqbufs_count > 1 ? 2 : 1; - if (fimc->vid_cap.active_buf_cnt >= min_bufs) + if (vid_cap->active_buf_cnt >= min_bufs && + !test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) { fimc_activate_capture(ctx); + if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state)) + fimc_pipeline_s_stream(fimc, 1); + } + return 0; error: fimc_capture_state_cleanup(fimc); @@ -202,11 +209,11 @@ static int buffer_prepare(struct vb2_buffer *vb) struct fimc_ctx *ctx = vq->drv_priv; int i; - if (!ctx->d_frame.fmt || vq->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + if (ctx->d_frame.fmt == NULL) return -EINVAL; for (i = 0; i < ctx->d_frame.fmt->memplanes; i++) { - unsigned long size = get_plane_size(&ctx->d_frame, i); + unsigned long size = ctx->d_frame.payload[i]; if (vb2_plane_size(vb, i) < size) { v4l2_err(ctx->fimc_dev->vid_cap.vfd, @@ -214,7 +221,6 @@ static int buffer_prepare(struct vb2_buffer *vb) vb2_plane_size(vb, i), size); return -EINVAL; } - vb2_set_plane_payload(vb, i, size); } @@ -223,10 +229,10 @@ static int buffer_prepare(struct vb2_buffer *vb) static void buffer_queue(struct vb2_buffer *vb) { - struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct fimc_dev *fimc = ctx->fimc_dev; struct fimc_vid_buffer *buf = container_of(vb, struct fimc_vid_buffer, vb); + struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct fimc_dev *fimc = ctx->fimc_dev; struct fimc_vid_cap *vid_cap = &fimc->vid_cap; unsigned long flags; int min_bufs; @@ -252,11 +258,17 @@ static void buffer_queue(struct vb2_buffer *vb) min_bufs = vid_cap->reqbufs_count > 1 ? 2 : 1; + if (vb2_is_streaming(&vid_cap->vbq) && vid_cap->active_buf_cnt >= min_bufs && - !test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) + !test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) { fimc_activate_capture(ctx); + spin_unlock_irqrestore(&fimc->slock, flags); + if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state)) + fimc_pipeline_s_stream(fimc, 1); + return; + } spin_unlock_irqrestore(&fimc->slock, flags); } @@ -321,15 +333,21 @@ static int fimc_capture_open(struct file *file) if (fimc_m2m_active(fimc)) return -EBUSY; - ret = pm_runtime_get_sync(&fimc->pdev->dev); - if (ret < 0) { - v4l2_fh_release(file); - return ret; - } - - if (++fimc->vid_cap.refcnt == 1) + pm_runtime_get_sync(&fimc->pdev->dev); + + if (++fimc->vid_cap.refcnt == 1) { + ret = fimc_pipeline_initialize(fimc, + &fimc->vid_cap.vfd->entity, true); + if (ret < 0) { + dev_err(&fimc->pdev->dev, + "Video pipeline initialization failed\n"); + pm_runtime_put_sync(&fimc->pdev->dev); + fimc->vid_cap.refcnt--; + v4l2_fh_release(file); + return ret; + } ret = fimc_capture_ctrls_create(fimc); - + } return ret; } @@ -341,6 +359,7 @@ static int fimc_capture_close(struct file *file) if (--fimc->vid_cap.refcnt == 0) { fimc_stop_capture(fimc); + fimc_pipeline_shutdown(fimc); fimc_ctrls_delete(fimc->vid_cap.ctx); vb2_queue_release(&fimc->vid_cap.vbq); } @@ -405,41 +424,11 @@ static int fimc_cap_enum_fmt_mplane(struct file *file, void *priv, return 0; } -/* Synchronize formats of the camera interface input and attached sensor. */ -static int sync_capture_fmt(struct fimc_ctx *ctx) -{ - struct fimc_frame *frame = &ctx->s_frame; - struct fimc_dev *fimc = ctx->fimc_dev; - struct v4l2_mbus_framefmt *fmt = &fimc->vid_cap.fmt; - int ret; - fmt->width = ctx->d_frame.o_width; - fmt->height = ctx->d_frame.o_height; - ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_mbus_fmt, fmt); - if (ret == -ENOIOCTLCMD) { - err("s_mbus_fmt failed"); - return ret; - } - dbg("w: %d, h: %d, code= %d", fmt->width, fmt->height, fmt->code); - frame->fmt = fimc_find_format(NULL, &fmt->code, FMT_FLAGS_CAM, -1); - if (!frame->fmt) { - err("fimc source format not found\n"); - return -EINVAL; - } - frame->f_width = fmt->width; - frame->f_height = fmt->height; - frame->width = fmt->width; - frame->height = fmt->height; - frame->o_width = fmt->width; - frame->o_height = fmt->height; - frame->offs_h = 0; - frame->offs_v = 0; - return 0; -} static int fimc_cap_g_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) @@ -459,7 +448,7 @@ static int fimc_cap_try_fmt_mplane(struct file *file, void *fh, struct fimc_dev *fimc = video_drvdata(file); struct fimc_ctx *ctx = fimc->vid_cap.ctx; - return fimc_try_fmt_mplane(ctx, f); + return 0; } static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, @@ -475,10 +464,6 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) return -EINVAL; - ret = fimc_try_fmt_mplane(ctx, f); - if (ret) - return ret; - if (vb2_is_busy(&fimc->vid_cap.vbq) || fimc_capture_active(fimc)) return -EBUSY; @@ -508,7 +493,6 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, ctx->state |= (FIMC_PARAMS | FIMC_DST_FMT); - ret = sync_capture_fmt(ctx); return ret; } @@ -516,12 +500,14 @@ static int fimc_cap_enum_input(struct file *file, void *priv, struct v4l2_input *i) { struct fimc_dev *fimc = video_drvdata(file); + struct v4l2_subdev *sd = fimc->pipeline.sensor; if (i->index != 0) return -EINVAL; - i->type = V4L2_INPUT_TYPE_CAMERA; + if (sd) + strlcpy(i->name, sd->name, sizeof(i->name)); return 0; } @@ -541,14 +527,16 @@ static int fimc_cap_streamon(struct file *file, void *priv, { struct fimc_dev *fimc = video_drvdata(file); struct fimc_ctx *ctx = fimc->vid_cap.ctx; + struct fimc_pipeline *p = &fimc->pipeline; - if (fimc_capture_active(fimc) || !fimc->vid_cap.sd) + if (fimc_capture_active(fimc)) return -EBUSY; if (!(ctx->state & FIMC_DST_FMT)) { v4l2_err(fimc->vid_cap.vfd, "Format is not set\n"); return -EINVAL; } + media_entity_pipeline_start(&p->sensor->entity, p->pipe); return vb2_streamon(&fimc->vid_cap.vbq, type); } @@ -557,8 +545,13 @@ static int fimc_cap_streamoff(struct file *file, void *priv, enum v4l2_buf_type type) { struct fimc_dev *fimc = video_drvdata(file); + struct v4l2_subdev *sd = fimc->pipeline.sensor; + int ret; - return vb2_streamoff(&fimc->vid_cap.vbq, type); + ret = vb2_streamoff(&fimc->vid_cap.vbq, type); + if (ret == 0) + media_entity_pipeline_stop(&sd->entity); + return ret; } static int fimc_cap_reqbufs(struct file *file, void *priv, @@ -664,7 +657,6 @@ static int fimc_cap_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) return 0; } - static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = { .vidioc_querycap = fimc_vidioc_querycap_capture, @@ -770,8 +762,6 @@ int fimc_register_capture_device(struct fimc_dev *fimc, vid_cap->active_buf_cnt = 0; vid_cap->reqbufs_count = 0; vid_cap->refcnt = 0; - /* Default color format for image sensor */ - vid_cap->fmt.code = V4L2_MBUS_FMT_YUYV8_2X8; INIT_LIST_HEAD(&vid_cap->pending_buf_q); INIT_LIST_HEAD(&vid_cap->active_buf_q); diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index af808bb..605eb46 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -903,6 +903,60 @@ int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f) return 0; } +void fimc_fill_frame(struct fimc_frame *frame, struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp; + + frame->f_width = pixm->plane_fmt[0].bytesperline; + if (frame->fmt->colplanes == 1) + frame->f_width = (frame->f_width * 8) / frame->fmt->depth[0]; + frame->f_height = pixm->height; + frame->width = pixm->width; + frame->height = pixm->height; + frame->o_width = pixm->width; + frame->o_height = pixm->height; + frame->offs_h = 0; + frame->offs_v = 0; +} + +/** + * fimc_adjust_mplane_format - adjust bytesperline/sizeimage for each plane + * @fmt: fimc pixel format description (input) + * @width: requested pixel width + * @height: requested pixel height + * @pix: multi-plane format to adjust + */ +void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height, + struct v4l2_pix_format_mplane *pix) +{ + u32 bytesperline = 0; + int i; + + pix->colorspace = V4L2_COLORSPACE_JPEG; + pix->field = V4L2_FIELD_NONE; + pix->num_planes = fmt->memplanes; + pix->height = height; + pix->width = width; + + for (i = 0; i < pix->num_planes; ++i) { + u32 bpl = pix->plane_fmt[i].bytesperline; + u32 *sizeimage = &pix->plane_fmt[i].sizeimage; + + if (fmt->colplanes > 1 && (bpl == 0 || bpl < pix->width)) + bpl = pix->width; /* Planar */ + + if (fmt->colplanes == 1 && /* Packed */ + (bpl == 0 || ((bpl * 8) / fmt->depth[i]) < pix->width)) + bpl = (pix->width * fmt->depth[0]) / 8; + + if (i == 0) /* Same bytesperline for each plane. */ + bytesperline = bpl; + + pix->plane_fmt[i].bytesperline = bytesperline; + *sizeimage = (pix->width * pix->height * fmt->depth[i]) / 8; + } +} + static int fimc_m2m_g_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { @@ -947,43 +1001,33 @@ struct fimc_fmt *fimc_find_format(u32 *pixelformat, u32 *mbus_code, return def_fmt; } -int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f) +static int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f) { struct fimc_dev *fimc = ctx->fimc_dev; struct samsung_fimc_variant *variant = fimc->variant; struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; struct fimc_fmt *fmt; - u32 max_width, mod_x, mod_y, mask; - int i, is_output = 0; + u32 max_w, mod_x, mod_y; - if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - if (fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx)) - return -EINVAL; - is_output = 1; - } else if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + if (!IS_M2M(f->type)) return -EINVAL; - } dbg("w: %d, h: %d", pix->width, pix->height); - mask = is_output ? FMT_FLAGS_M2M : FMT_FLAGS_M2M | FMT_FLAGS_CAM; - fmt = fimc_find_format(&pix->pixelformat, NULL, mask, -1); - if (!fmt) { - v4l2_err(fimc->v4l2_dev, "Fourcc format (0x%X) invalid.\n", - pix->pixelformat); + fmt = fimc_find_format(&pix->pixelformat, NULL, FMT_FLAGS_M2M, 0); + if (WARN(fmt == NULL, "Pixel format lookup failed")) return -EINVAL; - } if (pix->field == V4L2_FIELD_ANY) pix->field = V4L2_FIELD_NONE; - else if (V4L2_FIELD_NONE != pix->field) + else if (pix->field != V4L2_FIELD_NONE) return -EINVAL; - if (is_output) { - max_width = variant->pix_limit->scaler_dis_w; + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + max_w = variant->pix_limit->scaler_dis_w; mod_x = ffs(variant->min_inp_pixsize) - 1; } else { - max_width = variant->pix_limit->out_rot_dis_w; + max_w = variant->pix_limit->out_rot_dis_w; mod_x = ffs(variant->min_out_pixsize) - 1; } @@ -996,34 +1040,12 @@ int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f) else mod_y = mod_x; } + dbg("mod_x: %d, mod_y: %d, max_w: %d", mod_x, mod_y, max_w); - dbg("mod_x: %d, mod_y: %d, max_w: %d", mod_x, mod_y, max_width); - - v4l_bound_align_image(&pix->width, 16, max_width, mod_x, + v4l_bound_align_image(&pix->width, 16, max_w, mod_x, &pix->height, 8, variant->pix_limit->scaler_dis_w, mod_y, 0); - pix->num_planes = fmt->memplanes; - pix->colorspace = V4L2_COLORSPACE_JPEG; - - - for (i = 0; i < pix->num_planes; ++i) { - u32 bpl = pix->plane_fmt[i].bytesperline; - u32 *sizeimage = &pix->plane_fmt[i].sizeimage; - - if (fmt->colplanes > 1 && (bpl == 0 || bpl < pix->width)) - bpl = pix->width; /* Planar */ - - if (fmt->colplanes == 1 && /* Packed */ - (bpl == 0 || ((bpl * 8) / fmt->depth[i]) < pix->width)) - bpl = (pix->width * fmt->depth[0]) / 8; - - if (i == 0) /* Same bytesperline for each plane. */ - mod_x = bpl; - - pix->plane_fmt[i].bytesperline = mod_x; - *sizeimage = (pix->width * pix->height * fmt->depth[i]) / 8; - } - + fimc_adjust_mplane_format(fmt, pix->width, pix->height, &f->fmt.pix_mp); return 0; } @@ -1072,15 +1094,7 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh, (pix->width * pix->height * frame->fmt->depth[i]) / 8; } - frame->f_width = pix->plane_fmt[0].bytesperline * 8 / - frame->fmt->depth[0]; - frame->f_height = pix->height; - frame->width = pix->width; - frame->height = pix->height; - frame->o_width = pix->width; - frame->o_height = pix->height; - frame->offs_h = 0; - frame->offs_v = 0; + fimc_fill_frame(frame, f); if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) fimc_ctx_state_lock_set(FIMC_PARAMS | FIMC_DST_FMT, ctx); @@ -1160,8 +1174,8 @@ static int fimc_m2m_cropcap(struct file *file, void *fh, cr->bounds.left = 0; cr->bounds.top = 0; - cr->bounds.width = frame->f_width; - cr->bounds.height = frame->f_height; + cr->bounds.width = frame->o_width; + cr->bounds.height = frame->o_height; cr->defrect = cr->bounds; return 0; @@ -1612,7 +1626,6 @@ static int fimc_probe(struct platform_device *pdev) init_waitqueue_head(&fimc->irq_queue); spin_lock_init(&fimc->slock); - mutex_init(&fimc->lock); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index f107485..2935068 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -61,6 +61,7 @@ enum fimc_dev_flags { ST_CAPT_PEND, ST_CAPT_RUN, ST_CAPT_STREAM, + ST_CAPT_ISP_STREAM, ST_CAPT_SHUT, ST_CAPT_BUSY, ST_CAPT_APPLY_CFG, @@ -95,6 +96,9 @@ enum fimc_color_fmt { #define fimc_fmt_is_rgb(x) ((x) & 0x10) +#define IS_M2M(__strt) ((__strt) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE || \ + __strt == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + /* Cb/Cr chrominance components order for 2 plane Y/CbCr 4:2:2 formats. */ #define S5P_FIMC_LSB_CRCB S5P_CIOCTRL_ORDER422_2P_LSB_CRCB @@ -293,7 +297,6 @@ struct fimc_m2m_device { * struct fimc_vid_cap - camera capture device information * @ctx: hardware context data * @vfd: video device node for camera capture mode - * @sd: pointer to camera sensor subdevice currently in use * @vd_pad: fimc video capture node pad * @fmt: Media Bus format configured at selected image sensor * @pending_buf_q: the pending buffer queue head @@ -312,7 +315,6 @@ struct fimc_vid_cap { struct fimc_ctx *ctx; struct vb2_alloc_ctx *alloc_ctx; struct video_device *vfd; - struct v4l2_subdev *sd;; struct media_pad vd_pad; struct v4l2_mbus_framefmt fmt; struct list_head pending_buf_q; @@ -647,13 +649,13 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc, /* fimc-core.c */ int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv, struct v4l2_fmtdesc *f); -int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f); int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr); int fimc_ctrls_create(struct fimc_ctx *ctx); void fimc_ctrls_delete(struct fimc_ctx *ctx); void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active); int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f); - +void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height, + struct v4l2_pix_format_mplane *pix); struct fimc_fmt *fimc_find_format(u32 *pixelformat, u32 *mbus_code, unsigned int mask, int index); @@ -664,6 +666,7 @@ int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, struct fimc_frame *frame, struct fimc_addr *paddr); void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f); void fimc_set_yuv_order(struct fimc_ctx *ctx); +void fimc_fill_frame(struct fimc_frame *frame, struct v4l2_format *f); int fimc_register_m2m_device(struct fimc_dev *fimc, struct v4l2_device *v4l2_dev); -- cgit v0.10.2 From 237e026559b7cd03fc575b6007cea11aef9e0aa6 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 24 Aug 2011 20:35:30 -0300 Subject: [media] s5p-fimc: Add subdev for the FIMC processing block Add a subdev to expose the host's scaling and composition functions. The camera frame composition onto an output buffer may be configured through set/get_crop at FIMC.{n} source pad. Additionally allow crop, composition and controls to be modified during streaming. Make sure the default format is set when opening the video capture node. Rename struct fimc_vid_cap::fmt to more relevant 'mf' to avoid confusion. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index f0fed61..62fd8a1 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -63,6 +63,7 @@ static int fimc_init_capture(struct fimc_dev *fimc) fimc_hw_set_effect(ctx); fimc_hw_set_output_path(ctx); fimc_hw_set_out_dma(ctx); + clear_bit(ST_CAPT_APPLY_CFG, &fimc->state); } spin_unlock_irqrestore(&fimc->slock, flags); return ret; @@ -120,6 +121,36 @@ static int fimc_stop_capture(struct fimc_dev *fimc) return fimc_capture_state_cleanup(fimc); } +/** + * fimc_capture_config_update - apply the camera interface configuration + * + * To be called from within the interrupt handler with fimc.slock + * spinlock held. It updates the camera pixel crop, rotation and + * image flip in H/W. + */ +int fimc_capture_config_update(struct fimc_ctx *ctx) +{ + struct fimc_dev *fimc = ctx->fimc_dev; + int ret; + + if (test_bit(ST_CAPT_APPLY_CFG, &fimc->state)) + return 0; + + spin_lock(&ctx->slock); + fimc_hw_set_camera_offset(fimc, &ctx->s_frame); + ret = fimc_set_scaler_info(ctx); + if (ret == 0) { + fimc_hw_set_prescaler(ctx); + fimc_hw_set_mainscaler(ctx); + fimc_hw_set_target_format(ctx); + fimc_hw_set_rotation(ctx); + fimc_prepare_dma_offset(ctx, &ctx->d_frame); + fimc_hw_set_out_dma(ctx); + set_bit(ST_CAPT_APPLY_CFG, &fimc->state); + } + spin_unlock(&ctx->slock); + return ret; +} static int start_streaming(struct vb2_queue *q, unsigned int count) { @@ -319,6 +350,8 @@ int fimc_capture_ctrls_create(struct fimc_dev *fimc) fimc->pipeline.sensor->ctrl_handler); } +static int fimc_capture_set_default_format(struct fimc_dev *fimc); + static int fimc_capture_open(struct file *file) { struct fimc_dev *fimc = video_drvdata(file); @@ -347,6 +380,9 @@ static int fimc_capture_open(struct file *file) return ret; } ret = fimc_capture_ctrls_create(fimc); + + if (!ret && !fimc->vid_cap.user_subdev_api) + ret = fimc_capture_set_default_format(fimc); } return ret; } @@ -384,7 +420,6 @@ static int fimc_capture_mmap(struct file *file, struct vm_area_struct *vma) return vb2_mmap(&fimc->vid_cap.vbq, vma); } -/* video device file operations */ static const struct v4l2_file_operations fimc_capture_fops = { .owner = THIS_MODULE, .open = fimc_capture_open, @@ -394,6 +429,147 @@ static const struct v4l2_file_operations fimc_capture_fops = { .mmap = fimc_capture_mmap, }; +/* + * Format and crop negotiation helpers + */ + +static struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx, + u32 *width, u32 *height, + u32 *code, u32 *fourcc, int pad) +{ + bool rotation = ctx->rotation == 90 || ctx->rotation == 270; + struct fimc_dev *fimc = ctx->fimc_dev; + struct samsung_fimc_variant *var = fimc->variant; + struct fimc_pix_limit *pl = var->pix_limit; + struct fimc_frame *dst = &ctx->d_frame; + u32 depth, min_w, max_w, min_h, align_h = 3; + u32 mask = FMT_FLAGS_CAM; + struct fimc_fmt *ffmt; + + /* Color conversion from/to JPEG is not supported */ + if (code && ctx->s_frame.fmt && pad == FIMC_SD_PAD_SOURCE && + fimc_fmt_is_jpeg(ctx->s_frame.fmt->color)) + *code = V4L2_MBUS_FMT_JPEG_1X8; + + if (fourcc && *fourcc != V4L2_PIX_FMT_JPEG && pad != FIMC_SD_PAD_SINK) + mask |= FMT_FLAGS_M2M; + + ffmt = fimc_find_format(fourcc, code, mask, 0); + if (WARN_ON(!ffmt)) + return NULL; + if (code) + *code = ffmt->mbus_code; + if (fourcc) + *fourcc = ffmt->fourcc; + + if (pad == FIMC_SD_PAD_SINK) { + max_w = fimc_fmt_is_jpeg(ffmt->color) ? + pl->scaler_dis_w : pl->scaler_en_w; + /* Apply the camera input interface pixel constraints */ + v4l_bound_align_image(width, max_t(u32, *width, 32), max_w, 4, + height, max_t(u32, *height, 32), + FIMC_CAMIF_MAX_HEIGHT, + fimc_fmt_is_jpeg(ffmt->color) ? 3 : 1, + 0); + return ffmt; + } + /* Can't scale or crop in transparent (JPEG) transfer mode */ + if (fimc_fmt_is_jpeg(ffmt->color)) { + *width = ctx->s_frame.f_width; + *height = ctx->s_frame.f_height; + return ffmt; + } + /* Apply the scaler and the output DMA constraints */ + max_w = rotation ? pl->out_rot_en_w : pl->out_rot_dis_w; + min_w = ctx->state & FIMC_DST_CROP ? dst->width : var->min_out_pixsize; + min_h = ctx->state & FIMC_DST_CROP ? dst->height : var->min_out_pixsize; + if (fimc->id == 1 && var->pix_hoff) + align_h = fimc_fmt_is_rgb(ffmt->color) ? 0 : 1; + + depth = fimc_get_format_depth(ffmt); + v4l_bound_align_image(width, min_w, max_w, + ffs(var->min_out_pixsize) - 1, + height, min_h, FIMC_CAMIF_MAX_HEIGHT, + align_h, + 64/(ALIGN(depth, 8))); + + dbg("pad%d: code: 0x%x, %dx%d. dst fmt: %dx%d", + pad, code ? *code : 0, *width, *height, + dst->f_width, dst->f_height); + + return ffmt; +} + +static void fimc_capture_try_crop(struct fimc_ctx *ctx, struct v4l2_rect *r, + int pad) +{ + bool rotate = ctx->rotation == 90 || ctx->rotation == 270; + struct fimc_dev *fimc = ctx->fimc_dev; + struct samsung_fimc_variant *var = fimc->variant; + struct fimc_pix_limit *pl = var->pix_limit; + struct fimc_frame *sink = &ctx->s_frame; + u32 max_w, max_h, min_w = 0, min_h = 0, min_sz; + u32 align_sz = 0, align_h = 4; + u32 max_sc_h, max_sc_v; + + /* In JPEG transparent transfer mode cropping is not supported */ + if (fimc_fmt_is_jpeg(ctx->d_frame.fmt->color)) { + r->width = sink->f_width; + r->height = sink->f_height; + r->left = r->top = 0; + return; + } + if (pad == FIMC_SD_PAD_SOURCE) { + if (ctx->rotation != 90 && ctx->rotation != 270) + align_h = 1; + max_sc_h = min(SCALER_MAX_HRATIO, 1 << (ffs(sink->width) - 3)); + max_sc_v = min(SCALER_MAX_VRATIO, 1 << (ffs(sink->height) - 1)); + min_sz = var->min_out_pixsize; + } else { + u32 depth = fimc_get_format_depth(sink->fmt); + align_sz = 64/ALIGN(depth, 8); + min_sz = var->min_inp_pixsize; + min_w = min_h = min_sz; + max_sc_h = max_sc_v = 1; + } + /* + * For the crop rectangle at source pad the following constraints + * must be met: + * - it must fit in the sink pad format rectangle (f_width/f_height); + * - maximum downscaling ratio is 64; + * - maximum crop size depends if the rotator is used or not; + * - the sink pad format width/height must be 4 multiple of the + * prescaler ratios determined by sink pad size and source pad crop, + * the prescaler ratio is returned by fimc_get_scaler_factor(). + */ + max_w = min_t(u32, + rotate ? pl->out_rot_en_w : pl->out_rot_dis_w, + rotate ? sink->f_height : sink->f_width); + max_h = min_t(u32, FIMC_CAMIF_MAX_HEIGHT, sink->f_height); + if (pad == FIMC_SD_PAD_SOURCE) { + min_w = min_t(u32, max_w, sink->f_width / max_sc_h); + min_h = min_t(u32, max_h, sink->f_height / max_sc_v); + if (rotate) { + swap(max_sc_h, max_sc_v); + swap(min_w, min_h); + } + } + v4l_bound_align_image(&r->width, min_w, max_w, ffs(min_sz) - 1, + &r->height, min_h, max_h, align_h, + align_sz); + /* Adjust left/top if cropping rectangle is out of bounds */ + r->left = clamp_t(u32, r->left, 0, sink->f_width - r->width); + r->top = clamp_t(u32, r->top, 0, sink->f_height - r->height); + r->left = round_down(r->left, var->hor_offs_align); + + dbg("pad%d: (%d,%d)/%dx%d, sink fmt: %dx%d", + pad, r->left, r->top, r->width, r->height, + sink->f_width, sink->f_height); +} + +/* + * The video node ioctl operations + */ static int fimc_vidioc_querycap_capture(struct file *file, void *priv, struct v4l2_capability *cap) { @@ -424,11 +600,81 @@ static int fimc_cap_enum_fmt_mplane(struct file *file, void *priv, return 0; } +/** + * fimc_pipeline_try_format - negotiate and/or set formats at pipeline + * elements + * @ctx: FIMC capture context + * @tfmt: media bus format to try/set on subdevs + * @fmt_id: fimc pixel format id corresponding to returned @tfmt (output) + * @set: true to set format on subdevs, false to try only + */ +static int fimc_pipeline_try_format(struct fimc_ctx *ctx, + struct v4l2_mbus_framefmt *tfmt, + struct fimc_fmt **fmt_id, + bool set) +{ + struct fimc_dev *fimc = ctx->fimc_dev; + struct v4l2_subdev *sd = fimc->pipeline.sensor; + struct v4l2_subdev *csis = fimc->pipeline.csis; + struct v4l2_subdev_format sfmt; + struct v4l2_mbus_framefmt *mf = &sfmt.format; + struct fimc_fmt *ffmt = NULL; + int ret, i = 0; + + if (WARN_ON(!sd || !tfmt)) + return -EINVAL; + memset(&sfmt, 0, sizeof(sfmt)); + sfmt.format = *tfmt; + + sfmt.which = set ? V4L2_SUBDEV_FORMAT_ACTIVE : V4L2_SUBDEV_FORMAT_TRY; + while (1) { + ffmt = fimc_find_format(NULL, mf->code != 0 ? &mf->code : NULL, + FMT_FLAGS_CAM, i++); + if (ffmt == NULL) { + /* + * Notify user-space if common pixel code for + * host and sensor does not exist. + */ + return -EINVAL; + } + mf->code = tfmt->code = ffmt->mbus_code; + ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &sfmt); + if (ret) + return ret; + if (mf->code != tfmt->code) { + mf->code = 0; + continue; + } + if (mf->width != tfmt->width || mf->width != tfmt->width) { + u32 fcc = ffmt->fourcc; + tfmt->width = mf->width; + tfmt->height = mf->height; + ffmt = fimc_capture_try_format(ctx, + &tfmt->width, &tfmt->height, + NULL, &fcc, FIMC_SD_PAD_SOURCE); + if (ffmt && ffmt->mbus_code) + mf->code = ffmt->mbus_code; + if (mf->width != tfmt->width || mf->width != tfmt->width) + continue; + tfmt->code = mf->code; + } + if (csis) + ret = v4l2_subdev_call(csis, pad, set_fmt, NULL, &sfmt); + if (mf->code == tfmt->code && + mf->width == tfmt->width && mf->width == tfmt->width) + break; + } + if (fmt_id && ffmt) + *fmt_id = ffmt; + *tfmt = *mf; + dbg("code: 0x%x, %dx%d, %p", mf->code, mf->width, mf->height, ffmt); + return 0; +} static int fimc_cap_g_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) @@ -445,55 +691,114 @@ static int fimc_cap_g_fmt_mplane(struct file *file, void *fh, static int fimc_cap_try_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { + struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; struct fimc_dev *fimc = video_drvdata(file); struct fimc_ctx *ctx = fimc->vid_cap.ctx; + struct v4l2_mbus_framefmt mf; + struct fimc_fmt *ffmt = NULL; + + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + if (pix->pixelformat == V4L2_PIX_FMT_JPEG) { + fimc_capture_try_format(ctx, &pix->width, &pix->height, + NULL, &pix->pixelformat, + FIMC_SD_PAD_SINK); + ctx->s_frame.f_width = pix->width; + ctx->s_frame.f_height = pix->height; + } + ffmt = fimc_capture_try_format(ctx, &pix->width, &pix->height, + NULL, &pix->pixelformat, + FIMC_SD_PAD_SOURCE); + if (!ffmt) + return -EINVAL; + + if (!fimc->vid_cap.user_subdev_api) { + mf.width = pix->width; + mf.height = pix->height; + mf.code = ffmt->mbus_code; + fimc_md_graph_lock(fimc); + fimc_pipeline_try_format(ctx, &mf, &ffmt, false); + fimc_md_graph_unlock(fimc); + + pix->width = mf.width; + pix->height = mf.height; + if (ffmt) + pix->pixelformat = ffmt->fourcc; + } + fimc_adjust_mplane_format(ffmt, pix->width, pix->height, pix); return 0; } -static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, - struct v4l2_format *f) +static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f) { - struct fimc_dev *fimc = video_drvdata(file); struct fimc_ctx *ctx = fimc->vid_cap.ctx; - struct v4l2_pix_format_mplane *pix; - struct fimc_frame *frame; - int ret; - int i; + struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; + struct v4l2_mbus_framefmt *mf = &fimc->vid_cap.mf; + struct fimc_frame *ff = &ctx->d_frame; + struct fimc_fmt *s_fmt = NULL; + int ret, i; if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) return -EINVAL; - - if (vb2_is_busy(&fimc->vid_cap.vbq) || fimc_capture_active(fimc)) + if (vb2_is_busy(&fimc->vid_cap.vbq)) return -EBUSY; - frame = &ctx->d_frame; - - pix = &f->fmt.pix_mp; - frame->fmt = fimc_find_format(&pix->pixelformat, NULL, - FMT_FLAGS_M2M | FMT_FLAGS_CAM, 0); - if (WARN(frame->fmt == NULL, "Pixel format lookup failed\n")) + /* Pre-configure format at camera interface input, for JPEG only */ + if (pix->pixelformat == V4L2_PIX_FMT_JPEG) { + fimc_capture_try_format(ctx, &pix->width, &pix->height, + NULL, &pix->pixelformat, + FIMC_SD_PAD_SINK); + ctx->s_frame.f_width = pix->width; + ctx->s_frame.f_height = pix->height; + } + /* Try the format at the scaler and the DMA output */ + ff->fmt = fimc_capture_try_format(ctx, &pix->width, &pix->height, + NULL, &pix->pixelformat, + FIMC_SD_PAD_SOURCE); + if (!ff->fmt) return -EINVAL; - - for (i = 0; i < frame->fmt->colplanes; i++) { - frame->payload[i] = - (pix->width * pix->height * frame->fmt->depth[i]) >> 3; + /* Try to match format at the host and the sensor */ + if (!fimc->vid_cap.user_subdev_api) { + mf->code = ff->fmt->mbus_code; + mf->width = pix->width; + mf->height = pix->height; + + fimc_md_graph_lock(fimc); + ret = fimc_pipeline_try_format(ctx, mf, &s_fmt, true); + fimc_md_graph_unlock(fimc); + if (ret) + return ret; + pix->width = mf->width; + pix->height = mf->height; + } + fimc_adjust_mplane_format(ff->fmt, pix->width, pix->height, pix); + for (i = 0; i < ff->fmt->colplanes; i++) + ff->payload[i] = + (pix->width * pix->height * ff->fmt->depth[i]) / 8; + + set_frame_bounds(ff, pix->width, pix->height); + /* Reset the composition rectangle if not yet configured */ + if (!(ctx->state & FIMC_DST_CROP)) + set_frame_crop(ff, 0, 0, pix->width, pix->height); + + /* Reset cropping and set format at the camera interface input */ + if (!fimc->vid_cap.user_subdev_api) { + ctx->s_frame.fmt = s_fmt; + set_frame_bounds(&ctx->s_frame, pix->width, pix->height); + set_frame_crop(&ctx->s_frame, 0, 0, pix->width, pix->height); } - /* Output DMA frame pixel size and offsets. */ - frame->f_width = pix->plane_fmt[0].bytesperline * 8 - / frame->fmt->depth[0]; - frame->f_height = pix->height; - frame->width = pix->width; - frame->height = pix->height; - frame->o_width = pix->width; - frame->o_height = pix->height; - frame->offs_h = 0; - frame->offs_v = 0; + return ret; +} - ctx->state |= (FIMC_PARAMS | FIMC_DST_FMT); +static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct fimc_dev *fimc = video_drvdata(file); - return ret; + return fimc_capture_set_format(fimc, f); } static int fimc_cap_enum_input(struct file *file, void *priv, @@ -522,22 +827,83 @@ static int fimc_cap_g_input(struct file *file, void *priv, unsigned int *i) return 0; } +/** + * fimc_pipeline_validate - check for formats inconsistencies + * between source and sink pad of each link + * + * Return 0 if all formats match or -EPIPE otherwise. + */ +static int fimc_pipeline_validate(struct fimc_dev *fimc) +{ + struct v4l2_subdev_format sink_fmt, src_fmt; + struct fimc_vid_cap *vid_cap = &fimc->vid_cap; + struct v4l2_subdev *sd; + struct media_pad *pad; + int ret; + + /* Start with the video capture node pad */ + pad = media_entity_remote_source(&vid_cap->vd_pad); + if (pad == NULL) + return -EPIPE; + /* FIMC.{N} subdevice */ + sd = media_entity_to_v4l2_subdev(pad->entity); + + while (1) { + /* Retrieve format at the sink pad */ + pad = &sd->entity.pads[0]; + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + break; + /* Don't call FIMC subdev operation to avoid nested locking */ + if (sd == fimc->vid_cap.subdev) { + struct fimc_frame *ff = &vid_cap->ctx->s_frame; + sink_fmt.format.width = ff->f_width; + sink_fmt.format.height = ff->f_height; + sink_fmt.format.code = ff->fmt ? ff->fmt->mbus_code : 0; + } else { + sink_fmt.pad = pad->index; + sink_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sink_fmt); + if (ret < 0 && ret != -ENOIOCTLCMD) + return -EPIPE; + } + /* Retrieve format at the source pad */ + pad = media_entity_remote_source(pad); + if (pad == NULL || + media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + break; + + sd = media_entity_to_v4l2_subdev(pad->entity); + src_fmt.pad = pad->index; + src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &src_fmt); + if (ret < 0 && ret != -ENOIOCTLCMD) + return -EPIPE; + + if (src_fmt.format.width != sink_fmt.format.width || + src_fmt.format.height != sink_fmt.format.height || + src_fmt.format.code != sink_fmt.format.code) + return -EPIPE; + } + return 0; +} + static int fimc_cap_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { struct fimc_dev *fimc = video_drvdata(file); - struct fimc_ctx *ctx = fimc->vid_cap.ctx; struct fimc_pipeline *p = &fimc->pipeline; + int ret; if (fimc_capture_active(fimc)) return -EBUSY; - if (!(ctx->state & FIMC_DST_FMT)) { - v4l2_err(fimc->vid_cap.vfd, "Format is not set\n"); - return -EINVAL; - } media_entity_pipeline_start(&p->sensor->entity, p->pipe); + if (fimc->vid_cap.user_subdev_api) { + ret = fimc_pipeline_validate(fimc); + if (ret) + return ret; + } return vb2_streamon(&fimc->vid_cap.vbq, type); } @@ -624,35 +990,16 @@ static int fimc_cap_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) { struct fimc_dev *fimc = video_drvdata(file); struct fimc_ctx *ctx = fimc->vid_cap.ctx; - struct fimc_frame *f; - int ret = -EINVAL; - - if (fimc_capture_active(fimc)) - return -EBUSY; - - ret = fimc_try_crop(ctx, cr); - if (ret) - return ret; - - if (!(ctx->state & FIMC_DST_FMT)) { - v4l2_err(fimc->vid_cap.vfd, "Capture format is not set\n"); - return -EINVAL; - } + struct fimc_frame *ff; + unsigned long flags; - f = &ctx->s_frame; - /* Check for the pixel scaling ratio when cropping input image. */ - ret = fimc_check_scaler_ratio(cr->c.width, cr->c.height, - ctx->d_frame.width, ctx->d_frame.height, - ctx->rotation); - if (ret) { - v4l2_err(fimc->vid_cap.vfd, "Out of the scaler range\n"); - return ret; - } + fimc_capture_try_crop(ctx, &cr->c, FIMC_SD_PAD_SINK); + ff = &ctx->s_frame; - f->offs_h = cr->c.left; - f->offs_v = cr->c.top; - f->width = cr->c.width; - f->height = cr->c.height; + spin_lock_irqsave(&fimc->slock, flags); + set_frame_crop(ff, cr->c.left, cr->c.top, cr->c.width, cr->c.height); + set_bit(ST_CAPT_APPLY_CFG, &fimc->state); + spin_unlock_irqrestore(&fimc->slock, flags); return 0; } @@ -683,14 +1030,16 @@ static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = { .vidioc_g_input = fimc_cap_g_input, }; -/* Media operations */ +/* Capture subdev media entity operations */ static int fimc_link_setup(struct media_entity *entity, const struct media_pad *local, const struct media_pad *remote, u32 flags) { - struct video_device *vd = media_entity_to_video_device(entity); - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(remote->entity); - struct fimc_dev *fimc = video_get_drvdata(vd); + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); + struct fimc_dev *fimc = v4l2_get_subdevdata(sd); + + if (media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + return -EINVAL; if (WARN_ON(fimc == NULL)) return 0; @@ -710,10 +1059,241 @@ static int fimc_link_setup(struct media_entity *entity, return 0; } -static const struct media_entity_operations fimc_media_ops = { +static const struct media_entity_operations fimc_sd_media_ops = { .link_setup = fimc_link_setup, }; +static int fimc_subdev_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct fimc_fmt *fmt; + + fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, code->index); + if (!fmt) + return -EINVAL; + code->code = fmt->mbus_code; + return 0; +} + +static int fimc_subdev_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct fimc_dev *fimc = v4l2_get_subdevdata(sd); + struct fimc_ctx *ctx = fimc->vid_cap.ctx; + struct v4l2_mbus_framefmt *mf; + struct fimc_frame *ff; + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + mf = v4l2_subdev_get_try_format(fh, fmt->pad); + fmt->format = *mf; + return 0; + } + mf = &fmt->format; + mf->colorspace = V4L2_COLORSPACE_JPEG; + ff = fmt->pad == FIMC_SD_PAD_SINK ? &ctx->s_frame : &ctx->d_frame; + + mutex_lock(&fimc->lock); + /* The pixel code is same on both input and output pad */ + if (!WARN_ON(ctx->s_frame.fmt == NULL)) + mf->code = ctx->s_frame.fmt->mbus_code; + mf->width = ff->f_width; + mf->height = ff->f_height; + mutex_unlock(&fimc->lock); + + return 0; +} + +static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct fimc_dev *fimc = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *mf = &fmt->format; + struct fimc_ctx *ctx = fimc->vid_cap.ctx; + struct fimc_frame *ff; + struct fimc_fmt *ffmt; + + dbg("pad%d: code: 0x%x, %dx%d", + fmt->pad, mf->code, mf->width, mf->height); + + if (fmt->pad == FIMC_SD_PAD_SOURCE && + vb2_is_busy(&fimc->vid_cap.vbq)) + return -EBUSY; + + mutex_lock(&fimc->lock); + ffmt = fimc_capture_try_format(ctx, &mf->width, &mf->height, + &mf->code, NULL, fmt->pad); + mutex_unlock(&fimc->lock); + mf->colorspace = V4L2_COLORSPACE_JPEG; + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + mf = v4l2_subdev_get_try_format(fh, fmt->pad); + *mf = fmt->format; + return 0; + } + ff = fmt->pad == FIMC_SD_PAD_SINK ? + &ctx->s_frame : &ctx->d_frame; + + mutex_lock(&fimc->lock); + set_frame_bounds(ff, mf->width, mf->height); + ff->fmt = ffmt; + + /* Reset the crop rectangle if required. */ + if (!(fmt->pad == FIMC_SD_PAD_SOURCE && (ctx->state & FIMC_DST_CROP))) + set_frame_crop(ff, 0, 0, mf->width, mf->height); + + if (fmt->pad == FIMC_SD_PAD_SINK) + ctx->state &= ~FIMC_DST_CROP; + mutex_unlock(&fimc->lock); + return 0; +} + +static int fimc_subdev_get_crop(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_crop *crop) +{ + struct fimc_dev *fimc = v4l2_get_subdevdata(sd); + struct fimc_ctx *ctx = fimc->vid_cap.ctx; + struct v4l2_rect *r = &crop->rect; + struct fimc_frame *ff; + + if (crop->which == V4L2_SUBDEV_FORMAT_TRY) { + crop->rect = *v4l2_subdev_get_try_crop(fh, crop->pad); + return 0; + } + ff = crop->pad == FIMC_SD_PAD_SINK ? + &ctx->s_frame : &ctx->d_frame; + + mutex_lock(&fimc->lock); + r->left = ff->offs_h; + r->top = ff->offs_v; + r->width = ff->width; + r->height = ff->height; + mutex_unlock(&fimc->lock); + + dbg("ff:%p, pad%d: l:%d, t:%d, %dx%d, f_w: %d, f_h: %d", + ff, crop->pad, r->left, r->top, r->width, r->height, + ff->f_width, ff->f_height); + + return 0; +} + +static int fimc_subdev_set_crop(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_crop *crop) +{ + struct fimc_dev *fimc = v4l2_get_subdevdata(sd); + struct fimc_ctx *ctx = fimc->vid_cap.ctx; + struct v4l2_rect *r = &crop->rect; + struct fimc_frame *ff; + unsigned long flags; + + dbg("(%d,%d)/%dx%d", r->left, r->top, r->width, r->height); + + ff = crop->pad == FIMC_SD_PAD_SOURCE ? + &ctx->d_frame : &ctx->s_frame; + + mutex_lock(&fimc->lock); + fimc_capture_try_crop(ctx, r, crop->pad); + + if (crop->which == V4L2_SUBDEV_FORMAT_TRY) { + mutex_lock(&fimc->lock); + *v4l2_subdev_get_try_crop(fh, crop->pad) = *r; + return 0; + } + spin_lock_irqsave(&fimc->slock, flags); + set_frame_crop(ff, r->left, r->top, r->width, r->height); + if (crop->pad == FIMC_SD_PAD_SOURCE) + ctx->state |= FIMC_DST_CROP; + + set_bit(ST_CAPT_APPLY_CFG, &fimc->state); + spin_unlock_irqrestore(&fimc->slock, flags); + + dbg("pad%d: (%d,%d)/%dx%d", crop->pad, r->left, r->top, + r->width, r->height); + + mutex_unlock(&fimc->lock); + return 0; +} + +static struct v4l2_subdev_pad_ops fimc_subdev_pad_ops = { + .enum_mbus_code = fimc_subdev_enum_mbus_code, + .get_fmt = fimc_subdev_get_fmt, + .set_fmt = fimc_subdev_set_fmt, + .get_crop = fimc_subdev_get_crop, + .set_crop = fimc_subdev_set_crop, +}; + +static struct v4l2_subdev_ops fimc_subdev_ops = { + .pad = &fimc_subdev_pad_ops, +}; + +static int fimc_create_capture_subdev(struct fimc_dev *fimc, + struct v4l2_device *v4l2_dev) +{ + struct v4l2_subdev *sd; + int ret; + + sd = kzalloc(sizeof(*sd), GFP_KERNEL); + if (!sd) + return -ENOMEM; + + v4l2_subdev_init(sd, &fimc_subdev_ops); + sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(sd->name, sizeof(sd->name), "FIMC.%d", fimc->pdev->id); + + fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + fimc->vid_cap.sd_pads[FIMC_SD_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_init(&sd->entity, FIMC_SD_PADS_NUM, + fimc->vid_cap.sd_pads, 0); + if (ret) + goto me_err; + ret = v4l2_device_register_subdev(v4l2_dev, sd); + if (ret) + goto sd_err; + + fimc->vid_cap.subdev = sd; + v4l2_set_subdevdata(sd, fimc); + sd->entity.ops = &fimc_sd_media_ops; + return 0; +sd_err: + media_entity_cleanup(&sd->entity); +me_err: + kfree(sd); + return ret; +} + +static void fimc_destroy_capture_subdev(struct fimc_dev *fimc) +{ + struct v4l2_subdev *sd = fimc->vid_cap.subdev; + + if (!sd) + return; + media_entity_cleanup(&sd->entity); + v4l2_device_unregister_subdev(sd); + kfree(sd); + sd = NULL; +} + +/* Set default format at the sensor and host interface */ +static int fimc_capture_set_default_format(struct fimc_dev *fimc) +{ + struct v4l2_format fmt = { + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + .fmt.pix_mp = { + .width = 640, + .height = 480, + .pixelformat = V4L2_PIX_FMT_YUYV, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_JPEG, + }, + }; + + return fimc_capture_set_format(fimc, &fmt); +} + /* fimc->lock must be already initialized */ int fimc_register_capture_device(struct fimc_dev *fimc, struct v4l2_device *v4l2_dev) @@ -721,7 +1301,6 @@ int fimc_register_capture_device(struct fimc_dev *fimc, struct video_device *vfd; struct fimc_vid_cap *vid_cap; struct fimc_ctx *ctx; - struct fimc_frame *fr; struct vb2_queue *q; int ret = -ENOMEM; @@ -733,12 +1312,8 @@ int fimc_register_capture_device(struct fimc_dev *fimc, ctx->in_path = FIMC_CAMERA; ctx->out_path = FIMC_DMA; ctx->state = FIMC_CTX_CAP; - - /* Default format of the output frames */ - fr = &ctx->d_frame; - fr->fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, 0); - fr->width = fr->f_width = fr->o_width = 640; - fr->height = fr->f_height = fr->o_height = 480; + ctx->s_frame.fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, 0); + ctx->d_frame.fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, 0); vfd = video_device_alloc(); if (!vfd) { @@ -783,11 +1358,15 @@ int fimc_register_capture_device(struct fimc_dev *fimc, ret = media_entity_init(&vfd->entity, 1, &fimc->vid_cap.vd_pad, 0); if (ret) goto err_ent; + ret = fimc_create_capture_subdev(fimc, v4l2_dev); + if (ret) + goto err_sd_reg; - vfd->entity.ops = &fimc_media_ops; vfd->ctrl_handler = &ctx->ctrl_handler; return 0; +err_sd_reg: + media_entity_cleanup(&vfd->entity); err_ent: video_device_release(vfd); err_vd_alloc: @@ -805,6 +1384,7 @@ void fimc_unregister_capture_device(struct fimc_dev *fimc) not registered */ video_unregister_device(vfd); } + fimc_destroy_capture_subdev(fimc); kfree(fimc->vid_cap.ctx); fimc->vid_cap.ctx = NULL; } diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 605eb46..1a479a2 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -372,6 +372,8 @@ static void fimc_capture_irq_handler(struct fimc_dev *fimc) set_bit(ST_CAPT_RUN, &fimc->state); } + fimc_capture_config_update(cap->ctx); + dbg("frame: %d, active_buf_cnt: %d", fimc_hw_get_frame_index(fimc), cap->active_buf_cnt); } @@ -1198,12 +1200,11 @@ static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr) return 0; } -int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) +static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) { struct fimc_dev *fimc = ctx->fimc_dev; struct fimc_frame *f; u32 min_size, halign, depth = 0; - bool is_capture_ctx; int i; if (cr->c.top < 0 || cr->c.left < 0) { @@ -1211,13 +1212,9 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) "doesn't support negative values for top & left\n"); return -EINVAL; } - - is_capture_ctx = fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx); - if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - f = is_capture_ctx ? &ctx->s_frame : &ctx->d_frame; - else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && - !is_capture_ctx) + f = &ctx->d_frame; + else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) f = &ctx->s_frame; else return -EINVAL; @@ -1226,15 +1223,10 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize; /* Get pixel alignment constraints. */ - if (is_capture_ctx) { - min_size = 16; - halign = 4; - } else { - if (fimc->id == 1 && fimc->variant->pix_hoff) - halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1; - else - halign = ffs(min_size) - 1; - } + if (fimc->id == 1 && fimc->variant->pix_hoff) + halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1; + else + halign = ffs(min_size) - 1; for (i = 0; i < f->fmt->colplanes; i++) depth += f->fmt->depth[i]; @@ -1251,7 +1243,7 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) cr->c.top = f->o_height - cr->c.height; cr->c.left = round_down(cr->c.left, min_size); - cr->c.top = round_down(cr->c.top, is_capture_ctx ? 16 : 8); + cr->c.top = round_down(cr->c.top, fimc->variant->hor_offs_align); dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d", cr->c.left, cr->c.top, cr->c.width, cr->c.height, @@ -1267,7 +1259,7 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) struct fimc_frame *f; int ret; - ret = fimc_try_crop(ctx, cr); + ret = fimc_m2m_try_crop(ctx, cr); if (ret) return ret; diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 2935068..e4520b2 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -43,6 +43,7 @@ #define SCALER_MAX_HRATIO 64 #define SCALER_MAX_VRATIO 64 #define DMA_MIN_SIZE 8 +#define FIMC_CAMIF_MAX_HEIGHT 0x2000 /* indices to the clocks array */ enum { @@ -92,9 +93,11 @@ enum fimc_color_fmt { S5P_FIMC_CBYCRY422, S5P_FIMC_CRYCBY422, S5P_FIMC_YCBCR444_LOCAL, + S5P_FIMC_JPEG = 0x40, }; -#define fimc_fmt_is_rgb(x) ((x) & 0x10) +#define fimc_fmt_is_rgb(x) (!!((x) & 0x10)) +#define fimc_fmt_is_jpeg(x) (!!((x) & 0x40)) #define IS_M2M(__strt) ((__strt) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE || \ __strt == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) @@ -116,9 +119,10 @@ enum fimc_color_fmt { #define FIMC_DST_ADDR (1 << 2) #define FIMC_SRC_FMT (1 << 3) #define FIMC_DST_FMT (1 << 4) -#define FIMC_CTX_M2M (1 << 5) -#define FIMC_CTX_CAP (1 << 6) -#define FIMC_CTX_SHUT (1 << 7) +#define FIMC_DST_CROP (1 << 5) +#define FIMC_CTX_M2M (1 << 16) +#define FIMC_CTX_CAP (1 << 17) +#define FIMC_CTX_SHUT (1 << 18) /* Image conversion flags */ #define FIMC_IN_DMA_ACCESS_TILED (1 << 0) @@ -293,12 +297,18 @@ struct fimc_m2m_device { int refcnt; }; +#define FIMC_SD_PAD_SINK 0 +#define FIMC_SD_PAD_SOURCE 1 +#define FIMC_SD_PADS_NUM 2 + /** * struct fimc_vid_cap - camera capture device information * @ctx: hardware context data * @vfd: video device node for camera capture mode + * @subdev: subdev exposing the FIMC processing block * @vd_pad: fimc video capture node pad - * @fmt: Media Bus format configured at selected image sensor + * @sd_pads: fimc video processing block pads + * @mf: media bus format at the FIMC camera input (and the scaler output) pad * @pending_buf_q: the pending buffer queue head * @active_buf_q: the queue head of buffers scheduled in hardware * @vbq: the capture am video buffer queue @@ -315,8 +325,10 @@ struct fimc_vid_cap { struct fimc_ctx *ctx; struct vb2_alloc_ctx *alloc_ctx; struct video_device *vfd; + struct v4l2_subdev *subdev; struct media_pad vd_pad; - struct v4l2_mbus_framefmt fmt; + struct v4l2_mbus_framefmt mf; + struct media_pad sd_pads[FIMC_SD_PADS_NUM]; struct list_head pending_buf_q; struct list_head active_buf_q; struct vb2_queue vbq; @@ -498,6 +510,33 @@ struct fimc_ctx { #define fh_to_ctx(__fh) container_of(__fh, struct fimc_ctx, fh) +static inline void set_frame_bounds(struct fimc_frame *f, u32 width, u32 height) +{ + f->o_width = width; + f->o_height = height; + f->f_width = width; + f->f_height = height; +} + +static inline void set_frame_crop(struct fimc_frame *f, + u32 left, u32 top, u32 width, u32 height) +{ + f->offs_h = left; + f->offs_v = top; + f->width = width; + f->height = height; +} + +static inline u32 fimc_get_format_depth(struct fimc_fmt *ff) +{ + u32 i, depth = 0; + + if (ff != NULL) + for (i = 0; i < ff->colplanes; i++) + depth += ff->depth[i]; + return depth; +} + static inline bool fimc_capture_active(struct fimc_dev *fimc) { unsigned long flags; @@ -649,7 +688,6 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc, /* fimc-core.c */ int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv, struct v4l2_fmtdesc *f); -int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr); int fimc_ctrls_create(struct fimc_ctx *ctx); void fimc_ctrls_delete(struct fimc_ctx *ctx); void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active); @@ -684,6 +722,7 @@ int fimc_vid_cap_buf_queue(struct fimc_dev *fimc, struct fimc_vid_buffer *fimc_vb); int fimc_capture_suspend(struct fimc_dev *fimc); int fimc_capture_resume(struct fimc_dev *fimc); +int fimc_capture_config_update(struct fimc_ctx *ctx); /* Locking: the caller holds fimc->slock */ static inline void fimc_activate_capture(struct fimc_ctx *ctx) diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.c b/drivers/media/video/s5p-fimc/fimc-mdevice.c index 5bb2c0d..db17a6f 100644 --- a/drivers/media/video/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/video/s5p-fimc/fimc-mdevice.c @@ -416,7 +416,7 @@ static int __fimc_md_create_fimc_links(struct fimc_md *fmd, struct fimc_sensor_info *s_info; struct media_entity *sink; unsigned int flags; - int ret, i, src_pad; + int ret, i; for (i = 0; i < FIMC_MAX_DEVS; i++) { if (!fmd->fimc[i]) @@ -425,20 +425,27 @@ static int __fimc_md_create_fimc_links(struct fimc_md *fmd, * Some FIMC variants are not fitted with camera capture * interface. Skip creating a link from sensor for those. */ - if (sensor && sensor->grp_id == SENSOR_GROUP_ID && + if (sensor->grp_id == SENSOR_GROUP_ID && !fmd->fimc[i]->variant->has_cam_if) continue; flags = (i == fimc_id) ? MEDIA_LNK_FL_ENABLED : 0; - sink = &fmd->fimc[i]->vid_cap.vfd->entity; - ret = media_entity_create_link(source, 0, sink, 0, flags); + sink = &fmd->fimc[i]->vid_cap.subdev->entity; + ret = media_entity_create_link(source, pad, sink, + FIMC_SD_PAD_SINK, flags); if (ret) return ret; + /* Notify FIMC capture subdev entity */ + ret = media_entity_call(sink, link_setup, &sink->pads[0], + &source->pads[pad], flags); + if (ret) + break; + v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]", source->name, flags ? '=' : '-', sink->name); - if (flags == 0 || sensor == NULL) + if (flags == 0) continue; s_info = v4l2_get_subdev_hostdata(sensor); if (!WARN_ON(s_info == NULL)) { @@ -468,10 +475,10 @@ static int fimc_md_create_links(struct fimc_md *fmd) struct v4l2_subdev *sensor, *csis; struct s5p_fimc_isp_info *pdata; struct fimc_sensor_info *s_info; - struct media_entity *source; - int fimc_id = 0; - int i, pad; + struct media_entity *source, *sink; + int i, pad, fimc_id = 0; int ret = 0; + u32 flags; for (i = 0; i < fmd->num_sensors; i++) { if (fmd->sensor[i].subdev == NULL) @@ -507,7 +514,6 @@ static int fimc_md_create_links(struct fimc_md *fmd) v4l2_info(&fmd->v4l2_dev, "created link [%s] => [%s]", sensor->entity.name, csis->entity.name); - sensor = NULL; source = &csis->entity; pad = CSIS_PAD_SOURCE; break; @@ -526,8 +532,21 @@ static int fimc_md_create_links(struct fimc_md *fmd) continue; ret = __fimc_md_create_fimc_links(fmd, source, sensor, pad, - fimc_id++); + fimc_id++); } + /* Create immutable links between each FIMC's subdev and video node */ + flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED; + for (i = 0; i < FIMC_MAX_DEVS; i++) { + if (!fmd->fimc[i]) + continue; + source = &fmd->fimc[i]->vid_cap.subdev->entity; + sink = &fmd->fimc[i]->vid_cap.vfd->entity; + ret = media_entity_create_link(source, FIMC_SD_PAD_SOURCE, + sink, 0, flags); + if (ret) + break; + } + return ret; } @@ -636,15 +655,15 @@ int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on) static int fimc_md_link_notify(struct media_pad *source, struct media_pad *sink, u32 flags) { - struct video_device *vid_dev; + struct v4l2_subdev *sd; struct fimc_dev *fimc; int ret = 0; - if (WARN_ON(media_entity_type(sink->entity) != MEDIA_ENT_T_DEVNODE)) + if (media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV) return 0; - vid_dev = media_entity_to_video_device(sink->entity); - fimc = video_get_drvdata(vid_dev); + sd = media_entity_to_v4l2_subdev(sink->entity); + fimc = v4l2_get_subdevdata(sd); if (!(flags & MEDIA_LNK_FL_ENABLED)) { ret = __fimc_pipeline_shutdown(fimc); diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c index 50937b4..a1fff02 100644 --- a/drivers/media/video/s5p-fimc/fimc-reg.c +++ b/drivers/media/video/s5p-fimc/fimc-reg.c @@ -572,7 +572,7 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc, if (cam->bus_type == FIMC_ITU_601 || cam->bus_type == FIMC_ITU_656) { for (i = 0; i < ARRAY_SIZE(pix_desc); i++) { - if (fimc->vid_cap.fmt.code == pix_desc[i].pixelcode) { + if (fimc->vid_cap.mf.code == pix_desc[i].pixelcode) { cfg = pix_desc[i].cisrcfmt; bus_width = pix_desc[i].bus_width; break; @@ -582,7 +582,7 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc, if (i == ARRAY_SIZE(pix_desc)) { v4l2_err(fimc->vid_cap.vfd, "Camera color format not supported: %d\n", - fimc->vid_cap.fmt.code); + fimc->vid_cap.mf.code); return -EINVAL; } @@ -642,12 +642,12 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc, cfg |= S5P_CIGCTRL_SELCAM_MIPI_A; /* TODO: add remaining supported formats. */ - if (vid_cap->fmt.code == V4L2_MBUS_FMT_VYUY8_2X8) { + if (vid_cap->mf.code == V4L2_MBUS_FMT_VYUY8_2X8) { tmp = S5P_CSIIMGFMT_YCBCR422_8BIT; } else { v4l2_err(fimc->vid_cap.vfd, "Not supported camera pixel format: %d", - vid_cap->fmt.code); + vid_cap->mf.code); return -EINVAL; } tmp |= (cam->csi_data_align == 32) << 8; -- cgit v0.10.2 From ee7160e57c98ffb03253abb2cb4ad5b1376a2257 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 26 Aug 2011 14:57:06 -0300 Subject: [media] s5p-fimc: Add support for JPEG capture Add support for transparent DMA transfer of JPEG data with MIPI-CSI2 USER1 format. In JPEG mode the color effect, scaling and cropping is not supported as well as image rotation and flipping thus these controls are marked as inactive if V4L2_PIX_FMT_JPEG pixel format was selected. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 62fd8a1..adbbb63 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -60,7 +60,7 @@ static int fimc_init_capture(struct fimc_dev *fimc) fimc_hw_set_mainscaler(ctx); fimc_hw_set_target_format(ctx); fimc_hw_set_rotation(ctx); - fimc_hw_set_effect(ctx); + fimc_hw_set_effect(ctx, false); fimc_hw_set_output_path(ctx); fimc_hw_set_out_dma(ctx); clear_bit(ST_CAPT_APPLY_CFG, &fimc->state); @@ -731,6 +731,17 @@ static int fimc_cap_try_fmt_mplane(struct file *file, void *fh, return 0; } +static void fimc_capture_mark_jpeg_xfer(struct fimc_ctx *ctx, bool jpeg) +{ + ctx->scaler.enabled = !jpeg; + fimc_ctrls_activate(ctx, !jpeg); + + if (jpeg) + set_bit(ST_CAPT_JPEG, &ctx->fimc_dev->state); + else + clear_bit(ST_CAPT_JPEG, &ctx->fimc_dev->state); +} + static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f) { struct fimc_ctx *ctx = fimc->vid_cap.ctx; @@ -783,6 +794,8 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f) if (!(ctx->state & FIMC_DST_CROP)) set_frame_crop(ff, 0, 0, pix->width, pix->height); + fimc_capture_mark_jpeg_xfer(ctx, fimc_fmt_is_jpeg(ff->fmt->color)); + /* Reset cropping and set format at the camera interface input */ if (!fimc->vid_cap.user_subdev_api) { ctx->s_frame.fmt = s_fmt; @@ -1133,6 +1146,8 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, *mf = fmt->format; return 0; } + fimc_capture_mark_jpeg_xfer(ctx, fimc_fmt_is_jpeg(ffmt->color)); + ff = fmt->pad == FIMC_SD_PAD_SINK ? &ctx->s_frame : &ctx->d_frame; diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 1a479a2..10aee62 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -159,22 +159,28 @@ static struct fimc_fmt fimc_formats[] = { .memplanes = 2, .colplanes = 2, .flags = FMT_FLAGS_M2M, + }, { + .name = "JPEG encoded data", + .fourcc = V4L2_PIX_FMT_JPEG, + .color = S5P_FIMC_JPEG, + .depth = { 8 }, + .memplanes = 1, + .colplanes = 1, + .mbus_code = V4L2_MBUS_FMT_JPEG_1X8, + .flags = FMT_FLAGS_CAM, }, }; -int fimc_check_scaler_ratio(int sw, int sh, int dw, int dh, int rot) +int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh, + int dw, int dh, int rotation) { - int tx, ty; + if (rotation == 90 || rotation == 270) + swap(dw, dh); - if (rot == 90 || rot == 270) { - ty = dw; - tx = dh; - } else { - tx = dw; - ty = dh; - } + if (!ctx->scaler.enabled) + return (sw == dw && sh == dh) ? 0 : -EINVAL; - if ((sw >= SCALER_MAX_HRATIO * tx) || (sh >= SCALER_MAX_VRATIO * ty)) + if ((sw >= SCALER_MAX_HRATIO * dw) || (sh >= SCALER_MAX_VRATIO * dh)) return -EINVAL; return 0; @@ -321,7 +327,7 @@ static int stop_streaming(struct vb2_queue *q) return 0; } -static void fimc_capture_irq_handler(struct fimc_dev *fimc) +void fimc_capture_irq_handler(struct fimc_dev *fimc, bool final) { struct fimc_vid_cap *cap = &fimc->vid_cap; struct fimc_vid_buffer *v_buf; @@ -329,7 +335,7 @@ static void fimc_capture_irq_handler(struct fimc_dev *fimc) struct timespec ts; if (!list_empty(&cap->active_buf_q) && - test_bit(ST_CAPT_RUN, &fimc->state)) { + test_bit(ST_CAPT_RUN, &fimc->state) && final) { ktime_get_real_ts(&ts); v_buf = active_queue_pop(cap); @@ -364,7 +370,8 @@ static void fimc_capture_irq_handler(struct fimc_dev *fimc) } if (cap->active_buf_cnt == 0) { - clear_bit(ST_CAPT_RUN, &fimc->state); + if (final) + clear_bit(ST_CAPT_RUN, &fimc->state); if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) cap->buf_index = 0; @@ -407,14 +414,12 @@ static irqreturn_t fimc_irq_handler(int irq, void *priv) spin_unlock(&ctx->slock); } return IRQ_HANDLED; - } else { - if (test_bit(ST_CAPT_PEND, &fimc->state)) { - fimc_capture_irq_handler(fimc); - - if (cap->active_buf_cnt == 1) { - fimc_deactivate_capture(fimc); - clear_bit(ST_CAPT_STREAM, &fimc->state); - } + } else if (test_bit(ST_CAPT_PEND, &fimc->state)) { + fimc_capture_irq_handler(fimc, + !test_bit(ST_CAPT_JPEG, &fimc->state)); + if (cap->active_buf_cnt == 1) { + fimc_deactivate_capture(fimc); + clear_bit(ST_CAPT_STREAM, &fimc->state); } } out: @@ -586,9 +591,6 @@ int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags) fimc_set_yuv_order(ctx); } - /* Input DMA mode is not allowed when the scaler is disabled. */ - ctx->scaler.enabled = 1; - if (flags & FIMC_SRC_ADDR) { vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx); ret = fimc_prepare_addr(ctx, vb, s_frame, &s_frame->paddr); @@ -643,7 +645,7 @@ static void fimc_dma_run(void *priv) fimc_hw_set_mainscaler(ctx); fimc_hw_set_target_format(ctx); fimc_hw_set_rotation(ctx); - fimc_hw_set_effect(ctx); + fimc_hw_set_effect(ctx, false); } fimc_hw_set_output_path(ctx); @@ -773,7 +775,7 @@ static int fimc_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_ROTATE: if (fimc_capture_pending(fimc) || fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) { - ret = fimc_check_scaler_ratio(ctx->s_frame.width, + ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width, ctx->s_frame.height, ctx->d_frame.width, ctx->d_frame.height, ctrl->val); } @@ -1098,6 +1100,8 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh, fimc_fill_frame(frame, f); + ctx->scaler.enabled = 1; + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) fimc_ctx_state_lock_set(FIMC_PARAMS | FIMC_DST_FMT, ctx); else @@ -1269,15 +1273,13 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) /* Check to see if scaling ratio is within supported range */ if (fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) { if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - ret = fimc_check_scaler_ratio(cr->c.width, cr->c.height, - ctx->d_frame.width, - ctx->d_frame.height, - ctx->rotation); + ret = fimc_check_scaler_ratio(ctx, cr->c.width, + cr->c.height, ctx->d_frame.width, + ctx->d_frame.height, ctx->rotation); } else { - ret = fimc_check_scaler_ratio(ctx->s_frame.width, - ctx->s_frame.height, - cr->c.width, cr->c.height, - ctx->rotation); + ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width, + ctx->s_frame.height, cr->c.width, + cr->c.height, ctx->rotation); } if (ret) { v4l2_err(fimc->m2m.vfd, "Out of scaler range\n"); diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index e4520b2..9b44875 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -66,6 +66,7 @@ enum fimc_dev_flags { ST_CAPT_SHUT, ST_CAPT_BUSY, ST_CAPT_APPLY_CFG, + ST_CAPT_JPEG, }; #define fimc_m2m_active(dev) test_bit(ST_M2M_RUN, &(dev)->state) @@ -669,7 +670,7 @@ void fimc_hw_en_irq(struct fimc_dev *fimc, int enable); void fimc_hw_set_prescaler(struct fimc_ctx *ctx); void fimc_hw_set_mainscaler(struct fimc_ctx *ctx); void fimc_hw_en_capture(struct fimc_ctx *ctx); -void fimc_hw_set_effect(struct fimc_ctx *ctx); +void fimc_hw_set_effect(struct fimc_ctx *ctx, bool active); void fimc_hw_set_in_dma(struct fimc_ctx *ctx); void fimc_hw_set_input_path(struct fimc_ctx *ctx); void fimc_hw_set_output_path(struct fimc_ctx *ctx); @@ -697,7 +698,8 @@ void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height, struct fimc_fmt *fimc_find_format(u32 *pixelformat, u32 *mbus_code, unsigned int mask, int index); -int fimc_check_scaler_ratio(int sw, int sh, int dw, int dh, int rot); +int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh, + int dw, int dh, int rotation); int fimc_set_scaler_info(struct fimc_ctx *ctx); int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags); int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, @@ -705,6 +707,7 @@ int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f); void fimc_set_yuv_order(struct fimc_ctx *ctx); void fimc_fill_frame(struct fimc_frame *frame, struct v4l2_format *f); +void fimc_capture_irq_handler(struct fimc_dev *fimc, bool done); int fimc_register_m2m_device(struct fimc_dev *fimc, struct v4l2_device *v4l2_dev); diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c index a1fff02..2a1ae51 100644 --- a/drivers/media/video/s5p-fimc/fimc-reg.c +++ b/drivers/media/video/s5p-fimc/fimc-reg.c @@ -352,17 +352,19 @@ void fimc_hw_en_capture(struct fimc_ctx *ctx) writel(cfg | S5P_CIIMGCPT_IMGCPTEN, dev->regs + S5P_CIIMGCPT); } -void fimc_hw_set_effect(struct fimc_ctx *ctx) +void fimc_hw_set_effect(struct fimc_ctx *ctx, bool active) { struct fimc_dev *dev = ctx->fimc_dev; struct fimc_effect *effect = &ctx->effect; - u32 cfg = (S5P_CIIMGEFF_IE_ENABLE | S5P_CIIMGEFF_IE_SC_AFTER); - - cfg |= effect->type; + u32 cfg = 0; - if (effect->type == S5P_FIMC_EFFECT_ARBITRARY) { - cfg |= S5P_CIIMGEFF_PAT_CB(effect->pat_cb); - cfg |= S5P_CIIMGEFF_PAT_CR(effect->pat_cr); + if (active) { + cfg |= S5P_CIIMGEFF_IE_SC_AFTER | S5P_CIIMGEFF_IE_ENABLE; + cfg |= effect->type; + if (effect->type == S5P_FIMC_EFFECT_ARBITRARY) { + cfg |= S5P_CIIMGEFF_PAT_CB(effect->pat_cb); + cfg |= S5P_CIIMGEFF_PAT_CR(effect->pat_cr); + } } writel(cfg, dev->regs + S5P_CIIMGEFF); @@ -592,6 +594,9 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc, else if (bus_width == 16) cfg |= S5P_CISRCFMT_ITU601_16BIT; } /* else defaults to ITU-R BT.656 8-bit */ + } else if (cam->bus_type == FIMC_MIPI_CSI2) { + if (fimc_fmt_is_jpeg(f->fmt->color)) + cfg |= S5P_CISRCFMT_ITU601_8BIT; } cfg |= S5P_CISRCFMT_HSIZE(f->o_width) | S5P_CISRCFMT_VSIZE(f->o_height); @@ -633,7 +638,7 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc, /* Select ITU B interface, disable Writeback path and test pattern. */ cfg &= ~(S5P_CIGCTRL_TESTPAT_MASK | S5P_CIGCTRL_SELCAM_ITU_A | S5P_CIGCTRL_SELCAM_MIPI | S5P_CIGCTRL_CAMIF_SELWB | - S5P_CIGCTRL_SELCAM_MIPI_A); + S5P_CIGCTRL_SELCAM_MIPI_A | S5P_CIGCTRL_CAM_JPEG); if (cam->bus_type == FIMC_MIPI_CSI2) { cfg |= S5P_CIGCTRL_SELCAM_MIPI; @@ -642,9 +647,15 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc, cfg |= S5P_CIGCTRL_SELCAM_MIPI_A; /* TODO: add remaining supported formats. */ - if (vid_cap->mf.code == V4L2_MBUS_FMT_VYUY8_2X8) { + switch (vid_cap->mf.code) { + case V4L2_MBUS_FMT_VYUY8_2X8: tmp = S5P_CSIIMGFMT_YCBCR422_8BIT; - } else { + break; + case V4L2_MBUS_FMT_JPEG_1X8: + tmp = S5P_CSIIMGFMT_USER(1); + cfg |= S5P_CIGCTRL_CAM_JPEG; + break; + default: v4l2_err(fimc->vid_cap.vfd, "Not supported camera pixel format: %d", vid_cap->mf.code); diff --git a/drivers/media/video/s5p-fimc/regs-fimc.h b/drivers/media/video/s5p-fimc/regs-fimc.h index 0fea3e6..94d2302 100644 --- a/drivers/media/video/s5p-fimc/regs-fimc.h +++ b/drivers/media/video/s5p-fimc/regs-fimc.h @@ -54,6 +54,7 @@ #define S5P_CIGCTRL_IRQ_CLR (1 << 19) #define S5P_CIGCTRL_IRQ_ENABLE (1 << 16) #define S5P_CIGCTRL_SHDW_DISABLE (1 << 12) +#define S5P_CIGCTRL_CAM_JPEG (1 << 8) #define S5P_CIGCTRL_SELCAM_MIPI_A (1 << 7) #define S5P_CIGCTRL_CAMIF_SELWB (1 << 6) /* 0 - ITU601; 1 - ITU709 */ @@ -184,7 +185,6 @@ /* Image effect */ #define S5P_CIIMGEFF 0xd0 -#define S5P_CIIMGEFF_IE_DISABLE (0 << 30) #define S5P_CIIMGEFF_IE_ENABLE (1 << 30) #define S5P_CIIMGEFF_IE_SC_BEFORE (0 << 29) #define S5P_CIIMGEFF_IE_SC_AFTER (1 << 29) @@ -286,10 +286,8 @@ #define S5P_CSIIMGFMT_RAW8 0x2a #define S5P_CSIIMGFMT_RAW10 0x2b #define S5P_CSIIMGFMT_RAW12 0x2c -#define S5P_CSIIMGFMT_USER1 0x30 -#define S5P_CSIIMGFMT_USER2 0x31 -#define S5P_CSIIMGFMT_USER3 0x32 -#define S5P_CSIIMGFMT_USER4 0x33 +/* User defined formats. x = 0...16. */ +#define S5P_CSIIMGFMT_USER(x) (0x30 + x - 1) /* Output frame buffer sequence mask */ #define S5P_CIFCNTSEQ 0x1FC -- cgit v0.10.2 From e1d72f4d521733bbf16cb5ba63683fe4147fa349 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 10 Jun 2011 15:36:58 -0300 Subject: [media] s5p-fimc: Add v4l2_device notification support for single frame capture Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index adbbb63..7fafd12 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -1076,6 +1076,53 @@ static const struct media_entity_operations fimc_sd_media_ops = { .link_setup = fimc_link_setup, }; +/** + * fimc_sensor_notify - v4l2_device notification from a sensor subdev + * @sd: pointer to a subdev generating the notification + * @notification: the notification type, must be S5P_FIMC_TX_END_NOTIFY + * @arg: pointer to an u32 type integer that stores the frame payload value + * + * The End Of Frame notification sent by sensor subdev in its still capture + * mode. If there is only a single VSYNC generated by the sensor at the + * beginning of a frame transmission, FIMC does not issue the LastIrq + * (end of frame) interrupt. And this notification is used to complete the + * frame capture and returning a buffer to user-space. Subdev drivers should + * call this notification from their last 'End of frame capture' interrupt. + */ +void fimc_sensor_notify(struct v4l2_subdev *sd, unsigned int notification, + void *arg) +{ + struct fimc_sensor_info *sensor; + struct fimc_vid_buffer *buf; + struct fimc_md *fmd; + struct fimc_dev *fimc; + unsigned long flags; + + if (sd == NULL) + return; + + sensor = v4l2_get_subdev_hostdata(sd); + fmd = entity_to_fimc_mdev(&sd->entity); + + spin_lock_irqsave(&fmd->slock, flags); + fimc = sensor ? sensor->host : NULL; + + if (fimc && arg && notification == S5P_FIMC_TX_END_NOTIFY && + test_bit(ST_CAPT_PEND, &fimc->state)) { + unsigned long irq_flags; + spin_lock_irqsave(&fimc->slock, irq_flags); + if (!list_empty(&fimc->vid_cap.active_buf_q)) { + buf = list_entry(fimc->vid_cap.active_buf_q.next, + struct fimc_vid_buffer, list); + vb2_set_plane_payload(&buf->vb, 0, *((u32 *)arg)); + } + fimc_capture_irq_handler(fimc, true); + fimc_deactivate_capture(fimc); + spin_unlock_irqrestore(&fimc->slock, irq_flags); + } + spin_unlock_irqrestore(&fmd->slock, flags); +} + static int fimc_subdev_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct v4l2_subdev_mbus_code_enum *code) diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 9b44875..6ec8b37 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -723,6 +723,8 @@ void fimc_unregister_capture_device(struct fimc_dev *fimc); int fimc_capture_ctrls_create(struct fimc_dev *fimc); int fimc_vid_cap_buf_queue(struct fimc_dev *fimc, struct fimc_vid_buffer *fimc_vb); +void fimc_sensor_notify(struct v4l2_subdev *sd, unsigned int notification, + void *arg); int fimc_capture_suspend(struct fimc_dev *fimc); int fimc_capture_resume(struct fimc_dev *fimc); int fimc_capture_config_update(struct fimc_ctx *ctx); diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.c b/drivers/media/video/s5p-fimc/fimc-mdevice.c index db17a6f..cc337b1 100644 --- a/drivers/media/video/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/video/s5p-fimc/fimc-mdevice.c @@ -759,6 +759,7 @@ static int __devinit fimc_md_probe(struct platform_device *pdev) v4l2_dev = &fmd->v4l2_dev; v4l2_dev->mdev = &fmd->media_dev; + v4l2_dev->notify = fimc_sensor_notify; snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s", dev_name(&pdev->dev)); diff --git a/include/media/s5p_fimc.h b/include/media/s5p_fimc.h index 086a7aa..2b58904 100644 --- a/include/media/s5p_fimc.h +++ b/include/media/s5p_fimc.h @@ -60,4 +60,13 @@ struct s5p_platform_fimc { struct s5p_fimc_isp_info *isp_info; int num_clients; }; + +/* + * v4l2_device notification id. This is only for internal use in the kernel. + * Sensor subdevs should issue S5P_FIMC_TX_END_NOTIFY notification in single + * frame capture mode when there is only one VSYNC pulse issued by the sensor + * at begining of the frame transmission. + */ +#define S5P_FIMC_TX_END_NOTIFY _IO('e', 0) + #endif /* S5P_FIMC_H_ */ -- cgit v0.10.2 From 0295202ca7b2816ddccae83e6efcf6d24cc243c3 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 10 Jun 2011 15:36:59 -0300 Subject: [media] s5p-fimc: Use consistent names for the buffer list functions Also correct and improve *_queue_add/pop functions description. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 7fafd12..4693846 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -84,12 +84,12 @@ static int fimc_capture_state_cleanup(struct fimc_dev *fimc) /* Release buffers that were enqueued in the driver by videobuf2. */ while (!list_empty(&cap->pending_buf_q)) { - buf = pending_queue_pop(cap); + buf = fimc_pending_queue_pop(cap); vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } while (!list_empty(&cap->active_buf_q)) { - buf = active_queue_pop(cap); + buf = fimc_active_queue_pop(cap); vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } @@ -279,7 +279,7 @@ static void buffer_queue(struct vb2_buffer *vb) fimc_hw_set_output_addr(fimc, &buf->paddr, buf_id); buf->index = vid_cap->buf_index; - active_queue_add(vid_cap, buf); + fimc_active_queue_add(vid_cap, buf); if (++vid_cap->buf_index >= FIMC_MAX_OUT_BUFS) vid_cap->buf_index = 0; diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 10aee62..33c7069 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -338,7 +338,7 @@ void fimc_capture_irq_handler(struct fimc_dev *fimc, bool final) test_bit(ST_CAPT_RUN, &fimc->state) && final) { ktime_get_real_ts(&ts); - v_buf = active_queue_pop(cap); + v_buf = fimc_active_queue_pop(cap); tv = &v_buf->vb.v4l2_buf.timestamp; tv->tv_sec = ts.tv_sec; @@ -355,12 +355,12 @@ void fimc_capture_irq_handler(struct fimc_dev *fimc, bool final) if (!list_empty(&cap->pending_buf_q)) { - v_buf = pending_queue_pop(cap); + v_buf = fimc_pending_queue_pop(cap); fimc_hw_set_output_addr(fimc, &v_buf->paddr, cap->buf_index); v_buf->index = cap->buf_index; /* Move the buffer to the capture active queue */ - active_queue_add(cap, v_buf); + fimc_active_queue_add(cap, v_buf); dbg("next frame: %d, done frame: %d", fimc_hw_get_frame_index(fimc), v_buf->index); diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 6ec8b37..82ac597 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -745,22 +745,27 @@ static inline void fimc_deactivate_capture(struct fimc_dev *fimc) } /* - * Add buf to the capture active buffers queue. - * Locking: Need to be called with fimc_dev::slock held. + * Buffer list manipulation functions. Must be called with fimc.slock held. */ -static inline void active_queue_add(struct fimc_vid_cap *vid_cap, - struct fimc_vid_buffer *buf) + +/** + * fimc_active_queue_add - add buffer to the capture active buffers queue + * @buf: buffer to add to the active buffers list + */ +static inline void fimc_active_queue_add(struct fimc_vid_cap *vid_cap, + struct fimc_vid_buffer *buf) { list_add_tail(&buf->list, &vid_cap->active_buf_q); vid_cap->active_buf_cnt++; } -/* - * Pop a video buffer from the capture active buffers queue - * Locking: Need to be called with fimc_dev::slock held. +/** + * fimc_active_queue_pop - pop buffer from the capture active buffers queue + * + * The caller must assure the active_buf_q list is not empty. */ -static inline struct fimc_vid_buffer * -active_queue_pop(struct fimc_vid_cap *vid_cap) +static inline struct fimc_vid_buffer *fimc_active_queue_pop( + struct fimc_vid_cap *vid_cap) { struct fimc_vid_buffer *buf; buf = list_entry(vid_cap->active_buf_q.next, @@ -770,16 +775,23 @@ active_queue_pop(struct fimc_vid_cap *vid_cap) return buf; } -/* Add video buffer to the capture pending buffers queue */ +/** + * fimc_pending_queue_add - add buffer to the capture pending buffers queue + * @buf: buffer to add to the pending buffers list + */ static inline void fimc_pending_queue_add(struct fimc_vid_cap *vid_cap, struct fimc_vid_buffer *buf) { list_add_tail(&buf->list, &vid_cap->pending_buf_q); } -/* Add video buffer to the capture pending buffers queue */ -static inline struct fimc_vid_buffer * -pending_queue_pop(struct fimc_vid_cap *vid_cap) +/** + * fimc_pending_queue_pop - pop buffer from the capture pending buffers queue + * + * The caller must assure the pending_buf_q list is not empty. + */ +static inline struct fimc_vid_buffer *fimc_pending_queue_pop( + struct fimc_vid_cap *vid_cap) { struct fimc_vid_buffer *buf; buf = list_entry(vid_cap->pending_buf_q.next, -- cgit v0.10.2 From 3e4748d867781732c29c00fe8fe4b179d914a977 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 24 Aug 2011 20:45:34 -0300 Subject: [media] s5p-fimc: Add runtime PM support in the camera capture driver Add support for whole pipeline suspend/resume. Sensors must support suspend/resume through s_power subdev operation. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 4693846..d6219c5 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -69,41 +69,45 @@ static int fimc_init_capture(struct fimc_dev *fimc) return ret; } -static int fimc_capture_state_cleanup(struct fimc_dev *fimc) +static int fimc_capture_state_cleanup(struct fimc_dev *fimc, bool suspend) { struct fimc_vid_cap *cap = &fimc->vid_cap; struct fimc_vid_buffer *buf; unsigned long flags; + bool streaming; spin_lock_irqsave(&fimc->slock, flags); - fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_PEND | - 1 << ST_CAPT_SHUT | 1 << ST_CAPT_STREAM | - 1 << ST_CAPT_ISP_STREAM); + streaming = fimc->state & (1 << ST_CAPT_ISP_STREAM); - fimc->vid_cap.active_buf_cnt = 0; + fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_SHUT | + 1 << ST_CAPT_STREAM | 1 << ST_CAPT_ISP_STREAM); + if (!suspend) + fimc->state &= ~(1 << ST_CAPT_PEND | 1 << ST_CAPT_SUSPENDED); - /* Release buffers that were enqueued in the driver by videobuf2. */ - while (!list_empty(&cap->pending_buf_q)) { + /* Release unused buffers */ + while (!suspend && !list_empty(&cap->pending_buf_q)) { buf = fimc_pending_queue_pop(cap); vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } - + /* If suspending put unused buffers onto pending queue */ while (!list_empty(&cap->active_buf_q)) { buf = fimc_active_queue_pop(cap); - vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + if (suspend) + fimc_pending_queue_add(cap, buf); + else + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } - + set_bit(ST_CAPT_SUSPENDED, &fimc->state); spin_unlock_irqrestore(&fimc->slock, flags); - if (test_bit(ST_CAPT_ISP_STREAM, &fimc->state)) + if (streaming) return fimc_pipeline_s_stream(fimc, 0); else return 0; } -static int fimc_stop_capture(struct fimc_dev *fimc) +static int fimc_stop_capture(struct fimc_dev *fimc, bool suspend) { - struct fimc_vid_cap *cap = &fimc->vid_cap; unsigned long flags; if (!fimc_capture_active(fimc)) @@ -116,9 +120,9 @@ static int fimc_stop_capture(struct fimc_dev *fimc) wait_event_timeout(fimc->irq_queue, !test_bit(ST_CAPT_SHUT, &fimc->state), - FIMC_SHUTDOWN_TIMEOUT); + (2*HZ/10)); /* 200 ms */ - return fimc_capture_state_cleanup(fimc); + return fimc_capture_state_cleanup(fimc, suspend); } /** @@ -181,7 +185,7 @@ static int start_streaming(struct vb2_queue *q, unsigned int count) return 0; error: - fimc_capture_state_cleanup(fimc); + fimc_capture_state_cleanup(fimc, false); return ret; } @@ -193,17 +197,46 @@ static int stop_streaming(struct vb2_queue *q) if (!fimc_capture_active(fimc)) return -EINVAL; - return fimc_stop_capture(fimc); + return fimc_stop_capture(fimc, false); } int fimc_capture_suspend(struct fimc_dev *fimc) { - return -EBUSY; + bool suspend = fimc_capture_busy(fimc); + + int ret = fimc_stop_capture(fimc, suspend); + if (ret) + return ret; + return fimc_pipeline_shutdown(fimc); } +static void buffer_queue(struct vb2_buffer *vb); + int fimc_capture_resume(struct fimc_dev *fimc) { + struct fimc_vid_cap *vid_cap = &fimc->vid_cap; + struct fimc_vid_buffer *buf; + int i; + + if (!test_and_clear_bit(ST_CAPT_SUSPENDED, &fimc->state)) + return 0; + + INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q); + vid_cap->buf_index = 0; + fimc_pipeline_initialize(fimc, &fimc->vid_cap.vfd->entity, + false); + fimc_init_capture(fimc); + + clear_bit(ST_CAPT_SUSPENDED, &fimc->state); + + for (i = 0; i < vid_cap->reqbufs_count; i++) { + if (list_empty(&vid_cap->pending_buf_q)) + break; + buf = fimc_pending_queue_pop(vid_cap); + buffer_queue(&buf->vb); + } return 0; + } static unsigned int get_plane_size(struct fimc_frame *fr, unsigned int plane) @@ -271,8 +304,9 @@ static void buffer_queue(struct vb2_buffer *vb) spin_lock_irqsave(&fimc->slock, flags); fimc_prepare_addr(ctx, &buf->vb, &ctx->d_frame, &buf->paddr); - if (!test_bit(ST_CAPT_STREAM, &fimc->state) - && vid_cap->active_buf_cnt < FIMC_MAX_OUT_BUFS) { + if (!test_bit(ST_CAPT_SUSPENDED, &fimc->state) && + !test_bit(ST_CAPT_STREAM, &fimc->state) && + vid_cap->active_buf_cnt < FIMC_MAX_OUT_BUFS) { /* Setup the buffer directly for processing. */ int buf_id = (vid_cap->reqbufs_count == 1) ? -1 : vid_cap->buf_index; @@ -366,6 +400,7 @@ static int fimc_capture_open(struct file *file) if (fimc_m2m_active(fimc)) return -EBUSY; + set_bit(ST_CAPT_BUSY, &fimc->state); pm_runtime_get_sync(&fimc->pdev->dev); if (++fimc->vid_cap.refcnt == 1) { @@ -377,6 +412,7 @@ static int fimc_capture_open(struct file *file) pm_runtime_put_sync(&fimc->pdev->dev); fimc->vid_cap.refcnt--; v4l2_fh_release(file); + clear_bit(ST_CAPT_BUSY, &fimc->state); return ret; } ret = fimc_capture_ctrls_create(fimc); @@ -394,14 +430,18 @@ static int fimc_capture_close(struct file *file) dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state); if (--fimc->vid_cap.refcnt == 0) { - fimc_stop_capture(fimc); + clear_bit(ST_CAPT_BUSY, &fimc->state); + fimc_stop_capture(fimc, false); fimc_pipeline_shutdown(fimc); - fimc_ctrls_delete(fimc->vid_cap.ctx); - vb2_queue_release(&fimc->vid_cap.vbq); + clear_bit(ST_CAPT_SUSPENDED, &fimc->state); } pm_runtime_put(&fimc->pdev->dev); + if (fimc->vid_cap.refcnt == 0) { + vb2_queue_release(&fimc->vid_cap.vbq); + fimc_ctrls_delete(fimc->vid_cap.ctx); + } return v4l2_fh_release(file); } diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 33c7069..a51bf30 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -334,6 +334,11 @@ void fimc_capture_irq_handler(struct fimc_dev *fimc, bool final) struct timeval *tv; struct timespec ts; + if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) { + wake_up(&fimc->irq_queue); + return; + } + if (!list_empty(&cap->active_buf_q) && test_bit(ST_CAPT_RUN, &fimc->state) && final) { ktime_get_real_ts(&ts); @@ -348,11 +353,6 @@ void fimc_capture_irq_handler(struct fimc_dev *fimc, bool final) vb2_buffer_done(&v_buf->vb, VB2_BUF_STATE_DONE); } - if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) { - wake_up(&fimc->irq_queue); - return; - } - if (!list_empty(&cap->pending_buf_q)) { v_buf = fimc_pending_queue_pop(cap); diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 82ac597..a6936da 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -63,6 +63,7 @@ enum fimc_dev_flags { ST_CAPT_RUN, ST_CAPT_STREAM, ST_CAPT_ISP_STREAM, + ST_CAPT_SUSPENDED, ST_CAPT_SHUT, ST_CAPT_BUSY, ST_CAPT_APPLY_CFG, -- cgit v0.10.2 From 566afaace58e3a800d2a903424960ad97d203c68 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 7 Jun 2011 11:19:33 -0300 Subject: [media] s5p-fimc: Correct crop offset alignment on exynos4 Horizontal crop offset must be multiple of 2 otherwise color distortion occurs. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index a51bf30..afadb5e 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -1898,7 +1898,7 @@ static struct samsung_fimc_variant fimc0_variant_exynos4 = { .has_mainscaler_ext = 1, .min_inp_pixsize = 16, .min_out_pixsize = 16, - .hor_offs_align = 1, + .hor_offs_align = 2, .out_buf_count = 32, .pix_limit = &s5p_pix_limit[1], }; @@ -1910,7 +1910,7 @@ static struct samsung_fimc_variant fimc3_variant_exynos4 = { .has_mainscaler_ext = 1, .min_inp_pixsize = 16, .min_out_pixsize = 16, - .hor_offs_align = 1, + .hor_offs_align = 2, .out_buf_count = 32, .pix_limit = &s5p_pix_limit[3], }; -- cgit v0.10.2 From 8f401543ec96fb58533a2bef41e2c584fe55a114 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 7 Jul 2011 06:42:05 -0300 Subject: [media] s5p-fimc: Remove single-planar capability flags The driver supports only multi-planar API and conversion to single-planar API should be done in libv4l2. Remove misleading single planar capability flags to avoid problems in applications and libv4l2. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index d6219c5..931f469 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -618,8 +618,7 @@ static int fimc_vidioc_querycap_capture(struct file *file, void *priv, strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1); strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1); cap->bus_info[0] = 0; - cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VIDEO_CAPTURE_MPLANE; + cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE_MPLANE; return 0; } diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index afadb5e..6c1c9cb 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -864,7 +864,6 @@ static int fimc_m2m_querycap(struct file *file, void *fh, strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1); cap->bus_info[0] = 0; cap->capabilities = V4L2_CAP_STREAMING | - V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE; return 0; -- cgit v0.10.2 From 62dd28d0c659db29bdb89cfe9f0aefe42f0adfe9 Mon Sep 17 00:00:00 2001 From: Tony Jago Date: Fri, 12 Aug 2011 00:19:11 -0300 Subject: [media] saa7164: Add support for another HVR2200 hardware revision Hauppauge have released a new model rev, sub id 8940, this adds support. [stoth@kernellabs.com: I modified Tony's patch slightly in relation to the card numbering in saa7164.h, appending rather than inserting the new card - normal practise] Signed-off-by: Tony Jago Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/saa7164/saa7164-cards.c b/drivers/media/video/saa7164/saa7164-cards.c index 69822a4..c713691 100644 --- a/drivers/media/video/saa7164/saa7164-cards.c +++ b/drivers/media/video/saa7164/saa7164-cards.c @@ -203,6 +203,66 @@ struct saa7164_board saa7164_boards[] = { .i2c_reg_len = REGLEN_8bit, } }, }, + [SAA7164_BOARD_HAUPPAUGE_HVR2200_4] = { + .name = "Hauppauge WinTV-HVR2200", + .porta = SAA7164_MPEG_DVB, + .portb = SAA7164_MPEG_DVB, + .portc = SAA7164_MPEG_ENCODER, + .portd = SAA7164_MPEG_ENCODER, + .porte = SAA7164_MPEG_VBI, + .portf = SAA7164_MPEG_VBI, + .chiprev = SAA7164_CHIP_REV3, + .unit = {{ + .id = 0x1d, + .type = SAA7164_UNIT_EEPROM, + .name = "4K EEPROM", + .i2c_bus_nr = SAA7164_I2C_BUS_0, + .i2c_bus_addr = 0xa0 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x04, + .type = SAA7164_UNIT_TUNER, + .name = "TDA18271-1", + .i2c_bus_nr = SAA7164_I2C_BUS_1, + .i2c_bus_addr = 0xc0 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x05, + .type = SAA7164_UNIT_ANALOG_DEMODULATOR, + .name = "TDA8290-1", + .i2c_bus_nr = SAA7164_I2C_BUS_1, + .i2c_bus_addr = 0x84 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x1b, + .type = SAA7164_UNIT_TUNER, + .name = "TDA18271-2", + .i2c_bus_nr = SAA7164_I2C_BUS_2, + .i2c_bus_addr = 0xc0 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x1c, + .type = SAA7164_UNIT_ANALOG_DEMODULATOR, + .name = "TDA8290-2", + .i2c_bus_nr = SAA7164_I2C_BUS_2, + .i2c_bus_addr = 0x84 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x1e, + .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, + .name = "TDA10048-1", + .i2c_bus_nr = SAA7164_I2C_BUS_1, + .i2c_bus_addr = 0x10 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x1f, + .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, + .name = "TDA10048-2", + .i2c_bus_nr = SAA7164_I2C_BUS_2, + .i2c_bus_addr = 0x12 >> 1, + .i2c_reg_len = REGLEN_8bit, + } }, + }, [SAA7164_BOARD_HAUPPAUGE_HVR2250] = { .name = "Hauppauge WinTV-HVR2250", .porta = SAA7164_MPEG_DVB, @@ -426,6 +486,10 @@ struct saa7164_subid saa7164_subids[] = { .subvendor = 0x0070, .subdevice = 0x8851, .card = SAA7164_BOARD_HAUPPAUGE_HVR2250_2, + }, { + .subvendor = 0x0070, + .subdevice = 0x8940, + .card = SAA7164_BOARD_HAUPPAUGE_HVR2200_4, }, }; const unsigned int saa7164_idcount = ARRAY_SIZE(saa7164_subids); @@ -469,6 +533,7 @@ void saa7164_gpio_setup(struct saa7164_dev *dev) case SAA7164_BOARD_HAUPPAUGE_HVR2200: case SAA7164_BOARD_HAUPPAUGE_HVR2200_2: case SAA7164_BOARD_HAUPPAUGE_HVR2200_3: + case SAA7164_BOARD_HAUPPAUGE_HVR2200_4: case SAA7164_BOARD_HAUPPAUGE_HVR2250: case SAA7164_BOARD_HAUPPAUGE_HVR2250_2: case SAA7164_BOARD_HAUPPAUGE_HVR2250_3: @@ -549,6 +614,7 @@ void saa7164_card_setup(struct saa7164_dev *dev) case SAA7164_BOARD_HAUPPAUGE_HVR2200: case SAA7164_BOARD_HAUPPAUGE_HVR2200_2: case SAA7164_BOARD_HAUPPAUGE_HVR2200_3: + case SAA7164_BOARD_HAUPPAUGE_HVR2200_4: case SAA7164_BOARD_HAUPPAUGE_HVR2250: case SAA7164_BOARD_HAUPPAUGE_HVR2250_2: case SAA7164_BOARD_HAUPPAUGE_HVR2250_3: diff --git a/drivers/media/video/saa7164/saa7164-dvb.c b/drivers/media/video/saa7164/saa7164-dvb.c index f65eab6..d377937 100644 --- a/drivers/media/video/saa7164/saa7164-dvb.c +++ b/drivers/media/video/saa7164/saa7164-dvb.c @@ -475,6 +475,7 @@ int saa7164_dvb_register(struct saa7164_port *port) case SAA7164_BOARD_HAUPPAUGE_HVR2200: case SAA7164_BOARD_HAUPPAUGE_HVR2200_2: case SAA7164_BOARD_HAUPPAUGE_HVR2200_3: + case SAA7164_BOARD_HAUPPAUGE_HVR2200_4: i2c_bus = &dev->i2c_bus[port->nr + 1]; switch (port->nr) { case 0: diff --git a/drivers/media/video/saa7164/saa7164.h b/drivers/media/video/saa7164/saa7164.h index 6678bf1..35b6430 100644 --- a/drivers/media/video/saa7164/saa7164.h +++ b/drivers/media/video/saa7164/saa7164.h @@ -82,6 +82,7 @@ #define SAA7164_BOARD_HAUPPAUGE_HVR2200_3 6 #define SAA7164_BOARD_HAUPPAUGE_HVR2250_2 7 #define SAA7164_BOARD_HAUPPAUGE_HVR2250_3 8 +#define SAA7164_BOARD_HAUPPAUGE_HVR2200_4 9 #define SAA7164_MAX_UNITS 8 #define SAA7164_TS_NUMBER_OF_LINES 312 -- cgit v0.10.2 From 4b5d01e9f66446be0c2beebfab0463210bed315d Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 8 Sep 2011 00:30:31 -0300 Subject: [media] dvb-usb: fix streaming failure on channel change This fixes a bug introduced by a previous changeset entitled, [media] dvb-usb: refactor MFE code for individual streaming config per frontend As reported by Antti Palosaari, This error is shown by VLC when channel changed: [0x7f1bbc000cd0] dvb access error: DMXSetFilter: failed with -1 (Invalid argument) [0x7f1bbc000cd0] dvb access error: DMXSetFilter failed [0x7f1bbc32f910] main stream error: cannot pre fill buffer After my own investigations, I've determined that this error case occurs when the application stops streaming but leaves the frontend and dvr devices open. A typical example of this usage would be a channel change operation while watching live television. The error occurs when the application attempts to stream after tuning to the new channel. To prevent this error, don't set adap->active_fe to -1 unless the application closes the device. Cc: Antti Palosaari Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c index 3f11159..460b5ae 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c @@ -77,9 +77,6 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) } } - if ((adap->feedcount == onoff) && (!onoff)) - adap->active_fe = -1; - return 0; } -- cgit v0.10.2 From 2d04c13a507f5a01daa7422cd52250809573cfdb Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 8 Sep 2011 01:17:39 -0300 Subject: [media] dvb-usb: improve sanity check of adap->active_fe in dvb_usb_ctrl_feed The check for (adap->active_fe < 0) at the top of dvb_usb_ctrl_feed is a sanity check to ensure that adap->active_fe is valid. Improve that sanity check by also checking for (adap->active_fe >= adap->num_frontends_initialized) Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c index 460b5ae..038679b 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c @@ -17,7 +17,8 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) if (adap == NULL) return -ENODEV; - if (adap->active_fe < 0) { + if ((adap->active_fe < 0) || + (adap->active_fe >= adap->num_frontends_initialized)) { return -EINVAL; } -- cgit v0.10.2 From 72a16e8c7a9ba02a2e63c8c21bb055f4a33abc49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Tue, 9 Aug 2011 05:28:17 -0300 Subject: [media] gspca - ov519: Fix LED inversion of some ov519 webcams MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The list of the webcams which have LED inversion was rebuild scanning ms-win .inf files. Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index 17d0d56..6a01b35 100644 --- a/drivers/media/video/gspca/ov519.c +++ b/drivers/media/video/gspca/ov519.c @@ -2861,7 +2861,6 @@ static void ov7xx0_configure(struct sd *sd) case 0x60: PDEBUG(D_PROBE, "Sensor is a OV7660"); sd->sensor = SEN_OV7660; - sd->invert_led = 0; break; default: PDEBUG(D_PROBE, "Unknown sensor: 0x76%x", low); @@ -3338,7 +3337,6 @@ static int sd_config(struct gspca_dev *gspca_dev, case BRIDGE_OV519: cam->cam_mode = ov519_vga_mode; cam->nmodes = ARRAY_SIZE(ov519_vga_mode); - sd->invert_led = !sd->invert_led; break; case BRIDGE_OVFX2: cam->cam_mode = ov519_vga_mode; @@ -5006,24 +5004,24 @@ static const struct sd_desc sd_desc = { /* -- module initialisation -- */ static const struct usb_device_id device_table[] = { {USB_DEVICE(0x041e, 0x4003), .driver_info = BRIDGE_W9968CF }, - {USB_DEVICE(0x041e, 0x4052), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x041e, 0x405f), + {USB_DEVICE(0x041e, 0x4052), .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, + {USB_DEVICE(0x041e, 0x405f), .driver_info = BRIDGE_OV519 }, {USB_DEVICE(0x041e, 0x4060), .driver_info = BRIDGE_OV519 }, {USB_DEVICE(0x041e, 0x4061), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x041e, 0x4064), - .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, + {USB_DEVICE(0x041e, 0x4064), .driver_info = BRIDGE_OV519 }, {USB_DEVICE(0x041e, 0x4067), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x041e, 0x4068), + {USB_DEVICE(0x041e, 0x4068), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x045e, 0x028c), .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, - {USB_DEVICE(0x045e, 0x028c), .driver_info = BRIDGE_OV519 }, {USB_DEVICE(0x054c, 0x0154), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x054c, 0x0155), - .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, + {USB_DEVICE(0x054c, 0x0155), .driver_info = BRIDGE_OV519 }, {USB_DEVICE(0x05a9, 0x0511), .driver_info = BRIDGE_OV511 }, {USB_DEVICE(0x05a9, 0x0518), .driver_info = BRIDGE_OV518 }, - {USB_DEVICE(0x05a9, 0x0519), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x05a9, 0x0530), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x05a9, 0x0519), + .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, + {USB_DEVICE(0x05a9, 0x0530), + .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, {USB_DEVICE(0x05a9, 0x2800), .driver_info = BRIDGE_OVFX2 }, {USB_DEVICE(0x05a9, 0x4519), .driver_info = BRIDGE_OV519 }, {USB_DEVICE(0x05a9, 0x8519), .driver_info = BRIDGE_OV519 }, -- cgit v0.10.2 From 822f6e2a9a41d3fea094591bf8cc227e12f5cb8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Tue, 9 Aug 2011 15:13:50 -0300 Subject: [media] gspca - sonixj: Fix the darkness of sensor om6802 in 320x240 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The images are clearer with a lower bridge clock. Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 816008f..f3cfb97 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -2534,6 +2534,10 @@ static int sd_start(struct gspca_dev *gspca_dev) if (!mode) { /* if 640x480 */ reg17 &= ~MCK_SIZE_MASK; reg17 |= 0x04; /* clock / 4 */ + } else { + reg01 &= ~SYS_SEL_48M; /* clk 24Mz */ + reg17 &= ~MCK_SIZE_MASK; + reg17 |= 0x02; /* clock / 2 */ } break; case SENSOR_OV7630: -- cgit v0.10.2 From 7d84a179b1f8c473ae7557d9f227c25771cc63c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Sun, 3 Jul 2011 07:27:24 -0300 Subject: [media] gspca - jeilinj: Cleanup code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/jeilinj.c b/drivers/media/video/gspca/jeilinj.c index 4ccc08d..8e3dabe 100644 --- a/drivers/media/video/gspca/jeilinj.c +++ b/drivers/media/video/gspca/jeilinj.c @@ -405,13 +405,7 @@ static int sd_config(struct gspca_dev *gspca_dev, dev->type = id->driver_info; gspca_dev->cam.ctrls = dev->ctrls; dev->quality = QUALITY_DEF; - dev->ctrls[LIGHTFREQ].def = V4L2_CID_POWER_LINE_FREQUENCY_60HZ; - dev->ctrls[RED].def = RED_BALANCE_DEF; - dev->ctrls[GREEN].def = GREEN_BALANCE_DEF; - dev->ctrls[BLUE].def = BLUE_BALANCE_DEF; - PDEBUG(D_PROBE, - "JEILINJ camera detected" - " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); + cam->cam_mode = jlj_mode; cam->nmodes = ARRAY_SIZE(jlj_mode); cam->bulk = 1; @@ -424,7 +418,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev) { int i; u8 *buf; - u8 stop_commands[][2] = { + static u8 stop_commands[][2] = { {0x71, 0x00}, {0x70, 0x09}, {0x71, 0x80}, -- cgit v0.10.2 From abe8cee744aa8aa29a2d88b915a17f0c7744aa3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Wed, 10 Aug 2011 05:13:45 -0300 Subject: [media] gspca - sonixj: Adjust the contrast control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The contrast was too low. Higher values are better. Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index f3cfb97..7ab0c1a 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -159,7 +159,7 @@ static const struct ctrl sd_ctrls[NCTRLS] = { #define CONTRAST_MAX 127 .maximum = CONTRAST_MAX, .step = 1, - .default_value = 63, + .default_value = 20, }, .set_control = setcontrast }, @@ -2021,13 +2021,13 @@ static void setcontrast(struct gspca_dev *gspca_dev) u8 k2; u8 contrast[6]; - k2 = sd->ctrls[CONTRAST].val * 0x30 / (CONTRAST_MAX + 1) - + 0x10; /* 10..40 */ + k2 = sd->ctrls[CONTRAST].val * 37 / (CONTRAST_MAX + 1) + + 37; /* 37..73 */ contrast[0] = (k2 + 1) / 2; /* red */ contrast[1] = 0; contrast[2] = k2; /* green */ contrast[3] = 0; - contrast[4] = (k2 + 1) / 5; /* blue */ + contrast[4] = k2 / 5; /* blue */ contrast[5] = 0; reg_w(gspca_dev, 0x84, contrast, sizeof contrast); } -- cgit v0.10.2 From 2458df4324b802e51c830e2a7ff851dbe18df9bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Wed, 10 Aug 2011 05:47:34 -0300 Subject: [media] gspca - sonixj: Increase the exposure for sensor soi768 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lower exposure values give too dark images. Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 7ab0c1a..2c1e039 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -1279,7 +1279,7 @@ static const u8 soi768_sensor_param1[][8] = { /* global gain ? : 07 - change with 0x15 at the end */ {0xa1, 0x21, 0x10, 0x3f, 0x00, 0x00, 0x00, 0x10}, /* ???? : 063f */ {0xa1, 0x21, 0x04, 0x06, 0x00, 0x00, 0x00, 0x10}, - {0xb1, 0x21, 0x2d, 0x00, 0x02, 0x00, 0x00, 0x10}, + {0xb1, 0x21, 0x2d, 0x63, 0x03, 0x00, 0x00, 0x10}, /* exposure ? : 0200 - change with 0x1e at the end */ {} }; -- cgit v0.10.2 From b813b0ca1310a0fec2789bd34378492e983a866b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Wed, 10 Aug 2011 05:54:34 -0300 Subject: [media] gspca - sonixj: Cleanup source and remove useless instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 2c1e039..c746bf1 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -1,7 +1,7 @@ /* * Sonix sn9c102p sn9c105 sn9c120 (jpeg) subdriver * - * Copyright (C) 2009-2010 Jean-François Moine + * Copyright (C) 2009-2011 Jean-François Moine * Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr * * This program is free software; you can redistribute it and/or modify @@ -138,7 +138,7 @@ static void setillum(struct gspca_dev *gspca_dev); static void setfreq(struct gspca_dev *gspca_dev); static const struct ctrl sd_ctrls[NCTRLS] = { -[BRIGHTNESS] = { +[BRIGHTNESS] = { { .id = V4L2_CID_BRIGHTNESS, .type = V4L2_CTRL_TYPE_INTEGER, @@ -739,7 +739,7 @@ static const u8 mi0360_sensor_init[][8] = { {0xd1, 0x5d, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10}, {0xd1, 0x5d, 0x24, 0x00, 0x00, 0x00, 0x00, 0x10}, {0xd1, 0x5d, 0x26, 0x00, 0x00, 0x00, 0x24, 0x10}, - {0xd1, 0x5d, 0x2f, 0xf7, 0xB0, 0x00, 0x04, 0x10}, + {0xd1, 0x5d, 0x2f, 0xf7, 0xb0, 0x00, 0x04, 0x10}, {0xd1, 0x5d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x10}, {0xd1, 0x5d, 0x33, 0x00, 0x00, 0x01, 0x00, 0x10}, {0xb1, 0x5d, 0x3d, 0x06, 0x8f, 0x00, 0x00, 0x10}, @@ -2008,8 +2008,7 @@ static void setbrightness(struct gspca_dev *gspca_dev) case SENSOR_OM6802: expo = brightness << 2; sd->exposure = setexposure(gspca_dev, expo); - k2 = brightness >> 3; - break; + return; /* Y offset already set */ } reg_w1(gspca_dev, 0x96, k2); /* color matrix Y offset */ @@ -2509,9 +2508,7 @@ static int sd_start(struct gspca_dev *gspca_dev) break; case SENSOR_HV7131R: case SENSOR_MI0360: - if (mode) - reg01 |= SYS_SEL_48M; /* 320x240: clk 48Mhz */ - else + if (!mode) reg01 &= ~SYS_SEL_48M; /* 640x480: clk 24Mhz */ reg17 &= ~MCK_SIZE_MASK; reg17 |= 0x01; /* clock / 1 */ -- cgit v0.10.2 From d701a48a4bbcf7a4ac8c1b7d9adc9c2028cbea84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Wed, 10 Aug 2011 06:01:44 -0300 Subject: [media] gspca - kinect: Remove the gspca_debug definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The variable gspca_debug is defined and settable in gspca main. Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/kinect.c b/drivers/media/video/gspca/kinect.c index 9ed15a1..4fe51fd 100644 --- a/drivers/media/video/gspca/kinect.c +++ b/drivers/media/video/gspca/kinect.c @@ -36,11 +36,6 @@ MODULE_AUTHOR("Antonio Ospite "); MODULE_DESCRIPTION("GSPCA/Kinect Sensor Device USB Camera Driver"); MODULE_LICENSE("GPL"); -#ifdef GSPCA_DEBUG -int gspca_debug = D_ERR | D_PROBE | D_CONF | D_STREAM | D_FRAM | D_PACK | - D_USBI | D_USBO | D_V4L2; -#endif - struct pkt_hdr { uint8_t magic[2]; uint8_t pad; -- cgit v0.10.2 From 7592e0377636963eade33810fcad06487b8b153f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Wed, 10 Aug 2011 07:11:49 -0300 Subject: [media] gspca - ov534_9: Use the new control mechanism MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/ov534_9.c b/drivers/media/video/gspca/ov534_9.c index a954a31..8890319 100644 --- a/drivers/media/video/gspca/ov534_9.c +++ b/drivers/media/video/gspca/ov534_9.c @@ -47,39 +47,37 @@ MODULE_AUTHOR("Jean-Francois Moine "); MODULE_DESCRIPTION("GSPCA/OV534_9 USB Camera Driver"); MODULE_LICENSE("GPL"); +/* controls */ +enum e_ctrl { + BRIGHTNESS, + CONTRAST, + AUTOGAIN, + EXPOSURE, + SHARPNESS, + SATUR, + LIGHTFREQ, + NCTRLS /* number of controls */ +}; + /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ + struct gspca_ctrl ctrls[NCTRLS]; __u32 last_pts; u8 last_fid; - - u8 brightness; - u8 contrast; - u8 autogain; - u8 exposure; - s8 sharpness; - u8 satur; - u8 freq; }; /* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setsatur(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getsatur(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { - { /* 0 */ +static void setbrightness(struct gspca_dev *gspca_dev); +static void setcontrast(struct gspca_dev *gspca_dev); +static void setautogain(struct gspca_dev *gspca_dev); +static void setexposure(struct gspca_dev *gspca_dev); +static void setsharpness(struct gspca_dev *gspca_dev); +static void setsatur(struct gspca_dev *gspca_dev); +static void setlightfreq(struct gspca_dev *gspca_dev); + +static const struct ctrl sd_ctrls[NCTRLS] = { +[BRIGHTNESS] = { { .id = V4L2_CID_BRIGHTNESS, .type = V4L2_CTRL_TYPE_INTEGER, @@ -87,13 +85,11 @@ static const struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 15, .step = 1, -#define BRIGHTNESS_DEF 7 - .default_value = BRIGHTNESS_DEF, + .default_value = 7 }, - .set = sd_setbrightness, - .get = sd_getbrightness, + .set_control = setbrightness }, - { /* 1 */ +[CONTRAST] = { { .id = V4L2_CID_CONTRAST, .type = V4L2_CTRL_TYPE_INTEGER, @@ -101,13 +97,11 @@ static const struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 15, .step = 1, -#define CONTRAST_DEF 3 - .default_value = CONTRAST_DEF, + .default_value = 3 }, - .set = sd_setcontrast, - .get = sd_getcontrast, + .set_control = setcontrast }, - { /* 2 */ +[AUTOGAIN] = { { .id = V4L2_CID_AUTOGAIN, .type = V4L2_CTRL_TYPE_BOOLEAN, @@ -118,11 +112,9 @@ static const struct ctrl sd_ctrls[] = { #define AUTOGAIN_DEF 1 .default_value = AUTOGAIN_DEF, }, - .set = sd_setautogain, - .get = sd_getautogain, + .set_control = setautogain }, -#define EXPO_IDX 3 - { /* 3 */ +[EXPOSURE] = { { .id = V4L2_CID_EXPOSURE, .type = V4L2_CTRL_TYPE_INTEGER, @@ -130,13 +122,11 @@ static const struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 3, .step = 1, -#define EXPO_DEF 0 - .default_value = EXPO_DEF, + .default_value = 0 }, - .set = sd_setexposure, - .get = sd_getexposure, + .set_control = setexposure }, - { /* 4 */ +[SHARPNESS] = { { .id = V4L2_CID_SHARPNESS, .type = V4L2_CTRL_TYPE_INTEGER, @@ -144,13 +134,11 @@ static const struct ctrl sd_ctrls[] = { .minimum = -1, /* -1 = auto */ .maximum = 4, .step = 1, -#define SHARPNESS_DEF -1 - .default_value = SHARPNESS_DEF, + .default_value = -1 }, - .set = sd_setsharpness, - .get = sd_getsharpness, + .set_control = setsharpness }, - { /* 5 */ +[SATUR] = { { .id = V4L2_CID_SATURATION, .type = V4L2_CTRL_TYPE_INTEGER, @@ -158,13 +146,11 @@ static const struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 4, .step = 1, -#define SATUR_DEF 2 - .default_value = SATUR_DEF, + .default_value = 2 }, - .set = sd_setsatur, - .get = sd_getsatur, + .set_control = setsatur }, - { +[LIGHTFREQ] = { { .id = V4L2_CID_POWER_LINE_FREQUENCY, .type = V4L2_CTRL_TYPE_MENU, @@ -172,11 +158,9 @@ static const struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */ .step = 1, -#define FREQ_DEF 0 - .default_value = FREQ_DEF, + .default_value = 0 }, - .set = sd_setfreq, - .get = sd_getfreq, + .set_control = setlightfreq }, }; @@ -924,7 +908,9 @@ static void setbrightness(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; u8 val; - val = sd->brightness; + if (gspca_dev->ctrl_dis & (1 << BRIGHTNESS)) + return; + val = sd->ctrls[BRIGHTNESS].val; if (val < 8) val = 15 - val; /* f .. 8 */ else @@ -938,7 +924,7 @@ static void setcontrast(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; sccb_write(gspca_dev, 0x56, /* cnst1 - contrast 1 ctrl coeff */ - sd->contrast << 4); + sd->ctrls[CONTRAST].val << 4); } static void setautogain(struct gspca_dev *gspca_dev) @@ -949,7 +935,7 @@ static void setautogain(struct gspca_dev *gspca_dev) /*fixme: should adjust agc/awb/aec by different controls */ val = sccb_read(gspca_dev, 0x13); /* com8 */ sccb_write(gspca_dev, 0xff, 0x00); - if (sd->autogain) + if (sd->ctrls[AUTOGAIN].val) val |= 0x05; /* agc & aec */ else val &= 0xfa; @@ -963,7 +949,7 @@ static void setexposure(struct gspca_dev *gspca_dev) static const u8 expo[4] = {0x00, 0x25, 0x38, 0x5e}; sccb_write(gspca_dev, 0x10, /* aec[9:2] */ - expo[sd->exposure]); + expo[sd->ctrls[EXPOSURE].val]); val = sccb_read(gspca_dev, 0x13); /* com8 */ sccb_write(gspca_dev, 0xff, 0x00); @@ -979,7 +965,7 @@ static void setsharpness(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; s8 val; - val = sd->sharpness; + val = sd->ctrls[SHARPNESS].val; if (val < 0) { /* auto */ val = sccb_read(gspca_dev, 0x42); /* com17 */ sccb_write(gspca_dev, 0xff, 0x00); @@ -1008,8 +994,8 @@ static void setsatur(struct gspca_dev *gspca_dev) {0x48, 0x90} }; - val1 = matrix[sd->satur][0]; - val2 = matrix[sd->satur][1]; + val1 = matrix[sd->ctrls[SATUR].val][0]; + val2 = matrix[sd->ctrls[SATUR].val][1]; val3 = val1 + val2; sccb_write(gspca_dev, 0x4f, val3); /* matrix coeff */ sccb_write(gspca_dev, 0x50, val3); @@ -1024,14 +1010,14 @@ static void setsatur(struct gspca_dev *gspca_dev) sccb_write(gspca_dev, 0x41, val1); } -static void setfreq(struct gspca_dev *gspca_dev) +static void setlightfreq(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; u8 val; val = sccb_read(gspca_dev, 0x13); /* com8 */ sccb_write(gspca_dev, 0xff, 0x00); - if (sd->freq == 0) { + if (sd->ctrls[LIGHTFREQ].val == 0) { sccb_write(gspca_dev, 0x13, val & 0xdf); return; } @@ -1039,7 +1025,7 @@ static void setfreq(struct gspca_dev *gspca_dev) val = sccb_read(gspca_dev, 0x42); /* com17 */ sccb_write(gspca_dev, 0xff, 0x00); - if (sd->freq == 1) + if (sd->ctrls[LIGHTFREQ].val == 1) val |= 0x01; else val &= 0xfe; @@ -1051,28 +1037,12 @@ static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) { struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - - cam = &gspca_dev->cam; - cam->cam_mode = ov965x_mode; - cam->nmodes = ARRAY_SIZE(ov965x_mode); + gspca_dev->cam.ctrls = sd->ctrls; - sd->brightness = BRIGHTNESS_DEF; - sd->contrast = CONTRAST_DEF; #if AUTOGAIN_DEF != 0 - sd->autogain = AUTOGAIN_DEF; - gspca_dev->ctrl_inac |= (1 << EXPO_IDX); + gspca_dev->ctrl_inac |= (1 << EXPOSURE); #endif -#if EXPO_DEF != 0 - sd->exposure = EXPO_DEF; -#endif -#if SHARPNESS_DEF != 0 - sd->sharpness = SHARPNESS_DEF; -#endif - sd->satur = SATUR_DEF; - sd->freq = FREQ_DEF; - return 0; } @@ -1101,6 +1071,9 @@ static int sd_init(struct gspca_dev *gspca_dev) PDEBUG(D_PROBE, "Sensor ID: %04x", sensor_id); /* initialize */ + gspca_dev->cam.cam_mode = ov965x_mode; + gspca_dev->cam.nmodes = ARRAY_SIZE(ov965x_mode); + reg_w_array(gspca_dev, bridge_init, ARRAY_SIZE(bridge_init)); sccb_w_array(gspca_dev, sensor_init, @@ -1162,7 +1135,7 @@ static int sd_start(struct gspca_dev *gspca_dev) ARRAY_SIZE(sensor_start_2_sxga)); break; } - setfreq(gspca_dev); + setlightfreq(gspca_dev); setautogain(gspca_dev); setbrightness(gspca_dev); setcontrast(gspca_dev); @@ -1264,138 +1237,6 @@ scan_next: } while (remaining_len > 0); } -/* controls */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - return 0; -} - -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->autogain = val; - - if (gspca_dev->streaming) { - if (val) - gspca_dev->ctrl_inac |= (1 << EXPO_IDX); - else - gspca_dev->ctrl_inac &= ~(1 << EXPO_IDX); - setautogain(gspca_dev); - } - return gspca_dev->usb_err; -} - -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->autogain; - return 0; -} - -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->exposure = val; - if (gspca_dev->streaming) - setexposure(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->exposure; - return 0; -} - -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->sharpness = val; - if (gspca_dev->streaming) - setsharpness(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->sharpness; - return 0; -} - -static int sd_setsatur(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->satur = val; - if (gspca_dev->streaming) - setsatur(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getsatur(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->satur; - return 0; -} -static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->freq = val; - if (gspca_dev->streaming) - setfreq(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->freq; - return 0; -} - static int sd_querymenu(struct gspca_dev *gspca_dev, struct v4l2_querymenu *menu) { @@ -1421,7 +1262,7 @@ static int sd_querymenu(struct gspca_dev *gspca_dev, static const struct sd_desc sd_desc = { .name = MODULE_NAME, .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), + .nctrls = NCTRLS, .config = sd_config, .init = sd_init, .start = sd_start, -- cgit v0.10.2 From 8d64d4f67eb051551c0702501c35e9cc27d8b75d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Wed, 10 Aug 2011 07:17:13 -0300 Subject: [media] gspca - ov534_9: New sensor ov9712 and new webcam 05a9:8065 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The webcam is build from an Omnivision test kit which contains a OV538 bridge and a OV9712 sensor. Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt index 5bfa9a7..49102fb 100644 --- a/Documentation/video4linux/gspca.txt +++ b/Documentation/video4linux/gspca.txt @@ -190,6 +190,7 @@ ov519 05a9:0519 OV519 Microphone ov519 05a9:0530 OmniVision ov519 05a9:2800 OmniVision SuperCAM ov519 05a9:4519 Webcam Classic +ov534_9 05a9:8065 OmniVision test kit ov538+ov9712 ov519 05a9:8519 OmniVision ov519 05a9:a511 D-Link USB Digital Video Camera ov519 05a9:a518 D-Link DSB-C310 Webcam diff --git a/drivers/media/video/gspca/ov534_9.c b/drivers/media/video/gspca/ov534_9.c index 8890319..b3b1ea6 100644 --- a/drivers/media/video/gspca/ov534_9.c +++ b/drivers/media/video/gspca/ov534_9.c @@ -1,7 +1,7 @@ /* - * ov534-ov965x gspca driver + * ov534-ov9xxx gspca driver * - * Copyright (C) 2009-2010 Jean-Francois Moine http://moinejf.free.fr + * Copyright (C) 2009-2011 Jean-Francois Moine http://moinejf.free.fr * Copyright (C) 2008 Antonio Ospite * Copyright (C) 2008 Jim Paris * @@ -65,6 +65,13 @@ struct sd { struct gspca_ctrl ctrls[NCTRLS]; __u32 last_pts; u8 last_fid; + + u8 sensor; +}; +enum sensors { + SENSOR_OV965x, /* ov9657 */ + SENSOR_OV971x, /* ov9712 */ + NSENSORS }; /* V4L2 controls supported by the driver */ @@ -192,6 +199,14 @@ static const struct v4l2_pix_format ov965x_mode[] = { .colorspace = V4L2_COLORSPACE_JPEG}, }; +static const struct v4l2_pix_format ov971x_mode[] = { + {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB + } +}; + static const u8 bridge_init[][2] = { {0x88, 0xf8}, {0x89, 0xff}, @@ -226,7 +241,7 @@ static const u8 bridge_init[][2] = { {0x94, 0x11}, }; -static const u8 sensor_init[][2] = { +static const u8 ov965x_init[][2] = { {0x12, 0x80}, /* com7 - SSCB reset */ {0x00, 0x00}, /* gain */ {0x01, 0x80}, /* blue */ @@ -436,7 +451,7 @@ static const u8 bridge_init_2[][2] = { {0x94, 0x11}, }; -static const u8 sensor_init_2[][2] = { +static const u8 ov965x_init_2[][2] = { {0x3b, 0xc4}, {0x1e, 0x04}, /* mvfp */ {0x13, 0xe0}, /* com8 */ @@ -478,7 +493,65 @@ static const u8 sensor_init_2[][2] = { {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */ }; -static const u8 sensor_start_1_vga[][2] = { /* same for qvga */ +static const u8 ov971x_init[][2] = { + {0x12, 0x80}, + {0x09, 0x10}, + {0x1e, 0x07}, + {0x5f, 0x18}, + {0x69, 0x04}, + {0x65, 0x2a}, + {0x68, 0x0a}, + {0x39, 0x28}, + {0x4d, 0x90}, + {0xc1, 0x80}, + {0x0c, 0x30}, + {0x6d, 0x02}, + {0x96, 0xf1}, + {0xbc, 0x68}, + {0x12, 0x00}, + {0x3b, 0x00}, + {0x97, 0x80}, + {0x17, 0x25}, + {0x18, 0xa2}, + {0x19, 0x01}, + {0x1a, 0xca}, + {0x03, 0x0a}, + {0x32, 0x07}, + {0x98, 0x40}, /*{0x98, 0x00},*/ + {0x99, 0xA0}, /*{0x99, 0x00},*/ + {0x9a, 0x01}, /*{0x9a, 0x00},*/ + {0x57, 0x00}, + {0x58, 0x78}, /*{0x58, 0xc8},*/ + {0x59, 0x50}, /*{0x59, 0xa0},*/ + {0x4c, 0x13}, + {0x4b, 0x36}, + {0x3d, 0x3c}, + {0x3e, 0x03}, + {0xbd, 0x50}, /*{0xbd, 0xa0},*/ + {0xbe, 0x78}, /*{0xbe, 0xc8},*/ + {0x4e, 0x55}, + {0x4f, 0x55}, + {0x50, 0x55}, + {0x51, 0x55}, + {0x24, 0x55}, + {0x25, 0x40}, + {0x26, 0xa1}, + {0x5c, 0x59}, + {0x5d, 0x00}, + {0x11, 0x00}, + {0x2a, 0x98}, + {0x2b, 0x06}, + {0x2d, 0x00}, + {0x2e, 0x00}, + {0x13, 0xa5}, + {0x14, 0x40}, + {0x4a, 0x00}, + {0x49, 0xce}, + {0x22, 0x03}, + {0x09, 0x00} +}; + +static const u8 ov965x_start_1_vga[][2] = { /* same for qvga */ {0x12, 0x62}, /* com7 - 30fps VGA YUV */ {0x36, 0xfa}, /* aref3 */ {0x69, 0x0a}, /* hv */ @@ -501,7 +574,7 @@ static const u8 sensor_start_1_vga[][2] = { /* same for qvga */ {0xc0, 0xaa}, }; -static const u8 sensor_start_1_svga[][2] = { +static const u8 ov965x_start_1_svga[][2] = { {0x12, 0x02}, /* com7 - YUYV - VGA 15 full resolution */ {0x36, 0xf8}, /* aref3 */ {0x69, 0x02}, /* hv */ @@ -523,7 +596,7 @@ static const u8 sensor_start_1_svga[][2] = { {0xc0, 0xe2}, }; -static const u8 sensor_start_1_xga[][2] = { +static const u8 ov965x_start_1_xga[][2] = { {0x12, 0x02}, /* com7 */ {0x36, 0xf8}, /* aref3 */ {0x69, 0x02}, /* hv */ @@ -546,7 +619,7 @@ static const u8 sensor_start_1_xga[][2] = { {0xc0, 0xe2}, }; -static const u8 sensor_start_1_sxga[][2] = { +static const u8 ov965x_start_1_sxga[][2] = { {0x12, 0x02}, /* com7 */ {0x36, 0xf8}, /* aref3 */ {0x69, 0x02}, /* hv */ @@ -695,7 +768,7 @@ static const u8 bridge_start_sxga[][2] = { {0x94, 0x11}, }; -static const u8 sensor_start_2_qvga[][2] = { +static const u8 ov965x_start_2_qvga[][2] = { {0x3b, 0xe4}, /* com11 - night mode 1/4 frame rate */ {0x1e, 0x04}, /* mvfp */ {0x13, 0xe0}, /* com8 */ @@ -713,7 +786,7 @@ static const u8 sensor_start_2_qvga[][2] = { {0x3a, 0x80}, /* tslb - yuyv */ }; -static const u8 sensor_start_2_vga[][2] = { +static const u8 ov965x_start_2_vga[][2] = { {0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */ {0x1e, 0x04}, /* mvfp */ {0x13, 0xe0}, /* com8 */ @@ -729,7 +802,7 @@ static const u8 sensor_start_2_vga[][2] = { {0x2d, 0x00}, /* advfl */ }; -static const u8 sensor_start_2_svga[][2] = { /* same for xga */ +static const u8 ov965x_start_2_svga[][2] = { /* same for xga */ {0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */ {0x1e, 0x04}, /* mvfp */ {0x13, 0xe0}, /* com8 */ @@ -743,7 +816,7 @@ static const u8 sensor_start_2_svga[][2] = { /* same for xga */ {0xa3, 0x41}, /* bd60 */ }; -static const u8 sensor_start_2_sxga[][2] = { +static const u8 ov965x_start_2_sxga[][2] = { {0x13, 0xe0}, /* com8 */ {0x00, 0x00}, {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */ @@ -923,6 +996,8 @@ static void setcontrast(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + if (gspca_dev->ctrl_dis & (1 << CONTRAST)) + return; sccb_write(gspca_dev, 0x56, /* cnst1 - contrast 1 ctrl coeff */ sd->ctrls[CONTRAST].val << 4); } @@ -932,6 +1007,8 @@ static void setautogain(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; u8 val; + if (gspca_dev->ctrl_dis & (1 << AUTOGAIN)) + return; /*fixme: should adjust agc/awb/aec by different controls */ val = sccb_read(gspca_dev, 0x13); /* com8 */ sccb_write(gspca_dev, 0xff, 0x00); @@ -948,6 +1025,8 @@ static void setexposure(struct gspca_dev *gspca_dev) u8 val; static const u8 expo[4] = {0x00, 0x25, 0x38, 0x5e}; + if (gspca_dev->ctrl_dis & (1 << EXPOSURE)) + return; sccb_write(gspca_dev, 0x10, /* aec[9:2] */ expo[sd->ctrls[EXPOSURE].val]); @@ -965,6 +1044,8 @@ static void setsharpness(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; s8 val; + if (gspca_dev->ctrl_dis & (1 << SHARPNESS)) + return; val = sd->ctrls[SHARPNESS].val; if (val < 0) { /* auto */ val = sccb_read(gspca_dev, 0x42); /* com17 */ @@ -994,6 +1075,8 @@ static void setsatur(struct gspca_dev *gspca_dev) {0x48, 0x90} }; + if (gspca_dev->ctrl_dis & (1 << SATUR)) + return; val1 = matrix[sd->ctrls[SATUR].val][0]; val2 = matrix[sd->ctrls[SATUR].val][1]; val3 = val1 + val2; @@ -1015,6 +1098,8 @@ static void setlightfreq(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; u8 val; + if (gspca_dev->ctrl_dis & (1 << LIGHTFREQ)) + return; val = sccb_read(gspca_dev, 0x13); /* com8 */ sccb_write(gspca_dev, 0xff, 0x00); if (sd->ctrls[LIGHTFREQ].val == 0) { @@ -1049,6 +1134,7 @@ static int sd_config(struct gspca_dev *gspca_dev, /* this function is called at probe and resume time */ static int sd_init(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; u16 sensor_id; /* reset bridge */ @@ -1071,68 +1157,114 @@ static int sd_init(struct gspca_dev *gspca_dev) PDEBUG(D_PROBE, "Sensor ID: %04x", sensor_id); /* initialize */ - gspca_dev->cam.cam_mode = ov965x_mode; - gspca_dev->cam.nmodes = ARRAY_SIZE(ov965x_mode); - - reg_w_array(gspca_dev, bridge_init, - ARRAY_SIZE(bridge_init)); - sccb_w_array(gspca_dev, sensor_init, - ARRAY_SIZE(sensor_init)); - reg_w_array(gspca_dev, bridge_init_2, - ARRAY_SIZE(bridge_init_2)); - sccb_w_array(gspca_dev, sensor_init_2, - ARRAY_SIZE(sensor_init_2)); - reg_w(gspca_dev, 0xe0, 0x00); - reg_w(gspca_dev, 0xe0, 0x01); - set_led(gspca_dev, 0); - reg_w(gspca_dev, 0xe0, 0x00); + if ((sensor_id & 0xfff0) == 0x9650) { + sd->sensor = SENSOR_OV965x; + + gspca_dev->cam.cam_mode = ov965x_mode; + gspca_dev->cam.nmodes = ARRAY_SIZE(ov965x_mode); + + reg_w_array(gspca_dev, bridge_init, + ARRAY_SIZE(bridge_init)); + sccb_w_array(gspca_dev, ov965x_init, + ARRAY_SIZE(ov965x_init)); + reg_w_array(gspca_dev, bridge_init_2, + ARRAY_SIZE(bridge_init_2)); + sccb_w_array(gspca_dev, ov965x_init_2, + ARRAY_SIZE(ov965x_init_2)); + reg_w(gspca_dev, 0xe0, 0x00); + reg_w(gspca_dev, 0xe0, 0x01); + set_led(gspca_dev, 0); + reg_w(gspca_dev, 0xe0, 0x00); + } else if ((sensor_id & 0xfff0) == 0x9710) { + const char *p; + int l; + + sd->sensor = SENSOR_OV971x; + + gspca_dev->cam.cam_mode = ov971x_mode; + gspca_dev->cam.nmodes = ARRAY_SIZE(ov971x_mode); + + /* no control yet */ + gspca_dev->ctrl_dis = (1 << NCTRLS) - 1; + + gspca_dev->cam.bulk = 1; + gspca_dev->cam.bulk_size = 16384; + gspca_dev->cam.bulk_nurbs = 2; + + sccb_w_array(gspca_dev, ov971x_init, + ARRAY_SIZE(ov971x_init)); + + /* set video format on bridge processor */ + /* access bridge processor's video format registers at: 0x00 */ + reg_w(gspca_dev, 0x1c, 0x00); + /*set register: 0x00 is 'RAW8', 0x40 is 'YUV422' (YUYV?)*/ + reg_w(gspca_dev, 0x1d, 0x00); + + /* Will W. specific stuff + * set VSYNC to + * output (0x1f) if first webcam + * input (0x17) if 2nd or 3rd webcam */ + p = video_device_node_name(&gspca_dev->vdev); + l = strlen(p) - 1; + if (p[l] == '0') + reg_w(gspca_dev, 0x56, 0x1f); + else + reg_w(gspca_dev, 0x56, 0x17); + } else { + err("Unknown sensor %04x", sensor_id); + return -EINVAL; + } return gspca_dev->usb_err; } static int sd_start(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->sensor == SENSOR_OV971x) + return gspca_dev->usb_err; switch (gspca_dev->curr_mode) { case QVGA_MODE: /* 320x240 */ - sccb_w_array(gspca_dev, sensor_start_1_vga, - ARRAY_SIZE(sensor_start_1_vga)); + sccb_w_array(gspca_dev, ov965x_start_1_vga, + ARRAY_SIZE(ov965x_start_1_vga)); reg_w_array(gspca_dev, bridge_start_qvga, ARRAY_SIZE(bridge_start_qvga)); - sccb_w_array(gspca_dev, sensor_start_2_qvga, - ARRAY_SIZE(sensor_start_2_qvga)); + sccb_w_array(gspca_dev, ov965x_start_2_qvga, + ARRAY_SIZE(ov965x_start_2_qvga)); break; case VGA_MODE: /* 640x480 */ - sccb_w_array(gspca_dev, sensor_start_1_vga, - ARRAY_SIZE(sensor_start_1_vga)); + sccb_w_array(gspca_dev, ov965x_start_1_vga, + ARRAY_SIZE(ov965x_start_1_vga)); reg_w_array(gspca_dev, bridge_start_vga, ARRAY_SIZE(bridge_start_vga)); - sccb_w_array(gspca_dev, sensor_start_2_vga, - ARRAY_SIZE(sensor_start_2_vga)); + sccb_w_array(gspca_dev, ov965x_start_2_vga, + ARRAY_SIZE(ov965x_start_2_vga)); break; case SVGA_MODE: /* 800x600 */ - sccb_w_array(gspca_dev, sensor_start_1_svga, - ARRAY_SIZE(sensor_start_1_svga)); + sccb_w_array(gspca_dev, ov965x_start_1_svga, + ARRAY_SIZE(ov965x_start_1_svga)); reg_w_array(gspca_dev, bridge_start_svga, ARRAY_SIZE(bridge_start_svga)); - sccb_w_array(gspca_dev, sensor_start_2_svga, - ARRAY_SIZE(sensor_start_2_svga)); + sccb_w_array(gspca_dev, ov965x_start_2_svga, + ARRAY_SIZE(ov965x_start_2_svga)); break; case XGA_MODE: /* 1024x768 */ - sccb_w_array(gspca_dev, sensor_start_1_xga, - ARRAY_SIZE(sensor_start_1_xga)); + sccb_w_array(gspca_dev, ov965x_start_1_xga, + ARRAY_SIZE(ov965x_start_1_xga)); reg_w_array(gspca_dev, bridge_start_xga, ARRAY_SIZE(bridge_start_xga)); - sccb_w_array(gspca_dev, sensor_start_2_svga, - ARRAY_SIZE(sensor_start_2_svga)); + sccb_w_array(gspca_dev, ov965x_start_2_svga, + ARRAY_SIZE(ov965x_start_2_svga)); break; default: /* case SXGA_MODE: * 1280x1024 */ - sccb_w_array(gspca_dev, sensor_start_1_sxga, - ARRAY_SIZE(sensor_start_1_sxga)); + sccb_w_array(gspca_dev, ov965x_start_1_sxga, + ARRAY_SIZE(ov965x_start_1_sxga)); reg_w_array(gspca_dev, bridge_start_sxga, ARRAY_SIZE(bridge_start_sxga)); - sccb_w_array(gspca_dev, sensor_start_2_sxga, - ARRAY_SIZE(sensor_start_2_sxga)); + sccb_w_array(gspca_dev, ov965x_start_2_sxga, + ARRAY_SIZE(ov965x_start_2_sxga)); break; } setlightfreq(gspca_dev); @@ -1173,9 +1305,11 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, __u32 this_pts; u8 this_fid; int remaining_len = len; + int payload_len; + payload_len = gspca_dev->cam.bulk ? 2048 : 2040; do { - len = min(remaining_len, 2040); + len = min(remaining_len, payload_len); /* Payloads are prefixed with a UVC-style header. We consider a frame to start when the FID toggles, or the PTS @@ -1273,6 +1407,7 @@ static const struct sd_desc sd_desc = { /* -- module initialisation -- */ static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x05a9, 0x8065)}, {USB_DEVICE(0x06f8, 0x3003)}, {} }; -- cgit v0.10.2 From 480992b357d153b8417ba242fc43e96d90cff94c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Wed, 10 Aug 2011 07:28:44 -0300 Subject: [media] gspca - main: Fix the isochronous transfer interval MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For USB speeds different of 'low', the bInterval value is logarithmic. Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index a3c2d36..85d2469 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -754,7 +754,10 @@ static int create_urbs(struct gspca_dev *gspca_dev, ep->desc.bEndpointAddress); urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - urb->interval = ep->desc.bInterval; + if (gspca_dev->dev->speed == USB_SPEED_LOW) + urb->interval = ep->desc.bInterval; + else + urb->interval = 1 << (ep->desc.bInterval - 1); urb->complete = isoc_irq; urb->number_of_packets = npkt; for (i = 0; i < npkt; i++) { -- cgit v0.10.2 From b796fb6ed032b0ccdb769b3b3bce5fb2b186a8f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Wed, 10 Aug 2011 07:32:57 -0300 Subject: [media] gspca - main: Better values for V4L2_FMT_FLAG_COMPRESSED MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In vidioc_enum_fmt_vid_cap, the 'compressed' flag was set from the pixelformat, and all pixelformats were not treated. Now, images are told as compressed when the image size is smaller than its number of pixels. Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 85d2469..3ff26ba 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -499,19 +499,6 @@ void gspca_frame_add(struct gspca_dev *gspca_dev, } EXPORT_SYMBOL(gspca_frame_add); -static int gspca_is_compressed(__u32 format) -{ - switch (format) { - case V4L2_PIX_FMT_MJPEG: - case V4L2_PIX_FMT_JPEG: - case V4L2_PIX_FMT_SPCA561: - case V4L2_PIX_FMT_PAC207: - case V4L2_PIX_FMT_MR97310A: - return 1; - } - return 0; -} - static int frame_alloc(struct gspca_dev *gspca_dev, struct file *file, enum v4l2_memory memory, unsigned int count) { @@ -1049,7 +1036,9 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, return -EINVAL; /* no more format */ fmtdesc->pixelformat = fmt_tb[index]; - if (gspca_is_compressed(fmt_tb[index])) + if (gspca_dev->cam.cam_mode[i].sizeimage < + gspca_dev->cam.cam_mode[i].width * + gspca_dev->cam.cam_mode[i].height) fmtdesc->flags = V4L2_FMT_FLAG_COMPRESSED; fmtdesc->description[0] = fmtdesc->pixelformat & 0xff; fmtdesc->description[1] = (fmtdesc->pixelformat >> 8) & 0xff; -- cgit v0.10.2 From 00542edf071e249ccb541ffb2d2b9034e2533968 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 31 Jul 2011 17:12:02 +0200 Subject: [media] omap3isp: Don't accept pipelines with no video source as valid Make sure the pipeline has a valid video source (either a subdev with no sink pad, or a non-subdev entity) at stream-on time and return -EPIPE if no video source can be found. Reported-by: Jonathan Cameron Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c index fd965ad..fd94cdf 100644 --- a/drivers/media/video/omap3isp/ispvideo.c +++ b/drivers/media/video/omap3isp/ispvideo.c @@ -278,7 +278,8 @@ isp_video_far_end(struct isp_video *video) * limits reported by every block in the pipeline. * * Return 0 if all formats match, or -EPIPE if at least one link is found with - * different formats on its two ends. + * different formats on its two ends or if the pipeline doesn't start with a + * video source (either a subdev with no input pad, or a non-subdev entity). */ static int isp_video_validate_pipeline(struct isp_pipeline *pipe) { @@ -329,10 +330,15 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe) * in the middle of it. */ shifter_link = subdev == &isp->isp_ccdc.subdev; - /* Retrieve the source format */ + /* Retrieve the source format. Return an error if no source + * entity can be found, and stop checking the pipeline if the + * source entity isn't a subdev. + */ pad = media_entity_remote_source(pad); - if (pad == NULL || - media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + if (pad == NULL) + return -EPIPE; + + if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) break; subdev = media_entity_to_v4l2_subdev(pad->entity); -- cgit v0.10.2 From 61e6561fae573c3c618118a71ff966ddb14299da Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Tue, 9 Aug 2011 08:42:20 +0200 Subject: [media] omap3isp: queue: fail QBUF if user buffer is too small Add buffer length check to sanity checks for USERPTR QBUF. Signed-off-by: Michael Jones Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/omap3isp/ispqueue.c b/drivers/media/video/omap3isp/ispqueue.c index 9c31714..9bebb1e 100644 --- a/drivers/media/video/omap3isp/ispqueue.c +++ b/drivers/media/video/omap3isp/ispqueue.c @@ -868,6 +868,10 @@ int omap3isp_video_queue_qbuf(struct isp_video_queue *queue, goto done; if (vbuf->memory == V4L2_MEMORY_USERPTR && + vbuf->length < buf->vbuf.length) + goto done; + + if (vbuf->memory == V4L2_MEMORY_USERPTR && vbuf->m.userptr != buf->vbuf.m.userptr) { isp_video_buffer_cleanup(buf); buf->vbuf.m.userptr = vbuf->m.userptr; -- cgit v0.10.2 From b98d32f7e5cfed8deeaa9054e0977333ac419349 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 12 Aug 2011 19:09:34 +0200 Subject: [media] omap3isp: Move platform data definitions from isp.h to media/omap3isp.h drivers/media/video/omap3isp/isp.h is not a proper location for a header that needs to be included from board code. Move the platform data definitions to media/omap3isp.h. Board code still needs to include isp.h to get the struct isp_device definition and access OMAP3 ISP platform callbacks. Those callbacks will be replaced by more generic code. Signed-off-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/omap3isp/isp.h b/drivers/media/video/omap3isp/isp.h index 529e582..521db0c 100644 --- a/drivers/media/video/omap3isp/isp.h +++ b/drivers/media/video/omap3isp/isp.h @@ -27,6 +27,7 @@ #ifndef OMAP3_ISP_CORE_H #define OMAP3_ISP_CORE_H +#include #include #include #include @@ -94,14 +95,6 @@ enum isp_subclk_resource { OMAP3_ISP_SUBCLK_RESIZER = (1 << 4), }; -enum isp_interface_type { - ISP_INTERFACE_PARALLEL, - ISP_INTERFACE_CSI2A_PHY2, - ISP_INTERFACE_CCP2B_PHY1, - ISP_INTERFACE_CCP2B_PHY2, - ISP_INTERFACE_CSI2C_PHY1, -}; - /* ISP: OMAP 34xx ES 1.0 */ #define ISP_REVISION_1_0 0x10 /* ISP2: OMAP 34xx ES 2.0, 2.1 and 3.0 */ @@ -130,82 +123,6 @@ struct isp_reg { u32 val; }; -/** - * struct isp_parallel_platform_data - Parallel interface platform data - * @data_lane_shift: Data lane shifter - * 0 - CAMEXT[13:0] -> CAM[13:0] - * 1 - CAMEXT[13:2] -> CAM[11:0] - * 2 - CAMEXT[13:4] -> CAM[9:0] - * 3 - CAMEXT[13:6] -> CAM[7:0] - * @clk_pol: Pixel clock polarity - * 0 - Non Inverted, 1 - Inverted - * @hs_pol: Horizontal synchronization polarity - * 0 - Active high, 1 - Active low - * @vs_pol: Vertical synchronization polarity - * 0 - Active high, 1 - Active low - * @bridge: CCDC Bridge input control - * ISPCTRL_PAR_BRIDGE_DISABLE - Disable - * ISPCTRL_PAR_BRIDGE_LENDIAN - Little endian - * ISPCTRL_PAR_BRIDGE_BENDIAN - Big endian - */ -struct isp_parallel_platform_data { - unsigned int data_lane_shift:2; - unsigned int clk_pol:1; - unsigned int hs_pol:1; - unsigned int vs_pol:1; - unsigned int bridge:4; -}; - -/** - * struct isp_ccp2_platform_data - CCP2 interface platform data - * @strobe_clk_pol: Strobe/clock polarity - * 0 - Non Inverted, 1 - Inverted - * @crc: Enable the cyclic redundancy check - * @ccp2_mode: Enable CCP2 compatibility mode - * 0 - MIPI-CSI1 mode, 1 - CCP2 mode - * @phy_layer: Physical layer selection - * ISPCCP2_CTRL_PHY_SEL_CLOCK - Data/clock physical layer - * ISPCCP2_CTRL_PHY_SEL_STROBE - Data/strobe physical layer - * @vpclk_div: Video port output clock control - */ -struct isp_ccp2_platform_data { - unsigned int strobe_clk_pol:1; - unsigned int crc:1; - unsigned int ccp2_mode:1; - unsigned int phy_layer:1; - unsigned int vpclk_div:2; -}; - -/** - * struct isp_csi2_platform_data - CSI2 interface platform data - * @crc: Enable the cyclic redundancy check - * @vpclk_div: Video port output clock control - */ -struct isp_csi2_platform_data { - unsigned crc:1; - unsigned vpclk_div:2; -}; - -struct isp_subdev_i2c_board_info { - struct i2c_board_info *board_info; - int i2c_adapter_id; -}; - -struct isp_v4l2_subdevs_group { - struct isp_subdev_i2c_board_info *subdevs; - enum isp_interface_type interface; - union { - struct isp_parallel_platform_data parallel; - struct isp_ccp2_platform_data ccp2; - struct isp_csi2_platform_data csi2; - } bus; /* gcc < 4.6.0 chokes on anonymous union initializers */ -}; - -struct isp_platform_data { - struct isp_v4l2_subdevs_group *subdevs; - void (*set_constraints)(struct isp_device *isp, bool enable); -}; - struct isp_platform_callback { u32 (*set_xclk)(struct isp_device *isp, u32 xclk, u8 xclksel); int (*csiphy_config)(struct isp_csiphy *phy, diff --git a/drivers/media/video/omap3isp/ispccp2.c b/drivers/media/video/omap3isp/ispccp2.c index ec9e395..fa1d09b 100644 --- a/drivers/media/video/omap3isp/ispccp2.c +++ b/drivers/media/video/omap3isp/ispccp2.c @@ -243,9 +243,9 @@ static int ccp2_phyif_config(struct isp_ccp2_device *ccp2, val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); if (!(val & ISPCCP2_CTRL_MODE)) { - if (pdata->ccp2_mode) + if (pdata->ccp2_mode == ISP_CCP2_MODE_CCP2) dev_warn(isp->dev, "OMAP3 CCP2 bus not available\n"); - if (pdata->phy_layer == ISPCCP2_CTRL_PHY_SEL_STROBE) + if (pdata->phy_layer == ISP_CCP2_PHY_DATA_STROBE) /* Strobe mode requires CCP2 */ return -EIO; } diff --git a/include/media/omap3isp.h b/include/media/omap3isp.h new file mode 100644 index 0000000..e917b1d --- /dev/null +++ b/include/media/omap3isp.h @@ -0,0 +1,140 @@ +/* + * omap3isp.h + * + * TI OMAP3 ISP - Platform data + * + * Copyright (C) 2011 Nokia Corporation + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef __MEDIA_OMAP3ISP_H__ +#define __MEDIA_OMAP3ISP_H__ + +struct i2c_board_info; +struct isp_device; + +enum isp_interface_type { + ISP_INTERFACE_PARALLEL, + ISP_INTERFACE_CSI2A_PHY2, + ISP_INTERFACE_CCP2B_PHY1, + ISP_INTERFACE_CCP2B_PHY2, + ISP_INTERFACE_CSI2C_PHY1, +}; + +enum { + ISP_BRIDGE_DISABLE = 0, + ISP_BRIDGE_LITTLE_ENDIAN = 2, + ISP_BRIDGE_BIG_ENDIAN = 3, +}; + +enum { + ISP_LANE_SHIFT_0 = 0, + ISP_LANE_SHIFT_2 = 1, + ISP_LANE_SHIFT_4 = 2, + ISP_LANE_SHIFT_6 = 3, +}; + +/** + * struct isp_parallel_platform_data - Parallel interface platform data + * @data_lane_shift: Data lane shifter + * ISP_LANE_SHIFT_0 - CAMEXT[13:0] -> CAM[13:0] + * ISP_LANE_SHIFT_2 - CAMEXT[13:2] -> CAM[11:0] + * ISP_LANE_SHIFT_4 - CAMEXT[13:4] -> CAM[9:0] + * ISP_LANE_SHIFT_6 - CAMEXT[13:6] -> CAM[7:0] + * @clk_pol: Pixel clock polarity + * 0 - Non Inverted, 1 - Inverted + * @hs_pol: Horizontal synchronization polarity + * 0 - Active high, 1 - Active low + * @vs_pol: Vertical synchronization polarity + * 0 - Active high, 1 - Active low + * @bridge: CCDC Bridge input control + * ISP_BRIDGE_DISABLE - Disable + * ISP_BRIDGE_LITTLE_ENDIAN - Little endian + * ISP_BRIDGE_BIG_ENDIAN - Big endian + */ +struct isp_parallel_platform_data { + unsigned int data_lane_shift:2; + unsigned int clk_pol:1; + unsigned int hs_pol:1; + unsigned int vs_pol:1; + unsigned int bridge:2; +}; + +enum { + ISP_CCP2_PHY_DATA_CLOCK = 0, + ISP_CCP2_PHY_DATA_STROBE = 1, +}; + +enum { + ISP_CCP2_MODE_MIPI = 0, + ISP_CCP2_MODE_CCP2 = 1, +}; + +/** + * struct isp_ccp2_platform_data - CCP2 interface platform data + * @strobe_clk_pol: Strobe/clock polarity + * 0 - Non Inverted, 1 - Inverted + * @crc: Enable the cyclic redundancy check + * @ccp2_mode: Enable CCP2 compatibility mode + * ISP_CCP2_MODE_MIPI - MIPI-CSI1 mode + * ISP_CCP2_MODE_CCP2 - CCP2 mode + * @phy_layer: Physical layer selection + * ISP_CCP2_PHY_DATA_CLOCK - Data/clock physical layer + * ISP_CCP2_PHY_DATA_STROBE - Data/strobe physical layer + * @vpclk_div: Video port output clock control + */ +struct isp_ccp2_platform_data { + unsigned int strobe_clk_pol:1; + unsigned int crc:1; + unsigned int ccp2_mode:1; + unsigned int phy_layer:1; + unsigned int vpclk_div:2; +}; + +/** + * struct isp_csi2_platform_data - CSI2 interface platform data + * @crc: Enable the cyclic redundancy check + * @vpclk_div: Video port output clock control + */ +struct isp_csi2_platform_data { + unsigned crc:1; + unsigned vpclk_div:2; +}; + +struct isp_subdev_i2c_board_info { + struct i2c_board_info *board_info; + int i2c_adapter_id; +}; + +struct isp_v4l2_subdevs_group { + struct isp_subdev_i2c_board_info *subdevs; + enum isp_interface_type interface; + union { + struct isp_parallel_platform_data parallel; + struct isp_ccp2_platform_data ccp2; + struct isp_csi2_platform_data csi2; + } bus; /* gcc < 4.6.0 chokes on anonymous union initializers */ +}; + +struct isp_platform_data { + struct isp_v4l2_subdevs_group *subdevs; + void (*set_constraints)(struct isp_device *isp, bool enable); +}; + +#endif /* __MEDIA_OMAP3ISP_H__ */ -- cgit v0.10.2 From 418d93ac0be6d4a410731b80af4e836614ffe73e Mon Sep 17 00:00:00 2001 From: Javier Martin Date: Mon, 20 Jun 2011 13:21:16 +0200 Subject: [media] mt9p031: Aptina (Micron) MT9P031 5MP sensor driver The MT9P031 is a parallel 12-bit 5MP sensor from Aptina (formerly Micron) controlled through I2C. The driver creates a V4L2 subdevice. It currently supports skipping, cropping, automatic binning, and gain, exposure, h/v flip and test pattern controls. Signed-off-by: Javier Martin Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 6279663..9da6044 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -467,6 +467,13 @@ config VIDEO_OV7670 OV7670 VGA camera. It currently only works with the M88ALP01 controller. +config VIDEO_MT9P031 + tristate "Aptina MT9P031 support" + depends on I2C && VIDEO_V4L2 + ---help--- + This is a Video4Linux2 sensor-level driver for the Aptina + (Micron) mt9p031 5 Mpixel camera. + config VIDEO_MT9V011 tristate "Micron mt9v011 sensor support" depends on I2C && VIDEO_V4L2 diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index c06f515..f52a771 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -65,6 +65,7 @@ obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o obj-$(CONFIG_VIDEO_OV7670) += ov7670.o obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o +obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o diff --git a/drivers/media/video/mt9p031.c b/drivers/media/video/mt9p031.c new file mode 100644 index 0000000..5cfa39f --- /dev/null +++ b/drivers/media/video/mt9p031.c @@ -0,0 +1,963 @@ +/* + * Driver for MT9P031 CMOS Image Sensor from Aptina + * + * Copyright (C) 2011, Laurent Pinchart + * Copyright (C) 2011, Javier Martin + * Copyright (C) 2011, Guennadi Liakhovetski + * + * Based on the MT9V032 driver and Bastian Hecht's code. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define MT9P031_PIXEL_ARRAY_WIDTH 2752 +#define MT9P031_PIXEL_ARRAY_HEIGHT 2004 + +#define MT9P031_CHIP_VERSION 0x00 +#define MT9P031_CHIP_VERSION_VALUE 0x1801 +#define MT9P031_ROW_START 0x01 +#define MT9P031_ROW_START_MIN 0 +#define MT9P031_ROW_START_MAX 2004 +#define MT9P031_ROW_START_DEF 54 +#define MT9P031_COLUMN_START 0x02 +#define MT9P031_COLUMN_START_MIN 0 +#define MT9P031_COLUMN_START_MAX 2750 +#define MT9P031_COLUMN_START_DEF 16 +#define MT9P031_WINDOW_HEIGHT 0x03 +#define MT9P031_WINDOW_HEIGHT_MIN 2 +#define MT9P031_WINDOW_HEIGHT_MAX 2006 +#define MT9P031_WINDOW_HEIGHT_DEF 1944 +#define MT9P031_WINDOW_WIDTH 0x04 +#define MT9P031_WINDOW_WIDTH_MIN 2 +#define MT9P031_WINDOW_WIDTH_MAX 2752 +#define MT9P031_WINDOW_WIDTH_DEF 2592 +#define MT9P031_HORIZONTAL_BLANK 0x05 +#define MT9P031_HORIZONTAL_BLANK_MIN 0 +#define MT9P031_HORIZONTAL_BLANK_MAX 4095 +#define MT9P031_VERTICAL_BLANK 0x06 +#define MT9P031_VERTICAL_BLANK_MIN 0 +#define MT9P031_VERTICAL_BLANK_MAX 4095 +#define MT9P031_VERTICAL_BLANK_DEF 25 +#define MT9P031_OUTPUT_CONTROL 0x07 +#define MT9P031_OUTPUT_CONTROL_CEN 2 +#define MT9P031_OUTPUT_CONTROL_SYN 1 +#define MT9P031_OUTPUT_CONTROL_DEF 0x1f82 +#define MT9P031_SHUTTER_WIDTH_UPPER 0x08 +#define MT9P031_SHUTTER_WIDTH_LOWER 0x09 +#define MT9P031_SHUTTER_WIDTH_MIN 1 +#define MT9P031_SHUTTER_WIDTH_MAX 1048575 +#define MT9P031_SHUTTER_WIDTH_DEF 1943 +#define MT9P031_PLL_CONTROL 0x10 +#define MT9P031_PLL_CONTROL_PWROFF 0x0050 +#define MT9P031_PLL_CONTROL_PWRON 0x0051 +#define MT9P031_PLL_CONTROL_USEPLL 0x0052 +#define MT9P031_PLL_CONFIG_1 0x11 +#define MT9P031_PLL_CONFIG_2 0x12 +#define MT9P031_PIXEL_CLOCK_CONTROL 0x0a +#define MT9P031_FRAME_RESTART 0x0b +#define MT9P031_SHUTTER_DELAY 0x0c +#define MT9P031_RST 0x0d +#define MT9P031_RST_ENABLE 1 +#define MT9P031_RST_DISABLE 0 +#define MT9P031_READ_MODE_1 0x1e +#define MT9P031_READ_MODE_2 0x20 +#define MT9P031_READ_MODE_2_ROW_MIR (1 << 15) +#define MT9P031_READ_MODE_2_COL_MIR (1 << 14) +#define MT9P031_READ_MODE_2_ROW_BLC (1 << 6) +#define MT9P031_ROW_ADDRESS_MODE 0x22 +#define MT9P031_COLUMN_ADDRESS_MODE 0x23 +#define MT9P031_GLOBAL_GAIN 0x35 +#define MT9P031_GLOBAL_GAIN_MIN 8 +#define MT9P031_GLOBAL_GAIN_MAX 1024 +#define MT9P031_GLOBAL_GAIN_DEF 8 +#define MT9P031_GLOBAL_GAIN_MULT (1 << 6) +#define MT9P031_ROW_BLACK_DEF_OFFSET 0x4b +#define MT9P031_TEST_PATTERN 0xa0 +#define MT9P031_TEST_PATTERN_SHIFT 3 +#define MT9P031_TEST_PATTERN_ENABLE (1 << 0) +#define MT9P031_TEST_PATTERN_DISABLE (0 << 0) +#define MT9P031_TEST_PATTERN_GREEN 0xa1 +#define MT9P031_TEST_PATTERN_RED 0xa2 +#define MT9P031_TEST_PATTERN_BLUE 0xa3 + +struct mt9p031_pll_divs { + u32 ext_freq; + u32 target_freq; + u8 m; + u8 n; + u8 p1; +}; + +struct mt9p031 { + struct v4l2_subdev subdev; + struct media_pad pad; + struct v4l2_rect crop; /* Sensor window */ + struct v4l2_mbus_framefmt format; + struct v4l2_ctrl_handler ctrls; + struct mt9p031_platform_data *pdata; + struct mutex power_lock; /* lock to protect power_count */ + int power_count; + u16 xskip; + u16 yskip; + + const struct mt9p031_pll_divs *pll; + + /* Registers cache */ + u16 output_control; + u16 mode2; +}; + +static struct mt9p031 *to_mt9p031(struct v4l2_subdev *sd) +{ + return container_of(sd, struct mt9p031, subdev); +} + +static int mt9p031_read(struct i2c_client *client, u8 reg) +{ + s32 data = i2c_smbus_read_word_data(client, reg); + return data < 0 ? data : be16_to_cpu(data); +} + +static int mt9p031_write(struct i2c_client *client, u8 reg, u16 data) +{ + return i2c_smbus_write_word_data(client, reg, cpu_to_be16(data)); +} + +static int mt9p031_set_output_control(struct mt9p031 *mt9p031, u16 clear, + u16 set) +{ + struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev); + u16 value = (mt9p031->output_control & ~clear) | set; + int ret; + + ret = mt9p031_write(client, MT9P031_OUTPUT_CONTROL, value); + if (ret < 0) + return ret; + + mt9p031->output_control = value; + return 0; +} + +static int mt9p031_set_mode2(struct mt9p031 *mt9p031, u16 clear, u16 set) +{ + struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev); + u16 value = (mt9p031->mode2 & ~clear) | set; + int ret; + + ret = mt9p031_write(client, MT9P031_READ_MODE_2, value); + if (ret < 0) + return ret; + + mt9p031->mode2 = value; + return 0; +} + +static int mt9p031_reset(struct mt9p031 *mt9p031) +{ + struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev); + int ret; + + /* Disable chip output, synchronous option update */ + ret = mt9p031_write(client, MT9P031_RST, MT9P031_RST_ENABLE); + if (ret < 0) + return ret; + ret = mt9p031_write(client, MT9P031_RST, MT9P031_RST_DISABLE); + if (ret < 0) + return ret; + + return mt9p031_set_output_control(mt9p031, MT9P031_OUTPUT_CONTROL_CEN, + 0); +} + +/* + * This static table uses ext_freq and vdd_io values to select suitable + * PLL dividers m, n and p1 which have been calculated as specifiec in p36 + * of Aptina's mt9p031 datasheet. New values should be added here. + */ +static const struct mt9p031_pll_divs mt9p031_divs[] = { + /* ext_freq target_freq m n p1 */ + {21000000, 48000000, 26, 2, 6} +}; + +static int mt9p031_pll_get_divs(struct mt9p031 *mt9p031) +{ + struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev); + int i; + + for (i = 0; i < ARRAY_SIZE(mt9p031_divs); i++) { + if (mt9p031_divs[i].ext_freq == mt9p031->pdata->ext_freq && + mt9p031_divs[i].target_freq == mt9p031->pdata->target_freq) { + mt9p031->pll = &mt9p031_divs[i]; + return 0; + } + } + + dev_err(&client->dev, "Couldn't find PLL dividers for ext_freq = %d, " + "target_freq = %d\n", mt9p031->pdata->ext_freq, + mt9p031->pdata->target_freq); + return -EINVAL; +} + +static int mt9p031_pll_enable(struct mt9p031 *mt9p031) +{ + struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev); + int ret; + + ret = mt9p031_write(client, MT9P031_PLL_CONTROL, + MT9P031_PLL_CONTROL_PWRON); + if (ret < 0) + return ret; + + ret = mt9p031_write(client, MT9P031_PLL_CONFIG_1, + (mt9p031->pll->m << 8) | (mt9p031->pll->n - 1)); + if (ret < 0) + return ret; + + ret = mt9p031_write(client, MT9P031_PLL_CONFIG_2, mt9p031->pll->p1 - 1); + if (ret < 0) + return ret; + + usleep_range(1000, 2000); + ret = mt9p031_write(client, MT9P031_PLL_CONTROL, + MT9P031_PLL_CONTROL_PWRON | + MT9P031_PLL_CONTROL_USEPLL); + return ret; +} + +static inline int mt9p031_pll_disable(struct mt9p031 *mt9p031) +{ + struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev); + + return mt9p031_write(client, MT9P031_PLL_CONTROL, + MT9P031_PLL_CONTROL_PWROFF); +} + +static int mt9p031_power_on(struct mt9p031 *mt9p031) +{ + /* Ensure RESET_BAR is low */ + if (mt9p031->pdata->reset) { + mt9p031->pdata->reset(&mt9p031->subdev, 1); + usleep_range(1000, 2000); + } + + /* Emable clock */ + if (mt9p031->pdata->set_xclk) + mt9p031->pdata->set_xclk(&mt9p031->subdev, + mt9p031->pdata->ext_freq); + + /* Now RESET_BAR must be high */ + if (mt9p031->pdata->reset) { + mt9p031->pdata->reset(&mt9p031->subdev, 0); + usleep_range(1000, 2000); + } + + return 0; +} + +static void mt9p031_power_off(struct mt9p031 *mt9p031) +{ + if (mt9p031->pdata->reset) { + mt9p031->pdata->reset(&mt9p031->subdev, 1); + usleep_range(1000, 2000); + } + + if (mt9p031->pdata->set_xclk) + mt9p031->pdata->set_xclk(&mt9p031->subdev, 0); +} + +static int __mt9p031_set_power(struct mt9p031 *mt9p031, bool on) +{ + struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev); + int ret; + + if (!on) { + mt9p031_power_off(mt9p031); + return 0; + } + + ret = mt9p031_power_on(mt9p031); + if (ret < 0) + return ret; + + ret = mt9p031_reset(mt9p031); + if (ret < 0) { + dev_err(&client->dev, "Failed to reset the camera\n"); + return ret; + } + + return v4l2_ctrl_handler_setup(&mt9p031->ctrls); +} + +/* ----------------------------------------------------------------------------- + * V4L2 subdev video operations + */ + +static int mt9p031_set_params(struct mt9p031 *mt9p031) +{ + struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev); + struct v4l2_mbus_framefmt *format = &mt9p031->format; + const struct v4l2_rect *crop = &mt9p031->crop; + unsigned int hblank; + unsigned int vblank; + unsigned int xskip; + unsigned int yskip; + unsigned int xbin; + unsigned int ybin; + int ret; + + /* Windows position and size. + * + * TODO: Make sure the start coordinates and window size match the + * skipping, binning and mirroring (see description of registers 2 and 4 + * in table 13, and Binning section on page 41). + */ + ret = mt9p031_write(client, MT9P031_COLUMN_START, crop->left); + if (ret < 0) + return ret; + ret = mt9p031_write(client, MT9P031_ROW_START, crop->top); + if (ret < 0) + return ret; + ret = mt9p031_write(client, MT9P031_WINDOW_WIDTH, crop->width - 1); + if (ret < 0) + return ret; + ret = mt9p031_write(client, MT9P031_WINDOW_HEIGHT, crop->height - 1); + if (ret < 0) + return ret; + + /* Row and column binning and skipping. Use the maximum binning value + * compatible with the skipping settings. + */ + xskip = DIV_ROUND_CLOSEST(crop->width, format->width); + yskip = DIV_ROUND_CLOSEST(crop->height, format->height); + xbin = 1 << (ffs(xskip) - 1); + ybin = 1 << (ffs(yskip) - 1); + + ret = mt9p031_write(client, MT9P031_COLUMN_ADDRESS_MODE, + ((xbin - 1) << 4) | (xskip - 1)); + if (ret < 0) + return ret; + ret = mt9p031_write(client, MT9P031_ROW_ADDRESS_MODE, + ((ybin - 1) << 4) | (yskip - 1)); + if (ret < 0) + return ret; + + /* Blanking - use minimum value for horizontal blanking and default + * value for vertical blanking. + */ + hblank = 346 * ybin + 64 + (80 >> max_t(unsigned int, xbin, 3)); + vblank = MT9P031_VERTICAL_BLANK_DEF; + + ret = mt9p031_write(client, MT9P031_HORIZONTAL_BLANK, hblank); + if (ret < 0) + return ret; + ret = mt9p031_write(client, MT9P031_VERTICAL_BLANK, vblank); + if (ret < 0) + return ret; + + return ret; +} + +static int mt9p031_s_stream(struct v4l2_subdev *subdev, int enable) +{ + struct mt9p031 *mt9p031 = to_mt9p031(subdev); + int ret; + + if (!enable) { + /* Stop sensor readout */ + ret = mt9p031_set_output_control(mt9p031, + MT9P031_OUTPUT_CONTROL_CEN, 0); + if (ret < 0) + return ret; + + return mt9p031_pll_disable(mt9p031); + } + + ret = mt9p031_set_params(mt9p031); + if (ret < 0) + return ret; + + /* Switch to master "normal" mode */ + ret = mt9p031_set_output_control(mt9p031, 0, + MT9P031_OUTPUT_CONTROL_CEN); + if (ret < 0) + return ret; + + return mt9p031_pll_enable(mt9p031); +} + +static int mt9p031_enum_mbus_code(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct mt9p031 *mt9p031 = to_mt9p031(subdev); + + if (code->pad || code->index) + return -EINVAL; + + code->code = mt9p031->format.code; + return 0; +} + +static int mt9p031_enum_frame_size(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct mt9p031 *mt9p031 = to_mt9p031(subdev); + + if (fse->index >= 8 || fse->code != mt9p031->format.code) + return -EINVAL; + + fse->min_width = MT9P031_WINDOW_WIDTH_DEF + / min_t(unsigned int, 7, fse->index + 1); + fse->max_width = fse->min_width; + fse->min_height = MT9P031_WINDOW_HEIGHT_DEF / (fse->index + 1); + fse->max_height = fse->min_height; + + return 0; +} + +static struct v4l2_mbus_framefmt * +__mt9p031_get_pad_format(struct mt9p031 *mt9p031, struct v4l2_subdev_fh *fh, + unsigned int pad, u32 which) +{ + switch (which) { + case V4L2_SUBDEV_FORMAT_TRY: + return v4l2_subdev_get_try_format(fh, pad); + case V4L2_SUBDEV_FORMAT_ACTIVE: + return &mt9p031->format; + default: + return NULL; + } +} + +static struct v4l2_rect * +__mt9p031_get_pad_crop(struct mt9p031 *mt9p031, struct v4l2_subdev_fh *fh, + unsigned int pad, u32 which) +{ + switch (which) { + case V4L2_SUBDEV_FORMAT_TRY: + return v4l2_subdev_get_try_crop(fh, pad); + case V4L2_SUBDEV_FORMAT_ACTIVE: + return &mt9p031->crop; + default: + return NULL; + } +} + +static int mt9p031_get_format(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct mt9p031 *mt9p031 = to_mt9p031(subdev); + + fmt->format = *__mt9p031_get_pad_format(mt9p031, fh, fmt->pad, + fmt->which); + return 0; +} + +static int mt9p031_set_format(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *format) +{ + struct mt9p031 *mt9p031 = to_mt9p031(subdev); + struct v4l2_mbus_framefmt *__format; + struct v4l2_rect *__crop; + unsigned int width; + unsigned int height; + unsigned int hratio; + unsigned int vratio; + + __crop = __mt9p031_get_pad_crop(mt9p031, fh, format->pad, + format->which); + + /* Clamp the width and height to avoid dividing by zero. */ + width = clamp_t(unsigned int, ALIGN(format->format.width, 2), + max(__crop->width / 7, MT9P031_WINDOW_WIDTH_MIN), + __crop->width); + height = clamp_t(unsigned int, ALIGN(format->format.height, 2), + max(__crop->height / 8, MT9P031_WINDOW_HEIGHT_MIN), + __crop->height); + + hratio = DIV_ROUND_CLOSEST(__crop->width, width); + vratio = DIV_ROUND_CLOSEST(__crop->height, height); + + __format = __mt9p031_get_pad_format(mt9p031, fh, format->pad, + format->which); + __format->width = __crop->width / hratio; + __format->height = __crop->height / vratio; + + format->format = *__format; + + return 0; +} + +static int mt9p031_get_crop(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_crop *crop) +{ + struct mt9p031 *mt9p031 = to_mt9p031(subdev); + + crop->rect = *__mt9p031_get_pad_crop(mt9p031, fh, crop->pad, + crop->which); + return 0; +} + +static int mt9p031_set_crop(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_crop *crop) +{ + struct mt9p031 *mt9p031 = to_mt9p031(subdev); + struct v4l2_mbus_framefmt *__format; + struct v4l2_rect *__crop; + struct v4l2_rect rect; + + /* Clamp the crop rectangle boundaries and align them to a multiple of 2 + * pixels to ensure a GRBG Bayer pattern. + */ + rect.left = clamp(ALIGN(crop->rect.left, 2), MT9P031_COLUMN_START_MIN, + MT9P031_COLUMN_START_MAX); + rect.top = clamp(ALIGN(crop->rect.top, 2), MT9P031_ROW_START_MIN, + MT9P031_ROW_START_MAX); + rect.width = clamp(ALIGN(crop->rect.width, 2), + MT9P031_WINDOW_WIDTH_MIN, + MT9P031_WINDOW_WIDTH_MAX); + rect.height = clamp(ALIGN(crop->rect.height, 2), + MT9P031_WINDOW_HEIGHT_MIN, + MT9P031_WINDOW_HEIGHT_MAX); + + rect.width = min(rect.width, MT9P031_PIXEL_ARRAY_WIDTH - rect.left); + rect.height = min(rect.height, MT9P031_PIXEL_ARRAY_HEIGHT - rect.top); + + __crop = __mt9p031_get_pad_crop(mt9p031, fh, crop->pad, crop->which); + + if (rect.width != __crop->width || rect.height != __crop->height) { + /* Reset the output image size if the crop rectangle size has + * been modified. + */ + __format = __mt9p031_get_pad_format(mt9p031, fh, crop->pad, + crop->which); + __format->width = rect.width; + __format->height = rect.height; + } + + *__crop = rect; + crop->rect = rect; + + return 0; +} + +/* ----------------------------------------------------------------------------- + * V4L2 subdev control operations + */ + +#define V4L2_CID_TEST_PATTERN (V4L2_CID_USER_BASE | 0x1001) + +static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct mt9p031 *mt9p031 = + container_of(ctrl->handler, struct mt9p031, ctrls); + struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev); + u16 data; + int ret; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + ret = mt9p031_write(client, MT9P031_SHUTTER_WIDTH_UPPER, + (ctrl->val >> 16) & 0xffff); + if (ret < 0) + return ret; + + return mt9p031_write(client, MT9P031_SHUTTER_WIDTH_LOWER, + ctrl->val & 0xffff); + + case V4L2_CID_GAIN: + /* Gain is controlled by 2 analog stages and a digital stage. + * Valid values for the 3 stages are + * + * Stage Min Max Step + * ------------------------------------------ + * First analog stage x1 x2 1 + * Second analog stage x1 x4 0.125 + * Digital stage x1 x16 0.125 + * + * To minimize noise, the gain stages should be used in the + * second analog stage, first analog stage, digital stage order. + * Gain from a previous stage should be pushed to its maximum + * value before the next stage is used. + */ + if (ctrl->val <= 32) { + data = ctrl->val; + } else if (ctrl->val <= 64) { + ctrl->val &= ~1; + data = (1 << 6) | (ctrl->val >> 1); + } else { + ctrl->val &= ~7; + data = ((ctrl->val - 64) << 5) | (1 << 6) | 32; + } + + return mt9p031_write(client, MT9P031_GLOBAL_GAIN, data); + + case V4L2_CID_HFLIP: + if (ctrl->val) + return mt9p031_set_mode2(mt9p031, + 0, MT9P031_READ_MODE_2_COL_MIR); + else + return mt9p031_set_mode2(mt9p031, + MT9P031_READ_MODE_2_COL_MIR, 0); + + case V4L2_CID_VFLIP: + if (ctrl->val) + return mt9p031_set_mode2(mt9p031, + 0, MT9P031_READ_MODE_2_ROW_MIR); + else + return mt9p031_set_mode2(mt9p031, + MT9P031_READ_MODE_2_ROW_MIR, 0); + + case V4L2_CID_TEST_PATTERN: + if (!ctrl->val) { + ret = mt9p031_set_mode2(mt9p031, + 0, MT9P031_READ_MODE_2_ROW_BLC); + if (ret < 0) + return ret; + + return mt9p031_write(client, MT9P031_TEST_PATTERN, + MT9P031_TEST_PATTERN_DISABLE); + } + + ret = mt9p031_write(client, MT9P031_TEST_PATTERN_GREEN, 0x05a0); + if (ret < 0) + return ret; + ret = mt9p031_write(client, MT9P031_TEST_PATTERN_RED, 0x0a50); + if (ret < 0) + return ret; + ret = mt9p031_write(client, MT9P031_TEST_PATTERN_BLUE, 0x0aa0); + if (ret < 0) + return ret; + + ret = mt9p031_set_mode2(mt9p031, MT9P031_READ_MODE_2_ROW_BLC, + 0); + if (ret < 0) + return ret; + ret = mt9p031_write(client, MT9P031_ROW_BLACK_DEF_OFFSET, 0); + if (ret < 0) + return ret; + + return mt9p031_write(client, MT9P031_TEST_PATTERN, + ((ctrl->val - 1) << MT9P031_TEST_PATTERN_SHIFT) + | MT9P031_TEST_PATTERN_ENABLE); + } + return 0; +} + +static struct v4l2_ctrl_ops mt9p031_ctrl_ops = { + .s_ctrl = mt9p031_s_ctrl, +}; + +static const char * const mt9p031_test_pattern_menu[] = { + "Disabled", + "Color Field", + "Horizontal Gradient", + "Vertical Gradient", + "Diagonal Gradient", + "Classic Test Pattern", + "Walking 1s", + "Monochrome Horizontal Bars", + "Monochrome Vertical Bars", + "Vertical Color Bars", +}; + +static const struct v4l2_ctrl_config mt9p031_ctrls[] = { + { + .ops = &mt9p031_ctrl_ops, + .id = V4L2_CID_TEST_PATTERN, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Test Pattern", + .min = 0, + .max = ARRAY_SIZE(mt9p031_test_pattern_menu) - 1, + .step = 0, + .def = 0, + .flags = 0, + .menu_skip_mask = 0, + .qmenu = mt9p031_test_pattern_menu, + } +}; + +/* ----------------------------------------------------------------------------- + * V4L2 subdev core operations + */ + +static int mt9p031_set_power(struct v4l2_subdev *subdev, int on) +{ + struct mt9p031 *mt9p031 = to_mt9p031(subdev); + int ret = 0; + + mutex_lock(&mt9p031->power_lock); + + /* If the power count is modified from 0 to != 0 or from != 0 to 0, + * update the power state. + */ + if (mt9p031->power_count == !on) { + ret = __mt9p031_set_power(mt9p031, !!on); + if (ret < 0) + goto out; + } + + /* Update the power count. */ + mt9p031->power_count += on ? 1 : -1; + WARN_ON(mt9p031->power_count < 0); + +out: + mutex_unlock(&mt9p031->power_lock); + return ret; +} + +/* ----------------------------------------------------------------------------- + * V4L2 subdev internal operations + */ + +static int mt9p031_registered(struct v4l2_subdev *subdev) +{ + struct i2c_client *client = v4l2_get_subdevdata(subdev); + struct mt9p031 *mt9p031 = to_mt9p031(subdev); + s32 data; + int ret; + + ret = mt9p031_power_on(mt9p031); + if (ret < 0) { + dev_err(&client->dev, "MT9P031 power up failed\n"); + return ret; + } + + /* Read out the chip version register */ + data = mt9p031_read(client, MT9P031_CHIP_VERSION); + if (data != MT9P031_CHIP_VERSION_VALUE) { + dev_err(&client->dev, "MT9P031 not detected, wrong version " + "0x%04x\n", data); + return -ENODEV; + } + + mt9p031_power_off(mt9p031); + + dev_info(&client->dev, "MT9P031 detected at address 0x%02x\n", + client->addr); + + return ret; +} + +static int mt9p031_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) +{ + struct mt9p031 *mt9p031 = to_mt9p031(subdev); + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; + + crop = v4l2_subdev_get_try_crop(fh, 0); + crop->left = MT9P031_COLUMN_START_DEF; + crop->top = MT9P031_ROW_START_DEF; + crop->width = MT9P031_WINDOW_WIDTH_DEF; + crop->height = MT9P031_WINDOW_HEIGHT_DEF; + + format = v4l2_subdev_get_try_format(fh, 0); + + if (mt9p031->pdata->version == MT9P031_MONOCHROME_VERSION) + format->code = V4L2_MBUS_FMT_Y12_1X12; + else + format->code = V4L2_MBUS_FMT_SGRBG12_1X12; + + format->width = MT9P031_WINDOW_WIDTH_DEF; + format->height = MT9P031_WINDOW_HEIGHT_DEF; + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_SRGB; + + mt9p031->xskip = 1; + mt9p031->yskip = 1; + return mt9p031_set_power(subdev, 1); +} + +static int mt9p031_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) +{ + return mt9p031_set_power(subdev, 0); +} + +static struct v4l2_subdev_core_ops mt9p031_subdev_core_ops = { + .s_power = mt9p031_set_power, +}; + +static struct v4l2_subdev_video_ops mt9p031_subdev_video_ops = { + .s_stream = mt9p031_s_stream, +}; + +static struct v4l2_subdev_pad_ops mt9p031_subdev_pad_ops = { + .enum_mbus_code = mt9p031_enum_mbus_code, + .enum_frame_size = mt9p031_enum_frame_size, + .get_fmt = mt9p031_get_format, + .set_fmt = mt9p031_set_format, + .get_crop = mt9p031_get_crop, + .set_crop = mt9p031_set_crop, +}; + +static struct v4l2_subdev_ops mt9p031_subdev_ops = { + .core = &mt9p031_subdev_core_ops, + .video = &mt9p031_subdev_video_ops, + .pad = &mt9p031_subdev_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops mt9p031_subdev_internal_ops = { + .registered = mt9p031_registered, + .open = mt9p031_open, + .close = mt9p031_close, +}; + +/* ----------------------------------------------------------------------------- + * Driver initialization and probing + */ + +static int mt9p031_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct mt9p031_platform_data *pdata = client->dev.platform_data; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct mt9p031 *mt9p031; + unsigned int i; + int ret; + + if (pdata == NULL) { + dev_err(&client->dev, "No platform data\n"); + return -EINVAL; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { + dev_warn(&client->dev, + "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); + return -EIO; + } + + mt9p031 = kzalloc(sizeof(*mt9p031), GFP_KERNEL); + if (mt9p031 == NULL) + return -ENOMEM; + + mt9p031->pdata = pdata; + mt9p031->output_control = MT9P031_OUTPUT_CONTROL_DEF; + mt9p031->mode2 = MT9P031_READ_MODE_2_ROW_BLC; + + v4l2_ctrl_handler_init(&mt9p031->ctrls, ARRAY_SIZE(mt9p031_ctrls) + 4); + + v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops, + V4L2_CID_EXPOSURE, MT9P031_SHUTTER_WIDTH_MIN, + MT9P031_SHUTTER_WIDTH_MAX, 1, + MT9P031_SHUTTER_WIDTH_DEF); + v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops, + V4L2_CID_GAIN, MT9P031_GLOBAL_GAIN_MIN, + MT9P031_GLOBAL_GAIN_MAX, 1, MT9P031_GLOBAL_GAIN_DEF); + v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + + for (i = 0; i < ARRAY_SIZE(mt9p031_ctrls); ++i) + v4l2_ctrl_new_custom(&mt9p031->ctrls, &mt9p031_ctrls[i], NULL); + + mt9p031->subdev.ctrl_handler = &mt9p031->ctrls; + + if (mt9p031->ctrls.error) + printk(KERN_INFO "%s: control initialization error %d\n", + __func__, mt9p031->ctrls.error); + + mutex_init(&mt9p031->power_lock); + v4l2_i2c_subdev_init(&mt9p031->subdev, client, &mt9p031_subdev_ops); + mt9p031->subdev.internal_ops = &mt9p031_subdev_internal_ops; + + mt9p031->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_init(&mt9p031->subdev.entity, 1, &mt9p031->pad, 0); + if (ret < 0) + goto done; + + mt9p031->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + mt9p031->crop.width = MT9P031_WINDOW_WIDTH_DEF; + mt9p031->crop.height = MT9P031_WINDOW_HEIGHT_DEF; + mt9p031->crop.left = MT9P031_COLUMN_START_DEF; + mt9p031->crop.top = MT9P031_ROW_START_DEF; + + if (mt9p031->pdata->version == MT9P031_MONOCHROME_VERSION) + mt9p031->format.code = V4L2_MBUS_FMT_Y12_1X12; + else + mt9p031->format.code = V4L2_MBUS_FMT_SGRBG12_1X12; + + mt9p031->format.width = MT9P031_WINDOW_WIDTH_DEF; + mt9p031->format.height = MT9P031_WINDOW_HEIGHT_DEF; + mt9p031->format.field = V4L2_FIELD_NONE; + mt9p031->format.colorspace = V4L2_COLORSPACE_SRGB; + + ret = mt9p031_pll_get_divs(mt9p031); + +done: + if (ret < 0) { + v4l2_ctrl_handler_free(&mt9p031->ctrls); + media_entity_cleanup(&mt9p031->subdev.entity); + kfree(mt9p031); + } + + return ret; +} + +static int mt9p031_remove(struct i2c_client *client) +{ + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct mt9p031 *mt9p031 = to_mt9p031(subdev); + + v4l2_ctrl_handler_free(&mt9p031->ctrls); + v4l2_device_unregister_subdev(subdev); + media_entity_cleanup(&subdev->entity); + kfree(mt9p031); + + return 0; +} + +static const struct i2c_device_id mt9p031_id[] = { + { "mt9p031", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mt9p031_id); + +static struct i2c_driver mt9p031_i2c_driver = { + .driver = { + .name = "mt9p031", + }, + .probe = mt9p031_probe, + .remove = mt9p031_remove, + .id_table = mt9p031_id, +}; + +static int __init mt9p031_mod_init(void) +{ + return i2c_add_driver(&mt9p031_i2c_driver); +} + +static void __exit mt9p031_mod_exit(void) +{ + i2c_del_driver(&mt9p031_i2c_driver); +} + +module_init(mt9p031_mod_init); +module_exit(mt9p031_mod_exit); + +MODULE_DESCRIPTION("Aptina MT9P031 Camera driver"); +MODULE_AUTHOR("Bastian Hecht "); +MODULE_LICENSE("GPL v2"); diff --git a/include/media/mt9p031.h b/include/media/mt9p031.h new file mode 100644 index 0000000..96448c7 --- /dev/null +++ b/include/media/mt9p031.h @@ -0,0 +1,19 @@ +#ifndef MT9P031_H +#define MT9P031_H + +struct v4l2_subdev; + +enum { + MT9P031_COLOR_VERSION, + MT9P031_MONOCHROME_VERSION, +}; + +struct mt9p031_platform_data { + int (*set_xclk)(struct v4l2_subdev *subdev, int hz); + int (*reset)(struct v4l2_subdev *subdev, int active); + int ext_freq; /* input frequency to the mt9p031 for PLL dividers */ + int target_freq; /* frequency target for the PLL */ + int version; /* MT9P031_COLOR_VERSION or MT9P031_MONOCHROME_VERSION */ +}; + +#endif -- cgit v0.10.2 From 16e3d2f4fab6e001a79705fa273418afc10188f8 Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Sun, 4 Sep 2011 15:38:14 -0300 Subject: [media] EM28xx - Fix memory leak on disconnect or error Release the dev->alt_max_pkt_size buffer in all cases. Signed-off-by: Chris Rankin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 5fddcd0..013e946 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -3201,6 +3201,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, retval = em28xx_init_dev(&dev, udev, interface, nr); if (retval) { mutex_unlock(&dev->lock); + kfree(dev->alt_max_pkt_size); kfree(dev); goto err; } diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index d176dc0..61f35c8 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -2200,6 +2200,7 @@ static int em28xx_v4l2_close(struct file *filp) free the remaining resources */ if (dev->state & DEV_DISCONNECTED) { em28xx_release_resources(dev); + kfree(dev->alt_max_pkt_size); kfree(dev); return 0; } -- cgit v0.10.2 From 09fc9802c31a9358a4e34642aa5f569111752879 Mon Sep 17 00:00:00 2001 From: Simon Farnsworth Date: Mon, 5 Sep 2011 12:23:12 -0300 Subject: [media] cx18: Fix videobuf capture When we moved to 3.0, we found that the cx18 driver was oopsing on close with: NULL pointer deref at: [ 2290.461009] Call Trace: [ 2290.461009] [] ? pm_qos_add_request+0xc/0x6e [ 2290.461009] [] __mutex_lock_common+0x87/0x125 [ 2290.461009] [] ? cx18_queue_flush+0x31/0x87 [cx18] [ 2290.461009] [] ? __might_sleep+0x29/0xe4 [ 2290.461009] [] __mutex_lock_slowpath+0x25/0x27 [ 2290.461009] [] ? mutex_lock+0x2e/0x3b [ 2290.461009] [] mutex_lock+0x2e/0x3b [ 2290.461009] [] videobuf_queue_lock+0x13/0x15 [videobuf_core] [ 2290.461009] [] __videobuf_free+0xfc/0x112 [videobuf_core] [ 2290.461009] [] cx18_v4l2_close+0x158/0x172 [cx18] [ 2290.461009] [] ? cpumask_next+0x1a/0x1d [ 2290.461009] [] v4l2_release+0x35/0x52 [videodev] [ 2290.461009] [] fput+0x100/0x1a5 [ 2290.461009] [] filp_close+0x5c/0x64 [ 2290.461009] [] sys_close+0x5f/0x93 [ 2290.461009] [] sysenter_do_call+0x12/0x28 Some digging showed that a merge at some previous point partially added broken mmap() support, causing this trace. Remove the broken code completely. On top of that, the calculation in place for "buffer full" depended on UYUV instead of HM12, while our GStreamer code was picking HM12 in some circumstances. Finally, the V4L2_CAP_STREAMING capability was never exposed. Patch it into the YUV encoder node only. Signed-off-by: Simon Farnsworth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h index 1834207..b9a94fc 100644 --- a/drivers/media/video/cx18/cx18-driver.h +++ b/drivers/media/video/cx18/cx18-driver.h @@ -409,6 +409,7 @@ struct cx18_stream { /* Videobuf for YUV video */ u32 pixelformat; + u32 vb_bytes_per_frame; struct list_head vb_capture; /* video capture queue */ spinlock_t vb_lock; struct timer_list vb_timeout; @@ -430,10 +431,6 @@ struct cx18_open_id { u32 open_id; int type; struct cx18 *cx; - - struct videobuf_queue vbuf_q; - spinlock_t s_lock; /* Protect vbuf_q */ - enum v4l2_buf_type vb_type; }; static inline struct cx18_open_id *fh2id(struct v4l2_fh *fh) diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c index 07411f3..14cb961 100644 --- a/drivers/media/video/cx18/cx18-fileops.c +++ b/drivers/media/video/cx18/cx18-fileops.c @@ -784,8 +784,6 @@ int cx18_v4l2_close(struct file *filp) cx18_release_stream(s); } else { cx18_stop_capture(id, 0); - if (id->type == CX18_ENC_STREAM_TYPE_YUV) - videobuf_mmap_free(&id->vbuf_q); } kfree(id); mutex_unlock(&cx->serialize_lock); diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index afe0a29..66b1c15 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c @@ -160,12 +160,7 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh, pixfmt->priv = 0; if (id->type == CX18_ENC_STREAM_TYPE_YUV) { pixfmt->pixelformat = s->pixelformat; - /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2))) - UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */ - if (s->pixelformat == V4L2_PIX_FMT_HM12) - pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2; - else - pixfmt->sizeimage = pixfmt->height * 720 * 2; + pixfmt->sizeimage = s->vb_bytes_per_frame; pixfmt->bytesperline = 720; } else { pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; @@ -296,6 +291,12 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh, return -EBUSY; s->pixelformat = fmt->fmt.pix.pixelformat; + /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2))) + UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */ + if (s->pixelformat == V4L2_PIX_FMT_HM12) + s->vb_bytes_per_frame = h * 720 * 3 / 2; + else + s->vb_bytes_per_frame = h * 720 * 2; mbus_fmt.width = cx->cxhdl.width = w; mbus_fmt.height = cx->cxhdl.height = h; @@ -463,13 +464,16 @@ static int cx18_s_register(struct file *file, void *fh, static int cx18_querycap(struct file *file, void *fh, struct v4l2_capability *vcap) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18_open_id *id = fh2id(fh); + struct cx18 *cx = id->cx; strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver)); strlcpy(vcap->card, cx->card_name, sizeof(vcap->card)); snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(cx->pci_dev)); vcap->capabilities = cx->v4l2_cap; /* capabilities */ + if (id->type == CX18_ENC_STREAM_TYPE_YUV) + vcap->capabilities |= V4L2_CAP_STREAMING; return 0; } diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c index c07191e..0c7796e 100644 --- a/drivers/media/video/cx18/cx18-mailbox.c +++ b/drivers/media/video/cx18/cx18-mailbox.c @@ -196,7 +196,7 @@ static void cx18_mdl_send_to_videobuf(struct cx18_stream *s, } /* If we've filled the buffer as per the callers res then dispatch it */ - if (vb_buf->bytes_used >= (vb_buf->vb.width * vb_buf->vb.height * 2)) { + if (vb_buf->bytes_used >= s->vb_bytes_per_frame) { dispatch = 1; vb_buf->bytes_used = 0; } diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index 852f420..638cca1 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c @@ -138,6 +138,12 @@ static int cx18_prepare_buffer(struct videobuf_queue *q, buf->tvnorm = cx->std; s->pixelformat = pixelformat; + /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2))) + UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */ + if (s->pixelformat == V4L2_PIX_FMT_HM12) + s->vb_bytes_per_frame = height * 720 * 3 / 2; + else + s->vb_bytes_per_frame = height * 720 * 2; cx18_dma_free(q, s, buf); } @@ -154,6 +160,12 @@ static int cx18_prepare_buffer(struct videobuf_queue *q, buf->tvnorm = cx->std; s->pixelformat = pixelformat; + /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2))) + UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */ + if (s->pixelformat == V4L2_PIX_FMT_HM12) + s->vb_bytes_per_frame = height * 720 * 3 / 2; + else + s->vb_bytes_per_frame = height * 720 * 2; rc = videobuf_iolock(q, &buf->vb, NULL); if (rc != 0) goto fail; @@ -287,6 +299,7 @@ static void cx18_stream_init(struct cx18 *cx, int type) /* Assume the previous pixel default */ s->pixelformat = V4L2_PIX_FMT_HM12; + s->vb_bytes_per_frame = cx->cxhdl.height * 720 * 3 / 2; } } -- cgit v0.10.2 From e27412f5a5966629e3d4213c78a539068ca0ea26 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Wed, 7 Sep 2011 05:36:46 -0300 Subject: [media] mmp_camera: add MODULE_ALIAS This enables module autoloading. Signed-off-by: Daniel Drake Acked-by: Jonathan Corbet Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/marvell-ccic/mmp-driver.c b/drivers/media/video/marvell-ccic/mmp-driver.c index d6b7645..fb0b124 100644 --- a/drivers/media/video/marvell-ccic/mmp-driver.c +++ b/drivers/media/video/marvell-ccic/mmp-driver.c @@ -29,6 +29,7 @@ #include "mcam-core.h" +MODULE_ALIAS("platform:mmp-camera"); MODULE_AUTHOR("Jonathan Corbet "); MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 47a7e6f8d282d199f14abbb068c6c3ba00cb7bfc Mon Sep 17 00:00:00 2001 From: Arvydas Sidorenko Date: Tue, 13 Sep 2011 07:18:10 -0300 Subject: [media] drivers/media/video/stk-webcam.c: webcam LED bug fix The probem was on my DC-1125 webcam chip from Syntek. Whenever the webcam turns on, the LED light on it is turn on also and never turns off again unless system is shut downed or restarted. This patch will fix this issue - the LED will be turned off whenever the device is released. Signed-off-by: Arvydas Sidorenko Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c index d1a2cef..859e78f 100644 --- a/drivers/media/video/stk-webcam.c +++ b/drivers/media/video/stk-webcam.c @@ -574,6 +574,8 @@ static int v4l_stk_release(struct file *fp) if (dev->owner == fp) { stk_stop_stream(dev); stk_free_buffers(dev); + stk_camera_write_reg(dev, 0x0, 0x48); /* turn off the LED */ + unset_initialised(dev); dev->owner = NULL; } -- cgit v0.10.2 From b57ce4179b502b3f481f7632da20aae3e488e31a Mon Sep 17 00:00:00 2001 From: Arvydas Sidorenko Date: Tue, 13 Sep 2011 07:18:11 -0300 Subject: [media] drivers/media/video/stk-webcam.c: coding style issue checkpatch.pl gave some coding style errors, so on the way to the first patch I added the fix to them. Signed-off-by: Arvydas Sidorenko Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c index 859e78f..5fc6bbc 100644 --- a/drivers/media/video/stk-webcam.c +++ b/drivers/media/video/stk-webcam.c @@ -518,7 +518,7 @@ static int stk_prepare_sio_buffers(struct stk_camera *dev, unsigned n_sbufs) return -ENOMEM; for (i = 0; i < n_sbufs; i++) { if (stk_setup_siobuf(dev, i)) - return (dev->n_sbufs > 1)? 0 : -ENOMEM; + return (dev->n_sbufs > 1 ? 0 : -ENOMEM); dev->n_sbufs = i+1; } } @@ -558,9 +558,8 @@ static int v4l_stk_open(struct file *fp) vdev = video_devdata(fp); dev = vdev_to_camera(vdev); - if (dev == NULL || !is_present(dev)) { + if (dev == NULL || !is_present(dev)) return -ENXIO; - } fp->private_data = dev; usb_autopm_get_interface(dev->interface); @@ -579,7 +578,7 @@ static int v4l_stk_release(struct file *fp) dev->owner = NULL; } - if(is_present(dev)) + if (is_present(dev)) usb_autopm_put_interface(dev->interface); return 0; @@ -656,7 +655,7 @@ static unsigned int v4l_stk_poll(struct file *fp, poll_table *wait) return POLLERR; if (!list_empty(&dev->sio_full)) - return (POLLIN | POLLRDNORM); + return POLLIN | POLLRDNORM; return 0; } @@ -893,9 +892,9 @@ static int stk_vidioc_g_fmt_vid_cap(struct file *filp, struct stk_camera *dev = priv; int i; - for (i = 0; i < ARRAY_SIZE(stk_sizes) - && stk_sizes[i].m != dev->vsettings.mode; - i++); + for (i = 0; i < ARRAY_SIZE(stk_sizes) && + stk_sizes[i].m != dev->vsettings.mode; i++) + ; if (i == ARRAY_SIZE(stk_sizes)) { STK_ERROR("ERROR: mode invalid\n"); return -EINVAL; @@ -1307,9 +1306,8 @@ static int stk_camera_probe(struct usb_interface *interface, usb_set_intfdata(interface, dev); err = stk_register_video_device(dev); - if (err) { + if (err) goto error; - } return 0; -- cgit v0.10.2 From 74a45790861f659058e8f8b565d98e5a1fdd8440 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 26 Aug 2011 07:31:13 -0300 Subject: [media] videodev2.h: add V4L2_CTRL_FLAG_VOLATILE Add a new VOLATILE control flag that is set for volatile controls. That way applications know whether the value of the control is volatile (i.e. can change continuously) or not. Until now this was an internal property, but it is useful to know in userspace as well. A typical use case is the gain value when autogain is on. In that case the hardware will continuously adjust the gain based various environmental factors. This patch just adds and documents the flag, it's not yet used. Signed-off-by: Hans Verkuil Acked-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml index ce1004a..91410b6 100644 --- a/Documentation/DocBook/media/v4l/compat.xml +++ b/Documentation/DocBook/media/v4l/compat.xml @@ -2370,6 +2370,14 @@ that used it. It was originally scheduled for removal in 2.6.35. +
+ V4L2 in Linux 3.2 + + + V4L2_CTRL_FLAG_VOLATILE was added to signal volatile controls to userspace. + + +
Relation of V4L2 to other Linux multimedia APIs diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml index 0d05e87..40132c2 100644 --- a/Documentation/DocBook/media/v4l/v4l2.xml +++ b/Documentation/DocBook/media/v4l/v4l2.xml @@ -128,6 +128,13 @@ structs, ioctls) must be noted in more detail in the history chapter applications. --> + 3.2 + 2011-08-26 + hv + Added V4L2_CTRL_FLAG_VOLATILE. + + + 3.1 2011-06-27 mcc, po, hv @@ -410,7 +417,7 @@ and discussions on the V4L mailing list. Video for Linux Two API Specification - Revision 3.1 + Revision 3.2 &sub-common; diff --git a/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml index 677ea64..0ac0057 100644 --- a/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml +++ b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml @@ -406,6 +406,15 @@ flag is typically present for relative controls or action controls where writing a value will cause the device to carry out a given action (⪚ motor control) but no meaningful value can be returned. + + V4L2_CTRL_FLAG_VOLATILE + 0x0080 + This control is volatile, which means that the value of the control +changes continuously. A typical example would be the current gain value if the device +is in auto-gain mode. In such a case the hardware calculates the gain value based on +the lighting conditions which can change over time. Note that setting a new value for +a volatile control will have no effect. The new value will just be ignored. +
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index a5359c6..9d14523 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -1082,6 +1082,7 @@ struct v4l2_querymenu { #define V4L2_CTRL_FLAG_INACTIVE 0x0010 #define V4L2_CTRL_FLAG_SLIDER 0x0020 #define V4L2_CTRL_FLAG_WRITE_ONLY 0x0040 +#define V4L2_CTRL_FLAG_VOLATILE 0x0080 /* Query flag, to be ORed with the control ID */ #define V4L2_CTRL_FLAG_NEXT_CTRL 0x80000000 -- cgit v0.10.2 From 88365105d683187e02a4f75220eaf51fd0c0b6e0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 26 Aug 2011 07:35:14 -0300 Subject: [media] v4l2-ctrls: replace is_volatile with V4L2_CTRL_FLAG_VOLATILE With the new flag there is no need anymore to have a separate is_volatile field. Modify all users to use the new flag. Signed-off-by: Hans Verkuil Acked-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/video4linux/v4l2-controls.txt b/Documentation/video4linux/v4l2-controls.txt index 9346fc8..f92ee30 100644 --- a/Documentation/video4linux/v4l2-controls.txt +++ b/Documentation/video4linux/v4l2-controls.txt @@ -285,11 +285,11 @@ implement g_volatile_ctrl like this: Note that you use the 'new value' union as well in g_volatile_ctrl. In general controls that need to implement g_volatile_ctrl are read-only controls. -To mark a control as volatile you have to set the is_volatile flag: +To mark a control as volatile you have to set V4L2_CTRL_FLAG_VOLATILE: ctrl = v4l2_ctrl_new_std(&sd->ctrl_handler, ...); if (ctrl) - ctrl->is_volatile = 1; + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; For try/s_ctrl the new values (i.e. as passed by the user) are filled in and you can modify them in try_ctrl or set them in s_ctrl. The 'cur' union @@ -367,8 +367,7 @@ Driver specific controls can be created using v4l2_ctrl_new_custom(): The last argument is the priv pointer which can be set to driver-specific private data. -The v4l2_ctrl_config struct also has fields to set the is_private and is_volatile -flags. +The v4l2_ctrl_config struct also has a field to set the is_private flag. If the name field is not set, then the framework will assume this is a standard control and will fill in the name, type and flags fields accordingly. @@ -506,8 +505,8 @@ operation should return the value that the hardware's automatic mode set up automatically. If the cluster is put in manual mode, then the manual controls should become -active again and the is_volatile flag should be ignored (so g_volatile_ctrl is -no longer called while in manual mode). +active again and V4L2_CTRL_FLAG_VOLATILE should be ignored (so g_volatile_ctrl +is no longer called while in manual mode). Finally the V4L2_CTRL_FLAG_UPDATE should be set for the auto control since changing that control affects the control flags of the manual controls. @@ -520,7 +519,7 @@ void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls, The first two arguments are identical to v4l2_ctrl_cluster. The third argument tells the framework which value switches the cluster into manual mode. The -last argument will optionally set the is_volatile flag for the non-auto controls. +last argument will optionally set V4L2_CTRL_FLAG_VOLATILE for the non-auto controls. The first control of the cluster is assumed to be the 'auto' control. diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index 46cacf8..6d1e4e7 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -2109,7 +2109,7 @@ static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev) V4L2_CID_TUNE_ANTENNA_CAPACITOR, 0, 255, 1, 255); if (ctrl) - ctrl->is_volatile = 1; + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; if (radio->ctrl_handler.error) { r = radio->ctrl_handler.error; diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c index 478d1e9..aaee747 100644 --- a/drivers/media/radio/wl128x/fmdrv_v4l2.c +++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c @@ -559,7 +559,7 @@ int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr) 255, 1, 255); if (ctrl) - ctrl->is_volatile = 1; + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; return 0; } diff --git a/drivers/media/video/adp1653.c b/drivers/media/video/adp1653.c index 279d75d..d0e8ac1 100644 --- a/drivers/media/video/adp1653.c +++ b/drivers/media/video/adp1653.c @@ -258,7 +258,7 @@ static int adp1653_init_controls(struct adp1653_flash *flash) if (flash->ctrls.error) return flash->ctrls.error; - fault->is_volatile = 1; + fault->flags |= V4L2_CTRL_FLAG_VOLATILE; flash->subdev.ctrl_handler = &flash->ctrls; return 0; diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c index 8c70e64..6873bf5 100644 --- a/drivers/media/video/pwc/pwc-v4l.c +++ b/drivers/media/video/pwc/pwc-v4l.c @@ -640,7 +640,7 @@ static int pwc_set_awb(struct pwc_device *pdev) return ret; /* Update val when coming from auto or going to a preset */ - if (pdev->red_balance->is_volatile || + if ((pdev->red_balance->flags & V4L2_CTRL_FLAG_VOLATILE) || pdev->auto_white_balance->val == awb_indoor || pdev->auto_white_balance->val == awb_outdoor || pdev->auto_white_balance->val == awb_fl) { @@ -654,12 +654,12 @@ static int pwc_set_awb(struct pwc_device *pdev) &pdev->blue_balance->val); } if (pdev->auto_white_balance->val == awb_auto) { - pdev->red_balance->is_volatile = true; - pdev->blue_balance->is_volatile = true; + pdev->red_balance->flags |= V4L2_CTRL_FLAG_VOLATILE; + pdev->blue_balance->flags |= V4L2_CTRL_FLAG_VOLATILE; pdev->color_bal_valid = false; /* Force cache update */ } else { - pdev->red_balance->is_volatile = false; - pdev->blue_balance->is_volatile = false; + pdev->red_balance->flags &= ~V4L2_CTRL_FLAG_VOLATILE; + pdev->blue_balance->flags &= ~V4L2_CTRL_FLAG_VOLATILE; } } diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c index 32f8989..bfbe084 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c @@ -165,7 +165,7 @@ static struct mfc_control controls[] = { .maximum = 32, .step = 1, .default_value = 1, - .is_volatile = 1, + .flags = V4L2_CTRL_FLAG_VOLATILE, }, }; @@ -1020,7 +1020,7 @@ int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx) return ctx->ctrl_handler.error; } if (controls[i].is_volatile && ctx->ctrls[i]) - ctx->ctrls[i]->is_volatile = 1; + ctx->ctrls[i]->flags |= V4L2_CTRL_FLAG_VOLATILE; } return 0; } diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c index 14ddbd2..4c90e53 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c @@ -1814,7 +1814,7 @@ int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx) return ctx->ctrl_handler.error; } if (controls[i].is_volatile && ctx->ctrls[i]) - ctx->ctrls[i]->is_volatile = 1; + ctx->ctrls[i]->flags |= V4L2_CTRL_FLAG_VOLATILE; } return 0; } diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index f2ae405..e443d0d 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -1601,7 +1601,7 @@ static int saa711x_probe(struct i2c_client *client, V4L2_CID_CHROMA_AGC, 0, 1, 1, 1); state->gain = v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops, V4L2_CID_CHROMA_GAIN, 0, 127, 1, 40); - state->gain->is_volatile = 1; + state->gain->flags |= V4L2_CTRL_FLAG_VOLATILE; sd->ctrl_handler = hdl; if (hdl->error) { int err = hdl->error; diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c index 06b6014..1667621 100644 --- a/drivers/media/video/v4l2-ctrls.c +++ b/drivers/media/video/v4l2-ctrls.c @@ -43,7 +43,7 @@ struct v4l2_ctrl_helper { }; /* Small helper function to determine if the autocluster is set to manual - mode. In that case the is_volatile flag should be ignored. */ + mode. */ static bool is_cur_manual(const struct v4l2_ctrl *master) { return master->is_auto && master->cur.val == master->manual_mode_value; @@ -1394,10 +1394,8 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl, type, min, max, is_menu ? cfg->menu_skip_mask : step, def, flags, qmenu, priv); - if (ctrl) { + if (ctrl) ctrl->is_private = cfg->is_private; - ctrl->is_volatile = cfg->is_volatile; - } return ctrl; } EXPORT_SYMBOL(v4l2_ctrl_new_custom); @@ -1519,12 +1517,12 @@ void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls, master->manual_mode_value = manual_val; master->flags |= V4L2_CTRL_FLAG_UPDATE; flag = is_cur_manual(master) ? 0 : V4L2_CTRL_FLAG_INACTIVE; + if (set_volatile) + flag |= V4L2_CTRL_FLAG_VOLATILE; for (i = 1; i < ncontrols; i++) - if (controls[i]) { - controls[i]->is_volatile = set_volatile; + if (controls[i]) controls[i]->flags |= flag; - } } EXPORT_SYMBOL(v4l2_ctrl_auto_cluster); @@ -1579,9 +1577,6 @@ EXPORT_SYMBOL(v4l2_ctrl_grab); static void log_ctrl(const struct v4l2_ctrl *ctrl, const char *prefix, const char *colon) { - int fl_inact = ctrl->flags & V4L2_CTRL_FLAG_INACTIVE; - int fl_grabbed = ctrl->flags & V4L2_CTRL_FLAG_GRABBED; - if (ctrl->flags & (V4L2_CTRL_FLAG_DISABLED | V4L2_CTRL_FLAG_WRITE_ONLY)) return; if (ctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS) @@ -1612,14 +1607,17 @@ static void log_ctrl(const struct v4l2_ctrl *ctrl, printk(KERN_CONT "unknown type %d", ctrl->type); break; } - if (fl_inact && fl_grabbed) - printk(KERN_CONT " (inactive, grabbed)\n"); - else if (fl_inact) - printk(KERN_CONT " (inactive)\n"); - else if (fl_grabbed) - printk(KERN_CONT " (grabbed)\n"); - else - printk(KERN_CONT "\n"); + if (ctrl->flags & (V4L2_CTRL_FLAG_INACTIVE | + V4L2_CTRL_FLAG_GRABBED | + V4L2_CTRL_FLAG_VOLATILE)) { + if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) + printk(KERN_CONT " inactive"); + if (ctrl->flags & V4L2_CTRL_FLAG_GRABBED) + printk(KERN_CONT " grabbed"); + if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) + printk(KERN_CONT " volatile"); + } + printk(KERN_CONT "\n"); } /* Log all controls owned by the handler */ @@ -2004,7 +2002,7 @@ static int get_ctrl(struct v4l2_ctrl *ctrl, s32 *val) v4l2_ctrl_lock(master); /* g_volatile_ctrl will update the current control values */ - if (ctrl->is_volatile && !is_cur_manual(master)) { + if ((ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) && !is_cur_manual(master)) { for (i = 0; i < master->ncontrols; i++) cur_to_new(master->cluster[i]); ret = call_op(master, g_volatile_ctrl); diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index 13fe4d7..bd6a4a7 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -65,10 +65,6 @@ struct v4l2_ctrl_ops { * @is_private: If set, then this control is private to its handler and it * will not be added to any other handlers. Drivers can set * this flag. - * @is_volatile: If set, then this control is volatile. This means that the - * control's current value cannot be cached and needs to be - * retrieved through the g_volatile_ctrl op. Drivers can set - * this flag. * @is_auto: If set, then this control selects whether the other cluster * members are in 'automatic' mode or 'manual' mode. This is * used for autogain/gain type clusters. Drivers should never @@ -118,7 +114,6 @@ struct v4l2_ctrl { unsigned int is_new:1; unsigned int is_private:1; - unsigned int is_volatile:1; unsigned int is_auto:1; unsigned int manual_mode_value:8; @@ -208,9 +203,6 @@ struct v4l2_ctrl_handler { * must be NULL. * @is_private: If set, then this control is private to its handler and it * will not be added to any other handlers. - * @is_volatile: If set, then this control is volatile. This means that the - * control's current value cannot be cached and needs to be - * retrieved through the g_volatile_ctrl op. */ struct v4l2_ctrl_config { const struct v4l2_ctrl_ops *ops; @@ -225,7 +217,6 @@ struct v4l2_ctrl_config { u32 menu_skip_mask; const char * const *qmenu; unsigned int is_private:1; - unsigned int is_volatile:1; }; /** v4l2_ctrl_fill() - Fill in the control fields based on the control ID. @@ -389,8 +380,7 @@ void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls); * @manual_val: The value for the first control in the cluster that equals the * manual setting. * @set_volatile: If true, then all controls except the first auto control will - * have is_volatile set to true. If false, then is_volatile will not - * be touched. + * be volatile. * * Use for control groups where one control selects some automatic feature and * the other controls are only active whenever the automatic feature is turned -- cgit v0.10.2 From 85bc9b510aae310ac5530ae364b1145b5cc0ce68 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 1 Aug 2011 00:52:11 -0300 Subject: [media] a8293: Allegro A8293 SEC driver Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 17082df..8e1a183 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -621,6 +621,11 @@ config DVB_ISL6423 help A SEC controller chip from Intersil +config DVB_A8293 + tristate "Allegro A8293" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + config DVB_LGS8GL5 tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)" depends on DVB_CORE && I2C diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 18d045d..08040cf 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -92,4 +92,5 @@ obj-$(CONFIG_DVB_CXD2820R) += cxd2820r.o obj-$(CONFIG_DVB_DRXK) += drxk.o obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o obj-$(CONFIG_DVB_IT913X_FE) += it913x-fe.o +obj-$(CONFIG_DVB_A8293) += a8293.o diff --git a/drivers/media/dvb/frontends/a8293.c b/drivers/media/dvb/frontends/a8293.c new file mode 100644 index 0000000..bb56497 --- /dev/null +++ b/drivers/media/dvb/frontends/a8293.c @@ -0,0 +1,184 @@ +/* + * Allegro A8293 SEC driver + * + * Copyright (C) 2011 Antti Palosaari + * + * 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 of the License, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "dvb_frontend.h" +#include "a8293.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +#define LOG_PREFIX "a8293" + +#undef dbg +#define dbg(f, arg...) \ + if (debug) \ + printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) +#undef err +#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) +#undef info +#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) +#undef warn +#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) + + +struct a8293_priv { + struct i2c_adapter *i2c; + const struct a8293_config *cfg; + u8 reg[2]; +}; + +static int a8293_i2c(struct a8293_priv *priv, u8 *val, int len, bool rd) +{ + int ret; + struct i2c_msg msg[1] = { + { + .addr = priv->cfg->i2c_addr, + .len = len, + .buf = val, + } + }; + + if (rd) + msg[0].flags = I2C_M_RD; + else + msg[0].flags = 0; + + ret = i2c_transfer(priv->i2c, msg, 1); + if (ret == 1) { + ret = 0; + } else { + warn("i2c failed=%d rd=%d", ret, rd); + ret = -EREMOTEIO; + } + + return ret; +} + +static int a8293_wr(struct a8293_priv *priv, u8 *val, int len) +{ + return a8293_i2c(priv, val, len, 0); +} + +static int a8293_rd(struct a8293_priv *priv, u8 *val, int len) +{ + return a8293_i2c(priv, val, len, 1); +} + +static int a8293_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t fe_sec_voltage) +{ + struct a8293_priv *priv = fe->sec_priv; + int ret; + + dbg("%s: fe_sec_voltage=%d", __func__, fe_sec_voltage); + + switch (fe_sec_voltage) { + case SEC_VOLTAGE_OFF: + /* ENB=0 */ + priv->reg[0] = 0x10; + break; + case SEC_VOLTAGE_13: + /* VSEL0=1, VSEL1=0, VSEL2=0, VSEL3=0, ENB=1*/ + priv->reg[0] = 0x31; + break; + case SEC_VOLTAGE_18: + /* VSEL0=0, VSEL1=0, VSEL2=0, VSEL3=1, ENB=1*/ + priv->reg[0] = 0x38; + break; + default: + ret = -EINVAL; + goto err; + }; + + ret = a8293_wr(priv, &priv->reg[0], 1); + if (ret) + goto err; + + return ret; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static void a8293_release_sec(struct dvb_frontend *fe) +{ + dbg("%s:", __func__); + + a8293_set_voltage(fe, SEC_VOLTAGE_OFF); + + kfree(fe->sec_priv); + fe->sec_priv = NULL; +} + +struct dvb_frontend *a8293_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, const struct a8293_config *cfg) +{ + int ret; + struct a8293_priv *priv = NULL; + u8 buf[2]; + + /* allocate memory for the internal priv */ + priv = kzalloc(sizeof(struct a8293_priv), GFP_KERNEL); + if (priv == NULL) { + ret = -ENOMEM; + goto err; + } + + /* setup the priv */ + priv->i2c = i2c; + priv->cfg = cfg; + fe->sec_priv = priv; + + /* check if the SEC is there */ + ret = a8293_rd(priv, buf, 2); + if (ret) + goto err; + + /* ENB=0 */ + priv->reg[0] = 0x10; + ret = a8293_wr(priv, &priv->reg[1], 1); + if (ret) + goto err; + + /* TMODE=0, TGATE=1 */ + priv->reg[1] = 0x82; + ret = a8293_wr(priv, &priv->reg[1], 1); + if (ret) + goto err; + + info("Allegro A8293 SEC attached."); + + fe->ops.release_sec = a8293_release_sec; + + /* override frontend ops */ + fe->ops.set_voltage = a8293_set_voltage; + + return fe; +err: + dbg("%s: failed=%d", __func__, ret); + kfree(priv); + return NULL; +} +EXPORT_SYMBOL(a8293_attach); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Allegro A8293 SEC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/a8293.h b/drivers/media/dvb/frontends/a8293.h new file mode 100644 index 0000000..ed29e55 --- /dev/null +++ b/drivers/media/dvb/frontends/a8293.h @@ -0,0 +1,41 @@ +/* + * Allegro A8293 SEC driver + * + * Copyright (C) 2011 Antti Palosaari + * + * 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 of the License, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef A8293_H +#define A8293_H + +struct a8293_config { + u8 i2c_addr; +}; + +#if defined(CONFIG_DVB_A8293) || \ + (defined(CONFIG_DVB_A8293_MODULE) && defined(MODULE)) +extern struct dvb_frontend *a8293_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, const struct a8293_config *cfg); +#else +static inline struct dvb_frontend *a8293_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, const struct a8293_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* A8293_H */ -- cgit v0.10.2 From de8e42035014214708d9e32e12fe6d42a5ae59d1 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 1 Aug 2011 01:07:39 -0300 Subject: [media] tda10071: NXP TDA10071 DVB-S/S2 driver NXP TDA10071 DVB-S/S2 demodulator & Conexant CX24118A tuner combo driver Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 8e1a183..28fbb5c 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -236,6 +236,13 @@ config DVB_MB86A16 A DVB-S/DSS Direct Conversion reveiver. Say Y when you want to support this frontend. +config DVB_TDA10071 + tristate "NXP TDA10071" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + Say Y when you want to support this frontend. + comment "DVB-T (terrestrial) frontends" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 08040cf..36c8d81 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -93,4 +93,5 @@ obj-$(CONFIG_DVB_DRXK) += drxk.o obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o obj-$(CONFIG_DVB_IT913X_FE) += it913x-fe.o obj-$(CONFIG_DVB_A8293) += a8293.o +obj-$(CONFIG_DVB_TDA10071) += tda10071.o diff --git a/drivers/media/dvb/frontends/tda10071.c b/drivers/media/dvb/frontends/tda10071.c new file mode 100644 index 0000000..26b52cc --- /dev/null +++ b/drivers/media/dvb/frontends/tda10071.c @@ -0,0 +1,1266 @@ +/* + * NXP TDA10071 + Conexant CX24118A DVB-S/S2 demodulator + tuner driver + * + * Copyright (C) 2011 Antti Palosaari + * + * 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 of the License, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "tda10071_priv.h" + +int tda10071_debug; +module_param_named(debug, tda10071_debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +static struct dvb_frontend_ops tda10071_ops; + +/* write multiple registers */ +static int tda10071_wr_regs(struct tda10071_priv *priv, u8 reg, u8 *val, + int len) +{ + int ret; + u8 buf[len+1]; + struct i2c_msg msg[1] = { + { + .addr = priv->cfg.i2c_address, + .flags = 0, + .len = sizeof(buf), + .buf = buf, + } + }; + + buf[0] = reg; + memcpy(&buf[1], val, len); + + ret = i2c_transfer(priv->i2c, msg, 1); + if (ret == 1) { + ret = 0; + } else { + warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len); + ret = -EREMOTEIO; + } + return ret; +} + +/* read multiple registers */ +static int tda10071_rd_regs(struct tda10071_priv *priv, u8 reg, u8 *val, + int len) +{ + int ret; + u8 buf[len]; + struct i2c_msg msg[2] = { + { + .addr = priv->cfg.i2c_address, + .flags = 0, + .len = 1, + .buf = ®, + }, { + .addr = priv->cfg.i2c_address, + .flags = I2C_M_RD, + .len = sizeof(buf), + .buf = buf, + } + }; + + ret = i2c_transfer(priv->i2c, msg, 2); + if (ret == 2) { + memcpy(val, buf, len); + ret = 0; + } else { + warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len); + ret = -EREMOTEIO; + } + return ret; +} + +/* write single register */ +static int tda10071_wr_reg(struct tda10071_priv *priv, u8 reg, u8 val) +{ + return tda10071_wr_regs(priv, reg, &val, 1); +} + +/* read single register */ +static int tda10071_rd_reg(struct tda10071_priv *priv, u8 reg, u8 *val) +{ + return tda10071_rd_regs(priv, reg, val, 1); +} + +/* write single register with mask */ +int tda10071_wr_reg_mask(struct tda10071_priv *priv, u8 reg, u8 val, u8 mask) +{ + int ret; + u8 tmp; + + /* no need for read if whole reg is written */ + if (mask != 0xff) { + ret = tda10071_rd_regs(priv, reg, &tmp, 1); + if (ret) + return ret; + + val &= mask; + tmp &= ~mask; + val |= tmp; + } + + return tda10071_wr_regs(priv, reg, &val, 1); +} + +/* read single register with mask */ +int tda10071_rd_reg_mask(struct tda10071_priv *priv, u8 reg, u8 *val, u8 mask) +{ + int ret, i; + u8 tmp; + + ret = tda10071_rd_regs(priv, reg, &tmp, 1); + if (ret) + return ret; + + tmp &= mask; + + /* find position of the first bit */ + for (i = 0; i < 8; i++) { + if ((mask >> i) & 0x01) + break; + } + *val = tmp >> i; + + return 0; +} + +/* execute firmware command */ +static int tda10071_cmd_execute(struct tda10071_priv *priv, + struct tda10071_cmd *cmd) +{ + int ret, i; + u8 tmp; + + if (!priv->warm) { + ret = -EFAULT; + goto error; + } + + /* write cmd and args for firmware */ + ret = tda10071_wr_regs(priv, 0x00, cmd->args, cmd->len); + if (ret) + goto error; + + /* start cmd execution */ + ret = tda10071_wr_reg(priv, 0x1f, 1); + if (ret) + goto error; + + /* wait cmd execution terminate */ + for (i = 1000, tmp = 1; i && tmp; i--) { + ret = tda10071_rd_reg(priv, 0x1f, &tmp); + if (ret) + goto error; + + msleep(1); + } + + dbg("%s: loop=%d", __func__, i); + + if (i == 0) { + ret = -ETIMEDOUT; + goto error; + } + + return ret; +error: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int tda10071_set_tone(struct dvb_frontend *fe, + fe_sec_tone_mode_t fe_sec_tone_mode) +{ + struct tda10071_priv *priv = fe->demodulator_priv; + struct tda10071_cmd cmd; + int ret; + u8 tone; + + if (!priv->warm) { + ret = -EFAULT; + goto error; + } + + dbg("%s: tone_mode=%d", __func__, fe_sec_tone_mode); + + switch (fe_sec_tone_mode) { + case SEC_TONE_ON: + tone = 1; + break; + case SEC_TONE_OFF: + tone = 0; + break; + default: + dbg("%s: invalid fe_sec_tone_mode", __func__); + ret = -EINVAL; + goto error; + } + + cmd.args[0x00] = CMD_LNB_PCB_CONFIG; + cmd.args[0x01] = 0; + cmd.args[0x02] = 0x00; + cmd.args[0x03] = 0x00; + cmd.args[0x04] = tone; + cmd.len = 0x05; + ret = tda10071_cmd_execute(priv, &cmd); + if (ret) + goto error; + + return ret; +error: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int tda10071_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t fe_sec_voltage) +{ + struct tda10071_priv *priv = fe->demodulator_priv; + struct tda10071_cmd cmd; + int ret; + u8 voltage; + + if (!priv->warm) { + ret = -EFAULT; + goto error; + } + + dbg("%s: voltage=%d", __func__, fe_sec_voltage); + + switch (fe_sec_voltage) { + case SEC_VOLTAGE_13: + voltage = 0; + break; + case SEC_VOLTAGE_18: + voltage = 1; + break; + case SEC_VOLTAGE_OFF: + voltage = 0; + break; + default: + dbg("%s: invalid fe_sec_voltage", __func__); + ret = -EINVAL; + goto error; + }; + + cmd.args[0x00] = CMD_LNB_SET_DC_LEVEL; + cmd.args[0x01] = 0; + cmd.args[0x02] = voltage; + cmd.len = 0x03; + ret = tda10071_cmd_execute(priv, &cmd); + if (ret) + goto error; + + return ret; +error: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int tda10071_diseqc_send_master_cmd(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *diseqc_cmd) +{ + struct tda10071_priv *priv = fe->demodulator_priv; + struct tda10071_cmd cmd; + int ret, i; + u8 tmp; + + if (!priv->warm) { + ret = -EFAULT; + goto error; + } + + dbg("%s: msg_len=%d", __func__, diseqc_cmd->msg_len); + + if (diseqc_cmd->msg_len < 3 || diseqc_cmd->msg_len > 16) { + ret = -EINVAL; + goto error; + } + + /* wait LNB TX */ + for (i = 500, tmp = 0; i && !tmp; i--) { + ret = tda10071_rd_reg_mask(priv, 0x47, &tmp, 0x01); + if (ret) + goto error; + + msleep(10); + } + + dbg("%s: loop=%d", __func__, i); + + if (i == 0) { + ret = -ETIMEDOUT; + goto error; + } + + ret = tda10071_wr_reg_mask(priv, 0x47, 0x00, 0x01); + if (ret) + goto error; + + cmd.args[0x00] = CMD_LNB_SEND_DISEQC; + cmd.args[0x01] = 0; + cmd.args[0x02] = 0; + cmd.args[0x03] = 0; + cmd.args[0x04] = 2; + cmd.args[0x05] = 0; + cmd.args[0x06] = diseqc_cmd->msg_len; + memcpy(&cmd.args[0x07], diseqc_cmd->msg, diseqc_cmd->msg_len); + cmd.len = 0x07 + diseqc_cmd->msg_len; + ret = tda10071_cmd_execute(priv, &cmd); + if (ret) + goto error; + + return ret; +error: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int tda10071_diseqc_recv_slave_reply(struct dvb_frontend *fe, + struct dvb_diseqc_slave_reply *reply) +{ + struct tda10071_priv *priv = fe->demodulator_priv; + struct tda10071_cmd cmd; + int ret, i; + u8 tmp; + + if (!priv->warm) { + ret = -EFAULT; + goto error; + } + + dbg("%s:", __func__); + + /* wait LNB RX */ + for (i = 500, tmp = 0; i && !tmp; i--) { + ret = tda10071_rd_reg_mask(priv, 0x47, &tmp, 0x02); + if (ret) + goto error; + + msleep(10); + } + + dbg("%s: loop=%d", __func__, i); + + if (i == 0) { + ret = -ETIMEDOUT; + goto error; + } + + /* reply len */ + ret = tda10071_rd_reg(priv, 0x46, &tmp); + if (ret) + goto error; + + reply->msg_len = tmp & 0x1f; /* [4:0] */; + if (reply->msg_len > sizeof(reply->msg)) + reply->msg_len = sizeof(reply->msg); /* truncate API max */ + + /* read reply */ + cmd.args[0x00] = CMD_LNB_UPDATE_REPLY; + cmd.args[0x01] = 0; + cmd.len = 0x02; + ret = tda10071_cmd_execute(priv, &cmd); + if (ret) + goto error; + + ret = tda10071_rd_regs(priv, cmd.len, reply->msg, reply->msg_len); + if (ret) + goto error; + + return ret; +error: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int tda10071_diseqc_send_burst(struct dvb_frontend *fe, + fe_sec_mini_cmd_t fe_sec_mini_cmd) +{ + struct tda10071_priv *priv = fe->demodulator_priv; + struct tda10071_cmd cmd; + int ret, i; + u8 tmp, burst; + + if (!priv->warm) { + ret = -EFAULT; + goto error; + } + + dbg("%s: fe_sec_mini_cmd=%d", __func__, fe_sec_mini_cmd); + + switch (fe_sec_mini_cmd) { + case SEC_MINI_A: + burst = 0; + break; + case SEC_MINI_B: + burst = 1; + break; + default: + dbg("%s: invalid fe_sec_mini_cmd", __func__); + ret = -EINVAL; + goto error; + } + + /* wait LNB TX */ + for (i = 500, tmp = 0; i && !tmp; i--) { + ret = tda10071_rd_reg_mask(priv, 0x47, &tmp, 0x01); + if (ret) + goto error; + + msleep(10); + } + + dbg("%s: loop=%d", __func__, i); + + if (i == 0) { + ret = -ETIMEDOUT; + goto error; + } + + ret = tda10071_wr_reg_mask(priv, 0x47, 0x00, 0x01); + if (ret) + goto error; + + cmd.args[0x00] = CMD_LNB_SEND_TONEBURST; + cmd.args[0x01] = 0; + cmd.args[0x02] = burst; + cmd.len = 0x03; + ret = tda10071_cmd_execute(priv, &cmd); + if (ret) + goto error; + + return ret; +error: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int tda10071_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct tda10071_priv *priv = fe->demodulator_priv; + int ret; + u8 tmp; + + *status = 0; + + if (!priv->warm) { + ret = 0; + goto error; + } + + ret = tda10071_rd_reg(priv, 0x39, &tmp); + if (ret) + goto error; + + if (tmp & 0x01) /* tuner PLL */ + *status |= FE_HAS_SIGNAL; + if (tmp & 0x02) /* demod PLL */ + *status |= FE_HAS_CARRIER; + if (tmp & 0x04) /* viterbi or LDPC*/ + *status |= FE_HAS_VITERBI; + if (tmp & 0x08) /* RS or BCH */ + *status |= FE_HAS_SYNC | FE_HAS_LOCK; + + priv->fe_status = *status; + + return ret; +error: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int tda10071_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct tda10071_priv *priv = fe->demodulator_priv; + int ret; + u8 buf[2]; + + if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) { + *snr = 0; + ret = 0; + goto error; + } + + ret = tda10071_rd_regs(priv, 0x3a, buf, 2); + if (ret) + goto error; + + /* Es/No dBx10 */ + *snr = buf[0] << 8 | buf[1]; + + return ret; +error: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int tda10071_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct tda10071_priv *priv = fe->demodulator_priv; + struct tda10071_cmd cmd; + int ret; + u8 tmp; + + if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) { + *strength = 0; + ret = 0; + goto error; + } + + cmd.args[0x00] = CMD_GET_AGCACC; + cmd.args[0x01] = 0; + cmd.len = 0x02; + ret = tda10071_cmd_execute(priv, &cmd); + if (ret) + goto error; + + /* input power estimate dBm */ + ret = tda10071_rd_reg(priv, 0x50, &tmp); + if (ret) + goto error; + + if (tmp < 181) + tmp = 181; /* -75 dBm */ + else if (tmp > 236) + tmp = 236; /* -20 dBm */ + + /* scale value to 0x0000-0xffff */ + *strength = (tmp-181) * 0xffff / (236-181); + + return ret; +error: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int tda10071_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct tda10071_priv *priv = fe->demodulator_priv; + struct tda10071_cmd cmd; + int ret, i, len; + u8 tmp, reg, buf[8]; + + if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) { + *ber = priv->ber = 0; + ret = 0; + goto error; + } + + switch (priv->delivery_system) { + case SYS_DVBS: + reg = 0x4c; + len = 8; + i = 1; + break; + case SYS_DVBS2: + reg = 0x4d; + len = 4; + i = 0; + break; + default: + *ber = priv->ber = 0; + return 0; + } + + ret = tda10071_rd_reg(priv, reg, &tmp); + if (ret) + goto error; + + if (priv->meas_count[i] == tmp) { + dbg("%s: meas not ready=%02x", __func__, tmp); + *ber = priv->ber; + return 0; + } else { + priv->meas_count[i] = tmp; + } + + cmd.args[0x00] = CMD_BER_UPDATE_COUNTERS; + cmd.args[0x01] = 0; + cmd.args[0x02] = i; + cmd.len = 0x03; + ret = tda10071_cmd_execute(priv, &cmd); + if (ret) + goto error; + + ret = tda10071_rd_regs(priv, cmd.len, buf, len); + if (ret) + goto error; + + if (priv->delivery_system == SYS_DVBS) { + *ber = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + priv->ucb += (buf[4] << 8) | buf[5]; + } else { + *ber = (buf[0] << 8) | buf[1]; + } + priv->ber = *ber; + + return ret; +error: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int tda10071_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct tda10071_priv *priv = fe->demodulator_priv; + int ret = 0; + + if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) { + *ucblocks = 0; + goto error; + } + + /* UCB is updated when BER is read. Assume BER is read anyway. */ + + *ucblocks = priv->ucb; + + return ret; +error: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int tda10071_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct tda10071_priv *priv = fe->demodulator_priv; + struct tda10071_cmd cmd; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret, i; + u8 mode, rolloff, pilot, inversion, div; + + dbg("%s: delivery_system=%d modulation=%d frequency=%d " \ + "symbol_rate=%d inversion=%d pilot=%d rolloff=%d", __func__, + c->delivery_system, c->modulation, c->frequency, + c->symbol_rate, c->inversion, c->pilot, c->rolloff); + + priv->delivery_system = SYS_UNDEFINED; + + if (!priv->warm) { + ret = -EFAULT; + goto error; + } + + switch (c->inversion) { + case INVERSION_OFF: + inversion = 1; + break; + case INVERSION_ON: + inversion = 0; + break; + case INVERSION_AUTO: + /* 2 = auto; try first on then off + * 3 = auto; try first off then on */ + inversion = 3; + break; + default: + dbg("%s: invalid inversion", __func__); + ret = -EINVAL; + goto error; + } + + switch (c->delivery_system) { + case SYS_DVBS: + rolloff = 0; + pilot = 2; + break; + case SYS_DVBS2: + switch (c->rolloff) { + case ROLLOFF_20: + rolloff = 2; + break; + case ROLLOFF_25: + rolloff = 1; + break; + case ROLLOFF_35: + rolloff = 0; + break; + case ROLLOFF_AUTO: + default: + dbg("%s: invalid rolloff", __func__); + ret = -EINVAL; + goto error; + } + + switch (c->pilot) { + case PILOT_OFF: + pilot = 0; + break; + case PILOT_ON: + pilot = 1; + break; + case PILOT_AUTO: + pilot = 2; + break; + default: + dbg("%s: invalid pilot", __func__); + ret = -EINVAL; + goto error; + } + break; + default: + dbg("%s: invalid delivery_system", __func__); + ret = -EINVAL; + goto error; + } + + for (i = 0, mode = 0xff; i < ARRAY_SIZE(TDA10071_MODCOD); i++) { + if (c->delivery_system == TDA10071_MODCOD[i].delivery_system && + c->modulation == TDA10071_MODCOD[i].modulation && + c->fec_inner == TDA10071_MODCOD[i].fec) { + mode = TDA10071_MODCOD[i].val; + dbg("%s: mode found=%02x", __func__, mode); + break; + } + } + + if (mode == 0xff) { + dbg("%s: invalid parameter combination", __func__); + ret = -EINVAL; + goto error; + } + + if (c->symbol_rate <= 5000000) + div = 14; + else + div = 4; + + ret = tda10071_wr_reg(priv, 0x81, div); + if (ret) + goto error; + + ret = tda10071_wr_reg(priv, 0xe3, div); + if (ret) + goto error; + + cmd.args[0x00] = CMD_CHANGE_CHANNEL; + cmd.args[0x01] = 0; + cmd.args[0x02] = mode; + cmd.args[0x03] = (c->frequency >> 16) & 0xff; + cmd.args[0x04] = (c->frequency >> 8) & 0xff; + cmd.args[0x05] = (c->frequency >> 0) & 0xff; + cmd.args[0x06] = ((c->symbol_rate / 1000) >> 8) & 0xff; + cmd.args[0x07] = ((c->symbol_rate / 1000) >> 0) & 0xff; + cmd.args[0x08] = (tda10071_ops.info.frequency_tolerance >> 8) & 0xff; + cmd.args[0x09] = (tda10071_ops.info.frequency_tolerance >> 0) & 0xff; + cmd.args[0x0a] = rolloff; + cmd.args[0x0b] = inversion; + cmd.args[0x0c] = pilot; + cmd.args[0x0d] = 0x00; + cmd.args[0x0e] = 0x00; + cmd.len = 0x0f; + ret = tda10071_cmd_execute(priv, &cmd); + if (ret) + goto error; + + priv->delivery_system = c->delivery_system; + + return ret; +error: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int tda10071_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct tda10071_priv *priv = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret, i; + u8 buf[5], tmp; + + if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) { + ret = -EFAULT; + goto error; + } + + ret = tda10071_rd_regs(priv, 0x30, buf, 5); + if (ret) + goto error; + + tmp = buf[0] & 0x3f; + for (i = 0; i < ARRAY_SIZE(TDA10071_MODCOD); i++) { + if (tmp == TDA10071_MODCOD[i].val) { + c->modulation = TDA10071_MODCOD[i].modulation; + c->fec_inner = TDA10071_MODCOD[i].fec; + c->delivery_system = TDA10071_MODCOD[i].delivery_system; + } + } + + switch ((buf[1] >> 0) & 0x01) { + case 0: + c->inversion = INVERSION_OFF; + break; + case 1: + c->inversion = INVERSION_ON; + break; + } + + switch ((buf[1] >> 7) & 0x01) { + case 0: + c->pilot = PILOT_OFF; + break; + case 1: + c->pilot = PILOT_ON; + break; + } + + c->frequency = (buf[2] << 16) | (buf[3] << 8) | (buf[4] << 0); + + ret = tda10071_rd_regs(priv, 0x52, buf, 3); + if (ret) + goto error; + + c->symbol_rate = (buf[0] << 16) | (buf[1] << 8) | (buf[2] << 0); + + return ret; +error: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int tda10071_init(struct dvb_frontend *fe) +{ + struct tda10071_priv *priv = fe->demodulator_priv; + struct tda10071_cmd cmd; + int ret, i, len, remaining; + const struct firmware *fw; + u8 *fw_file = TDA10071_DEFAULT_FIRMWARE; + u8 tmp, buf[4]; + struct tda10071_reg_val_mask tab[] = { + { 0xcd, 0x00, 0x07 }, + { 0x80, 0x00, 0x02 }, + { 0xcd, 0x00, 0xc0 }, + { 0xce, 0x00, 0x1b }, + { 0x9d, 0x00, 0x01 }, + { 0x9d, 0x00, 0x02 }, + { 0x9e, 0x00, 0x01 }, + { 0x87, 0x00, 0x80 }, + { 0xce, 0x00, 0x08 }, + { 0xce, 0x00, 0x10 }, + }; + struct tda10071_reg_val_mask tab2[] = { + { 0xf1, 0x70, 0xff }, + { 0x88, priv->cfg.pll_multiplier, 0x3f }, + { 0x89, 0x00, 0x10 }, + { 0x89, 0x10, 0x10 }, + { 0xc0, 0x01, 0x01 }, + { 0xc0, 0x00, 0x01 }, + { 0xe0, 0xff, 0xff }, + { 0xe0, 0x00, 0xff }, + { 0x96, 0x1e, 0x7e }, + { 0x8b, 0x08, 0x08 }, + { 0x8b, 0x00, 0x08 }, + { 0x8f, 0x1a, 0x7e }, + { 0x8c, 0x68, 0xff }, + { 0x8d, 0x08, 0xff }, + { 0x8e, 0x4c, 0xff }, + { 0x8f, 0x01, 0x01 }, + { 0x8b, 0x04, 0x04 }, + { 0x8b, 0x00, 0x04 }, + { 0x87, 0x05, 0x07 }, + { 0x80, 0x00, 0x20 }, + { 0xc8, 0x01, 0xff }, + { 0xb4, 0x47, 0xff }, + { 0xb5, 0x9c, 0xff }, + { 0xb6, 0x7d, 0xff }, + { 0xba, 0x00, 0x03 }, + { 0xb7, 0x47, 0xff }, + { 0xb8, 0x9c, 0xff }, + { 0xb9, 0x7d, 0xff }, + { 0xba, 0x00, 0x0c }, + { 0xc8, 0x00, 0xff }, + { 0xcd, 0x00, 0x04 }, + { 0xcd, 0x00, 0x20 }, + { 0xe8, 0x02, 0xff }, + { 0xcf, 0x20, 0xff }, + { 0x9b, 0xd7, 0xff }, + { 0x9a, 0x01, 0x03 }, + { 0xa8, 0x05, 0x0f }, + { 0xa8, 0x65, 0xf0 }, + { 0xa6, 0xa0, 0xf0 }, + { 0x9d, 0x50, 0xfc }, + { 0x9e, 0x20, 0xe0 }, + { 0xa3, 0x1c, 0x7c }, + { 0xd5, 0x03, 0x03 }, + }; + + /* firmware status */ + ret = tda10071_rd_reg(priv, 0x51, &tmp); + if (ret) + goto error; + + if (!tmp) { + /* warm state - wake up device from sleep */ + priv->warm = 1; + + for (i = 0; i < ARRAY_SIZE(tab); i++) { + ret = tda10071_wr_reg_mask(priv, tab[i].reg, + tab[i].val, tab[i].mask); + if (ret) + goto error; + } + + cmd.args[0x00] = CMD_SET_SLEEP_MODE; + cmd.args[0x01] = 0; + cmd.args[0x02] = 0; + cmd.len = 0x03; + ret = tda10071_cmd_execute(priv, &cmd); + if (ret) + goto error; + } else { + /* cold state - try to download firmware */ + priv->warm = 0; + + /* request the firmware, this will block and timeout */ + ret = request_firmware(&fw, fw_file, priv->i2c->dev.parent); + if (ret) { + err("did not find the firmware file. (%s) " + "Please see linux/Documentation/dvb/ for more" \ + " details on firmware-problems. (%d)", + fw_file, ret); + goto error; + } + + /* init */ + for (i = 0; i < ARRAY_SIZE(tab2); i++) { + ret = tda10071_wr_reg_mask(priv, tab2[i].reg, + tab2[i].val, tab2[i].mask); + if (ret) + goto error_release_firmware; + } + + /* download firmware */ + ret = tda10071_wr_reg(priv, 0xe0, 0x7f); + if (ret) + goto error_release_firmware; + + ret = tda10071_wr_reg(priv, 0xf7, 0x81); + if (ret) + goto error_release_firmware; + + ret = tda10071_wr_reg(priv, 0xf8, 0x00); + if (ret) + goto error_release_firmware; + + ret = tda10071_wr_reg(priv, 0xf9, 0x00); + if (ret) + goto error_release_firmware; + + info("found a '%s' in cold state, will try to load a firmware", + tda10071_ops.info.name); + + info("downloading firmware from file '%s'", fw_file); + + for (remaining = fw->size; remaining > 0; + remaining -= (priv->cfg.i2c_wr_max - 1)) { + len = remaining; + if (len > (priv->cfg.i2c_wr_max - 1)) + len = (priv->cfg.i2c_wr_max - 1); + + ret = tda10071_wr_regs(priv, 0xfa, + (u8 *) &fw->data[fw->size - remaining], len); + if (ret) { + err("firmware download failed=%d", ret); + if (ret) + goto error_release_firmware; + } + } + release_firmware(fw); + + ret = tda10071_wr_reg(priv, 0xf7, 0x0c); + if (ret) + goto error; + + ret = tda10071_wr_reg(priv, 0xe0, 0x00); + if (ret) + goto error; + + /* wait firmware start */ + msleep(250); + + /* firmware status */ + ret = tda10071_rd_reg(priv, 0x51, &tmp); + if (ret) + goto error; + + if (tmp) { + info("firmware did not run"); + ret = -EFAULT; + goto error; + } else { + priv->warm = 1; + } + + cmd.args[0x00] = CMD_GET_FW_VERSION; + cmd.len = 0x01; + ret = tda10071_cmd_execute(priv, &cmd); + if (ret) + goto error; + + ret = tda10071_rd_regs(priv, cmd.len, buf, 4); + if (ret) + goto error; + + info("firmware version %d.%d.%d.%d", + buf[0], buf[1], buf[2], buf[3]); + info("found a '%s' in warm state.", tda10071_ops.info.name); + + ret = tda10071_rd_regs(priv, 0x81, buf, 2); + if (ret) + goto error; + + cmd.args[0x00] = CMD_DEMOD_INIT; + cmd.args[0x01] = ((priv->cfg.xtal / 1000) >> 8) & 0xff; + cmd.args[0x02] = ((priv->cfg.xtal / 1000) >> 0) & 0xff; + cmd.args[0x03] = buf[0]; + cmd.args[0x04] = buf[1]; + cmd.args[0x05] = priv->cfg.pll_multiplier; + cmd.args[0x06] = priv->cfg.spec_inv; + cmd.args[0x07] = 0x00; + cmd.len = 0x08; + ret = tda10071_cmd_execute(priv, &cmd); + if (ret) + goto error; + + cmd.args[0x00] = CMD_TUNER_INIT; + cmd.args[0x01] = 0x00; + cmd.args[0x02] = 0x00; + cmd.args[0x03] = 0x00; + cmd.args[0x04] = 0x00; + cmd.args[0x05] = 0x14; + cmd.args[0x06] = 0x00; + cmd.args[0x07] = 0x03; + cmd.args[0x08] = 0x02; + cmd.args[0x09] = 0x02; + cmd.args[0x0a] = 0x00; + cmd.args[0x0b] = 0x00; + cmd.args[0x0c] = 0x00; + cmd.args[0x0d] = 0x00; + cmd.args[0x0e] = 0x00; + cmd.len = 0x0f; + ret = tda10071_cmd_execute(priv, &cmd); + if (ret) + goto error; + + cmd.args[0x00] = CMD_MPEG_CONFIG; + cmd.args[0x01] = 0; + cmd.args[0x02] = priv->cfg.ts_mode; + cmd.args[0x03] = 0x00; + cmd.args[0x04] = 0x04; + cmd.args[0x05] = 0x00; + cmd.len = 0x06; + ret = tda10071_cmd_execute(priv, &cmd); + if (ret) + goto error; + + ret = tda10071_wr_reg_mask(priv, 0xf0, 0x01, 0x01); + if (ret) + goto error; + + cmd.args[0x00] = CMD_LNB_CONFIG; + cmd.args[0x01] = 0; + cmd.args[0x02] = 150; + cmd.args[0x03] = 3; + cmd.args[0x04] = 22; + cmd.args[0x05] = 1; + cmd.args[0x06] = 1; + cmd.args[0x07] = 30; + cmd.args[0x08] = 30; + cmd.args[0x09] = 30; + cmd.args[0x0a] = 30; + cmd.len = 0x0b; + ret = tda10071_cmd_execute(priv, &cmd); + if (ret) + goto error; + + cmd.args[0x00] = CMD_BER_CONTROL; + cmd.args[0x01] = 0; + cmd.args[0x02] = 14; + cmd.args[0x03] = 14; + cmd.len = 0x04; + ret = tda10071_cmd_execute(priv, &cmd); + if (ret) + goto error; + } + + return ret; +error_release_firmware: + release_firmware(fw); +error: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int tda10071_sleep(struct dvb_frontend *fe) +{ + struct tda10071_priv *priv = fe->demodulator_priv; + struct tda10071_cmd cmd; + int ret, i; + struct tda10071_reg_val_mask tab[] = { + { 0xcd, 0x07, 0x07 }, + { 0x80, 0x02, 0x02 }, + { 0xcd, 0xc0, 0xc0 }, + { 0xce, 0x1b, 0x1b }, + { 0x9d, 0x01, 0x01 }, + { 0x9d, 0x02, 0x02 }, + { 0x9e, 0x01, 0x01 }, + { 0x87, 0x80, 0x80 }, + { 0xce, 0x08, 0x08 }, + { 0xce, 0x10, 0x10 }, + }; + + if (!priv->warm) { + ret = -EFAULT; + goto error; + } + + cmd.args[0x00] = CMD_SET_SLEEP_MODE; + cmd.args[0x01] = 0; + cmd.args[0x02] = 1; + cmd.len = 0x03; + ret = tda10071_cmd_execute(priv, &cmd); + if (ret) + goto error; + + for (i = 0; i < ARRAY_SIZE(tab); i++) { + ret = tda10071_wr_reg_mask(priv, tab[i].reg, tab[i].val, + tab[i].mask); + if (ret) + goto error; + } + + return ret; +error: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int tda10071_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *s) +{ + s->min_delay_ms = 8000; + s->step_size = 0; + s->max_drift = 0; + + return 0; +} + +static void tda10071_release(struct dvb_frontend *fe) +{ + struct tda10071_priv *priv = fe->demodulator_priv; + kfree(priv); +} + +struct dvb_frontend *tda10071_attach(const struct tda10071_config *config, + struct i2c_adapter *i2c) +{ + int ret; + struct tda10071_priv *priv = NULL; + u8 tmp; + + /* allocate memory for the internal priv */ + priv = kzalloc(sizeof(struct tda10071_priv), GFP_KERNEL); + if (priv == NULL) { + ret = -ENOMEM; + goto error; + } + + /* setup the priv */ + priv->i2c = i2c; + memcpy(&priv->cfg, config, sizeof(struct tda10071_config)); + + /* chip ID */ + ret = tda10071_rd_reg(priv, 0xff, &tmp); + if (ret || tmp != 0x0f) + goto error; + + /* chip type */ + ret = tda10071_rd_reg(priv, 0xdd, &tmp); + if (ret || tmp != 0x00) + goto error; + + /* chip version */ + ret = tda10071_rd_reg(priv, 0xfe, &tmp); + if (ret || tmp != 0x01) + goto error; + + /* create dvb_frontend */ + memcpy(&priv->fe.ops, &tda10071_ops, sizeof(struct dvb_frontend_ops)); + priv->fe.demodulator_priv = priv; + + return &priv->fe; +error: + dbg("%s: failed=%d", __func__, ret); + kfree(priv); + return NULL; +} +EXPORT_SYMBOL(tda10071_attach); + +static struct dvb_frontend_ops tda10071_ops = { + .info = { + .name = "NXP TDA10071", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_tolerance = 5000, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | + FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | + FE_CAN_FEC_4_5 | + FE_CAN_FEC_5_6 | + FE_CAN_FEC_6_7 | + FE_CAN_FEC_7_8 | + FE_CAN_FEC_8_9 | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK | + FE_CAN_RECOVER | + FE_CAN_2G_MODULATION + }, + + .release = tda10071_release, + + .get_tune_settings = tda10071_get_tune_settings, + + .init = tda10071_init, + .sleep = tda10071_sleep, + + .set_frontend = tda10071_set_frontend, + .get_frontend = tda10071_get_frontend, + + .read_status = tda10071_read_status, + .read_snr = tda10071_read_snr, + .read_signal_strength = tda10071_read_signal_strength, + .read_ber = tda10071_read_ber, + .read_ucblocks = tda10071_read_ucblocks, + + .diseqc_send_master_cmd = tda10071_diseqc_send_master_cmd, + .diseqc_recv_slave_reply = tda10071_diseqc_recv_slave_reply, + .diseqc_send_burst = tda10071_diseqc_send_burst, + + .set_tone = tda10071_set_tone, + .set_voltage = tda10071_set_voltage, +}; + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("NXP TDA10071 DVB-S/S2 demodulator driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/tda10071.h b/drivers/media/dvb/frontends/tda10071.h new file mode 100644 index 0000000..21163c4 --- /dev/null +++ b/drivers/media/dvb/frontends/tda10071.h @@ -0,0 +1,81 @@ +/* + * NXP TDA10071 + Conexant CX24118A DVB-S/S2 demodulator + tuner driver + * + * Copyright (C) 2011 Antti Palosaari + * + * 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 of the License, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef TDA10071_H +#define TDA10071_H + +#include + +struct tda10071_config { + /* Demodulator I2C address. + * Default: none, must set + * Values: 0x55, + */ + u8 i2c_address; + + /* Max bytes I2C provider can write at once. + * Note: Buffer is taken from the stack currently! + * Default: none, must set + * Values: + */ + u16 i2c_wr_max; + + /* TS output mode. + * Default: TDA10071_TS_SERIAL + * Values: + */ +#define TDA10071_TS_SERIAL 0 +#define TDA10071_TS_PARALLEL 1 + u8 ts_mode; + + /* Input spectrum inversion. + * Default: 0 + * Values: 0, 1 + */ + bool spec_inv; + + /* Xtal frequency Hz + * Default: none, must set + * Values: + */ + u32 xtal; + + /* PLL multiplier. + * Default: none, must set + * Values: + */ + u8 pll_multiplier; +}; + + +#if defined(CONFIG_DVB_TDA10071) || \ + (defined(CONFIG_DVB_TDA10071_MODULE) && defined(MODULE)) +extern struct dvb_frontend *tda10071_attach( + const struct tda10071_config *config, struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *tda10071_attach( + const struct tda10071_config *config, struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* TDA10071_H */ diff --git a/drivers/media/dvb/frontends/tda10071_priv.h b/drivers/media/dvb/frontends/tda10071_priv.h new file mode 100644 index 0000000..93c5e63 --- /dev/null +++ b/drivers/media/dvb/frontends/tda10071_priv.h @@ -0,0 +1,122 @@ +/* + * NXP TDA10071 + Conexant CX24118A DVB-S/S2 demodulator + tuner driver + * + * Copyright (C) 2011 Antti Palosaari + * + * 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 of the License, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef TDA10071_PRIV +#define TDA10071_PRIV + +#include "dvb_frontend.h" +#include "tda10071.h" +#include + +#define LOG_PREFIX "tda10071" + +#undef dbg +#define dbg(f, arg...) \ + if (tda10071_debug) \ + printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) +#undef err +#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) +#undef info +#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) +#undef warn +#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) + +struct tda10071_priv { + struct i2c_adapter *i2c; + struct dvb_frontend fe; + struct tda10071_config cfg; + + u8 meas_count[2]; + u32 ber; + u32 ucb; + fe_status_t fe_status; + fe_delivery_system_t delivery_system; + bool warm; /* FW running */ +}; + +static struct tda10071_modcod { + fe_delivery_system_t delivery_system; + fe_modulation_t modulation; + fe_code_rate_t fec; + u8 val; +} TDA10071_MODCOD[] = { + /* NBC-QPSK */ + { SYS_DVBS2, QPSK, FEC_AUTO, 0x00 }, + { SYS_DVBS2, QPSK, FEC_1_2, 0x04 }, + { SYS_DVBS2, QPSK, FEC_3_5, 0x05 }, + { SYS_DVBS2, QPSK, FEC_2_3, 0x06 }, + { SYS_DVBS2, QPSK, FEC_3_4, 0x07 }, + { SYS_DVBS2, QPSK, FEC_4_5, 0x08 }, + { SYS_DVBS2, QPSK, FEC_5_6, 0x09 }, + { SYS_DVBS2, QPSK, FEC_8_9, 0x0a }, + { SYS_DVBS2, QPSK, FEC_9_10, 0x0b }, + /* 8PSK */ + { SYS_DVBS2, PSK_8, FEC_3_5, 0x0c }, + { SYS_DVBS2, PSK_8, FEC_2_3, 0x0d }, + { SYS_DVBS2, PSK_8, FEC_3_4, 0x0e }, + { SYS_DVBS2, PSK_8, FEC_5_6, 0x0f }, + { SYS_DVBS2, PSK_8, FEC_8_9, 0x10 }, + { SYS_DVBS2, PSK_8, FEC_9_10, 0x11 }, + /* QPSK */ + { SYS_DVBS, QPSK, FEC_AUTO, 0x2d }, + { SYS_DVBS, QPSK, FEC_1_2, 0x2e }, + { SYS_DVBS, QPSK, FEC_2_3, 0x2f }, + { SYS_DVBS, QPSK, FEC_3_4, 0x30 }, + { SYS_DVBS, QPSK, FEC_5_6, 0x31 }, + { SYS_DVBS, QPSK, FEC_7_8, 0x32 }, +}; + +struct tda10071_reg_val_mask { + u8 reg; + u8 val; + u8 mask; +}; + +/* firmware filename */ +#define TDA10071_DEFAULT_FIRMWARE "dvb-fe-tda10071.fw" + +/* firmware commands */ +#define CMD_DEMOD_INIT 0x10 +#define CMD_CHANGE_CHANNEL 0x11 +#define CMD_MPEG_CONFIG 0x13 +#define CMD_TUNER_INIT 0x15 +#define CMD_GET_AGCACC 0x1a + +#define CMD_LNB_CONFIG 0x20 +#define CMD_LNB_SEND_DISEQC 0x21 +#define CMD_LNB_SET_DC_LEVEL 0x22 +#define CMD_LNB_PCB_CONFIG 0x23 +#define CMD_LNB_SEND_TONEBURST 0x24 +#define CMD_LNB_UPDATE_REPLY 0x25 + +#define CMD_GET_FW_VERSION 0x35 +#define CMD_SET_SLEEP_MODE 0x36 +#define CMD_BER_CONTROL 0x3e +#define CMD_BER_UPDATE_COUNTERS 0x3f + +/* firmare command struct */ +#define TDA10071_ARGLEN 0x1e +struct tda10071_cmd { + u8 args[TDA10071_ARGLEN]; + u8 len; +}; + + +#endif /* TDA10071_PRIV */ -- cgit v0.10.2 From 36588715fc0ed3ff0ffb025dc841652cb3b2b667 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 1 Aug 2011 01:15:30 -0300 Subject: [media] em28xx: add support for PCTV DVB-S2 Stick 460e [2013:024f] It is based of... * Empia EM28174 * NXP TDA10071 & Conexant CX24118A combo * Allegro A8293 Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig index 281ee42..f6f622e 100644 --- a/drivers/media/video/em28xx/Kconfig +++ b/drivers/media/video/em28xx/Kconfig @@ -41,6 +41,8 @@ config VIDEO_EM28XX_DVB select DVB_CXD2820R if !DVB_FE_CUSTOMISE select DVB_DRXK if !DVB_FE_CUSTOMISE select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE + select DVB_TDA10071 if !DVB_FE_CUSTOMISE + select DVB_A8293 if !DVB_FE_CUSTOMISE select VIDEOBUF_DVB ---help--- This adds support for DVB cards based on the diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 013e946..8845ff8 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -317,6 +317,25 @@ static struct em28xx_reg_seq terratec_h5_digital[] = { }; #endif +/* 2013:024f PCTV DVB-S2 Stick 460e + * GPIO_0 - POWER_ON + * GPIO_1 - BOOST + * GPIO_2 - VUV_LNB (red LED) + * GPIO_3 - EXT_12V + * GPIO_4 - INT_DEM (DEMOD GPIO_0) + * GPIO_5 - INT_LNB + * GPIO_6 - RESET_DEM + * GPIO_7 - LED (green LED) + */ +static struct em28xx_reg_seq pctv_460e[] = { + {EM2874_R80_GPIO, 0x01, 0xff, 50}, + {0x0d, 0xff, 0xff, 50}, + {EM2874_R80_GPIO, 0x41, 0xff, 50}, /* GPIO_6=1 */ + {0x0d, 0x42, 0xff, 50}, + {EM2874_R80_GPIO, 0x61, 0xff, 50}, /* GPIO_5=1 */ + { -1, -1, -1, -1}, +}; + /* * Board definitions */ @@ -1810,6 +1829,17 @@ struct em28xx_board em28xx_boards[] = { .has_dvb = 1, .ir_codes = RC_MAP_PINNACLE_PCTV_HD, }, + /* 2013:024f PCTV DVB-S2 Stick 460e + * Empia EM28174, NXP TDA10071, Conexant CX24118A and Allegro A8293 */ + [EM28174_BOARD_PCTV_460E] = { + .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | + EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, + .name = "PCTV DVB-S2 Stick (460e)", + .tuner_type = TUNER_ABSENT, + .tuner_gpio = pctv_460e, + .has_dvb = 1, + .ir_codes = RC_MAP_PINNACLE_PCTV_HD, + }, }; const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); @@ -1941,6 +1971,8 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2870_BOARD_KWORLD_A340 }, { USB_DEVICE(0x2013, 0x024f), .driver_info = EM28174_BOARD_PCTV_290E }, + { USB_DEVICE(0x2013, 0x024c), + .driver_info = EM28174_BOARD_PCTV_460E }, { }, }; MODULE_DEVICE_TABLE(usb, em28xx_id_table); diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index 62b558d..cef7a2d 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c @@ -42,6 +42,8 @@ #include "cxd2820r.h" #include "tda18271c2dd.h" #include "drxk.h" +#include "tda10071.h" +#include "a8293.h" MODULE_DESCRIPTION("driver for em28xx based DVB cards"); MODULE_AUTHOR("Mauro Carvalho Chehab "); @@ -441,6 +443,19 @@ static struct tda18271_config em28xx_cxd2820r_tda18271_config = { .gate = TDA18271_GATE_DIGITAL, }; +static const struct tda10071_config em28xx_tda10071_config = { + .i2c_address = 0x55, /* (0xaa >> 1) */ + .i2c_wr_max = 64, + .ts_mode = TDA10071_TS_SERIAL, + .spec_inv = 0, + .xtal = 40444000, /* 40.444 MHz */ + .pll_multiplier = 20, +}; + +static const struct a8293_config em28xx_a8293_config = { + .i2c_addr = 0x08, /* (0x10 >> 1) */ +}; + /* ------------------------------------------------------------------ */ static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev) @@ -808,6 +823,16 @@ static int em28xx_dvb_init(struct em28xx *dev) sizeof(dvb->fe[0]->ops.tuner_ops)); break; + case EM28174_BOARD_PCTV_460E: + /* attach demod */ + dvb->fe[0] = dvb_attach(tda10071_attach, + &em28xx_tda10071_config, &dev->i2c_adap); + + /* attach SEC */ + if (dvb->fe[0]) + dvb_attach(a8293_attach, dvb->fe[0], &dev->i2c_adap, + &em28xx_a8293_config); + break; default: em28xx_errdev("/2: The frontend of your DVB/ATSC card" " isn't supported yet\n"); diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index d80658b..1626e4a 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -120,6 +120,7 @@ #define EM2874_BOARD_LEADERSHIP_ISDBT 77 #define EM28174_BOARD_PCTV_290E 78 #define EM2884_BOARD_TERRATEC_H5 79 +#define EM28174_BOARD_PCTV_460E 80 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 -- cgit v0.10.2 From 1251312a5cabd2416fd4df61941fa15ad85b0225 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 8 Sep 2011 04:12:57 -0300 Subject: [media] mxl111sf: use adap->num_frontends_initialized to determine which frontend is being attached Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.c b/drivers/media/dvb/dvb-usb/mxl111sf.c index 0c3f69a..546ba59 100644 --- a/drivers/media/dvb/dvb-usb/mxl111sf.c +++ b/drivers/media/dvb/dvb-usb/mxl111sf.c @@ -379,7 +379,8 @@ static int mxl111sf_lgdt3305_frontend_attach(struct dvb_usb_adapter *adap) { struct dvb_usb_device *d = adap->dev; struct mxl111sf_state *state = d->priv; - struct mxl111sf_adap_state *adap_state = adap->fe_adap[0].priv; + int fe_id = adap->num_frontends_initialized; + struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv; int ret; deb_adv("%s()\n", __func__); @@ -422,14 +423,14 @@ static int mxl111sf_lgdt3305_frontend_attach(struct dvb_usb_adapter *adap) if (mxl_fail(ret)) goto fail; - adap->fe_adap[0].fe = dvb_attach(lgdt3305_attach, + adap->fe_adap[fe_id].fe = dvb_attach(lgdt3305_attach, &hauppauge_lgdt3305_config, &adap->dev->i2c_adap); - if (adap->fe_adap[0].fe) { - adap_state->fe_init = adap->fe_adap[0].fe->ops.init; - adap->fe_adap[0].fe->ops.init = mxl111sf_adap_fe_init; - adap_state->fe_sleep = adap->fe_adap[0].fe->ops.sleep; - adap->fe_adap[0].fe->ops.sleep = mxl111sf_adap_fe_sleep; + if (adap->fe_adap[fe_id].fe) { + adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init; + adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init; + adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep; + adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep; return 0; } ret = -EIO; @@ -514,10 +515,12 @@ static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap) { struct dvb_usb_device *d = adap->dev; struct mxl111sf_state *state = d->priv; + int fe_id = adap->num_frontends_initialized; deb_adv("%s()\n", __func__); - if (NULL != dvb_attach(mxl111sf_tuner_attach, adap->fe_adap[0].fe, state, + if (NULL != dvb_attach(mxl111sf_tuner_attach, + adap->fe_adap[fe_id].fe, state, &mxl_tuner_config)) return 0; -- cgit v0.10.2 From e3e59b085e1fc5fff9143be157218782d1f75d5c Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 11 Sep 2011 19:47:49 -0300 Subject: [media] dib0700: fix WARNING: please, no spaces at the start of a line Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 3ed6203..b256bcf 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -892,12 +892,12 @@ static int stk7700p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) static int stk70x0p_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) { - return dib7000p_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff); + return dib7000p_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff); } static int stk70x0p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) { - return dib7000p_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff); + return dib7000p_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff); } static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = { -- cgit v0.10.2 From 6e1ce98df1029701d8133a09e52134cfc15f86d9 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 13 Sep 2011 01:08:44 -0300 Subject: [media] dib0700: fix WARNING: suspect code indent for conditional statements Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index b256bcf..ef5c078 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -847,7 +847,7 @@ static int dib7770p_tuner_attach(struct dvb_usb_adapter *adap) DIBX000_I2C_INTERFACE_TUNER, 1); if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, - &dib7770p_dib0070_config) == NULL) + &dib7770p_dib0070_config) == NULL) return -ENODEV; st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; -- cgit v0.10.2 From 9a9677afed9a4009f1201a23765a23e49ef8b95f Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 13 Sep 2011 01:32:11 -0300 Subject: [media] dib0700: fix ERROR: space required before that '&' Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index ef5c078..5cdbe64 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -125,8 +125,9 @@ static int bristol_tuner_attach(struct dvb_usb_adapter *adap) adap->dev->udev->descriptor.idProduct == cpu_to_le16(USB_PID_HAUPPAUGE_NOVA_T_500_2)) { if (!eeprom_read(prim_i2c,0x59 + adap->id,&a)) if1=1220+a; } - return dvb_attach(mt2060_attach,adap->fe_adap[0].fe, tun_i2c,&bristol_mt2060_config[adap->id], - if1) == NULL ? -ENODEV : 0; + return dvb_attach(mt2060_attach, adap->fe_adap[0].fe, tun_i2c, + &bristol_mt2060_config[adap->id], if1) == NULL ? + -ENODEV : 0; } /* STK7700D: Pinnacle/Terratec/Hauppauge Dual DVB-T Diversity */ -- cgit v0.10.2 From 2a776313332c98bdc61485d79aa6f3592f03793a Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 16 Sep 2011 09:26:59 -0300 Subject: [media] dib0700: fix ERROR: space required after that ',' Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 5cdbe64..f313182 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -280,8 +280,10 @@ static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap) } } - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1), - &stk7700d_dib7000p_mt2266_config[adap->id]); + adap->fe_adap[0].fe = + dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, + 0x80 + (adap->id << 1), + &stk7700d_dib7000p_mt2266_config[adap->id]); return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } @@ -307,8 +309,10 @@ static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap) } } - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1), - &stk7700d_dib7000p_mt2266_config[adap->id]); + adap->fe_adap[0].fe = + dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, + 0x80 + (adap->id << 1), + &stk7700d_dib7000p_mt2266_config[adap->id]); return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } -- cgit v0.10.2 From b6bd5de2b1fffb1e103118aa558de91b1cef244e Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 16 Sep 2011 09:32:00 -0300 Subject: [media] dibusb-common: fix ERROR: space required after that ',' Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c index 735e914..109a460 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-common.c +++ b/drivers/media/dvb/dvb-usb/dibusb-common.c @@ -23,7 +23,7 @@ int dibusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) if (adap->priv != NULL) { struct dibusb_state *st = adap->priv; if (st->ops.fifo_ctrl != NULL) - if (st->ops.fifo_ctrl(adap->fe_adap[0].fe,onoff)) { + if (st->ops.fifo_ctrl(adap->fe_adap[0].fe, onoff)) { err("error while controlling the fifo of the demod."); return -ENODEV; } @@ -37,7 +37,8 @@ int dibusb_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onof if (adap->priv != NULL) { struct dibusb_state *st = adap->priv; if (st->ops.pid_ctrl != NULL) - st->ops.pid_ctrl(adap->fe_adap[0].fe,index,pid,onoff); + st->ops.pid_ctrl(adap->fe_adap[0].fe, + index, pid, onoff); } return 0; } @@ -48,7 +49,7 @@ int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) if (adap->priv != NULL) { struct dibusb_state *st = adap->priv; if (st->ops.pid_parse != NULL) - if (st->ops.pid_parse(adap->fe_adap[0].fe,onoff) < 0) + if (st->ops.pid_parse(adap->fe_adap[0].fe, onoff) < 0) err("could not handle pid_parser"); } return 0; -- cgit v0.10.2 From 4594303b870588bad3a9ee4d6a28e73f7012b6b3 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 16 Sep 2011 09:35:06 -0300 Subject: [media] dibusb-mb: fix ERROR: space required after that ',' Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c index f13b3a3..c65bfbf 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mb.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c @@ -79,7 +79,7 @@ static int dibusb_tuner_probe_and_attach(struct dvb_usb_adapter *adap) msg[0].addr = msg[1].addr = st->tuner_addr = 0x60; if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl) - adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe,1); + adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 1); if (i2c_transfer(&adap->dev->i2c_adap, msg, 2) != 2) { err("tuner i2c write failed."); @@ -87,7 +87,7 @@ static int dibusb_tuner_probe_and_attach(struct dvb_usb_adapter *adap) } if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl) - adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe,0); + adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 0); if (b2[0] == 0xfe) { info("This device has the Thomson Cable onboard. Which is default."); -- cgit v0.10.2 From 1645c879ff688f776371a2478e1948fdf5e0f7fe Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 16 Sep 2011 09:36:56 -0300 Subject: [media] ttusb2: fix ERROR: space required after that ',' Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c index 130d296..7b07cf6 100644 --- a/drivers/media/dvb/dvb-usb/ttusb2.c +++ b/drivers/media/dvb/dvb-usb/ttusb2.c @@ -472,7 +472,7 @@ static struct dvb_usb_device_properties ttusb2_properties_ct3650 = { } } } - },{ + }, { .streaming_ctrl = NULL, .frontend_attach = ttusb2_frontend_tda10023_attach, -- cgit v0.10.2 From 2b7a7c30e3e9802f13960d096cd6198bb6f4a8c9 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 16 Sep 2011 09:40:32 -0300 Subject: [media] dvb-usb-dvb: ERROR: space required after that ',' Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c index 038679b..ba4a751 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c @@ -41,9 +41,10 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) adap->feedcount = newfeedcount; /* activate the pid on the device specific pid_filter */ - deb_ts("setting pid (%s): %5d %04x at index %d '%s'\n",adap->fe_adap[adap->active_fe].pid_filtering ? - "yes" : "no", dvbdmxfeed->pid,dvbdmxfeed->pid,dvbdmxfeed->index,onoff ? - "on" : "off"); + deb_ts("setting pid (%s): %5d %04x at index %d '%s'\n", + adap->fe_adap[adap->active_fe].pid_filtering ? + "yes" : "no", dvbdmxfeed->pid, dvbdmxfeed->pid, + dvbdmxfeed->index, onoff ? "on" : "off"); if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER && adap->fe_adap[adap->active_fe].pid_filtering && adap->props.fe[adap->active_fe].pid_filter != NULL) -- cgit v0.10.2 From 310df3662e07e38b054334462bbee71356a9b0a5 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 17 Sep 2011 14:22:59 -0300 Subject: [media] cxusb: fix ERROR: do not use assignment in if condition Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 7f610da..9f2a02c 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -837,8 +837,9 @@ static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap) cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, &b, 1); - if ((adap->fe_adap[0].fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config, - &adap->dev->i2c_adap)) != NULL) + adap->fe_adap[0].fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config, + &adap->dev->i2c_adap); + if ((adap->fe_adap[0].fe) != NULL) return 0; return -EIO; @@ -851,8 +852,10 @@ static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - if ((adap->fe_adap[0].fe = dvb_attach(lgdt330x_attach, &cxusb_lgdt3303_config, - &adap->dev->i2c_adap)) != NULL) + adap->fe_adap[0].fe = dvb_attach(lgdt330x_attach, + &cxusb_lgdt3303_config, + &adap->dev->i2c_adap); + if ((adap->fe_adap[0].fe) != NULL) return 0; return -EIO; @@ -876,8 +879,9 @@ static int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap) cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - if ((adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_mt352_config, - &adap->dev->i2c_adap)) != NULL) + adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_mt352_config, + &adap->dev->i2c_adap); + if ((adap->fe_adap[0].fe) != NULL) return 0; return -EIO; @@ -890,11 +894,15 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap) cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - if (((adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_dee1601_config, - &adap->dev->i2c_adap)) != NULL) || - ((adap->fe_adap[0].fe = dvb_attach(zl10353_attach, - &cxusb_zl10353_dee1601_config, - &adap->dev->i2c_adap)) != NULL)) + adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_dee1601_config, + &adap->dev->i2c_adap); + if ((adap->fe_adap[0].fe) != NULL) + return 0; + + adap->fe_adap[0].fe = dvb_attach(zl10353_attach, + &cxusb_zl10353_dee1601_config, + &adap->dev->i2c_adap); + if ((adap->fe_adap[0].fe) != NULL) return 0; return -EIO; @@ -917,9 +925,11 @@ static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap) cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1); cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); - if ((adap->fe_adap[0].fe = dvb_attach(zl10353_attach, - &cxusb_zl10353_xc3028_config_no_i2c_gate, - &adap->dev->i2c_adap)) == NULL) + adap->fe_adap[0].fe = + dvb_attach(zl10353_attach, + &cxusb_zl10353_xc3028_config_no_i2c_gate, + &adap->dev->i2c_adap); + if ((adap->fe_adap[0].fe) == NULL) return -EIO; /* try to determine if there is no IR decoder on the I2C bus */ @@ -1108,14 +1118,16 @@ static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap) cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1); cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); - if ((adap->fe_adap[0].fe = dvb_attach(zl10353_attach, - &cxusb_zl10353_xc3028_config, - &adap->dev->i2c_adap)) != NULL) + adap->fe_adap[0].fe = dvb_attach(zl10353_attach, + &cxusb_zl10353_xc3028_config, + &adap->dev->i2c_adap); + if ((adap->fe_adap[0].fe) != NULL) return 0; - if ((adap->fe_adap[0].fe = dvb_attach(mt352_attach, - &cxusb_mt352_xc3028_config, - &adap->dev->i2c_adap)) != NULL) + adap->fe_adap[0].fe = dvb_attach(mt352_attach, + &cxusb_mt352_xc3028_config, + &adap->dev->i2c_adap); + if ((adap->fe_adap[0].fe) != NULL) return 0; return -EIO; -- cgit v0.10.2 From d9abcd743ecbaaf3044d22070245d48814e81771 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 17 Sep 2011 14:34:56 -0300 Subject: [media] dibusb-common: fix ERROR: do not use assignment in if condition Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c index 109a460..a76bbb2 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-common.c +++ b/drivers/media/dvb/dvb-usb/dibusb-common.c @@ -255,8 +255,16 @@ int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap) msleep(1000); } - if ((adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000P_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL || - (adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000MC_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL) { + adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach, + &adap->dev->i2c_adap, + DEFAULT_DIB3000P_I2C_ADDRESS, + &mod3000p_dib3000p_config); + if ((adap->fe_adap[0].fe) == NULL) + adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach, + &adap->dev->i2c_adap, + DEFAULT_DIB3000MC_I2C_ADDRESS, + &mod3000p_dib3000p_config); + if ((adap->fe_adap[0].fe) != NULL) { if (adap->priv != NULL) { struct dibusb_state *st = adap->priv; st->ops.pid_parse = dib3000mc_pid_parse; -- cgit v0.10.2 From d4dd5ce7cae4210539b0a0a11d17ac5912e6496f Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 17 Sep 2011 14:38:50 -0300 Subject: [media] dibusb-mb: fix ERROR: do not use assignment in if condition Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c index c65bfbf..7270791 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mb.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c @@ -31,8 +31,9 @@ static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap) demod_cfg.demod_address = 0x8; - if ((adap->fe_adap[0].fe = dvb_attach(dib3000mb_attach, &demod_cfg, - &adap->dev->i2c_adap, &st->ops)) == NULL) + adap->fe_adap[0].fe = dvb_attach(dib3000mb_attach, &demod_cfg, + &adap->dev->i2c_adap, &st->ops); + if ((adap->fe_adap[0].fe) == NULL) return -ENODEV; adap->fe_adap[0].fe->ops.i2c_gate_ctrl = dib3000mb_i2c_gate_ctrl; -- cgit v0.10.2 From 331423c46df9df000586c08223be95a34a881cc0 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 17 Sep 2011 14:55:47 -0300 Subject: [media] digitv: fix ERROR: do not use assignment in if condition Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c index edabdae..f718411 100644 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -137,11 +137,16 @@ static int digitv_frontend_attach(struct dvb_usb_adapter *adap) { struct digitv_state *st = adap->dev->priv; - if ((adap->fe_adap[0].fe = dvb_attach(mt352_attach, &digitv_mt352_config, &adap->dev->i2c_adap)) != NULL) { + adap->fe_adap[0].fe = dvb_attach(mt352_attach, &digitv_mt352_config, + &adap->dev->i2c_adap); + if ((adap->fe_adap[0].fe) != NULL) { st->is_nxt6000 = 0; return 0; } - if ((adap->fe_adap[0].fe = dvb_attach(nxt6000_attach, &digitv_nxt6000_config, &adap->dev->i2c_adap)) != NULL) { + adap->fe_adap[0].fe = dvb_attach(nxt6000_attach, + &digitv_nxt6000_config, + &adap->dev->i2c_adap); + if ((adap->fe_adap[0].fe) != NULL) { st->is_nxt6000 = 1; return 0; } -- cgit v0.10.2 From d12f51aa7bd43667078d021ba89e6ed8bfe42432 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 17 Sep 2011 14:59:54 -0300 Subject: [media] m920x: fix ERROR: do not use assignment in if condition Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c index c3e461e..a1e1287 100644 --- a/drivers/media/dvb/dvb-usb/m920x.c +++ b/drivers/media/dvb/dvb-usb/m920x.c @@ -501,9 +501,10 @@ static int m920x_mt352_frontend_attach(struct dvb_usb_adapter *adap) { deb("%s\n",__func__); - if ((adap->fe_adap[0].fe = dvb_attach(mt352_attach, - &m920x_mt352_config, - &adap->dev->i2c_adap)) == NULL) + adap->fe_adap[0].fe = dvb_attach(mt352_attach, + &m920x_mt352_config, + &adap->dev->i2c_adap); + if ((adap->fe_adap[0].fe) == NULL) return -EIO; return 0; @@ -513,9 +514,10 @@ static int m920x_tda10046_08_frontend_attach(struct dvb_usb_adapter *adap) { deb("%s\n",__func__); - if ((adap->fe_adap[0].fe = dvb_attach(tda10046_attach, - &m920x_tda10046_08_config, - &adap->dev->i2c_adap)) == NULL) + adap->fe_adap[0].fe = dvb_attach(tda10046_attach, + &m920x_tda10046_08_config, + &adap->dev->i2c_adap); + if ((adap->fe_adap[0].fe) == NULL) return -EIO; return 0; @@ -525,9 +527,10 @@ static int m920x_tda10046_0b_frontend_attach(struct dvb_usb_adapter *adap) { deb("%s\n",__func__); - if ((adap->fe_adap[0].fe = dvb_attach(tda10046_attach, - &m920x_tda10046_0b_config, - &adap->dev->i2c_adap)) == NULL) + adap->fe_adap[0].fe = dvb_attach(tda10046_attach, + &m920x_tda10046_0b_config, + &adap->dev->i2c_adap); + if ((adap->fe_adap[0].fe) == NULL) return -EIO; return 0; -- cgit v0.10.2 From ee03a6795e6a303e498e1c87e1e5d3702258e329 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 17 Sep 2011 15:03:26 -0300 Subject: [media] opera1: fix ERROR: do not use assignment in if condition Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c index b6e12f9..98fd9a6 100644 --- a/drivers/media/dvb/dvb-usb/opera1.c +++ b/drivers/media/dvb/dvb-usb/opera1.c @@ -263,9 +263,9 @@ static struct stv0299_config opera1_stv0299_config = { static int opera1_frontend_attach(struct dvb_usb_adapter *d) { - if ((d->fe_adap[0].fe = - dvb_attach(stv0299_attach, &opera1_stv0299_config, - &d->dev->i2c_adap)) != NULL) { + d->fe_adap[0].fe = dvb_attach(stv0299_attach, &opera1_stv0299_config, + &d->dev->i2c_adap); + if ((d->fe_adap[0].fe) != NULL) { d->fe_adap[0].fe->ops.set_voltage = opera1_set_voltage; return 0; } -- cgit v0.10.2 From 465301b10f592bf902650b8d70df8fe10f9d3769 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 1 Aug 2011 23:34:58 -0300 Subject: [media] get_dvb_firmware: add dvb-fe-tda10071.fw TDA10071 firmware version 1.21.31.2 Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware index 65ebe20..f1b27e2 100755 --- a/Documentation/dvb/get_dvb_firmware +++ b/Documentation/dvb/get_dvb_firmware @@ -27,7 +27,7 @@ use IO::Handle; "or51211", "or51132_qam", "or51132_vsb", "bluebird", "opera1", "cx231xx", "cx18", "cx23885", "pvrusb2", "mpc718", "af9015", "ngene", "az6027", "lme2510_lg", "lme2510c_s7395", - "lme2510c_s7395_old", "drxk", "drxk_terratec_h5", + "lme2510c_s7395_old", "drxk", "drxk_terratec_h5", "tda10071", "it9135" ); # Check args @@ -684,7 +684,22 @@ sub it9135 { "$fwfile" } +sub tda10071 { + my $sourcefile = "PCTV%2070e%2080e%20100e%20320e%20330e%20800e%20880e.zip"; + my $url = "ftp://ftp.pctvsystems.com/TV/driver/PCTV%2070e%2080e%20100e%20320e%20330e%20800e/"; + my $hash = "4403de903bf2593464c8d74bbc200a57"; + my $fwfile = "dvb-fe-tda10071.fw"; + my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1); + + checkstandard(); + wgetfile($sourcefile, $url . $sourcefile); + verify($sourcefile, $hash); + unzip($sourcefile, $tmpdir); + extract("$tmpdir/PCTV\ 70e\ 80e\ 100e\ 320e\ 330e\ 800e/32\ bit/emOEM.sys", 0x67d38, 40504, $fwfile); + + "$fwfile"; +} # --------------------------------------------------------------- # Utilities -- cgit v0.10.2 From ead20951fbf3e256c7abee300e28caecab27b1f7 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 2 Aug 2011 11:35:06 -0300 Subject: [media] get_dvb_firmware: update tda10071 file url Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware index f1b27e2..06ec384 100755 --- a/Documentation/dvb/get_dvb_firmware +++ b/Documentation/dvb/get_dvb_firmware @@ -685,7 +685,7 @@ sub it9135 { } sub tda10071 { - my $sourcefile = "PCTV%2070e%2080e%20100e%20320e%20330e%20800e%20880e.zip"; + my $sourcefile = "PCTV_460e_reference.zip"; my $url = "ftp://ftp.pctvsystems.com/TV/driver/PCTV%2070e%2080e%20100e%20320e%20330e%20800e/"; my $hash = "4403de903bf2593464c8d74bbc200a57"; my $fwfile = "dvb-fe-tda10071.fw"; -- cgit v0.10.2 From f6c226b550292e8b3ae3426868957e63e77b506b Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Tue, 13 Sep 2011 06:23:39 -0300 Subject: [media] em28xx: ERROR: "em28xx_add_into_devlist" [drivers/media/video/em28xx/em28xx.ko] undefined! Signed-off-by: Chris Rankin Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 8845ff8..4bdf2d0 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -2917,7 +2917,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, retval = em28xx_audio_setup(dev); if (retval) return -ENODEV; - em28xx_add_into_devlist(dev); em28xx_init_extension(dev); return 0; -- cgit v0.10.2 From 75d404ec041ef0e036e3100f730391f6e0818019 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 13 Sep 2011 07:30:11 -0300 Subject: [media] tda10071: do not download last byte of fw Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/frontends/tda10071.c b/drivers/media/dvb/frontends/tda10071.c index 26b52cc..352ddc6 100644 --- a/drivers/media/dvb/frontends/tda10071.c +++ b/drivers/media/dvb/frontends/tda10071.c @@ -839,7 +839,7 @@ static int tda10071_init(struct dvb_frontend *fe) { struct tda10071_priv *priv = fe->demodulator_priv; struct tda10071_cmd cmd; - int ret, i, len, remaining; + int ret, i, len, remaining, fw_size; const struct firmware *fw; u8 *fw_file = TDA10071_DEFAULT_FIRMWARE; u8 tmp, buf[4]; @@ -968,14 +968,17 @@ static int tda10071_init(struct dvb_frontend *fe) info("downloading firmware from file '%s'", fw_file); - for (remaining = fw->size; remaining > 0; + /* do not download last byte */ + fw_size = fw->size - 1; + + for (remaining = fw_size; remaining > 0; remaining -= (priv->cfg.i2c_wr_max - 1)) { len = remaining; if (len > (priv->cfg.i2c_wr_max - 1)) len = (priv->cfg.i2c_wr_max - 1); ret = tda10071_wr_regs(priv, 0xfa, - (u8 *) &fw->data[fw->size - remaining], len); + (u8 *) &fw->data[fw_size - remaining], len); if (ret) { err("firmware download failed=%d", ret); if (ret) -- cgit v0.10.2 From d102b739f3a352425fcdb39afbf898f8bdbd2bc3 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 13 Sep 2011 11:51:23 -0300 Subject: [media] tda10071: change sleeps to more suitable ones msleep() => usleep_range() Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/frontends/tda10071.c b/drivers/media/dvb/frontends/tda10071.c index 352ddc6..0c37434 100644 --- a/drivers/media/dvb/frontends/tda10071.c +++ b/drivers/media/dvb/frontends/tda10071.c @@ -167,7 +167,7 @@ static int tda10071_cmd_execute(struct tda10071_priv *priv, if (ret) goto error; - msleep(1); + usleep_range(200, 5000); } dbg("%s: loop=%d", __func__, i); @@ -298,7 +298,7 @@ static int tda10071_diseqc_send_master_cmd(struct dvb_frontend *fe, if (ret) goto error; - msleep(10); + usleep_range(10000, 20000); } dbg("%s: loop=%d", __func__, i); @@ -352,7 +352,7 @@ static int tda10071_diseqc_recv_slave_reply(struct dvb_frontend *fe, if (ret) goto error; - msleep(10); + usleep_range(10000, 20000); } dbg("%s: loop=%d", __func__, i); @@ -423,7 +423,7 @@ static int tda10071_diseqc_send_burst(struct dvb_frontend *fe, if (ret) goto error; - msleep(10); + usleep_range(10000, 20000); } dbg("%s: loop=%d", __func__, i); -- cgit v0.10.2 From 9637433cf82e484d76d40c2fca9d0a1307ed08c7 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 13 Sep 2011 11:55:18 -0300 Subject: [media] get_dvb_firmware: whitespace fix it9135 was the only one intended with spaces as others are tabs. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware index 06ec384..996f578 100755 --- a/Documentation/dvb/get_dvb_firmware +++ b/Documentation/dvb/get_dvb_firmware @@ -28,7 +28,7 @@ use IO::Handle; "opera1", "cx231xx", "cx18", "cx23885", "pvrusb2", "mpc718", "af9015", "ngene", "az6027", "lme2510_lg", "lme2510c_s7395", "lme2510c_s7395_old", "drxk", "drxk_terratec_h5", "tda10071", - "it9135" ); + "it9135" ); # Check args syntax() if (scalar(@ARGV) != 1); -- cgit v0.10.2 From de2fb698c6fb1e968a5ed9cc449024f119ad3853 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Fri, 9 Sep 2011 15:35:20 -0300 Subject: [media] saa7164: Adding support for HVR2200 card id 0x8953 Thanks to Greg Tangey for prompting me to merge this. Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/saa7164/saa7164-cards.c b/drivers/media/video/saa7164/saa7164-cards.c index c713691..971591d 100644 --- a/drivers/media/video/saa7164/saa7164-cards.c +++ b/drivers/media/video/saa7164/saa7164-cards.c @@ -447,6 +447,62 @@ struct saa7164_board saa7164_boards[] = { .i2c_reg_len = REGLEN_8bit, } }, }, + [SAA7164_BOARD_HAUPPAUGE_HVR2200_5] = { + .name = "Hauppauge WinTV-HVR2200", + .porta = SAA7164_MPEG_DVB, + .portb = SAA7164_MPEG_DVB, + .chiprev = SAA7164_CHIP_REV3, + .unit = {{ + .id = 0x23, + .type = SAA7164_UNIT_EEPROM, + .name = "4K EEPROM", + .i2c_bus_nr = SAA7164_I2C_BUS_0, + .i2c_bus_addr = 0xa0 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x04, + .type = SAA7164_UNIT_TUNER, + .name = "TDA18271-1", + .i2c_bus_nr = SAA7164_I2C_BUS_1, + .i2c_bus_addr = 0xc0 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x05, + .type = SAA7164_UNIT_ANALOG_DEMODULATOR, + .name = "TDA8290-1", + .i2c_bus_nr = SAA7164_I2C_BUS_1, + .i2c_bus_addr = 0x84 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x21, + .type = SAA7164_UNIT_TUNER, + .name = "TDA18271-2", + .i2c_bus_nr = SAA7164_I2C_BUS_2, + .i2c_bus_addr = 0xc0 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x22, + .type = SAA7164_UNIT_ANALOG_DEMODULATOR, + .name = "TDA8290-2", + .i2c_bus_nr = SAA7164_I2C_BUS_2, + .i2c_bus_addr = 0x84 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x24, + .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, + .name = "TDA10048-1", + .i2c_bus_nr = SAA7164_I2C_BUS_1, + .i2c_bus_addr = 0x10 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x25, + .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, + .name = "TDA10048-2", + .i2c_bus_nr = SAA7164_I2C_BUS_2, + .i2c_bus_addr = 0x12 >> 1, + .i2c_reg_len = REGLEN_8bit, + } }, + }, }; const unsigned int saa7164_bcount = ARRAY_SIZE(saa7164_boards); @@ -490,6 +546,10 @@ struct saa7164_subid saa7164_subids[] = { .subvendor = 0x0070, .subdevice = 0x8940, .card = SAA7164_BOARD_HAUPPAUGE_HVR2200_4, + }, { + .subvendor = 0x0070, + .subdevice = 0x8953, + .card = SAA7164_BOARD_HAUPPAUGE_HVR2200_5, }, }; const unsigned int saa7164_idcount = ARRAY_SIZE(saa7164_subids); @@ -534,6 +594,7 @@ void saa7164_gpio_setup(struct saa7164_dev *dev) case SAA7164_BOARD_HAUPPAUGE_HVR2200_2: case SAA7164_BOARD_HAUPPAUGE_HVR2200_3: case SAA7164_BOARD_HAUPPAUGE_HVR2200_4: + case SAA7164_BOARD_HAUPPAUGE_HVR2200_5: case SAA7164_BOARD_HAUPPAUGE_HVR2250: case SAA7164_BOARD_HAUPPAUGE_HVR2250_2: case SAA7164_BOARD_HAUPPAUGE_HVR2250_3: @@ -615,6 +676,7 @@ void saa7164_card_setup(struct saa7164_dev *dev) case SAA7164_BOARD_HAUPPAUGE_HVR2200_2: case SAA7164_BOARD_HAUPPAUGE_HVR2200_3: case SAA7164_BOARD_HAUPPAUGE_HVR2200_4: + case SAA7164_BOARD_HAUPPAUGE_HVR2200_5: case SAA7164_BOARD_HAUPPAUGE_HVR2250: case SAA7164_BOARD_HAUPPAUGE_HVR2250_2: case SAA7164_BOARD_HAUPPAUGE_HVR2250_3: diff --git a/drivers/media/video/saa7164/saa7164-dvb.c b/drivers/media/video/saa7164/saa7164-dvb.c index d377937..5c5cc3e 100644 --- a/drivers/media/video/saa7164/saa7164-dvb.c +++ b/drivers/media/video/saa7164/saa7164-dvb.c @@ -476,6 +476,7 @@ int saa7164_dvb_register(struct saa7164_port *port) case SAA7164_BOARD_HAUPPAUGE_HVR2200_2: case SAA7164_BOARD_HAUPPAUGE_HVR2200_3: case SAA7164_BOARD_HAUPPAUGE_HVR2200_4: + case SAA7164_BOARD_HAUPPAUGE_HVR2200_5: i2c_bus = &dev->i2c_bus[port->nr + 1]; switch (port->nr) { case 0: diff --git a/drivers/media/video/saa7164/saa7164.h b/drivers/media/video/saa7164/saa7164.h index 35b6430..742b341 100644 --- a/drivers/media/video/saa7164/saa7164.h +++ b/drivers/media/video/saa7164/saa7164.h @@ -83,6 +83,7 @@ #define SAA7164_BOARD_HAUPPAUGE_HVR2250_2 7 #define SAA7164_BOARD_HAUPPAUGE_HVR2250_3 8 #define SAA7164_BOARD_HAUPPAUGE_HVR2200_4 9 +#define SAA7164_BOARD_HAUPPAUGE_HVR2200_5 10 #define SAA7164_MAX_UNITS 8 #define SAA7164_TS_NUMBER_OF_LINES 312 -- cgit v0.10.2 From 5626b8c75bc13aa3287c18d49e92edc84fa85b2d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 26 Aug 2011 07:53:53 -0300 Subject: [media] v4l2-ctrls: implement new volatile autocluster scheme The problem tackled in this patch is how to handle volatile autoclusters correctly. A volatile autocluster is a cluster of related controls where one control is the control that toggles between manual and auto mode and the other controls are the values for the manual mode. For example autogain and gain, autoexposure and exposure, etc. If the hardware lets you read out the automatically calculated manual values while in automode, then those manual controls should be marked volatile. gain value as calculated by the autogain circuitry, then you would mark the gain control as volatile (i.e. continuously changing). The question in such use cases is what to do when switching from the auto mode to the manual mode. Should we switch to the last set manual values or should the volatile values be copied and used as the initial manual values. For example: suppose the mode is manual gain and gain is set to 5. Then autogain is turned on and the gain is set by the hardware to 2. Finally the user switches back to manual gain. What should the gain be? 2 or 5? After a long discussion the decisions was made to keep the last value as calculated by the auto mode (so 2 in the example above). The reason is that webcams that do such things will adapt themselves to the current light conditions and when you switch back to manual mode you expect that you keep the same picture. If you would switch back to old manual values, then that would give you a suddenly different picture, which is jarring for the user. Additionally, this would be difficult to implement in applications that store and restore the control values at application exit and start. If you want to keep the old manual values when you switch from auto to manual, then there would have to be a way for applications to get hold of those old values while in auto mode, but there isn't. So this patch will do all the heavy lifting in v4l2-ctrls.c: if you go from auto mode to manual mode and the manual controls are volatile, then g_volatile_ctrl will be called to get the current values for the manual controls before switching to manual mode. Signed-off-by: Hans Verkuil Acked-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c index 1667621..fc8666a 100644 --- a/drivers/media/video/v4l2-ctrls.c +++ b/drivers/media/video/v4l2-ctrls.c @@ -937,9 +937,14 @@ static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, break; } if (update_inactive) { - ctrl->flags &= ~V4L2_CTRL_FLAG_INACTIVE; - if (!is_cur_manual(ctrl->cluster[0])) + /* Note: update_inactive can only be true for auto clusters. */ + ctrl->flags &= + ~(V4L2_CTRL_FLAG_INACTIVE | V4L2_CTRL_FLAG_VOLATILE); + if (!is_cur_manual(ctrl->cluster[0])) { ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + if (ctrl->cluster[0]->has_volatiles) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + } } if (changed || update_inactive) { /* If a control was changed that was not one of the controls @@ -1489,6 +1494,7 @@ EXPORT_SYMBOL(v4l2_ctrl_add_handler); /* Cluster controls */ void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls) { + bool has_volatiles = false; int i; /* The first control is the master control and it must not be NULL */ @@ -1498,8 +1504,11 @@ void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls) if (controls[i]) { controls[i]->cluster = controls; controls[i]->ncontrols = ncontrols; + if (controls[i]->flags & V4L2_CTRL_FLAG_VOLATILE) + has_volatiles = true; } } + controls[0]->has_volatiles = has_volatiles; } EXPORT_SYMBOL(v4l2_ctrl_cluster); @@ -1507,18 +1516,21 @@ void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls, u8 manual_val, bool set_volatile) { struct v4l2_ctrl *master = controls[0]; - u32 flag; + u32 flag = 0; int i; v4l2_ctrl_cluster(ncontrols, controls); WARN_ON(ncontrols <= 1); WARN_ON(manual_val < master->minimum || manual_val > master->maximum); + WARN_ON(set_volatile && !has_op(master, g_volatile_ctrl)); master->is_auto = true; + master->has_volatiles = set_volatile; master->manual_mode_value = manual_val; master->flags |= V4L2_CTRL_FLAG_UPDATE; - flag = is_cur_manual(master) ? 0 : V4L2_CTRL_FLAG_INACTIVE; - if (set_volatile) - flag |= V4L2_CTRL_FLAG_VOLATILE; + + if (!is_cur_manual(master)) + flag = V4L2_CTRL_FLAG_INACTIVE | + (set_volatile ? V4L2_CTRL_FLAG_VOLATILE : 0); for (i = 1; i < ncontrols; i++) if (controls[i]) @@ -1957,7 +1969,8 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs v4l2_ctrl_lock(master); /* g_volatile_ctrl will update the new control values */ - if (has_op(master, g_volatile_ctrl) && !is_cur_manual(master)) { + if ((master->flags & V4L2_CTRL_FLAG_VOLATILE) || + (master->has_volatiles && !is_cur_manual(master))) { for (j = 0; j < master->ncontrols; j++) cur_to_new(master->cluster[j]); ret = call_op(master, g_volatile_ctrl); @@ -2002,7 +2015,7 @@ static int get_ctrl(struct v4l2_ctrl *ctrl, s32 *val) v4l2_ctrl_lock(master); /* g_volatile_ctrl will update the current control values */ - if ((ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) && !is_cur_manual(master)) { + if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) { for (i = 0; i < master->ncontrols; i++) cur_to_new(master->cluster[i]); ret = call_op(master, g_volatile_ctrl); @@ -2118,6 +2131,20 @@ static int validate_ctrls(struct v4l2_ext_controls *cs, return 0; } +/* Obtain the current volatile values of an autocluster and mark them + as new. */ +static void update_from_auto_cluster(struct v4l2_ctrl *master) +{ + int i; + + for (i = 0; i < master->ncontrols; i++) + cur_to_new(master->cluster[i]); + if (!call_op(master, g_volatile_ctrl)) + for (i = 1; i < master->ncontrols; i++) + if (master->cluster[i]) + master->cluster[i]->is_new = 1; +} + /* Try or try-and-set controls */ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs, @@ -2163,6 +2190,31 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl, if (master->cluster[j]) master->cluster[j]->is_new = 0; + /* For volatile autoclusters that are currently in auto mode + we need to discover if it will be set to manual mode. + If so, then we have to copy the current volatile values + first since those will become the new manual values (which + may be overwritten by explicit new values from this set + of controls). */ + if (master->is_auto && master->has_volatiles && + !is_cur_manual(master)) { + /* Pick an initial non-manual value */ + s32 new_auto_val = master->manual_mode_value + 1; + u32 tmp_idx = idx; + + do { + /* Check if the auto control is part of the + list, and remember the new value. */ + if (helpers[tmp_idx].ctrl == master) + new_auto_val = cs->controls[tmp_idx].value; + tmp_idx = helpers[tmp_idx].next; + } while (tmp_idx); + /* If the new value == the manual value, then copy + the current volatile values. */ + if (new_auto_val == master->manual_mode_value) + update_from_auto_cluster(master); + } + /* Copy the new caller-supplied control values. user_to_new() sets 'is_new' to 1. */ do { @@ -2233,6 +2285,12 @@ static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, s32 *val) if (master->cluster[i]) master->cluster[i]->is_new = 0; + /* For autoclusters with volatiles that are switched from auto to + manual mode we have to update the current volatile values since + those will become the initial manual values after such a switch. */ + if (master->is_auto && master->has_volatiles && ctrl == master && + !is_cur_manual(master) && *val == master->manual_mode_value) + update_from_auto_cluster(master); ctrl->val = *val; ctrl->is_new = 1; ret = try_or_set_cluster(fh, master, true); diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index bd6a4a7..eeb3df6 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -69,6 +69,8 @@ struct v4l2_ctrl_ops { * members are in 'automatic' mode or 'manual' mode. This is * used for autogain/gain type clusters. Drivers should never * set this flag directly. + * @has_volatiles: If set, then one or more members of the cluster are volatile. + * Drivers should never touch this flag. * @manual_mode_value: If the is_auto flag is set, then this is the value * of the auto control that determines if that control is in * manual mode. So if the value of the auto control equals this @@ -115,6 +117,7 @@ struct v4l2_ctrl { unsigned int is_new:1; unsigned int is_private:1; unsigned int is_auto:1; + unsigned int has_volatiles:1; unsigned int manual_mode_value:8; const struct v4l2_ctrl_ops *ops; -- cgit v0.10.2 From 882a935c4395a67ea0a6ed6d61531d680190b23f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 26 Aug 2011 08:35:59 -0300 Subject: [media] v4l2-controls.txt: update auto cluster documentation Signed-off-by: Hans Verkuil Acked-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/video4linux/v4l2-controls.txt b/Documentation/video4linux/v4l2-controls.txt index f92ee30..26aa057 100644 --- a/Documentation/video4linux/v4l2-controls.txt +++ b/Documentation/video4linux/v4l2-controls.txt @@ -495,18 +495,20 @@ Handling autogain/gain-type Controls with Auto Clusters A common type of control cluster is one that handles 'auto-foo/foo'-type controls. Typical examples are autogain/gain, autoexposure/exposure, -autowhitebalance/red balance/blue balance. In all cases you have one controls +autowhitebalance/red balance/blue balance. In all cases you have one control that determines whether another control is handled automatically by the hardware, or whether it is under manual control from the user. If the cluster is in automatic mode, then the manual controls should be -marked inactive. When the volatile controls are read the g_volatile_ctrl -operation should return the value that the hardware's automatic mode set up -automatically. +marked inactive and volatile. When the volatile controls are read the +g_volatile_ctrl operation should return the value that the hardware's automatic +mode set up automatically. If the cluster is put in manual mode, then the manual controls should become -active again and V4L2_CTRL_FLAG_VOLATILE should be ignored (so g_volatile_ctrl -is no longer called while in manual mode). +active again and the volatile flag is cleared (so g_volatile_ctrl is no longer +called while in manual mode). In addition just before switching to manual mode +the current values as determined by the auto mode are copied as the new manual +values. Finally the V4L2_CTRL_FLAG_UPDATE should be set for the auto control since changing that control affects the control flags of the manual controls. @@ -520,6 +522,10 @@ void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls, The first two arguments are identical to v4l2_ctrl_cluster. The third argument tells the framework which value switches the cluster into manual mode. The last argument will optionally set V4L2_CTRL_FLAG_VOLATILE for the non-auto controls. +If it is false, then the manual controls are never volatile. You would typically +use that if the hardware does not give you the option to read back to values as +determined by the auto mode (e.g. if autogain is on, the hardware doesn't allow +you to obtain the current gain value). The first control of the cluster is assumed to be the 'auto' control. @@ -680,16 +686,6 @@ if there are no controls at all. count if nothing was done yet. If it is less than count then only the controls up to error_idx-1 were successfully applied. -3) When attempting to read a button control the framework will return -EACCES -instead of -EINVAL as stated in the spec. It seems to make more sense since -button controls are write-only controls. - -4) Attempting to write to a read-only control will return -EACCES instead of --EINVAL as the spec says. - -5) The spec does not mention what should happen when you try to set/get a -control class controls. The framework will return -EACCES. - Proposals for Extensions ======================== @@ -702,9 +698,3 @@ decimal. Useful for e.g. video_mute_yuv. 2) It is possible to mark in the controls array which controls have been successfully written and which failed by for example adding a bit to the control ID. Not sure if it is worth the effort, though. - -3) Trying to set volatile inactive controls should result in -EACCESS. - -4) Add a new flag to mark volatile controls. Any application that wants -to store the state of the controls can then skip volatile inactive controls. -Currently it is not possible to detect such controls. -- cgit v0.10.2 From 43d23f36297d030194c5c82a0593eb7eddcb4fbb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 26 Aug 2011 08:40:43 -0300 Subject: [media] pwc: switch to the new auto-cluster volatile handling Now that the auto cluster core changed to a different scheme of how to handle volatile controls (including how to switch from auto to manual mode) the pwc code can be simplified to use that new core support. Signed-off-by: Hans Verkuil Acked-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c index 6873bf5..0a41ebb 100644 --- a/drivers/media/video/pwc/pwc-v4l.c +++ b/drivers/media/video/pwc/pwc-v4l.c @@ -83,6 +83,7 @@ static const struct v4l2_ctrl_config pwc_contour_cfg = { .id = PWC_CID_CUSTOM(contour), .type = V4L2_CTRL_TYPE_INTEGER, .name = "Contour", + .flags = V4L2_CTRL_FLAG_SLIDER, .min = 0, .max = 63, .step = 1, @@ -206,8 +207,7 @@ int pwc_init_controls(struct pwc_device *pdev) pdev->blue_balance = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, V4L2_CID_BLUE_BALANCE, 0, 255, 1, def); - v4l2_ctrl_auto_cluster(3, &pdev->auto_white_balance, awb_manual, - pdev->auto_white_balance->cur.val == awb_auto); + v4l2_ctrl_auto_cluster(3, &pdev->auto_white_balance, awb_manual, true); /* autogain, gain */ r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, AGC_MODE_FORMATTER, &def); @@ -331,12 +331,12 @@ int pwc_init_controls(struct pwc_device *pdev) pdev->restore_user = v4l2_ctrl_new_custom(hdl, &pwc_restore_user_cfg, NULL); if (pdev->restore_user) - pdev->restore_user->flags = V4L2_CTRL_FLAG_UPDATE; + pdev->restore_user->flags |= V4L2_CTRL_FLAG_UPDATE; pdev->restore_factory = v4l2_ctrl_new_custom(hdl, &pwc_restore_factory_cfg, NULL); if (pdev->restore_factory) - pdev->restore_factory->flags = V4L2_CTRL_FLAG_UPDATE; + pdev->restore_factory->flags |= V4L2_CTRL_FLAG_UPDATE; if (!(pdev->features & FEATURE_MOTOR_PANTILT)) return hdl->error; @@ -563,8 +563,10 @@ static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl) switch (ctrl->id) { case V4L2_CID_AUTO_WHITE_BALANCE: - if (pdev->color_bal_valid && time_before(jiffies, - pdev->last_color_bal_update + HZ / 4)) { + if (pdev->color_bal_valid && + (pdev->auto_white_balance->val != awb_auto || + time_before(jiffies, + pdev->last_color_bal_update + HZ / 4))) { pdev->red_balance->val = pdev->last_red_balance; pdev->blue_balance->val = pdev->last_blue_balance; break; @@ -630,7 +632,7 @@ leave: static int pwc_set_awb(struct pwc_device *pdev) { - int ret = 0; + int ret; if (pdev->auto_white_balance->is_new) { ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL, @@ -639,52 +641,34 @@ static int pwc_set_awb(struct pwc_device *pdev) if (ret) return ret; - /* Update val when coming from auto or going to a preset */ - if ((pdev->red_balance->flags & V4L2_CTRL_FLAG_VOLATILE) || - pdev->auto_white_balance->val == awb_indoor || - pdev->auto_white_balance->val == awb_outdoor || - pdev->auto_white_balance->val == awb_fl) { - if (!pdev->red_balance->is_new) - pwc_get_u8_ctrl(pdev, GET_STATUS_CTL, - READ_RED_GAIN_FORMATTER, - &pdev->red_balance->val); - if (!pdev->blue_balance->is_new) - pwc_get_u8_ctrl(pdev, GET_STATUS_CTL, - READ_BLUE_GAIN_FORMATTER, - &pdev->blue_balance->val); - } - if (pdev->auto_white_balance->val == awb_auto) { - pdev->red_balance->flags |= V4L2_CTRL_FLAG_VOLATILE; - pdev->blue_balance->flags |= V4L2_CTRL_FLAG_VOLATILE; + if (pdev->auto_white_balance->val != awb_manual) pdev->color_bal_valid = false; /* Force cache update */ - } else { - pdev->red_balance->flags &= ~V4L2_CTRL_FLAG_VOLATILE; - pdev->blue_balance->flags &= ~V4L2_CTRL_FLAG_VOLATILE; - } } + if (pdev->auto_white_balance->val != awb_manual) + return 0; - if (ret == 0 && pdev->red_balance->is_new) { - if (pdev->auto_white_balance->val != awb_manual) - return -EBUSY; + if (pdev->red_balance->is_new) { ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, pdev->red_balance->val); + if (ret) + return ret; } - if (ret == 0 && pdev->blue_balance->is_new) { - if (pdev->auto_white_balance->val != awb_manual) - return -EBUSY; + if (pdev->blue_balance->is_new) { ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, pdev->blue_balance->val); + if (ret) + return ret; } - return ret; + return 0; } /* For CODEC2 models which have separate autogain and auto exposure */ static int pwc_set_autogain(struct pwc_device *pdev) { - int ret = 0; + int ret; if (pdev->autogain->is_new) { ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, @@ -692,27 +676,28 @@ static int pwc_set_autogain(struct pwc_device *pdev) pdev->autogain->val ? 0 : 0xff); if (ret) return ret; + if (pdev->autogain->val) pdev->gain_valid = false; /* Force cache update */ - else if (!pdev->gain->is_new) - pwc_get_u8_ctrl(pdev, GET_STATUS_CTL, - READ_AGC_FORMATTER, - &pdev->gain->val); } - if (ret == 0 && pdev->gain->is_new) { - if (pdev->autogain->val) - return -EBUSY; + + if (pdev->autogain->val) + return 0; + + if (pdev->gain->is_new) { ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, PRESET_AGC_FORMATTER, pdev->gain->val); + if (ret) + return ret; } - return ret; + return 0; } /* For CODEC2 models which have separate autogain and auto exposure */ static int pwc_set_exposure_auto(struct pwc_device *pdev) { - int ret = 0; + int ret; int is_auto = pdev->exposure_auto->val == V4L2_EXPOSURE_AUTO; if (pdev->exposure_auto->is_new) { @@ -721,27 +706,28 @@ static int pwc_set_exposure_auto(struct pwc_device *pdev) is_auto ? 0 : 0xff); if (ret) return ret; + if (is_auto) pdev->exposure_valid = false; /* Force cache update */ - else if (!pdev->exposure->is_new) - pwc_get_u16_ctrl(pdev, GET_STATUS_CTL, - READ_SHUTTER_FORMATTER, - &pdev->exposure->val); } - if (ret == 0 && pdev->exposure->is_new) { - if (is_auto) - return -EBUSY; + + if (is_auto) + return 0; + + if (pdev->exposure->is_new) { ret = pwc_set_u16_ctrl(pdev, SET_LUM_CTL, PRESET_SHUTTER_FORMATTER, pdev->exposure->val); + if (ret) + return ret; } - return ret; + return 0; } /* For CODEC3 models which have autogain controlling both gain and exposure */ static int pwc_set_autogain_expo(struct pwc_device *pdev) { - int ret = 0; + int ret; if (pdev->autogain->is_new) { ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, @@ -749,35 +735,32 @@ static int pwc_set_autogain_expo(struct pwc_device *pdev) pdev->autogain->val ? 0 : 0xff); if (ret) return ret; + if (pdev->autogain->val) { pdev->gain_valid = false; /* Force cache update */ pdev->exposure_valid = false; /* Force cache update */ - } else { - if (!pdev->gain->is_new) - pwc_get_u8_ctrl(pdev, GET_STATUS_CTL, - READ_AGC_FORMATTER, - &pdev->gain->val); - if (!pdev->exposure->is_new) - pwc_get_u16_ctrl(pdev, GET_STATUS_CTL, - READ_SHUTTER_FORMATTER, - &pdev->exposure->val); } } - if (ret == 0 && pdev->gain->is_new) { - if (pdev->autogain->val) - return -EBUSY; + + if (pdev->autogain->val) + return 0; + + if (pdev->gain->is_new) { ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, PRESET_AGC_FORMATTER, pdev->gain->val); + if (ret) + return ret; } - if (ret == 0 && pdev->exposure->is_new) { - if (pdev->autogain->val) - return -EBUSY; + + if (pdev->exposure->is_new) { ret = pwc_set_u16_ctrl(pdev, SET_LUM_CTL, PRESET_SHUTTER_FORMATTER, pdev->exposure->val); + if (ret) + return ret; } - return ret; + return 0; } static int pwc_set_motor(struct pwc_device *pdev) @@ -878,10 +861,6 @@ static int pwc_s_ctrl(struct v4l2_ctrl *ctrl) pdev->autocontour->val ? 0 : 0xff); } if (ret == 0 && pdev->contour->is_new) { - if (pdev->autocontour->val) { - ret = -EBUSY; - break; - } ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, PRESET_CONTOUR_FORMATTER, pdev->contour->val); -- cgit v0.10.2 From 380834d674c2b3655a9d7a219f288331f5cc7b4f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 26 Aug 2011 08:45:38 -0300 Subject: [media] vivi: add support for VIDIOC_LOG_STATUS Signed-off-by: Hans Verkuil Acked-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 21bb324..7cf94c0 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -958,6 +958,14 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) return vb2_streamoff(&dev->vb_vidq, i); } +static int vidioc_log_status(struct file *file, void *priv) +{ + struct vivi_dev *dev = video_drvdata(file); + + v4l2_ctrl_handler_log_status(&dev->ctrl_handler, dev->v4l2_dev.name); + return 0; +} + static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) { return 0; @@ -1201,6 +1209,7 @@ static const struct v4l2_ioctl_ops vivi_ioctl_ops = { .vidioc_s_input = vidioc_s_input, .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, + .vidioc_log_status = vidioc_log_status, .vidioc_subscribe_event = vidioc_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -- cgit v0.10.2 From 34ebdc97b9f273262559ab410d18f4e9424a54c2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 26 Aug 2011 08:46:13 -0300 Subject: [media] pwc: add support for VIDIOC_LOG_STATUS Signed-off-by: Hans Verkuil Acked-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c index 0a41ebb..a10ff6b 100644 --- a/drivers/media/video/pwc/pwc-v4l.c +++ b/drivers/media/video/pwc/pwc-v4l.c @@ -1078,6 +1078,14 @@ static int pwc_enum_frameintervals(struct file *file, void *fh, return 0; } +static int pwc_log_status(struct file *file, void *priv) +{ + struct pwc_device *pdev = video_drvdata(file); + + v4l2_ctrl_handler_log_status(&pdev->ctrl_handler, PWC_NAME); + return 0; +} + static long pwc_default(struct file *file, void *fh, bool valid_prio, int cmd, void *arg) { @@ -1101,6 +1109,7 @@ const struct v4l2_ioctl_ops pwc_ioctl_ops = { .vidioc_dqbuf = pwc_dqbuf, .vidioc_streamon = pwc_streamon, .vidioc_streamoff = pwc_streamoff, + .vidioc_log_status = pwc_log_status, .vidioc_enum_framesizes = pwc_enum_framesizes, .vidioc_enum_frameintervals = pwc_enum_frameintervals, .vidioc_default = pwc_default, -- cgit v0.10.2 From 6f43dbfd8fa7f80b1cf073446275c691b52cd7b2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 26 Aug 2011 08:46:29 -0300 Subject: [media] saa7115: use the new auto cluster support Signed-off-by: Hans Verkuil Acked-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index e443d0d..cee98ea 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -793,7 +793,6 @@ static int saa711x_s_ctrl(struct v4l2_ctrl *ctrl) saa711x_write(sd, R_0F_CHROMA_GAIN_CNTL, state->gain->val); else saa711x_write(sd, R_0F_CHROMA_GAIN_CNTL, state->gain->val | 0x80); - v4l2_ctrl_activate(state->gain, !state->agc->val); break; default: @@ -1601,7 +1600,6 @@ static int saa711x_probe(struct i2c_client *client, V4L2_CID_CHROMA_AGC, 0, 1, 1, 1); state->gain = v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops, V4L2_CID_CHROMA_GAIN, 0, 127, 1, 40); - state->gain->flags |= V4L2_CTRL_FLAG_VOLATILE; sd->ctrl_handler = hdl; if (hdl->error) { int err = hdl->error; @@ -1610,8 +1608,7 @@ static int saa711x_probe(struct i2c_client *client, kfree(state); return err; } - state->agc->flags |= V4L2_CTRL_FLAG_UPDATE; - v4l2_ctrl_cluster(2, &state->agc); + v4l2_ctrl_auto_cluster(2, &state->agc, 0, true); state->input = -1; state->output = SAA7115_IPORT_ON; -- cgit v0.10.2 From e553000a14ead0e265a8aa4d241c7b3221e233e3 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 19 Jan 2011 21:44:00 -0300 Subject: [media] sr030pc30: Remove empty s_stream op s_stream does nothing in current form so remove it. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/sr030pc30.c b/drivers/media/video/sr030pc30.c index 8afb0e8..10aff3f 100644 --- a/drivers/media/video/sr030pc30.c +++ b/drivers/media/video/sr030pc30.c @@ -714,11 +714,6 @@ static int sr030pc30_base_config(struct v4l2_subdev *sd) return ret; } -static int sr030pc30_s_stream(struct v4l2_subdev *sd, int enable) -{ - return 0; -} - static int sr030pc30_s_power(struct v4l2_subdev *sd, int on) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -764,7 +759,6 @@ static const struct v4l2_subdev_core_ops sr030pc30_core_ops = { }; static const struct v4l2_subdev_video_ops sr030pc30_video_ops = { - .s_stream = sr030pc30_s_stream, .g_mbus_fmt = sr030pc30_g_fmt, .s_mbus_fmt = sr030pc30_s_fmt, .try_mbus_fmt = sr030pc30_try_fmt, -- cgit v0.10.2 From 096b703fb6cc9c9e4a188b80932c467b96985fcf Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Tue, 19 Jul 2011 09:26:35 -0300 Subject: [media] mt9m111: move lastpage to struct mt9m111 for multi instances Signed-off-by: Michael Grzeschik Acked-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index a357aa8..07af26e 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c @@ -184,6 +184,7 @@ struct mt9m111 { struct mutex power_lock; /* lock to protect power_count */ int power_count; const struct mt9m111_datafmt *fmt; + int lastpage; /* PageMap cache value */ unsigned int gain; unsigned char autoexposure; unsigned char datawidth; @@ -202,17 +203,17 @@ static int reg_page_map_set(struct i2c_client *client, const u16 reg) { int ret; u16 page; - static int lastpage = -1; /* PageMap cache value */ + struct mt9m111 *mt9m111 = to_mt9m111(client); page = (reg >> 8); - if (page == lastpage) + if (page == mt9m111->lastpage) return 0; if (page > 2) return -EINVAL; ret = i2c_smbus_write_word_data(client, MT9M111_PAGE_MAP, swab16(page)); if (!ret) - lastpage = page; + mt9m111->lastpage = page; return ret; } @@ -932,6 +933,8 @@ static int mt9m111_video_probe(struct soc_camera_device *icd, BUG_ON(!icd->parent || to_soc_camera_host(icd->parent)->nr != icd->iface); + mt9m111->lastpage = -1; + mt9m111->autoexposure = 1; mt9m111->autowhitebalance = 1; -- cgit v0.10.2 From fbc09d3aa1510552e36d9bae05def25d039a98f2 Mon Sep 17 00:00:00 2001 From: Thomas Meyer Date: Sat, 6 Aug 2011 04:48:32 -0300 Subject: [media] davinci vpbe: Use resource_size() Use resource_size function on resource object instead of explicit computation. The semantic patch that makes this output is available in scripts/coccinelle/api/resource_size.cocci. More information about semantic patching is available at http://coccinelle.lip6.fr/ Signed-off-by: Thomas Meyer Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/davinci/vpbe_osd.c b/drivers/media/video/davinci/vpbe_osd.c index 5352884..ceccf43 100644 --- a/drivers/media/video/davinci/vpbe_osd.c +++ b/drivers/media/video/davinci/vpbe_osd.c @@ -1162,7 +1162,7 @@ static int osd_probe(struct platform_device *pdev) goto free_mem; } osd->osd_base_phys = res->start; - osd->osd_size = res->end - res->start + 1; + osd->osd_size = resource_size(res); if (!request_mem_region(osd->osd_base_phys, osd->osd_size, MODULE_NAME)) { dev_err(osd->dev, "Unable to reserve OSD MMIO region\n"); -- cgit v0.10.2 From 6426e14a7ebfaea831db8d95f55da334701f2c37 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 16 Sep 2011 12:33:08 -0300 Subject: [media] noon010pc30: Conversion to the media controller API Replace g/s_mbus_fmt ops with the pad level get/set_fmt operations. Add media entity initialization and set subdev flags so the host driver creates a subdev device node for the driver. A mutex was added for serializing the subdev operations. When setting format is attempted during streaming an (EBUSY) error will be returned. After the device is powered up it will now remain in "power sleep" mode until s_stream(1) is called. The "power sleep" mode is used to suspend/resume frame generation at the sensor's output through s_stream op. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 9da6044..eb4fd6b 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -762,7 +762,7 @@ config VIDEO_VIA_CAMERA config VIDEO_NOON010PC30 tristate "NOON010PC30 CIF camera sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_V4L2 && EXPERIMENTAL && VIDEO_V4L2_SUBDEV_API ---help--- This driver supports NOON010PC30 CIF camera from Siliconfile diff --git a/drivers/media/video/noon010pc30.c b/drivers/media/video/noon010pc30.c index 35f722a..1a874ec 100644 --- a/drivers/media/video/noon010pc30.c +++ b/drivers/media/video/noon010pc30.c @@ -1,7 +1,7 @@ /* * Driver for SiliconFile NOON010PC30 CIF (1/11") Image Sensor with ISP * - * Copyright (C) 2010 Samsung Electronics + * Copyright (C) 2010 - 2011 Samsung Electronics Co., Ltd. * Contact: Sylwester Nawrocki, * * Initial register configuration based on a driver authored by @@ -10,7 +10,7 @@ * 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 of the License, or - * (at your option) any later vergsion. + * (at your option) any later version. */ #include @@ -131,17 +131,24 @@ static const char * const noon010_supply_name[] = { struct noon010_info { struct v4l2_subdev sd; + struct media_pad pad; struct v4l2_ctrl_handler hdl; const struct noon010pc30_platform_data *pdata; + struct regulator_bulk_data supply[NOON010_NUM_SUPPLIES]; + u32 gpio_nreset; + u32 gpio_nstby; + + /* Protects the struct members below */ + struct mutex lock; + const struct noon010_format *curr_fmt; const struct noon010_frmsize *curr_win; + unsigned int apply_new_cfg:1; + unsigned int streaming:1; unsigned int hflip:1; unsigned int vflip:1; unsigned int power:1; u8 i2c_reg_page; - struct regulator_bulk_data supply[NOON010_NUM_SUPPLIES]; - u32 gpio_nreset; - u32 gpio_nstby; }; struct i2c_regval { @@ -313,6 +320,7 @@ static int noon010_enable_autowhitebalance(struct v4l2_subdev *sd, int on) return ret; } +/* Called with struct noon010_info.lock mutex held */ static int noon010_set_flip(struct v4l2_subdev *sd, int hflip, int vflip) { struct noon010_info *info = to_noon010(sd); @@ -340,21 +348,18 @@ static int noon010_set_flip(struct v4l2_subdev *sd, int hflip, int vflip) static int noon010_set_params(struct v4l2_subdev *sd) { struct noon010_info *info = to_noon010(sd); - int ret; - if (!info->curr_win) - return -EINVAL; - - ret = cam_i2c_write(sd, VDO_CTL_REG(0), info->curr_win->vid_ctl1); - - if (!ret && info->curr_fmt) - ret = cam_i2c_write(sd, ISP_CTL_REG(0), - info->curr_fmt->ispctl1_reg); - return ret; + int ret = cam_i2c_write(sd, VDO_CTL_REG(0), + info->curr_win->vid_ctl1); + if (ret) + return ret; + return cam_i2c_write(sd, ISP_CTL_REG(0), + info->curr_fmt->ispctl1_reg); } /* Find nearest matching image pixel size. */ -static int noon010_try_frame_size(struct v4l2_mbus_framefmt *mf) +static int noon010_try_frame_size(struct v4l2_mbus_framefmt *mf, + const struct noon010_frmsize **size) { unsigned int min_err = ~0; int i = ARRAY_SIZE(noon010_sizes); @@ -374,11 +379,14 @@ static int noon010_try_frame_size(struct v4l2_mbus_framefmt *mf) if (match) { mf->width = match->width; mf->height = match->height; + if (size) + *size = match; return 0; } return -EINVAL; } +/* Called with info.lock mutex held */ static int power_enable(struct noon010_info *info) { int ret; @@ -419,6 +427,7 @@ static int power_enable(struct noon010_info *info) return 0; } +/* Called with info.lock mutex held */ static int power_disable(struct noon010_info *info) { int ret; @@ -448,93 +457,120 @@ static int power_disable(struct noon010_info *info) static int noon010_s_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_subdev *sd = to_sd(ctrl); + struct noon010_info *info = to_noon010(sd); + int ret = 0; v4l2_dbg(1, debug, sd, "%s: ctrl_id: %d, value: %d\n", __func__, ctrl->id, ctrl->val); + mutex_lock(&info->lock); + /* + * If the device is not powered up by the host driver do + * not apply any controls to H/W at this time. Instead + * the controls will be restored right after power-up. + */ + if (!info->power) + goto unlock; + switch (ctrl->id) { case V4L2_CID_AUTO_WHITE_BALANCE: - return noon010_enable_autowhitebalance(sd, ctrl->val); + ret = noon010_enable_autowhitebalance(sd, ctrl->val); + break; case V4L2_CID_BLUE_BALANCE: - return cam_i2c_write(sd, MWB_BGAIN_REG, ctrl->val); + ret = cam_i2c_write(sd, MWB_BGAIN_REG, ctrl->val); + break; case V4L2_CID_RED_BALANCE: - return cam_i2c_write(sd, MWB_RGAIN_REG, ctrl->val); + ret = cam_i2c_write(sd, MWB_RGAIN_REG, ctrl->val); + break; default: - return -EINVAL; + ret = -EINVAL; } +unlock: + mutex_unlock(&info->lock); + return ret; } -static int noon010_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - enum v4l2_mbus_pixelcode *code) +static int noon010_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) { - if (!code || index >= ARRAY_SIZE(noon010_formats)) + if (code->index >= ARRAY_SIZE(noon010_formats)) return -EINVAL; - *code = noon010_formats[index].code; + code->code = noon010_formats[code->index].code; return 0; } -static int noon010_g_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +static int noon010_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) { struct noon010_info *info = to_noon010(sd); - int ret; - - if (!mf) - return -EINVAL; + struct v4l2_mbus_framefmt *mf; - if (!info->curr_win || !info->curr_fmt) { - ret = noon010_set_params(sd); - if (ret) - return ret; + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + if (fh) { + mf = v4l2_subdev_get_try_format(fh, 0); + fmt->format = *mf; + } + return 0; } + mf = &fmt->format; - mf->width = info->curr_win->width; - mf->height = info->curr_win->height; - mf->code = info->curr_fmt->code; - mf->colorspace = info->curr_fmt->colorspace; - mf->field = V4L2_FIELD_NONE; + mutex_lock(&info->lock); + mf->width = info->curr_win->width; + mf->height = info->curr_win->height; + mf->code = info->curr_fmt->code; + mf->colorspace = info->curr_fmt->colorspace; + mf->field = V4L2_FIELD_NONE; + mutex_unlock(&info->lock); return 0; } /* Return nearest media bus frame format. */ -static const struct noon010_format *try_fmt(struct v4l2_subdev *sd, +static const struct noon010_format *noon010_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) { int i = ARRAY_SIZE(noon010_formats); - noon010_try_frame_size(mf); - - while (i--) + while (--i) if (mf->code == noon010_formats[i].code) break; - mf->code = noon010_formats[i].code; return &noon010_formats[i]; } -static int noon010_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - if (!sd || !mf) - return -EINVAL; - - try_fmt(sd, mf); - return 0; -} - -static int noon010_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int noon010_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) { struct noon010_info *info = to_noon010(sd); + const struct noon010_frmsize *size = NULL; + const struct noon010_format *nf; + struct v4l2_mbus_framefmt *mf; + int ret = 0; - if (!sd || !mf) - return -EINVAL; - - info->curr_fmt = try_fmt(sd, mf); + nf = noon010_try_fmt(sd, &fmt->format); + noon010_try_frame_size(&fmt->format, &size); + fmt->format.colorspace = V4L2_COLORSPACE_JPEG; - return noon010_set_params(sd); + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + if (fh) { + mf = v4l2_subdev_get_try_format(fh, 0); + *mf = fmt->format; + } + return 0; + } + mutex_lock(&info->lock); + if (!info->streaming) { + info->apply_new_cfg = 1; + info->curr_fmt = nf; + info->curr_win = size; + } else { + ret = -EBUSY; + } + mutex_unlock(&info->lock); + return ret; } static int noon010_base_config(struct v4l2_subdev *sd) @@ -550,8 +586,6 @@ static int noon010_base_config(struct v4l2_subdev *sd) } if (!ret) ret = noon010_set_flip(sd, 1, 0); - if (!ret) - ret = noon010_power_ctrl(sd, false, false); /* sync the handler and the registers state */ v4l2_ctrl_handler_setup(&to_noon010(sd)->hdl); @@ -582,6 +616,26 @@ static int noon010_s_power(struct v4l2_subdev *sd, int on) return ret; } +static int noon010_s_stream(struct v4l2_subdev *sd, int on) +{ + struct noon010_info *info = to_noon010(sd); + int ret = 0; + + mutex_lock(&info->lock); + if (!info->streaming != !on) { + ret = noon010_power_ctrl(sd, false, !on); + if (!ret) + info->streaming = on; + } + if (!ret && on && info->apply_new_cfg) { + ret = noon010_set_params(sd); + if (!ret) + info->apply_new_cfg = 0; + } + mutex_unlock(&info->lock); + return ret; +} + static int noon010_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) { @@ -599,6 +653,22 @@ static int noon010_log_status(struct v4l2_subdev *sd) return 0; } +static int noon010_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(fh, 0); + + mf->width = noon010_sizes[0].width; + mf->height = noon010_sizes[0].height; + mf->code = noon010_formats[0].code; + mf->colorspace = V4L2_COLORSPACE_JPEG; + mf->field = V4L2_FIELD_NONE; + return 0; +} + +static const struct v4l2_subdev_internal_ops noon010_subdev_internal_ops = { + .open = noon010_open, +}; + static const struct v4l2_ctrl_ops noon010_ctrl_ops = { .s_ctrl = noon010_s_ctrl, }; @@ -616,15 +686,19 @@ static const struct v4l2_subdev_core_ops noon010_core_ops = { .log_status = noon010_log_status, }; -static const struct v4l2_subdev_video_ops noon010_video_ops = { - .g_mbus_fmt = noon010_g_fmt, - .s_mbus_fmt = noon010_s_fmt, - .try_mbus_fmt = noon010_try_fmt, - .enum_mbus_fmt = noon010_enum_fmt, +static struct v4l2_subdev_pad_ops noon010_pad_ops = { + .enum_mbus_code = noon010_enum_mbus_code, + .get_fmt = noon010_get_fmt, + .set_fmt = noon010_set_fmt, +}; + +static struct v4l2_subdev_video_ops noon010_video_ops = { + .s_stream = noon010_s_stream, }; static const struct v4l2_subdev_ops noon010_ops = { .core = &noon010_core_ops, + .pad = &noon010_pad_ops, .video = &noon010_video_ops, }; @@ -665,10 +739,14 @@ static int noon010_probe(struct i2c_client *client, if (!info) return -ENOMEM; + mutex_init(&info->lock); sd = &info->sd; strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); v4l2_i2c_subdev_init(sd, client, &noon010_ops); + sd->internal_ops = &noon010_subdev_internal_ops; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + v4l2_ctrl_handler_init(&info->hdl, 3); v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops, @@ -719,11 +797,17 @@ static int noon010_probe(struct i2c_client *client, if (ret) goto np_reg_err; + info->pad.flags = MEDIA_PAD_FL_SOURCE; + sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; + ret = media_entity_init(&sd->entity, 1, &info->pad, 0); + if (ret < 0) + goto np_me_err; + ret = noon010_detect(client, info); if (!ret) return 0; - /* the sensor detection failed */ +np_me_err: regulator_bulk_free(NOON010_NUM_SUPPLIES, info->supply); np_reg_err: if (gpio_is_valid(info->gpio_nstby)) @@ -754,6 +838,7 @@ static int noon010_remove(struct i2c_client *client) if (gpio_is_valid(info->gpio_nstby)) gpio_free(info->gpio_nstby); + media_entity_cleanup(&sd->entity); kfree(info); return 0; } -- cgit v0.10.2 From bc3603248fecbdeb4a2c0568fc6606f257b6ca23 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 12 Sep 2011 10:34:03 -0300 Subject: [media] noon010pc30: Improve s_power operation handling Remove the now unneeded check for the platform data in s_power handler and the platform data pointer in struct noon010_info. Also do not reset the configured output resolution and pixel format when cycling sensor's power. Add small delay for proper reset signal shape. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/noon010pc30.c b/drivers/media/video/noon010pc30.c index 1a874ec..935c96b 100644 --- a/drivers/media/video/noon010pc30.c +++ b/drivers/media/video/noon010pc30.c @@ -133,7 +133,6 @@ struct noon010_info { struct v4l2_subdev sd; struct media_pad pad; struct v4l2_ctrl_handler hdl; - const struct noon010pc30_platform_data *pdata; struct regulator_bulk_data supply[NOON010_NUM_SUPPLIES]; u32 gpio_nreset; u32 gpio_nstby; @@ -299,8 +298,10 @@ static int noon010_power_ctrl(struct v4l2_subdev *sd, bool reset, bool sleep) u8 reg = sleep ? 0xF1 : 0xF0; int ret = 0; - if (reset) + if (reset) { ret = cam_i2c_write(sd, POWER_CTRL_REG, reg | 0x02); + udelay(20); + } if (!ret) { ret = cam_i2c_write(sd, POWER_CTRL_REG, reg); if (reset && !ret) @@ -573,45 +574,37 @@ static int noon010_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, return ret; } +/* Called with struct noon010_info.lock mutex held */ static int noon010_base_config(struct v4l2_subdev *sd) { - struct noon010_info *info = to_noon010(sd); - int ret; - - ret = noon010_bulk_write_reg(sd, noon010_base_regs); - if (!ret) { - info->curr_fmt = &noon010_formats[0]; - info->curr_win = &noon010_sizes[0]; + int ret = noon010_bulk_write_reg(sd, noon010_base_regs); + if (!ret) ret = noon010_set_params(sd); - } if (!ret) ret = noon010_set_flip(sd, 1, 0); - /* sync the handler and the registers state */ - v4l2_ctrl_handler_setup(&to_noon010(sd)->hdl); return ret; } static int noon010_s_power(struct v4l2_subdev *sd, int on) { struct noon010_info *info = to_noon010(sd); - const struct noon010pc30_platform_data *pdata = info->pdata; - int ret = 0; - - if (WARN(pdata == NULL, "No platform data!\n")) - return -ENOMEM; + int ret; + mutex_lock(&info->lock); if (on) { ret = power_enable(info); - if (ret) - return ret; - ret = noon010_base_config(sd); + if (!ret) + ret = noon010_base_config(sd); } else { noon010_power_ctrl(sd, false, true); ret = power_disable(info); - info->curr_win = NULL; - info->curr_fmt = NULL; } + mutex_unlock(&info->lock); + + /* Restore the controls state */ + if (!ret && on) + ret = v4l2_ctrl_handler_setup(&info->hdl); return ret; } @@ -762,10 +755,11 @@ static int noon010_probe(struct i2c_client *client, if (ret) goto np_err; - info->pdata = client->dev.platform_data; info->i2c_reg_page = -1; info->gpio_nreset = -EINVAL; info->gpio_nstby = -EINVAL; + info->curr_fmt = &noon010_formats[0]; + info->curr_win = &noon010_sizes[0]; if (gpio_is_valid(pdata->gpio_nreset)) { ret = gpio_request(pdata->gpio_nreset, "NOON010PC30 NRST"); -- cgit v0.10.2 From 3accb18ca14479d794e4b7a825abb93343f81855 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 20 Sep 2011 10:32:13 -0300 Subject: [media] v4l: Move SR030PC30, NOON010PC30, M5MOLS drivers to the right location SR030PC30, NOON010PC30, M5MOLS are camera sensors so better place for them is under the "Camera sensors" Kconfig section. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index eb4fd6b..f41ae69 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -496,6 +496,20 @@ config VIDEO_TCM825X This is a driver for the Toshiba TCM825x VGA camera sensor. It is used for example in Nokia N800. +config VIDEO_SR030PC30 + tristate "Siliconfile SR030PC30 sensor support" + depends on I2C && VIDEO_V4L2 + ---help--- + This driver supports SR030PC30 VGA camera from Siliconfile + +config VIDEO_NOON010PC30 + tristate "Siliconfile NOON010PC30 sensor support" + depends on I2C && VIDEO_V4L2 && EXPERIMENTAL && VIDEO_V4L2_SUBDEV_API + ---help--- + This driver supports NOON010PC30 CIF camera from Siliconfile + +source "drivers/media/video/m5mols/Kconfig" + comment "Flash devices" config VIDEO_ADP1653 @@ -744,12 +758,6 @@ config VIDEO_M32R_AR_M64278 To compile this driver as a module, choose M here: the module will be called arv. -config VIDEO_SR030PC30 - tristate "SR030PC30 VGA camera sensor support" - depends on I2C && VIDEO_V4L2 - ---help--- - This driver supports SR030PC30 VGA camera from Siliconfile - config VIDEO_VIA_CAMERA tristate "VIAFB camera controller support" depends on FB_VIA @@ -760,14 +768,6 @@ config VIDEO_VIA_CAMERA Chrome9 chipsets. Currently only tested on OLPC xo-1.5 systems with ov7670 sensors. -config VIDEO_NOON010PC30 - tristate "NOON010PC30 CIF camera sensor support" - depends on I2C && VIDEO_V4L2 && EXPERIMENTAL && VIDEO_V4L2_SUBDEV_API - ---help--- - This driver supports NOON010PC30 CIF camera from Siliconfile - -source "drivers/media/video/m5mols/Kconfig" - config VIDEO_OMAP3 tristate "OMAP 3 Camera support (EXPERIMENTAL)" select OMAP_IOMMU -- cgit v0.10.2 From 6783fe5f16c2fa9b474f096f66b3c8101fc48714 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 28 Jun 2011 10:13:01 -0300 Subject: [media] noon010pc30: Remove g_chip_ident operation handler It is now not needed as the sensor identification is done through the media controller API. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/noon010pc30.c b/drivers/media/video/noon010pc30.c index 935c96b..6cd21cf 100644 --- a/drivers/media/video/noon010pc30.c +++ b/drivers/media/video/noon010pc30.c @@ -629,15 +629,6 @@ static int noon010_s_stream(struct v4l2_subdev *sd, int on) return ret; } -static int noon010_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, - V4L2_IDENT_NOON010PC30, 0); -} - static int noon010_log_status(struct v4l2_subdev *sd) { struct noon010_info *info = to_noon010(sd); @@ -667,7 +658,6 @@ static const struct v4l2_ctrl_ops noon010_ctrl_ops = { }; static const struct v4l2_subdev_core_ops noon010_core_ops = { - .g_chip_ident = noon010_g_chip_ident, .s_power = noon010_s_power, .g_ctrl = v4l2_subdev_g_ctrl, .s_ctrl = v4l2_subdev_s_ctrl, diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h index 63fd9d3..810a209 100644 --- a/include/media/v4l2-chip-ident.h +++ b/include/media/v4l2-chip-ident.h @@ -212,9 +212,6 @@ enum { /* module sn9c20x: just ident 10000 */ V4L2_IDENT_SN9C20X = 10000, - /* Siliconfile sensors: reserved range 10100 - 10199 */ - V4L2_IDENT_NOON010PC30 = 10100, - /* module cx231xx and cx25840 */ V4L2_IDENT_CX2310X_AV = 23099, /* Integrated A/V decoder; not in '100 */ V4L2_IDENT_CX23100 = 23100, -- cgit v0.10.2 From 59152b1cf1182fd671dafa056cebeed95d0b1468 Mon Sep 17 00:00:00 2001 From: tvboxspy Date: Sun, 10 Jul 2011 18:37:13 -0300 Subject: [media] STV0288 frontend provide wider carrier search and DVB-S2 drop out. resend The following patch provides wider carrier search. As with existing code search starts at MSB aligned. The boundary is widened to start at -9. In order to save time, if no carrier is detected at the start it advances to the next alignment until carrier is found. The stv0288 will detect a DVB-S2 carrier on all steps , a time out of 11 steps is introduced to drop out of the loop. In stv0288_set_symbol carrier and timing loops are restored to default values (inittab) before setting the symbol rate on each tune. A slight drift was noticed with full scan in the higher IF frequencies of each band. Signed-off-by: Malcolm Priestley Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/frontends/stv0288.c b/drivers/media/dvb/frontends/stv0288.c index 8e0cfad..0aa3962 100644 --- a/drivers/media/dvb/frontends/stv0288.c +++ b/drivers/media/dvb/frontends/stv0288.c @@ -127,6 +127,11 @@ static int stv0288_set_symbolrate(struct dvb_frontend *fe, u32 srate) if ((srate < 1000000) || (srate > 45000000)) return -EINVAL; + stv0288_writeregI(state, 0x22, 0); + stv0288_writeregI(state, 0x23, 0); + stv0288_writeregI(state, 0x2b, 0xff); + stv0288_writeregI(state, 0x2c, 0xf7); + temp = (unsigned int)srate / 1000; temp = temp * 32768; @@ -461,6 +466,7 @@ static int stv0288_set_frontend(struct dvb_frontend *fe, char tm; unsigned char tda[3]; + u8 reg, time_out = 0; dprintk("%s : FE_SET_FRONTEND\n", __func__); @@ -488,22 +494,29 @@ static int stv0288_set_frontend(struct dvb_frontend *fe, /* Carrier lock control register */ stv0288_writeregI(state, 0x15, 0xc5); - tda[0] = 0x2b; /* CFRM */ tda[2] = 0x0; /* CFRL */ - for (tm = -6; tm < 7;) { + for (tm = -9; tm < 7;) { /* Viterbi status */ - if (stv0288_readreg(state, 0x24) & 0x8) - break; - - tda[2] += 40; - if (tda[2] < 40) + reg = stv0288_readreg(state, 0x24); + if (reg & 0x8) + break; + if (reg & 0x80) { + time_out++; + if (time_out > 10) + break; + tda[2] += 40; + if (tda[2] < 40) + tm++; + } else { tm++; + tda[2] = 0; + time_out = 0; + } tda[1] = (unsigned char)tm; stv0288_writeregI(state, 0x2b, tda[1]); stv0288_writeregI(state, 0x2c, tda[2]); udelay(30); } - state->tuner_frequency = c->frequency; state->fec_inner = FEC_AUTO; state->symbol_rate = c->symbol_rate; -- cgit v0.10.2 From 6f6b90c9231ad6b18f7393e1b6c6cef9dc6aa77c Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Tue, 19 Jul 2011 12:12:47 -0300 Subject: [media] imon: don't parse scancodes until intf configured The imon devices have either 1 or 2 usb interfaces on them, each wired up to its own urb callback. The interface 0 urb callback is wired up before the imon context's rc_dev pointer is filled in, which is necessary for imon 0xffdc device auto-detection to work properly, but we need to make sure we don't actually run the callback routines until we've entirely filled in the necessary bits for each given interface, lest we wind up oopsing. Technically, any imon device could have hit this, but the issue is exacerbated on the 0xffdc devices, which send a constant stream of interrupts, even when they have no valid key data. CC: Andy Walls CC: Chris W Reported-by: Chris W Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index caa3e3a..6ed9646 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -1658,7 +1658,7 @@ static void usb_rx_callback_intf0(struct urb *urb) return; ictx = (struct imon_context *)urb->context; - if (!ictx) + if (!ictx || !ictx->dev_present_intf0) return; switch (urb->status) { @@ -1690,7 +1690,7 @@ static void usb_rx_callback_intf1(struct urb *urb) return; ictx = (struct imon_context *)urb->context; - if (!ictx) + if (!ictx || !ictx->dev_present_intf1) return; switch (urb->status) { @@ -2118,7 +2118,6 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf) ictx->dev = dev; ictx->usbdev_intf0 = usb_get_dev(interface_to_usbdev(intf)); - ictx->dev_present_intf0 = true; ictx->rx_urb_intf0 = rx_urb; ictx->tx_urb = tx_urb; ictx->rf_device = false; @@ -2157,6 +2156,8 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf) goto rdev_setup_failed; } + ictx->dev_present_intf0 = true; + mutex_unlock(&ictx->lock); return ictx; @@ -2200,7 +2201,6 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf, } ictx->usbdev_intf1 = usb_get_dev(interface_to_usbdev(intf)); - ictx->dev_present_intf1 = true; ictx->rx_urb_intf1 = rx_urb; ret = -ENODEV; @@ -2229,6 +2229,8 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf, goto urb_submit_failed; } + ictx->dev_present_intf1 = true; + mutex_unlock(&ictx->lock); return ictx; -- cgit v0.10.2 From ae11e354b80fabdb57ca09a7ff26a89a79396034 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 3 Aug 2011 13:12:26 -0300 Subject: [media] [-mmotm] media: video/adp1653.c needs module.h adp1653.c uses interfaces that are provided by and needs to include that header file to fix build errors. and more. Signed-off-by: Randy Dunlap Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/adp1653.c b/drivers/media/video/adp1653.c index d0e8ac1..2e874c3 100644 --- a/drivers/media/video/adp1653.c +++ b/drivers/media/video/adp1653.c @@ -32,6 +32,7 @@ #include #include +#include #include #include #include -- cgit v0.10.2 From 1e393e90ab444dd24d28448e92bab099703fd006 Mon Sep 17 00:00:00 2001 From: Kamil Debski Date: Mon, 8 Aug 2011 13:12:51 -0300 Subject: [media] media: s5p-mfc: fix section mismatch Fix section mismatch in the MFC driver. Reported-by: Marek Szyprowski Signed-off-by: Kamil Debski Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-mfc/s5p_mfc.c b/drivers/media/video/s5p-mfc/s5p_mfc.c index af32e02..8be8b54 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc.c @@ -940,9 +940,8 @@ static int match_child(struct device *dev, void *data) return !strcmp(dev_name(dev), (char *)data); } - /* MFC probe function */ -static int __devinit s5p_mfc_probe(struct platform_device *pdev) +static int s5p_mfc_probe(struct platform_device *pdev) { struct s5p_mfc_dev *dev; struct video_device *vfd; @@ -1236,7 +1235,7 @@ static const struct dev_pm_ops s5p_mfc_pm_ops = { NULL) }; -static struct platform_driver s5p_mfc_pdrv = { +static struct platform_driver s5p_mfc_driver = { .probe = s5p_mfc_probe, .remove = __devexit_p(s5p_mfc_remove), .driver = { @@ -1254,15 +1253,15 @@ static int __init s5p_mfc_init(void) int ret; pr_info("%s", banner); - ret = platform_driver_register(&s5p_mfc_pdrv); + ret = platform_driver_register(&s5p_mfc_driver); if (ret) pr_err("Platform device registration failed.\n"); return ret; } -static void __devexit s5p_mfc_exit(void) +static void __exit s5p_mfc_exit(void) { - platform_driver_unregister(&s5p_mfc_pdrv); + platform_driver_unregister(&s5p_mfc_driver); } module_init(s5p_mfc_init); -- cgit v0.10.2 From c62e2a19d2b8c884c6f3ab3bb29d6fde2e13d8ac Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 13 Aug 2011 13:09:11 -0300 Subject: [media] omap3isp: Don't fail streamon when the sensor doesn't implement s_stream The code handles subdevs with no s_stream operation correctly, but returns -ENOIOCTLCMD by mistake if the first subdev in the chain has no s_stream operation. Return 0 in that case. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c index 5cea2bb..fda4be0 100644 --- a/drivers/media/video/omap3isp/isp.c +++ b/drivers/media/video/omap3isp/isp.c @@ -732,7 +732,7 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe, struct media_pad *pad; struct v4l2_subdev *subdev; unsigned long flags; - int ret = 0; + int ret; spin_lock_irqsave(&pipe->lock, flags); pipe->state &= ~(ISP_PIPELINE_IDLE_INPUT | ISP_PIPELINE_IDLE_OUTPUT); @@ -756,7 +756,7 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe, ret = v4l2_subdev_call(subdev, video, s_stream, mode); if (ret < 0 && ret != -ENOIOCTLCMD) - break; + return ret; if (subdev == &isp->isp_ccdc.subdev) { v4l2_subdev_call(&isp->isp_aewb.subdev, video, @@ -777,7 +777,7 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe, if (pipe->do_propagation && mode == ISP_PIPELINE_STREAM_SINGLESHOT) atomic_inc(&pipe->frame_number); - return ret; + return 0; } static int isp_pipeline_wait_resizer(struct isp_device *isp) -- cgit v0.10.2 From 5b6c3ef0e43fe80b517735697e4d0fb5729b2ab4 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 13 Aug 2011 13:13:32 -0300 Subject: [media] omap3isp: video: Avoid crashes when pipeline set stream operation fails If streaming can't be enabled on the pipeline, the DMA buffers queue is not emptied. If the buffers then get freed the queue will end up referencing free memory. This is usually not an issue, as the DMA queue will be reinitialized the next time streaming is enabled, before enabling the hardware. However, if the sensor connected at the pipeline input is free-running, the CCDC will start generating interrupts as soon as it gets powered up, before the streaming gets enabled on the hardware. This will make the CCDC interrupt handler access freed memory, causing a crash. Reinitialize the DMA buffers queue in isp_video_streamon() if the error path to make sure this situation won't happen. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c index fd94cdf..ba86f11 100644 --- a/drivers/media/video/omap3isp/ispvideo.c +++ b/drivers/media/video/omap3isp/ispvideo.c @@ -1056,6 +1056,14 @@ error: if (video->isp->pdata->set_constraints) video->isp->pdata->set_constraints(video->isp, false); media_entity_pipeline_stop(&video->video.entity); + /* The DMA queue must be emptied here, otherwise CCDC interrupts + * that will get triggered the next time the CCDC is powered up + * will try to access buffers that might have been freed but + * still present in the DMA queue. This can easily get triggered + * if the above omap3isp_pipeline_set_stream() call fails on a + * system with a free-running sensor. + */ + INIT_LIST_HEAD(&video->dmaqueue); video->queue = NULL; } -- cgit v0.10.2 From 0a54b86a71dfec88d9b12f0e003ebc4ebb4b1f0a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 14 Jun 2010 09:47:50 -0300 Subject: [media] mt9t001: Aptina (Micron) MT9T001 3MP sensor driver The MT9T001 is a parallel 3MP sensor from Aptina (formerly Micron) controlled through I2C. The driver creates a V4L2 subdevice. It currently supports binning and cropping, and the gain, exposure, test pattern and black level controls. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index f41ae69..4a10086 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -474,6 +474,13 @@ config VIDEO_MT9P031 This is a Video4Linux2 sensor-level driver for the Aptina (Micron) mt9p031 5 Mpixel camera. +config VIDEO_MT9T001 + tristate "Aptina MT9T001 support" + depends on I2C && VIDEO_V4L2 + ---help--- + This is a Video4Linux2 sensor-level driver for the Aptina + (Micron) mt0t001 3 Mpixel camera. + config VIDEO_MT9V011 tristate "Micron mt9v011 sensor support" depends on I2C && VIDEO_V4L2 diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index f52a771..0f0c6af 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -66,6 +66,7 @@ obj-$(CONFIG_VIDEO_OV7670) += ov7670.o obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o +obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o diff --git a/drivers/media/video/mt9t001.c b/drivers/media/video/mt9t001.c new file mode 100644 index 0000000..cac1416 --- /dev/null +++ b/drivers/media/video/mt9t001.c @@ -0,0 +1,835 @@ +/* + * Driver for MT9T001 CMOS Image Sensor from Aptina (Micron) + * + * Copyright (C) 2010-2011, Laurent Pinchart + * + * Based on the MT9M001 driver, + * + * Copyright (C) 2008, Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define MT9T001_PIXEL_ARRAY_HEIGHT 1568 +#define MT9T001_PIXEL_ARRAY_WIDTH 2112 + +#define MT9T001_CHIP_VERSION 0x00 +#define MT9T001_CHIP_ID 0x1621 +#define MT9T001_ROW_START 0x01 +#define MT9T001_ROW_START_MIN 0 +#define MT9T001_ROW_START_DEF 20 +#define MT9T001_ROW_START_MAX 1534 +#define MT9T001_COLUMN_START 0x02 +#define MT9T001_COLUMN_START_MIN 0 +#define MT9T001_COLUMN_START_DEF 32 +#define MT9T001_COLUMN_START_MAX 2046 +#define MT9T001_WINDOW_HEIGHT 0x03 +#define MT9T001_WINDOW_HEIGHT_MIN 1 +#define MT9T001_WINDOW_HEIGHT_DEF 1535 +#define MT9T001_WINDOW_HEIGHT_MAX 1567 +#define MT9T001_WINDOW_WIDTH 0x04 +#define MT9T001_WINDOW_WIDTH_MIN 1 +#define MT9T001_WINDOW_WIDTH_DEF 2047 +#define MT9T001_WINDOW_WIDTH_MAX 2111 +#define MT9T001_HORIZONTAL_BLANKING 0x05 +#define MT9T001_HORIZONTAL_BLANKING_MIN 21 +#define MT9T001_HORIZONTAL_BLANKING_MAX 1023 +#define MT9T001_VERTICAL_BLANKING 0x06 +#define MT9T001_VERTICAL_BLANKING_MIN 3 +#define MT9T001_VERTICAL_BLANKING_MAX 1023 +#define MT9T001_OUTPUT_CONTROL 0x07 +#define MT9T001_OUTPUT_CONTROL_SYNC (1 << 0) +#define MT9T001_OUTPUT_CONTROL_CHIP_ENABLE (1 << 1) +#define MT9T001_OUTPUT_CONTROL_TEST_DATA (1 << 6) +#define MT9T001_SHUTTER_WIDTH_HIGH 0x08 +#define MT9T001_SHUTTER_WIDTH_LOW 0x09 +#define MT9T001_SHUTTER_WIDTH_MIN 1 +#define MT9T001_SHUTTER_WIDTH_DEF 1561 +#define MT9T001_SHUTTER_WIDTH_MAX (1024 * 1024) +#define MT9T001_PIXEL_CLOCK 0x0a +#define MT9T001_PIXEL_CLOCK_INVERT (1 << 15) +#define MT9T001_PIXEL_CLOCK_SHIFT_MASK (7 << 8) +#define MT9T001_PIXEL_CLOCK_SHIFT_SHIFT 8 +#define MT9T001_PIXEL_CLOCK_DIVIDE_MASK (0x7f << 0) +#define MT9T001_FRAME_RESTART 0x0b +#define MT9T001_SHUTTER_DELAY 0x0c +#define MT9T001_SHUTTER_DELAY_MAX 2047 +#define MT9T001_RESET 0x0d +#define MT9T001_READ_MODE1 0x1e +#define MT9T001_READ_MODE_SNAPSHOT (1 << 8) +#define MT9T001_READ_MODE_STROBE_ENABLE (1 << 9) +#define MT9T001_READ_MODE_STROBE_WIDTH (1 << 10) +#define MT9T001_READ_MODE_STROBE_OVERRIDE (1 << 11) +#define MT9T001_READ_MODE2 0x20 +#define MT9T001_READ_MODE_BAD_FRAMES (1 << 0) +#define MT9T001_READ_MODE_LINE_VALID_CONTINUOUS (1 << 9) +#define MT9T001_READ_MODE_LINE_VALID_FRAME (1 << 10) +#define MT9T001_READ_MODE3 0x21 +#define MT9T001_READ_MODE_GLOBAL_RESET (1 << 0) +#define MT9T001_READ_MODE_GHST_CTL (1 << 1) +#define MT9T001_ROW_ADDRESS_MODE 0x22 +#define MT9T001_ROW_SKIP_MASK (7 << 0) +#define MT9T001_ROW_BIN_MASK (3 << 3) +#define MT9T001_ROW_BIN_SHIFT 3 +#define MT9T001_COLUMN_ADDRESS_MODE 0x23 +#define MT9T001_COLUMN_SKIP_MASK (7 << 0) +#define MT9T001_COLUMN_BIN_MASK (3 << 3) +#define MT9T001_COLUMN_BIN_SHIFT 3 +#define MT9T001_GREEN1_GAIN 0x2b +#define MT9T001_BLUE_GAIN 0x2c +#define MT9T001_RED_GAIN 0x2d +#define MT9T001_GREEN2_GAIN 0x2e +#define MT9T001_TEST_DATA 0x32 +#define MT9T001_GLOBAL_GAIN 0x35 +#define MT9T001_GLOBAL_GAIN_MIN 8 +#define MT9T001_GLOBAL_GAIN_MAX 1024 +#define MT9T001_BLACK_LEVEL 0x49 +#define MT9T001_ROW_BLACK_DEFAULT_OFFSET 0x4b +#define MT9T001_BLC_DELTA_THRESHOLDS 0x5d +#define MT9T001_CAL_THRESHOLDS 0x5f +#define MT9T001_GREEN1_OFFSET 0x60 +#define MT9T001_GREEN2_OFFSET 0x61 +#define MT9T001_BLACK_LEVEL_CALIBRATION 0x62 +#define MT9T001_BLACK_LEVEL_OVERRIDE (1 << 0) +#define MT9T001_BLACK_LEVEL_DISABLE_OFFSET (1 << 1) +#define MT9T001_BLACK_LEVEL_RECALCULATE (1 << 12) +#define MT9T001_BLACK_LEVEL_LOCK_RED_BLUE (1 << 13) +#define MT9T001_BLACK_LEVEL_LOCK_GREEN (1 << 14) +#define MT9T001_RED_OFFSET 0x63 +#define MT9T001_BLUE_OFFSET 0x64 + +struct mt9t001 { + struct v4l2_subdev subdev; + struct media_pad pad; + + struct v4l2_mbus_framefmt format; + struct v4l2_rect crop; + + struct v4l2_ctrl_handler ctrls; + struct v4l2_ctrl *gains[4]; + + u16 output_control; + u16 black_level; +}; + +static inline struct mt9t001 *to_mt9t001(struct v4l2_subdev *sd) +{ + return container_of(sd, struct mt9t001, subdev); +} + +static int mt9t001_read(struct i2c_client *client, u8 reg) +{ + s32 data = i2c_smbus_read_word_data(client, reg); + return data < 0 ? data : be16_to_cpu(data); +} + +static int mt9t001_write(struct i2c_client *client, u8 reg, u16 data) +{ + return i2c_smbus_write_word_data(client, reg, cpu_to_be16(data)); +} + +static int mt9t001_set_output_control(struct mt9t001 *mt9t001, u16 clear, + u16 set) +{ + struct i2c_client *client = v4l2_get_subdevdata(&mt9t001->subdev); + u16 value = (mt9t001->output_control & ~clear) | set; + int ret; + + if (value == mt9t001->output_control) + return 0; + + ret = mt9t001_write(client, MT9T001_OUTPUT_CONTROL, value); + if (ret < 0) + return ret; + + mt9t001->output_control = value; + return 0; +} + +/* ----------------------------------------------------------------------------- + * V4L2 subdev video operations + */ + +static struct v4l2_mbus_framefmt * +__mt9t001_get_pad_format(struct mt9t001 *mt9t001, struct v4l2_subdev_fh *fh, + unsigned int pad, enum v4l2_subdev_format_whence which) +{ + switch (which) { + case V4L2_SUBDEV_FORMAT_TRY: + return v4l2_subdev_get_try_format(fh, pad); + case V4L2_SUBDEV_FORMAT_ACTIVE: + return &mt9t001->format; + default: + return NULL; + } +} + +static struct v4l2_rect * +__mt9t001_get_pad_crop(struct mt9t001 *mt9t001, struct v4l2_subdev_fh *fh, + unsigned int pad, enum v4l2_subdev_format_whence which) +{ + switch (which) { + case V4L2_SUBDEV_FORMAT_TRY: + return v4l2_subdev_get_try_crop(fh, pad); + case V4L2_SUBDEV_FORMAT_ACTIVE: + return &mt9t001->crop; + default: + return NULL; + } +} + +static int mt9t001_s_stream(struct v4l2_subdev *subdev, int enable) +{ + const u16 mode = MT9T001_OUTPUT_CONTROL_CHIP_ENABLE; + struct i2c_client *client = v4l2_get_subdevdata(subdev); + struct mt9t001 *mt9t001 = to_mt9t001(subdev); + struct v4l2_mbus_framefmt *format = &mt9t001->format; + struct v4l2_rect *crop = &mt9t001->crop; + unsigned int hratio; + unsigned int vratio; + int ret; + + if (!enable) + return mt9t001_set_output_control(mt9t001, mode, 0); + + /* Configure the window size and row/column bin */ + hratio = DIV_ROUND_CLOSEST(crop->width, format->width); + vratio = DIV_ROUND_CLOSEST(crop->height, format->height); + + ret = mt9t001_write(client, MT9T001_ROW_ADDRESS_MODE, hratio - 1); + if (ret < 0) + return ret; + + ret = mt9t001_write(client, MT9T001_COLUMN_ADDRESS_MODE, vratio - 1); + if (ret < 0) + return ret; + + ret = mt9t001_write(client, MT9T001_COLUMN_START, crop->left); + if (ret < 0) + return ret; + + ret = mt9t001_write(client, MT9T001_ROW_START, crop->top); + if (ret < 0) + return ret; + + ret = mt9t001_write(client, MT9T001_WINDOW_WIDTH, crop->width - 1); + if (ret < 0) + return ret; + + ret = mt9t001_write(client, MT9T001_WINDOW_HEIGHT, crop->height - 1); + if (ret < 0) + return ret; + + /* Switch to master "normal" mode */ + return mt9t001_set_output_control(mt9t001, 0, mode); +} + +static int mt9t001_enum_mbus_code(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index > 0) + return -EINVAL; + + code->code = V4L2_MBUS_FMT_SGRBG10_1X10; + return 0; +} + +static int mt9t001_enum_frame_size(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index >= 8 || fse->code != V4L2_MBUS_FMT_SGRBG10_1X10) + return -EINVAL; + + fse->min_width = (MT9T001_WINDOW_WIDTH_DEF + 1) / fse->index; + fse->max_width = fse->min_width; + fse->min_height = (MT9T001_WINDOW_HEIGHT_DEF + 1) / fse->index; + fse->max_height = fse->min_height; + + return 0; +} + +static int mt9t001_get_format(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *format) +{ + struct mt9t001 *mt9t001 = to_mt9t001(subdev); + + format->format = *__mt9t001_get_pad_format(mt9t001, fh, format->pad, + format->which); + return 0; +} + +static int mt9t001_set_format(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *format) +{ + struct mt9t001 *mt9t001 = to_mt9t001(subdev); + struct v4l2_mbus_framefmt *__format; + struct v4l2_rect *__crop; + unsigned int width; + unsigned int height; + unsigned int hratio; + unsigned int vratio; + + __crop = __mt9t001_get_pad_crop(mt9t001, fh, format->pad, + format->which); + + /* Clamp the width and height to avoid dividing by zero. */ + width = clamp_t(unsigned int, ALIGN(format->format.width, 2), + max(__crop->width / 8, MT9T001_WINDOW_HEIGHT_MIN + 1), + __crop->width); + height = clamp_t(unsigned int, ALIGN(format->format.height, 2), + max(__crop->height / 8, MT9T001_WINDOW_HEIGHT_MIN + 1), + __crop->height); + + hratio = DIV_ROUND_CLOSEST(__crop->width, width); + vratio = DIV_ROUND_CLOSEST(__crop->height, height); + + __format = __mt9t001_get_pad_format(mt9t001, fh, format->pad, + format->which); + __format->width = __crop->width / hratio; + __format->height = __crop->height / vratio; + + format->format = *__format; + + return 0; +} + +static int mt9t001_get_crop(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_crop *crop) +{ + struct mt9t001 *mt9t001 = to_mt9t001(subdev); + + crop->rect = *__mt9t001_get_pad_crop(mt9t001, fh, crop->pad, + crop->which); + return 0; +} + +static int mt9t001_set_crop(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_crop *crop) +{ + struct mt9t001 *mt9t001 = to_mt9t001(subdev); + struct v4l2_mbus_framefmt *__format; + struct v4l2_rect *__crop; + struct v4l2_rect rect; + + /* Clamp the crop rectangle boundaries and align them to a multiple of 2 + * pixels. + */ + rect.left = clamp(ALIGN(crop->rect.left, 2), + MT9T001_COLUMN_START_MIN, + MT9T001_COLUMN_START_MAX); + rect.top = clamp(ALIGN(crop->rect.top, 2), + MT9T001_ROW_START_MIN, + MT9T001_ROW_START_MAX); + rect.width = clamp(ALIGN(crop->rect.width, 2), + MT9T001_WINDOW_WIDTH_MIN + 1, + MT9T001_WINDOW_WIDTH_MAX + 1); + rect.height = clamp(ALIGN(crop->rect.height, 2), + MT9T001_WINDOW_HEIGHT_MIN + 1, + MT9T001_WINDOW_HEIGHT_MAX + 1); + + rect.width = min(rect.width, MT9T001_PIXEL_ARRAY_WIDTH - rect.left); + rect.height = min(rect.height, MT9T001_PIXEL_ARRAY_HEIGHT - rect.top); + + __crop = __mt9t001_get_pad_crop(mt9t001, fh, crop->pad, crop->which); + + if (rect.width != __crop->width || rect.height != __crop->height) { + /* Reset the output image size if the crop rectangle size has + * been modified. + */ + __format = __mt9t001_get_pad_format(mt9t001, fh, crop->pad, + crop->which); + __format->width = rect.width; + __format->height = rect.height; + } + + *__crop = rect; + crop->rect = rect; + + return 0; +} + +/* ----------------------------------------------------------------------------- + * V4L2 subdev control operations + */ + +#define V4L2_CID_TEST_PATTERN (V4L2_CID_USER_BASE | 0x1001) +#define V4L2_CID_BLACK_LEVEL_AUTO (V4L2_CID_USER_BASE | 0x1002) +#define V4L2_CID_BLACK_LEVEL_OFFSET (V4L2_CID_USER_BASE | 0x1003) +#define V4L2_CID_BLACK_LEVEL_CALIBRATE (V4L2_CID_USER_BASE | 0x1004) + +#define V4L2_CID_GAIN_RED (V4L2_CTRL_CLASS_CAMERA | 0x1001) +#define V4L2_CID_GAIN_GREEN_RED (V4L2_CTRL_CLASS_CAMERA | 0x1002) +#define V4L2_CID_GAIN_GREEN_BLUE (V4L2_CTRL_CLASS_CAMERA | 0x1003) +#define V4L2_CID_GAIN_BLUE (V4L2_CTRL_CLASS_CAMERA | 0x1004) + +static u16 mt9t001_gain_value(s32 *gain) +{ + /* Gain is controlled by 2 analog stages and a digital stage. Valid + * values for the 3 stages are + * + * Stage Min Max Step + * ------------------------------------------ + * First analog stage x1 x2 1 + * Second analog stage x1 x4 0.125 + * Digital stage x1 x16 0.125 + * + * To minimize noise, the gain stages should be used in the second + * analog stage, first analog stage, digital stage order. Gain from a + * previous stage should be pushed to its maximum value before the next + * stage is used. + */ + if (*gain <= 32) + return *gain; + + if (*gain <= 64) { + *gain &= ~1; + return (1 << 6) | (*gain >> 1); + } + + *gain &= ~7; + return ((*gain - 64) << 5) | (1 << 6) | 32; +} + +static int mt9t001_ctrl_freeze(struct mt9t001 *mt9t001, bool freeze) +{ + return mt9t001_set_output_control(mt9t001, + freeze ? 0 : MT9T001_OUTPUT_CONTROL_SYNC, + freeze ? MT9T001_OUTPUT_CONTROL_SYNC : 0); +} + +static int mt9t001_s_ctrl(struct v4l2_ctrl *ctrl) +{ + static const u8 gains[4] = { + MT9T001_RED_GAIN, MT9T001_GREEN1_GAIN, + MT9T001_GREEN2_GAIN, MT9T001_BLUE_GAIN + }; + + struct mt9t001 *mt9t001 = + container_of(ctrl->handler, struct mt9t001, ctrls); + struct i2c_client *client = v4l2_get_subdevdata(&mt9t001->subdev); + unsigned int count; + unsigned int i; + u16 value; + int ret; + + switch (ctrl->id) { + case V4L2_CID_GAIN_RED: + case V4L2_CID_GAIN_GREEN_RED: + case V4L2_CID_GAIN_GREEN_BLUE: + case V4L2_CID_GAIN_BLUE: + + /* Disable control updates if more than one control has changed + * in the cluster. + */ + for (i = 0, count = 0; i < 4; ++i) { + struct v4l2_ctrl *gain = mt9t001->gains[i]; + + if (gain->val != gain->cur.val) + count++; + } + + if (count > 1) { + ret = mt9t001_ctrl_freeze(mt9t001, true); + if (ret < 0) + return ret; + } + + /* Update the gain controls. */ + for (i = 0; i < 4; ++i) { + struct v4l2_ctrl *gain = mt9t001->gains[i]; + + if (gain->val == gain->cur.val) + continue; + + value = mt9t001_gain_value(&gain->val); + ret = mt9t001_write(client, gains[i], value); + if (ret < 0) { + mt9t001_ctrl_freeze(mt9t001, false); + return ret; + } + } + + /* Enable control updates. */ + if (count > 1) { + ret = mt9t001_ctrl_freeze(mt9t001, false); + if (ret < 0) + return ret; + } + + break; + + case V4L2_CID_EXPOSURE: + ret = mt9t001_write(client, MT9T001_SHUTTER_WIDTH_LOW, + ctrl->val & 0xffff); + if (ret < 0) + return ret; + + return mt9t001_write(client, MT9T001_SHUTTER_WIDTH_HIGH, + ctrl->val >> 16); + + case V4L2_CID_TEST_PATTERN: + ret = mt9t001_set_output_control(mt9t001, + ctrl->val ? 0 : MT9T001_OUTPUT_CONTROL_TEST_DATA, + ctrl->val ? MT9T001_OUTPUT_CONTROL_TEST_DATA : 0); + if (ret < 0) + return ret; + + return mt9t001_write(client, MT9T001_TEST_DATA, ctrl->val << 2); + + case V4L2_CID_BLACK_LEVEL_AUTO: + value = ctrl->val ? 0 : MT9T001_BLACK_LEVEL_OVERRIDE; + ret = mt9t001_write(client, MT9T001_BLACK_LEVEL_CALIBRATION, + value); + if (ret < 0) + return ret; + + mt9t001->black_level = value; + break; + + case V4L2_CID_BLACK_LEVEL_OFFSET: + ret = mt9t001_write(client, MT9T001_GREEN1_OFFSET, ctrl->val); + if (ret < 0) + return ret; + + ret = mt9t001_write(client, MT9T001_GREEN2_OFFSET, ctrl->val); + if (ret < 0) + return ret; + + ret = mt9t001_write(client, MT9T001_RED_OFFSET, ctrl->val); + if (ret < 0) + return ret; + + return mt9t001_write(client, MT9T001_BLUE_OFFSET, ctrl->val); + + case V4L2_CID_BLACK_LEVEL_CALIBRATE: + return mt9t001_write(client, MT9T001_BLACK_LEVEL_CALIBRATION, + MT9T001_BLACK_LEVEL_RECALCULATE | + mt9t001->black_level); + } + + return 0; +} + +static struct v4l2_ctrl_ops mt9t001_ctrl_ops = { + .s_ctrl = mt9t001_s_ctrl, +}; + +static const struct v4l2_ctrl_config mt9t001_ctrls[] = { + { + .ops = &mt9t001_ctrl_ops, + .id = V4L2_CID_TEST_PATTERN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Test pattern", + .min = 0, + .max = 1023, + .step = 1, + .def = 0, + .flags = 0, + }, { + .ops = &mt9t001_ctrl_ops, + .id = V4L2_CID_BLACK_LEVEL_AUTO, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Black Level, Auto", + .min = 0, + .max = 1, + .step = 1, + .def = 1, + .flags = 0, + }, { + .ops = &mt9t001_ctrl_ops, + .id = V4L2_CID_BLACK_LEVEL_OFFSET, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Black Level, Offset", + .min = -256, + .max = 255, + .step = 1, + .def = 32, + .flags = 0, + }, { + .ops = &mt9t001_ctrl_ops, + .id = V4L2_CID_BLACK_LEVEL_CALIBRATE, + .type = V4L2_CTRL_TYPE_BUTTON, + .name = "Black Level, Calibrate", + .min = 0, + .max = 0, + .step = 0, + .def = 0, + .flags = V4L2_CTRL_FLAG_WRITE_ONLY, + }, +}; + +static const struct v4l2_ctrl_config mt9t001_gains[] = { + { + .ops = &mt9t001_ctrl_ops, + .id = V4L2_CID_GAIN_RED, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain, Red", + .min = MT9T001_GLOBAL_GAIN_MIN, + .max = MT9T001_GLOBAL_GAIN_MAX, + .step = 1, + .def = MT9T001_GLOBAL_GAIN_MIN, + .flags = 0, + }, { + .ops = &mt9t001_ctrl_ops, + .id = V4L2_CID_GAIN_GREEN_RED, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain, Green (R)", + .min = MT9T001_GLOBAL_GAIN_MIN, + .max = MT9T001_GLOBAL_GAIN_MAX, + .step = 1, + .def = MT9T001_GLOBAL_GAIN_MIN, + .flags = 0, + }, { + .ops = &mt9t001_ctrl_ops, + .id = V4L2_CID_GAIN_GREEN_BLUE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain, Green (B)", + .min = MT9T001_GLOBAL_GAIN_MIN, + .max = MT9T001_GLOBAL_GAIN_MAX, + .step = 1, + .def = MT9T001_GLOBAL_GAIN_MIN, + .flags = 0, + }, { + .ops = &mt9t001_ctrl_ops, + .id = V4L2_CID_GAIN_BLUE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain, Blue", + .min = MT9T001_GLOBAL_GAIN_MIN, + .max = MT9T001_GLOBAL_GAIN_MAX, + .step = 1, + .def = MT9T001_GLOBAL_GAIN_MIN, + .flags = 0, + }, +}; + +/* ----------------------------------------------------------------------------- + * V4L2 subdev internal operations + */ + +static int mt9t001_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) +{ + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; + + crop = v4l2_subdev_get_try_crop(fh, 0); + crop->left = MT9T001_COLUMN_START_DEF; + crop->top = MT9T001_ROW_START_DEF; + crop->width = MT9T001_WINDOW_WIDTH_DEF + 1; + crop->height = MT9T001_WINDOW_HEIGHT_DEF + 1; + + format = v4l2_subdev_get_try_format(fh, 0); + format->code = V4L2_MBUS_FMT_SGRBG10_1X10; + format->width = MT9T001_WINDOW_WIDTH_DEF + 1; + format->height = MT9T001_WINDOW_HEIGHT_DEF + 1; + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_SRGB; + + return 0; +} + +static struct v4l2_subdev_video_ops mt9t001_subdev_video_ops = { + .s_stream = mt9t001_s_stream, +}; + +static struct v4l2_subdev_pad_ops mt9t001_subdev_pad_ops = { + .enum_mbus_code = mt9t001_enum_mbus_code, + .enum_frame_size = mt9t001_enum_frame_size, + .get_fmt = mt9t001_get_format, + .set_fmt = mt9t001_set_format, + .get_crop = mt9t001_get_crop, + .set_crop = mt9t001_set_crop, +}; + +static struct v4l2_subdev_ops mt9t001_subdev_ops = { + .video = &mt9t001_subdev_video_ops, + .pad = &mt9t001_subdev_pad_ops, +}; + +static struct v4l2_subdev_internal_ops mt9t001_subdev_internal_ops = { + .open = mt9t001_open, +}; + +static int mt9t001_video_probe(struct i2c_client *client) +{ + struct mt9t001_platform_data *pdata = client->dev.platform_data; + s32 data; + int ret; + + dev_info(&client->dev, "Probing MT9T001 at address 0x%02x\n", + client->addr); + + /* Reset the chip and stop data read out */ + ret = mt9t001_write(client, MT9T001_RESET, 1); + if (ret < 0) + return ret; + + ret = mt9t001_write(client, MT9T001_RESET, 0); + if (ret < 0) + return ret; + + ret = mt9t001_write(client, MT9T001_OUTPUT_CONTROL, 0); + if (ret < 0) + return ret; + + /* Configure the pixel clock polarity */ + if (pdata && pdata->clk_pol) { + ret = mt9t001_write(client, MT9T001_PIXEL_CLOCK, + MT9T001_PIXEL_CLOCK_INVERT); + if (ret < 0) + return ret; + } + + /* Read and check the sensor version */ + data = mt9t001_read(client, MT9T001_CHIP_VERSION); + if (data != MT9T001_CHIP_ID) { + dev_err(&client->dev, "MT9T001 not detected, wrong version " + "0x%04x\n", data); + return -ENODEV; + } + + dev_info(&client->dev, "MT9T001 detected at address 0x%02x\n", + client->addr); + + return ret; +} + +static int mt9t001_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct mt9t001 *mt9t001; + unsigned int i; + int ret; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_WORD_DATA)) { + dev_warn(&client->adapter->dev, + "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); + return -EIO; + } + + ret = mt9t001_video_probe(client); + if (ret < 0) + return ret; + + mt9t001 = kzalloc(sizeof(*mt9t001), GFP_KERNEL); + if (!mt9t001) + return -ENOMEM; + + v4l2_ctrl_handler_init(&mt9t001->ctrls, ARRAY_SIZE(mt9t001_ctrls) + + ARRAY_SIZE(mt9t001_gains) + 2); + + v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops, + V4L2_CID_EXPOSURE, MT9T001_SHUTTER_WIDTH_MIN, + MT9T001_SHUTTER_WIDTH_MAX, 1, + MT9T001_SHUTTER_WIDTH_DEF); + v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops, + V4L2_CID_BLACK_LEVEL, 1, 1, 1, 1); + + for (i = 0; i < ARRAY_SIZE(mt9t001_ctrls); ++i) + v4l2_ctrl_new_custom(&mt9t001->ctrls, &mt9t001_ctrls[i], NULL); + + for (i = 0; i < ARRAY_SIZE(mt9t001_gains); ++i) + mt9t001->gains[i] = v4l2_ctrl_new_custom(&mt9t001->ctrls, + &mt9t001_gains[i], NULL); + + v4l2_ctrl_cluster(ARRAY_SIZE(mt9t001_gains), mt9t001->gains); + + mt9t001->subdev.ctrl_handler = &mt9t001->ctrls; + + if (mt9t001->ctrls.error) { + printk(KERN_INFO "%s: control initialization error %d\n", + __func__, mt9t001->ctrls.error); + ret = -EINVAL; + goto done; + } + + mt9t001->crop.left = MT9T001_COLUMN_START_DEF; + mt9t001->crop.top = MT9T001_ROW_START_DEF; + mt9t001->crop.width = MT9T001_WINDOW_WIDTH_DEF + 1; + mt9t001->crop.height = MT9T001_WINDOW_HEIGHT_DEF + 1; + + mt9t001->format.code = V4L2_MBUS_FMT_SGRBG10_1X10; + mt9t001->format.width = MT9T001_WINDOW_WIDTH_DEF + 1; + mt9t001->format.height = MT9T001_WINDOW_HEIGHT_DEF + 1; + mt9t001->format.field = V4L2_FIELD_NONE; + mt9t001->format.colorspace = V4L2_COLORSPACE_SRGB; + + v4l2_i2c_subdev_init(&mt9t001->subdev, client, &mt9t001_subdev_ops); + mt9t001->subdev.internal_ops = &mt9t001_subdev_internal_ops; + mt9t001->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + mt9t001->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_init(&mt9t001->subdev.entity, 1, &mt9t001->pad, 0); + +done: + if (ret < 0) { + v4l2_ctrl_handler_free(&mt9t001->ctrls); + media_entity_cleanup(&mt9t001->subdev.entity); + kfree(mt9t001); + } + + return ret; +} + +static int mt9t001_remove(struct i2c_client *client) +{ + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct mt9t001 *mt9t001 = to_mt9t001(subdev); + + v4l2_ctrl_handler_free(&mt9t001->ctrls); + v4l2_device_unregister_subdev(subdev); + media_entity_cleanup(&subdev->entity); + kfree(mt9t001); + return 0; +} + +static const struct i2c_device_id mt9t001_id[] = { + { "mt9t001", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mt9t001_id); + +static struct i2c_driver mt9t001_driver = { + .driver = { + .name = "mt9t001", + }, + .probe = mt9t001_probe, + .remove = mt9t001_remove, + .id_table = mt9t001_id, +}; + +static int __init mt9t001_init(void) +{ + return i2c_add_driver(&mt9t001_driver); +} + +static void __exit mt9t001_exit(void) +{ + i2c_del_driver(&mt9t001_driver); +} + +module_init(mt9t001_init); +module_exit(mt9t001_exit); + +MODULE_DESCRIPTION("Aptina (Micron) MT9T001 Camera driver"); +MODULE_AUTHOR("Laurent Pinchart "); +MODULE_LICENSE("GPL"); diff --git a/include/media/mt9t001.h b/include/media/mt9t001.h new file mode 100644 index 0000000..e839a78 --- /dev/null +++ b/include/media/mt9t001.h @@ -0,0 +1,8 @@ +#ifndef _MEDIA_MT9T001_H +#define _MEDIA_MT9T001_H + +struct mt9t001_platform_data { + unsigned int clk_pol:1; +}; + +#endif -- cgit v0.10.2 From 42845708363fc92a190f5c47e6fe750e3919f867 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 1 Sep 2011 02:43:03 -0300 Subject: [media] tm6000: Add fast USB access quirk Some devices support fast access to registers using the USB interface while others require a certain delay after each operation. This commit adds a quirk that can be enabled by devices that don't need the delay. Signed-off-by: Thierry Reding Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/tm6000/tm6000-core.c b/drivers/staging/tm6000/tm6000-core.c index b3c4e05..6d0803c 100644 --- a/drivers/staging/tm6000/tm6000-core.c +++ b/drivers/staging/tm6000/tm6000-core.c @@ -619,7 +619,8 @@ int tm6000_reset(struct tm6000_core *dev) return err; } - msleep(5); + if ((dev->quirks & TM6000_QUIRK_NO_USB_DELAY) == 0) + msleep(5); /* * Not all devices have int_in defined diff --git a/drivers/staging/tm6000/tm6000.h b/drivers/staging/tm6000/tm6000.h index dac2063..5bdce84 100644 --- a/drivers/staging/tm6000/tm6000.h +++ b/drivers/staging/tm6000/tm6000.h @@ -169,6 +169,8 @@ struct tm6000_endpoint { unsigned maxsize; }; +#define TM6000_QUIRK_NO_USB_DELAY (1 << 0) + struct tm6000_core { /* generic device properties */ char name[30]; /* name (including minor) of the device */ @@ -260,6 +262,8 @@ struct tm6000_core { struct usb_isoc_ctl isoc_ctl; spinlock_t slock; + + unsigned long quirks; }; enum tm6000_ops_type { -- cgit v0.10.2 From 6e89648195eba51ae7f6de9104fdb2e0920b4aef Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 1 Sep 2011 02:43:04 -0300 Subject: [media] tm6000: Enable fast USB quirk on Cinergy Hybrid The Cinergy Hybrid cards are known not to need an artificial delay after USB accesses so the quirk can safely be enabled. Signed-off-by: Thierry Reding Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c index 8483c56..ec2578a 100644 --- a/drivers/staging/tm6000/tm6000-cards.c +++ b/drivers/staging/tm6000/tm6000-cards.c @@ -999,6 +999,16 @@ static int fill_board_specific_data(struct tm6000_core *dev) dev->vinput[2] = tm6000_boards[dev->model].vinput[2]; dev->rinput = tm6000_boards[dev->model].rinput; + /* setup per-model quirks */ + switch (dev->model) { + case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: + dev->quirks |= TM6000_QUIRK_NO_USB_DELAY; + break; + + default: + break; + } + /* initialize hardware */ rc = tm6000_init(dev); if (rc < 0) -- cgit v0.10.2 From 9da9f356dc73c2ae65a15a1c1d6e53142706e96b Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Sun, 4 Sep 2011 15:26:21 -0300 Subject: [media] em28xx: Fix em28xx_devused cleanup logic on error On 04/09/11 00:49, Mauro Carvalho Chehab wrote: > This is an automatic generated email to let you know that the following patch were queued at the > http://git.linuxtv.org/media_tree.git tree: > > Subject: [media] em28xx: use atomic bit operations for devices-in-use mask > Author: Chris Rankin > Date: Sat Aug 20 08:21:03 2011 -0300 > > Use atomic bit operations for the em28xx_devused mask, to prevent an > unlikely race condition should two adapters be plugged in > simultaneously. The operations also clearer than explicit bit > manipulation anyway. > > Signed-off-by: Chris Rankin > Signed-off-by: Mauro Carvalho Chehab > > drivers/media/video/em28xx/em28xx-cards.c | 33 ++++++++++++++--------------- I think you missed this line in the merge. Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 4bdf2d0..7425f92 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -3114,7 +3114,6 @@ static int em28xx_usb_probe(struct usb_interface *interface, em28xx_err(DRIVER_NAME " This is an anciliary " "interface not used by the driver\n"); - em28xx_devused &= ~(1< Date: Tue, 6 Sep 2011 08:08:08 -0300 Subject: [media] v4l2: uvcvideo use after free bug fix Unplugging uvc video camera trigger following oops: eeepc kernel: [ 1393.500719] usb 3-2: USB disconnect, device number 4 eeepc kernel: [ 1393.504351] uvcvideo: Failed to resubmit video URB (-19). eeepc kernel: [ 1495.428853] BUG: unable to handle kernel paging request at 6b6b6bcb eeepc kernel: [ 1495.429017] IP: [] dev_get_drvdata+0x17/0x20 eeepc kernel: [ 1495.429017] *pde = 00000000 eeepc kernel: [ 1495.429017] Oops: 0000 [#1] DEBUG_PAGEALLOC eeepc kernel: [ 1495.429017] eeepc kernel: [ 1495.429017] Pid: 3476, comm: cheese Not tainted 3.1.0-rc3-00270-g7a54f5e-dirty #485 ASUSTeK Computer INC. 900/900 eeepc kernel: [ 1495.429017] EIP: 0060:[] EFLAGS: 00010202 CPU: 0 eeepc kernel: [ 1495.429017] EIP is at dev_get_drvdata+0x17/0x20 eeepc kernel: [ 1495.429017] EAX: 6b6b6b6b EBX: eb08d870 ECX: 00000000 EDX: eb08d930 eeepc kernel: [ 1495.429017] ESI: eb08d870 EDI: eb08d870 EBP: d3249cac ESP: d3249cac eeepc kernel: [ 1495.429017] DS: 007b ES: 007b FS: 0000 GS: 00e0 SS: 0068 eeepc kernel: [ 1495.429017] Process cheese (pid: 3476, ti=d3248000 task=df46d870 task.ti=d3248000) eeepc kernel: [ 1495.429017] Stack: eeepc kernel: [ 1495.429017] d3249cb8 b03e77a1 d307b840 d3249ccc b03e77d1 d307b840 eb08d870 eb08d830 eeepc kernel: [ 1495.429017] d3249ce4 b03ed3b7 00000246 d307b840 eb08d870 d3021b80 d3249cec b03ed565 eeepc kernel: [ 1495.429017] d3249cfc b03e044d e8323d10 b06e013c d3249d18 b0355fb9 fffffffe d3249d1c eeepc kernel: [ 1495.429017] Call Trace: eeepc kernel: [ 1495.429017] [] v4l2_device_disconnect+0x11/0x30 eeepc kernel: [ 1495.429017] [] v4l2_device_unregister+0x11/0x50 eeepc kernel: [ 1495.429017] [] uvc_delete+0x37/0x110 eeepc kernel: [ 1495.429017] [] uvc_release+0x25/0x30 eeepc kernel: [ 1495.429017] [] v4l2_device_release+0x9d/0xc0 eeepc kernel: [ 1495.429017] [] device_release+0x19/0x90 eeepc kernel: [ 1495.429017] [] ? usb_hcd_unlink_urb+0x7c/0x90 eeepc kernel: [ 1495.429017] [] kobject_release+0x3c/0x90 eeepc kernel: [ 1495.429017] [] ? kobject_del+0x30/0x30 eeepc kernel: [ 1495.429017] [] kref_put+0x2c/0x60 eeepc kernel: [ 1495.429017] [] kobject_put+0x1d/0x50 eeepc kernel: [ 1495.429017] [] ? usb_autopm_put_interface+0x25/0x30 eeepc kernel: [ 1495.429017] [] ? uvc_v4l2_release+0x5d/0xd0 eeepc kernel: [ 1495.429017] [] put_device+0xf/0x20 eeepc kernel: [ 1495.429017] [] v4l2_release+0x56/0x60 eeepc kernel: [ 1495.429017] [] fput+0xcc/0x220 eeepc kernel: [ 1495.429017] [] filp_close+0x44/0x70 eeepc kernel: [ 1495.429017] [] put_files_struct+0x158/0x180 eeepc kernel: [ 1495.429017] [] ? put_files_struct+0x20/0x180 eeepc kernel: [ 1495.429017] [] exit_files+0x40/0x50 eeepc kernel: [ 1495.429017] [] do_exit+0x5a7/0x660 eeepc kernel: [ 1495.429017] [] ? __dequeue_signal+0x12/0x120 eeepc kernel: [ 1495.429017] [] ? _raw_spin_unlock_irq+0x22/0x30 eeepc kernel: [ 1495.429017] [] do_group_exit+0x3c/0xb0 eeepc kernel: [ 1495.429017] [] ? trace_hardirqs_on+0xb/0x10 eeepc kernel: [ 1495.429017] [] get_signal_to_deliver+0x18f/0x570 eeepc kernel: [ 1495.429017] [] do_signal+0x47/0x9e0 eeepc kernel: [ 1495.429017] [] ? _raw_spin_unlock_irq+0x22/0x30 eeepc kernel: [ 1495.429017] [] ? trace_hardirqs_on+0xb/0x10 eeepc kernel: [ 1495.429017] [] ? T.1034+0x30/0xc0 eeepc kernel: [ 1495.429017] [] ? schedule+0x29f/0x640 eeepc kernel: [ 1495.429017] [] do_notify_resume+0x38/0x40 eeepc kernel: [ 1495.429017] [] work_notifysig+0x9/0x11 eeepc kernel: [ 1495.429017] Code: e5 5d 83 f8 01 19 c0 f7 d0 83 e0 f0 c3 8d b4 26 00 00 00 00 55 85 c0 89 e5 75 09 31 c0 5d c3 90 8d 74 26 00 8b 40 04 85 c0 74 f0 <8b> 40 60 5d c3 8d 74 26 00 55 89 e5 53 89 c3 83 ec 04 8b 40 04 eeepc kernel: [ 1495.429017] EIP: [] dev_get_drvdata+0x17/0x20 SS:ESP 0068:d3249cac eeepc kernel: [ 1495.429017] CR2: 000000006b6b6bcb eeepc kernel: [ 1495.466975] uvcvideo: Failed to resubmit video URB (-27). eeepc kernel: [ 1495.467860] uvcvideo: Failed to resubmit video URB (-27). eeepc kernel: last message repeated 3 times eeepc kernel: [ 1495.512610] ---[ end trace 73ec16848794e5a5 ]--- For uvc device, dev->vdev.dev is the &intf->dev, uvc_delete code is as below: usb_put_intf(dev->intf); usb_put_dev(dev->udev); uvc_status_cleanup(dev); uvc_ctrl_cleanup_device(dev); if (dev->vdev.dev) v4l2_device_unregister(&dev->vdev); Fix it by get_device in v4l2_device_register and put_device in v4l2_device_disconnect Reported-by: Sitsofe Wheeler Signed-off-by: Dave Young Tested-by: Sitsofe Wheeler Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c index c72856c..e6a2c3b 100644 --- a/drivers/media/video/v4l2-device.c +++ b/drivers/media/video/v4l2-device.c @@ -38,6 +38,7 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev) mutex_init(&v4l2_dev->ioctl_lock); v4l2_prio_init(&v4l2_dev->prio); kref_init(&v4l2_dev->ref); + get_device(dev); v4l2_dev->dev = dev; if (dev == NULL) { /* If dev == NULL, then name must be filled in by the caller */ @@ -93,6 +94,7 @@ void v4l2_device_disconnect(struct v4l2_device *v4l2_dev) if (dev_get_drvdata(v4l2_dev->dev) == v4l2_dev) dev_set_drvdata(v4l2_dev->dev, NULL); + put_device(v4l2_dev->dev); v4l2_dev->dev = NULL; } EXPORT_SYMBOL_GPL(v4l2_device_disconnect); -- cgit v0.10.2 From 95c21c4158cc8b5a2920ccbe989b17b6f955d976 Mon Sep 17 00:00:00 2001 From: tvboxspy Date: Sun, 11 Sep 2011 19:26:50 -0300 Subject: [media] [1/2,ver,1.89] DM04/QQBOX Interupt Urb and Timing changes Reduce buffer size of Interupt urb to 128 bytes and polling interval to 8. The devices buffer appears to only handle a maxium of 40 bytes. If the buffer is full a slowing effect is noticed causing occasionnal dropped streaming packets. Signed-off-by: Malcolm Priestley Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c index 55b25be..5fdeed1 100644 --- a/drivers/media/dvb/dvb-usb/lmedm04.c +++ b/drivers/media/dvb/dvb-usb/lmedm04.c @@ -333,7 +333,7 @@ static int lme2510_int_read(struct dvb_usb_adapter *adap) if (lme_int->lme_urb == NULL) return -ENOMEM; - lme_int->buffer = usb_alloc_coherent(adap->dev->udev, 5000, GFP_ATOMIC, + lme_int->buffer = usb_alloc_coherent(adap->dev->udev, 128, GFP_ATOMIC, &lme_int->lme_urb->transfer_dma); if (lme_int->buffer == NULL) @@ -343,10 +343,10 @@ static int lme2510_int_read(struct dvb_usb_adapter *adap) adap->dev->udev, usb_rcvintpipe(adap->dev->udev, 0xa), lme_int->buffer, - 4096, + 128, lme2510_int_response, adap, - 11); + 8); lme_int->lme_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; @@ -1261,7 +1261,7 @@ static void *lme2510_exit_int(struct dvb_usb_device *d) if (st->lme_urb != NULL) { usb_kill_urb(st->lme_urb); - usb_free_coherent(d->udev, 5000, st->buffer, + usb_free_coherent(d->udev, 128, st->buffer, st->lme_urb->transfer_dma); info("Interrupt Service Stopped"); } @@ -1312,5 +1312,5 @@ module_exit(lme2510_module_exit); MODULE_AUTHOR("Malcolm Priestley "); MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0"); -MODULE_VERSION("1.88"); +MODULE_VERSION("1.89"); MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 810fda9bccc6513856346a9a714cf951d569cd35 Mon Sep 17 00:00:00 2001 From: tvboxspy Date: Sun, 11 Sep 2011 19:30:10 -0300 Subject: [media] [2/2,ver,1.90] DM04/QQBOX Reduce USB buffer size Reduced unused buffer size to 64. Signed-off-by: Malcolm Priestley Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c index 5fdeed1..b922824 100644 --- a/drivers/media/dvb/dvb-usb/lmedm04.c +++ b/drivers/media/dvb/dvb-usb/lmedm04.c @@ -162,7 +162,7 @@ static int lme2510_usb_talk(struct dvb_usb_device *d, int ret = 0; if (st->usb_buffer == NULL) { - st->usb_buffer = kmalloc(512, GFP_KERNEL); + st->usb_buffer = kmalloc(64, GFP_KERNEL); if (st->usb_buffer == NULL) { info("MEM Error no memory"); return -ENOMEM; @@ -175,8 +175,8 @@ static int lme2510_usb_talk(struct dvb_usb_device *d, if (ret < 0) return -EAGAIN; - /* the read/write capped at 512 */ - memcpy(buff, wbuf, (wlen > 512) ? 512 : wlen); + /* the read/write capped at 64 */ + memcpy(buff, wbuf, (wlen < 64) ? wlen : 64); ret |= usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, 0x01)); @@ -186,8 +186,8 @@ static int lme2510_usb_talk(struct dvb_usb_device *d, ret |= usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, 0x01)); - ret |= lme2510_bulk_read(d->udev, buff, (rlen > 512) ? - 512 : rlen , 0x01); + ret |= lme2510_bulk_read(d->udev, buff, (rlen < 64) ? + rlen : 64 , 0x01); if (rlen > 0) memcpy(rbuf, buff, rlen); @@ -580,7 +580,7 @@ static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], { struct dvb_usb_device *d = i2c_get_adapdata(adap); struct lme2510_state *st = d->priv; - static u8 obuf[64], ibuf[512]; + static u8 obuf[64], ibuf[64]; int i, read, read_o; u16 len; u8 gate = st->i2c_gate; @@ -621,7 +621,7 @@ static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], len = msg[i].len+3; } - if (lme2510_msg(d, obuf, len, ibuf, 512) < 0) { + if (lme2510_msg(d, obuf, len, ibuf, 64) < 0) { deb_info(1, "i2c transfer failed."); return -EAGAIN; } @@ -1312,5 +1312,5 @@ module_exit(lme2510_module_exit); MODULE_AUTHOR("Malcolm Priestley "); MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0"); -MODULE_VERSION("1.89"); +MODULE_VERSION("1.90"); MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 699cc1962c85351689c27dd46e598e4204fdd105 Mon Sep 17 00:00:00 2001 From: Lutz Sammer Date: Wed, 4 May 2011 07:27:31 -0300 Subject: [media] TT-budget S2-3200 cannot tune on HB13E DVBS2 transponder The FEC fix patch fixed locking on 11,681 Ghz, but not on 12,692 Ghz for me. Reviewed-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/frontends/stb0899_drv.c b/drivers/media/dvb/frontends/stb0899_drv.c index 37a222d..7691282 100644 --- a/drivers/media/dvb/frontends/stb0899_drv.c +++ b/drivers/media/dvb/frontends/stb0899_drv.c @@ -1426,9 +1426,9 @@ static void stb0899_set_iterations(struct stb0899_state *state) if (iter_scale > config->ldpc_max_iter) iter_scale = config->ldpc_max_iter; - reg = STB0899_READ_S2REG(STB0899_S2DEMOD, MAX_ITER); + reg = STB0899_READ_S2REG(STB0899_S2FEC, MAX_ITER); STB0899_SETFIELD_VAL(MAX_ITERATIONS, reg, iter_scale); - stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_MAX_ITER, STB0899_OFF0_MAX_ITER, reg); + stb0899_write_s2reg(state, STB0899_S2FEC, STB0899_BASE_MAX_ITER, STB0899_OFF0_MAX_ITER, reg); } static enum dvbfe_search stb0899_search(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) -- cgit v0.10.2 From ab0ab19032d16ad63e81f2fe98ae35d76296d8d9 Mon Sep 17 00:00:00 2001 From: Mats Randgaard Date: Tue, 3 Aug 2010 04:18:03 -0300 Subject: [media] TVP7002: Return V4L2_DV_INVALID if any of the errors occur Signed-off-by: Mats Randgaard Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/tvp7002.c b/drivers/media/video/tvp7002.c index b799851..d78be2f 100644 --- a/drivers/media/video/tvp7002.c +++ b/drivers/media/video/tvp7002.c @@ -687,6 +687,9 @@ static int tvp7002_query_dv_preset(struct v4l2_subdev *sd, u8 cpl_msb; int index; + /* Return invalid preset if no active input is detected */ + qpreset->preset = V4L2_DV_INVALID; + device = to_tvp7002(sd); /* Read standards from device registers */ @@ -720,8 +723,6 @@ static int tvp7002_query_dv_preset(struct v4l2_subdev *sd, if (index == NUM_PRESETS) { v4l2_dbg(1, debug, sd, "detection failed: lpf = %x, cpl = %x\n", lpfr, cpln); - /* Could not detect a signal, so return the 'invalid' preset */ - qpreset->preset = V4L2_DV_INVALID; return 0; } -- cgit v0.10.2 From 425b91c94a8287a9e1463f2ba23170584077ebe6 Mon Sep 17 00:00:00 2001 From: Mats Randgaard Date: Tue, 3 Aug 2010 04:18:04 -0300 Subject: [media] TVP7002: Changed register values Register values changed according to the data sheet and Texas Instruments DaVinci_PSP_03_02_00_37. - TVP7002_RGB_COARSE_CLAMP_CTL changed to the default value in data sheet. - TVP7002_HPLL_PHASE_SEL deleted because the registers write to reserved bits. The default value works fine. Signed-off-by: Mats Randgaard Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/tvp7002.c b/drivers/media/video/tvp7002.c index d78be2f..2e6059a 100644 --- a/drivers/media/video/tvp7002.c +++ b/drivers/media/video/tvp7002.c @@ -128,7 +128,7 @@ static const struct i2c_reg_value tvp7002_init_default[] = { { TVP7002_ADC_SETUP, 0x50, TVP7002_WRITE }, { TVP7002_COARSE_CLAMP_CTL, 0x00, TVP7002_WRITE }, { TVP7002_SOG_CLAMP, 0x80, TVP7002_WRITE }, - { TVP7002_RGB_COARSE_CLAMP_CTL, 0x00, TVP7002_WRITE }, + { TVP7002_RGB_COARSE_CLAMP_CTL, 0x8c, TVP7002_WRITE }, { TVP7002_SOG_COARSE_CLAMP_CTL, 0x04, TVP7002_WRITE }, { TVP7002_ALC_PLACEMENT, 0x5a, TVP7002_WRITE }, { 0x32, 0x18, TVP7002_RESERVED }, @@ -182,7 +182,6 @@ static const struct i2c_reg_value tvp7002_parms_480P[] = { { TVP7002_HPLL_FDBK_DIV_MSBS, 0x35, TVP7002_WRITE }, { TVP7002_HPLL_FDBK_DIV_LSBS, 0xa0, TVP7002_WRITE }, { TVP7002_HPLL_CRTL, 0x02, TVP7002_WRITE }, - { TVP7002_HPLL_PHASE_SEL, 0x14, TVP7002_WRITE }, { TVP7002_AVID_START_PIXEL_LSBS, 0x91, TVP7002_WRITE }, { TVP7002_AVID_START_PIXEL_MSBS, 0x00, TVP7002_WRITE }, { TVP7002_AVID_STOP_PIXEL_LSBS, 0x0B, TVP7002_WRITE }, @@ -204,7 +203,6 @@ static const struct i2c_reg_value tvp7002_parms_576P[] = { { TVP7002_HPLL_FDBK_DIV_MSBS, 0x36, TVP7002_WRITE }, { TVP7002_HPLL_FDBK_DIV_LSBS, 0x00, TVP7002_WRITE }, { TVP7002_HPLL_CRTL, 0x18, TVP7002_WRITE }, - { TVP7002_HPLL_PHASE_SEL, 0x14, TVP7002_WRITE }, { TVP7002_AVID_START_PIXEL_LSBS, 0x9B, TVP7002_WRITE }, { TVP7002_AVID_START_PIXEL_MSBS, 0x00, TVP7002_WRITE }, { TVP7002_AVID_STOP_PIXEL_LSBS, 0x0F, TVP7002_WRITE }, @@ -226,7 +224,6 @@ static const struct i2c_reg_value tvp7002_parms_1080I60[] = { { TVP7002_HPLL_FDBK_DIV_MSBS, 0x89, TVP7002_WRITE }, { TVP7002_HPLL_FDBK_DIV_LSBS, 0x80, TVP7002_WRITE }, { TVP7002_HPLL_CRTL, 0x98, TVP7002_WRITE }, - { TVP7002_HPLL_PHASE_SEL, 0x14, TVP7002_WRITE }, { TVP7002_AVID_START_PIXEL_LSBS, 0x06, TVP7002_WRITE }, { TVP7002_AVID_START_PIXEL_MSBS, 0x01, TVP7002_WRITE }, { TVP7002_AVID_STOP_PIXEL_LSBS, 0x8a, TVP7002_WRITE }, @@ -248,7 +245,6 @@ static const struct i2c_reg_value tvp7002_parms_1080P60[] = { { TVP7002_HPLL_FDBK_DIV_MSBS, 0x89, TVP7002_WRITE }, { TVP7002_HPLL_FDBK_DIV_LSBS, 0x80, TVP7002_WRITE }, { TVP7002_HPLL_CRTL, 0xE0, TVP7002_WRITE }, - { TVP7002_HPLL_PHASE_SEL, 0x14, TVP7002_WRITE }, { TVP7002_AVID_START_PIXEL_LSBS, 0x06, TVP7002_WRITE }, { TVP7002_AVID_START_PIXEL_MSBS, 0x01, TVP7002_WRITE }, { TVP7002_AVID_STOP_PIXEL_LSBS, 0x8a, TVP7002_WRITE }, @@ -270,7 +266,6 @@ static const struct i2c_reg_value tvp7002_parms_1080I50[] = { { TVP7002_HPLL_FDBK_DIV_MSBS, 0xa5, TVP7002_WRITE }, { TVP7002_HPLL_FDBK_DIV_LSBS, 0x00, TVP7002_WRITE }, { TVP7002_HPLL_CRTL, 0x98, TVP7002_WRITE }, - { TVP7002_HPLL_PHASE_SEL, 0x14, TVP7002_WRITE }, { TVP7002_AVID_START_PIXEL_LSBS, 0x06, TVP7002_WRITE }, { TVP7002_AVID_START_PIXEL_MSBS, 0x01, TVP7002_WRITE }, { TVP7002_AVID_STOP_PIXEL_LSBS, 0x8a, TVP7002_WRITE }, @@ -292,7 +287,6 @@ static const struct i2c_reg_value tvp7002_parms_720P60[] = { { TVP7002_HPLL_FDBK_DIV_MSBS, 0x67, TVP7002_WRITE }, { TVP7002_HPLL_FDBK_DIV_LSBS, 0x20, TVP7002_WRITE }, { TVP7002_HPLL_CRTL, 0xa0, TVP7002_WRITE }, - { TVP7002_HPLL_PHASE_SEL, 0x16, TVP7002_WRITE }, { TVP7002_AVID_START_PIXEL_LSBS, 0x47, TVP7002_WRITE }, { TVP7002_AVID_START_PIXEL_MSBS, 0x01, TVP7002_WRITE }, { TVP7002_AVID_STOP_PIXEL_LSBS, 0x4B, TVP7002_WRITE }, @@ -314,7 +308,6 @@ static const struct i2c_reg_value tvp7002_parms_720P50[] = { { TVP7002_HPLL_FDBK_DIV_MSBS, 0x7b, TVP7002_WRITE }, { TVP7002_HPLL_FDBK_DIV_LSBS, 0xc0, TVP7002_WRITE }, { TVP7002_HPLL_CRTL, 0x98, TVP7002_WRITE }, - { TVP7002_HPLL_PHASE_SEL, 0x16, TVP7002_WRITE }, { TVP7002_AVID_START_PIXEL_LSBS, 0x47, TVP7002_WRITE }, { TVP7002_AVID_START_PIXEL_MSBS, 0x01, TVP7002_WRITE }, { TVP7002_AVID_STOP_PIXEL_LSBS, 0x4B, TVP7002_WRITE }, -- cgit v0.10.2 From 653822b9276472aa760fa80f32ffcc777de9c403 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 11 Aug 2011 08:35:04 -0300 Subject: [media] adp1653: set media entity type The type of a media entity is default for this driver. This patch makes it explicitly defined as MEDIA_ENT_T_V4L2_SUBDEV_FLASH. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/adp1653.c b/drivers/media/video/adp1653.c index 2e874c3..5914390 100644 --- a/drivers/media/video/adp1653.c +++ b/drivers/media/video/adp1653.c @@ -438,6 +438,8 @@ static int adp1653_probe(struct i2c_client *client, if (ret < 0) goto free_and_quit; + flash->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH; + return 0; free_and_quit: -- cgit v0.10.2 From 9688efda3fb0abb487ae44ced1dd02d14a4312c4 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Sat, 6 Aug 2011 18:18:07 -0300 Subject: [media] move ati_remote driver from input/misc to media/rc The driver will be migrated to the RC driver API in a following commit. [mchehab@redhat.com: Fix some bad whitespacing] Signed-off-by: Anssi Hannula Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index c9104bb..05cbdab 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -183,22 +183,6 @@ config INPUT_ATLAS_BTNS To compile this driver as a module, choose M here: the module will be called atlas_btns. -config INPUT_ATI_REMOTE - tristate "ATI / X10 USB RF remote control" - depends on USB_ARCH_HAS_HCD - select USB - help - Say Y here if you want to use an ATI or X10 "Lola" USB remote control. - These are RF remotes with USB receivers. - The ATI remote comes with many of ATI's All-In-Wonder video cards. - The X10 "Lola" remote is available at: - - This driver provides mouse pointer, left and right mouse buttons, - and maps all the other remote buttons to keypress events. - - To compile this driver as a module, choose M here: the module will be - called ati_remote. - config INPUT_ATI_REMOTE2 tristate "ATI / Philips USB RF remote control" depends on USB_ARCH_HAS_HCD diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 299ad5e..9032d34 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_INPUT_ADXL34X) += adxl34x.o obj-$(CONFIG_INPUT_ADXL34X_I2C) += adxl34x-i2c.o obj-$(CONFIG_INPUT_ADXL34X_SPI) += adxl34x-spi.o obj-$(CONFIG_INPUT_APANEL) += apanel.o -obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o diff --git a/drivers/input/misc/ati_remote.c b/drivers/input/misc/ati_remote.c deleted file mode 100644 index bce5712..0000000 --- a/drivers/input/misc/ati_remote.c +++ /dev/null @@ -1,867 +0,0 @@ -/* - * USB ATI Remote support - * - * Version 2.2.0 Copyright (c) 2004 Torrey Hoffman - * Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev - * - * This 2.2.0 version is a rewrite / cleanup of the 2.1.1 driver, including - * porting to the 2.6 kernel interfaces, along with other modification - * to better match the style of the existing usb/input drivers. However, the - * protocol and hardware handling is essentially unchanged from 2.1.1. - * - * The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by - * Vojtech Pavlik. - * - * Changes: - * - * Feb 2004: Torrey Hoffman - * Version 2.2.0 - * Jun 2004: Torrey Hoffman - * Version 2.2.1 - * Added key repeat support contributed by: - * Vincent Vanackere - * Added support for the "Lola" remote contributed by: - * Seth Cohn - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * - * 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 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * - * Hardware & software notes - * - * These remote controls are distributed by ATI as part of their - * "All-In-Wonder" video card packages. The receiver self-identifies as a - * "USB Receiver" with manufacturer "X10 Wireless Technology Inc". - * - * The "Lola" remote is available from X10. See: - * http://www.x10.com/products/lola_sg1.htm - * The Lola is similar to the ATI remote but has no mouse support, and slightly - * different keys. - * - * It is possible to use multiple receivers and remotes on multiple computers - * simultaneously by configuring them to use specific channels. - * - * The RF protocol used by the remote supports 16 distinct channels, 1 to 16. - * Actually, it may even support more, at least in some revisions of the - * hardware. - * - * Each remote can be configured to transmit on one channel as follows: - * - Press and hold the "hand icon" button. - * - When the red LED starts to blink, let go of the "hand icon" button. - * - When it stops blinking, input the channel code as two digits, from 01 - * to 16, and press the hand icon again. - * - * The timing can be a little tricky. Try loading the module with debug=1 - * to have the kernel print out messages about the remote control number - * and mask. Note: debugging prints remote numbers as zero-based hexadecimal. - * - * The driver has a "channel_mask" parameter. This bitmask specifies which - * channels will be ignored by the module. To mask out channels, just add - * all the 2^channel_number values together. - * - * For instance, set channel_mask = 2^4 = 16 (binary 10000) to make ati_remote - * ignore signals coming from remote controls transmitting on channel 4, but - * accept all other channels. - * - * Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be - * ignored. - * - * The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this - * parameter are unused. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Module and Version Information, Module Parameters - */ - -#define ATI_REMOTE_VENDOR_ID 0x0bc7 -#define LOLA_REMOTE_PRODUCT_ID 0x0002 -#define LOLA2_REMOTE_PRODUCT_ID 0x0003 -#define ATI_REMOTE_PRODUCT_ID 0x0004 -#define NVIDIA_REMOTE_PRODUCT_ID 0x0005 -#define MEDION_REMOTE_PRODUCT_ID 0x0006 - -#define DRIVER_VERSION "2.2.1" -#define DRIVER_AUTHOR "Torrey Hoffman " -#define DRIVER_DESC "ATI/X10 RF USB Remote Control" - -#define NAME_BUFSIZE 80 /* size of product name, path buffers */ -#define DATA_BUFSIZE 63 /* size of URB data buffers */ - -/* - * Duplicate event filtering time. - * Sequential, identical KIND_FILTERED inputs with less than - * FILTER_TIME milliseconds between them are considered as repeat - * events. The hardware generates 5 events for the first keypress - * and we have to take this into account for an accurate repeat - * behaviour. - */ -#define FILTER_TIME 60 /* msec */ -#define REPEAT_DELAY 500 /* msec */ - -static unsigned long channel_mask; -module_param(channel_mask, ulong, 0644); -MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore"); - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Enable extra debug messages and information"); - -static int repeat_filter = FILTER_TIME; -module_param(repeat_filter, int, 0644); -MODULE_PARM_DESC(repeat_filter, "Repeat filter time, default = 60 msec"); - -static int repeat_delay = REPEAT_DELAY; -module_param(repeat_delay, int, 0644); -MODULE_PARM_DESC(repeat_delay, "Delay before sending repeats, default = 500 msec"); - -#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0) -#undef err -#define err(format, arg...) printk(KERN_ERR format , ## arg) - -static struct usb_device_id ati_remote_table[] = { - { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID) }, - { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA2_REMOTE_PRODUCT_ID) }, - { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) }, - { USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID) }, - { USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID) }, - {} /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, ati_remote_table); - -/* Get hi and low bytes of a 16-bits int */ -#define HI(a) ((unsigned char)((a) >> 8)) -#define LO(a) ((unsigned char)((a) & 0xff)) - -#define SEND_FLAG_IN_PROGRESS 1 -#define SEND_FLAG_COMPLETE 2 - -/* Device initialization strings */ -static char init1[] = { 0x01, 0x00, 0x20, 0x14 }; -static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 }; - -struct ati_remote { - struct input_dev *idev; - struct usb_device *udev; - struct usb_interface *interface; - - struct urb *irq_urb; - struct urb *out_urb; - struct usb_endpoint_descriptor *endpoint_in; - struct usb_endpoint_descriptor *endpoint_out; - unsigned char *inbuf; - unsigned char *outbuf; - dma_addr_t inbuf_dma; - dma_addr_t outbuf_dma; - - unsigned char old_data[2]; /* Detect duplicate events */ - unsigned long old_jiffies; - unsigned long acc_jiffies; /* handle acceleration */ - unsigned long first_jiffies; - - unsigned int repeat_count; - - char name[NAME_BUFSIZE]; - char phys[NAME_BUFSIZE]; - - wait_queue_head_t wait; - int send_flags; -}; - -/* "Kinds" of messages sent from the hardware to the driver. */ -#define KIND_END 0 -#define KIND_LITERAL 1 /* Simply pass to input system */ -#define KIND_FILTERED 2 /* Add artificial key-up events, drop keyrepeats */ -#define KIND_LU 3 /* Directional keypad diagonals - left up, */ -#define KIND_RU 4 /* right up, */ -#define KIND_LD 5 /* left down, */ -#define KIND_RD 6 /* right down */ -#define KIND_ACCEL 7 /* Directional keypad - left, right, up, down.*/ - -/* Translation table from hardware messages to input events. */ -static const struct { - short kind; - unsigned char data1, data2; - int type; - unsigned int code; - int value; -} ati_remote_tbl[] = { - /* Directional control pad axes */ - {KIND_ACCEL, 0x35, 0x70, EV_REL, REL_X, -1}, /* left */ - {KIND_ACCEL, 0x36, 0x71, EV_REL, REL_X, 1}, /* right */ - {KIND_ACCEL, 0x37, 0x72, EV_REL, REL_Y, -1}, /* up */ - {KIND_ACCEL, 0x38, 0x73, EV_REL, REL_Y, 1}, /* down */ - /* Directional control pad diagonals */ - {KIND_LU, 0x39, 0x74, EV_REL, 0, 0}, /* left up */ - {KIND_RU, 0x3a, 0x75, EV_REL, 0, 0}, /* right up */ - {KIND_LD, 0x3c, 0x77, EV_REL, 0, 0}, /* left down */ - {KIND_RD, 0x3b, 0x76, EV_REL, 0, 0}, /* right down */ - - /* "Mouse button" buttons */ - {KIND_LITERAL, 0x3d, 0x78, EV_KEY, BTN_LEFT, 1}, /* left btn down */ - {KIND_LITERAL, 0x3e, 0x79, EV_KEY, BTN_LEFT, 0}, /* left btn up */ - {KIND_LITERAL, 0x41, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */ - {KIND_LITERAL, 0x42, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */ - - /* Artificial "doubleclick" events are generated by the hardware. - * They are mapped to the "side" and "extra" mouse buttons here. */ - {KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */ - {KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */ - - /* keyboard. */ - {KIND_FILTERED, 0xd2, 0x0d, EV_KEY, KEY_1, 1}, - {KIND_FILTERED, 0xd3, 0x0e, EV_KEY, KEY_2, 1}, - {KIND_FILTERED, 0xd4, 0x0f, EV_KEY, KEY_3, 1}, - {KIND_FILTERED, 0xd5, 0x10, EV_KEY, KEY_4, 1}, - {KIND_FILTERED, 0xd6, 0x11, EV_KEY, KEY_5, 1}, - {KIND_FILTERED, 0xd7, 0x12, EV_KEY, KEY_6, 1}, - {KIND_FILTERED, 0xd8, 0x13, EV_KEY, KEY_7, 1}, - {KIND_FILTERED, 0xd9, 0x14, EV_KEY, KEY_8, 1}, - {KIND_FILTERED, 0xda, 0x15, EV_KEY, KEY_9, 1}, - {KIND_FILTERED, 0xdc, 0x17, EV_KEY, KEY_0, 1}, - {KIND_FILTERED, 0xc5, 0x00, EV_KEY, KEY_A, 1}, - {KIND_FILTERED, 0xc6, 0x01, EV_KEY, KEY_B, 1}, - {KIND_FILTERED, 0xde, 0x19, EV_KEY, KEY_C, 1}, - {KIND_FILTERED, 0xe0, 0x1b, EV_KEY, KEY_D, 1}, - {KIND_FILTERED, 0xe6, 0x21, EV_KEY, KEY_E, 1}, - {KIND_FILTERED, 0xe8, 0x23, EV_KEY, KEY_F, 1}, - - /* "special" keys */ - {KIND_FILTERED, 0xdd, 0x18, EV_KEY, KEY_KPENTER, 1}, /* "check" */ - {KIND_FILTERED, 0xdb, 0x16, EV_KEY, KEY_MENU, 1}, /* "menu" */ - {KIND_FILTERED, 0xc7, 0x02, EV_KEY, KEY_POWER, 1}, /* Power */ - {KIND_FILTERED, 0xc8, 0x03, EV_KEY, KEY_TV, 1}, /* TV */ - {KIND_FILTERED, 0xc9, 0x04, EV_KEY, KEY_DVD, 1}, /* DVD */ - {KIND_FILTERED, 0xca, 0x05, EV_KEY, KEY_WWW, 1}, /* WEB */ - {KIND_FILTERED, 0xcb, 0x06, EV_KEY, KEY_BOOKMARKS, 1}, /* "book" */ - {KIND_FILTERED, 0xcc, 0x07, EV_KEY, KEY_EDIT, 1}, /* "hand" */ - {KIND_FILTERED, 0xe1, 0x1c, EV_KEY, KEY_COFFEE, 1}, /* "timer" */ - {KIND_FILTERED, 0xe5, 0x20, EV_KEY, KEY_FRONT, 1}, /* "max" */ - {KIND_FILTERED, 0xe2, 0x1d, EV_KEY, KEY_LEFT, 1}, /* left */ - {KIND_FILTERED, 0xe4, 0x1f, EV_KEY, KEY_RIGHT, 1}, /* right */ - {KIND_FILTERED, 0xe7, 0x22, EV_KEY, KEY_DOWN, 1}, /* down */ - {KIND_FILTERED, 0xdf, 0x1a, EV_KEY, KEY_UP, 1}, /* up */ - {KIND_FILTERED, 0xe3, 0x1e, EV_KEY, KEY_OK, 1}, /* "OK" */ - {KIND_FILTERED, 0xce, 0x09, EV_KEY, KEY_VOLUMEDOWN, 1}, /* VOL + */ - {KIND_FILTERED, 0xcd, 0x08, EV_KEY, KEY_VOLUMEUP, 1}, /* VOL - */ - {KIND_FILTERED, 0xcf, 0x0a, EV_KEY, KEY_MUTE, 1}, /* MUTE */ - {KIND_FILTERED, 0xd0, 0x0b, EV_KEY, KEY_CHANNELUP, 1}, /* CH + */ - {KIND_FILTERED, 0xd1, 0x0c, EV_KEY, KEY_CHANNELDOWN, 1},/* CH - */ - {KIND_FILTERED, 0xec, 0x27, EV_KEY, KEY_RECORD, 1}, /* ( o) red */ - {KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAY, 1}, /* ( >) */ - {KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1}, /* (<<) */ - {KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1}, /* (>>) */ - {KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1}, /* ([]) */ - {KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_PAUSE, 1}, /* ('') */ - {KIND_FILTERED, 0xf0, 0x2b, EV_KEY, KEY_PREVIOUS, 1}, /* (<-) */ - {KIND_FILTERED, 0xef, 0x2a, EV_KEY, KEY_NEXT, 1}, /* (>+) */ - {KIND_FILTERED, 0xf2, 0x2D, EV_KEY, KEY_INFO, 1}, /* PLAYING */ - {KIND_FILTERED, 0xf3, 0x2E, EV_KEY, KEY_HOME, 1}, /* TOP */ - {KIND_FILTERED, 0xf4, 0x2F, EV_KEY, KEY_END, 1}, /* END */ - {KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_SELECT, 1}, /* SELECT */ - - {KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0} -}; - -/* Local function prototypes */ -static int ati_remote_open (struct input_dev *inputdev); -static void ati_remote_close (struct input_dev *inputdev); -static int ati_remote_sendpacket (struct ati_remote *ati_remote, u16 cmd, unsigned char *data); -static void ati_remote_irq_out (struct urb *urb); -static void ati_remote_irq_in (struct urb *urb); -static void ati_remote_input_report (struct urb *urb); -static int ati_remote_initialize (struct ati_remote *ati_remote); -static int ati_remote_probe (struct usb_interface *interface, const struct usb_device_id *id); -static void ati_remote_disconnect (struct usb_interface *interface); - -/* usb specific object to register with the usb subsystem */ -static struct usb_driver ati_remote_driver = { - .name = "ati_remote", - .probe = ati_remote_probe, - .disconnect = ati_remote_disconnect, - .id_table = ati_remote_table, -}; - -/* - * ati_remote_dump_input - */ -static void ati_remote_dump(struct device *dev, unsigned char *data, - unsigned int len) -{ - if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00)) - dev_warn(dev, "Weird byte 0x%02x\n", data[0]); - else if (len == 4) - dev_warn(dev, "Weird key %02x %02x %02x %02x\n", - data[0], data[1], data[2], data[3]); - else - dev_warn(dev, "Weird data, len=%d %02x %02x %02x %02x %02x %02x ...\n", - len, data[0], data[1], data[2], data[3], data[4], data[5]); -} - -/* - * ati_remote_open - */ -static int ati_remote_open(struct input_dev *inputdev) -{ - struct ati_remote *ati_remote = input_get_drvdata(inputdev); - - /* On first open, submit the read urb which was set up previously. */ - ati_remote->irq_urb->dev = ati_remote->udev; - if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) { - dev_err(&ati_remote->interface->dev, - "%s: usb_submit_urb failed!\n", __func__); - return -EIO; - } - - return 0; -} - -/* - * ati_remote_close - */ -static void ati_remote_close(struct input_dev *inputdev) -{ - struct ati_remote *ati_remote = input_get_drvdata(inputdev); - - usb_kill_urb(ati_remote->irq_urb); -} - -/* - * ati_remote_irq_out - */ -static void ati_remote_irq_out(struct urb *urb) -{ - struct ati_remote *ati_remote = urb->context; - - if (urb->status) { - dev_dbg(&ati_remote->interface->dev, "%s: status %d\n", - __func__, urb->status); - return; - } - - ati_remote->send_flags |= SEND_FLAG_COMPLETE; - wmb(); - wake_up(&ati_remote->wait); -} - -/* - * ati_remote_sendpacket - * - * Used to send device initialization strings - */ -static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigned char *data) -{ - int retval = 0; - - /* Set up out_urb */ - memcpy(ati_remote->out_urb->transfer_buffer + 1, data, LO(cmd)); - ((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd); - - ati_remote->out_urb->transfer_buffer_length = LO(cmd) + 1; - ati_remote->out_urb->dev = ati_remote->udev; - ati_remote->send_flags = SEND_FLAG_IN_PROGRESS; - - retval = usb_submit_urb(ati_remote->out_urb, GFP_ATOMIC); - if (retval) { - dev_dbg(&ati_remote->interface->dev, - "sendpacket: usb_submit_urb failed: %d\n", retval); - return retval; - } - - wait_event_timeout(ati_remote->wait, - ((ati_remote->out_urb->status != -EINPROGRESS) || - (ati_remote->send_flags & SEND_FLAG_COMPLETE)), - HZ); - usb_kill_urb(ati_remote->out_urb); - - return retval; -} - -/* - * ati_remote_event_lookup - */ -static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2) -{ - int i; - - for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) { - /* - * Decide if the table entry matches the remote input. - */ - if ((((ati_remote_tbl[i].data1 & 0x0f) == (d1 & 0x0f))) && - ((((ati_remote_tbl[i].data1 >> 4) - - (d1 >> 4) + rem) & 0x0f) == 0x0f) && - (ati_remote_tbl[i].data2 == d2)) - return i; - - } - return -1; -} - -/* - * ati_remote_compute_accel - * - * Implements acceleration curve for directional control pad - * If elapsed time since last event is > 1/4 second, user "stopped", - * so reset acceleration. Otherwise, user is probably holding the control - * pad down, so we increase acceleration, ramping up over two seconds to - * a maximum speed. - */ -static int ati_remote_compute_accel(struct ati_remote *ati_remote) -{ - static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 }; - unsigned long now = jiffies; - int acc; - - if (time_after(now, ati_remote->old_jiffies + msecs_to_jiffies(250))) { - acc = 1; - ati_remote->acc_jiffies = now; - } - else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(125))) - acc = accel[0]; - else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(250))) - acc = accel[1]; - else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(500))) - acc = accel[2]; - else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1000))) - acc = accel[3]; - else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1500))) - acc = accel[4]; - else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(2000))) - acc = accel[5]; - else - acc = accel[6]; - - return acc; -} - -/* - * ati_remote_report_input - */ -static void ati_remote_input_report(struct urb *urb) -{ - struct ati_remote *ati_remote = urb->context; - unsigned char *data= ati_remote->inbuf; - struct input_dev *dev = ati_remote->idev; - int index, acc; - int remote_num; - - /* Deal with strange looking inputs */ - if ( (urb->actual_length != 4) || (data[0] != 0x14) || - ((data[3] & 0x0f) != 0x00) ) { - ati_remote_dump(&urb->dev->dev, data, urb->actual_length); - return; - } - - /* Mask unwanted remote channels. */ - /* note: remote_num is 0-based, channel 1 on remote == 0 here */ - remote_num = (data[3] >> 4) & 0x0f; - if (channel_mask & (1 << (remote_num + 1))) { - dbginfo(&ati_remote->interface->dev, - "Masked input from channel 0x%02x: data %02x,%02x, mask= 0x%02lx\n", - remote_num, data[1], data[2], channel_mask); - return; - } - - /* Look up event code index in translation table */ - index = ati_remote_event_lookup(remote_num, data[1], data[2]); - if (index < 0) { - dev_warn(&ati_remote->interface->dev, - "Unknown input from channel 0x%02x: data %02x,%02x\n", - remote_num, data[1], data[2]); - return; - } - dbginfo(&ati_remote->interface->dev, - "channel 0x%02x; data %02x,%02x; index %d; keycode %d\n", - remote_num, data[1], data[2], index, ati_remote_tbl[index].code); - - if (ati_remote_tbl[index].kind == KIND_LITERAL) { - input_event(dev, ati_remote_tbl[index].type, - ati_remote_tbl[index].code, - ati_remote_tbl[index].value); - input_sync(dev); - - ati_remote->old_jiffies = jiffies; - return; - } - - if (ati_remote_tbl[index].kind == KIND_FILTERED) { - unsigned long now = jiffies; - - /* Filter duplicate events which happen "too close" together. */ - if (ati_remote->old_data[0] == data[1] && - ati_remote->old_data[1] == data[2] && - time_before(now, ati_remote->old_jiffies + - msecs_to_jiffies(repeat_filter))) { - ati_remote->repeat_count++; - } else { - ati_remote->repeat_count = 0; - ati_remote->first_jiffies = now; - } - - ati_remote->old_data[0] = data[1]; - ati_remote->old_data[1] = data[2]; - ati_remote->old_jiffies = now; - - /* Ensure we skip at least the 4 first duplicate events (generated - * by a single keypress), and continue skipping until repeat_delay - * msecs have passed - */ - if (ati_remote->repeat_count > 0 && - (ati_remote->repeat_count < 5 || - time_before(now, ati_remote->first_jiffies + - msecs_to_jiffies(repeat_delay)))) - return; - - - input_event(dev, ati_remote_tbl[index].type, - ati_remote_tbl[index].code, 1); - input_sync(dev); - input_event(dev, ati_remote_tbl[index].type, - ati_remote_tbl[index].code, 0); - input_sync(dev); - - } else { - - /* - * Other event kinds are from the directional control pad, and have an - * acceleration factor applied to them. Without this acceleration, the - * control pad is mostly unusable. - */ - acc = ati_remote_compute_accel(ati_remote); - - switch (ati_remote_tbl[index].kind) { - case KIND_ACCEL: - input_event(dev, ati_remote_tbl[index].type, - ati_remote_tbl[index].code, - ati_remote_tbl[index].value * acc); - break; - case KIND_LU: - input_report_rel(dev, REL_X, -acc); - input_report_rel(dev, REL_Y, -acc); - break; - case KIND_RU: - input_report_rel(dev, REL_X, acc); - input_report_rel(dev, REL_Y, -acc); - break; - case KIND_LD: - input_report_rel(dev, REL_X, -acc); - input_report_rel(dev, REL_Y, acc); - break; - case KIND_RD: - input_report_rel(dev, REL_X, acc); - input_report_rel(dev, REL_Y, acc); - break; - default: - dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n", - ati_remote_tbl[index].kind); - } - input_sync(dev); - - ati_remote->old_jiffies = jiffies; - ati_remote->old_data[0] = data[1]; - ati_remote->old_data[1] = data[2]; - } -} - -/* - * ati_remote_irq_in - */ -static void ati_remote_irq_in(struct urb *urb) -{ - struct ati_remote *ati_remote = urb->context; - int retval; - - switch (urb->status) { - case 0: /* success */ - ati_remote_input_report(urb); - break; - case -ECONNRESET: /* unlink */ - case -ENOENT: - case -ESHUTDOWN: - dev_dbg(&ati_remote->interface->dev, "%s: urb error status, unlink? \n", - __func__); - return; - default: /* error */ - dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n", - __func__, urb->status); - } - - retval = usb_submit_urb(urb, GFP_ATOMIC); - if (retval) - dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n", - __func__, retval); -} - -/* - * ati_remote_alloc_buffers - */ -static int ati_remote_alloc_buffers(struct usb_device *udev, - struct ati_remote *ati_remote) -{ - ati_remote->inbuf = usb_alloc_coherent(udev, DATA_BUFSIZE, GFP_ATOMIC, - &ati_remote->inbuf_dma); - if (!ati_remote->inbuf) - return -1; - - ati_remote->outbuf = usb_alloc_coherent(udev, DATA_BUFSIZE, GFP_ATOMIC, - &ati_remote->outbuf_dma); - if (!ati_remote->outbuf) - return -1; - - ati_remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!ati_remote->irq_urb) - return -1; - - ati_remote->out_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!ati_remote->out_urb) - return -1; - - return 0; -} - -/* - * ati_remote_free_buffers - */ -static void ati_remote_free_buffers(struct ati_remote *ati_remote) -{ - usb_free_urb(ati_remote->irq_urb); - usb_free_urb(ati_remote->out_urb); - - usb_free_coherent(ati_remote->udev, DATA_BUFSIZE, - ati_remote->inbuf, ati_remote->inbuf_dma); - - usb_free_coherent(ati_remote->udev, DATA_BUFSIZE, - ati_remote->outbuf, ati_remote->outbuf_dma); -} - -static void ati_remote_input_init(struct ati_remote *ati_remote) -{ - struct input_dev *idev = ati_remote->idev; - int i; - - idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); - idev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) | - BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA); - idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); - for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) - if (ati_remote_tbl[i].type == EV_KEY) - set_bit(ati_remote_tbl[i].code, idev->keybit); - - input_set_drvdata(idev, ati_remote); - - idev->open = ati_remote_open; - idev->close = ati_remote_close; - - idev->name = ati_remote->name; - idev->phys = ati_remote->phys; - - usb_to_input_id(ati_remote->udev, &idev->id); - idev->dev.parent = &ati_remote->udev->dev; -} - -static int ati_remote_initialize(struct ati_remote *ati_remote) -{ - struct usb_device *udev = ati_remote->udev; - int pipe, maxp; - - init_waitqueue_head(&ati_remote->wait); - - /* Set up irq_urb */ - pipe = usb_rcvintpipe(udev, ati_remote->endpoint_in->bEndpointAddress); - maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); - maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp; - - usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf, - maxp, ati_remote_irq_in, ati_remote, - ati_remote->endpoint_in->bInterval); - ati_remote->irq_urb->transfer_dma = ati_remote->inbuf_dma; - ati_remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - - /* Set up out_urb */ - pipe = usb_sndintpipe(udev, ati_remote->endpoint_out->bEndpointAddress); - maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); - maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp; - - usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf, - maxp, ati_remote_irq_out, ati_remote, - ati_remote->endpoint_out->bInterval); - ati_remote->out_urb->transfer_dma = ati_remote->outbuf_dma; - ati_remote->out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - - /* send initialization strings */ - if ((ati_remote_sendpacket(ati_remote, 0x8004, init1)) || - (ati_remote_sendpacket(ati_remote, 0x8007, init2))) { - dev_err(&ati_remote->interface->dev, - "Initializing ati_remote hardware failed.\n"); - return -EIO; - } - - return 0; -} - -/* - * ati_remote_probe - */ -static int ati_remote_probe(struct usb_interface *interface, const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(interface); - struct usb_host_interface *iface_host = interface->cur_altsetting; - struct usb_endpoint_descriptor *endpoint_in, *endpoint_out; - struct ati_remote *ati_remote; - struct input_dev *input_dev; - int err = -ENOMEM; - - if (iface_host->desc.bNumEndpoints != 2) { - err("%s: Unexpected desc.bNumEndpoints\n", __func__); - return -ENODEV; - } - - endpoint_in = &iface_host->endpoint[0].desc; - endpoint_out = &iface_host->endpoint[1].desc; - - if (!usb_endpoint_is_int_in(endpoint_in)) { - err("%s: Unexpected endpoint_in\n", __func__); - return -ENODEV; - } - if (le16_to_cpu(endpoint_in->wMaxPacketSize) == 0) { - err("%s: endpoint_in message size==0? \n", __func__); - return -ENODEV; - } - - ati_remote = kzalloc(sizeof (struct ati_remote), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!ati_remote || !input_dev) - goto fail1; - - /* Allocate URB buffers, URBs */ - if (ati_remote_alloc_buffers(udev, ati_remote)) - goto fail2; - - ati_remote->endpoint_in = endpoint_in; - ati_remote->endpoint_out = endpoint_out; - ati_remote->udev = udev; - ati_remote->idev = input_dev; - ati_remote->interface = interface; - - usb_make_path(udev, ati_remote->phys, sizeof(ati_remote->phys)); - strlcat(ati_remote->phys, "/input0", sizeof(ati_remote->phys)); - - if (udev->manufacturer) - strlcpy(ati_remote->name, udev->manufacturer, sizeof(ati_remote->name)); - - if (udev->product) - snprintf(ati_remote->name, sizeof(ati_remote->name), - "%s %s", ati_remote->name, udev->product); - - if (!strlen(ati_remote->name)) - snprintf(ati_remote->name, sizeof(ati_remote->name), - DRIVER_DESC "(%04x,%04x)", - le16_to_cpu(ati_remote->udev->descriptor.idVendor), - le16_to_cpu(ati_remote->udev->descriptor.idProduct)); - - ati_remote_input_init(ati_remote); - - /* Device Hardware Initialization - fills in ati_remote->idev from udev. */ - err = ati_remote_initialize(ati_remote); - if (err) - goto fail3; - - /* Set up and register input device */ - err = input_register_device(ati_remote->idev); - if (err) - goto fail3; - - usb_set_intfdata(interface, ati_remote); - return 0; - - fail3: usb_kill_urb(ati_remote->irq_urb); - usb_kill_urb(ati_remote->out_urb); - fail2: ati_remote_free_buffers(ati_remote); - fail1: input_free_device(input_dev); - kfree(ati_remote); - return err; -} - -/* - * ati_remote_disconnect - */ -static void ati_remote_disconnect(struct usb_interface *interface) -{ - struct ati_remote *ati_remote; - - ati_remote = usb_get_intfdata(interface); - usb_set_intfdata(interface, NULL); - if (!ati_remote) { - dev_warn(&interface->dev, "%s - null device?\n", __func__); - return; - } - - usb_kill_urb(ati_remote->irq_urb); - usb_kill_urb(ati_remote->out_urb); - input_unregister_device(ati_remote->idev); - ati_remote_free_buffers(ati_remote); - kfree(ati_remote); -} - -/* - * ati_remote_init - */ -static int __init ati_remote_init(void) -{ - int result; - - result = usb_register(&ati_remote_driver); - if (result) - printk(KERN_ERR KBUILD_MODNAME - ": usb_register error #%d\n", result); - else - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - - return result; -} - -/* - * ati_remote_exit - */ -static void __exit ati_remote_exit(void) -{ - usb_deregister(&ati_remote_driver); -} - -/* - * module specification - */ - -module_init(ati_remote_init); -module_exit(ati_remote_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 899f783..756884e 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -4,8 +4,8 @@ menuconfig RC_CORE default INPUT ---help--- Enable support for Remote Controllers on Linux. This is - needed in order to support several video capture adapters. - Currently, all supported devices use InfraRed. + needed in order to support several video capture adapters, + standalone IR receivers/transmitters, and RF receivers. Enable this option if you have a video capture board even if you don't need IR, as otherwise, you may not be able to @@ -108,6 +108,22 @@ config IR_LIRC_CODEC Enable this option to pass raw IR to and from userspace via the LIRC interface. +config RC_ATI_REMOTE + tristate "ATI / X10 USB RF remote control" + depends on USB_ARCH_HAS_HCD + select USB + help + Say Y here if you want to use an ATI or X10 "Lola" USB remote control. + These are RF remotes with USB receivers. + The ATI remote comes with many of ATI's All-In-Wonder video cards. + The X10 "Lola" remote is available at: + + This driver provides mouse pointer, left and right mouse buttons, + and maps all the other remote buttons to keypress events. + + To compile this driver as a module, choose M here: the module will be + called ati_remote. + config IR_ENE tristate "ENE eHome Receiver/Transceiver (pnp id: ENE0100/ENE02xxx)" depends on PNP diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index f224db0..2156e78 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o # stand-alone IR receivers/transmitters +obj-$(CONFIG_RC_ATI_REMOTE) += ati_remote.o obj-$(CONFIG_IR_IMON) += imon.o obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o obj-$(CONFIG_IR_MCEUSB) += mceusb.o diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c new file mode 100644 index 0000000..53388a5 --- /dev/null +++ b/drivers/media/rc/ati_remote.c @@ -0,0 +1,867 @@ +/* + * USB ATI Remote support + * + * Version 2.2.0 Copyright (c) 2004 Torrey Hoffman + * Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev + * + * This 2.2.0 version is a rewrite / cleanup of the 2.1.1 driver, including + * porting to the 2.6 kernel interfaces, along with other modification + * to better match the style of the existing usb/input drivers. However, the + * protocol and hardware handling is essentially unchanged from 2.1.1. + * + * The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by + * Vojtech Pavlik. + * + * Changes: + * + * Feb 2004: Torrey Hoffman + * Version 2.2.0 + * Jun 2004: Torrey Hoffman + * Version 2.2.1 + * Added key repeat support contributed by: + * Vincent Vanackere + * Added support for the "Lola" remote contributed by: + * Seth Cohn + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * 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 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * Hardware & software notes + * + * These remote controls are distributed by ATI as part of their + * "All-In-Wonder" video card packages. The receiver self-identifies as a + * "USB Receiver" with manufacturer "X10 Wireless Technology Inc". + * + * The "Lola" remote is available from X10. See: + * http://www.x10.com/products/lola_sg1.htm + * The Lola is similar to the ATI remote but has no mouse support, and slightly + * different keys. + * + * It is possible to use multiple receivers and remotes on multiple computers + * simultaneously by configuring them to use specific channels. + * + * The RF protocol used by the remote supports 16 distinct channels, 1 to 16. + * Actually, it may even support more, at least in some revisions of the + * hardware. + * + * Each remote can be configured to transmit on one channel as follows: + * - Press and hold the "hand icon" button. + * - When the red LED starts to blink, let go of the "hand icon" button. + * - When it stops blinking, input the channel code as two digits, from 01 + * to 16, and press the hand icon again. + * + * The timing can be a little tricky. Try loading the module with debug=1 + * to have the kernel print out messages about the remote control number + * and mask. Note: debugging prints remote numbers as zero-based hexadecimal. + * + * The driver has a "channel_mask" parameter. This bitmask specifies which + * channels will be ignored by the module. To mask out channels, just add + * all the 2^channel_number values together. + * + * For instance, set channel_mask = 2^4 = 16 (binary 10000) to make ati_remote + * ignore signals coming from remote controls transmitting on channel 4, but + * accept all other channels. + * + * Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be + * ignored. + * + * The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this + * parameter are unused. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Module and Version Information, Module Parameters + */ + +#define ATI_REMOTE_VENDOR_ID 0x0bc7 +#define LOLA_REMOTE_PRODUCT_ID 0x0002 +#define LOLA2_REMOTE_PRODUCT_ID 0x0003 +#define ATI_REMOTE_PRODUCT_ID 0x0004 +#define NVIDIA_REMOTE_PRODUCT_ID 0x0005 +#define MEDION_REMOTE_PRODUCT_ID 0x0006 + +#define DRIVER_VERSION "2.2.1" +#define DRIVER_AUTHOR "Torrey Hoffman " +#define DRIVER_DESC "ATI/X10 RF USB Remote Control" + +#define NAME_BUFSIZE 80 /* size of product name, path buffers */ +#define DATA_BUFSIZE 63 /* size of URB data buffers */ + +/* + * Duplicate event filtering time. + * Sequential, identical KIND_FILTERED inputs with less than + * FILTER_TIME milliseconds between them are considered as repeat + * events. The hardware generates 5 events for the first keypress + * and we have to take this into account for an accurate repeat + * behaviour. + */ +#define FILTER_TIME 60 /* msec */ +#define REPEAT_DELAY 500 /* msec */ + +static unsigned long channel_mask; +module_param(channel_mask, ulong, 0644); +MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore"); + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Enable extra debug messages and information"); + +static int repeat_filter = FILTER_TIME; +module_param(repeat_filter, int, 0644); +MODULE_PARM_DESC(repeat_filter, "Repeat filter time, default = 60 msec"); + +static int repeat_delay = REPEAT_DELAY; +module_param(repeat_delay, int, 0644); +MODULE_PARM_DESC(repeat_delay, "Delay before sending repeats, default = 500 msec"); + +#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0) +#undef err +#define err(format, arg...) printk(KERN_ERR format , ## arg) + +static struct usb_device_id ati_remote_table[] = { + { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID) }, + { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA2_REMOTE_PRODUCT_ID) }, + { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) }, + { USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID) }, + { USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID) }, + {} /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, ati_remote_table); + +/* Get hi and low bytes of a 16-bits int */ +#define HI(a) ((unsigned char)((a) >> 8)) +#define LO(a) ((unsigned char)((a) & 0xff)) + +#define SEND_FLAG_IN_PROGRESS 1 +#define SEND_FLAG_COMPLETE 2 + +/* Device initialization strings */ +static char init1[] = { 0x01, 0x00, 0x20, 0x14 }; +static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 }; + +struct ati_remote { + struct input_dev *idev; + struct usb_device *udev; + struct usb_interface *interface; + + struct urb *irq_urb; + struct urb *out_urb; + struct usb_endpoint_descriptor *endpoint_in; + struct usb_endpoint_descriptor *endpoint_out; + unsigned char *inbuf; + unsigned char *outbuf; + dma_addr_t inbuf_dma; + dma_addr_t outbuf_dma; + + unsigned char old_data[2]; /* Detect duplicate events */ + unsigned long old_jiffies; + unsigned long acc_jiffies; /* handle acceleration */ + unsigned long first_jiffies; + + unsigned int repeat_count; + + char name[NAME_BUFSIZE]; + char phys[NAME_BUFSIZE]; + + wait_queue_head_t wait; + int send_flags; +}; + +/* "Kinds" of messages sent from the hardware to the driver. */ +#define KIND_END 0 +#define KIND_LITERAL 1 /* Simply pass to input system */ +#define KIND_FILTERED 2 /* Add artificial key-up events, drop keyrepeats */ +#define KIND_LU 3 /* Directional keypad diagonals - left up, */ +#define KIND_RU 4 /* right up, */ +#define KIND_LD 5 /* left down, */ +#define KIND_RD 6 /* right down */ +#define KIND_ACCEL 7 /* Directional keypad - left, right, up, down.*/ + +/* Translation table from hardware messages to input events. */ +static const struct { + short kind; + unsigned char data1, data2; + int type; + unsigned int code; + int value; +} ati_remote_tbl[] = { + /* Directional control pad axes */ + {KIND_ACCEL, 0x35, 0x70, EV_REL, REL_X, -1}, /* left */ + {KIND_ACCEL, 0x36, 0x71, EV_REL, REL_X, 1}, /* right */ + {KIND_ACCEL, 0x37, 0x72, EV_REL, REL_Y, -1}, /* up */ + {KIND_ACCEL, 0x38, 0x73, EV_REL, REL_Y, 1}, /* down */ + /* Directional control pad diagonals */ + {KIND_LU, 0x39, 0x74, EV_REL, 0, 0}, /* left up */ + {KIND_RU, 0x3a, 0x75, EV_REL, 0, 0}, /* right up */ + {KIND_LD, 0x3c, 0x77, EV_REL, 0, 0}, /* left down */ + {KIND_RD, 0x3b, 0x76, EV_REL, 0, 0}, /* right down */ + + /* "Mouse button" buttons */ + {KIND_LITERAL, 0x3d, 0x78, EV_KEY, BTN_LEFT, 1}, /* left btn down */ + {KIND_LITERAL, 0x3e, 0x79, EV_KEY, BTN_LEFT, 0}, /* left btn up */ + {KIND_LITERAL, 0x41, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */ + {KIND_LITERAL, 0x42, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */ + + /* Artificial "doubleclick" events are generated by the hardware. + * They are mapped to the "side" and "extra" mouse buttons here. */ + {KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */ + {KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */ + + /* keyboard. */ + {KIND_FILTERED, 0xd2, 0x0d, EV_KEY, KEY_1, 1}, + {KIND_FILTERED, 0xd3, 0x0e, EV_KEY, KEY_2, 1}, + {KIND_FILTERED, 0xd4, 0x0f, EV_KEY, KEY_3, 1}, + {KIND_FILTERED, 0xd5, 0x10, EV_KEY, KEY_4, 1}, + {KIND_FILTERED, 0xd6, 0x11, EV_KEY, KEY_5, 1}, + {KIND_FILTERED, 0xd7, 0x12, EV_KEY, KEY_6, 1}, + {KIND_FILTERED, 0xd8, 0x13, EV_KEY, KEY_7, 1}, + {KIND_FILTERED, 0xd9, 0x14, EV_KEY, KEY_8, 1}, + {KIND_FILTERED, 0xda, 0x15, EV_KEY, KEY_9, 1}, + {KIND_FILTERED, 0xdc, 0x17, EV_KEY, KEY_0, 1}, + {KIND_FILTERED, 0xc5, 0x00, EV_KEY, KEY_A, 1}, + {KIND_FILTERED, 0xc6, 0x01, EV_KEY, KEY_B, 1}, + {KIND_FILTERED, 0xde, 0x19, EV_KEY, KEY_C, 1}, + {KIND_FILTERED, 0xe0, 0x1b, EV_KEY, KEY_D, 1}, + {KIND_FILTERED, 0xe6, 0x21, EV_KEY, KEY_E, 1}, + {KIND_FILTERED, 0xe8, 0x23, EV_KEY, KEY_F, 1}, + + /* "special" keys */ + {KIND_FILTERED, 0xdd, 0x18, EV_KEY, KEY_KPENTER, 1}, /* "check" */ + {KIND_FILTERED, 0xdb, 0x16, EV_KEY, KEY_MENU, 1}, /* "menu" */ + {KIND_FILTERED, 0xc7, 0x02, EV_KEY, KEY_POWER, 1}, /* Power */ + {KIND_FILTERED, 0xc8, 0x03, EV_KEY, KEY_TV, 1}, /* TV */ + {KIND_FILTERED, 0xc9, 0x04, EV_KEY, KEY_DVD, 1}, /* DVD */ + {KIND_FILTERED, 0xca, 0x05, EV_KEY, KEY_WWW, 1}, /* WEB */ + {KIND_FILTERED, 0xcb, 0x06, EV_KEY, KEY_BOOKMARKS, 1}, /* "book" */ + {KIND_FILTERED, 0xcc, 0x07, EV_KEY, KEY_EDIT, 1}, /* "hand" */ + {KIND_FILTERED, 0xe1, 0x1c, EV_KEY, KEY_COFFEE, 1}, /* "timer" */ + {KIND_FILTERED, 0xe5, 0x20, EV_KEY, KEY_FRONT, 1}, /* "max" */ + {KIND_FILTERED, 0xe2, 0x1d, EV_KEY, KEY_LEFT, 1}, /* left */ + {KIND_FILTERED, 0xe4, 0x1f, EV_KEY, KEY_RIGHT, 1}, /* right */ + {KIND_FILTERED, 0xe7, 0x22, EV_KEY, KEY_DOWN, 1}, /* down */ + {KIND_FILTERED, 0xdf, 0x1a, EV_KEY, KEY_UP, 1}, /* up */ + {KIND_FILTERED, 0xe3, 0x1e, EV_KEY, KEY_OK, 1}, /* "OK" */ + {KIND_FILTERED, 0xce, 0x09, EV_KEY, KEY_VOLUMEDOWN, 1}, /* VOL + */ + {KIND_FILTERED, 0xcd, 0x08, EV_KEY, KEY_VOLUMEUP, 1}, /* VOL - */ + {KIND_FILTERED, 0xcf, 0x0a, EV_KEY, KEY_MUTE, 1}, /* MUTE */ + {KIND_FILTERED, 0xd0, 0x0b, EV_KEY, KEY_CHANNELUP, 1}, /* CH + */ + {KIND_FILTERED, 0xd1, 0x0c, EV_KEY, KEY_CHANNELDOWN, 1},/* CH - */ + {KIND_FILTERED, 0xec, 0x27, EV_KEY, KEY_RECORD, 1}, /* ( o) red */ + {KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAY, 1}, /* ( >) */ + {KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1}, /* (<<) */ + {KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1}, /* (>>) */ + {KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1}, /* ([]) */ + {KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_PAUSE, 1}, /* ('') */ + {KIND_FILTERED, 0xf0, 0x2b, EV_KEY, KEY_PREVIOUS, 1}, /* (<-) */ + {KIND_FILTERED, 0xef, 0x2a, EV_KEY, KEY_NEXT, 1}, /* (>+) */ + {KIND_FILTERED, 0xf2, 0x2D, EV_KEY, KEY_INFO, 1}, /* PLAYING */ + {KIND_FILTERED, 0xf3, 0x2E, EV_KEY, KEY_HOME, 1}, /* TOP */ + {KIND_FILTERED, 0xf4, 0x2F, EV_KEY, KEY_END, 1}, /* END */ + {KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_SELECT, 1}, /* SELECT */ + + {KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0} +}; + +/* Local function prototypes */ +static int ati_remote_open (struct input_dev *inputdev); +static void ati_remote_close (struct input_dev *inputdev); +static int ati_remote_sendpacket (struct ati_remote *ati_remote, u16 cmd, unsigned char *data); +static void ati_remote_irq_out (struct urb *urb); +static void ati_remote_irq_in (struct urb *urb); +static void ati_remote_input_report (struct urb *urb); +static int ati_remote_initialize (struct ati_remote *ati_remote); +static int ati_remote_probe (struct usb_interface *interface, const struct usb_device_id *id); +static void ati_remote_disconnect (struct usb_interface *interface); + +/* usb specific object to register with the usb subsystem */ +static struct usb_driver ati_remote_driver = { + .name = "ati_remote", + .probe = ati_remote_probe, + .disconnect = ati_remote_disconnect, + .id_table = ati_remote_table, +}; + +/* + * ati_remote_dump_input + */ +static void ati_remote_dump(struct device *dev, unsigned char *data, + unsigned int len) +{ + if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00)) + dev_warn(dev, "Weird byte 0x%02x\n", data[0]); + else if (len == 4) + dev_warn(dev, "Weird key %02x %02x %02x %02x\n", + data[0], data[1], data[2], data[3]); + else + dev_warn(dev, "Weird data, len=%d %02x %02x %02x %02x %02x %02x ...\n", + len, data[0], data[1], data[2], data[3], data[4], data[5]); +} + +/* + * ati_remote_open + */ +static int ati_remote_open(struct input_dev *inputdev) +{ + struct ati_remote *ati_remote = input_get_drvdata(inputdev); + + /* On first open, submit the read urb which was set up previously. */ + ati_remote->irq_urb->dev = ati_remote->udev; + if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) { + dev_err(&ati_remote->interface->dev, + "%s: usb_submit_urb failed!\n", __func__); + return -EIO; + } + + return 0; +} + +/* + * ati_remote_close + */ +static void ati_remote_close(struct input_dev *inputdev) +{ + struct ati_remote *ati_remote = input_get_drvdata(inputdev); + + usb_kill_urb(ati_remote->irq_urb); +} + +/* + * ati_remote_irq_out + */ +static void ati_remote_irq_out(struct urb *urb) +{ + struct ati_remote *ati_remote = urb->context; + + if (urb->status) { + dev_dbg(&ati_remote->interface->dev, "%s: status %d\n", + __func__, urb->status); + return; + } + + ati_remote->send_flags |= SEND_FLAG_COMPLETE; + wmb(); + wake_up(&ati_remote->wait); +} + +/* + * ati_remote_sendpacket + * + * Used to send device initialization strings + */ +static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigned char *data) +{ + int retval = 0; + + /* Set up out_urb */ + memcpy(ati_remote->out_urb->transfer_buffer + 1, data, LO(cmd)); + ((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd); + + ati_remote->out_urb->transfer_buffer_length = LO(cmd) + 1; + ati_remote->out_urb->dev = ati_remote->udev; + ati_remote->send_flags = SEND_FLAG_IN_PROGRESS; + + retval = usb_submit_urb(ati_remote->out_urb, GFP_ATOMIC); + if (retval) { + dev_dbg(&ati_remote->interface->dev, + "sendpacket: usb_submit_urb failed: %d\n", retval); + return retval; + } + + wait_event_timeout(ati_remote->wait, + ((ati_remote->out_urb->status != -EINPROGRESS) || + (ati_remote->send_flags & SEND_FLAG_COMPLETE)), + HZ); + usb_kill_urb(ati_remote->out_urb); + + return retval; +} + +/* + * ati_remote_event_lookup + */ +static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2) +{ + int i; + + for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) { + /* + * Decide if the table entry matches the remote input. + */ + if ((((ati_remote_tbl[i].data1 & 0x0f) == (d1 & 0x0f))) && + ((((ati_remote_tbl[i].data1 >> 4) - + (d1 >> 4) + rem) & 0x0f) == 0x0f) && + (ati_remote_tbl[i].data2 == d2)) + return i; + + } + return -1; +} + +/* + * ati_remote_compute_accel + * + * Implements acceleration curve for directional control pad + * If elapsed time since last event is > 1/4 second, user "stopped", + * so reset acceleration. Otherwise, user is probably holding the control + * pad down, so we increase acceleration, ramping up over two seconds to + * a maximum speed. + */ +static int ati_remote_compute_accel(struct ati_remote *ati_remote) +{ + static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 }; + unsigned long now = jiffies; + int acc; + + if (time_after(now, ati_remote->old_jiffies + msecs_to_jiffies(250))) { + acc = 1; + ati_remote->acc_jiffies = now; + } + else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(125))) + acc = accel[0]; + else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(250))) + acc = accel[1]; + else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(500))) + acc = accel[2]; + else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1000))) + acc = accel[3]; + else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1500))) + acc = accel[4]; + else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(2000))) + acc = accel[5]; + else + acc = accel[6]; + + return acc; +} + +/* + * ati_remote_report_input + */ +static void ati_remote_input_report(struct urb *urb) +{ + struct ati_remote *ati_remote = urb->context; + unsigned char *data= ati_remote->inbuf; + struct input_dev *dev = ati_remote->idev; + int index, acc; + int remote_num; + + /* Deal with strange looking inputs */ + if ( (urb->actual_length != 4) || (data[0] != 0x14) || + ((data[3] & 0x0f) != 0x00) ) { + ati_remote_dump(&urb->dev->dev, data, urb->actual_length); + return; + } + + /* Mask unwanted remote channels. */ + /* note: remote_num is 0-based, channel 1 on remote == 0 here */ + remote_num = (data[3] >> 4) & 0x0f; + if (channel_mask & (1 << (remote_num + 1))) { + dbginfo(&ati_remote->interface->dev, + "Masked input from channel 0x%02x: data %02x,%02x, mask= 0x%02lx\n", + remote_num, data[1], data[2], channel_mask); + return; + } + + /* Look up event code index in translation table */ + index = ati_remote_event_lookup(remote_num, data[1], data[2]); + if (index < 0) { + dev_warn(&ati_remote->interface->dev, + "Unknown input from channel 0x%02x: data %02x,%02x\n", + remote_num, data[1], data[2]); + return; + } + dbginfo(&ati_remote->interface->dev, + "channel 0x%02x; data %02x,%02x; index %d; keycode %d\n", + remote_num, data[1], data[2], index, ati_remote_tbl[index].code); + + if (ati_remote_tbl[index].kind == KIND_LITERAL) { + input_event(dev, ati_remote_tbl[index].type, + ati_remote_tbl[index].code, + ati_remote_tbl[index].value); + input_sync(dev); + + ati_remote->old_jiffies = jiffies; + return; + } + + if (ati_remote_tbl[index].kind == KIND_FILTERED) { + unsigned long now = jiffies; + + /* Filter duplicate events which happen "too close" together. */ + if (ati_remote->old_data[0] == data[1] && + ati_remote->old_data[1] == data[2] && + time_before(now, ati_remote->old_jiffies + + msecs_to_jiffies(repeat_filter))) { + ati_remote->repeat_count++; + } else { + ati_remote->repeat_count = 0; + ati_remote->first_jiffies = now; + } + + ati_remote->old_data[0] = data[1]; + ati_remote->old_data[1] = data[2]; + ati_remote->old_jiffies = now; + + /* Ensure we skip at least the 4 first duplicate events (generated + * by a single keypress), and continue skipping until repeat_delay + * msecs have passed + */ + if (ati_remote->repeat_count > 0 && + (ati_remote->repeat_count < 5 || + time_before(now, ati_remote->first_jiffies + + msecs_to_jiffies(repeat_delay)))) + return; + + + input_event(dev, ati_remote_tbl[index].type, + ati_remote_tbl[index].code, 1); + input_sync(dev); + input_event(dev, ati_remote_tbl[index].type, + ati_remote_tbl[index].code, 0); + input_sync(dev); + + } else { + + /* + * Other event kinds are from the directional control pad, and have an + * acceleration factor applied to them. Without this acceleration, the + * control pad is mostly unusable. + */ + acc = ati_remote_compute_accel(ati_remote); + + switch (ati_remote_tbl[index].kind) { + case KIND_ACCEL: + input_event(dev, ati_remote_tbl[index].type, + ati_remote_tbl[index].code, + ati_remote_tbl[index].value * acc); + break; + case KIND_LU: + input_report_rel(dev, REL_X, -acc); + input_report_rel(dev, REL_Y, -acc); + break; + case KIND_RU: + input_report_rel(dev, REL_X, acc); + input_report_rel(dev, REL_Y, -acc); + break; + case KIND_LD: + input_report_rel(dev, REL_X, -acc); + input_report_rel(dev, REL_Y, acc); + break; + case KIND_RD: + input_report_rel(dev, REL_X, acc); + input_report_rel(dev, REL_Y, acc); + break; + default: + dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n", + ati_remote_tbl[index].kind); + } + input_sync(dev); + + ati_remote->old_jiffies = jiffies; + ati_remote->old_data[0] = data[1]; + ati_remote->old_data[1] = data[2]; + } +} + +/* + * ati_remote_irq_in + */ +static void ati_remote_irq_in(struct urb *urb) +{ + struct ati_remote *ati_remote = urb->context; + int retval; + + switch (urb->status) { + case 0: /* success */ + ati_remote_input_report(urb); + break; + case -ECONNRESET: /* unlink */ + case -ENOENT: + case -ESHUTDOWN: + dev_dbg(&ati_remote->interface->dev, "%s: urb error status, unlink? \n", + __func__); + return; + default: /* error */ + dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n", + __func__, urb->status); + } + + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) + dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n", + __func__, retval); +} + +/* + * ati_remote_alloc_buffers + */ +static int ati_remote_alloc_buffers(struct usb_device *udev, + struct ati_remote *ati_remote) +{ + ati_remote->inbuf = usb_alloc_coherent(udev, DATA_BUFSIZE, GFP_ATOMIC, + &ati_remote->inbuf_dma); + if (!ati_remote->inbuf) + return -1; + + ati_remote->outbuf = usb_alloc_coherent(udev, DATA_BUFSIZE, GFP_ATOMIC, + &ati_remote->outbuf_dma); + if (!ati_remote->outbuf) + return -1; + + ati_remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!ati_remote->irq_urb) + return -1; + + ati_remote->out_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!ati_remote->out_urb) + return -1; + + return 0; +} + +/* + * ati_remote_free_buffers + */ +static void ati_remote_free_buffers(struct ati_remote *ati_remote) +{ + usb_free_urb(ati_remote->irq_urb); + usb_free_urb(ati_remote->out_urb); + + usb_free_coherent(ati_remote->udev, DATA_BUFSIZE, + ati_remote->inbuf, ati_remote->inbuf_dma); + + usb_free_coherent(ati_remote->udev, DATA_BUFSIZE, + ati_remote->outbuf, ati_remote->outbuf_dma); +} + +static void ati_remote_input_init(struct ati_remote *ati_remote) +{ + struct input_dev *idev = ati_remote->idev; + int i; + + idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); + idev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) | + BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA); + idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); + for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) + if (ati_remote_tbl[i].type == EV_KEY) + set_bit(ati_remote_tbl[i].code, idev->keybit); + + input_set_drvdata(idev, ati_remote); + + idev->open = ati_remote_open; + idev->close = ati_remote_close; + + idev->name = ati_remote->name; + idev->phys = ati_remote->phys; + + usb_to_input_id(ati_remote->udev, &idev->id); + idev->dev.parent = &ati_remote->udev->dev; +} + +static int ati_remote_initialize(struct ati_remote *ati_remote) +{ + struct usb_device *udev = ati_remote->udev; + int pipe, maxp; + + init_waitqueue_head(&ati_remote->wait); + + /* Set up irq_urb */ + pipe = usb_rcvintpipe(udev, ati_remote->endpoint_in->bEndpointAddress); + maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); + maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp; + + usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf, + maxp, ati_remote_irq_in, ati_remote, + ati_remote->endpoint_in->bInterval); + ati_remote->irq_urb->transfer_dma = ati_remote->inbuf_dma; + ati_remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + /* Set up out_urb */ + pipe = usb_sndintpipe(udev, ati_remote->endpoint_out->bEndpointAddress); + maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); + maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp; + + usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf, + maxp, ati_remote_irq_out, ati_remote, + ati_remote->endpoint_out->bInterval); + ati_remote->out_urb->transfer_dma = ati_remote->outbuf_dma; + ati_remote->out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + /* send initialization strings */ + if ((ati_remote_sendpacket(ati_remote, 0x8004, init1)) || + (ati_remote_sendpacket(ati_remote, 0x8007, init2))) { + dev_err(&ati_remote->interface->dev, + "Initializing ati_remote hardware failed.\n"); + return -EIO; + } + + return 0; +} + +/* + * ati_remote_probe + */ +static int ati_remote_probe(struct usb_interface *interface, const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(interface); + struct usb_host_interface *iface_host = interface->cur_altsetting; + struct usb_endpoint_descriptor *endpoint_in, *endpoint_out; + struct ati_remote *ati_remote; + struct input_dev *input_dev; + int err = -ENOMEM; + + if (iface_host->desc.bNumEndpoints != 2) { + err("%s: Unexpected desc.bNumEndpoints\n", __func__); + return -ENODEV; + } + + endpoint_in = &iface_host->endpoint[0].desc; + endpoint_out = &iface_host->endpoint[1].desc; + + if (!usb_endpoint_is_int_in(endpoint_in)) { + err("%s: Unexpected endpoint_in\n", __func__); + return -ENODEV; + } + if (le16_to_cpu(endpoint_in->wMaxPacketSize) == 0) { + err("%s: endpoint_in message size==0? \n", __func__); + return -ENODEV; + } + + ati_remote = kzalloc(sizeof (struct ati_remote), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!ati_remote || !input_dev) + goto fail1; + + /* Allocate URB buffers, URBs */ + if (ati_remote_alloc_buffers(udev, ati_remote)) + goto fail2; + + ati_remote->endpoint_in = endpoint_in; + ati_remote->endpoint_out = endpoint_out; + ati_remote->udev = udev; + ati_remote->idev = input_dev; + ati_remote->interface = interface; + + usb_make_path(udev, ati_remote->phys, sizeof(ati_remote->phys)); + strlcat(ati_remote->phys, "/input0", sizeof(ati_remote->phys)); + + if (udev->manufacturer) + strlcpy(ati_remote->name, udev->manufacturer, sizeof(ati_remote->name)); + + if (udev->product) + snprintf(ati_remote->name, sizeof(ati_remote->name), + "%s %s", ati_remote->name, udev->product); + + if (!strlen(ati_remote->name)) + snprintf(ati_remote->name, sizeof(ati_remote->name), + DRIVER_DESC "(%04x,%04x)", + le16_to_cpu(ati_remote->udev->descriptor.idVendor), + le16_to_cpu(ati_remote->udev->descriptor.idProduct)); + + ati_remote_input_init(ati_remote); + + /* Device Hardware Initialization - fills in ati_remote->idev from udev. */ + err = ati_remote_initialize(ati_remote); + if (err) + goto fail3; + + /* Set up and register input device */ + err = input_register_device(ati_remote->idev); + if (err) + goto fail3; + + usb_set_intfdata(interface, ati_remote); + return 0; + + fail3: usb_kill_urb(ati_remote->irq_urb); + usb_kill_urb(ati_remote->out_urb); + fail2: ati_remote_free_buffers(ati_remote); + fail1: input_free_device(input_dev); + kfree(ati_remote); + return err; +} + +/* + * ati_remote_disconnect + */ +static void ati_remote_disconnect(struct usb_interface *interface) +{ + struct ati_remote *ati_remote; + + ati_remote = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); + if (!ati_remote) { + dev_warn(&interface->dev, "%s - null device?\n", __func__); + return; + } + + usb_kill_urb(ati_remote->irq_urb); + usb_kill_urb(ati_remote->out_urb); + input_unregister_device(ati_remote->idev); + ati_remote_free_buffers(ati_remote); + kfree(ati_remote); +} + +/* + * ati_remote_init + */ +static int __init ati_remote_init(void) +{ + int result; + + result = usb_register(&ati_remote_driver); + if (result) + printk(KERN_ERR KBUILD_MODNAME + ": usb_register error #%d\n", result); + else + printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" + DRIVER_DESC "\n"); + + return result; +} + +/* + * ati_remote_exit + */ +static void __exit ati_remote_exit(void) +{ + usb_deregister(&ati_remote_driver); +} + +/* + * module specification + */ + +module_init(ati_remote_init); +module_exit(ati_remote_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From c34516e599d9c00388ab49e88f3e9e38f8fc5346 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Sat, 6 Aug 2011 18:18:08 -0300 Subject: [media] ati_remote: migrate to the rc subsystem The keycode mangling algorithm is kept the same, so the new external keymap has the same values as the old static table. [mchehab@redhat.com: Fix some bad whitespacing] Signed-off-by: Anssi Hannula Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 756884e..ea45f35 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -111,6 +111,7 @@ config IR_LIRC_CODEC config RC_ATI_REMOTE tristate "ATI / X10 USB RF remote control" depends on USB_ARCH_HAS_HCD + depends on RC_CORE select USB help Say Y here if you want to use an ATI or X10 "Lola" USB remote control. diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index 53388a5..4b4509a 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c @@ -1,6 +1,7 @@ /* * USB ATI Remote support * + * Copyright (c) 2011 Anssi Hannula * Version 2.2.0 Copyright (c) 2004 Torrey Hoffman * Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev * @@ -90,9 +91,11 @@ #include #include #include +#include #include #include #include +#include /* * Module and Version Information, Module Parameters @@ -139,6 +142,10 @@ static int repeat_delay = REPEAT_DELAY; module_param(repeat_delay, int, 0644); MODULE_PARM_DESC(repeat_delay, "Delay before sending repeats, default = 500 msec"); +static bool mouse = true; +module_param(mouse, bool, 0444); +MODULE_PARM_DESC(mouse, "Enable mouse device, default = yes"); + #define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0) #undef err #define err(format, arg...) printk(KERN_ERR format , ## arg) @@ -167,6 +174,7 @@ static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 }; struct ati_remote { struct input_dev *idev; + struct rc_dev *rdev; struct usb_device *udev; struct usb_interface *interface; @@ -186,11 +194,16 @@ struct ati_remote { unsigned int repeat_count; - char name[NAME_BUFSIZE]; - char phys[NAME_BUFSIZE]; + char rc_name[NAME_BUFSIZE]; + char rc_phys[NAME_BUFSIZE]; + char mouse_name[NAME_BUFSIZE]; + char mouse_phys[NAME_BUFSIZE]; wait_queue_head_t wait; int send_flags; + + int users; /* 0-2, users are rc and input */ + struct mutex open_mutex; }; /* "Kinds" of messages sent from the hardware to the driver. */ @@ -233,64 +246,11 @@ static const struct { {KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */ {KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */ - /* keyboard. */ - {KIND_FILTERED, 0xd2, 0x0d, EV_KEY, KEY_1, 1}, - {KIND_FILTERED, 0xd3, 0x0e, EV_KEY, KEY_2, 1}, - {KIND_FILTERED, 0xd4, 0x0f, EV_KEY, KEY_3, 1}, - {KIND_FILTERED, 0xd5, 0x10, EV_KEY, KEY_4, 1}, - {KIND_FILTERED, 0xd6, 0x11, EV_KEY, KEY_5, 1}, - {KIND_FILTERED, 0xd7, 0x12, EV_KEY, KEY_6, 1}, - {KIND_FILTERED, 0xd8, 0x13, EV_KEY, KEY_7, 1}, - {KIND_FILTERED, 0xd9, 0x14, EV_KEY, KEY_8, 1}, - {KIND_FILTERED, 0xda, 0x15, EV_KEY, KEY_9, 1}, - {KIND_FILTERED, 0xdc, 0x17, EV_KEY, KEY_0, 1}, - {KIND_FILTERED, 0xc5, 0x00, EV_KEY, KEY_A, 1}, - {KIND_FILTERED, 0xc6, 0x01, EV_KEY, KEY_B, 1}, - {KIND_FILTERED, 0xde, 0x19, EV_KEY, KEY_C, 1}, - {KIND_FILTERED, 0xe0, 0x1b, EV_KEY, KEY_D, 1}, - {KIND_FILTERED, 0xe6, 0x21, EV_KEY, KEY_E, 1}, - {KIND_FILTERED, 0xe8, 0x23, EV_KEY, KEY_F, 1}, - - /* "special" keys */ - {KIND_FILTERED, 0xdd, 0x18, EV_KEY, KEY_KPENTER, 1}, /* "check" */ - {KIND_FILTERED, 0xdb, 0x16, EV_KEY, KEY_MENU, 1}, /* "menu" */ - {KIND_FILTERED, 0xc7, 0x02, EV_KEY, KEY_POWER, 1}, /* Power */ - {KIND_FILTERED, 0xc8, 0x03, EV_KEY, KEY_TV, 1}, /* TV */ - {KIND_FILTERED, 0xc9, 0x04, EV_KEY, KEY_DVD, 1}, /* DVD */ - {KIND_FILTERED, 0xca, 0x05, EV_KEY, KEY_WWW, 1}, /* WEB */ - {KIND_FILTERED, 0xcb, 0x06, EV_KEY, KEY_BOOKMARKS, 1}, /* "book" */ - {KIND_FILTERED, 0xcc, 0x07, EV_KEY, KEY_EDIT, 1}, /* "hand" */ - {KIND_FILTERED, 0xe1, 0x1c, EV_KEY, KEY_COFFEE, 1}, /* "timer" */ - {KIND_FILTERED, 0xe5, 0x20, EV_KEY, KEY_FRONT, 1}, /* "max" */ - {KIND_FILTERED, 0xe2, 0x1d, EV_KEY, KEY_LEFT, 1}, /* left */ - {KIND_FILTERED, 0xe4, 0x1f, EV_KEY, KEY_RIGHT, 1}, /* right */ - {KIND_FILTERED, 0xe7, 0x22, EV_KEY, KEY_DOWN, 1}, /* down */ - {KIND_FILTERED, 0xdf, 0x1a, EV_KEY, KEY_UP, 1}, /* up */ - {KIND_FILTERED, 0xe3, 0x1e, EV_KEY, KEY_OK, 1}, /* "OK" */ - {KIND_FILTERED, 0xce, 0x09, EV_KEY, KEY_VOLUMEDOWN, 1}, /* VOL + */ - {KIND_FILTERED, 0xcd, 0x08, EV_KEY, KEY_VOLUMEUP, 1}, /* VOL - */ - {KIND_FILTERED, 0xcf, 0x0a, EV_KEY, KEY_MUTE, 1}, /* MUTE */ - {KIND_FILTERED, 0xd0, 0x0b, EV_KEY, KEY_CHANNELUP, 1}, /* CH + */ - {KIND_FILTERED, 0xd1, 0x0c, EV_KEY, KEY_CHANNELDOWN, 1},/* CH - */ - {KIND_FILTERED, 0xec, 0x27, EV_KEY, KEY_RECORD, 1}, /* ( o) red */ - {KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAY, 1}, /* ( >) */ - {KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1}, /* (<<) */ - {KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1}, /* (>>) */ - {KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1}, /* ([]) */ - {KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_PAUSE, 1}, /* ('') */ - {KIND_FILTERED, 0xf0, 0x2b, EV_KEY, KEY_PREVIOUS, 1}, /* (<-) */ - {KIND_FILTERED, 0xef, 0x2a, EV_KEY, KEY_NEXT, 1}, /* (>+) */ - {KIND_FILTERED, 0xf2, 0x2D, EV_KEY, KEY_INFO, 1}, /* PLAYING */ - {KIND_FILTERED, 0xf3, 0x2E, EV_KEY, KEY_HOME, 1}, /* TOP */ - {KIND_FILTERED, 0xf4, 0x2F, EV_KEY, KEY_END, 1}, /* END */ - {KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_SELECT, 1}, /* SELECT */ - + /* Non-mouse events are handled by rc-core */ {KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0} }; /* Local function prototypes */ -static int ati_remote_open (struct input_dev *inputdev); -static void ati_remote_close (struct input_dev *inputdev); static int ati_remote_sendpacket (struct ati_remote *ati_remote, u16 cmd, unsigned char *data); static void ati_remote_irq_out (struct urb *urb); static void ati_remote_irq_in (struct urb *urb); @@ -326,29 +286,60 @@ static void ati_remote_dump(struct device *dev, unsigned char *data, /* * ati_remote_open */ -static int ati_remote_open(struct input_dev *inputdev) +static int ati_remote_open(struct ati_remote *ati_remote) { - struct ati_remote *ati_remote = input_get_drvdata(inputdev); + int err = 0; + + mutex_lock(&ati_remote->open_mutex); + + if (ati_remote->users++ != 0) + goto out; /* one was already active */ /* On first open, submit the read urb which was set up previously. */ ati_remote->irq_urb->dev = ati_remote->udev; if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) { dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb failed!\n", __func__); - return -EIO; + err = -EIO; } - return 0; +out: mutex_unlock(&ati_remote->open_mutex); + return err; } /* * ati_remote_close */ -static void ati_remote_close(struct input_dev *inputdev) +static void ati_remote_close(struct ati_remote *ati_remote) +{ + mutex_lock(&ati_remote->open_mutex); + if (--ati_remote->users == 0) + usb_kill_urb(ati_remote->irq_urb); + mutex_unlock(&ati_remote->open_mutex); +} + +static int ati_remote_input_open(struct input_dev *inputdev) { struct ati_remote *ati_remote = input_get_drvdata(inputdev); + return ati_remote_open(ati_remote); +} - usb_kill_urb(ati_remote->irq_urb); +static void ati_remote_input_close(struct input_dev *inputdev) +{ + struct ati_remote *ati_remote = input_get_drvdata(inputdev); + ati_remote_close(ati_remote); +} + +static int ati_remote_rc_open(struct rc_dev *rdev) +{ + struct ati_remote *ati_remote = rdev->priv; + return ati_remote_open(ati_remote); +} + +static void ati_remote_rc_close(struct rc_dev *rdev) +{ + struct ati_remote *ati_remote = rdev->priv; + ati_remote_close(ati_remote); } /* @@ -413,10 +404,8 @@ static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2) /* * Decide if the table entry matches the remote input. */ - if ((((ati_remote_tbl[i].data1 & 0x0f) == (d1 & 0x0f))) && - ((((ati_remote_tbl[i].data1 >> 4) - - (d1 >> 4) + rem) & 0x0f) == 0x0f) && - (ati_remote_tbl[i].data2 == d2)) + if (ati_remote_tbl[i].data1 == d1 && + ati_remote_tbl[i].data2 == d2) return i; } @@ -468,8 +457,10 @@ static void ati_remote_input_report(struct urb *urb) struct ati_remote *ati_remote = urb->context; unsigned char *data= ati_remote->inbuf; struct input_dev *dev = ati_remote->idev; - int index, acc; + int index = -1; + int acc; int remote_num; + unsigned char scancode[2]; /* Deal with strange looking inputs */ if ( (urb->actual_length != 4) || (data[0] != 0x14) || @@ -488,19 +479,26 @@ static void ati_remote_input_report(struct urb *urb) return; } - /* Look up event code index in translation table */ - index = ati_remote_event_lookup(remote_num, data[1], data[2]); - if (index < 0) { - dev_warn(&ati_remote->interface->dev, - "Unknown input from channel 0x%02x: data %02x,%02x\n", - remote_num, data[1], data[2]); - return; - } - dbginfo(&ati_remote->interface->dev, - "channel 0x%02x; data %02x,%02x; index %d; keycode %d\n", - remote_num, data[1], data[2], index, ati_remote_tbl[index].code); + scancode[0] = (((data[1] - ((remote_num + 1) << 4)) & 0xf0) | (data[1] & 0x0f)); + + scancode[1] = data[2]; + + /* Look up event code index in mouse translation table. */ + index = ati_remote_event_lookup(remote_num, scancode[0], scancode[1]); + + if (index >= 0) { + dbginfo(&ati_remote->interface->dev, + "channel 0x%02x; mouse data %02x,%02x; index %d; keycode %d\n", + remote_num, data[1], data[2], index, ati_remote_tbl[index].code); + if (!dev) + return; /* no mouse device */ + } else + dbginfo(&ati_remote->interface->dev, + "channel 0x%02x; key data %02x,%02x, scancode %02x,%02x\n", + remote_num, data[1], data[2], scancode[0], scancode[1]); - if (ati_remote_tbl[index].kind == KIND_LITERAL) { + + if (index >= 0 && ati_remote_tbl[index].kind == KIND_LITERAL) { input_event(dev, ati_remote_tbl[index].type, ati_remote_tbl[index].code, ati_remote_tbl[index].value); @@ -510,7 +508,7 @@ static void ati_remote_input_report(struct urb *urb) return; } - if (ati_remote_tbl[index].kind == KIND_FILTERED) { + if (index < 0 || ati_remote_tbl[index].kind == KIND_FILTERED) { unsigned long now = jiffies; /* Filter duplicate events which happen "too close" together. */ @@ -538,6 +536,19 @@ static void ati_remote_input_report(struct urb *urb) msecs_to_jiffies(repeat_delay)))) return; + if (index < 0) { + /* Not a mouse event, hand it to rc-core. */ + u32 rc_code = (scancode[0] << 8) | scancode[1]; + + /* + * We don't use the rc-core repeat handling yet as + * it would cause ghost repeats which would be a + * regression for this driver. + */ + rc_keydown_notimeout(ati_remote->rdev, rc_code, 0); + rc_keyup(ati_remote->rdev); + return; + } input_event(dev, ati_remote_tbl[index].type, ati_remote_tbl[index].code, 1); @@ -675,16 +686,37 @@ static void ati_remote_input_init(struct ati_remote *ati_remote) input_set_drvdata(idev, ati_remote); - idev->open = ati_remote_open; - idev->close = ati_remote_close; + idev->open = ati_remote_input_open; + idev->close = ati_remote_input_close; - idev->name = ati_remote->name; - idev->phys = ati_remote->phys; + idev->name = ati_remote->mouse_name; + idev->phys = ati_remote->mouse_phys; usb_to_input_id(ati_remote->udev, &idev->id); idev->dev.parent = &ati_remote->udev->dev; } +static void ati_remote_rc_init(struct ati_remote *ati_remote) +{ + struct rc_dev *rdev = ati_remote->rdev; + + rdev->priv = ati_remote; + rdev->driver_type = RC_DRIVER_SCANCODE; + rdev->allowed_protos = RC_TYPE_OTHER; + rdev->driver_name = "ati_remote"; + + rdev->open = ati_remote_rc_open; + rdev->close = ati_remote_rc_close; + + rdev->input_name = ati_remote->rc_name; + rdev->input_phys = ati_remote->rc_phys; + + usb_to_input_id(ati_remote->udev, &rdev->input_id); + rdev->dev.parent = &ati_remote->udev->dev; + + rdev->map_name = RC_MAP_ATI_X10; +} + static int ati_remote_initialize(struct ati_remote *ati_remote) { struct usb_device *udev = ati_remote->udev; @@ -735,6 +767,7 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de struct usb_endpoint_descriptor *endpoint_in, *endpoint_out; struct ati_remote *ati_remote; struct input_dev *input_dev; + struct rc_dev *rc_dev; int err = -ENOMEM; if (iface_host->desc.bNumEndpoints != 2) { @@ -755,8 +788,8 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de } ati_remote = kzalloc(sizeof (struct ati_remote), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!ati_remote || !input_dev) + rc_dev = rc_allocate_device(); + if (!ati_remote || !rc_dev) goto fail1; /* Allocate URB buffers, URBs */ @@ -766,44 +799,73 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de ati_remote->endpoint_in = endpoint_in; ati_remote->endpoint_out = endpoint_out; ati_remote->udev = udev; - ati_remote->idev = input_dev; + ati_remote->rdev = rc_dev; ati_remote->interface = interface; - usb_make_path(udev, ati_remote->phys, sizeof(ati_remote->phys)); - strlcat(ati_remote->phys, "/input0", sizeof(ati_remote->phys)); + usb_make_path(udev, ati_remote->rc_phys, sizeof(ati_remote->rc_phys)); + strlcpy(ati_remote->mouse_phys, ati_remote->rc_phys, + sizeof(ati_remote->mouse_phys)); + + strlcat(ati_remote->rc_phys, "/input0", sizeof(ati_remote->rc_phys)); + strlcat(ati_remote->mouse_phys, "/input1", sizeof(ati_remote->mouse_phys)); if (udev->manufacturer) - strlcpy(ati_remote->name, udev->manufacturer, sizeof(ati_remote->name)); + strlcpy(ati_remote->rc_name, udev->manufacturer, + sizeof(ati_remote->rc_name)); if (udev->product) - snprintf(ati_remote->name, sizeof(ati_remote->name), - "%s %s", ati_remote->name, udev->product); + snprintf(ati_remote->rc_name, sizeof(ati_remote->rc_name), + "%s %s", ati_remote->rc_name, udev->product); - if (!strlen(ati_remote->name)) - snprintf(ati_remote->name, sizeof(ati_remote->name), + if (!strlen(ati_remote->rc_name)) + snprintf(ati_remote->rc_name, sizeof(ati_remote->rc_name), DRIVER_DESC "(%04x,%04x)", le16_to_cpu(ati_remote->udev->descriptor.idVendor), le16_to_cpu(ati_remote->udev->descriptor.idProduct)); - ati_remote_input_init(ati_remote); + snprintf(ati_remote->mouse_name, sizeof(ati_remote->mouse_name), + "%s mouse", ati_remote->rc_name); + + ati_remote_rc_init(ati_remote); + mutex_init(&ati_remote->open_mutex); /* Device Hardware Initialization - fills in ati_remote->idev from udev. */ err = ati_remote_initialize(ati_remote); if (err) goto fail3; - /* Set up and register input device */ - err = input_register_device(ati_remote->idev); + /* Set up and register rc device */ + err = rc_register_device(ati_remote->rdev); if (err) goto fail3; + /* use our delay for rc_dev */ + ati_remote->rdev->input_dev->rep[REP_DELAY] = repeat_delay; + + /* Set up and register mouse input device */ + if (mouse) { + input_dev = input_allocate_device(); + if (!input_dev) + goto fail4; + + ati_remote->idev = input_dev; + ati_remote_input_init(ati_remote); + err = input_register_device(input_dev); + + if (err) + goto fail5; + } + usb_set_intfdata(interface, ati_remote); return 0; + fail5: input_free_device(input_dev); + fail4: rc_unregister_device(rc_dev); + rc_dev = NULL; fail3: usb_kill_urb(ati_remote->irq_urb); usb_kill_urb(ati_remote->out_urb); fail2: ati_remote_free_buffers(ati_remote); - fail1: input_free_device(input_dev); + fail1: rc_free_device(rc_dev); kfree(ati_remote); return err; } @@ -824,7 +886,9 @@ static void ati_remote_disconnect(struct usb_interface *interface) usb_kill_urb(ati_remote->irq_urb); usb_kill_urb(ati_remote->out_urb); - input_unregister_device(ati_remote->idev); + if (ati_remote->idev) + input_unregister_device(ati_remote->idev); + rc_unregister_device(ati_remote->rdev); ati_remote_free_buffers(ati_remote); kfree(ati_remote); } diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index b57fc83..8dd9fdf 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-apac-viewcomp.o \ rc-asus-pc39.o \ rc-ati-tv-wonder-hd-600.o \ + rc-ati-x10.o \ rc-avermedia-a16d.o \ rc-avermedia.o \ rc-avermedia-cardbus.o \ diff --git a/drivers/media/rc/keymaps/rc-ati-x10.c b/drivers/media/rc/keymaps/rc-ati-x10.c new file mode 100644 index 0000000..f3397f8 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-ati-x10.c @@ -0,0 +1,103 @@ +/* + * ATI X10 RF remote keytable + * + * Copyright (C) 2011 Anssi Hannula + * + * This file is based on the static generic keytable previously found in + * ati_remote.c, which is + * Copyright (c) 2004 Torrey Hoffman + * Copyright (c) 2002 Vladimir Dergachev + * + * 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 of the License, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +static struct rc_map_table ati_x10[] = { + { 0xd20d, KEY_1 }, + { 0xd30e, KEY_2 }, + { 0xd40f, KEY_3 }, + { 0xd510, KEY_4 }, + { 0xd611, KEY_5 }, + { 0xd712, KEY_6 }, + { 0xd813, KEY_7 }, + { 0xd914, KEY_8 }, + { 0xda15, KEY_9 }, + { 0xdc17, KEY_0 }, + { 0xc500, KEY_A }, + { 0xc601, KEY_B }, + { 0xde19, KEY_C }, + { 0xe01b, KEY_D }, + { 0xe621, KEY_E }, + { 0xe823, KEY_F }, + + { 0xdd18, KEY_KPENTER }, /* "check" */ + { 0xdb16, KEY_MENU }, /* "menu" */ + { 0xc702, KEY_POWER }, /* Power */ + { 0xc803, KEY_TV }, /* TV */ + { 0xc904, KEY_DVD }, /* DVD */ + { 0xca05, KEY_WWW }, /* WEB */ + { 0xcb06, KEY_BOOKMARKS }, /* "book" */ + { 0xcc07, KEY_EDIT }, /* "hand" */ + { 0xe11c, KEY_COFFEE }, /* "timer" */ + { 0xe520, KEY_FRONT }, /* "max" */ + { 0xe21d, KEY_LEFT }, /* left */ + { 0xe41f, KEY_RIGHT }, /* right */ + { 0xe722, KEY_DOWN }, /* down */ + { 0xdf1a, KEY_UP }, /* up */ + { 0xe31e, KEY_OK }, /* "OK" */ + { 0xce09, KEY_VOLUMEDOWN }, /* VOL + */ + { 0xcd08, KEY_VOLUMEUP }, /* VOL - */ + { 0xcf0a, KEY_MUTE }, /* MUTE */ + { 0xd00b, KEY_CHANNELUP }, /* CH + */ + { 0xd10c, KEY_CHANNELDOWN },/* CH - */ + { 0xec27, KEY_RECORD }, /* ( o) red */ + { 0xea25, KEY_PLAY }, /* ( >) */ + { 0xe924, KEY_REWIND }, /* (<<) */ + { 0xeb26, KEY_FORWARD }, /* (>>) */ + { 0xed28, KEY_STOP }, /* ([]) */ + { 0xee29, KEY_PAUSE }, /* ('') */ + { 0xf02b, KEY_PREVIOUS }, /* (<-) */ + { 0xef2a, KEY_NEXT }, /* (>+) */ + { 0xf22d, KEY_INFO }, /* PLAYING */ + { 0xf32e, KEY_HOME }, /* TOP */ + { 0xf42f, KEY_END }, /* END */ + { 0xf530, KEY_SELECT }, /* SELECT */ +}; + +static struct rc_map_list ati_x10_map = { + .map = { + .scan = ati_x10, + .size = ARRAY_SIZE(ati_x10), + .rc_type = RC_TYPE_OTHER, + .name = RC_MAP_ATI_X10, + } +}; + +static int __init init_rc_map_ati_x10(void) +{ + return rc_map_register(&ati_x10_map); +} + +static void __exit exit_rc_map_ati_x10(void) +{ + rc_map_unregister(&ati_x10_map); +} + +module_init(init_rc_map_ati_x10) +module_exit(exit_rc_map_ati_x10) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Anssi Hannula "); diff --git a/include/media/rc-map.h b/include/media/rc-map.h index 17c9759..14c7461 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -61,6 +61,7 @@ void rc_map_init(void); #define RC_MAP_APAC_VIEWCOMP "rc-apac-viewcomp" #define RC_MAP_ASUS_PC39 "rc-asus-pc39" #define RC_MAP_ATI_TV_WONDER_HD_600 "rc-ati-tv-wonder-hd-600" +#define RC_MAP_ATI_X10 "rc-ati-x10" #define RC_MAP_AVERMEDIA_A16D "rc-avermedia-a16d" #define RC_MAP_AVERMEDIA_CARDBUS "rc-avermedia-cardbus" #define RC_MAP_AVERMEDIA_DVBT "rc-avermedia-dvbt" -- cgit v0.10.2 From 44fd0b600fbc21de9d771f0a5db79d24b321fce7 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Sat, 6 Aug 2011 18:18:09 -0300 Subject: [media] ati_remote: parent input devices to usb interface Parent the input devices to usb_interface instead of usb_device. This fixes (at least) persistent input device nodes. Signed-off-by: Anssi Hannula Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index 4b4509a..7a47d7e 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c @@ -693,7 +693,7 @@ static void ati_remote_input_init(struct ati_remote *ati_remote) idev->phys = ati_remote->mouse_phys; usb_to_input_id(ati_remote->udev, &idev->id); - idev->dev.parent = &ati_remote->udev->dev; + idev->dev.parent = &ati_remote->interface->dev; } static void ati_remote_rc_init(struct ati_remote *ati_remote) @@ -712,7 +712,7 @@ static void ati_remote_rc_init(struct ati_remote *ati_remote) rdev->input_phys = ati_remote->rc_phys; usb_to_input_id(ati_remote->udev, &rdev->input_id); - rdev->dev.parent = &ati_remote->udev->dev; + rdev->dev.parent = &ati_remote->interface->dev; rdev->map_name = RC_MAP_ATI_X10; } -- cgit v0.10.2 From 0224e0401f0b18e1f5fce010558b12fc24257e37 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Sat, 6 Aug 2011 18:18:10 -0300 Subject: [media] ati_remote: fix check for a weird byte The ati_remote_dump() function tries to not print "Weird byte" warning for 1-byte responses that contain 0xff or 0x00, but it doesn't work properly as it simply falls back to the "Weird data" warning in the else clause. Fix that by adding an inner if clause. Signed-off-by: Anssi Hannula Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index 7a47d7e..92f2b1b 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c @@ -273,9 +273,10 @@ static struct usb_driver ati_remote_driver = { static void ati_remote_dump(struct device *dev, unsigned char *data, unsigned int len) { - if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00)) - dev_warn(dev, "Weird byte 0x%02x\n", data[0]); - else if (len == 4) + if (len == 1) { + if (data[0] != (unsigned char)0xff && data[0] != 0x00) + dev_warn(dev, "Weird byte 0x%02x\n", data[0]); + } else if (len == 4) dev_warn(dev, "Weird key %02x %02x %02x %02x\n", data[0], data[1], data[2], data[3]); else -- cgit v0.10.2 From 175fcecf79b4698c7beea5810326dba66a56ea39 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Sat, 6 Aug 2011 18:18:11 -0300 Subject: [media] ati_remote: add keymap for Medion X10 RF remote Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index 92f2b1b..94d241d 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c @@ -151,11 +151,11 @@ MODULE_PARM_DESC(mouse, "Enable mouse device, default = yes"); #define err(format, arg...) printk(KERN_ERR format , ## arg) static struct usb_device_id ati_remote_table[] = { - { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID) }, - { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA2_REMOTE_PRODUCT_ID) }, - { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) }, - { USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID) }, - { USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID) }, + { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)RC_MAP_ATI_X10 }, + { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA2_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)RC_MAP_ATI_X10 }, + { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)RC_MAP_ATI_X10 }, + { USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)RC_MAP_ATI_X10 }, + { USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)RC_MAP_MEDION_X10 }, {} /* Terminating entry */ }; @@ -714,8 +714,6 @@ static void ati_remote_rc_init(struct ati_remote *ati_remote) usb_to_input_id(ati_remote->udev, &rdev->input_id); rdev->dev.parent = &ati_remote->interface->dev; - - rdev->map_name = RC_MAP_ATI_X10; } static int ati_remote_initialize(struct ati_remote *ati_remote) @@ -827,6 +825,11 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de snprintf(ati_remote->mouse_name, sizeof(ati_remote->mouse_name), "%s mouse", ati_remote->rc_name); + if (id->driver_info) + rc_dev->map_name = (const char *)id->driver_info; + else + rc_dev->map_name = RC_MAP_ATI_X10; + ati_remote_rc_init(ati_remote); mutex_init(&ati_remote->open_mutex); diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index 8dd9fdf..2b97b43 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-lirc.o \ rc-lme2510.o \ rc-manli.o \ + rc-medion-x10.o \ rc-msi-digivox-ii.o \ rc-msi-digivox-iii.o \ rc-msi-tvanywhere.o \ diff --git a/drivers/media/rc/keymaps/rc-medion-x10.c b/drivers/media/rc/keymaps/rc-medion-x10.c new file mode 100644 index 0000000..5fc57468 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-medion-x10.c @@ -0,0 +1,116 @@ +/* + * Medion X10 RF remote keytable + * + * Copyright (C) 2011 Anssi Hannula + * + * This file is based on a keytable provided by + * Jan Losinski + * + * 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 of the License, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +static struct rc_map_table medion_x10[] = { + { 0xf12c, KEY_TV }, /* TV */ + { 0xf22d, KEY_VCR }, /* VCR */ + { 0xc904, KEY_DVD }, /* DVD */ + { 0xcb06, KEY_AUDIO }, /* MUSIC */ + + { 0xf32e, KEY_RADIO }, /* RADIO */ + { 0xca05, KEY_DIRECTORY }, /* PHOTO */ + { 0xf42f, KEY_INFO }, /* TV-PREVIEW */ + { 0xf530, KEY_LIST }, /* CHANNEL-LST */ + + { 0xe01b, KEY_SETUP }, /* SETUP */ + { 0xf631, KEY_VIDEO }, /* VIDEO DESKTOP */ + + { 0xcd08, KEY_VOLUMEDOWN }, /* VOL - */ + { 0xce09, KEY_VOLUMEUP }, /* VOL + */ + { 0xd00b, KEY_CHANNELUP }, /* CHAN + */ + { 0xd10c, KEY_CHANNELDOWN }, /* CHAN - */ + { 0xc500, KEY_MUTE }, /* MUTE */ + + { 0xf732, KEY_RED }, /* red */ + { 0xf833, KEY_GREEN }, /* green */ + { 0xf934, KEY_YELLOW }, /* yellow */ + { 0xfa35, KEY_BLUE }, /* blue */ + { 0xdb16, KEY_TEXT }, /* TXT */ + + { 0xd20d, KEY_1 }, + { 0xd30e, KEY_2 }, + { 0xd40f, KEY_3 }, + { 0xd510, KEY_4 }, + { 0xd611, KEY_5 }, + { 0xd712, KEY_6 }, + { 0xd813, KEY_7 }, + { 0xd914, KEY_8 }, + { 0xda15, KEY_9 }, + { 0xdc17, KEY_0 }, + { 0xe11c, KEY_SEARCH }, /* TV/RAD, CH SRC */ + { 0xe520, KEY_DELETE }, /* DELETE */ + + { 0xfb36, KEY_KEYBOARD }, /* RENAME */ + { 0xdd18, KEY_SCREEN }, /* SNAPSHOT */ + + { 0xdf1a, KEY_UP }, /* up */ + { 0xe722, KEY_DOWN }, /* down */ + { 0xe21d, KEY_LEFT }, /* left */ + { 0xe41f, KEY_RIGHT }, /* right */ + { 0xe31e, KEY_OK }, /* OK */ + + { 0xfc37, KEY_SELECT }, /* ACQUIRE IMAGE */ + { 0xfd38, KEY_EDIT }, /* EDIT IMAGE */ + + { 0xe924, KEY_REWIND }, /* rewind (<<) */ + { 0xea25, KEY_PLAY }, /* play ( >) */ + { 0xeb26, KEY_FORWARD }, /* forward (>>) */ + { 0xec27, KEY_RECORD }, /* record ( o) */ + { 0xed28, KEY_STOP }, /* stop ([]) */ + { 0xee29, KEY_PAUSE }, /* pause ('') */ + + { 0xe621, KEY_PREVIOUS }, /* prev */ + { 0xfe39, KEY_SWITCHVIDEOMODE }, /* F SCR */ + { 0xe823, KEY_NEXT }, /* next */ + { 0xde19, KEY_MENU }, /* MENU */ + { 0xff3a, KEY_LANGUAGE }, /* AUDIO */ + + { 0xc702, KEY_POWER }, /* POWER */ +}; + +static struct rc_map_list medion_x10_map = { + .map = { + .scan = medion_x10, + .size = ARRAY_SIZE(medion_x10), + .rc_type = RC_TYPE_OTHER, + .name = RC_MAP_MEDION_X10, + } +}; + +static int __init init_rc_map_medion_x10(void) +{ + return rc_map_register(&medion_x10_map); +} + +static void __exit exit_rc_map_medion_x10(void) +{ + rc_map_unregister(&medion_x10_map); +} + +module_init(init_rc_map_medion_x10) +module_exit(exit_rc_map_medion_x10) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Anssi Hannula "); diff --git a/include/media/rc-map.h b/include/media/rc-map.h index 14c7461..73ae5ee 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -107,6 +107,7 @@ void rc_map_init(void); #define RC_MAP_LIRC "rc-lirc" #define RC_MAP_LME2510 "rc-lme2510" #define RC_MAP_MANLI "rc-manli" +#define RC_MAP_MEDION_X10 "rc-medion-x10" #define RC_MAP_MSI_DIGIVOX_II "rc-msi-digivox-ii" #define RC_MAP_MSI_DIGIVOX_III "rc-msi-digivox-iii" #define RC_MAP_MSI_TVANYWHERE_PLUS "rc-msi-tvanywhere-plus" -- cgit v0.10.2 From 999d6bc9b142a531fb10652c64de51e2ad672a1e Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Sat, 6 Aug 2011 18:18:12 -0300 Subject: [media] ati_remote: add support for SnapStream Firefly remote The protocol differs by having two toggle bits in the scancode. Since one of the bits is otherwise unused, we can safely handle the bits unconditionally. [mchehab@redhat.com: Fix some bad whitespacing] Signed-off-by: Anssi Hannula Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index 94d241d..303f22e 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c @@ -107,6 +107,7 @@ #define ATI_REMOTE_PRODUCT_ID 0x0004 #define NVIDIA_REMOTE_PRODUCT_ID 0x0005 #define MEDION_REMOTE_PRODUCT_ID 0x0006 +#define FIREFLY_REMOTE_PRODUCT_ID 0x0008 #define DRIVER_VERSION "2.2.1" #define DRIVER_AUTHOR "Torrey Hoffman " @@ -156,6 +157,7 @@ static struct usb_device_id ati_remote_table[] = { { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)RC_MAP_ATI_X10 }, { USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)RC_MAP_ATI_X10 }, { USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)RC_MAP_MEDION_X10 }, + { USB_DEVICE(ATI_REMOTE_VENDOR_ID, FIREFLY_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)RC_MAP_SNAPSTREAM_FIREFLY }, {} /* Terminating entry */ }; @@ -482,7 +484,15 @@ static void ati_remote_input_report(struct urb *urb) scancode[0] = (((data[1] - ((remote_num + 1) << 4)) & 0xf0) | (data[1] & 0x0f)); - scancode[1] = data[2]; + /* + * Some devices (e.g. SnapStream Firefly) use 8080 as toggle code, + * so we have to clear them. The first bit is a bit tricky as the + * "non-toggled" state depends on remote_num, so we xor it with the + * second bit which is only used for toggle. + */ + scancode[0] ^= (data[2] & 0x80); + + scancode[1] = data[2] & ~0x80; /* Look up event code index in mouse translation table. */ index = ati_remote_event_lookup(remote_num, scancode[0], scancode[1]); @@ -546,7 +556,8 @@ static void ati_remote_input_report(struct urb *urb) * it would cause ghost repeats which would be a * regression for this driver. */ - rc_keydown_notimeout(ati_remote->rdev, rc_code, 0); + rc_keydown_notimeout(ati_remote->rdev, rc_code, + data[2]); rc_keyup(ati_remote->rdev); return; } diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index 2b97b43..36e4d5e 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -72,6 +72,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-hauppauge.o \ rc-rc6-mce.o \ rc-real-audio-220-32-keys.o \ + rc-snapstream-firefly.o \ rc-streamzap.o \ rc-tbs-nec.o \ rc-technisat-usb2.o \ diff --git a/drivers/media/rc/keymaps/rc-snapstream-firefly.c b/drivers/media/rc/keymaps/rc-snapstream-firefly.c new file mode 100644 index 0000000..5836aa2 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-snapstream-firefly.c @@ -0,0 +1,106 @@ +/* + * SnapStream Firefly X10 RF remote keytable + * + * Copyright (C) 2011 Anssi Hannula + * + * 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 of the License, 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +static struct rc_map_table snapstream_firefly[] = { + { 0xf12c, KEY_ZOOM }, /* Maximize */ + { 0xc702, KEY_CLOSE }, + + { 0xd20d, KEY_1 }, + { 0xd30e, KEY_2 }, + { 0xd40f, KEY_3 }, + { 0xd510, KEY_4 }, + { 0xd611, KEY_5 }, + { 0xd712, KEY_6 }, + { 0xd813, KEY_7 }, + { 0xd914, KEY_8 }, + { 0xda15, KEY_9 }, + { 0xdc17, KEY_0 }, + { 0xdb16, KEY_BACK }, + { 0xdd18, KEY_KPENTER }, /* ent */ + + { 0xce09, KEY_VOLUMEUP }, + { 0xcd08, KEY_VOLUMEDOWN }, + { 0xcf0a, KEY_MUTE }, + { 0xd00b, KEY_CHANNELUP }, + { 0xd10c, KEY_CHANNELDOWN }, + { 0xc500, KEY_VENDOR }, /* firefly */ + + { 0xf32e, KEY_INFO }, + { 0xf42f, KEY_OPTION }, + + { 0xe21d, KEY_LEFT }, + { 0xe41f, KEY_RIGHT }, + { 0xe722, KEY_DOWN }, + { 0xdf1a, KEY_UP }, + { 0xe31e, KEY_OK }, + + { 0xe11c, KEY_MENU }, + { 0xe520, KEY_EXIT }, + + { 0xec27, KEY_RECORD }, + { 0xea25, KEY_PLAY }, + { 0xed28, KEY_STOP }, + { 0xe924, KEY_REWIND }, + { 0xeb26, KEY_FORWARD }, + { 0xee29, KEY_PAUSE }, + { 0xf02b, KEY_PREVIOUS }, + { 0xef2a, KEY_NEXT }, + + { 0xcb06, KEY_AUDIO }, /* Music */ + { 0xca05, KEY_IMAGES }, /* Photos */ + { 0xc904, KEY_DVD }, + { 0xc803, KEY_TV }, + { 0xcc07, KEY_VIDEO }, + + { 0xc601, KEY_HELP }, + { 0xf22d, KEY_MODE }, /* Mouse */ + + { 0xde19, KEY_A }, + { 0xe01b, KEY_B }, + { 0xe621, KEY_C }, + { 0xe823, KEY_D }, +}; + +static struct rc_map_list snapstream_firefly_map = { + .map = { + .scan = snapstream_firefly, + .size = ARRAY_SIZE(snapstream_firefly), + .rc_type = RC_TYPE_OTHER, + .name = RC_MAP_SNAPSTREAM_FIREFLY, + } +}; + +static int __init init_rc_map_snapstream_firefly(void) +{ + return rc_map_register(&snapstream_firefly_map); +} + +static void __exit exit_rc_map_snapstream_firefly(void) +{ + rc_map_unregister(&snapstream_firefly_map); +} + +module_init(init_rc_map_snapstream_firefly) +module_exit(exit_rc_map_snapstream_firefly) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Anssi Hannula "); diff --git a/include/media/rc-map.h b/include/media/rc-map.h index 73ae5ee..26a3bd0 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -132,6 +132,7 @@ void rc_map_init(void); #define RC_MAP_RC5_TV "rc-rc5-tv" #define RC_MAP_RC6_MCE "rc-rc6-mce" #define RC_MAP_REAL_AUDIO_220_32_KEYS "rc-real-audio-220-32-keys" +#define RC_MAP_SNAPSTREAM_FIREFLY "rc-snapstream-firefly" #define RC_MAP_STREAMZAP "rc-streamzap" #define RC_MAP_TBS_NEC "rc-tbs-nec" #define RC_MAP_TECHNISAT_USB2 "rc-technisat-usb2" -- cgit v0.10.2 From 3a7a62378be538944ff00904b8e0b795fe16609a Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Sat, 6 Aug 2011 18:18:13 -0300 Subject: [media] ati_remote: update Kconfig description The ati_remote driver supports more remotes nowadays, update the description to reflect that. Signed-off-by: Anssi Hannula Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index ea45f35..aeb7f43 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -109,16 +109,18 @@ config IR_LIRC_CODEC the LIRC interface. config RC_ATI_REMOTE - tristate "ATI / X10 USB RF remote control" + tristate "ATI / X10 based USB RF remote controls" depends on USB_ARCH_HAS_HCD depends on RC_CORE select USB help - Say Y here if you want to use an ATI or X10 "Lola" USB remote control. + Say Y here if you want to use an X10 based USB remote control. These are RF remotes with USB receivers. - The ATI remote comes with many of ATI's All-In-Wonder video cards. - The X10 "Lola" remote is available at: - + + Such devices include the ATI remote that comes with many of ATI's + All-In-Wonder video cards, the X10 "Lola" remote, NVIDIA RF remote, + Medion RF remote, and SnapStream FireFly remote. + This driver provides mouse pointer, left and right mouse buttons, and maps all the other remote buttons to keypress events. -- cgit v0.10.2 From 45dbf0db5ac974fb699fec39330d01642dff98dc Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Sep 2011 09:26:22 -0300 Subject: [media] tm6000: Fix some CodingStyle issues Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/tm6000/tm6000-core.c b/drivers/staging/tm6000/tm6000-core.c index 6d0803c..9783616 100644 --- a/drivers/staging/tm6000/tm6000-core.c +++ b/drivers/staging/tm6000/tm6000-core.c @@ -52,18 +52,18 @@ int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req, } if (tm6000_debug & V4L2_DEBUG_I2C) { - printk("(dev %p, pipe %08x): ", dev->udev, pipe); + printk(KERN_DEBUG "(dev %p, pipe %08x): ", dev->udev, pipe); - printk("%s: %02x %02x %02x %02x %02x %02x %02x %02x ", + printk(KERN_CONT "%s: %02x %02x %02x %02x %02x %02x %02x %02x ", (req_type & USB_DIR_IN) ? " IN" : "OUT", req_type, req, value&0xff, value>>8, index&0xff, index>>8, len&0xff, len>>8); if (!(req_type & USB_DIR_IN)) { - printk(">>> "); + printk(KERN_CONT ">>> "); for (i = 0; i < len; i++) - printk(" %02x", buf[i]); - printk("\n"); + printk(KERN_CONT " %02x", buf[i]); + printk(KERN_CONT "\n"); } } @@ -76,14 +76,14 @@ int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req, if (tm6000_debug & V4L2_DEBUG_I2C) { if (ret < 0) { if (req_type & USB_DIR_IN) - printk("<<< (len=%d)\n", len); + printk(KERN_DEBUG "<<< (len=%d)\n", len); - printk("%s: Error #%d\n", __FUNCTION__, ret); + printk(KERN_CONT "%s: Error #%d\n", __func__, ret); } else if (req_type & USB_DIR_IN) { - printk("<<< "); + printk(KERN_CONT "<<< "); for (i = 0; i < len; i++) - printk(" %02x", buf[i]); - printk("\n"); + printk(KERN_CONT " %02x", buf[i]); + printk(KERN_CONT "\n"); } } diff --git a/drivers/staging/tm6000/tm6000-dvb.c b/drivers/staging/tm6000/tm6000-dvb.c index 8f2a50b..5e6c129 100644 --- a/drivers/staging/tm6000/tm6000-dvb.c +++ b/drivers/staging/tm6000/tm6000-dvb.c @@ -330,7 +330,7 @@ static int register_dvb(struct tm6000_core *dev) dvb->demux.write_to_decoder = NULL; ret = dvb_dmx_init(&dvb->demux); if (ret < 0) { - printk("tm6000: dvb_dmx_init failed (errno = %d)\n", ret); + printk(KERN_ERR "tm6000: dvb_dmx_init failed (errno = %d)\n", ret); goto frontend_err; } @@ -340,7 +340,7 @@ static int register_dvb(struct tm6000_core *dev) ret = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); if (ret < 0) { - printk("tm6000: dvb_dmxdev_init failed (errno = %d)\n", ret); + printk(KERN_ERR "tm6000: dvb_dmxdev_init failed (errno = %d)\n", ret); goto dvb_dmx_err; } diff --git a/drivers/staging/tm6000/tm6000-i2c.c b/drivers/staging/tm6000/tm6000-i2c.c index 76a8e3a..0290bbf 100644 --- a/drivers/staging/tm6000/tm6000-i2c.c +++ b/drivers/staging/tm6000/tm6000-i2c.c @@ -189,7 +189,7 @@ static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap, /* 1 or 2 byte write followed by a read */ if (i2c_debug >= 2) for (byte = 0; byte < msgs[i].len; byte++) - printk(" %02x", msgs[i].buf[byte]); + printk(KERN_CONT " %02x", msgs[i].buf[byte]); i2c_dprintk(2, "; joined to read %s len=%d:", i == num - 2 ? "stop" : "nonstop", msgs[i + 1].len); @@ -211,17 +211,17 @@ static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap, } if (i2c_debug >= 2) for (byte = 0; byte < msgs[i].len; byte++) - printk(" %02x", msgs[i].buf[byte]); + printk(KERN_CONT " %02x", msgs[i].buf[byte]); } else { /* write bytes */ if (i2c_debug >= 2) for (byte = 0; byte < msgs[i].len; byte++) - printk(" %02x", msgs[i].buf[byte]); + printk(KERN_CONT " %02x", msgs[i].buf[byte]); rc = tm6000_i2c_send_regs(dev, addr, msgs[i].buf[0], msgs[i].buf + 1, msgs[i].len - 1); } if (i2c_debug >= 2) - printk("\n"); + printk(KERN_CONT "\n"); if (rc < 0) goto err; } @@ -259,7 +259,7 @@ static int tm6000_i2c_eeprom(struct tm6000_core *dev) p++; if (0 == (i % 16)) printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i); - printk(" %02x", dev->eedata[i]); + printk(KERN_CONT " %02x", dev->eedata[i]); if ((dev->eedata[i] >= ' ') && (dev->eedata[i] <= 'z')) bytes[i%16] = dev->eedata[i]; else @@ -269,14 +269,14 @@ static int tm6000_i2c_eeprom(struct tm6000_core *dev) if (0 == (i % 16)) { bytes[16] = '\0'; - printk(" %s\n", bytes); + printk(KERN_CONT " %s\n", bytes); } } if (0 != (i%16)) { bytes[i%16] = '\0'; for (i %= 16; i < 16; i++) - printk(" "); - printk(" %s\n", bytes); + printk(KERN_CONT " "); + printk(KERN_CONT " %s\n", bytes); } return 0; diff --git a/drivers/staging/tm6000/tm6000-regs.h b/drivers/staging/tm6000/tm6000-regs.h index 6e4ef95..7f491b6 100644 --- a/drivers/staging/tm6000/tm6000-regs.h +++ b/drivers/staging/tm6000/tm6000-regs.h @@ -90,7 +90,7 @@ */ enum { - TM6000_URB_MSG_VIDEO=1, + TM6000_URB_MSG_VIDEO = 1, TM6000_URB_MSG_AUDIO, TM6000_URB_MSG_VBI, TM6000_URB_MSG_PTS, diff --git a/drivers/staging/tm6000/tm6000-usb-isoc.h b/drivers/staging/tm6000/tm6000-usb-isoc.h index 084c2a8..99d15a5 100644 --- a/drivers/staging/tm6000/tm6000-usb-isoc.h +++ b/drivers/staging/tm6000/tm6000-usb-isoc.h @@ -46,5 +46,5 @@ struct usb_isoc_ctl { int tmp_buf_len; /* Stores already requested buffers */ - struct tm6000_buffer *buf; + struct tm6000_buffer *buf; }; diff --git a/drivers/staging/tm6000/tm6000.h b/drivers/staging/tm6000/tm6000.h index 5bdce84..2777e51 100644 --- a/drivers/staging/tm6000/tm6000.h +++ b/drivers/staging/tm6000/tm6000.h @@ -384,7 +384,7 @@ extern int tm6000_debug; #define dprintk(dev, level, fmt, arg...) do {\ if (tm6000_debug & level) \ printk(KERN_INFO "(%lu) %s %s :"fmt, jiffies, \ - dev->name, __FUNCTION__ , ##arg); } while (0) + dev->name, __func__ , ##arg); } while (0) #define V4L2_DEBUG_REG 0x0004 #define V4L2_DEBUG_I2C 0x0008 @@ -395,4 +395,4 @@ extern int tm6000_debug; #define tm6000_err(fmt, arg...) do {\ printk(KERN_ERR "tm6000 %s :"fmt, \ - __FUNCTION__ , ##arg); } while (0) + __func__ , ##arg); } while (0) -- cgit v0.10.2 From be304970850806abea880da95fbfb743a4d9f87d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Sep 2011 09:30:01 -0300 Subject: [media] move tm6000 to drivers/media/video The serious bugs got fixed already. Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/video4linux/CARDLIST.tm6000 b/Documentation/video4linux/CARDLIST.tm6000 new file mode 100644 index 0000000..b5edce4 --- /dev/null +++ b/Documentation/video4linux/CARDLIST.tm6000 @@ -0,0 +1,16 @@ + 1 -> Generic tm5600 board (tm5600) [6000:0001] + 2 -> Generic tm6000 board (tm6000) [6000:0001] + 3 -> Generic tm6010 board (tm6010) [6000:0002] + 4 -> 10Moons UT821 (tm5600) [6000:0001] + 5 -> 10Moons UT330 (tm5600) + 6 -> ADSTech Dual TV (tm6000) [06e1:f332] + 7 -> FreeCom and similar (tm6000) [14aa:0620] + 8 -> ADSTech Mini Dual TV (tm6000) [06e1:b339] + 9 -> Hauppauge WinTV HVR-900H/USB2 Stick (tm6010) [2040:6600,2040:6601,2040:6610,2040:6611] + 10 -> Beholder Wander (tm6010) [6000:dec0] + 11 -> Beholder Voyager (tm6010) [6000:dec1] + 12 -> TerraTec Cinergy Hybrid XE/Cinergy Hybrid Stick (tm6010) [0ccd:0086,0ccd:00a5] + 13 -> TwinHan TU501 (tm6010) [13d3:3240,13d3:3241,13d3:3243,13d3:3264] + 14 -> Beholder Wander Lite (tm6010) [6000:dec2] + 15 -> Beholder Voyager Lite (tm6010) [6000:dec3] + diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 4a10086..aed5b3d 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -1019,6 +1019,8 @@ source "drivers/media/video/tlg2300/Kconfig" source "drivers/media/video/cx231xx/Kconfig" +source "drivers/media/video/tm6000/Kconfig" + source "drivers/media/video/usbvision/Kconfig" source "drivers/media/video/et61x251/Kconfig" diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 0f0c6af..11fff97 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -107,6 +107,7 @@ obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/ obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ obj-$(CONFIG_VIDEO_CPIA2) += cpia2/ +obj-$(CONFIG_VIDEO_TM6000) += tm6000/ obj-$(CONFIG_VIDEO_MXB) += mxb.o obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o diff --git a/drivers/media/video/tm6000/Kconfig b/drivers/media/video/tm6000/Kconfig new file mode 100644 index 0000000..114eec8 --- /dev/null +++ b/drivers/media/video/tm6000/Kconfig @@ -0,0 +1,33 @@ +config VIDEO_TM6000 + tristate "TV Master TM5600/6000/6010 driver" + depends on VIDEO_DEV && I2C && INPUT && RC_CORE && USB && EXPERIMENTAL + select VIDEO_TUNER + select MEDIA_TUNER_XC2028 + select MEDIA_TUNER_XC5000 + select VIDEOBUF_VMALLOC + help + Support for TM5600/TM6000/TM6010 USB Device + + Since these cards have no MPEG decoder onboard, they transmit + only compressed MPEG data over the usb bus, so you need + an external software decoder to watch TV on your computer. + + Say Y if you own such a device and want to use it. + +config VIDEO_TM6000_ALSA + tristate "TV Master TM5600/6000/6010 audio support" + depends on VIDEO_TM6000 && SND && EXPERIMENTAL + select SND_PCM + ---help--- + This is a video4linux driver for direct (DMA) audio for + TM5600/TM6000/TM6010 USB Devices. + + To compile this driver as a module, choose M here: the + module will be called tm6000-alsa. + +config VIDEO_TM6000_DVB + tristate "DVB Support for tm6000 based TV cards" + depends on VIDEO_TM6000 && DVB_CORE && USB && EXPERIMENTAL + select DVB_ZL10353 + ---help--- + This adds support for DVB cards based on the tm5600/tm6000 chip. diff --git a/drivers/media/video/tm6000/Makefile b/drivers/media/video/tm6000/Makefile new file mode 100644 index 0000000..395515b --- /dev/null +++ b/drivers/media/video/tm6000/Makefile @@ -0,0 +1,15 @@ +tm6000-y := tm6000-cards.o \ + tm6000-core.o \ + tm6000-i2c.o \ + tm6000-video.o \ + tm6000-stds.o \ + tm6000-input.o + +obj-$(CONFIG_VIDEO_TM6000) += tm6000.o +obj-$(CONFIG_VIDEO_TM6000_ALSA) += tm6000-alsa.o +obj-$(CONFIG_VIDEO_TM6000_DVB) += tm6000-dvb.o + +ccflags-y := -Idrivers/media/video +ccflags-y += -Idrivers/media/common/tuners +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-y += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/tm6000/tm6000-alsa.c b/drivers/media/video/tm6000/tm6000-alsa.c new file mode 100644 index 0000000..7d675c7 --- /dev/null +++ b/drivers/media/video/tm6000/tm6000-alsa.c @@ -0,0 +1,513 @@ +/* + * + * Support for audio capture for tm5600/6000/6010 + * (c) 2007-2008 Mauro Carvalho Chehab + * + * Based on cx88-alsa.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +#include "tm6000.h" +#include "tm6000-regs.h" + +#undef dprintk + +#define dprintk(level, fmt, arg...) do { \ + if (debug >= level) \ + printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg); \ + } while (0) + +/**************************************************************************** + Module global static vars + ****************************************************************************/ + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ + +static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1}; + +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "Enable tm6000x soundcard. default enabled."); + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for tm6000x capture interface(s)."); + + +/**************************************************************************** + Module macros + ****************************************************************************/ + +MODULE_DESCRIPTION("ALSA driver module for tm5600/tm6000/tm6010 based TV cards"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("{{Trident,tm5600}," + "{{Trident,tm6000}," + "{{Trident,tm6010}"); +static unsigned int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable debug messages"); + +/**************************************************************************** + Module specific funtions + ****************************************************************************/ + +/* + * BOARD Specific: Sets audio DMA + */ + +static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip) +{ + struct tm6000_core *core = chip->core; + + dprintk(1, "Starting audio DMA\n"); + + /* Enables audio */ + tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_IF, 0x40, 0x40); + + tm6000_set_audio_bitrate(core, 48000); + + return 0; +} + +/* + * BOARD Specific: Resets audio DMA + */ +static int _tm6000_stop_audio_dma(struct snd_tm6000_card *chip) +{ + struct tm6000_core *core = chip->core; + + dprintk(1, "Stopping audio DMA\n"); + + /* Disables audio */ + tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_IF, 0x00, 0x40); + + return 0; +} + +static void dsp_buffer_free(struct snd_pcm_substream *substream) +{ + struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); + + dprintk(2, "Freeing buffer\n"); + + vfree(substream->runtime->dma_area); + substream->runtime->dma_area = NULL; + substream->runtime->dma_bytes = 0; +} + +static int dsp_buffer_alloc(struct snd_pcm_substream *substream, int size) +{ + struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); + + dprintk(2, "Allocating buffer\n"); + + if (substream->runtime->dma_area) { + if (substream->runtime->dma_bytes > size) + return 0; + + dsp_buffer_free(substream); + } + + substream->runtime->dma_area = vmalloc(size); + if (!substream->runtime->dma_area) + return -ENOMEM; + + substream->runtime->dma_bytes = size; + + return 0; +} + + +/**************************************************************************** + ALSA PCM Interface + ****************************************************************************/ + +/* + * Digital hardware definition + */ +#define DEFAULT_FIFO_SIZE 4096 + +static struct snd_pcm_hardware snd_tm6000_digital_hw = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .period_bytes_min = 64, + .period_bytes_max = 12544, + .periods_min = 1, + .periods_max = 98, + .buffer_bytes_max = 62720 * 8, +}; + +/* + * audio pcm capture open callback + */ +static int snd_tm6000_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + int err; + + err = snd_pcm_hw_constraint_pow2(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) + goto _error; + + chip->substream = substream; + + runtime->hw = snd_tm6000_digital_hw; + + return 0; +_error: + dprintk(1, "Error opening PCM!\n"); + return err; +} + +/* + * audio close callback + */ +static int snd_tm6000_close(struct snd_pcm_substream *substream) +{ + struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); + struct tm6000_core *core = chip->core; + + if (atomic_read(&core->stream_started) > 0) { + atomic_set(&core->stream_started, 0); + schedule_work(&core->wq_trigger); + } + + return 0; +} + +static int tm6000_fillbuf(struct tm6000_core *core, char *buf, int size) +{ + struct snd_tm6000_card *chip = core->adev; + struct snd_pcm_substream *substream = chip->substream; + struct snd_pcm_runtime *runtime; + int period_elapsed = 0; + unsigned int stride, buf_pos; + int length; + + if (atomic_read(&core->stream_started) == 0) + return 0; + + if (!size || !substream) { + dprintk(1, "substream was NULL\n"); + return -EINVAL; + } + + runtime = substream->runtime; + if (!runtime || !runtime->dma_area) { + dprintk(1, "runtime was NULL\n"); + return -EINVAL; + } + + buf_pos = chip->buf_pos; + stride = runtime->frame_bits >> 3; + + if (stride == 0) { + dprintk(1, "stride is zero\n"); + return -EINVAL; + } + + length = size / stride; + if (length == 0) { + dprintk(1, "%s: length was zero\n", __func__); + return -EINVAL; + } + + dprintk(1, "Copying %d bytes at %p[%d] - buf size=%d x %d\n", size, + runtime->dma_area, buf_pos, + (unsigned int)runtime->buffer_size, stride); + + if (buf_pos + length >= runtime->buffer_size) { + unsigned int cnt = runtime->buffer_size - buf_pos; + memcpy(runtime->dma_area + buf_pos * stride, buf, cnt * stride); + memcpy(runtime->dma_area, buf + cnt * stride, + length * stride - cnt * stride); + } else + memcpy(runtime->dma_area + buf_pos * stride, buf, + length * stride); + + snd_pcm_stream_lock(substream); + + chip->buf_pos += length; + if (chip->buf_pos >= runtime->buffer_size) + chip->buf_pos -= runtime->buffer_size; + + chip->period_pos += length; + if (chip->period_pos >= runtime->period_size) { + chip->period_pos -= runtime->period_size; + period_elapsed = 1; + } + + snd_pcm_stream_unlock(substream); + + if (period_elapsed) + snd_pcm_period_elapsed(substream); + + return 0; +} + +/* + * hw_params callback + */ +static int snd_tm6000_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + int size, rc; + + size = params_period_bytes(hw_params) * params_periods(hw_params); + + rc = dsp_buffer_alloc(substream, size); + if (rc < 0) + return rc; + + return 0; +} + +/* + * hw free callback + */ +static int snd_tm6000_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); + struct tm6000_core *core = chip->core; + + if (atomic_read(&core->stream_started) > 0) { + atomic_set(&core->stream_started, 0); + schedule_work(&core->wq_trigger); + } + + dsp_buffer_free(substream); + return 0; +} + +/* + * prepare callback + */ +static int snd_tm6000_prepare(struct snd_pcm_substream *substream) +{ + struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); + + chip->buf_pos = 0; + chip->period_pos = 0; + + return 0; +} + + +/* + * trigger callback + */ +static void audio_trigger(struct work_struct *work) +{ + struct tm6000_core *core = container_of(work, struct tm6000_core, + wq_trigger); + struct snd_tm6000_card *chip = core->adev; + + if (atomic_read(&core->stream_started)) { + dprintk(1, "starting capture"); + _tm6000_start_audio_dma(chip); + } else { + dprintk(1, "stopping capture"); + _tm6000_stop_audio_dma(chip); + } +} + +static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); + struct tm6000_core *core = chip->core; + int err = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + atomic_set(&core->stream_started, 1); + break; + case SNDRV_PCM_TRIGGER_STOP: + atomic_set(&core->stream_started, 0); + break; + default: + err = -EINVAL; + break; + } + schedule_work(&core->wq_trigger); + + return err; +} +/* + * pointer callback + */ +static snd_pcm_uframes_t snd_tm6000_pointer(struct snd_pcm_substream *substream) +{ + struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); + + return chip->buf_pos; +} + +/* + * operators + */ +static struct snd_pcm_ops snd_tm6000_pcm_ops = { + .open = snd_tm6000_pcm_open, + .close = snd_tm6000_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_tm6000_hw_params, + .hw_free = snd_tm6000_hw_free, + .prepare = snd_tm6000_prepare, + .trigger = snd_tm6000_card_trigger, + .pointer = snd_tm6000_pointer, +}; + +/* + * create a PCM device + */ + +/* FIXME: Control interface - How to control volume/mute? */ + +/**************************************************************************** + Basic Flow for Sound Devices + ****************************************************************************/ + +/* + * Alsa Constructor - Component probe + */ +static int tm6000_audio_init(struct tm6000_core *dev) +{ + struct snd_card *card; + struct snd_tm6000_card *chip; + int rc; + static int devnr; + char component[14]; + struct snd_pcm *pcm; + + if (!dev) + return 0; + + if (devnr >= SNDRV_CARDS) + return -ENODEV; + + if (!enable[devnr]) + return -ENOENT; + + rc = snd_card_create(index[devnr], "tm6000", THIS_MODULE, 0, &card); + if (rc < 0) { + snd_printk(KERN_ERR "cannot create card instance %d\n", devnr); + return rc; + } + strcpy(card->driver, "tm6000-alsa"); + strcpy(card->shortname, "TM5600/60x0"); + sprintf(card->longname, "TM5600/60x0 Audio at bus %d device %d", + dev->udev->bus->busnum, dev->udev->devnum); + + sprintf(component, "USB%04x:%04x", + le16_to_cpu(dev->udev->descriptor.idVendor), + le16_to_cpu(dev->udev->descriptor.idProduct)); + snd_component_add(card, component); + snd_card_set_dev(card, &dev->udev->dev); + + chip = kzalloc(sizeof(struct snd_tm6000_card), GFP_KERNEL); + if (!chip) { + rc = -ENOMEM; + goto error; + } + + chip->core = dev; + chip->card = card; + dev->adev = chip; + spin_lock_init(&chip->reg_lock); + + rc = snd_pcm_new(card, "TM6000 Audio", 0, 0, 1, &pcm); + if (rc < 0) + goto error_chip; + + pcm->info_flags = 0; + pcm->private_data = chip; + strcpy(pcm->name, "Trident TM5600/60x0"); + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops); + + INIT_WORK(&dev->wq_trigger, audio_trigger); + rc = snd_card_register(card); + if (rc < 0) + goto error_chip; + + dprintk(1, "Registered audio driver for %s\n", card->longname); + + return 0; + +error_chip: + kfree(chip); + dev->adev = NULL; +error: + snd_card_free(card); + return rc; +} + +static int tm6000_audio_fini(struct tm6000_core *dev) +{ + struct snd_tm6000_card *chip = dev->adev; + + if (!dev) + return 0; + + if (!chip) + return 0; + + if (!chip->card) + return 0; + + snd_card_free(chip->card); + chip->card = NULL; + kfree(chip); + dev->adev = NULL; + + return 0; +} + +static struct tm6000_ops audio_ops = { + .type = TM6000_AUDIO, + .name = "TM6000 Audio Extension", + .init = tm6000_audio_init, + .fini = tm6000_audio_fini, + .fillbuf = tm6000_fillbuf, +}; + +static int __init tm6000_alsa_register(void) +{ + return tm6000_register_extension(&audio_ops); +} + +static void __exit tm6000_alsa_unregister(void) +{ + tm6000_unregister_extension(&audio_ops); +} + +module_init(tm6000_alsa_register); +module_exit(tm6000_alsa_unregister); diff --git a/drivers/media/video/tm6000/tm6000-cards.c b/drivers/media/video/tm6000/tm6000-cards.c new file mode 100644 index 0000000..ec2578a --- /dev/null +++ b/drivers/media/video/tm6000/tm6000-cards.c @@ -0,0 +1,1402 @@ +/* + * tm6000-cards.c - driver for TM5600/TM6000/TM6010 USB video capture devices + * + * Copyright (C) 2006-2007 Mauro Carvalho Chehab + * + * 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 version 2 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tm6000.h" +#include "tm6000-regs.h" +#include "tuner-xc2028.h" +#include "xc5000.h" + +#define TM6000_BOARD_UNKNOWN 0 +#define TM5600_BOARD_GENERIC 1 +#define TM6000_BOARD_GENERIC 2 +#define TM6010_BOARD_GENERIC 3 +#define TM5600_BOARD_10MOONS_UT821 4 +#define TM5600_BOARD_10MOONS_UT330 5 +#define TM6000_BOARD_ADSTECH_DUAL_TV 6 +#define TM6000_BOARD_FREECOM_AND_SIMILAR 7 +#define TM6000_BOARD_ADSTECH_MINI_DUAL_TV 8 +#define TM6010_BOARD_HAUPPAUGE_900H 9 +#define TM6010_BOARD_BEHOLD_WANDER 10 +#define TM6010_BOARD_BEHOLD_VOYAGER 11 +#define TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE 12 +#define TM6010_BOARD_TWINHAN_TU501 13 +#define TM6010_BOARD_BEHOLD_WANDER_LITE 14 +#define TM6010_BOARD_BEHOLD_VOYAGER_LITE 15 +#define TM5600_BOARD_TERRATEC_GRABSTER 16 + +#define is_generic(model) ((model == TM6000_BOARD_UNKNOWN) || \ + (model == TM5600_BOARD_GENERIC) || \ + (model == TM6000_BOARD_GENERIC) || \ + (model == TM6010_BOARD_GENERIC)) + +#define TM6000_MAXBOARDS 16 +static unsigned int card[] = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET }; + +module_param_array(card, int, NULL, 0444); + +static unsigned long tm6000_devused; + + +struct tm6000_board { + char *name; + char eename[16]; /* EEPROM name */ + unsigned eename_size; /* size of EEPROM name */ + unsigned eename_pos; /* Position where it appears at ROM */ + + struct tm6000_capabilities caps; + + enum tm6000_devtype type; /* variant of the chipset */ + int tuner_type; /* type of the tuner */ + int tuner_addr; /* tuner address */ + int demod_addr; /* demodulator address */ + + struct tm6000_gpio gpio; + + struct tm6000_input vinput[3]; + struct tm6000_input rinput; + + char *ir_codes; +}; + +static struct tm6000_board tm6000_boards[] = { + [TM6000_BOARD_UNKNOWN] = { + .name = "Unknown tm6000 video grabber", + .caps = { + .has_tuner = 1, + .has_eeprom = 1, + }, + .gpio = { + .tuner_reset = TM6000_GPIO_1, + }, + .vinput = { { + .type = TM6000_INPUT_TV, + .vmux = TM6000_VMUX_VIDEO_B, + .amux = TM6000_AMUX_ADC1, + }, { + .type = TM6000_INPUT_COMPOSITE1, + .vmux = TM6000_VMUX_VIDEO_A, + .amux = TM6000_AMUX_ADC2, + }, { + .type = TM6000_INPUT_SVIDEO, + .vmux = TM6000_VMUX_VIDEO_AB, + .amux = TM6000_AMUX_ADC2, + }, + }, + }, + [TM5600_BOARD_GENERIC] = { + .name = "Generic tm5600 board", + .type = TM5600, + .tuner_type = TUNER_XC2028, + .tuner_addr = 0xc2 >> 1, + .caps = { + .has_tuner = 1, + .has_eeprom = 1, + }, + .gpio = { + .tuner_reset = TM6000_GPIO_1, + }, + .vinput = { { + .type = TM6000_INPUT_TV, + .vmux = TM6000_VMUX_VIDEO_B, + .amux = TM6000_AMUX_ADC1, + }, { + .type = TM6000_INPUT_COMPOSITE1, + .vmux = TM6000_VMUX_VIDEO_A, + .amux = TM6000_AMUX_ADC2, + }, { + .type = TM6000_INPUT_SVIDEO, + .vmux = TM6000_VMUX_VIDEO_AB, + .amux = TM6000_AMUX_ADC2, + }, + }, + }, + [TM6000_BOARD_GENERIC] = { + .name = "Generic tm6000 board", + .tuner_type = TUNER_XC2028, + .tuner_addr = 0xc2 >> 1, + .caps = { + .has_tuner = 1, + .has_eeprom = 1, + }, + .gpio = { + .tuner_reset = TM6000_GPIO_1, + }, + .vinput = { { + .type = TM6000_INPUT_TV, + .vmux = TM6000_VMUX_VIDEO_B, + .amux = TM6000_AMUX_ADC1, + }, { + .type = TM6000_INPUT_COMPOSITE1, + .vmux = TM6000_VMUX_VIDEO_A, + .amux = TM6000_AMUX_ADC2, + }, { + .type = TM6000_INPUT_SVIDEO, + .vmux = TM6000_VMUX_VIDEO_AB, + .amux = TM6000_AMUX_ADC2, + }, + }, + }, + [TM6010_BOARD_GENERIC] = { + .name = "Generic tm6010 board", + .type = TM6010, + .tuner_type = TUNER_XC2028, + .tuner_addr = 0xc2 >> 1, + .demod_addr = 0x1e >> 1, + .caps = { + .has_tuner = 1, + .has_dvb = 1, + .has_zl10353 = 1, + .has_eeprom = 1, + .has_remote = 1, + }, + .gpio = { + .tuner_reset = TM6010_GPIO_2, + .tuner_on = TM6010_GPIO_3, + .demod_reset = TM6010_GPIO_1, + .demod_on = TM6010_GPIO_4, + .power_led = TM6010_GPIO_7, + .dvb_led = TM6010_GPIO_5, + .ir = TM6010_GPIO_0, + }, + .vinput = { { + .type = TM6000_INPUT_TV, + .vmux = TM6000_VMUX_VIDEO_B, + .amux = TM6000_AMUX_SIF1, + }, { + .type = TM6000_INPUT_COMPOSITE1, + .vmux = TM6000_VMUX_VIDEO_A, + .amux = TM6000_AMUX_ADC2, + }, { + .type = TM6000_INPUT_SVIDEO, + .vmux = TM6000_VMUX_VIDEO_AB, + .amux = TM6000_AMUX_ADC2, + }, + }, + }, + [TM5600_BOARD_10MOONS_UT821] = { + .name = "10Moons UT 821", + .tuner_type = TUNER_XC2028, + .eename = { '1', '0', 'M', 'O', 'O', 'N', 'S', '5', '6', '0', '0', 0xff, 0x45, 0x5b}, + .eename_size = 14, + .eename_pos = 0x14, + .type = TM5600, + .tuner_addr = 0xc2 >> 1, + .caps = { + .has_tuner = 1, + .has_eeprom = 1, + }, + .gpio = { + .tuner_reset = TM6000_GPIO_1, + }, + .vinput = { { + .type = TM6000_INPUT_TV, + .vmux = TM6000_VMUX_VIDEO_B, + .amux = TM6000_AMUX_ADC1, + }, { + .type = TM6000_INPUT_COMPOSITE1, + .vmux = TM6000_VMUX_VIDEO_A, + .amux = TM6000_AMUX_ADC2, + }, { + .type = TM6000_INPUT_SVIDEO, + .vmux = TM6000_VMUX_VIDEO_AB, + .amux = TM6000_AMUX_ADC2, + }, + }, + }, + [TM5600_BOARD_10MOONS_UT330] = { + .name = "10Moons UT 330", + .tuner_type = TUNER_PHILIPS_FQ1216AME_MK4, + .tuner_addr = 0xc8 >> 1, + .caps = { + .has_tuner = 1, + .has_dvb = 0, + .has_zl10353 = 0, + .has_eeprom = 1, + }, + .vinput = { { + .type = TM6000_INPUT_TV, + .vmux = TM6000_VMUX_VIDEO_B, + .amux = TM6000_AMUX_ADC1, + }, { + .type = TM6000_INPUT_COMPOSITE1, + .vmux = TM6000_VMUX_VIDEO_A, + .amux = TM6000_AMUX_ADC2, + }, { + .type = TM6000_INPUT_SVIDEO, + .vmux = TM6000_VMUX_VIDEO_AB, + .amux = TM6000_AMUX_ADC2, + }, + }, + }, + [TM6000_BOARD_ADSTECH_DUAL_TV] = { + .name = "ADSTECH Dual TV USB", + .tuner_type = TUNER_XC2028, + .tuner_addr = 0xc8 >> 1, + .caps = { + .has_tuner = 1, + .has_tda9874 = 1, + .has_dvb = 1, + .has_zl10353 = 1, + .has_eeprom = 1, + }, + .vinput = { { + .type = TM6000_INPUT_TV, + .vmux = TM6000_VMUX_VIDEO_B, + .amux = TM6000_AMUX_ADC1, + }, { + .type = TM6000_INPUT_COMPOSITE1, + .vmux = TM6000_VMUX_VIDEO_A, + .amux = TM6000_AMUX_ADC2, + }, { + .type = TM6000_INPUT_SVIDEO, + .vmux = TM6000_VMUX_VIDEO_AB, + .amux = TM6000_AMUX_ADC2, + }, + }, + }, + [TM6000_BOARD_FREECOM_AND_SIMILAR] = { + .name = "Freecom Hybrid Stick / Moka DVB-T Receiver Dual", + .tuner_type = TUNER_XC2028, /* has a XC3028 */ + .tuner_addr = 0xc2 >> 1, + .demod_addr = 0x1e >> 1, + .caps = { + .has_tuner = 1, + .has_dvb = 1, + .has_zl10353 = 1, + .has_eeprom = 0, + .has_remote = 1, + }, + .gpio = { + .tuner_reset = TM6000_GPIO_4, + }, + .vinput = { { + .type = TM6000_INPUT_TV, + .vmux = TM6000_VMUX_VIDEO_B, + .amux = TM6000_AMUX_ADC1, + }, { + .type = TM6000_INPUT_COMPOSITE1, + .vmux = TM6000_VMUX_VIDEO_A, + .amux = TM6000_AMUX_ADC2, + }, { + .type = TM6000_INPUT_SVIDEO, + .vmux = TM6000_VMUX_VIDEO_AB, + .amux = TM6000_AMUX_ADC2, + }, + }, + }, + [TM6000_BOARD_ADSTECH_MINI_DUAL_TV] = { + .name = "ADSTECH Mini Dual TV USB", + .tuner_type = TUNER_XC2028, /* has a XC3028 */ + .tuner_addr = 0xc8 >> 1, + .demod_addr = 0x1e >> 1, + .caps = { + .has_tuner = 1, + .has_dvb = 1, + .has_zl10353 = 1, + .has_eeprom = 0, + }, + .gpio = { + .tuner_reset = TM6000_GPIO_4, + }, + .vinput = { { + .type = TM6000_INPUT_TV, + .vmux = TM6000_VMUX_VIDEO_B, + .amux = TM6000_AMUX_ADC1, + }, { + .type = TM6000_INPUT_COMPOSITE1, + .vmux = TM6000_VMUX_VIDEO_A, + .amux = TM6000_AMUX_ADC2, + }, { + .type = TM6000_INPUT_SVIDEO, + .vmux = TM6000_VMUX_VIDEO_AB, + .amux = TM6000_AMUX_ADC2, + }, + }, + }, + [TM6010_BOARD_HAUPPAUGE_900H] = { + .name = "Hauppauge WinTV HVR-900H / WinTV USB2-Stick", + .eename = { 'H', 0, 'V', 0, 'R', 0, '9', 0, '0', 0, '0', 0, 'H', 0 }, + .eename_size = 14, + .eename_pos = 0x42, + .tuner_type = TUNER_XC2028, /* has a XC3028 */ + .tuner_addr = 0xc2 >> 1, + .demod_addr = 0x1e >> 1, + .type = TM6010, + .caps = { + .has_tuner = 1, + .has_dvb = 1, + .has_zl10353 = 1, + .has_eeprom = 1, + .has_remote = 1, + }, + .gpio = { + .tuner_reset = TM6010_GPIO_2, + .tuner_on = TM6010_GPIO_3, + .demod_reset = TM6010_GPIO_1, + .demod_on = TM6010_GPIO_4, + .power_led = TM6010_GPIO_7, + .dvb_led = TM6010_GPIO_5, + .ir = TM6010_GPIO_0, + }, + .vinput = { { + .type = TM6000_INPUT_TV, + .vmux = TM6000_VMUX_VIDEO_B, + .amux = TM6000_AMUX_SIF1, + }, { + .type = TM6000_INPUT_COMPOSITE1, + .vmux = TM6000_VMUX_VIDEO_A, + .amux = TM6000_AMUX_ADC2, + }, { + .type = TM6000_INPUT_SVIDEO, + .vmux = TM6000_VMUX_VIDEO_AB, + .amux = TM6000_AMUX_ADC2, + }, + }, + }, + [TM6010_BOARD_BEHOLD_WANDER] = { + .name = "Beholder Wander DVB-T/TV/FM USB2.0", + .tuner_type = TUNER_XC5000, + .tuner_addr = 0xc2 >> 1, + .demod_addr = 0x1e >> 1, + .type = TM6010, + .caps = { + .has_tuner = 1, + .has_dvb = 1, + .has_zl10353 = 1, + .has_eeprom = 1, + .has_remote = 1, + .has_radio = 1, + }, + .gpio = { + .tuner_reset = TM6010_GPIO_0, + .demod_reset = TM6010_GPIO_1, + .power_led = TM6010_GPIO_6, + }, + .vinput = { { + .type = TM6000_INPUT_TV, + .vmux = TM6000_VMUX_VIDEO_B, + .amux = TM6000_AMUX_SIF1, + }, { + .type = TM6000_INPUT_COMPOSITE1, + .vmux = TM6000_VMUX_VIDEO_A, + .amux = TM6000_AMUX_ADC2, + }, { + .type = TM6000_INPUT_SVIDEO, + .vmux = TM6000_VMUX_VIDEO_AB, + .amux = TM6000_AMUX_ADC2, + }, + }, + .rinput = { + .type = TM6000_INPUT_RADIO, + .amux = TM6000_AMUX_ADC1, + }, + }, + [TM6010_BOARD_BEHOLD_VOYAGER] = { + .name = "Beholder Voyager TV/FM USB2.0", + .tuner_type = TUNER_XC5000, + .tuner_addr = 0xc2 >> 1, + .type = TM6010, + .caps = { + .has_tuner = 1, + .has_dvb = 0, + .has_zl10353 = 0, + .has_eeprom = 1, + .has_remote = 1, + .has_radio = 1, + }, + .gpio = { + .tuner_reset = TM6010_GPIO_0, + .power_led = TM6010_GPIO_6, + }, + .vinput = { { + .type = TM6000_INPUT_TV, + .vmux = TM6000_VMUX_VIDEO_B, + .amux = TM6000_AMUX_SIF1, + }, { + .type = TM6000_INPUT_COMPOSITE1, + .vmux = TM6000_VMUX_VIDEO_A, + .amux = TM6000_AMUX_ADC2, + }, { + .type = TM6000_INPUT_SVIDEO, + .vmux = TM6000_VMUX_VIDEO_AB, + .amux = TM6000_AMUX_ADC2, + }, + }, + .rinput = { + .type = TM6000_INPUT_RADIO, + .amux = TM6000_AMUX_ADC1, + }, + }, + [TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = { + .name = "Terratec Cinergy Hybrid XE / Cinergy Hybrid-Stick", + .tuner_type = TUNER_XC2028, /* has a XC3028 */ + .tuner_addr = 0xc2 >> 1, + .demod_addr = 0x1e >> 1, + .type = TM6010, + .caps = { + .has_tuner = 1, + .has_dvb = 1, + .has_zl10353 = 1, + .has_eeprom = 1, + .has_remote = 1, + .has_radio = 1, + }, + .gpio = { + .tuner_reset = TM6010_GPIO_2, + .tuner_on = TM6010_GPIO_3, + .demod_reset = TM6010_GPIO_1, + .demod_on = TM6010_GPIO_4, + .power_led = TM6010_GPIO_7, + .dvb_led = TM6010_GPIO_5, + .ir = TM6010_GPIO_0, + }, + .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS, + .vinput = { { + .type = TM6000_INPUT_TV, + .vmux = TM6000_VMUX_VIDEO_B, + .amux = TM6000_AMUX_SIF1, + }, { + .type = TM6000_INPUT_COMPOSITE1, + .vmux = TM6000_VMUX_VIDEO_A, + .amux = TM6000_AMUX_ADC2, + }, { + .type = TM6000_INPUT_SVIDEO, + .vmux = TM6000_VMUX_VIDEO_AB, + .amux = TM6000_AMUX_ADC2, + }, + }, + .rinput = { + .type = TM6000_INPUT_RADIO, + .amux = TM6000_AMUX_SIF1, + }, + }, + [TM5600_BOARD_TERRATEC_GRABSTER] = { + .name = "Terratec Grabster AV 150/250 MX", + .type = TM5600, + .tuner_type = TUNER_ABSENT, + .vinput = { { + .type = TM6000_INPUT_TV, + .vmux = TM6000_VMUX_VIDEO_B, + .amux = TM6000_AMUX_ADC1, + }, { + .type = TM6000_INPUT_COMPOSITE1, + .vmux = TM6000_VMUX_VIDEO_A, + .amux = TM6000_AMUX_ADC2, + }, { + .type = TM6000_INPUT_SVIDEO, + .vmux = TM6000_VMUX_VIDEO_AB, + .amux = TM6000_AMUX_ADC2, + }, + }, + }, + [TM6010_BOARD_TWINHAN_TU501] = { + .name = "Twinhan TU501(704D1)", + .tuner_type = TUNER_XC2028, /* has a XC3028 */ + .tuner_addr = 0xc2 >> 1, + .demod_addr = 0x1e >> 1, + .type = TM6010, + .caps = { + .has_tuner = 1, + .has_dvb = 1, + .has_zl10353 = 1, + .has_eeprom = 1, + .has_remote = 1, + }, + .gpio = { + .tuner_reset = TM6010_GPIO_2, + .tuner_on = TM6010_GPIO_3, + .demod_reset = TM6010_GPIO_1, + .demod_on = TM6010_GPIO_4, + .power_led = TM6010_GPIO_7, + .dvb_led = TM6010_GPIO_5, + .ir = TM6010_GPIO_0, + }, + .vinput = { { + .type = TM6000_INPUT_TV, + .vmux = TM6000_VMUX_VIDEO_B, + .amux = TM6000_AMUX_SIF1, + }, { + .type = TM6000_INPUT_COMPOSITE1, + .vmux = TM6000_VMUX_VIDEO_A, + .amux = TM6000_AMUX_ADC2, + }, { + .type = TM6000_INPUT_SVIDEO, + .vmux = TM6000_VMUX_VIDEO_AB, + .amux = TM6000_AMUX_ADC2, + }, + }, + }, + [TM6010_BOARD_BEHOLD_WANDER_LITE] = { + .name = "Beholder Wander Lite DVB-T/TV/FM USB2.0", + .tuner_type = TUNER_XC5000, + .tuner_addr = 0xc2 >> 1, + .demod_addr = 0x1e >> 1, + .type = TM6010, + .caps = { + .has_tuner = 1, + .has_dvb = 1, + .has_zl10353 = 1, + .has_eeprom = 1, + .has_remote = 0, + .has_radio = 1, + }, + .gpio = { + .tuner_reset = TM6010_GPIO_0, + .demod_reset = TM6010_GPIO_1, + .power_led = TM6010_GPIO_6, + }, + .vinput = { { + .type = TM6000_INPUT_TV, + .vmux = TM6000_VMUX_VIDEO_B, + .amux = TM6000_AMUX_SIF1, + }, + }, + .rinput = { + .type = TM6000_INPUT_RADIO, + .amux = TM6000_AMUX_ADC1, + }, + }, + [TM6010_BOARD_BEHOLD_VOYAGER_LITE] = { + .name = "Beholder Voyager Lite TV/FM USB2.0", + .tuner_type = TUNER_XC5000, + .tuner_addr = 0xc2 >> 1, + .type = TM6010, + .caps = { + .has_tuner = 1, + .has_dvb = 0, + .has_zl10353 = 0, + .has_eeprom = 1, + .has_remote = 0, + .has_radio = 1, + }, + .gpio = { + .tuner_reset = TM6010_GPIO_0, + .power_led = TM6010_GPIO_6, + }, + .vinput = { { + .type = TM6000_INPUT_TV, + .vmux = TM6000_VMUX_VIDEO_B, + .amux = TM6000_AMUX_SIF1, + }, + }, + .rinput = { + .type = TM6000_INPUT_RADIO, + .amux = TM6000_AMUX_ADC1, + }, + }, +}; + +/* table of devices that work with this driver */ +static struct usb_device_id tm6000_id_table[] = { + { USB_DEVICE(0x6000, 0x0001), .driver_info = TM5600_BOARD_GENERIC }, + { USB_DEVICE(0x6000, 0x0002), .driver_info = TM6010_BOARD_GENERIC }, + { USB_DEVICE(0x06e1, 0xf332), .driver_info = TM6000_BOARD_ADSTECH_DUAL_TV }, + { USB_DEVICE(0x14aa, 0x0620), .driver_info = TM6000_BOARD_FREECOM_AND_SIMILAR }, + { USB_DEVICE(0x06e1, 0xb339), .driver_info = TM6000_BOARD_ADSTECH_MINI_DUAL_TV }, + { USB_DEVICE(0x2040, 0x6600), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, + { USB_DEVICE(0x2040, 0x6601), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, + { USB_DEVICE(0x2040, 0x6610), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, + { USB_DEVICE(0x2040, 0x6611), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, + { USB_DEVICE(0x6000, 0xdec0), .driver_info = TM6010_BOARD_BEHOLD_WANDER }, + { USB_DEVICE(0x6000, 0xdec1), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER }, + { USB_DEVICE(0x0ccd, 0x0086), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE }, + { USB_DEVICE(0x0ccd, 0x00A5), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE }, + { USB_DEVICE(0x0ccd, 0x0079), .driver_info = TM5600_BOARD_TERRATEC_GRABSTER }, + { USB_DEVICE(0x13d3, 0x3240), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, + { USB_DEVICE(0x13d3, 0x3241), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, + { USB_DEVICE(0x13d3, 0x3243), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, + { USB_DEVICE(0x13d3, 0x3264), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, + { USB_DEVICE(0x6000, 0xdec2), .driver_info = TM6010_BOARD_BEHOLD_WANDER_LITE }, + { USB_DEVICE(0x6000, 0xdec3), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER_LITE }, + { } +}; + +/* Control power led for show some activity */ +void tm6000_flash_led(struct tm6000_core *dev, u8 state) +{ + /* Power LED unconfigured */ + if (!dev->gpio.power_led) + return; + + /* ON Power LED */ + if (state) { + switch (dev->model) { + case TM6010_BOARD_HAUPPAUGE_900H: + case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: + case TM6010_BOARD_TWINHAN_TU501: + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.power_led, 0x00); + break; + case TM6010_BOARD_BEHOLD_WANDER: + case TM6010_BOARD_BEHOLD_VOYAGER: + case TM6010_BOARD_BEHOLD_WANDER_LITE: + case TM6010_BOARD_BEHOLD_VOYAGER_LITE: + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.power_led, 0x01); + break; + } + } + /* OFF Power LED */ + else { + switch (dev->model) { + case TM6010_BOARD_HAUPPAUGE_900H: + case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: + case TM6010_BOARD_TWINHAN_TU501: + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.power_led, 0x01); + break; + case TM6010_BOARD_BEHOLD_WANDER: + case TM6010_BOARD_BEHOLD_VOYAGER: + case TM6010_BOARD_BEHOLD_WANDER_LITE: + case TM6010_BOARD_BEHOLD_VOYAGER_LITE: + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.power_led, 0x00); + break; + } + } +} + +/* Tuner callback to provide the proper gpio changes needed for xc5000 */ +int tm6000_xc5000_callback(void *ptr, int component, int command, int arg) +{ + int rc = 0; + struct tm6000_core *dev = ptr; + + if (dev->tuner_type != TUNER_XC5000) + return 0; + + switch (command) { + case XC5000_TUNER_RESET: + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.tuner_reset, 0x01); + msleep(15); + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.tuner_reset, 0x00); + msleep(15); + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.tuner_reset, 0x01); + break; + } + return rc; +} +EXPORT_SYMBOL_GPL(tm6000_xc5000_callback); + +/* Tuner callback to provide the proper gpio changes needed for xc2028 */ + +int tm6000_tuner_callback(void *ptr, int component, int command, int arg) +{ + int rc = 0; + struct tm6000_core *dev = ptr; + + if (dev->tuner_type != TUNER_XC2028) + return 0; + + switch (command) { + case XC2028_RESET_CLK: + tm6000_ir_wait(dev, 0); + + tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, + 0x02, arg); + msleep(10); + rc = tm6000_i2c_reset(dev, 10); + break; + case XC2028_TUNER_RESET: + /* Reset codes during load firmware */ + switch (arg) { + case 0: + /* newer tuner can faster reset */ + switch (dev->model) { + case TM5600_BOARD_10MOONS_UT821: + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.tuner_reset, 0x01); + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + 0x300, 0x01); + msleep(10); + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.tuner_reset, 0x00); + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + 0x300, 0x00); + msleep(10); + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.tuner_reset, 0x01); + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + 0x300, 0x01); + break; + case TM6010_BOARD_HAUPPAUGE_900H: + case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: + case TM6010_BOARD_TWINHAN_TU501: + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.tuner_reset, 0x01); + msleep(60); + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.tuner_reset, 0x00); + msleep(75); + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.tuner_reset, 0x01); + msleep(60); + break; + default: + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.tuner_reset, 0x00); + msleep(130); + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.tuner_reset, 0x01); + msleep(130); + break; + } + + tm6000_ir_wait(dev, 1); + break; + case 1: + tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, + 0x02, 0x01); + msleep(10); + break; + case 2: + rc = tm6000_i2c_reset(dev, 100); + break; + } + break; + case XC2028_I2C_FLUSH: + tm6000_set_reg(dev, REQ_50_SET_START, 0, 0); + tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0); + break; + } + return rc; +} +EXPORT_SYMBOL_GPL(tm6000_tuner_callback); + +int tm6000_cards_setup(struct tm6000_core *dev) +{ + /* + * Board-specific initialization sequence. Handles all GPIO + * initialization sequences that are board-specific. + * Up to now, all found devices use GPIO1 and GPIO4 at the same way. + * Probably, they're all based on some reference device. Due to that, + * there's a common routine at the end to handle those GPIO's. Devices + * that use different pinups or init sequences can just return at + * the board-specific session. + */ + switch (dev->model) { + case TM6010_BOARD_HAUPPAUGE_900H: + case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: + case TM6010_BOARD_TWINHAN_TU501: + case TM6010_BOARD_GENERIC: + /* Turn xceive 3028 on */ + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.tuner_on, 0x01); + msleep(15); + /* Turn zarlink zl10353 on */ + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00); + msleep(15); + /* Reset zarlink zl10353 */ + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00); + msleep(50); + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01); + msleep(15); + /* Turn zarlink zl10353 off */ + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x01); + msleep(15); + /* ir ? */ + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.ir, 0x01); + msleep(15); + /* Power led on (blue) */ + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x00); + msleep(15); + /* DVB led off (orange) */ + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.dvb_led, 0x01); + msleep(15); + /* Turn zarlink zl10353 on */ + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00); + msleep(15); + break; + case TM6010_BOARD_BEHOLD_WANDER: + case TM6010_BOARD_BEHOLD_WANDER_LITE: + /* Power led on (blue) */ + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01); + msleep(15); + /* Reset zarlink zl10353 */ + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00); + msleep(50); + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01); + msleep(15); + break; + case TM6010_BOARD_BEHOLD_VOYAGER: + case TM6010_BOARD_BEHOLD_VOYAGER_LITE: + /* Power led on (blue) */ + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01); + msleep(15); + break; + default: + break; + } + + /* + * Default initialization. Most of the devices seem to use GPIO1 + * and GPIO4.on the same way, so, this handles the common sequence + * used by most devices. + * If a device uses a different sequence or different GPIO pins for + * reset, just add the code at the board-specific part + */ + + if (dev->gpio.tuner_reset) { + int rc; + int i; + + for (i = 0; i < 2; i++) { + rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.tuner_reset, 0x00); + if (rc < 0) { + printk(KERN_ERR "Error %i doing tuner reset\n", rc); + return rc; + } + + msleep(10); /* Just to be conservative */ + rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.tuner_reset, 0x01); + if (rc < 0) { + printk(KERN_ERR "Error %i doing tuner reset\n", rc); + return rc; + } + } + } else { + printk(KERN_ERR "Tuner reset is not configured\n"); + return -1; + } + + msleep(50); + + return 0; +}; + +static void tm6000_config_tuner(struct tm6000_core *dev) +{ + struct tuner_setup tun_setup; + + /* Load tuner module */ + v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, + "tuner", dev->tuner_addr, NULL); + + memset(&tun_setup, 0, sizeof(tun_setup)); + tun_setup.type = dev->tuner_type; + tun_setup.addr = dev->tuner_addr; + + tun_setup.mode_mask = 0; + if (dev->caps.has_tuner) + tun_setup.mode_mask |= (T_ANALOG_TV | T_RADIO); + + switch (dev->tuner_type) { + case TUNER_XC2028: + tun_setup.tuner_callback = tm6000_tuner_callback; + break; + case TUNER_XC5000: + tun_setup.tuner_callback = tm6000_xc5000_callback; + break; + } + + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup); + + switch (dev->tuner_type) { + case TUNER_XC2028: { + struct v4l2_priv_tun_config xc2028_cfg; + struct xc2028_ctrl ctl; + + memset(&xc2028_cfg, 0, sizeof(xc2028_cfg)); + memset(&ctl, 0, sizeof(ctl)); + + ctl.demod = XC3028_FE_ZARLINK456; + + xc2028_cfg.tuner = TUNER_XC2028; + xc2028_cfg.priv = &ctl; + + switch (dev->model) { + case TM6010_BOARD_HAUPPAUGE_900H: + case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: + case TM6010_BOARD_TWINHAN_TU501: + ctl.fname = "xc3028L-v36.fw"; + break; + default: + if (dev->dev_type == TM6010) + ctl.fname = "xc3028-v27.fw"; + else + ctl.fname = "xc3028-v24.fw"; + } + + printk(KERN_INFO "Setting firmware parameters for xc2028\n"); + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, + &xc2028_cfg); + + } + break; + case TUNER_XC5000: + { + struct v4l2_priv_tun_config xc5000_cfg; + struct xc5000_config ctl = { + .i2c_address = dev->tuner_addr, + .if_khz = 4570, + .radio_input = XC5000_RADIO_FM1_MONO, + }; + + xc5000_cfg.tuner = TUNER_XC5000; + xc5000_cfg.priv = &ctl; + + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, + &xc5000_cfg); + } + break; + default: + printk(KERN_INFO "Unknown tuner type. Tuner is not configured.\n"); + break; + } +} + +static int fill_board_specific_data(struct tm6000_core *dev) +{ + int rc; + + dev->dev_type = tm6000_boards[dev->model].type; + dev->tuner_type = tm6000_boards[dev->model].tuner_type; + dev->tuner_addr = tm6000_boards[dev->model].tuner_addr; + + dev->gpio = tm6000_boards[dev->model].gpio; + + dev->ir_codes = tm6000_boards[dev->model].ir_codes; + + dev->demod_addr = tm6000_boards[dev->model].demod_addr; + + dev->caps = tm6000_boards[dev->model].caps; + + dev->vinput[0] = tm6000_boards[dev->model].vinput[0]; + dev->vinput[1] = tm6000_boards[dev->model].vinput[1]; + dev->vinput[2] = tm6000_boards[dev->model].vinput[2]; + dev->rinput = tm6000_boards[dev->model].rinput; + + /* setup per-model quirks */ + switch (dev->model) { + case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: + dev->quirks |= TM6000_QUIRK_NO_USB_DELAY; + break; + + default: + break; + } + + /* initialize hardware */ + rc = tm6000_init(dev); + if (rc < 0) + return rc; + + return v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev); +} + + +static void use_alternative_detection_method(struct tm6000_core *dev) +{ + int i, model = -1; + + if (!dev->eedata_size) + return; + + for (i = 0; i < ARRAY_SIZE(tm6000_boards); i++) { + if (!tm6000_boards[i].eename_size) + continue; + if (dev->eedata_size < tm6000_boards[i].eename_pos + + tm6000_boards[i].eename_size) + continue; + + if (!memcmp(&dev->eedata[tm6000_boards[i].eename_pos], + tm6000_boards[i].eename, + tm6000_boards[i].eename_size)) { + model = i; + break; + } + } + if (model < 0) { + printk(KERN_INFO "Device has eeprom but is currently unknown\n"); + return; + } + + dev->model = model; + + printk(KERN_INFO "Device identified via eeprom as %s (type = %d)\n", + tm6000_boards[model].name, model); +} + +static int tm6000_init_dev(struct tm6000_core *dev) +{ + struct v4l2_frequency f; + int rc = 0; + + mutex_init(&dev->lock); + mutex_lock(&dev->lock); + + if (!is_generic(dev->model)) { + rc = fill_board_specific_data(dev); + if (rc < 0) + goto err; + + /* register i2c bus */ + rc = tm6000_i2c_register(dev); + if (rc < 0) + goto err; + } else { + /* register i2c bus */ + rc = tm6000_i2c_register(dev); + if (rc < 0) + goto err; + + use_alternative_detection_method(dev); + + rc = fill_board_specific_data(dev); + if (rc < 0) + goto err; + } + + /* Default values for STD and resolutions */ + dev->width = 720; + dev->height = 480; + dev->norm = V4L2_STD_PAL_M; + + /* Configure tuner */ + tm6000_config_tuner(dev); + + /* Set video standard */ + v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm); + + /* Set tuner frequency - also loads firmware on xc2028/xc3028 */ + f.tuner = 0; + f.type = V4L2_TUNER_ANALOG_TV; + f.frequency = 3092; /* 193.25 MHz */ + dev->freq = f.frequency; + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f); + + if (dev->caps.has_tda9874) + v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, + "tvaudio", I2C_ADDR_TDA9874, NULL); + + /* register and initialize V4L2 */ + rc = tm6000_v4l2_register(dev); + if (rc < 0) + goto err; + + tm6000_add_into_devlist(dev); + tm6000_init_extension(dev); + + tm6000_ir_init(dev); + + mutex_unlock(&dev->lock); + return 0; + +err: + mutex_unlock(&dev->lock); + return rc; +} + +/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */ +#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03)) + +static void get_max_endpoint(struct usb_device *udev, + struct usb_host_interface *alt, + char *msgtype, + struct usb_host_endpoint *curr_e, + struct tm6000_endpoint *tm_ep) +{ + u16 tmp = le16_to_cpu(curr_e->desc.wMaxPacketSize); + unsigned int size = tmp & 0x7ff; + + if (udev->speed == USB_SPEED_HIGH) + size = size * hb_mult(tmp); + + if (size > tm_ep->maxsize) { + tm_ep->endp = curr_e; + tm_ep->maxsize = size; + tm_ep->bInterfaceNumber = alt->desc.bInterfaceNumber; + tm_ep->bAlternateSetting = alt->desc.bAlternateSetting; + + printk(KERN_INFO "tm6000: %s endpoint: 0x%02x (max size=%u bytes)\n", + msgtype, curr_e->desc.bEndpointAddress, + size); + } +} + +/* + * tm6000_usb_probe() + * checks for supported devices + */ +static int tm6000_usb_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct usb_device *usbdev; + struct tm6000_core *dev = NULL; + int i, rc = 0; + int nr = 0; + char *speed; + + usbdev = usb_get_dev(interface_to_usbdev(interface)); + + /* Selects the proper interface */ + rc = usb_set_interface(usbdev, 0, 1); + if (rc < 0) + goto err; + + /* Check to see next free device and mark as used */ + nr = find_first_zero_bit(&tm6000_devused, TM6000_MAXBOARDS); + if (nr >= TM6000_MAXBOARDS) { + printk(KERN_ERR "tm6000: Supports only %i tm60xx boards.\n", TM6000_MAXBOARDS); + usb_put_dev(usbdev); + return -ENOMEM; + } + + /* Create and initialize dev struct */ + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { + printk(KERN_ERR "tm6000" ": out of memory!\n"); + usb_put_dev(usbdev); + return -ENOMEM; + } + spin_lock_init(&dev->slock); + mutex_init(&dev->usb_lock); + + /* Increment usage count */ + set_bit(nr, &tm6000_devused); + snprintf(dev->name, 29, "tm6000 #%d", nr); + + dev->model = id->driver_info; + if (card[nr] < ARRAY_SIZE(tm6000_boards)) + dev->model = card[nr]; + + dev->udev = usbdev; + dev->devno = nr; + + switch (usbdev->speed) { + case USB_SPEED_LOW: + speed = "1.5"; + break; + case USB_SPEED_UNKNOWN: + case USB_SPEED_FULL: + speed = "12"; + break; + case USB_SPEED_HIGH: + speed = "480"; + break; + default: + speed = "unknown"; + } + + /* Get endpoints */ + for (i = 0; i < interface->num_altsetting; i++) { + int ep; + + for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) { + struct usb_host_endpoint *e; + int dir_out; + + e = &interface->altsetting[i].endpoint[ep]; + + dir_out = ((e->desc.bEndpointAddress & + USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT); + + printk(KERN_INFO "tm6000: alt %d, interface %i, class %i\n", + i, + interface->altsetting[i].desc.bInterfaceNumber, + interface->altsetting[i].desc.bInterfaceClass); + + switch (e->desc.bmAttributes) { + case USB_ENDPOINT_XFER_BULK: + if (!dir_out) { + get_max_endpoint(usbdev, + &interface->altsetting[i], + "Bulk IN", e, + &dev->bulk_in); + } else { + get_max_endpoint(usbdev, + &interface->altsetting[i], + "Bulk OUT", e, + &dev->bulk_out); + } + break; + case USB_ENDPOINT_XFER_ISOC: + if (!dir_out) { + get_max_endpoint(usbdev, + &interface->altsetting[i], + "ISOC IN", e, + &dev->isoc_in); + } else { + get_max_endpoint(usbdev, + &interface->altsetting[i], + "ISOC OUT", e, + &dev->isoc_out); + } + break; + case USB_ENDPOINT_XFER_INT: + if (!dir_out) { + get_max_endpoint(usbdev, + &interface->altsetting[i], + "INT IN", e, + &dev->int_in); + } else { + get_max_endpoint(usbdev, + &interface->altsetting[i], + "INT OUT", e, + &dev->int_out); + } + break; + } + } + } + + + printk(KERN_INFO "tm6000: New video device @ %s Mbps (%04x:%04x, ifnum %d)\n", + speed, + le16_to_cpu(dev->udev->descriptor.idVendor), + le16_to_cpu(dev->udev->descriptor.idProduct), + interface->altsetting->desc.bInterfaceNumber); + +/* check if the the device has the iso in endpoint at the correct place */ + if (!dev->isoc_in.endp) { + printk(KERN_ERR "tm6000: probing error: no IN ISOC endpoint!\n"); + rc = -ENODEV; + + goto err; + } + + /* save our data pointer in this interface device */ + usb_set_intfdata(interface, dev); + + printk(KERN_INFO "tm6000: Found %s\n", tm6000_boards[dev->model].name); + + rc = tm6000_init_dev(dev); + if (rc < 0) + goto err; + + return 0; + +err: + printk(KERN_ERR "tm6000: Error %d while registering\n", rc); + + clear_bit(nr, &tm6000_devused); + usb_put_dev(usbdev); + + kfree(dev); + return rc; +} + +/* + * tm6000_usb_disconnect() + * called when the device gets diconencted + * video device will be unregistered on v4l2_close in case it is still open + */ +static void tm6000_usb_disconnect(struct usb_interface *interface) +{ + struct tm6000_core *dev = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); + + if (!dev) + return; + + printk(KERN_INFO "tm6000: disconnecting %s\n", dev->name); + + tm6000_ir_fini(dev); + + if (dev->gpio.power_led) { + switch (dev->model) { + case TM6010_BOARD_HAUPPAUGE_900H: + case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: + case TM6010_BOARD_TWINHAN_TU501: + /* Power led off */ + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.power_led, 0x01); + msleep(15); + break; + case TM6010_BOARD_BEHOLD_WANDER: + case TM6010_BOARD_BEHOLD_VOYAGER: + case TM6010_BOARD_BEHOLD_WANDER_LITE: + case TM6010_BOARD_BEHOLD_VOYAGER_LITE: + /* Power led off */ + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.power_led, 0x00); + msleep(15); + break; + } + } + tm6000_v4l2_unregister(dev); + + tm6000_i2c_unregister(dev); + + v4l2_device_unregister(&dev->v4l2_dev); + + dev->state |= DEV_DISCONNECTED; + + usb_put_dev(dev->udev); + + tm6000_close_extension(dev); + tm6000_remove_from_devlist(dev); + + clear_bit(dev->devno, &tm6000_devused); + kfree(dev); +} + +static struct usb_driver tm6000_usb_driver = { + .name = "tm6000", + .probe = tm6000_usb_probe, + .disconnect = tm6000_usb_disconnect, + .id_table = tm6000_id_table, +}; + +static int __init tm6000_module_init(void) +{ + int result; + + printk(KERN_INFO "tm6000" " v4l2 driver version %d.%d.%d loaded\n", + (TM6000_VERSION >> 16) & 0xff, + (TM6000_VERSION >> 8) & 0xff, TM6000_VERSION & 0xff); + + /* register this driver with the USB subsystem */ + result = usb_register(&tm6000_usb_driver); + if (result) + printk(KERN_ERR "tm6000" + " usb_register failed. Error number %d.\n", result); + + return result; +} + +static void __exit tm6000_module_exit(void) +{ + /* deregister at USB subsystem */ + usb_deregister(&tm6000_usb_driver); +} + +module_init(tm6000_module_init); +module_exit(tm6000_module_exit); + +MODULE_DESCRIPTION("Trident TVMaster TM5600/TM6000/TM6010 USB2 adapter"); +MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/tm6000/tm6000-core.c b/drivers/media/video/tm6000/tm6000-core.c new file mode 100644 index 0000000..9783616 --- /dev/null +++ b/drivers/media/video/tm6000/tm6000-core.c @@ -0,0 +1,965 @@ +/* + * tm6000-core.c - driver for TM5600/TM6000/TM6010 USB video capture devices + * + * Copyright (C) 2006-2007 Mauro Carvalho Chehab + * + * Copyright (C) 2007 Michel Ludwig + * - DVB-T support + * + * 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 version 2 + * + * 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 +#include +#include +#include +#include +#include "tm6000.h" +#include "tm6000-regs.h" +#include +#include + +#define USB_TIMEOUT (5 * HZ) /* ms */ + +int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req, + u16 value, u16 index, u8 *buf, u16 len) +{ + int ret, i; + unsigned int pipe; + u8 *data = NULL; + + mutex_lock(&dev->usb_lock); + + if (len) + data = kzalloc(len, GFP_KERNEL); + + if (req_type & USB_DIR_IN) + pipe = usb_rcvctrlpipe(dev->udev, 0); + else { + pipe = usb_sndctrlpipe(dev->udev, 0); + memcpy(data, buf, len); + } + + if (tm6000_debug & V4L2_DEBUG_I2C) { + printk(KERN_DEBUG "(dev %p, pipe %08x): ", dev->udev, pipe); + + printk(KERN_CONT "%s: %02x %02x %02x %02x %02x %02x %02x %02x ", + (req_type & USB_DIR_IN) ? " IN" : "OUT", + req_type, req, value&0xff, value>>8, index&0xff, + index>>8, len&0xff, len>>8); + + if (!(req_type & USB_DIR_IN)) { + printk(KERN_CONT ">>> "); + for (i = 0; i < len; i++) + printk(KERN_CONT " %02x", buf[i]); + printk(KERN_CONT "\n"); + } + } + + ret = usb_control_msg(dev->udev, pipe, req, req_type, value, index, + data, len, USB_TIMEOUT); + + if (req_type & USB_DIR_IN) + memcpy(buf, data, len); + + if (tm6000_debug & V4L2_DEBUG_I2C) { + if (ret < 0) { + if (req_type & USB_DIR_IN) + printk(KERN_DEBUG "<<< (len=%d)\n", len); + + printk(KERN_CONT "%s: Error #%d\n", __func__, ret); + } else if (req_type & USB_DIR_IN) { + printk(KERN_CONT "<<< "); + for (i = 0; i < len; i++) + printk(KERN_CONT " %02x", buf[i]); + printk(KERN_CONT "\n"); + } + } + + kfree(data); + msleep(5); + + mutex_unlock(&dev->usb_lock); + return ret; +} + +int tm6000_set_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index) +{ + return + tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR, + req, value, index, NULL, 0); +} +EXPORT_SYMBOL_GPL(tm6000_set_reg); + +int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index) +{ + int rc; + u8 buf[1]; + + rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req, + value, index, buf, 1); + + if (rc < 0) + return rc; + + return *buf; +} +EXPORT_SYMBOL_GPL(tm6000_get_reg); + +int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value, + u16 index, u16 mask) +{ + int rc; + u8 buf[1]; + u8 new_index; + + rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req, + value, index, buf, 1); + + if (rc < 0) + return rc; + + new_index = (buf[0] & ~mask) | (index & mask); + + if (new_index == index) + return 0; + + return tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR, + req, value, new_index, NULL, 0); +} +EXPORT_SYMBOL_GPL(tm6000_set_reg_mask); + +int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index) +{ + int rc; + u8 buf[2]; + + rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req, + value, index, buf, 2); + + if (rc < 0) + return rc; + + return buf[1]|buf[0]<<8; +} + +int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index) +{ + int rc; + u8 buf[4]; + + rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req, + value, index, buf, 4); + + if (rc < 0) + return rc; + + return buf[3] | buf[2] << 8 | buf[1] << 16 | buf[0] << 24; +} + +int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep) +{ + int rc; + + rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_CLK, 0); + if (rc < 0) + return rc; + + msleep(tsleep); + + rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_CLK, 1); + msleep(tsleep); + + return rc; +} + +void tm6000_set_fourcc_format(struct tm6000_core *dev) +{ + if (dev->dev_type == TM6010) { + int val; + + val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_IF, 0) & 0xfc; + if (dev->fourcc == V4L2_PIX_FMT_UYVY) + tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_IF, val); + else + tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_IF, val | 1); + } else { + if (dev->fourcc == V4L2_PIX_FMT_UYVY) + tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0); + else + tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0x90); + } +} + +static void tm6000_set_vbi(struct tm6000_core *dev) +{ + /* + * FIXME: + * VBI lines and start/end are different between 60Hz and 50Hz + * So, it is very likely that we need to change the config to + * something that takes it into account, doing something different + * if (dev->norm & V4L2_STD_525_60) + */ + + if (dev->dev_type == TM6010) { + tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01); + tm6000_set_reg(dev, TM6010_REQ07_R41_TELETEXT_VBI_CODE1, 0x27); + tm6000_set_reg(dev, TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55); + tm6000_set_reg(dev, TM6010_REQ07_R43_VBI_DATA_TYPE_LINE7, 0x66); + tm6000_set_reg(dev, TM6010_REQ07_R44_VBI_DATA_TYPE_LINE8, 0x66); + tm6000_set_reg(dev, TM6010_REQ07_R45_VBI_DATA_TYPE_LINE9, 0x66); + tm6000_set_reg(dev, + TM6010_REQ07_R46_VBI_DATA_TYPE_LINE10, 0x66); + tm6000_set_reg(dev, + TM6010_REQ07_R47_VBI_DATA_TYPE_LINE11, 0x66); + tm6000_set_reg(dev, + TM6010_REQ07_R48_VBI_DATA_TYPE_LINE12, 0x66); + tm6000_set_reg(dev, + TM6010_REQ07_R49_VBI_DATA_TYPE_LINE13, 0x66); + tm6000_set_reg(dev, + TM6010_REQ07_R4A_VBI_DATA_TYPE_LINE14, 0x66); + tm6000_set_reg(dev, + TM6010_REQ07_R4B_VBI_DATA_TYPE_LINE15, 0x66); + tm6000_set_reg(dev, + TM6010_REQ07_R4C_VBI_DATA_TYPE_LINE16, 0x66); + tm6000_set_reg(dev, + TM6010_REQ07_R4D_VBI_DATA_TYPE_LINE17, 0x66); + tm6000_set_reg(dev, + TM6010_REQ07_R4E_VBI_DATA_TYPE_LINE18, 0x66); + tm6000_set_reg(dev, + TM6010_REQ07_R4F_VBI_DATA_TYPE_LINE19, 0x66); + tm6000_set_reg(dev, + TM6010_REQ07_R50_VBI_DATA_TYPE_LINE20, 0x66); + tm6000_set_reg(dev, + TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x66); + tm6000_set_reg(dev, + TM6010_REQ07_R52_VBI_DATA_TYPE_LINE22, 0x66); + tm6000_set_reg(dev, + TM6010_REQ07_R53_VBI_DATA_TYPE_LINE23, 0x00); + tm6000_set_reg(dev, + TM6010_REQ07_R54_VBI_DATA_TYPE_RLINES, 0x00); + tm6000_set_reg(dev, + TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01); + tm6000_set_reg(dev, + TM6010_REQ07_R56_VBI_LOOP_FILTER_I_GAIN, 0x00); + tm6000_set_reg(dev, + TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02); + tm6000_set_reg(dev, TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35); + tm6000_set_reg(dev, TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0); + tm6000_set_reg(dev, TM6010_REQ07_R5A_VBI_TELETEXT_DTO1, 0x11); + tm6000_set_reg(dev, TM6010_REQ07_R5B_VBI_TELETEXT_DTO0, 0x4c); + tm6000_set_reg(dev, TM6010_REQ07_R40_TELETEXT_VBI_CODE0, 0x01); + tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00); + } +} + +int tm6000_init_analog_mode(struct tm6000_core *dev) +{ + struct v4l2_frequency f; + + if (dev->dev_type == TM6010) { + u8 active = TM6010_REQ07_RCC_ACTIVE_IF_AUDIO_ENABLE; + + if (!dev->radio) + active |= TM6010_REQ07_RCC_ACTIVE_IF_VIDEO_ENABLE; + + /* Enable video and audio */ + tm6000_set_reg_mask(dev, TM6010_REQ07_RCC_ACTIVE_IF, + active, 0x60); + /* Disable TS input */ + tm6000_set_reg_mask(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, + 0x00, 0x40); + } else { + /* Enables soft reset */ + tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01); + + if (dev->scaler) + /* Disable Hfilter and Enable TS Drop err */ + tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x20); + else /* Enable Hfilter and disable TS Drop err */ + tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x80); + + tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x88); + tm6000_set_reg(dev, TM6000_REQ07_RDA_CLK_SEL, 0x23); + tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xc0); + tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xd8); + tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x06); + tm6000_set_reg(dev, TM6000_REQ07_RDF_PWDOWN_ACLK, 0x1f); + + /* AP Software reset */ + tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08); + tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00); + + tm6000_set_fourcc_format(dev); + + /* Disables soft reset */ + tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00); + } + msleep(20); + + /* Tuner firmware can now be loaded */ + + /* + * FIXME: This is a hack! xc3028 "sleeps" when no channel is detected + * for more than a few seconds. Not sure why, as this behavior does + * not happen on other devices with xc3028. So, I suspect that it + * is yet another bug at tm6000. After start sleeping, decoding + * doesn't start automatically. Instead, it requires some + * I2C commands to wake it up. As we want to have image at the + * beginning, we needed to add this hack. The better would be to + * discover some way to make tm6000 to wake up without this hack. + */ + f.frequency = dev->freq; + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f); + + msleep(100); + tm6000_set_standard(dev); + tm6000_set_vbi(dev); + tm6000_set_audio_bitrate(dev, 48000); + + /* switch dvb led off */ + if (dev->gpio.dvb_led) { + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.dvb_led, 0x01); + } + + return 0; +} + +int tm6000_init_digital_mode(struct tm6000_core *dev) +{ + if (dev->dev_type == TM6010) { + /* Disable video and audio */ + tm6000_set_reg_mask(dev, TM6010_REQ07_RCC_ACTIVE_IF, + 0x00, 0x60); + /* Enable TS input */ + tm6000_set_reg_mask(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, + 0x40, 0x40); + /* all power down, but not the digital data port */ + tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, 0x28); + tm6000_set_reg(dev, TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xfc); + tm6000_set_reg(dev, TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0xff); + } else { + tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08); + tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00); + tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01); + tm6000_set_reg(dev, TM6000_REQ07_RDF_PWDOWN_ACLK, 0x08); + tm6000_set_reg(dev, TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x0c); + tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0xff); + tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0xd8); + tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x40); + tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0); + tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x09); + tm6000_set_reg(dev, TM6000_REQ07_RDA_CLK_SEL, 0x37); + tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xd8); + tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xc0); + tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x60); + + tm6000_set_reg(dev, TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x0c); + tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0xff); + tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0x08); + msleep(50); + + tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00); + msleep(50); + tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x01); + msleep(50); + tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00); + msleep(100); + } + + /* switch dvb led on */ + if (dev->gpio.dvb_led) { + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.dvb_led, 0x00); + } + + return 0; +} +EXPORT_SYMBOL(tm6000_init_digital_mode); + +struct reg_init { + u8 req; + u8 reg; + u8 val; +}; + +/* The meaning of those initializations are unknown */ +static struct reg_init tm6000_init_tab[] = { + /* REG VALUE */ + { TM6000_REQ07_RDF_PWDOWN_ACLK, 0x1f }, + { TM6010_REQ07_RFF_SOFT_RESET, 0x08 }, + { TM6010_REQ07_RFF_SOFT_RESET, 0x00 }, + { TM6010_REQ07_RD5_POWERSAVE, 0x4f }, + { TM6000_REQ07_RDA_CLK_SEL, 0x23 }, + { TM6000_REQ07_RDB_OUT_SEL, 0x08 }, + { TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x00 }, + { TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10 }, + { TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00 }, + { TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x00 }, + { TM6000_REQ07_REB_VADC_AADC_MODE, 0x64 }, /* 48000 bits/sample, external input */ + { TM6000_REQ07_REE_VADC_CTRL_SEL_CONTROL, 0xc2 }, + + { TM6010_REQ07_R3F_RESET, 0x01 }, /* Start of soft reset */ + { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 }, + { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x07 }, + { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, + { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 }, + { TM6010_REQ07_R05_NOISE_THRESHOLD, 0x64 }, + { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01 }, + { TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0x82 }, + { TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0x36 }, + { TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0x50 }, + { TM6010_REQ07_R0C_CHROMA_AGC_CONTROL, 0x6a }, + { TM6010_REQ07_R11_AGC_PEAK_CONTROL, 0xc9 }, + { TM6010_REQ07_R12_AGC_GATE_STARTH, 0x07 }, + { TM6010_REQ07_R13_AGC_GATE_STARTL, 0x3b }, + { TM6010_REQ07_R14_AGC_GATE_WIDTH, 0x47 }, + { TM6010_REQ07_R15_AGC_BP_DELAY, 0x6f }, + { TM6010_REQ07_R17_HLOOP_MAXSTATE, 0xcd }, + { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, + { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b }, + { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 }, + { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 }, + { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, + { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, + { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, + { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, + { TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME, 0x3c }, + { TM6010_REQ07_R21_HSYNC_PHASE_OFFSET, 0x3c }, + { TM6010_REQ07_R2D_CHROMA_BURST_END, 0x48 }, + { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, + { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 }, + { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 }, + { TM6010_REQ07_R32_VSYNC_HLOCK_MIN, 0x74 }, + { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c }, + { TM6010_REQ07_R34_VSYNC_AGC_MIN, 0x74 }, + { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, + { TM6010_REQ07_R36_VSYNC_VBI_MIN, 0x7a }, + { TM6010_REQ07_R37_VSYNC_VBI_MAX, 0x26 }, + { TM6010_REQ07_R38_VSYNC_THRESHOLD, 0x40 }, + { TM6010_REQ07_R39_VSYNC_TIME_CONSTANT, 0x0a }, + { TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55 }, + { TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x11 }, + { TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01 }, + { TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02 }, + { TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35 }, + { TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0 }, + { TM6010_REQ07_R80_COMB_FILTER_TRESHOLD, 0x15 }, + { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 }, + { TM6010_REQ07_RC1_TRESHOLD, 0xd0 }, + { TM6010_REQ07_RC3_HSTART1, 0x88 }, + { TM6010_REQ07_R3F_RESET, 0x00 }, /* End of the soft reset */ + { TM6010_REQ05_R18_IMASK7, 0x00 }, +}; + +static struct reg_init tm6010_init_tab[] = { + { TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x00 }, + { TM6010_REQ07_RC4_HSTART0, 0xa0 }, + { TM6010_REQ07_RC6_HEND0, 0x40 }, + { TM6010_REQ07_RCA_VEND0, 0x31 }, + { TM6010_REQ07_RCC_ACTIVE_IF, 0xe1 }, + { TM6010_REQ07_RE0_DVIDEO_SOURCE, 0x03 }, + { TM6010_REQ07_RFE_POWER_DOWN, 0x7f }, + + { TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0 }, + { TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4 }, + { TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8 }, + { TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x00 }, + { TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2 }, + { TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0 }, + { TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2 }, + { TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60 }, + { TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc }, + + { TM6010_REQ07_R3F_RESET, 0x01 }, + { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 }, + { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x07 }, + { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, + { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 }, + { TM6010_REQ07_R05_NOISE_THRESHOLD, 0x64 }, + { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01 }, + { TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0x82 }, + { TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0x36 }, + { TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0x50 }, + { TM6010_REQ07_R0C_CHROMA_AGC_CONTROL, 0x6a }, + { TM6010_REQ07_R11_AGC_PEAK_CONTROL, 0xc9 }, + { TM6010_REQ07_R12_AGC_GATE_STARTH, 0x07 }, + { TM6010_REQ07_R13_AGC_GATE_STARTL, 0x3b }, + { TM6010_REQ07_R14_AGC_GATE_WIDTH, 0x47 }, + { TM6010_REQ07_R15_AGC_BP_DELAY, 0x6f }, + { TM6010_REQ07_R17_HLOOP_MAXSTATE, 0xcd }, + { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, + { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b }, + { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 }, + { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 }, + { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, + { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, + { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, + { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, + { TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME, 0x3c }, + { TM6010_REQ07_R21_HSYNC_PHASE_OFFSET, 0x3c }, + { TM6010_REQ07_R2D_CHROMA_BURST_END, 0x48 }, + { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, + { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 }, + { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 }, + { TM6010_REQ07_R32_VSYNC_HLOCK_MIN, 0x74 }, + { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c }, + { TM6010_REQ07_R34_VSYNC_AGC_MIN, 0x74 }, + { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, + { TM6010_REQ07_R36_VSYNC_VBI_MIN, 0x7a }, + { TM6010_REQ07_R37_VSYNC_VBI_MAX, 0x26 }, + { TM6010_REQ07_R38_VSYNC_THRESHOLD, 0x40 }, + { TM6010_REQ07_R39_VSYNC_TIME_CONSTANT, 0x0a }, + { TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55 }, + { TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x11 }, + { TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01 }, + { TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02 }, + { TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35 }, + { TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0 }, + { TM6010_REQ07_R80_COMB_FILTER_TRESHOLD, 0x15 }, + { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 }, + { TM6010_REQ07_RC1_TRESHOLD, 0xd0 }, + { TM6010_REQ07_RC3_HSTART1, 0x88 }, + { TM6010_REQ07_R3F_RESET, 0x00 }, + + { TM6010_REQ05_R18_IMASK7, 0x00 }, + + { TM6010_REQ07_RD8_IR_LEADER1, 0xaa }, + { TM6010_REQ07_RD8_IR_LEADER0, 0x30 }, + { TM6010_REQ07_RD8_IR_PULSE_CNT1, 0x20 }, + { TM6010_REQ07_RD8_IR_PULSE_CNT0, 0xd0 }, + { REQ_04_EN_DISABLE_MCU_INT, 0x02, 0x00 }, + { TM6010_REQ07_RD8_IR, 0x2f }, + + /* set remote wakeup key:any key wakeup */ + { TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe }, + { TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0xff }, +}; + +int tm6000_init(struct tm6000_core *dev) +{ + int board, rc = 0, i, size; + struct reg_init *tab; + + /* Check board revision */ + board = tm6000_get_reg32(dev, REQ_40_GET_VERSION, 0, 0); + if (board >= 0) { + switch (board & 0xff) { + case 0xf3: + printk(KERN_INFO "Found tm6000\n"); + if (dev->dev_type != TM6000) + dev->dev_type = TM6000; + break; + case 0xf4: + printk(KERN_INFO "Found tm6010\n"); + if (dev->dev_type != TM6010) + dev->dev_type = TM6010; + break; + default: + printk(KERN_INFO "Unknown board version = 0x%08x\n", board); + } + } else + printk(KERN_ERR "Error %i while retrieving board version\n", board); + + if (dev->dev_type == TM6010) { + tab = tm6010_init_tab; + size = ARRAY_SIZE(tm6010_init_tab); + } else { + tab = tm6000_init_tab; + size = ARRAY_SIZE(tm6000_init_tab); + } + + /* Load board's initialization table */ + for (i = 0; i < size; i++) { + rc = tm6000_set_reg(dev, tab[i].req, tab[i].reg, tab[i].val); + if (rc < 0) { + printk(KERN_ERR "Error %i while setting req %d, " + "reg %d to value %d\n", rc, + tab[i].req, tab[i].reg, tab[i].val); + return rc; + } + } + + msleep(5); /* Just to be conservative */ + + rc = tm6000_cards_setup(dev); + + return rc; +} + +int tm6000_reset(struct tm6000_core *dev) +{ + int pipe; + int err; + + msleep(500); + + err = usb_set_interface(dev->udev, dev->isoc_in.bInterfaceNumber, 0); + if (err < 0) { + tm6000_err("failed to select interface %d, alt. setting 0\n", + dev->isoc_in.bInterfaceNumber); + return err; + } + + err = usb_reset_configuration(dev->udev); + if (err < 0) { + tm6000_err("failed to reset configuration\n"); + return err; + } + + if ((dev->quirks & TM6000_QUIRK_NO_USB_DELAY) == 0) + msleep(5); + + /* + * Not all devices have int_in defined + */ + if (!dev->int_in.endp) + return 0; + + err = usb_set_interface(dev->udev, dev->isoc_in.bInterfaceNumber, 2); + if (err < 0) { + tm6000_err("failed to select interface %d, alt. setting 2\n", + dev->isoc_in.bInterfaceNumber); + return err; + } + + msleep(5); + + pipe = usb_rcvintpipe(dev->udev, + dev->int_in.endp->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + + err = usb_clear_halt(dev->udev, pipe); + if (err < 0) { + tm6000_err("usb_clear_halt failed: %d\n", err); + return err; + } + + return 0; +} + +int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate) +{ + int val = 0; + u8 areg_f0 = 0x60; /* ADC MCLK = 250 Fs */ + u8 areg_0a = 0x91; /* SIF 48KHz */ + + switch (bitrate) { + case 48000: + areg_f0 = 0x60; /* ADC MCLK = 250 Fs */ + areg_0a = 0x91; /* SIF 48KHz */ + dev->audio_bitrate = bitrate; + break; + case 32000: + areg_f0 = 0x00; /* ADC MCLK = 375 Fs */ + areg_0a = 0x90; /* SIF 32KHz */ + dev->audio_bitrate = bitrate; + break; + default: + return -EINVAL; + } + + + /* enable I2S, if we use sif or external I2S device */ + if (dev->dev_type == TM6010) { + val = tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, areg_0a); + if (val < 0) + return val; + + val = tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, + areg_f0, 0xf0); + if (val < 0) + return val; + } else { + val = tm6000_set_reg_mask(dev, TM6000_REQ07_REB_VADC_AADC_MODE, + areg_f0, 0xf0); + if (val < 0) + return val; + } + return 0; +} +EXPORT_SYMBOL_GPL(tm6000_set_audio_bitrate); + +int tm6000_set_audio_rinput(struct tm6000_core *dev) +{ + if (dev->dev_type == TM6010) { + /* Audio crossbar setting, default SIF1 */ + u8 areg_f0; + + switch (dev->rinput.amux) { + case TM6000_AMUX_SIF1: + case TM6000_AMUX_SIF2: + areg_f0 = 0x03; + break; + case TM6000_AMUX_ADC1: + areg_f0 = 0x00; + break; + case TM6000_AMUX_ADC2: + areg_f0 = 0x08; + break; + case TM6000_AMUX_I2S: + areg_f0 = 0x04; + break; + default: + printk(KERN_INFO "%s: audio input dosn't support\n", + dev->name); + return 0; + break; + } + /* Set audio input crossbar */ + tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, + areg_f0, 0x0f); + } else { + u8 areg_eb; + /* Audio setting, default LINE1 */ + switch (dev->rinput.amux) { + case TM6000_AMUX_ADC1: + areg_eb = 0x00; + break; + case TM6000_AMUX_ADC2: + areg_eb = 0x04; + break; + default: + printk(KERN_INFO "%s: audio input dosn't support\n", + dev->name); + return 0; + break; + } + /* Set audio input */ + tm6000_set_reg_mask(dev, TM6000_REQ07_REB_VADC_AADC_MODE, + areg_eb, 0x0f); + } + return 0; +} + +static void tm6010_set_mute_sif(struct tm6000_core *dev, u8 mute) +{ + u8 mute_reg = 0; + + if (mute) + mute_reg = 0x08; + + tm6000_set_reg_mask(dev, TM6010_REQ08_R0A_A_I2S_MOD, mute_reg, 0x08); +} + +static void tm6010_set_mute_adc(struct tm6000_core *dev, u8 mute) +{ + u8 mute_reg = 0; + + if (mute) + mute_reg = 0x20; + + if (dev->dev_type == TM6010) { + tm6000_set_reg_mask(dev, TM6010_REQ08_RF2_LEFT_CHANNEL_VOL, + mute_reg, 0x20); + tm6000_set_reg_mask(dev, TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL, + mute_reg, 0x20); + } else { + tm6000_set_reg_mask(dev, TM6000_REQ07_REC_VADC_AADC_LVOL, + mute_reg, 0x20); + tm6000_set_reg_mask(dev, TM6000_REQ07_RED_VADC_AADC_RVOL, + mute_reg, 0x20); + } +} + +int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute) +{ + enum tm6000_mux mux; + + if (dev->radio) + mux = dev->rinput.amux; + else + mux = dev->vinput[dev->input].amux; + + switch (mux) { + case TM6000_AMUX_SIF1: + case TM6000_AMUX_SIF2: + if (dev->dev_type == TM6010) + tm6010_set_mute_sif(dev, mute); + else { + printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has" + " SIF audio inputs. Please check the %s" + " configuration.\n", dev->name); + return -EINVAL; + } + break; + case TM6000_AMUX_ADC1: + case TM6000_AMUX_ADC2: + tm6010_set_mute_adc(dev, mute); + break; + default: + return -EINVAL; + break; + } + return 0; +} + +static void tm6010_set_volume_sif(struct tm6000_core *dev, int vol) +{ + u8 vol_reg; + + vol_reg = vol & 0x0F; + + if (vol < 0) + vol_reg |= 0x40; + + tm6000_set_reg(dev, TM6010_REQ08_R07_A_LEFT_VOL, vol_reg); + tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, vol_reg); +} + +static void tm6010_set_volume_adc(struct tm6000_core *dev, int vol) +{ + u8 vol_reg; + + vol_reg = (vol + 0x10) & 0x1f; + + if (dev->dev_type == TM6010) { + tm6000_set_reg(dev, TM6010_REQ08_RF2_LEFT_CHANNEL_VOL, vol_reg); + tm6000_set_reg(dev, TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL, vol_reg); + } else { + tm6000_set_reg(dev, TM6000_REQ07_REC_VADC_AADC_LVOL, vol_reg); + tm6000_set_reg(dev, TM6000_REQ07_RED_VADC_AADC_RVOL, vol_reg); + } +} + +void tm6000_set_volume(struct tm6000_core *dev, int vol) +{ + enum tm6000_mux mux; + + if (dev->radio) { + mux = dev->rinput.amux; + vol += 8; /* Offset to 0 dB */ + } else + mux = dev->vinput[dev->input].amux; + + switch (mux) { + case TM6000_AMUX_SIF1: + case TM6000_AMUX_SIF2: + if (dev->dev_type == TM6010) + tm6010_set_volume_sif(dev, vol); + else + printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has" + " SIF audio inputs. Please check the %s" + " configuration.\n", dev->name); + break; + case TM6000_AMUX_ADC1: + case TM6000_AMUX_ADC2: + tm6010_set_volume_adc(dev, vol); + break; + default: + break; + } +} + +static LIST_HEAD(tm6000_devlist); +static DEFINE_MUTEX(tm6000_devlist_mutex); + +/* + * tm6000_realease_resource() + */ + +void tm6000_remove_from_devlist(struct tm6000_core *dev) +{ + mutex_lock(&tm6000_devlist_mutex); + list_del(&dev->devlist); + mutex_unlock(&tm6000_devlist_mutex); +}; + +void tm6000_add_into_devlist(struct tm6000_core *dev) +{ + mutex_lock(&tm6000_devlist_mutex); + list_add_tail(&dev->devlist, &tm6000_devlist); + mutex_unlock(&tm6000_devlist_mutex); +}; + +/* + * Extension interface + */ + +static LIST_HEAD(tm6000_extension_devlist); + +int tm6000_call_fillbuf(struct tm6000_core *dev, enum tm6000_ops_type type, + char *buf, int size) +{ + struct tm6000_ops *ops = NULL; + + /* FIXME: tm6000_extension_devlist_lock should be a spinlock */ + + if (!list_empty(&tm6000_extension_devlist)) { + list_for_each_entry(ops, &tm6000_extension_devlist, next) { + if (ops->fillbuf && ops->type == type) + ops->fillbuf(dev, buf, size); + } + } + + return 0; +} + +int tm6000_register_extension(struct tm6000_ops *ops) +{ + struct tm6000_core *dev = NULL; + + mutex_lock(&tm6000_devlist_mutex); + list_add_tail(&ops->next, &tm6000_extension_devlist); + list_for_each_entry(dev, &tm6000_devlist, devlist) { + ops->init(dev); + printk(KERN_INFO "%s: Initialized (%s) extension\n", + dev->name, ops->name); + } + mutex_unlock(&tm6000_devlist_mutex); + return 0; +} +EXPORT_SYMBOL(tm6000_register_extension); + +void tm6000_unregister_extension(struct tm6000_ops *ops) +{ + struct tm6000_core *dev = NULL; + + mutex_lock(&tm6000_devlist_mutex); + list_for_each_entry(dev, &tm6000_devlist, devlist) + ops->fini(dev); + + printk(KERN_INFO "tm6000: Remove (%s) extension\n", ops->name); + list_del(&ops->next); + mutex_unlock(&tm6000_devlist_mutex); +} +EXPORT_SYMBOL(tm6000_unregister_extension); + +void tm6000_init_extension(struct tm6000_core *dev) +{ + struct tm6000_ops *ops = NULL; + + mutex_lock(&tm6000_devlist_mutex); + if (!list_empty(&tm6000_extension_devlist)) { + list_for_each_entry(ops, &tm6000_extension_devlist, next) { + if (ops->init) + ops->init(dev); + } + } + mutex_unlock(&tm6000_devlist_mutex); +} + +void tm6000_close_extension(struct tm6000_core *dev) +{ + struct tm6000_ops *ops = NULL; + + mutex_lock(&tm6000_devlist_mutex); + if (!list_empty(&tm6000_extension_devlist)) { + list_for_each_entry(ops, &tm6000_extension_devlist, next) { + if (ops->fini) + ops->fini(dev); + } + } + mutex_unlock(&tm6000_devlist_mutex); +} diff --git a/drivers/media/video/tm6000/tm6000-dvb.c b/drivers/media/video/tm6000/tm6000-dvb.c new file mode 100644 index 0000000..5e6c129 --- /dev/null +++ b/drivers/media/video/tm6000/tm6000-dvb.c @@ -0,0 +1,452 @@ +/* + * tm6000-dvb.c - dvb-t support for TM5600/TM6000/TM6010 USB video capture devices + * + * Copyright (C) 2007 Michel Ludwig + * + * 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 version 2 + * + * 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 +#include +#include + +#include "tm6000.h" +#include "tm6000-regs.h" + +#include "zl10353.h" + +#include + +#include "tuner-xc2028.h" +#include "xc5000.h" + +MODULE_DESCRIPTION("DVB driver extension module for tm5600/6000/6010 based TV cards"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); + +MODULE_SUPPORTED_DEVICE("{{Trident, tm5600}," + "{{Trident, tm6000}," + "{{Trident, tm6010}"); + +static int debug; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable debug message"); + +static inline void print_err_status(struct tm6000_core *dev, + int packet, int status) +{ + char *errmsg = "Unknown"; + + switch (status) { + case -ENOENT: + errmsg = "unlinked synchronuously"; + break; + case -ECONNRESET: + errmsg = "unlinked asynchronuously"; + break; + case -ENOSR: + errmsg = "Buffer error (overrun)"; + break; + case -EPIPE: + errmsg = "Stalled (device not responding)"; + break; + case -EOVERFLOW: + errmsg = "Babble (bad cable?)"; + break; + case -EPROTO: + errmsg = "Bit-stuff error (bad cable?)"; + break; + case -EILSEQ: + errmsg = "CRC/Timeout (could be anything)"; + break; + case -ETIME: + errmsg = "Device does not respond"; + break; + } + if (packet < 0) { + dprintk(dev, 1, "URB status %d [%s].\n", + status, errmsg); + } else { + dprintk(dev, 1, "URB packet %d, status %d [%s].\n", + packet, status, errmsg); + } +} + +static void tm6000_urb_received(struct urb *urb) +{ + int ret; + struct tm6000_core *dev = urb->context; + + if (urb->status != 0) + print_err_status(dev, 0, urb->status); + else if (urb->actual_length > 0) + dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer, + urb->actual_length); + + if (dev->dvb->streams > 0) { + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret < 0) { + printk(KERN_ERR "tm6000: error %s\n", __func__); + kfree(urb->transfer_buffer); + usb_free_urb(urb); + } + } +} + +static int tm6000_start_stream(struct tm6000_core *dev) +{ + int ret; + unsigned int pipe, size; + struct tm6000_dvb *dvb = dev->dvb; + + printk(KERN_INFO "tm6000: got start stream request %s\n", __func__); + + if (dev->mode != TM6000_MODE_DIGITAL) { + tm6000_init_digital_mode(dev); + dev->mode = TM6000_MODE_DIGITAL; + } + + dvb->bulk_urb = usb_alloc_urb(0, GFP_KERNEL); + if (dvb->bulk_urb == NULL) { + printk(KERN_ERR "tm6000: couldn't allocate urb\n"); + return -ENOMEM; + } + + pipe = usb_rcvbulkpipe(dev->udev, dev->bulk_in.endp->desc.bEndpointAddress + & USB_ENDPOINT_NUMBER_MASK); + + size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe)); + size = size * 15; /* 512 x 8 or 12 or 15 */ + + dvb->bulk_urb->transfer_buffer = kzalloc(size, GFP_KERNEL); + if (dvb->bulk_urb->transfer_buffer == NULL) { + usb_free_urb(dvb->bulk_urb); + printk(KERN_ERR "tm6000: couldn't allocate transfer buffer!\n"); + return -ENOMEM; + } + + usb_fill_bulk_urb(dvb->bulk_urb, dev->udev, pipe, + dvb->bulk_urb->transfer_buffer, + size, + tm6000_urb_received, dev); + + ret = usb_clear_halt(dev->udev, pipe); + if (ret < 0) { + printk(KERN_ERR "tm6000: error %i in %s during pipe reset\n", + ret, __func__); + return ret; + } else + printk(KERN_ERR "tm6000: pipe resetted\n"); + +/* mutex_lock(&tm6000_driver.open_close_mutex); */ + ret = usb_submit_urb(dvb->bulk_urb, GFP_KERNEL); + +/* mutex_unlock(&tm6000_driver.open_close_mutex); */ + if (ret) { + printk(KERN_ERR "tm6000: submit of urb failed (error=%i)\n", + ret); + + kfree(dvb->bulk_urb->transfer_buffer); + usb_free_urb(dvb->bulk_urb); + return ret; + } + + return 0; +} + +static void tm6000_stop_stream(struct tm6000_core *dev) +{ + struct tm6000_dvb *dvb = dev->dvb; + + if (dvb->bulk_urb) { + printk(KERN_INFO "urb killing\n"); + usb_kill_urb(dvb->bulk_urb); + printk(KERN_INFO "urb buffer free\n"); + kfree(dvb->bulk_urb->transfer_buffer); + usb_free_urb(dvb->bulk_urb); + dvb->bulk_urb = NULL; + } +} + +static int tm6000_start_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct tm6000_core *dev = demux->priv; + struct tm6000_dvb *dvb = dev->dvb; + printk(KERN_INFO "tm6000: got start feed request %s\n", __func__); + + mutex_lock(&dvb->mutex); + if (dvb->streams == 0) { + dvb->streams = 1; +/* mutex_init(&tm6000_dev->streming_mutex); */ + tm6000_start_stream(dev); + } else + ++(dvb->streams); + mutex_unlock(&dvb->mutex); + + return 0; +} + +static int tm6000_stop_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct tm6000_core *dev = demux->priv; + struct tm6000_dvb *dvb = dev->dvb; + + printk(KERN_INFO "tm6000: got stop feed request %s\n", __func__); + + mutex_lock(&dvb->mutex); + + printk(KERN_INFO "stream %#x\n", dvb->streams); + --(dvb->streams); + if (dvb->streams == 0) { + printk(KERN_INFO "stop stream\n"); + tm6000_stop_stream(dev); +/* mutex_destroy(&tm6000_dev->streaming_mutex); */ + } + mutex_unlock(&dvb->mutex); +/* mutex_destroy(&tm6000_dev->streaming_mutex); */ + + return 0; +} + +static int tm6000_dvb_attach_frontend(struct tm6000_core *dev) +{ + struct tm6000_dvb *dvb = dev->dvb; + + if (dev->caps.has_zl10353) { + struct zl10353_config config = { + .demod_address = dev->demod_addr, + .no_tuner = 1, + .parallel_ts = 1, + .if2 = 45700, + .disable_i2c_gate_ctrl = 1, + }; + + dvb->frontend = dvb_attach(zl10353_attach, &config, + &dev->i2c_adap); + } else { + printk(KERN_ERR "tm6000: no frontend defined for the device!\n"); + return -1; + } + + return (!dvb->frontend) ? -1 : 0; +} + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int register_dvb(struct tm6000_core *dev) +{ + int ret = -1; + struct tm6000_dvb *dvb = dev->dvb; + + mutex_init(&dvb->mutex); + + dvb->streams = 0; + + /* attach the frontend */ + ret = tm6000_dvb_attach_frontend(dev); + if (ret < 0) { + printk(KERN_ERR "tm6000: couldn't attach the frontend!\n"); + goto err; + } + + ret = dvb_register_adapter(&dvb->adapter, "Trident TVMaster 6000 DVB-T", + THIS_MODULE, &dev->udev->dev, adapter_nr); + dvb->adapter.priv = dev; + + if (dvb->frontend) { + switch (dev->tuner_type) { + case TUNER_XC2028: { + struct xc2028_config cfg = { + .i2c_adap = &dev->i2c_adap, + .i2c_addr = dev->tuner_addr, + }; + + dvb->frontend->callback = tm6000_tuner_callback; + ret = dvb_register_frontend(&dvb->adapter, dvb->frontend); + if (ret < 0) { + printk(KERN_ERR + "tm6000: couldn't register frontend\n"); + goto adapter_err; + } + + if (!dvb_attach(xc2028_attach, dvb->frontend, &cfg)) { + printk(KERN_ERR "tm6000: couldn't register " + "frontend (xc3028)\n"); + ret = -EINVAL; + goto frontend_err; + } + printk(KERN_INFO "tm6000: XC2028/3028 asked to be " + "attached to frontend!\n"); + break; + } + case TUNER_XC5000: { + struct xc5000_config cfg = { + .i2c_address = dev->tuner_addr, + }; + + dvb->frontend->callback = tm6000_xc5000_callback; + ret = dvb_register_frontend(&dvb->adapter, dvb->frontend); + if (ret < 0) { + printk(KERN_ERR + "tm6000: couldn't register frontend\n"); + goto adapter_err; + } + + if (!dvb_attach(xc5000_attach, dvb->frontend, &dev->i2c_adap, &cfg)) { + printk(KERN_ERR "tm6000: couldn't register " + "frontend (xc5000)\n"); + ret = -EINVAL; + goto frontend_err; + } + printk(KERN_INFO "tm6000: XC5000 asked to be " + "attached to frontend!\n"); + break; + } + } + } else + printk(KERN_ERR "tm6000: no frontend found\n"); + + dvb->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING + | DMX_MEMORY_BASED_FILTERING; + dvb->demux.priv = dev; + dvb->demux.filternum = 8; + dvb->demux.feednum = 8; + dvb->demux.start_feed = tm6000_start_feed; + dvb->demux.stop_feed = tm6000_stop_feed; + dvb->demux.write_to_decoder = NULL; + ret = dvb_dmx_init(&dvb->demux); + if (ret < 0) { + printk(KERN_ERR "tm6000: dvb_dmx_init failed (errno = %d)\n", ret); + goto frontend_err; + } + + dvb->dmxdev.filternum = dev->dvb->demux.filternum; + dvb->dmxdev.demux = &dev->dvb->demux.dmx; + dvb->dmxdev.capabilities = 0; + + ret = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); + if (ret < 0) { + printk(KERN_ERR "tm6000: dvb_dmxdev_init failed (errno = %d)\n", ret); + goto dvb_dmx_err; + } + + return 0; + +dvb_dmx_err: + dvb_dmx_release(&dvb->demux); +frontend_err: + if (dvb->frontend) { + dvb_frontend_detach(dvb->frontend); + dvb_unregister_frontend(dvb->frontend); + } +adapter_err: + dvb_unregister_adapter(&dvb->adapter); +err: + return ret; +} + +static void unregister_dvb(struct tm6000_core *dev) +{ + struct tm6000_dvb *dvb = dev->dvb; + + if (dvb->bulk_urb != NULL) { + struct urb *bulk_urb = dvb->bulk_urb; + + kfree(bulk_urb->transfer_buffer); + bulk_urb->transfer_buffer = NULL; + usb_unlink_urb(bulk_urb); + usb_free_urb(bulk_urb); + } + +/* mutex_lock(&tm6000_driver.open_close_mutex); */ + if (dvb->frontend) { + dvb_frontend_detach(dvb->frontend); + dvb_unregister_frontend(dvb->frontend); + } + + dvb_dmxdev_release(&dvb->dmxdev); + dvb_dmx_release(&dvb->demux); + dvb_unregister_adapter(&dvb->adapter); + mutex_destroy(&dvb->mutex); +/* mutex_unlock(&tm6000_driver.open_close_mutex); */ +} + +static int dvb_init(struct tm6000_core *dev) +{ + struct tm6000_dvb *dvb; + int rc; + + if (!dev) + return 0; + + if (!dev->caps.has_dvb) + return 0; + + dvb = kzalloc(sizeof(struct tm6000_dvb), GFP_KERNEL); + if (!dvb) { + printk(KERN_INFO "Cannot allocate memory\n"); + return -ENOMEM; + } + + dev->dvb = dvb; + + rc = register_dvb(dev); + if (rc < 0) { + kfree(dvb); + dev->dvb = NULL; + return 0; + } + + return 0; +} + +static int dvb_fini(struct tm6000_core *dev) +{ + if (!dev) + return 0; + + if (!dev->caps.has_dvb) + return 0; + + if (dev->dvb) { + unregister_dvb(dev); + kfree(dev->dvb); + dev->dvb = NULL; + } + + return 0; +} + +static struct tm6000_ops dvb_ops = { + .type = TM6000_DVB, + .name = "TM6000 dvb Extension", + .init = dvb_init, + .fini = dvb_fini, +}; + +static int __init tm6000_dvb_register(void) +{ + return tm6000_register_extension(&dvb_ops); +} + +static void __exit tm6000_dvb_unregister(void) +{ + tm6000_unregister_extension(&dvb_ops); +} + +module_init(tm6000_dvb_register); +module_exit(tm6000_dvb_unregister); diff --git a/drivers/media/video/tm6000/tm6000-i2c.c b/drivers/media/video/tm6000/tm6000-i2c.c new file mode 100644 index 0000000..0290bbf --- /dev/null +++ b/drivers/media/video/tm6000/tm6000-i2c.c @@ -0,0 +1,340 @@ +/* + * tm6000-i2c.c - driver for TM5600/TM6000/TM6010 USB video capture devices + * + * Copyright (C) 2006-2007 Mauro Carvalho Chehab + * + * Copyright (C) 2007 Michel Ludwig + * - Fix SMBus Read Byte command + * + * 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 version 2 + * + * 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 +#include +#include +#include + +#include "tm6000.h" +#include "tm6000-regs.h" +#include +#include +#include "tuner-xc2028.h" + + +/* ----------------------------------------------------------- */ + +static unsigned int i2c_debug; +module_param(i2c_debug, int, 0644); +MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); + +#define i2c_dprintk(lvl, fmt, args...) if (i2c_debug >= lvl) do { \ + printk(KERN_DEBUG "%s at %s: " fmt, \ + dev->name, __func__, ##args); } while (0) + +static int tm6000_i2c_send_regs(struct tm6000_core *dev, unsigned char addr, + __u8 reg, char *buf, int len) +{ + int rc; + unsigned int tsleep; + unsigned int i2c_packet_limit = 16; + + if (dev->dev_type == TM6010) + i2c_packet_limit = 64; + + if (!buf) + return -1; + + if (len < 1 || len > i2c_packet_limit) { + printk(KERN_ERR "Incorrect length of i2c packet = %d, limit set to %d\n", + len, i2c_packet_limit); + return -1; + } + + /* capture mutex */ + rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, REQ_16_SET_GET_I2C_WR1_RDN, + addr | reg << 8, 0, buf, len); + + if (rc < 0) { + /* release mutex */ + return rc; + } + + /* Calculate delay time, 14000us for 64 bytes */ + tsleep = ((len * 200) + 200 + 1000) / 1000; + msleep(tsleep); + + /* release mutex */ + return rc; +} + +/* Generic read - doesn't work fine with 16bit registers */ +static int tm6000_i2c_recv_regs(struct tm6000_core *dev, unsigned char addr, + __u8 reg, char *buf, int len) +{ + int rc; + u8 b[2]; + unsigned int i2c_packet_limit = 16; + + if (dev->dev_type == TM6010) + i2c_packet_limit = 64; + + if (!buf) + return -1; + + if (len < 1 || len > i2c_packet_limit) { + printk(KERN_ERR "Incorrect length of i2c packet = %d, limit set to %d\n", + len, i2c_packet_limit); + return -1; + } + + /* capture mutex */ + if ((dev->caps.has_zl10353) && (dev->demod_addr << 1 == addr) && (reg % 2 == 0)) { + /* + * Workaround an I2C bug when reading from zl10353 + */ + reg -= 1; + len += 1; + + rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + REQ_16_SET_GET_I2C_WR1_RDN, addr | reg << 8, 0, b, len); + + *buf = b[1]; + } else { + rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + REQ_16_SET_GET_I2C_WR1_RDN, addr | reg << 8, 0, buf, len); + } + + /* release mutex */ + return rc; +} + +/* + * read from a 16bit register + * for example xc2028, xc3028 or xc3028L + */ +static int tm6000_i2c_recv_regs16(struct tm6000_core *dev, unsigned char addr, + __u16 reg, char *buf, int len) +{ + int rc; + unsigned char ureg; + + if (!buf || len != 2) + return -1; + + /* capture mutex */ + if (dev->dev_type == TM6010) { + ureg = reg & 0xFF; + rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, REQ_16_SET_GET_I2C_WR1_RDN, + addr | (reg & 0xFF00), 0, &ureg, 1); + + if (rc < 0) { + /* release mutex */ + return rc; + } + + msleep(1400 / 1000); + rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, REQ_35_AFTEK_TUNER_READ, + reg, 0, buf, len); + } else { + rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, REQ_14_SET_GET_I2C_WR2_RDN, + addr, reg, buf, len); + } + + /* release mutex */ + return rc; +} + +static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg msgs[], int num) +{ + struct tm6000_core *dev = i2c_adap->algo_data; + int addr, rc, i, byte; + + if (num <= 0) + return 0; + for (i = 0; i < num; i++) { + addr = (msgs[i].addr << 1) & 0xff; + i2c_dprintk(2, "%s %s addr=0x%x len=%d:", + (msgs[i].flags & I2C_M_RD) ? "read" : "write", + i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len); + if (msgs[i].flags & I2C_M_RD) { + /* read request without preceding register selection */ + /* + * The TM6000 only supports a read transaction + * immediately after a 1 or 2 byte write to select + * a register. We cannot fulfil this request. + */ + i2c_dprintk(2, " read without preceding write not" + " supported"); + rc = -EOPNOTSUPP; + goto err; + } else if (i + 1 < num && msgs[i].len <= 2 && + (msgs[i + 1].flags & I2C_M_RD) && + msgs[i].addr == msgs[i + 1].addr) { + /* 1 or 2 byte write followed by a read */ + if (i2c_debug >= 2) + for (byte = 0; byte < msgs[i].len; byte++) + printk(KERN_CONT " %02x", msgs[i].buf[byte]); + i2c_dprintk(2, "; joined to read %s len=%d:", + i == num - 2 ? "stop" : "nonstop", + msgs[i + 1].len); + + if (msgs[i].len == 2) { + rc = tm6000_i2c_recv_regs16(dev, addr, + msgs[i].buf[0] << 8 | msgs[i].buf[1], + msgs[i + 1].buf, msgs[i + 1].len); + } else { + rc = tm6000_i2c_recv_regs(dev, addr, msgs[i].buf[0], + msgs[i + 1].buf, msgs[i + 1].len); + } + + i++; + + if (addr == dev->tuner_addr << 1) { + tm6000_set_reg(dev, REQ_50_SET_START, 0, 0); + tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0); + } + if (i2c_debug >= 2) + for (byte = 0; byte < msgs[i].len; byte++) + printk(KERN_CONT " %02x", msgs[i].buf[byte]); + } else { + /* write bytes */ + if (i2c_debug >= 2) + for (byte = 0; byte < msgs[i].len; byte++) + printk(KERN_CONT " %02x", msgs[i].buf[byte]); + rc = tm6000_i2c_send_regs(dev, addr, msgs[i].buf[0], + msgs[i].buf + 1, msgs[i].len - 1); + } + if (i2c_debug >= 2) + printk(KERN_CONT "\n"); + if (rc < 0) + goto err; + } + + return num; +err: + i2c_dprintk(2, " ERROR: %i\n", rc); + return rc; +} + +static int tm6000_i2c_eeprom(struct tm6000_core *dev) +{ + int i, rc; + unsigned char *p = dev->eedata; + unsigned char bytes[17]; + + dev->i2c_client.addr = 0xa0 >> 1; + dev->eedata_size = 0; + + bytes[16] = '\0'; + for (i = 0; i < sizeof(dev->eedata); ) { + *p = i; + rc = tm6000_i2c_recv_regs(dev, 0xa0, i, p, 1); + if (rc < 1) { + if (p == dev->eedata) + goto noeeprom; + else { + printk(KERN_WARNING + "%s: i2c eeprom read error (err=%d)\n", + dev->name, rc); + } + return -EINVAL; + } + dev->eedata_size++; + p++; + if (0 == (i % 16)) + printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i); + printk(KERN_CONT " %02x", dev->eedata[i]); + if ((dev->eedata[i] >= ' ') && (dev->eedata[i] <= 'z')) + bytes[i%16] = dev->eedata[i]; + else + bytes[i%16] = '.'; + + i++; + + if (0 == (i % 16)) { + bytes[16] = '\0'; + printk(KERN_CONT " %s\n", bytes); + } + } + if (0 != (i%16)) { + bytes[i%16] = '\0'; + for (i %= 16; i < 16; i++) + printk(KERN_CONT " "); + printk(KERN_CONT " %s\n", bytes); + } + + return 0; + +noeeprom: + printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n", + dev->name, rc); + return -EINVAL; +} + +/* ----------------------------------------------------------- */ + +/* + * functionality() + */ +static u32 functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm tm6000_algo = { + .master_xfer = tm6000_i2c_xfer, + .functionality = functionality, +}; + +/* ----------------------------------------------------------- */ + +/* + * tm6000_i2c_register() + * register i2c bus + */ +int tm6000_i2c_register(struct tm6000_core *dev) +{ + int rc; + + dev->i2c_adap.owner = THIS_MODULE; + dev->i2c_adap.algo = &tm6000_algo; + dev->i2c_adap.dev.parent = &dev->udev->dev; + strlcpy(dev->i2c_adap.name, dev->name, sizeof(dev->i2c_adap.name)); + dev->i2c_adap.algo_data = dev; + i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev); + rc = i2c_add_adapter(&dev->i2c_adap); + if (rc) + return rc; + + dev->i2c_client.adapter = &dev->i2c_adap; + strlcpy(dev->i2c_client.name, "tm6000 internal", I2C_NAME_SIZE); + tm6000_i2c_eeprom(dev); + + return 0; +} + +/* + * tm6000_i2c_unregister() + * unregister i2c_bus + */ +int tm6000_i2c_unregister(struct tm6000_core *dev) +{ + i2c_del_adapter(&dev->i2c_adap); + return 0; +} diff --git a/drivers/media/video/tm6000/tm6000-input.c b/drivers/media/video/tm6000/tm6000-input.c new file mode 100644 index 0000000..405d127 --- /dev/null +++ b/drivers/media/video/tm6000/tm6000-input.c @@ -0,0 +1,459 @@ +/* + * tm6000-input.c - driver for TM5600/TM6000/TM6010 USB video capture devices + * + * Copyright (C) 2010 Stefan Ringel + * + * 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 version 2 + * + * 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 +#include +#include + +#include +#include + +#include + +#include "tm6000.h" +#include "tm6000-regs.h" + +static unsigned int ir_debug; +module_param(ir_debug, int, 0644); +MODULE_PARM_DESC(ir_debug, "enable debug message [IR]"); + +static unsigned int enable_ir = 1; +module_param(enable_ir, int, 0644); +MODULE_PARM_DESC(enable_ir, "enable ir (default is enable)"); + +/* number of 50ms for ON-OFF-ON power led */ +/* show IR activity */ +#define PWLED_OFF 2 + +#undef dprintk + +#define dprintk(fmt, arg...) \ + if (ir_debug) { \ + printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \ + } + +struct tm6000_ir_poll_result { + u16 rc_data; +}; + +struct tm6000_IR { + struct tm6000_core *dev; + struct rc_dev *rc; + char name[32]; + char phys[32]; + + /* poll expernal decoder */ + int polling; + struct delayed_work work; + u8 wait:1; + u8 key:1; + u8 pwled:1; + u8 pwledcnt; + u16 key_addr; + struct urb *int_urb; + u8 *urb_data; + + int (*get_key) (struct tm6000_IR *, struct tm6000_ir_poll_result *); + + /* IR device properties */ + u64 rc_type; +}; + + +void tm6000_ir_wait(struct tm6000_core *dev, u8 state) +{ + struct tm6000_IR *ir = dev->ir; + + if (!dev->ir) + return; + + if (state) + ir->wait = 1; + else + ir->wait = 0; +} + + +static int tm6000_ir_config(struct tm6000_IR *ir) +{ + struct tm6000_core *dev = ir->dev; + u8 buf[10]; + int rc; + + switch (ir->rc_type) { + case RC_TYPE_NEC: + /* Setup IR decoder for NEC standard 12MHz system clock */ + /* IR_LEADER_CNT = 0.9ms */ + tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER1, 0xaa); + tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER0, 0x30); + /* IR_PULSE_CNT = 0.7ms */ + tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT1, 0x20); + tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0xd0); + /* Remote WAKEUP = enable */ + tm6000_set_reg(dev, TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe); + /* IR_WKUP_SEL = Low byte in decoded IR data */ + tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0xff); + /* IR_WKU_ADD code */ + tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_ADD, 0xff); + tm6000_flash_led(dev, 0); + msleep(100); + tm6000_flash_led(dev, 1); + break; + default: + /* hack */ + buf[0] = 0xff; + buf[1] = 0xff; + buf[2] = 0xf2; + buf[3] = 0x2b; + buf[4] = 0x20; + buf[5] = 0x35; + buf[6] = 0x60; + buf[7] = 0x04; + buf[8] = 0xc0; + buf[9] = 0x08; + + rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, REQ_00_SET_IR_VALUE, 0, 0, buf, 0x0a); + msleep(100); + + if (rc < 0) { + printk(KERN_INFO "IR configuration failed"); + return rc; + } + break; + } + + return 0; +} + +static void tm6000_ir_urb_received(struct urb *urb) +{ + struct tm6000_core *dev = urb->context; + struct tm6000_IR *ir = dev->ir; + int rc; + + if (urb->status != 0) + printk(KERN_INFO "not ready\n"); + else if (urb->actual_length > 0) { + memcpy(ir->urb_data, urb->transfer_buffer, urb->actual_length); + + dprintk("data %02x %02x %02x %02x\n", ir->urb_data[0], + ir->urb_data[1], ir->urb_data[2], ir->urb_data[3]); + + ir->key = 1; + } + + rc = usb_submit_urb(urb, GFP_ATOMIC); +} + +static int default_polling_getkey(struct tm6000_IR *ir, + struct tm6000_ir_poll_result *poll_result) +{ + struct tm6000_core *dev = ir->dev; + int rc; + u8 buf[2]; + + if (ir->wait && !&dev->int_in) + return 0; + + if (&dev->int_in) { + switch (ir->rc_type) { + case RC_TYPE_RC5: + poll_result->rc_data = ir->urb_data[0]; + break; + case RC_TYPE_NEC: + if (ir->urb_data[1] == ((ir->key_addr >> 8) & 0xff)) { + poll_result->rc_data = ir->urb_data[0] + | ir->urb_data[1] << 8; + } + break; + default: + poll_result->rc_data = ir->urb_data[0] + | ir->urb_data[1] << 8; + break; + } + } else { + tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0); + msleep(10); + tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 1); + msleep(10); + + if (ir->rc_type == RC_TYPE_RC5) { + rc = tm6000_read_write_usb(dev, USB_DIR_IN | + USB_TYPE_VENDOR | USB_RECIP_DEVICE, + REQ_02_GET_IR_CODE, 0, 0, buf, 1); + + msleep(10); + + dprintk("read data=%02x\n", buf[0]); + if (rc < 0) + return rc; + + poll_result->rc_data = buf[0]; + } else { + rc = tm6000_read_write_usb(dev, USB_DIR_IN | + USB_TYPE_VENDOR | USB_RECIP_DEVICE, + REQ_02_GET_IR_CODE, 0, 0, buf, 2); + + msleep(10); + + dprintk("read data=%04x\n", buf[0] | buf[1] << 8); + if (rc < 0) + return rc; + + poll_result->rc_data = buf[0] | buf[1] << 8; + } + if ((poll_result->rc_data & 0x00ff) != 0xff) + ir->key = 1; + } + return 0; +} + +static void tm6000_ir_handle_key(struct tm6000_IR *ir) +{ + struct tm6000_core *dev = ir->dev; + int result; + struct tm6000_ir_poll_result poll_result; + + /* read the registers containing the IR status */ + result = ir->get_key(ir, &poll_result); + if (result < 0) { + printk(KERN_INFO "ir->get_key() failed %d\n", result); + return; + } + + dprintk("ir->get_key result data=%04x\n", poll_result.rc_data); + + if (ir->pwled) { + if (ir->pwledcnt >= PWLED_OFF) { + ir->pwled = 0; + ir->pwledcnt = 0; + tm6000_flash_led(dev, 1); + } else + ir->pwledcnt += 1; + } + + if (ir->key) { + rc_keydown(ir->rc, poll_result.rc_data, 0); + ir->key = 0; + ir->pwled = 1; + ir->pwledcnt = 0; + tm6000_flash_led(dev, 0); + } + return; +} + +static void tm6000_ir_work(struct work_struct *work) +{ + struct tm6000_IR *ir = container_of(work, struct tm6000_IR, work.work); + + tm6000_ir_handle_key(ir); + schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling)); +} + +static int tm6000_ir_start(struct rc_dev *rc) +{ + struct tm6000_IR *ir = rc->priv; + + INIT_DELAYED_WORK(&ir->work, tm6000_ir_work); + schedule_delayed_work(&ir->work, 0); + + return 0; +} + +static void tm6000_ir_stop(struct rc_dev *rc) +{ + struct tm6000_IR *ir = rc->priv; + + cancel_delayed_work_sync(&ir->work); +} + +static int tm6000_ir_change_protocol(struct rc_dev *rc, u64 rc_type) +{ + struct tm6000_IR *ir = rc->priv; + + if (!ir) + return 0; + + if ((rc->rc_map.scan) && (rc_type == RC_TYPE_NEC)) + ir->key_addr = ((rc->rc_map.scan[0].scancode >> 8) & 0xffff); + + ir->get_key = default_polling_getkey; + ir->rc_type = rc_type; + + tm6000_ir_config(ir); + /* TODO */ + return 0; +} + +int tm6000_ir_int_start(struct tm6000_core *dev) +{ + struct tm6000_IR *ir = dev->ir; + int pipe, size; + int err = -ENOMEM; + + + if (!ir) + return -ENODEV; + + ir->int_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!ir->int_urb) + return -ENOMEM; + + pipe = usb_rcvintpipe(dev->udev, + dev->int_in.endp->desc.bEndpointAddress + & USB_ENDPOINT_NUMBER_MASK); + + size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe)); + dprintk("IR max size: %d\n", size); + + ir->int_urb->transfer_buffer = kzalloc(size, GFP_KERNEL); + if (ir->int_urb->transfer_buffer == NULL) { + usb_free_urb(ir->int_urb); + return err; + } + dprintk("int interval: %d\n", dev->int_in.endp->desc.bInterval); + usb_fill_int_urb(ir->int_urb, dev->udev, pipe, + ir->int_urb->transfer_buffer, size, + tm6000_ir_urb_received, dev, + dev->int_in.endp->desc.bInterval); + err = usb_submit_urb(ir->int_urb, GFP_KERNEL); + if (err) { + kfree(ir->int_urb->transfer_buffer); + usb_free_urb(ir->int_urb); + return err; + } + ir->urb_data = kzalloc(size, GFP_KERNEL); + + return 0; +} + +void tm6000_ir_int_stop(struct tm6000_core *dev) +{ + struct tm6000_IR *ir = dev->ir; + + if (!ir) + return; + + usb_kill_urb(ir->int_urb); + kfree(ir->int_urb->transfer_buffer); + usb_free_urb(ir->int_urb); + ir->int_urb = NULL; + kfree(ir->urb_data); + ir->urb_data = NULL; +} + +int tm6000_ir_init(struct tm6000_core *dev) +{ + struct tm6000_IR *ir; + struct rc_dev *rc; + int err = -ENOMEM; + + if (!enable_ir) + return -ENODEV; + + if (!dev->caps.has_remote) + return 0; + + if (!dev->ir_codes) + return 0; + + ir = kzalloc(sizeof(*ir), GFP_KERNEL); + rc = rc_allocate_device(); + if (!ir || !rc) + goto out; + + /* record handles to ourself */ + ir->dev = dev; + dev->ir = ir; + ir->rc = rc; + + /* input einrichten */ + rc->allowed_protos = RC_TYPE_RC5 | RC_TYPE_NEC; + rc->priv = ir; + rc->change_protocol = tm6000_ir_change_protocol; + rc->open = tm6000_ir_start; + rc->close = tm6000_ir_stop; + rc->driver_type = RC_DRIVER_SCANCODE; + + ir->polling = 50; + ir->pwled = 0; + ir->pwledcnt = 0; + + + snprintf(ir->name, sizeof(ir->name), "tm5600/60x0 IR (%s)", + dev->name); + + usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); + strlcat(ir->phys, "/input0", sizeof(ir->phys)); + + tm6000_ir_change_protocol(rc, RC_TYPE_UNKNOWN); + + rc->input_name = ir->name; + rc->input_phys = ir->phys; + rc->input_id.bustype = BUS_USB; + rc->input_id.version = 1; + rc->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); + rc->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct); + rc->map_name = dev->ir_codes; + rc->driver_name = "tm6000"; + rc->dev.parent = &dev->udev->dev; + + if (&dev->int_in) { + dprintk("IR over int\n"); + + err = tm6000_ir_int_start(dev); + + if (err) + goto out; + } + + /* ir register */ + err = rc_register_device(rc); + if (err) + goto out; + + return 0; + +out: + dev->ir = NULL; + rc_free_device(rc); + kfree(ir); + return err; +} + +int tm6000_ir_fini(struct tm6000_core *dev) +{ + struct tm6000_IR *ir = dev->ir; + + /* skip detach on non attached board */ + + if (!ir) + return 0; + + rc_unregister_device(ir->rc); + + if (ir->int_urb) + tm6000_ir_int_stop(dev); + + kfree(ir); + dev->ir = NULL; + + return 0; +} diff --git a/drivers/media/video/tm6000/tm6000-regs.h b/drivers/media/video/tm6000/tm6000-regs.h new file mode 100644 index 0000000..7f491b6 --- /dev/null +++ b/drivers/media/video/tm6000/tm6000-regs.h @@ -0,0 +1,600 @@ +/* + * tm6000-regs.h - driver for TM5600/TM6000/TM6010 USB video capture devices + * + * Copyright (C) 2006-2007 Mauro Carvalho Chehab + * + * 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 version 2 + * + * 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. + */ + +/* + * Define TV Master TM5600/TM6000/TM6010 Request codes + */ +#define REQ_00_SET_IR_VALUE 0 +#define REQ_01_SET_WAKEUP_IRCODE 1 +#define REQ_02_GET_IR_CODE 2 +#define REQ_03_SET_GET_MCU_PIN 3 +#define REQ_04_EN_DISABLE_MCU_INT 4 +#define REQ_05_SET_GET_USBREG 5 + /* Write: RegNum, Value, 0 */ + /* Read : RegNum, Value, 1, RegStatus */ +#define REQ_06_SET_GET_USBREG_BIT 6 +#define REQ_07_SET_GET_AVREG 7 + /* Write: RegNum, Value, 0 */ + /* Read : RegNum, Value, 1, RegStatus */ +#define REQ_08_SET_GET_AVREG_BIT 8 +#define REQ_09_SET_GET_TUNER_FQ 9 +#define REQ_10_SET_TUNER_SYSTEM 10 +#define REQ_11_SET_EEPROM_ADDR 11 +#define REQ_12_SET_GET_EEPROMBYTE 12 +#define REQ_13_GET_EEPROM_SEQREAD 13 +#define REQ_14_SET_GET_I2C_WR2_RDN 14 +#define REQ_15_SET_GET_I2CBYTE 15 + /* Write: Subaddr, Slave Addr, value, 0 */ + /* Read : Subaddr, Slave Addr, value, 1 */ +#define REQ_16_SET_GET_I2C_WR1_RDN 16 + /* Subaddr, Slave Addr, 0, length */ +#define REQ_17_SET_GET_I2CFP 17 + /* Write: Slave Addr, register, value */ + /* Read : Slave Addr, register, 2, data */ +#define REQ_20_DATA_TRANSFER 20 +#define REQ_30_I2C_WRITE 30 +#define REQ_31_I2C_READ 31 +#define REQ_35_AFTEK_TUNER_READ 35 +#define REQ_40_GET_VERSION 40 +#define REQ_50_SET_START 50 +#define REQ_51_SET_STOP 51 +#define REQ_52_TRANSMIT_DATA 52 +#define REQ_53_SPI_INITIAL 53 +#define REQ_54_SPI_SETSTART 54 +#define REQ_55_SPI_INOUTDATA 55 +#define REQ_56_SPI_SETSTOP 56 + +/* + * Define TV Master TM5600/TM6000/TM6010 GPIO lines + */ + +#define TM6000_GPIO_CLK 0x101 +#define TM6000_GPIO_DATA 0x100 + +#define TM6000_GPIO_1 0x102 +#define TM6000_GPIO_2 0x103 +#define TM6000_GPIO_3 0x104 +#define TM6000_GPIO_4 0x300 +#define TM6000_GPIO_5 0x301 +#define TM6000_GPIO_6 0x304 +#define TM6000_GPIO_7 0x305 + +/* tm6010 defines GPIO with different values */ +#define TM6010_GPIO_0 0x0102 +#define TM6010_GPIO_1 0x0103 +#define TM6010_GPIO_2 0x0104 +#define TM6010_GPIO_3 0x0105 +#define TM6010_GPIO_4 0x0106 +#define TM6010_GPIO_5 0x0107 +#define TM6010_GPIO_6 0x0300 +#define TM6010_GPIO_7 0x0301 +#define TM6010_GPIO_9 0x0305 +/* + * Define TV Master TM5600/TM6000/TM6010 URB message codes and length + */ + +enum { + TM6000_URB_MSG_VIDEO = 1, + TM6000_URB_MSG_AUDIO, + TM6000_URB_MSG_VBI, + TM6000_URB_MSG_PTS, + TM6000_URB_MSG_ERR, +}; + +/* Define specific TM6000 Video decoder registers */ +#define TM6000_REQ07_RD8_TEST_SEL 0x07, 0xd8 +#define TM6000_REQ07_RD9_A_SIM_SEL 0x07, 0xd9 +#define TM6000_REQ07_RDA_CLK_SEL 0x07, 0xda +#define TM6000_REQ07_RDB_OUT_SEL 0x07, 0xdb +#define TM6000_REQ07_RDC_NSEL_I2S 0x07, 0xdc +#define TM6000_REQ07_RDD_GPIO2_MDRV 0x07, 0xdd +#define TM6000_REQ07_RDE_GPIO1_MDRV 0x07, 0xde +#define TM6000_REQ07_RDF_PWDOWN_ACLK 0x07, 0xdf +#define TM6000_REQ07_RE0_VADC_REF_CTL 0x07, 0xe0 +#define TM6000_REQ07_RE1_VADC_DACLIMP 0x07, 0xe1 +#define TM6000_REQ07_RE2_VADC_STATUS_CTL 0x07, 0xe2 +#define TM6000_REQ07_RE3_VADC_INP_LPF_SEL1 0x07, 0xe3 +#define TM6000_REQ07_RE4_VADC_TARGET1 0x07, 0xe4 +#define TM6000_REQ07_RE5_VADC_INP_LPF_SEL2 0x07, 0xe5 +#define TM6000_REQ07_RE6_VADC_TARGET2 0x07, 0xe6 +#define TM6000_REQ07_RE7_VADC_AGAIN_CTL 0x07, 0xe7 +#define TM6000_REQ07_RE8_VADC_PWDOWN_CTL 0x07, 0xe8 +#define TM6000_REQ07_RE9_VADC_INPUT_CTL1 0x07, 0xe9 +#define TM6000_REQ07_REA_VADC_INPUT_CTL2 0x07, 0xea +#define TM6000_REQ07_REB_VADC_AADC_MODE 0x07, 0xeb +#define TM6000_REQ07_REC_VADC_AADC_LVOL 0x07, 0xec +#define TM6000_REQ07_RED_VADC_AADC_RVOL 0x07, 0xed +#define TM6000_REQ07_REE_VADC_CTRL_SEL_CONTROL 0x07, 0xee +#define TM6000_REQ07_REF_VADC_GAIN_MAP_CTL 0x07, 0xef +#define TM6000_REQ07_RFD_BIST_ERR_VST_LOW 0x07, 0xfd +#define TM6000_REQ07_RFE_BIST_ERR_VST_HIGH 0x07, 0xfe + +/* Define TM6000/TM6010 Video decoder registers */ +#define TM6010_REQ07_R00_VIDEO_CONTROL0 0x07, 0x00 +#define TM6010_REQ07_R01_VIDEO_CONTROL1 0x07, 0x01 +#define TM6010_REQ07_R02_VIDEO_CONTROL2 0x07, 0x02 +#define TM6010_REQ07_R03_YC_SEP_CONTROL 0x07, 0x03 +#define TM6010_REQ07_R04_LUMA_HAGC_CONTROL 0x07, 0x04 +#define TM6010_REQ07_R05_NOISE_THRESHOLD 0x07, 0x05 +#define TM6010_REQ07_R06_AGC_GATE_THRESHOLD 0x07, 0x06 +#define TM6010_REQ07_R07_OUTPUT_CONTROL 0x07, 0x07 +#define TM6010_REQ07_R08_LUMA_CONTRAST_ADJ 0x07, 0x08 +#define TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ 0x07, 0x09 +#define TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ 0x07, 0x0a +#define TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ 0x07, 0x0b +#define TM6010_REQ07_R0C_CHROMA_AGC_CONTROL 0x07, 0x0c +#define TM6010_REQ07_R0D_CHROMA_KILL_LEVEL 0x07, 0x0d +#define TM6010_REQ07_R0F_CHROMA_AUTO_POSITION 0x07, 0x0f +#define TM6010_REQ07_R10_AGC_PEAK_NOMINAL 0x07, 0x10 +#define TM6010_REQ07_R11_AGC_PEAK_CONTROL 0x07, 0x11 +#define TM6010_REQ07_R12_AGC_GATE_STARTH 0x07, 0x12 +#define TM6010_REQ07_R13_AGC_GATE_STARTL 0x07, 0x13 +#define TM6010_REQ07_R14_AGC_GATE_WIDTH 0x07, 0x14 +#define TM6010_REQ07_R15_AGC_BP_DELAY 0x07, 0x15 +#define TM6010_REQ07_R16_LOCK_COUNT 0x07, 0x16 +#define TM6010_REQ07_R17_HLOOP_MAXSTATE 0x07, 0x17 +#define TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3 0x07, 0x18 +#define TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2 0x07, 0x19 +#define TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1 0x07, 0x1a +#define TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0 0x07, 0x1b +#define TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3 0x07, 0x1c +#define TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2 0x07, 0x1d +#define TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1 0x07, 0x1e +#define TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0 0x07, 0x1f +#define TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME 0x07, 0x20 +#define TM6010_REQ07_R21_HSYNC_PHASE_OFFSET 0x07, 0x21 +#define TM6010_REQ07_R22_HSYNC_PLL_START_TIME 0x07, 0x22 +#define TM6010_REQ07_R23_HSYNC_PLL_END_TIME 0x07, 0x23 +#define TM6010_REQ07_R24_HSYNC_TIP_START_TIME 0x07, 0x24 +#define TM6010_REQ07_R25_HSYNC_TIP_END_TIME 0x07, 0x25 +#define TM6010_REQ07_R26_HSYNC_RISING_EDGE_START 0x07, 0x26 +#define TM6010_REQ07_R27_HSYNC_RISING_EDGE_END 0x07, 0x27 +#define TM6010_REQ07_R28_BACKPORCH_START 0x07, 0x28 +#define TM6010_REQ07_R29_BACKPORCH_END 0x07, 0x29 +#define TM6010_REQ07_R2A_HSYNC_FILTER_START 0x07, 0x2a +#define TM6010_REQ07_R2B_HSYNC_FILTER_END 0x07, 0x2b +#define TM6010_REQ07_R2C_CHROMA_BURST_START 0x07, 0x2c +#define TM6010_REQ07_R2D_CHROMA_BURST_END 0x07, 0x2d +#define TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART 0x07, 0x2e +#define TM6010_REQ07_R2F_ACTIVE_VIDEO_HWIDTH 0x07, 0x2f +#define TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART 0x07, 0x30 +#define TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT 0x07, 0x31 +#define TM6010_REQ07_R32_VSYNC_HLOCK_MIN 0x07, 0x32 +#define TM6010_REQ07_R33_VSYNC_HLOCK_MAX 0x07, 0x33 +#define TM6010_REQ07_R34_VSYNC_AGC_MIN 0x07, 0x34 +#define TM6010_REQ07_R35_VSYNC_AGC_MAX 0x07, 0x35 +#define TM6010_REQ07_R36_VSYNC_VBI_MIN 0x07, 0x36 +#define TM6010_REQ07_R37_VSYNC_VBI_MAX 0x07, 0x37 +#define TM6010_REQ07_R38_VSYNC_THRESHOLD 0x07, 0x38 +#define TM6010_REQ07_R39_VSYNC_TIME_CONSTANT 0x07, 0x39 +#define TM6010_REQ07_R3A_STATUS1 0x07, 0x3a +#define TM6010_REQ07_R3B_STATUS2 0x07, 0x3b +#define TM6010_REQ07_R3C_STATUS3 0x07, 0x3c +#define TM6010_REQ07_R3F_RESET 0x07, 0x3f +#define TM6010_REQ07_R40_TELETEXT_VBI_CODE0 0x07, 0x40 +#define TM6010_REQ07_R41_TELETEXT_VBI_CODE1 0x07, 0x41 +#define TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL 0x07, 0x42 +#define TM6010_REQ07_R43_VBI_DATA_TYPE_LINE7 0x07, 0x43 +#define TM6010_REQ07_R44_VBI_DATA_TYPE_LINE8 0x07, 0x44 +#define TM6010_REQ07_R45_VBI_DATA_TYPE_LINE9 0x07, 0x45 +#define TM6010_REQ07_R46_VBI_DATA_TYPE_LINE10 0x07, 0x46 +#define TM6010_REQ07_R47_VBI_DATA_TYPE_LINE11 0x07, 0x47 +#define TM6010_REQ07_R48_VBI_DATA_TYPE_LINE12 0x07, 0x48 +#define TM6010_REQ07_R49_VBI_DATA_TYPE_LINE13 0x07, 0x49 +#define TM6010_REQ07_R4A_VBI_DATA_TYPE_LINE14 0x07, 0x4a +#define TM6010_REQ07_R4B_VBI_DATA_TYPE_LINE15 0x07, 0x4b +#define TM6010_REQ07_R4C_VBI_DATA_TYPE_LINE16 0x07, 0x4c +#define TM6010_REQ07_R4D_VBI_DATA_TYPE_LINE17 0x07, 0x4d +#define TM6010_REQ07_R4E_VBI_DATA_TYPE_LINE18 0x07, 0x4e +#define TM6010_REQ07_R4F_VBI_DATA_TYPE_LINE19 0x07, 0x4f +#define TM6010_REQ07_R50_VBI_DATA_TYPE_LINE20 0x07, 0x50 +#define TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21 0x07, 0x51 +#define TM6010_REQ07_R52_VBI_DATA_TYPE_LINE22 0x07, 0x52 +#define TM6010_REQ07_R53_VBI_DATA_TYPE_LINE23 0x07, 0x53 +#define TM6010_REQ07_R54_VBI_DATA_TYPE_RLINES 0x07, 0x54 +#define TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN 0x07, 0x55 +#define TM6010_REQ07_R56_VBI_LOOP_FILTER_I_GAIN 0x07, 0x56 +#define TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN 0x07, 0x57 +#define TM6010_REQ07_R58_VBI_CAPTION_DTO1 0x07, 0x58 +#define TM6010_REQ07_R59_VBI_CAPTION_DTO0 0x07, 0x59 +#define TM6010_REQ07_R5A_VBI_TELETEXT_DTO1 0x07, 0x5a +#define TM6010_REQ07_R5B_VBI_TELETEXT_DTO0 0x07, 0x5b +#define TM6010_REQ07_R5C_VBI_WSS625_DTO1 0x07, 0x5c +#define TM6010_REQ07_R5D_VBI_WSS625_DTO0 0x07, 0x5d +#define TM6010_REQ07_R5E_VBI_CAPTION_FRAME_START 0x07, 0x5e +#define TM6010_REQ07_R5F_VBI_WSS625_FRAME_START 0x07, 0x5f +#define TM6010_REQ07_R60_TELETEXT_FRAME_START 0x07, 0x60 +#define TM6010_REQ07_R61_VBI_CCDATA1 0x07, 0x61 +#define TM6010_REQ07_R62_VBI_CCDATA2 0x07, 0x62 +#define TM6010_REQ07_R63_VBI_WSS625_DATA1 0x07, 0x63 +#define TM6010_REQ07_R64_VBI_WSS625_DATA2 0x07, 0x64 +#define TM6010_REQ07_R65_VBI_DATA_STATUS 0x07, 0x65 +#define TM6010_REQ07_R66_VBI_CAPTION_START 0x07, 0x66 +#define TM6010_REQ07_R67_VBI_WSS625_START 0x07, 0x67 +#define TM6010_REQ07_R68_VBI_TELETEXT_START 0x07, 0x68 +#define TM6010_REQ07_R70_HSYNC_DTO_INC_STATUS3 0x07, 0x70 +#define TM6010_REQ07_R71_HSYNC_DTO_INC_STATUS2 0x07, 0x71 +#define TM6010_REQ07_R72_HSYNC_DTO_INC_STATUS1 0x07, 0x72 +#define TM6010_REQ07_R73_HSYNC_DTO_INC_STATUS0 0x07, 0x73 +#define TM6010_REQ07_R74_CHROMA_DTO_INC_STATUS3 0x07, 0x74 +#define TM6010_REQ07_R75_CHROMA_DTO_INC_STATUS2 0x07, 0x75 +#define TM6010_REQ07_R76_CHROMA_DTO_INC_STATUS1 0x07, 0x76 +#define TM6010_REQ07_R77_CHROMA_DTO_INC_STATUS0 0x07, 0x77 +#define TM6010_REQ07_R78_AGC_AGAIN_STATUS 0x07, 0x78 +#define TM6010_REQ07_R79_AGC_DGAIN_STATUS 0x07, 0x79 +#define TM6010_REQ07_R7A_CHROMA_MAG_STATUS 0x07, 0x7a +#define TM6010_REQ07_R7B_CHROMA_GAIN_STATUS1 0x07, 0x7b +#define TM6010_REQ07_R7C_CHROMA_GAIN_STATUS0 0x07, 0x7c +#define TM6010_REQ07_R7D_CORDIC_FREQ_STATUS 0x07, 0x7d +#define TM6010_REQ07_R7F_STATUS_NOISE 0x07, 0x7f +#define TM6010_REQ07_R80_COMB_FILTER_TRESHOLD 0x07, 0x80 +#define TM6010_REQ07_R82_COMB_FILTER_CONFIG 0x07, 0x82 +#define TM6010_REQ07_R83_CHROMA_LOCK_CONFIG 0x07, 0x83 +#define TM6010_REQ07_R84_NOISE_NTSC_C 0x07, 0x84 +#define TM6010_REQ07_R85_NOISE_PAL_C 0x07, 0x85 +#define TM6010_REQ07_R86_NOISE_PHASE_C 0x07, 0x86 +#define TM6010_REQ07_R87_NOISE_PHASE_Y 0x07, 0x87 +#define TM6010_REQ07_R8A_CHROMA_LOOPFILTER_STATE 0x07, 0x8a +#define TM6010_REQ07_R8B_CHROMA_HRESAMPLER 0x07, 0x8b +#define TM6010_REQ07_R8D_CPUMP_DELAY_ADJ 0x07, 0x8d +#define TM6010_REQ07_R8E_CPUMP_ADJ 0x07, 0x8e +#define TM6010_REQ07_R8F_CPUMP_DELAY 0x07, 0x8f + +/* Define TM6000/TM6010 Miscellaneous registers */ +#define TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE 0x07, 0xc0 +#define TM6010_REQ07_RC1_TRESHOLD 0x07, 0xc1 +#define TM6010_REQ07_RC2_HSYNC_WIDTH 0x07, 0xc2 +#define TM6010_REQ07_RC3_HSTART1 0x07, 0xc3 +#define TM6010_REQ07_RC4_HSTART0 0x07, 0xc4 +#define TM6010_REQ07_RC5_HEND1 0x07, 0xc5 +#define TM6010_REQ07_RC6_HEND0 0x07, 0xc6 +#define TM6010_REQ07_RC7_VSTART1 0x07, 0xc7 +#define TM6010_REQ07_RC8_VSTART0 0x07, 0xc8 +#define TM6010_REQ07_RC9_VEND1 0x07, 0xc9 +#define TM6010_REQ07_RCA_VEND0 0x07, 0xca +#define TM6010_REQ07_RCB_DELAY 0x07, 0xcb +/* ONLY for TM6010 */ +#define TM6010_REQ07_RCC_ACTIVE_IF 0x07, 0xcc +#define TM6010_REQ07_RCC_ACTIVE_IF_VIDEO_ENABLE (1 << 5) +#define TM6010_REQ07_RCC_ACTIVE_IF_AUDIO_ENABLE (1 << 6) +#define TM6010_REQ07_RD0_USB_PERIPHERY_CONTROL 0x07, 0xd0 +#define TM6010_REQ07_RD1_ADDR_FOR_REQ1 0x07, 0xd1 +#define TM6010_REQ07_RD2_ADDR_FOR_REQ2 0x07, 0xd2 +#define TM6010_REQ07_RD3_ADDR_FOR_REQ3 0x07, 0xd3 +#define TM6010_REQ07_RD4_ADDR_FOR_REQ4 0x07, 0xd4 +#define TM6010_REQ07_RD5_POWERSAVE 0x07, 0xd5 +#define TM6010_REQ07_RD6_ENDP_REQ1_REQ2 0x07, 0xd6 +#define TM6010_REQ07_RD7_ENDP_REQ3_REQ4 0x07, 0xd7 +/* ONLY for TM6010 */ +#define TM6010_REQ07_RD8_IR 0x07, 0xd8 +/* ONLY for TM6010 */ +#define TM6010_REQ07_RD8_IR_BSIZE 0x07, 0xd9 +/* ONLY for TM6010 */ +#define TM6010_REQ07_RD8_IR_WAKEUP_SEL 0x07, 0xda +/* ONLY for TM6010 */ +#define TM6010_REQ07_RD8_IR_WAKEUP_ADD 0x07, 0xdb +/* ONLY for TM6010 */ +#define TM6010_REQ07_RD8_IR_LEADER1 0x07, 0xdc +/* ONLY for TM6010 */ +#define TM6010_REQ07_RD8_IR_LEADER0 0x07, 0xdd +/* ONLY for TM6010 */ +#define TM6010_REQ07_RD8_IR_PULSE_CNT1 0x07, 0xde +/* ONLY for TM6010 */ +#define TM6010_REQ07_RD8_IR_PULSE_CNT0 0x07, 0xdf +/* ONLY for TM6010 */ +#define TM6010_REQ07_RE0_DVIDEO_SOURCE 0x07, 0xe0 +/* ONLY for TM6010 */ +#define TM6010_REQ07_RE0_DVIDEO_SOURCE_IF 0x07, 0xe1 +/* ONLY for TM6010 */ +#define TM6010_REQ07_RE2_OUT_SEL2 0x07, 0xe2 +/* ONLY for TM6010 */ +#define TM6010_REQ07_RE3_OUT_SEL1 0x07, 0xe3 +/* ONLY for TM6010 */ +#define TM6010_REQ07_RE4_OUT_SEL0 0x07, 0xe4 +/* ONLY for TM6010 */ +#define TM6010_REQ07_RE5_REMOTE_WAKEUP 0x07, 0xe5 +/* ONLY for TM6010 */ +#define TM6010_REQ07_RE7_PUB_GPIO 0x07, 0xe7 +/* ONLY for TM6010 */ +#define TM6010_REQ07_RE8_TYPESEL_MOS_I2S 0x07, 0xe8 +/* ONLY for TM6010 */ +#define TM6010_REQ07_RE9_TYPESEL_MOS_TS 0x07, 0xe9 +/* ONLY for TM6010 */ +#define TM6010_REQ07_REA_TYPESEL_MOS_CCIR 0x07, 0xea +/* ONLY for TM6010 */ +#define TM6010_REQ07_RF0_BIST_CRC_RESULT0 0x07, 0xf0 +/* ONLY for TM6010 */ +#define TM6010_REQ07_RF1_BIST_CRC_RESULT1 0x07, 0xf1 +/* ONLY for TM6010 */ +#define TM6010_REQ07_RF2_BIST_CRC_RESULT2 0x07, 0xf2 +/* ONLY for TM6010 */ +#define TM6010_REQ07_RF3_BIST_CRC_RESULT3 0x07, 0xf3 +/* ONLY for TM6010 */ +#define TM6010_REQ07_RF4_BIST_ERR_VST2 0x07, 0xf4 +/* ONLY for TM6010 */ +#define TM6010_REQ07_RF5_BIST_ERR_VST1 0x07, 0xf5 +/* ONLY for TM6010 */ +#define TM6010_REQ07_RF6_BIST_ERR_VST0 0x07, 0xf6 +/* ONLY for TM6010 */ +#define TM6010_REQ07_RF7_BIST 0x07, 0xf7 +/* ONLY for TM6010 */ +#define TM6010_REQ07_RFE_POWER_DOWN 0x07, 0xfe +#define TM6010_REQ07_RFF_SOFT_RESET 0x07, 0xff + +/* Define TM6000/TM6010 USB registers */ +#define TM6010_REQ05_R00_MAIN_CTRL 0x05, 0x00 +#define TM6010_REQ05_R01_DEVADDR 0x05, 0x01 +#define TM6010_REQ05_R02_TEST 0x05, 0x02 +#define TM6010_REQ05_R04_SOFN0 0x05, 0x04 +#define TM6010_REQ05_R05_SOFN1 0x05, 0x05 +#define TM6010_REQ05_R06_SOFTM0 0x05, 0x06 +#define TM6010_REQ05_R07_SOFTM1 0x05, 0x07 +#define TM6010_REQ05_R08_PHY_TEST 0x05, 0x08 +#define TM6010_REQ05_R09_VCTL 0x05, 0x09 +#define TM6010_REQ05_R0A_VSTA 0x05, 0x0a +#define TM6010_REQ05_R0B_CX_CFG 0x05, 0x0b +#define TM6010_REQ05_R0C_ENDP0_REG0 0x05, 0x0c +#define TM6010_REQ05_R10_GMASK 0x05, 0x10 +#define TM6010_REQ05_R11_IMASK0 0x05, 0x11 +#define TM6010_REQ05_R12_IMASK1 0x05, 0x12 +#define TM6010_REQ05_R13_IMASK2 0x05, 0x13 +#define TM6010_REQ05_R14_IMASK3 0x05, 0x14 +#define TM6010_REQ05_R15_IMASK4 0x05, 0x15 +#define TM6010_REQ05_R16_IMASK5 0x05, 0x16 +#define TM6010_REQ05_R17_IMASK6 0x05, 0x17 +#define TM6010_REQ05_R18_IMASK7 0x05, 0x18 +#define TM6010_REQ05_R19_ZEROP0 0x05, 0x19 +#define TM6010_REQ05_R1A_ZEROP1 0x05, 0x1a +#define TM6010_REQ05_R1C_FIFO_EMP0 0x05, 0x1c +#define TM6010_REQ05_R1D_FIFO_EMP1 0x05, 0x1d +#define TM6010_REQ05_R20_IRQ_GROUP 0x05, 0x20 +#define TM6010_REQ05_R21_IRQ_SOURCE0 0x05, 0x21 +#define TM6010_REQ05_R22_IRQ_SOURCE1 0x05, 0x22 +#define TM6010_REQ05_R23_IRQ_SOURCE2 0x05, 0x23 +#define TM6010_REQ05_R24_IRQ_SOURCE3 0x05, 0x24 +#define TM6010_REQ05_R25_IRQ_SOURCE4 0x05, 0x25 +#define TM6010_REQ05_R26_IRQ_SOURCE5 0x05, 0x26 +#define TM6010_REQ05_R27_IRQ_SOURCE6 0x05, 0x27 +#define TM6010_REQ05_R28_IRQ_SOURCE7 0x05, 0x28 +#define TM6010_REQ05_R29_SEQ_ERR0 0x05, 0x29 +#define TM6010_REQ05_R2A_SEQ_ERR1 0x05, 0x2a +#define TM6010_REQ05_R2B_SEQ_ABORT0 0x05, 0x2b +#define TM6010_REQ05_R2C_SEQ_ABORT1 0x05, 0x2c +#define TM6010_REQ05_R2D_TX_ZERO0 0x05, 0x2d +#define TM6010_REQ05_R2E_TX_ZERO1 0x05, 0x2e +#define TM6010_REQ05_R2F_IDLE_CNT 0x05, 0x2f +#define TM6010_REQ05_R30_FNO_P1 0x05, 0x30 +#define TM6010_REQ05_R31_FNO_P2 0x05, 0x31 +#define TM6010_REQ05_R32_FNO_P3 0x05, 0x32 +#define TM6010_REQ05_R33_FNO_P4 0x05, 0x33 +#define TM6010_REQ05_R34_FNO_P5 0x05, 0x34 +#define TM6010_REQ05_R35_FNO_P6 0x05, 0x35 +#define TM6010_REQ05_R36_FNO_P7 0x05, 0x36 +#define TM6010_REQ05_R37_FNO_P8 0x05, 0x37 +#define TM6010_REQ05_R38_FNO_P9 0x05, 0x38 +#define TM6010_REQ05_R30_FNO_P10 0x05, 0x39 +#define TM6010_REQ05_R30_FNO_P11 0x05, 0x3a +#define TM6010_REQ05_R30_FNO_P12 0x05, 0x3b +#define TM6010_REQ05_R30_FNO_P13 0x05, 0x3c +#define TM6010_REQ05_R30_FNO_P14 0x05, 0x3d +#define TM6010_REQ05_R30_FNO_P15 0x05, 0x3e +#define TM6010_REQ05_R40_IN_MAXPS_LOW1 0x05, 0x40 +#define TM6010_REQ05_R41_IN_MAXPS_HIGH1 0x05, 0x41 +#define TM6010_REQ05_R42_IN_MAXPS_LOW2 0x05, 0x42 +#define TM6010_REQ05_R43_IN_MAXPS_HIGH2 0x05, 0x43 +#define TM6010_REQ05_R44_IN_MAXPS_LOW3 0x05, 0x44 +#define TM6010_REQ05_R45_IN_MAXPS_HIGH3 0x05, 0x45 +#define TM6010_REQ05_R46_IN_MAXPS_LOW4 0x05, 0x46 +#define TM6010_REQ05_R47_IN_MAXPS_HIGH4 0x05, 0x47 +#define TM6010_REQ05_R48_IN_MAXPS_LOW5 0x05, 0x48 +#define TM6010_REQ05_R49_IN_MAXPS_HIGH5 0x05, 0x49 +#define TM6010_REQ05_R4A_IN_MAXPS_LOW6 0x05, 0x4a +#define TM6010_REQ05_R4B_IN_MAXPS_HIGH6 0x05, 0x4b +#define TM6010_REQ05_R4C_IN_MAXPS_LOW7 0x05, 0x4c +#define TM6010_REQ05_R4D_IN_MAXPS_HIGH7 0x05, 0x4d +#define TM6010_REQ05_R4E_IN_MAXPS_LOW8 0x05, 0x4e +#define TM6010_REQ05_R4F_IN_MAXPS_HIGH8 0x05, 0x4f +#define TM6010_REQ05_R50_IN_MAXPS_LOW9 0x05, 0x50 +#define TM6010_REQ05_R51_IN_MAXPS_HIGH9 0x05, 0x51 +#define TM6010_REQ05_R40_IN_MAXPS_LOW10 0x05, 0x52 +#define TM6010_REQ05_R41_IN_MAXPS_HIGH10 0x05, 0x53 +#define TM6010_REQ05_R40_IN_MAXPS_LOW11 0x05, 0x54 +#define TM6010_REQ05_R41_IN_MAXPS_HIGH11 0x05, 0x55 +#define TM6010_REQ05_R40_IN_MAXPS_LOW12 0x05, 0x56 +#define TM6010_REQ05_R41_IN_MAXPS_HIGH12 0x05, 0x57 +#define TM6010_REQ05_R40_IN_MAXPS_LOW13 0x05, 0x58 +#define TM6010_REQ05_R41_IN_MAXPS_HIGH13 0x05, 0x59 +#define TM6010_REQ05_R40_IN_MAXPS_LOW14 0x05, 0x5a +#define TM6010_REQ05_R41_IN_MAXPS_HIGH14 0x05, 0x5b +#define TM6010_REQ05_R40_IN_MAXPS_LOW15 0x05, 0x5c +#define TM6010_REQ05_R41_IN_MAXPS_HIGH15 0x05, 0x5d +#define TM6010_REQ05_R60_OUT_MAXPS_LOW1 0x05, 0x60 +#define TM6010_REQ05_R61_OUT_MAXPS_HIGH1 0x05, 0x61 +#define TM6010_REQ05_R62_OUT_MAXPS_LOW2 0x05, 0x62 +#define TM6010_REQ05_R63_OUT_MAXPS_HIGH2 0x05, 0x63 +#define TM6010_REQ05_R64_OUT_MAXPS_LOW3 0x05, 0x64 +#define TM6010_REQ05_R65_OUT_MAXPS_HIGH3 0x05, 0x65 +#define TM6010_REQ05_R66_OUT_MAXPS_LOW4 0x05, 0x66 +#define TM6010_REQ05_R67_OUT_MAXPS_HIGH4 0x05, 0x67 +#define TM6010_REQ05_R68_OUT_MAXPS_LOW5 0x05, 0x68 +#define TM6010_REQ05_R69_OUT_MAXPS_HIGH5 0x05, 0x69 +#define TM6010_REQ05_R6A_OUT_MAXPS_LOW6 0x05, 0x6a +#define TM6010_REQ05_R6B_OUT_MAXPS_HIGH6 0x05, 0x6b +#define TM6010_REQ05_R6C_OUT_MAXPS_LOW7 0x05, 0x6c +#define TM6010_REQ05_R6D_OUT_MAXPS_HIGH7 0x05, 0x6d +#define TM6010_REQ05_R6E_OUT_MAXPS_LOW8 0x05, 0x6e +#define TM6010_REQ05_R6F_OUT_MAXPS_HIGH8 0x05, 0x6f +#define TM6010_REQ05_R70_OUT_MAXPS_LOW9 0x05, 0x70 +#define TM6010_REQ05_R71_OUT_MAXPS_HIGH9 0x05, 0x71 +#define TM6010_REQ05_R60_OUT_MAXPS_LOW10 0x05, 0x72 +#define TM6010_REQ05_R61_OUT_MAXPS_HIGH10 0x05, 0x73 +#define TM6010_REQ05_R60_OUT_MAXPS_LOW11 0x05, 0x74 +#define TM6010_REQ05_R61_OUT_MAXPS_HIGH11 0x05, 0x75 +#define TM6010_REQ05_R60_OUT_MAXPS_LOW12 0x05, 0x76 +#define TM6010_REQ05_R61_OUT_MAXPS_HIGH12 0x05, 0x77 +#define TM6010_REQ05_R60_OUT_MAXPS_LOW13 0x05, 0x78 +#define TM6010_REQ05_R61_OUT_MAXPS_HIGH13 0x05, 0x79 +#define TM6010_REQ05_R60_OUT_MAXPS_LOW14 0x05, 0x7a +#define TM6010_REQ05_R61_OUT_MAXPS_HIGH14 0x05, 0x7b +#define TM6010_REQ05_R60_OUT_MAXPS_LOW15 0x05, 0x7c +#define TM6010_REQ05_R61_OUT_MAXPS_HIGH15 0x05, 0x7d +#define TM6010_REQ05_R80_FIFO0 0x05, 0x80 +#define TM6010_REQ05_R81_FIFO1 0x05, 0x81 +#define TM6010_REQ05_R82_FIFO2 0x05, 0x82 +#define TM6010_REQ05_R83_FIFO3 0x05, 0x83 +#define TM6010_REQ05_R84_FIFO4 0x05, 0x84 +#define TM6010_REQ05_R85_FIFO5 0x05, 0x85 +#define TM6010_REQ05_R86_FIFO6 0x05, 0x86 +#define TM6010_REQ05_R87_FIFO7 0x05, 0x87 +#define TM6010_REQ05_R88_FIFO8 0x05, 0x88 +#define TM6010_REQ05_R89_FIFO9 0x05, 0x89 +#define TM6010_REQ05_R81_FIFO10 0x05, 0x8a +#define TM6010_REQ05_R81_FIFO11 0x05, 0x8b +#define TM6010_REQ05_R81_FIFO12 0x05, 0x8c +#define TM6010_REQ05_R81_FIFO13 0x05, 0x8d +#define TM6010_REQ05_R81_FIFO14 0x05, 0x8e +#define TM6010_REQ05_R81_FIFO15 0x05, 0x8f +#define TM6010_REQ05_R90_CFG_FIFO0 0x05, 0x90 +#define TM6010_REQ05_R91_CFG_FIFO1 0x05, 0x91 +#define TM6010_REQ05_R92_CFG_FIFO2 0x05, 0x92 +#define TM6010_REQ05_R93_CFG_FIFO3 0x05, 0x93 +#define TM6010_REQ05_R94_CFG_FIFO4 0x05, 0x94 +#define TM6010_REQ05_R95_CFG_FIFO5 0x05, 0x95 +#define TM6010_REQ05_R96_CFG_FIFO6 0x05, 0x96 +#define TM6010_REQ05_R97_CFG_FIFO7 0x05, 0x97 +#define TM6010_REQ05_R98_CFG_FIFO8 0x05, 0x98 +#define TM6010_REQ05_R99_CFG_FIFO9 0x05, 0x99 +#define TM6010_REQ05_R91_CFG_FIFO10 0x05, 0x9a +#define TM6010_REQ05_R91_CFG_FIFO11 0x05, 0x9b +#define TM6010_REQ05_R91_CFG_FIFO12 0x05, 0x9c +#define TM6010_REQ05_R91_CFG_FIFO13 0x05, 0x9d +#define TM6010_REQ05_R91_CFG_FIFO14 0x05, 0x9e +#define TM6010_REQ05_R91_CFG_FIFO15 0x05, 0x9f +#define TM6010_REQ05_RA0_CTL_FIFO0 0x05, 0xa0 +#define TM6010_REQ05_RA1_CTL_FIFO1 0x05, 0xa1 +#define TM6010_REQ05_RA2_CTL_FIFO2 0x05, 0xa2 +#define TM6010_REQ05_RA3_CTL_FIFO3 0x05, 0xa3 +#define TM6010_REQ05_RA4_CTL_FIFO4 0x05, 0xa4 +#define TM6010_REQ05_RA5_CTL_FIFO5 0x05, 0xa5 +#define TM6010_REQ05_RA6_CTL_FIFO6 0x05, 0xa6 +#define TM6010_REQ05_RA7_CTL_FIFO7 0x05, 0xa7 +#define TM6010_REQ05_RA8_CTL_FIFO8 0x05, 0xa8 +#define TM6010_REQ05_RA9_CTL_FIFO9 0x05, 0xa9 +#define TM6010_REQ05_RA1_CTL_FIFO10 0x05, 0xaa +#define TM6010_REQ05_RA1_CTL_FIFO11 0x05, 0xab +#define TM6010_REQ05_RA1_CTL_FIFO12 0x05, 0xac +#define TM6010_REQ05_RA1_CTL_FIFO13 0x05, 0xad +#define TM6010_REQ05_RA1_CTL_FIFO14 0x05, 0xae +#define TM6010_REQ05_RA1_CTL_FIFO15 0x05, 0xaf +#define TM6010_REQ05_RB0_BC_LOW_FIFO0 0x05, 0xb0 +#define TM6010_REQ05_RB1_BC_LOW_FIFO1 0x05, 0xb1 +#define TM6010_REQ05_RB2_BC_LOW_FIFO2 0x05, 0xb2 +#define TM6010_REQ05_RB3_BC_LOW_FIFO3 0x05, 0xb3 +#define TM6010_REQ05_RB4_BC_LOW_FIFO4 0x05, 0xb4 +#define TM6010_REQ05_RB5_BC_LOW_FIFO5 0x05, 0xb5 +#define TM6010_REQ05_RB6_BC_LOW_FIFO6 0x05, 0xb6 +#define TM6010_REQ05_RB7_BC_LOW_FIFO7 0x05, 0xb7 +#define TM6010_REQ05_RB8_BC_LOW_FIFO8 0x05, 0xb8 +#define TM6010_REQ05_RB9_BC_LOW_FIFO9 0x05, 0xb9 +#define TM6010_REQ05_RB1_BC_LOW_FIFO10 0x05, 0xba +#define TM6010_REQ05_RB1_BC_LOW_FIFO11 0x05, 0xbb +#define TM6010_REQ05_RB1_BC_LOW_FIFO12 0x05, 0xbc +#define TM6010_REQ05_RB1_BC_LOW_FIFO13 0x05, 0xbd +#define TM6010_REQ05_RB1_BC_LOW_FIFO14 0x05, 0xbe +#define TM6010_REQ05_RB1_BC_LOW_FIFO15 0x05, 0xbf +#define TM6010_REQ05_RC0_DATA_FIFO0 0x05, 0xc0 +#define TM6010_REQ05_RC4_DATA_FIFO1 0x05, 0xc4 +#define TM6010_REQ05_RC8_DATA_FIFO2 0x05, 0xc8 +#define TM6010_REQ05_RCC_DATA_FIFO3 0x05, 0xcc +#define TM6010_REQ05_RD0_DATA_FIFO4 0x05, 0xd0 +#define TM6010_REQ05_RD4_DATA_FIFO5 0x05, 0xd4 +#define TM6010_REQ05_RD8_DATA_FIFO6 0x05, 0xd8 +#define TM6010_REQ05_RDC_DATA_FIFO7 0x05, 0xdc +#define TM6010_REQ05_RE0_DATA_FIFO8 0x05, 0xe0 +#define TM6010_REQ05_RE4_DATA_FIFO9 0x05, 0xe4 +#define TM6010_REQ05_RC4_DATA_FIFO10 0x05, 0xe8 +#define TM6010_REQ05_RC4_DATA_FIFO11 0x05, 0xec +#define TM6010_REQ05_RC4_DATA_FIFO12 0x05, 0xf0 +#define TM6010_REQ05_RC4_DATA_FIFO13 0x05, 0xf4 +#define TM6010_REQ05_RC4_DATA_FIFO14 0x05, 0xf8 +#define TM6010_REQ05_RC4_DATA_FIFO15 0x05, 0xfc + +/* Define TM6010 Audio decoder registers */ +/* This core available only in TM6010 */ +#define TM6010_REQ08_R00_A_VERSION 0x08, 0x00 +#define TM6010_REQ08_R01_A_INIT 0x08, 0x01 +#define TM6010_REQ08_R02_A_FIX_GAIN_CTRL 0x08, 0x02 +#define TM6010_REQ08_R03_A_AUTO_GAIN_CTRL 0x08, 0x03 +#define TM6010_REQ08_R04_A_SIF_AMP_CTRL 0x08, 0x04 +#define TM6010_REQ08_R05_A_STANDARD_MOD 0x08, 0x05 +#define TM6010_REQ08_R06_A_SOUND_MOD 0x08, 0x06 +#define TM6010_REQ08_R07_A_LEFT_VOL 0x08, 0x07 +#define TM6010_REQ08_R08_A_RIGHT_VOL 0x08, 0x08 +#define TM6010_REQ08_R09_A_MAIN_VOL 0x08, 0x09 +#define TM6010_REQ08_R0A_A_I2S_MOD 0x08, 0x0a +#define TM6010_REQ08_R0B_A_ASD_THRES1 0x08, 0x0b +#define TM6010_REQ08_R0C_A_ASD_THRES2 0x08, 0x0c +#define TM6010_REQ08_R0D_A_AMD_THRES 0x08, 0x0d +#define TM6010_REQ08_R0E_A_MONO_THRES1 0x08, 0x0e +#define TM6010_REQ08_R0F_A_MONO_THRES2 0x08, 0x0f +#define TM6010_REQ08_R10_A_MUTE_THRES1 0x08, 0x10 +#define TM6010_REQ08_R11_A_MUTE_THRES2 0x08, 0x11 +#define TM6010_REQ08_R12_A_AGC_U 0x08, 0x12 +#define TM6010_REQ08_R13_A_AGC_ERR_T 0x08, 0x13 +#define TM6010_REQ08_R14_A_AGC_GAIN_INIT 0x08, 0x14 +#define TM6010_REQ08_R15_A_AGC_STEP_THR 0x08, 0x15 +#define TM6010_REQ08_R16_A_AGC_GAIN_MAX 0x08, 0x16 +#define TM6010_REQ08_R17_A_AGC_GAIN_MIN 0x08, 0x17 +#define TM6010_REQ08_R18_A_TR_CTRL 0x08, 0x18 +#define TM6010_REQ08_R19_A_FH_2FH_GAIN 0x08, 0x19 +#define TM6010_REQ08_R1A_A_NICAM_SER_MAX 0x08, 0x1a +#define TM6010_REQ08_R1B_A_NICAM_SER_MIN 0x08, 0x1b +#define TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT 0x08, 0x1e +#define TM6010_REQ08_R1F_A_TEST_INTF_SEL 0x08, 0x1f +#define TM6010_REQ08_R20_A_TEST_PIN_SEL 0x08, 0x20 +#define TM6010_REQ08_R21_A_AGC_ERR 0x08, 0x21 +#define TM6010_REQ08_R22_A_AGC_GAIN 0x08, 0x22 +#define TM6010_REQ08_R23_A_NICAM_INFO 0x08, 0x23 +#define TM6010_REQ08_R24_A_SER 0x08, 0x24 +#define TM6010_REQ08_R25_A_C1_AMP 0x08, 0x25 +#define TM6010_REQ08_R26_A_C2_AMP 0x08, 0x26 +#define TM6010_REQ08_R27_A_NOISE_AMP 0x08, 0x27 +#define TM6010_REQ08_R28_A_AUDIO_MODE_RES 0x08, 0x28 + +/* Define TM6010 Video ADC registers */ +#define TM6010_REQ08_RE0_ADC_REF 0x08, 0xe0 +#define TM6010_REQ08_RE1_DAC_CLMP 0x08, 0xe1 +#define TM6010_REQ08_RE2_POWER_DOWN_CTRL1 0x08, 0xe2 +#define TM6010_REQ08_RE3_ADC_IN1_SEL 0x08, 0xe3 +#define TM6010_REQ08_RE4_ADC_IN2_SEL 0x08, 0xe4 +#define TM6010_REQ08_RE5_GAIN_PARAM 0x08, 0xe5 +#define TM6010_REQ08_RE6_POWER_DOWN_CTRL2 0x08, 0xe6 +#define TM6010_REQ08_RE7_REG_GAIN_Y 0x08, 0xe7 +#define TM6010_REQ08_RE8_REG_GAIN_C 0x08, 0xe8 +#define TM6010_REQ08_RE9_BIAS_CTRL 0x08, 0xe9 +#define TM6010_REQ08_REA_BUFF_DRV_CTRL 0x08, 0xea +#define TM6010_REQ08_REB_SIF_GAIN_CTRL 0x08, 0xeb +#define TM6010_REQ08_REC_REVERSE_YC_CTRL 0x08, 0xec +#define TM6010_REQ08_RED_GAIN_SEL 0x08, 0xed + +/* Define TM6010 Audio ADC registers */ +#define TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG 0x08, 0xf0 +#define TM6010_REQ08_RF1_AADC_POWER_DOWN 0x08, 0xf1 +#define TM6010_REQ08_RF2_LEFT_CHANNEL_VOL 0x08, 0xf2 +#define TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL 0x08, 0xf3 diff --git a/drivers/media/video/tm6000/tm6000-stds.c b/drivers/media/video/tm6000/tm6000-stds.c new file mode 100644 index 0000000..9a4145d --- /dev/null +++ b/drivers/media/video/tm6000/tm6000-stds.c @@ -0,0 +1,659 @@ +/* + * tm6000-stds.c - driver for TM5600/TM6000/TM6010 USB video capture devices + * + * Copyright (C) 2007 Mauro Carvalho Chehab + * + * 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 version 2 + * + * 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 +#include +#include "tm6000.h" +#include "tm6000-regs.h" + +static unsigned int tm6010_a_mode; +module_param(tm6010_a_mode, int, 0644); +MODULE_PARM_DESC(tm6010_a_mode, "set tm6010 sif audio mode"); + +struct tm6000_reg_settings { + unsigned char req; + unsigned char reg; + unsigned char value; +}; + + +struct tm6000_std_settings { + v4l2_std_id id; + struct tm6000_reg_settings *common; +}; + +static struct tm6000_reg_settings composite_pal_m[] = { + { TM6010_REQ07_R3F_RESET, 0x01 }, + { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x04 }, + { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, + { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, + { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 }, + { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, + { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, + { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83 }, + { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a }, + { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe0 }, + { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, + { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, + { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, + { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, + { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, + { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x20 }, + { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 }, + { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c }, + { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, + { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 }, + { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, + { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc }, + { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, + { TM6010_REQ07_R3F_RESET, 0x00 }, + { 0, 0, 0 } +}; + +static struct tm6000_reg_settings composite_pal_nc[] = { + { TM6010_REQ07_R3F_RESET, 0x01 }, + { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x36 }, + { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, + { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, + { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02 }, + { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, + { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, + { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91 }, + { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f }, + { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x0c }, + { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, + { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, + { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, + { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, + { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c }, + { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c }, + { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 }, + { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c }, + { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, + { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 }, + { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, + { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc }, + { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, + { TM6010_REQ07_R3F_RESET, 0x00 }, + { 0, 0, 0 } +}; + +static struct tm6000_reg_settings composite_pal[] = { + { TM6010_REQ07_R3F_RESET, 0x01 }, + { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x32 }, + { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, + { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, + { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02 }, + { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, + { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25 }, + { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5 }, + { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63 }, + { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x50 }, + { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, + { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, + { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, + { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, + { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c }, + { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c }, + { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 }, + { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c }, + { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, + { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 }, + { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, + { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc }, + { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, + { TM6010_REQ07_R3F_RESET, 0x00 }, + { 0, 0, 0 } +}; + +static struct tm6000_reg_settings composite_secam[] = { + { TM6010_REQ07_R3F_RESET, 0x01 }, + { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x38 }, + { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, + { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, + { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02 }, + { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, + { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24 }, + { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92 }, + { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8 }, + { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed }, + { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, + { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, + { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, + { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, + { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c }, + { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c }, + { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 }, + { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c }, + { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18 }, + { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 }, + { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xff }, + { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, + { TM6010_REQ07_R3F_RESET, 0x00 }, + { 0, 0, 0 } +}; + +static struct tm6000_reg_settings composite_ntsc[] = { + { TM6010_REQ07_R3F_RESET, 0x01 }, + { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 }, + { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f }, + { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, + { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 }, + { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, + { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, + { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b }, + { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 }, + { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 }, + { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, + { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, + { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, + { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, + { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, + { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 }, + { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 }, + { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c }, + { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, + { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 }, + { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, + { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdd }, + { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, + { TM6010_REQ07_R3F_RESET, 0x00 }, + { 0, 0, 0 } +}; + +static struct tm6000_std_settings composite_stds[] = { + { .id = V4L2_STD_PAL_M, .common = composite_pal_m, }, + { .id = V4L2_STD_PAL_Nc, .common = composite_pal_nc, }, + { .id = V4L2_STD_PAL, .common = composite_pal, }, + { .id = V4L2_STD_SECAM, .common = composite_secam, }, + { .id = V4L2_STD_NTSC, .common = composite_ntsc, }, +}; + +static struct tm6000_reg_settings svideo_pal_m[] = { + { TM6010_REQ07_R3F_RESET, 0x01 }, + { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x05 }, + { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, + { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, + { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04 }, + { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, + { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, + { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83 }, + { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a }, + { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe0 }, + { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, + { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, + { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, + { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, + { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, + { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 }, + { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 }, + { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c }, + { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, + { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 }, + { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, + { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc }, + { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, + { TM6010_REQ07_R3F_RESET, 0x00 }, + { 0, 0, 0 } +}; + +static struct tm6000_reg_settings svideo_pal_nc[] = { + { TM6010_REQ07_R3F_RESET, 0x01 }, + { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x37 }, + { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, + { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, + { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04 }, + { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, + { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, + { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91 }, + { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f }, + { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x0c }, + { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, + { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, + { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, + { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, + { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, + { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 }, + { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 }, + { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c }, + { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, + { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 }, + { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, + { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc }, + { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, + { TM6010_REQ07_R3F_RESET, 0x00 }, + { 0, 0, 0 } +}; + +static struct tm6000_reg_settings svideo_pal[] = { + { TM6010_REQ07_R3F_RESET, 0x01 }, + { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x33 }, + { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, + { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, + { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04 }, + { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x30 }, + { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25 }, + { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5 }, + { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63 }, + { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x50 }, + { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, + { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, + { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, + { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, + { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c }, + { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2a }, + { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 }, + { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c }, + { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, + { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 }, + { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, + { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc }, + { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, + { TM6010_REQ07_R3F_RESET, 0x00 }, + { 0, 0, 0 } +}; + +static struct tm6000_reg_settings svideo_secam[] = { + { TM6010_REQ07_R3F_RESET, 0x01 }, + { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x39 }, + { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, + { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, + { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03 }, + { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, + { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24 }, + { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92 }, + { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8 }, + { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed }, + { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, + { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, + { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, + { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, + { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c }, + { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2a }, + { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 }, + { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c }, + { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18 }, + { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 }, + { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xff }, + { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, + { TM6010_REQ07_R3F_RESET, 0x00 }, + { 0, 0, 0 } +}; + +static struct tm6000_reg_settings svideo_ntsc[] = { + { TM6010_REQ07_R3F_RESET, 0x01 }, + { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x01 }, + { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f }, + { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, + { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03 }, + { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x30 }, + { TM6010_REQ07_R17_HLOOP_MAXSTATE, 0x8b }, + { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, + { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b }, + { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 }, + { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 }, + { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, + { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, + { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, + { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, + { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, + { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 }, + { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 }, + { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c }, + { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, + { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 }, + { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, + { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdd }, + { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, + { TM6010_REQ07_R3F_RESET, 0x00 }, + { 0, 0, 0 } +}; + +static struct tm6000_std_settings svideo_stds[] = { + { .id = V4L2_STD_PAL_M, .common = svideo_pal_m, }, + { .id = V4L2_STD_PAL_Nc, .common = svideo_pal_nc, }, + { .id = V4L2_STD_PAL, .common = svideo_pal, }, + { .id = V4L2_STD_SECAM, .common = svideo_secam, }, + { .id = V4L2_STD_NTSC, .common = svideo_ntsc, }, +}; + +static int tm6000_set_audio_std(struct tm6000_core *dev) +{ + uint8_t areg_02 = 0x04; /* GC1 Fixed gain 0dB */ + uint8_t areg_05 = 0x01; /* Auto 4.5 = M Japan, Auto 6.5 = DK */ + uint8_t areg_06 = 0x02; /* Auto de-emphasis, mannual channel mode */ + uint8_t nicam_flag = 0; /* No NICAM */ + + if (dev->radio) { + tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00); + tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, 0x04); + tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00); + tm6000_set_reg(dev, TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0x80); + tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, 0x0c); + /* set mono or stereo */ + if (dev->amode == V4L2_TUNER_MODE_MONO) + tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x00); + else if (dev->amode == V4L2_TUNER_MODE_STEREO) + tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x02); + tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x18); + tm6000_set_reg(dev, TM6010_REQ08_R0C_A_ASD_THRES2, 0x0a); + tm6000_set_reg(dev, TM6010_REQ08_R0D_A_AMD_THRES, 0x40); + tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe); + tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13); + tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80); + tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, 0xff); + return 0; + } + + switch (tm6010_a_mode) { + /* auto */ + case 0: + switch (dev->norm) { + case V4L2_STD_NTSC_M_KR: + areg_05 |= 0x00; + break; + case V4L2_STD_NTSC_M_JP: + areg_05 |= 0x40; + break; + case V4L2_STD_NTSC_M: + case V4L2_STD_PAL_M: + case V4L2_STD_PAL_N: + areg_05 |= 0x20; + break; + case V4L2_STD_PAL_Nc: + areg_05 |= 0x60; + break; + case V4L2_STD_SECAM_L: + areg_05 |= 0x00; + break; + case V4L2_STD_DK: + areg_05 |= 0x10; + break; + } + break; + /* A2 */ + case 1: + switch (dev->norm) { + case V4L2_STD_B: + case V4L2_STD_GH: + areg_05 = 0x05; + break; + case V4L2_STD_DK: + areg_05 = 0x09; + break; + } + break; + /* NICAM */ + case 2: + switch (dev->norm) { + case V4L2_STD_B: + case V4L2_STD_GH: + areg_05 = 0x07; + break; + case V4L2_STD_DK: + areg_05 = 0x06; + break; + case V4L2_STD_PAL_I: + areg_05 = 0x08; + break; + case V4L2_STD_SECAM_L: + areg_05 = 0x0a; + areg_02 = 0x02; + break; + } + nicam_flag = 1; + break; + /* other */ + case 3: + switch (dev->norm) { + /* DK3_A2 */ + case V4L2_STD_DK: + areg_05 = 0x0b; + break; + /* Korea */ + case V4L2_STD_NTSC_M_KR: + areg_05 = 0x04; + break; + /* EIAJ */ + case V4L2_STD_NTSC_M_JP: + areg_05 = 0x03; + break; + default: + areg_05 = 0x02; + break; + } + break; + } + + tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00); + tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, areg_02); + tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00); + tm6000_set_reg(dev, TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0xa0); + tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, areg_05); + tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, areg_06); + tm6000_set_reg(dev, TM6010_REQ08_R07_A_LEFT_VOL, 0x00); + tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, 0x00); + tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x08); + tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0x91); + tm6000_set_reg(dev, TM6010_REQ08_R0B_A_ASD_THRES1, 0x20); + tm6000_set_reg(dev, TM6010_REQ08_R0C_A_ASD_THRES2, 0x12); + tm6000_set_reg(dev, TM6010_REQ08_R0D_A_AMD_THRES, 0x20); + tm6000_set_reg(dev, TM6010_REQ08_R0E_A_MONO_THRES1, 0xf0); + tm6000_set_reg(dev, TM6010_REQ08_R0F_A_MONO_THRES2, 0x80); + tm6000_set_reg(dev, TM6010_REQ08_R10_A_MUTE_THRES1, 0xc0); + tm6000_set_reg(dev, TM6010_REQ08_R11_A_MUTE_THRES2, 0x80); + tm6000_set_reg(dev, TM6010_REQ08_R12_A_AGC_U, 0x12); + tm6000_set_reg(dev, TM6010_REQ08_R13_A_AGC_ERR_T, 0xfe); + tm6000_set_reg(dev, TM6010_REQ08_R14_A_AGC_GAIN_INIT, 0x20); + tm6000_set_reg(dev, TM6010_REQ08_R15_A_AGC_STEP_THR, 0x14); + tm6000_set_reg(dev, TM6010_REQ08_R16_A_AGC_GAIN_MAX, 0xfe); + tm6000_set_reg(dev, TM6010_REQ08_R17_A_AGC_GAIN_MIN, 0x01); + tm6000_set_reg(dev, TM6010_REQ08_R18_A_TR_CTRL, 0xa0); + tm6000_set_reg(dev, TM6010_REQ08_R19_A_FH_2FH_GAIN, 0x32); + tm6000_set_reg(dev, TM6010_REQ08_R1A_A_NICAM_SER_MAX, 0x64); + tm6000_set_reg(dev, TM6010_REQ08_R1B_A_NICAM_SER_MIN, 0x20); + tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1c, 0x00); + tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1d, 0x00); + tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13); + tm6000_set_reg(dev, TM6010_REQ08_R1F_A_TEST_INTF_SEL, 0x00); + tm6000_set_reg(dev, TM6010_REQ08_R20_A_TEST_PIN_SEL, 0x00); + tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80); + + return 0; +} + +void tm6000_get_std_res(struct tm6000_core *dev) +{ + /* Currently, those are the only supported resoltions */ + if (dev->norm & V4L2_STD_525_60) + dev->height = 480; + else + dev->height = 576; + + dev->width = 720; +} + +static int tm6000_load_std(struct tm6000_core *dev, struct tm6000_reg_settings *set) +{ + int i, rc; + + /* Load board's initialization table */ + for (i = 0; set[i].req; i++) { + rc = tm6000_set_reg(dev, set[i].req, set[i].reg, set[i].value); + if (rc < 0) { + printk(KERN_ERR "Error %i while setting " + "req %d, reg %d to value %d\n", + rc, set[i].req, set[i].reg, set[i].value); + return rc; + } + } + + return 0; +} + +int tm6000_set_standard(struct tm6000_core *dev) +{ + struct tm6000_input *input; + int i, rc = 0; + u8 reg_07_fe = 0x8a; + u8 reg_08_f1 = 0xfc; + u8 reg_08_e2 = 0xf0; + u8 reg_08_e6 = 0x0f; + + tm6000_get_std_res(dev); + + if (!dev->radio) + input = &dev->vinput[dev->input]; + else + input = &dev->rinput; + + if (dev->dev_type == TM6010) { + switch (input->vmux) { + case TM6000_VMUX_VIDEO_A: + tm6000_set_reg(dev, TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4); + tm6000_set_reg(dev, TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1); + tm6000_set_reg(dev, TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0); + tm6000_set_reg(dev, TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2); + tm6000_set_reg(dev, TM6010_REQ08_RED_GAIN_SEL, 0xe8); + reg_07_fe |= 0x01; + break; + case TM6000_VMUX_VIDEO_B: + tm6000_set_reg(dev, TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8); + tm6000_set_reg(dev, TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1); + tm6000_set_reg(dev, TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0); + tm6000_set_reg(dev, TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2); + tm6000_set_reg(dev, TM6010_REQ08_RED_GAIN_SEL, 0xe8); + reg_07_fe |= 0x01; + break; + case TM6000_VMUX_VIDEO_AB: + tm6000_set_reg(dev, TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc); + tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8); + reg_08_e6 = 0x00; + tm6000_set_reg(dev, TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2); + tm6000_set_reg(dev, TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0); + tm6000_set_reg(dev, TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2); + tm6000_set_reg(dev, TM6010_REQ08_RED_GAIN_SEL, 0xe0); + break; + default: + break; + } + switch (input->amux) { + case TM6000_AMUX_ADC1: + tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, + 0x00, 0x0f); + break; + case TM6000_AMUX_ADC2: + tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, + 0x08, 0x0f); + break; + case TM6000_AMUX_SIF1: + reg_08_e2 |= 0x02; + reg_08_e6 = 0x08; + reg_07_fe |= 0x40; + reg_08_f1 |= 0x02; + tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3); + tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, + 0x02, 0x0f); + break; + case TM6000_AMUX_SIF2: + reg_08_e2 |= 0x02; + reg_08_e6 = 0x08; + reg_07_fe |= 0x40; + reg_08_f1 |= 0x02; + tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf7); + tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, + 0x02, 0x0f); + break; + default: + break; + } + tm6000_set_reg(dev, TM6010_REQ08_RE2_POWER_DOWN_CTRL1, reg_08_e2); + tm6000_set_reg(dev, TM6010_REQ08_RE6_POWER_DOWN_CTRL2, reg_08_e6); + tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, reg_08_f1); + tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, reg_07_fe); + } else { + switch (input->vmux) { + case TM6000_VMUX_VIDEO_A: + tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10); + tm6000_set_reg(dev, TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00); + tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x0f); + tm6000_set_reg(dev, + REQ_03_SET_GET_MCU_PIN, input->v_gpio, 0); + break; + case TM6000_VMUX_VIDEO_B: + tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x00); + tm6000_set_reg(dev, TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00); + tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x0f); + tm6000_set_reg(dev, + REQ_03_SET_GET_MCU_PIN, input->v_gpio, 0); + break; + case TM6000_VMUX_VIDEO_AB: + tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10); + tm6000_set_reg(dev, TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x10); + tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x00); + tm6000_set_reg(dev, + REQ_03_SET_GET_MCU_PIN, input->v_gpio, 1); + break; + default: + break; + } + switch (input->amux) { + case TM6000_AMUX_ADC1: + tm6000_set_reg_mask(dev, + TM6000_REQ07_REB_VADC_AADC_MODE, 0x00, 0x0f); + break; + case TM6000_AMUX_ADC2: + tm6000_set_reg_mask(dev, + TM6000_REQ07_REB_VADC_AADC_MODE, 0x04, 0x0f); + break; + default: + break; + } + } + if (input->type == TM6000_INPUT_SVIDEO) { + for (i = 0; i < ARRAY_SIZE(svideo_stds); i++) { + if (dev->norm & svideo_stds[i].id) { + rc = tm6000_load_std(dev, svideo_stds[i].common); + goto ret; + } + } + return -EINVAL; + } else { + for (i = 0; i < ARRAY_SIZE(composite_stds); i++) { + if (dev->norm & composite_stds[i].id) { + rc = tm6000_load_std(dev, composite_stds[i].common); + goto ret; + } + } + return -EINVAL; + } + +ret: + if (rc < 0) + return rc; + + if ((dev->dev_type == TM6010) && + ((input->amux == TM6000_AMUX_SIF1) || + (input->amux == TM6000_AMUX_SIF2))) + tm6000_set_audio_std(dev); + + msleep(40); + + return 0; +} diff --git a/drivers/media/video/tm6000/tm6000-usb-isoc.h b/drivers/media/video/tm6000/tm6000-usb-isoc.h new file mode 100644 index 0000000..99d15a5 --- /dev/null +++ b/drivers/media/video/tm6000/tm6000-usb-isoc.h @@ -0,0 +1,50 @@ +/* + * tm6000-buf.c - driver for TM5600/TM6000/TM6010 USB video capture devices + * + * Copyright (C) 2006-2007 Mauro Carvalho Chehab + * + * 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 version 2 + * + * 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 + +#define TM6000_URB_MSG_LEN 180 + +struct usb_isoc_ctl { + /* max packet size of isoc transaction */ + int max_pkt_size; + + /* number of allocated urbs */ + int num_bufs; + + /* urb for isoc transfers */ + struct urb **urb; + + /* transfer buffers for isoc transfer */ + char **transfer_buffer; + + /* Last buffer command and region */ + u8 cmd; + int pos, size, pktsize; + + /* Last field: ODD or EVEN? */ + int vfield, field; + + /* Stores incomplete commands */ + u32 tmp_buf; + int tmp_buf_len; + + /* Stores already requested buffers */ + struct tm6000_buffer *buf; +}; diff --git a/drivers/media/video/tm6000/tm6000-video.c b/drivers/media/video/tm6000/tm6000-video.c new file mode 100644 index 0000000..1e5ace0 --- /dev/null +++ b/drivers/media/video/tm6000/tm6000-video.c @@ -0,0 +1,1813 @@ +/* + * tm6000-video.c - driver for TM5600/TM6000/TM6010 USB video capture devices + * + * Copyright (C) 2006-2007 Mauro Carvalho Chehab + * + * Copyright (C) 2007 Michel Ludwig + * - Fixed module load/unload + * + * 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 version 2 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tm6000-regs.h" +#include "tm6000.h" + +#define BUFFER_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ + +/* Limits minimum and default number of buffers */ +#define TM6000_MIN_BUF 4 +#define TM6000_DEF_BUF 8 + +#define TM6000_MAX_ISO_PACKETS 46 /* Max number of ISO packets */ + +/* Declare static vars that will be used as parameters */ +static unsigned int vid_limit = 16; /* Video memory limit, in Mb */ +static int video_nr = -1; /* /dev/videoN, -1 for autodetect */ +static int radio_nr = -1; /* /dev/radioN, -1 for autodetect */ + +/* Debug level */ +int tm6000_debug; +EXPORT_SYMBOL_GPL(tm6000_debug); + +static const struct v4l2_queryctrl no_ctrl = { + .name = "42", + .flags = V4L2_CTRL_FLAG_DISABLED, +}; + +/* supported controls */ +static struct v4l2_queryctrl tm6000_qctrl[] = { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 54, + .flags = 0, + }, { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 255, + .step = 0x1, + .default_value = 119, + .flags = 0, + }, { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 0, + .maximum = 255, + .step = 0x1, + .default_value = 112, + .flags = 0, + }, { + .id = V4L2_CID_HUE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Hue", + .minimum = -128, + .maximum = 127, + .step = 0x1, + .default_value = 0, + .flags = 0, + }, + /* --- audio --- */ + { + .id = V4L2_CID_AUDIO_MUTE, + .name = "Mute", + .minimum = 0, + .maximum = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + }, { + .id = V4L2_CID_AUDIO_VOLUME, + .name = "Volume", + .minimum = -15, + .maximum = 15, + .step = 1, + .default_value = 0, + .type = V4L2_CTRL_TYPE_INTEGER, + } +}; + +static const unsigned int CTRLS = ARRAY_SIZE(tm6000_qctrl); +static int qctl_regs[ARRAY_SIZE(tm6000_qctrl)]; + +static struct tm6000_fmt format[] = { + { + .name = "4:2:2, packed, YVY2", + .fourcc = V4L2_PIX_FMT_YUYV, + .depth = 16, + }, { + .name = "4:2:2, packed, UYVY", + .fourcc = V4L2_PIX_FMT_UYVY, + .depth = 16, + }, { + .name = "A/V + VBI mux packet", + .fourcc = V4L2_PIX_FMT_TM6000, + .depth = 16, + } +}; + +static const struct v4l2_queryctrl *ctrl_by_id(unsigned int id) +{ + unsigned int i; + + for (i = 0; i < CTRLS; i++) + if (tm6000_qctrl[i].id == id) + return tm6000_qctrl+i; + return NULL; +} + +/* ------------------------------------------------------------------ + * DMA and thread functions + * ------------------------------------------------------------------ + */ + +#define norm_maxw(a) 720 +#define norm_maxh(a) 576 + +#define norm_minw(a) norm_maxw(a) +#define norm_minh(a) norm_maxh(a) + +/* + * video-buf generic routine to get the next available buffer + */ +static inline void get_next_buf(struct tm6000_dmaqueue *dma_q, + struct tm6000_buffer **buf) +{ + struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq); + char *outp; + + if (list_empty(&dma_q->active)) { + dprintk(dev, V4L2_DEBUG_QUEUE, "No active queue to serve\n"); + *buf = NULL; + return; + } + + *buf = list_entry(dma_q->active.next, + struct tm6000_buffer, vb.queue); + + /* Cleans up buffer - Useful for testing for frame/URB loss */ + outp = videobuf_to_vmalloc(&(*buf)->vb); + + return; +} + +/* + * Announces that a buffer were filled and request the next + */ +static inline void buffer_filled(struct tm6000_core *dev, + struct tm6000_dmaqueue *dma_q, + struct tm6000_buffer *buf) +{ + /* Advice that buffer was filled */ + dprintk(dev, V4L2_DEBUG_ISOC, "[%p/%d] wakeup\n", buf, buf->vb.i); + buf->vb.state = VIDEOBUF_DONE; + buf->vb.field_count++; + do_gettimeofday(&buf->vb.ts); + + list_del(&buf->vb.queue); + wake_up(&buf->vb.done); +} + +/* + * Identify the tm5600/6000 buffer header type and properly handles + */ +static int copy_streams(u8 *data, unsigned long len, + struct urb *urb) +{ + struct tm6000_dmaqueue *dma_q = urb->context; + struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq); + u8 *ptr = data, *endp = data+len, c; + unsigned long header = 0; + int rc = 0; + unsigned int cmd, cpysize, pktsize, size, field, block, line, pos = 0; + struct tm6000_buffer *vbuf = NULL; + char *voutp = NULL; + unsigned int linewidth; + + if (!dev->radio) { + /* get video buffer */ + get_next_buf(dma_q, &vbuf); + + if (!vbuf) + return rc; + voutp = videobuf_to_vmalloc(&vbuf->vb); + + if (!voutp) + return 0; + } + + for (ptr = data; ptr < endp;) { + if (!dev->isoc_ctl.cmd) { + /* Header */ + if (dev->isoc_ctl.tmp_buf_len > 0) { + /* from last urb or packet */ + header = dev->isoc_ctl.tmp_buf; + if (4 - dev->isoc_ctl.tmp_buf_len > 0) { + memcpy((u8 *)&header + + dev->isoc_ctl.tmp_buf_len, + ptr, + 4 - dev->isoc_ctl.tmp_buf_len); + ptr += 4 - dev->isoc_ctl.tmp_buf_len; + } + dev->isoc_ctl.tmp_buf_len = 0; + } else { + if (ptr + 3 >= endp) { + /* have incomplete header */ + dev->isoc_ctl.tmp_buf_len = endp - ptr; + memcpy(&dev->isoc_ctl.tmp_buf, ptr, + dev->isoc_ctl.tmp_buf_len); + return rc; + } + /* Seek for sync */ + for (; ptr < endp - 3; ptr++) { + if (*(ptr + 3) == 0x47) + break; + } + /* Get message header */ + header = *(unsigned long *)ptr; + ptr += 4; + } + + /* split the header fields */ + c = (header >> 24) & 0xff; + size = ((header & 0x7e) << 1); + if (size > 0) + size -= 4; + block = (header >> 7) & 0xf; + field = (header >> 11) & 0x1; + line = (header >> 12) & 0x1ff; + cmd = (header >> 21) & 0x7; + /* Validates haeder fields */ + if (size > TM6000_URB_MSG_LEN) + size = TM6000_URB_MSG_LEN; + pktsize = TM6000_URB_MSG_LEN; + /* + * calculate position in buffer and change the buffer + */ + switch (cmd) { + case TM6000_URB_MSG_VIDEO: + if (!dev->radio) { + if ((dev->isoc_ctl.vfield != field) && + (field == 1)) { + /* + * Announces that a new buffer + * were filled + */ + buffer_filled(dev, dma_q, vbuf); + dprintk(dev, V4L2_DEBUG_ISOC, + "new buffer filled\n"); + get_next_buf(dma_q, &vbuf); + if (!vbuf) + return rc; + voutp = videobuf_to_vmalloc(&vbuf->vb); + if (!voutp) + return rc; + memset(voutp, 0, vbuf->vb.size); + } + linewidth = vbuf->vb.width << 1; + pos = ((line << 1) - field - 1) * + linewidth + block * TM6000_URB_MSG_LEN; + /* Don't allow to write out of the buffer */ + if (pos + size > vbuf->vb.size) + cmd = TM6000_URB_MSG_ERR; + dev->isoc_ctl.vfield = field; + } + break; + case TM6000_URB_MSG_VBI: + break; + case TM6000_URB_MSG_AUDIO: + case TM6000_URB_MSG_PTS: + size = pktsize; /* Size is always 180 bytes */ + break; + } + } else { + /* Continue the last copy */ + cmd = dev->isoc_ctl.cmd; + size = dev->isoc_ctl.size; + pos = dev->isoc_ctl.pos; + pktsize = dev->isoc_ctl.pktsize; + field = dev->isoc_ctl.field; + } + cpysize = (endp - ptr > size) ? size : endp - ptr; + if (cpysize) { + /* copy data in different buffers */ + switch (cmd) { + case TM6000_URB_MSG_VIDEO: + /* Fills video buffer */ + if (vbuf) + memcpy(&voutp[pos], ptr, cpysize); + break; + case TM6000_URB_MSG_AUDIO: { + int i; + for (i = 0; i < cpysize; i += 2) + swab16s((u16 *)(ptr + i)); + + tm6000_call_fillbuf(dev, TM6000_AUDIO, ptr, cpysize); + break; + } + case TM6000_URB_MSG_VBI: + /* Need some code to copy vbi buffer */ + break; + case TM6000_URB_MSG_PTS: { + /* Need some code to copy pts */ + u32 pts; + pts = *(u32 *)ptr; + dprintk(dev, V4L2_DEBUG_ISOC, "field %d, PTS %x", + field, pts); + break; + } + } + } + if (ptr + pktsize > endp) { + /* + * End of URB packet, but cmd processing is not + * complete. Preserve the state for a next packet + */ + dev->isoc_ctl.pos = pos + cpysize; + dev->isoc_ctl.size = size - cpysize; + dev->isoc_ctl.cmd = cmd; + dev->isoc_ctl.field = field; + dev->isoc_ctl.pktsize = pktsize - (endp - ptr); + ptr += endp - ptr; + } else { + dev->isoc_ctl.cmd = 0; + ptr += pktsize; + } + } + return 0; +} + +/* + * Identify the tm5600/6000 buffer header type and properly handles + */ +static int copy_multiplexed(u8 *ptr, unsigned long len, + struct urb *urb) +{ + struct tm6000_dmaqueue *dma_q = urb->context; + struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq); + unsigned int pos = dev->isoc_ctl.pos, cpysize; + int rc = 1; + struct tm6000_buffer *buf; + char *outp = NULL; + + get_next_buf(dma_q, &buf); + if (buf) + outp = videobuf_to_vmalloc(&buf->vb); + + if (!outp) + return 0; + + while (len > 0) { + cpysize = min(len, buf->vb.size-pos); + memcpy(&outp[pos], ptr, cpysize); + pos += cpysize; + ptr += cpysize; + len -= cpysize; + if (pos >= buf->vb.size) { + pos = 0; + /* Announces that a new buffer were filled */ + buffer_filled(dev, dma_q, buf); + dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n"); + get_next_buf(dma_q, &buf); + if (!buf) + break; + outp = videobuf_to_vmalloc(&(buf->vb)); + if (!outp) + return rc; + pos = 0; + } + } + + dev->isoc_ctl.pos = pos; + return rc; +} + +static inline void print_err_status(struct tm6000_core *dev, + int packet, int status) +{ + char *errmsg = "Unknown"; + + switch (status) { + case -ENOENT: + errmsg = "unlinked synchronuously"; + break; + case -ECONNRESET: + errmsg = "unlinked asynchronuously"; + break; + case -ENOSR: + errmsg = "Buffer error (overrun)"; + break; + case -EPIPE: + errmsg = "Stalled (device not responding)"; + break; + case -EOVERFLOW: + errmsg = "Babble (bad cable?)"; + break; + case -EPROTO: + errmsg = "Bit-stuff error (bad cable?)"; + break; + case -EILSEQ: + errmsg = "CRC/Timeout (could be anything)"; + break; + case -ETIME: + errmsg = "Device does not respond"; + break; + } + if (packet < 0) { + dprintk(dev, V4L2_DEBUG_QUEUE, "URB status %d [%s].\n", + status, errmsg); + } else { + dprintk(dev, V4L2_DEBUG_QUEUE, "URB packet %d, status %d [%s].\n", + packet, status, errmsg); + } +} + + +/* + * Controls the isoc copy of each urb packet + */ +static inline int tm6000_isoc_copy(struct urb *urb) +{ + struct tm6000_dmaqueue *dma_q = urb->context; + struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq); + int i, len = 0, rc = 1, status; + char *p; + + if (urb->status < 0) { + print_err_status(dev, -1, urb->status); + return 0; + } + + for (i = 0; i < urb->number_of_packets; i++) { + status = urb->iso_frame_desc[i].status; + + if (status < 0) { + print_err_status(dev, i, status); + continue; + } + + len = urb->iso_frame_desc[i].actual_length; + + if (len > 0) { + p = urb->transfer_buffer + urb->iso_frame_desc[i].offset; + if (!urb->iso_frame_desc[i].status) { + if ((dev->fourcc) == V4L2_PIX_FMT_TM6000) { + rc = copy_multiplexed(p, len, urb); + if (rc <= 0) + return rc; + } else { + copy_streams(p, len, urb); + } + } + } + } + return rc; +} + +/* ------------------------------------------------------------------ + * URB control + * ------------------------------------------------------------------ + */ + +/* + * IRQ callback, called by URB callback + */ +static void tm6000_irq_callback(struct urb *urb) +{ + struct tm6000_dmaqueue *dma_q = urb->context; + struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq); + int i; + + switch (urb->status) { + case 0: + case -ETIMEDOUT: + break; + + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + return; + + default: + tm6000_err("urb completion error %d.\n", urb->status); + break; + } + + spin_lock(&dev->slock); + tm6000_isoc_copy(urb); + spin_unlock(&dev->slock); + + /* Reset urb buffers */ + for (i = 0; i < urb->number_of_packets; i++) { + urb->iso_frame_desc[i].status = 0; + urb->iso_frame_desc[i].actual_length = 0; + } + + urb->status = usb_submit_urb(urb, GFP_ATOMIC); + if (urb->status) + tm6000_err("urb resubmit failed (error=%i)\n", + urb->status); +} + +/* + * Stop and Deallocate URBs + */ +static void tm6000_uninit_isoc(struct tm6000_core *dev) +{ + struct urb *urb; + int i; + + dev->isoc_ctl.buf = NULL; + for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { + urb = dev->isoc_ctl.urb[i]; + if (urb) { + usb_kill_urb(urb); + usb_unlink_urb(urb); + if (dev->isoc_ctl.transfer_buffer[i]) { + usb_free_coherent(dev->udev, + urb->transfer_buffer_length, + dev->isoc_ctl.transfer_buffer[i], + urb->transfer_dma); + } + usb_free_urb(urb); + dev->isoc_ctl.urb[i] = NULL; + } + dev->isoc_ctl.transfer_buffer[i] = NULL; + } + + kfree(dev->isoc_ctl.urb); + kfree(dev->isoc_ctl.transfer_buffer); + + dev->isoc_ctl.urb = NULL; + dev->isoc_ctl.transfer_buffer = NULL; + dev->isoc_ctl.num_bufs = 0; +} + +/* + * Allocate URBs and start IRQ + */ +static int tm6000_prepare_isoc(struct tm6000_core *dev) +{ + struct tm6000_dmaqueue *dma_q = &dev->vidq; + int i, j, sb_size, pipe, size, max_packets, num_bufs = 8; + struct urb *urb; + + /* De-allocates all pending stuff */ + tm6000_uninit_isoc(dev); + /* Stop interrupt USB pipe */ + tm6000_ir_int_stop(dev); + + usb_set_interface(dev->udev, + dev->isoc_in.bInterfaceNumber, + dev->isoc_in.bAlternateSetting); + + /* Start interrupt USB pipe */ + tm6000_ir_int_start(dev); + + pipe = usb_rcvisocpipe(dev->udev, + dev->isoc_in.endp->desc.bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK); + + size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe)); + + if (size > dev->isoc_in.maxsize) + size = dev->isoc_in.maxsize; + + dev->isoc_ctl.max_pkt_size = size; + + max_packets = TM6000_MAX_ISO_PACKETS; + sb_size = max_packets * size; + + dev->isoc_ctl.num_bufs = num_bufs; + + dev->isoc_ctl.urb = kmalloc(sizeof(void *)*num_bufs, GFP_KERNEL); + if (!dev->isoc_ctl.urb) { + tm6000_err("cannot alloc memory for usb buffers\n"); + return -ENOMEM; + } + + dev->isoc_ctl.transfer_buffer = kmalloc(sizeof(void *)*num_bufs, + GFP_KERNEL); + if (!dev->isoc_ctl.transfer_buffer) { + tm6000_err("cannot allocate memory for usbtransfer\n"); + kfree(dev->isoc_ctl.urb); + return -ENOMEM; + } + + dprintk(dev, V4L2_DEBUG_QUEUE, "Allocating %d x %d packets" + " (%d bytes) of %d bytes each to handle %u size\n", + max_packets, num_bufs, sb_size, + dev->isoc_in.maxsize, size); + + /* allocate urbs and transfer buffers */ + for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { + urb = usb_alloc_urb(max_packets, GFP_KERNEL); + if (!urb) { + tm6000_err("cannot alloc isoc_ctl.urb %i\n", i); + tm6000_uninit_isoc(dev); + usb_free_urb(urb); + return -ENOMEM; + } + dev->isoc_ctl.urb[i] = urb; + + dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev, + sb_size, GFP_KERNEL, &urb->transfer_dma); + if (!dev->isoc_ctl.transfer_buffer[i]) { + tm6000_err("unable to allocate %i bytes for transfer" + " buffer %i%s\n", + sb_size, i, + in_interrupt() ? " while in int" : ""); + tm6000_uninit_isoc(dev); + return -ENOMEM; + } + memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size); + + usb_fill_bulk_urb(urb, dev->udev, pipe, + dev->isoc_ctl.transfer_buffer[i], sb_size, + tm6000_irq_callback, dma_q); + urb->interval = dev->isoc_in.endp->desc.bInterval; + urb->number_of_packets = max_packets; + urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; + + for (j = 0; j < max_packets; j++) { + urb->iso_frame_desc[j].offset = size * j; + urb->iso_frame_desc[j].length = size; + } + } + + return 0; +} + +static int tm6000_start_thread(struct tm6000_core *dev) +{ + struct tm6000_dmaqueue *dma_q = &dev->vidq; + int i; + + dma_q->frame = 0; + dma_q->ini_jiffies = jiffies; + + init_waitqueue_head(&dma_q->wq); + + /* submit urbs and enables IRQ */ + for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { + int rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC); + if (rc) { + tm6000_err("submit of urb %i failed (error=%i)\n", i, + rc); + tm6000_uninit_isoc(dev); + return rc; + } + } + + return 0; +} + +/* ------------------------------------------------------------------ + * Videobuf operations + * ------------------------------------------------------------------ + */ + +static int +buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) +{ + struct tm6000_fh *fh = vq->priv_data; + + *size = fh->fmt->depth * fh->width * fh->height >> 3; + if (0 == *count) + *count = TM6000_DEF_BUF; + + if (*count < TM6000_MIN_BUF) + *count = TM6000_MIN_BUF; + + while (*size * *count > vid_limit * 1024 * 1024) + (*count)--; + + return 0; +} + +static void free_buffer(struct videobuf_queue *vq, struct tm6000_buffer *buf) +{ + struct tm6000_fh *fh = vq->priv_data; + struct tm6000_core *dev = fh->dev; + unsigned long flags; + + if (in_interrupt()) + BUG(); + + /* We used to wait for the buffer to finish here, but this didn't work + because, as we were keeping the state as VIDEOBUF_QUEUED, + videobuf_queue_cancel marked it as finished for us. + (Also, it could wedge forever if the hardware was misconfigured.) + + This should be safe; by the time we get here, the buffer isn't + queued anymore. If we ever start marking the buffers as + VIDEOBUF_ACTIVE, it won't be, though. + */ + spin_lock_irqsave(&dev->slock, flags); + if (dev->isoc_ctl.buf == buf) + dev->isoc_ctl.buf = NULL; + spin_unlock_irqrestore(&dev->slock, flags); + + videobuf_vmalloc_free(&buf->vb); + buf->vb.state = VIDEOBUF_NEEDS_INIT; +} + +static int +buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct tm6000_fh *fh = vq->priv_data; + struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb); + struct tm6000_core *dev = fh->dev; + int rc = 0; + + BUG_ON(NULL == fh->fmt); + + + /* FIXME: It assumes depth=2 */ + /* The only currently supported format is 16 bits/pixel */ + buf->vb.size = fh->fmt->depth*fh->width*fh->height >> 3; + if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + return -EINVAL; + + if (buf->fmt != fh->fmt || + buf->vb.width != fh->width || + buf->vb.height != fh->height || + buf->vb.field != field) { + buf->fmt = fh->fmt; + buf->vb.width = fh->width; + buf->vb.height = fh->height; + buf->vb.field = field; + buf->vb.state = VIDEOBUF_NEEDS_INIT; + } + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + rc = videobuf_iolock(vq, &buf->vb, NULL); + if (rc != 0) + goto fail; + } + + if (!dev->isoc_ctl.num_bufs) { + rc = tm6000_prepare_isoc(dev); + if (rc < 0) + goto fail; + + rc = tm6000_start_thread(dev); + if (rc < 0) + goto fail; + + } + + buf->vb.state = VIDEOBUF_PREPARED; + return 0; + +fail: + free_buffer(vq, buf); + return rc; +} + +static void +buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +{ + struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb); + struct tm6000_fh *fh = vq->priv_data; + struct tm6000_core *dev = fh->dev; + struct tm6000_dmaqueue *vidq = &dev->vidq; + + buf->vb.state = VIDEOBUF_QUEUED; + list_add_tail(&buf->vb.queue, &vidq->active); +} + +static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb) +{ + struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb); + + free_buffer(vq, buf); +} + +static struct videobuf_queue_ops tm6000_video_qops = { + .buf_setup = buffer_setup, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .buf_release = buffer_release, +}; + +/* ------------------------------------------------------------------ + * IOCTL handling + * ------------------------------------------------------------------ + */ + +static bool is_res_read(struct tm6000_core *dev, struct tm6000_fh *fh) +{ + /* Is the current fh handling it? if so, that's OK */ + if (dev->resources == fh && dev->is_res_read) + return true; + + return false; +} + +static bool is_res_streaming(struct tm6000_core *dev, struct tm6000_fh *fh) +{ + /* Is the current fh handling it? if so, that's OK */ + if (dev->resources == fh) + return true; + + return false; +} + +static bool res_get(struct tm6000_core *dev, struct tm6000_fh *fh, + bool is_res_read) +{ + /* Is the current fh handling it? if so, that's OK */ + if (dev->resources == fh && dev->is_res_read == is_res_read) + return true; + + /* is it free? */ + if (dev->resources) + return false; + + /* grab it */ + dev->resources = fh; + dev->is_res_read = is_res_read; + dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: get\n"); + return true; +} + +static void res_free(struct tm6000_core *dev, struct tm6000_fh *fh) +{ + /* Is the current fh handling it? if so, that's OK */ + if (dev->resources != fh) + return; + + dev->resources = NULL; + dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: put\n"); +} + +/* ------------------------------------------------------------------ + * IOCTL vidioc handling + * ------------------------------------------------------------------ + */ +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev; + + strlcpy(cap->driver, "tm6000", sizeof(cap->driver)); + strlcpy(cap->card, "Trident TVMaster TM5600/6000/6010", sizeof(cap->card)); + cap->version = TM6000_VERSION; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_STREAMING | + V4L2_CAP_AUDIO | + V4L2_CAP_READWRITE; + + if (dev->tuner_type != TUNER_ABSENT) + cap->capabilities |= V4L2_CAP_TUNER; + + return 0; +} + +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (unlikely(f->index >= ARRAY_SIZE(format))) + return -EINVAL; + + strlcpy(f->description, format[f->index].name, sizeof(f->description)); + f->pixelformat = format[f->index].fourcc; + return 0; +} + +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct tm6000_fh *fh = priv; + + f->fmt.pix.width = fh->width; + f->fmt.pix.height = fh->height; + f->fmt.pix.field = fh->vb_vidq.field; + f->fmt.pix.pixelformat = fh->fmt->fourcc; + f->fmt.pix.bytesperline = + (f->fmt.pix.width * fh->fmt->depth) >> 3; + f->fmt.pix.sizeimage = + f->fmt.pix.height * f->fmt.pix.bytesperline; + + return 0; +} + +static struct tm6000_fmt *format_by_fourcc(unsigned int fourcc) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(format); i++) + if (format[i].fourcc == fourcc) + return format+i; + return NULL; +} + +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev; + struct tm6000_fmt *fmt; + enum v4l2_field field; + + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + if (NULL == fmt) { + dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Fourcc format (0x%08x)" + " invalid.\n", f->fmt.pix.pixelformat); + return -EINVAL; + } + + field = f->fmt.pix.field; + + if (field == V4L2_FIELD_ANY) + field = V4L2_FIELD_SEQ_TB; + else if (V4L2_FIELD_INTERLACED != field) { + dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Field type invalid.\n"); + return -EINVAL; + } + + tm6000_get_std_res(dev); + + f->fmt.pix.width = dev->width; + f->fmt.pix.height = dev->height; + + f->fmt.pix.width &= ~0x01; + + f->fmt.pix.field = field; + + f->fmt.pix.bytesperline = + (f->fmt.pix.width * fmt->depth) >> 3; + f->fmt.pix.sizeimage = + f->fmt.pix.height * f->fmt.pix.bytesperline; + + return 0; +} + +/*FIXME: This seems to be generic enough to be at videodev2 */ +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct tm6000_fh *fh = priv; + struct tm6000_core *dev = fh->dev; + int ret = vidioc_try_fmt_vid_cap(file, fh, f); + if (ret < 0) + return ret; + + fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); + fh->width = f->fmt.pix.width; + fh->height = f->fmt.pix.height; + fh->vb_vidq.field = f->fmt.pix.field; + fh->type = f->type; + + dev->fourcc = f->fmt.pix.pixelformat; + + tm6000_set_fourcc_format(dev); + + return 0; +} + +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) +{ + struct tm6000_fh *fh = priv; + + return videobuf_reqbufs(&fh->vb_vidq, p); +} + +static int vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct tm6000_fh *fh = priv; + + return videobuf_querybuf(&fh->vb_vidq, p); +} + +static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) +{ + struct tm6000_fh *fh = priv; + + return videobuf_qbuf(&fh->vb_vidq, p); +} + +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) +{ + struct tm6000_fh *fh = priv; + + return videobuf_dqbuf(&fh->vb_vidq, p, + file->f_flags & O_NONBLOCK); +} + +static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) +{ + struct tm6000_fh *fh = priv; + struct tm6000_core *dev = fh->dev; + + if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (i != fh->type) + return -EINVAL; + + if (!res_get(dev, fh, false)) + return -EBUSY; + return videobuf_streamon(&fh->vb_vidq); +} + +static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) +{ + struct tm6000_fh *fh = priv; + struct tm6000_core *dev = fh->dev; + + if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (i != fh->type) + return -EINVAL; + + videobuf_streamoff(&fh->vb_vidq); + res_free(dev, fh); + + return 0; +} + +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) +{ + int rc = 0; + struct tm6000_fh *fh = priv; + struct tm6000_core *dev = fh->dev; + + dev->norm = *norm; + rc = tm6000_init_analog_mode(dev); + + fh->width = dev->width; + fh->height = dev->height; + + if (rc < 0) + return rc; + + v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm); + + return 0; +} + +static const char *iname[] = { + [TM6000_INPUT_TV] = "Television", + [TM6000_INPUT_COMPOSITE1] = "Composite 1", + [TM6000_INPUT_COMPOSITE2] = "Composite 2", + [TM6000_INPUT_SVIDEO] = "S-Video", +}; + +static int vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + struct tm6000_fh *fh = priv; + struct tm6000_core *dev = fh->dev; + unsigned int n; + + n = i->index; + if (n >= 3) + return -EINVAL; + + if (!dev->vinput[n].type) + return -EINVAL; + + i->index = n; + + if (dev->vinput[n].type == TM6000_INPUT_TV) + i->type = V4L2_INPUT_TYPE_TUNER; + else + i->type = V4L2_INPUT_TYPE_CAMERA; + + strcpy(i->name, iname[dev->vinput[n].type]); + + i->std = TM6000_STD; + + return 0; +} + +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + struct tm6000_fh *fh = priv; + struct tm6000_core *dev = fh->dev; + + *i = dev->input; + + return 0; +} + +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + struct tm6000_fh *fh = priv; + struct tm6000_core *dev = fh->dev; + int rc = 0; + + if (i >= 3) + return -EINVAL; + if (!dev->vinput[i].type) + return -EINVAL; + + dev->input = i; + + rc = vidioc_s_std(file, priv, &dev->vfd->current_norm); + + return rc; +} + +/* --- controls ---------------------------------------------- */ +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(tm6000_qctrl); i++) + if (qc->id && qc->id == tm6000_qctrl[i].id) { + memcpy(qc, &(tm6000_qctrl[i]), + sizeof(*qc)); + return 0; + } + + return -EINVAL; +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct tm6000_fh *fh = priv; + struct tm6000_core *dev = fh->dev; + int val; + + /* FIXME: Probably, those won't work! Maybe we need shadow regs */ + switch (ctrl->id) { + case V4L2_CID_CONTRAST: + val = tm6000_get_reg(dev, TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0); + break; + case V4L2_CID_BRIGHTNESS: + val = tm6000_get_reg(dev, TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0); + return 0; + case V4L2_CID_SATURATION: + val = tm6000_get_reg(dev, TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0); + return 0; + case V4L2_CID_HUE: + val = tm6000_get_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, 0); + return 0; + case V4L2_CID_AUDIO_MUTE: + val = dev->ctl_mute; + return 0; + case V4L2_CID_AUDIO_VOLUME: + val = dev->ctl_volume; + return 0; + default: + return -EINVAL; + } + + if (val < 0) + return val; + + ctrl->value = val; + + return 0; +} +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct tm6000_fh *fh = priv; + struct tm6000_core *dev = fh->dev; + u8 val = ctrl->value; + + switch (ctrl->id) { + case V4L2_CID_CONTRAST: + tm6000_set_reg(dev, TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, val); + return 0; + case V4L2_CID_BRIGHTNESS: + tm6000_set_reg(dev, TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, val); + return 0; + case V4L2_CID_SATURATION: + tm6000_set_reg(dev, TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, val); + return 0; + case V4L2_CID_HUE: + tm6000_set_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, val); + return 0; + case V4L2_CID_AUDIO_MUTE: + dev->ctl_mute = val; + tm6000_tvaudio_set_mute(dev, val); + return 0; + case V4L2_CID_AUDIO_VOLUME: + dev->ctl_volume = val; + tm6000_set_volume(dev, val); + return 0; + } + return -EINVAL; +} + +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct tm6000_fh *fh = priv; + struct tm6000_core *dev = fh->dev; + + if (unlikely(UNSET == dev->tuner_type)) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + + strcpy(t->name, "Television"); + t->type = V4L2_TUNER_ANALOG_TV; + t->capability = V4L2_TUNER_CAP_NORM; + t->rangehigh = 0xffffffffUL; + t->rxsubchans = V4L2_TUNER_SUB_STEREO; + + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t); + + t->audmode = dev->amode; + + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct tm6000_fh *fh = priv; + struct tm6000_core *dev = fh->dev; + + if (UNSET == dev->tuner_type) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + + dev->amode = t->audmode; + dprintk(dev, 3, "audio mode: %x\n", t->audmode); + + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t); + + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct tm6000_fh *fh = priv; + struct tm6000_core *dev = fh->dev; + + if (unlikely(UNSET == dev->tuner_type)) + return -EINVAL; + + f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + f->frequency = dev->freq; + + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, f); + + return 0; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct tm6000_fh *fh = priv; + struct tm6000_core *dev = fh->dev; + + if (unlikely(UNSET == dev->tuner_type)) + return -EINVAL; + if (unlikely(f->tuner != 0)) + return -EINVAL; + if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type) + return -EINVAL; + if (1 == fh->radio && V4L2_TUNER_RADIO != f->type) + return -EINVAL; + + dev->freq = f->frequency; + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f); + + return 0; +} + +static int radio_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct tm6000_fh *fh = file->private_data; + struct tm6000_core *dev = fh->dev; + + strcpy(cap->driver, "tm6000"); + strlcpy(cap->card, dev->name, sizeof(dev->name)); + sprintf(cap->bus_info, "USB%04x:%04x", + le16_to_cpu(dev->udev->descriptor.idVendor), + le16_to_cpu(dev->udev->descriptor.idProduct)); + cap->version = dev->dev_type; + cap->capabilities = V4L2_CAP_TUNER | + V4L2_CAP_AUDIO | + V4L2_CAP_RADIO | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + + return 0; +} + +static int radio_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct tm6000_fh *fh = file->private_data; + struct tm6000_core *dev = fh->dev; + + if (0 != t->index) + return -EINVAL; + + memset(t, 0, sizeof(*t)); + strcpy(t->name, "Radio"); + t->type = V4L2_TUNER_RADIO; + t->rxsubchans = V4L2_TUNER_SUB_STEREO; + + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t); + + return 0; +} + +static int radio_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct tm6000_fh *fh = file->private_data; + struct tm6000_core *dev = fh->dev; + + if (0 != t->index) + return -EINVAL; + + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t); + + return 0; +} + +static int radio_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + struct tm6000_fh *fh = priv; + struct tm6000_core *dev = fh->dev; + + if (i->index != 0) + return -EINVAL; + + if (!dev->rinput.type) + return -EINVAL; + + strcpy(i->name, "Radio"); + i->type = V4L2_INPUT_TYPE_TUNER; + + return 0; +} + +static int radio_g_input(struct file *filp, void *priv, unsigned int *i) +{ + struct tm6000_fh *fh = priv; + struct tm6000_core *dev = fh->dev; + + if (dev->input != 5) + return -EINVAL; + + *i = dev->input - 5; + + return 0; +} + +static int radio_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + memset(a, 0, sizeof(*a)); + strcpy(a->name, "Radio"); + return 0; +} + +static int radio_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + return 0; +} + +static int radio_s_input(struct file *filp, void *priv, unsigned int i) +{ + struct tm6000_fh *fh = priv; + struct tm6000_core *dev = fh->dev; + + if (i) + return -EINVAL; + + if (!dev->rinput.type) + return -EINVAL; + + dev->input = i + 5; + + return 0; +} + +static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm) +{ + return 0; +} + +static int radio_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *c) +{ + const struct v4l2_queryctrl *ctrl; + + if (c->id < V4L2_CID_BASE || + c->id >= V4L2_CID_LASTP1) + return -EINVAL; + if (c->id == V4L2_CID_AUDIO_MUTE) { + ctrl = ctrl_by_id(c->id); + *c = *ctrl; + } else + *c = no_ctrl; + + return 0; +} + +/* ------------------------------------------------------------------ + File operations for the device + ------------------------------------------------------------------*/ + +static int tm6000_open(struct file *file) +{ + struct video_device *vdev = video_devdata(file); + struct tm6000_core *dev = video_drvdata(file); + struct tm6000_fh *fh; + enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + int i, rc; + int radio = 0; + + dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: open called (dev=%s)\n", + video_device_node_name(vdev)); + + switch (vdev->vfl_type) { + case VFL_TYPE_GRABBER: + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + break; + case VFL_TYPE_VBI: + type = V4L2_BUF_TYPE_VBI_CAPTURE; + break; + case VFL_TYPE_RADIO: + radio = 1; + break; + } + + /* If more than one user, mutex should be added */ + dev->users++; + + dprintk(dev, V4L2_DEBUG_OPEN, "open dev=%s type=%s users=%d\n", + video_device_node_name(vdev), v4l2_type_names[type], + dev->users); + + /* allocate + initialize per filehandle data */ + fh = kzalloc(sizeof(*fh), GFP_KERNEL); + if (NULL == fh) { + dev->users--; + return -ENOMEM; + } + + file->private_data = fh; + fh->dev = dev; + fh->radio = radio; + dev->radio = radio; + fh->type = type; + dev->fourcc = format[0].fourcc; + + fh->fmt = format_by_fourcc(dev->fourcc); + + tm6000_get_std_res(dev); + + fh->width = dev->width; + fh->height = dev->height; + + dprintk(dev, V4L2_DEBUG_OPEN, "Open: fh=0x%08lx, dev=0x%08lx, " + "dev->vidq=0x%08lx\n", + (unsigned long)fh, (unsigned long)dev, + (unsigned long)&dev->vidq); + dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty " + "queued=%d\n", list_empty(&dev->vidq.queued)); + dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty " + "active=%d\n", list_empty(&dev->vidq.active)); + + /* initialize hardware on analog mode */ + rc = tm6000_init_analog_mode(dev); + if (rc < 0) + return rc; + + if (dev->mode != TM6000_MODE_ANALOG) { + /* Put all controls at a sane state */ + for (i = 0; i < ARRAY_SIZE(tm6000_qctrl); i++) + qctl_regs[i] = tm6000_qctrl[i].default_value; + + dev->mode = TM6000_MODE_ANALOG; + } + + if (!fh->radio) { + videobuf_queue_vmalloc_init(&fh->vb_vidq, &tm6000_video_qops, + NULL, &dev->slock, + fh->type, + V4L2_FIELD_INTERLACED, + sizeof(struct tm6000_buffer), fh, &dev->lock); + } else { + dprintk(dev, V4L2_DEBUG_OPEN, "video_open: setting radio device\n"); + dev->input = 5; + tm6000_set_audio_rinput(dev); + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio); + tm6000_prepare_isoc(dev); + tm6000_start_thread(dev); + } + + return 0; +} + +static ssize_t +tm6000_read(struct file *file, char __user *data, size_t count, loff_t *pos) +{ + struct tm6000_fh *fh = file->private_data; + + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + if (!res_get(fh->dev, fh, true)) + return -EBUSY; + + return videobuf_read_stream(&fh->vb_vidq, data, count, pos, 0, + file->f_flags & O_NONBLOCK); + } + return 0; +} + +static unsigned int +tm6000_poll(struct file *file, struct poll_table_struct *wait) +{ + struct tm6000_fh *fh = file->private_data; + struct tm6000_buffer *buf; + + if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) + return POLLERR; + + if (!!is_res_streaming(fh->dev, fh)) + return POLLERR; + + if (!is_res_read(fh->dev, fh)) { + /* streaming capture */ + if (list_empty(&fh->vb_vidq.stream)) + return POLLERR; + buf = list_entry(fh->vb_vidq.stream.next, struct tm6000_buffer, vb.stream); + } else { + /* read() capture */ + return videobuf_poll_stream(file, &fh->vb_vidq, wait); + } + poll_wait(file, &buf->vb.done, wait); + if (buf->vb.state == VIDEOBUF_DONE || + buf->vb.state == VIDEOBUF_ERROR) + return POLLIN | POLLRDNORM; + return 0; +} + +static int tm6000_release(struct file *file) +{ + struct tm6000_fh *fh = file->private_data; + struct tm6000_core *dev = fh->dev; + struct video_device *vdev = video_devdata(file); + + dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: close called (dev=%s, users=%d)\n", + video_device_node_name(vdev), dev->users); + + dev->users--; + + res_free(dev, fh); + + if (!dev->users) { + int err; + + tm6000_uninit_isoc(dev); + + if (!fh->radio) + videobuf_mmap_free(&fh->vb_vidq); + + err = tm6000_reset(dev); + if (err < 0) + dev_err(&vdev->dev, "reset failed: %d\n", err); + } + + kfree(fh); + + return 0; +} + +static int tm6000_mmap(struct file *file, struct vm_area_struct * vma) +{ + struct tm6000_fh *fh = file->private_data; + + return videobuf_mmap_mapper(&fh->vb_vidq, vma); +} + +static struct v4l2_file_operations tm6000_fops = { + .owner = THIS_MODULE, + .open = tm6000_open, + .release = tm6000_release, + .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ + .read = tm6000_read, + .poll = tm6000_poll, + .mmap = tm6000_mmap, +}; + +static const struct v4l2_ioctl_ops video_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + .vidioc_s_std = vidioc_s_std, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, +}; + +static struct video_device tm6000_template = { + .name = "tm6000", + .fops = &tm6000_fops, + .ioctl_ops = &video_ioctl_ops, + .release = video_device_release, + .tvnorms = TM6000_STD, + .current_norm = V4L2_STD_NTSC_M, +}; + +static const struct v4l2_file_operations radio_fops = { + .owner = THIS_MODULE, + .open = tm6000_open, + .release = tm6000_release, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops radio_ioctl_ops = { + .vidioc_querycap = radio_querycap, + .vidioc_g_tuner = radio_g_tuner, + .vidioc_enum_input = radio_enum_input, + .vidioc_g_audio = radio_g_audio, + .vidioc_s_tuner = radio_s_tuner, + .vidioc_s_audio = radio_s_audio, + .vidioc_s_input = radio_s_input, + .vidioc_s_std = radio_s_std, + .vidioc_queryctrl = radio_queryctrl, + .vidioc_g_input = radio_g_input, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, +}; + +static struct video_device tm6000_radio_template = { + .name = "tm6000", + .fops = &radio_fops, + .ioctl_ops = &radio_ioctl_ops, +}; + +/* ----------------------------------------------------------------- + * Initialization and module stuff + * ------------------------------------------------------------------ + */ + +static struct video_device *vdev_init(struct tm6000_core *dev, + const struct video_device + *template, const char *type_name) +{ + struct video_device *vfd; + + vfd = video_device_alloc(); + if (NULL == vfd) + return NULL; + + *vfd = *template; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->release = video_device_release; + vfd->debug = tm6000_debug; + vfd->lock = &dev->lock; + + snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name); + + video_set_drvdata(vfd, dev); + return vfd; +} + +int tm6000_v4l2_register(struct tm6000_core *dev) +{ + int ret = -1; + + dev->vfd = vdev_init(dev, &tm6000_template, "video"); + + if (!dev->vfd) { + printk(KERN_INFO "%s: can't register video device\n", + dev->name); + return -ENOMEM; + } + + /* init video dma queues */ + INIT_LIST_HEAD(&dev->vidq.active); + INIT_LIST_HEAD(&dev->vidq.queued); + + ret = video_register_device(dev->vfd, VFL_TYPE_GRABBER, video_nr); + + if (ret < 0) { + printk(KERN_INFO "%s: can't register video device\n", + dev->name); + return ret; + } + + printk(KERN_INFO "%s: registered device %s\n", + dev->name, video_device_node_name(dev->vfd)); + + if (dev->caps.has_radio) { + dev->radio_dev = vdev_init(dev, &tm6000_radio_template, + "radio"); + if (!dev->radio_dev) { + printk(KERN_INFO "%s: can't register radio device\n", + dev->name); + return ret; /* FIXME release resource */ + } + + ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, + radio_nr); + if (ret < 0) { + printk(KERN_INFO "%s: can't register radio device\n", + dev->name); + return ret; /* FIXME release resource */ + } + + printk(KERN_INFO "%s: registered device %s\n", + dev->name, video_device_node_name(dev->radio_dev)); + } + + printk(KERN_INFO "Trident TVMaster TM5600/TM6000/TM6010 USB2 board (Load status: %d)\n", ret); + return ret; +} + +int tm6000_v4l2_unregister(struct tm6000_core *dev) +{ + video_unregister_device(dev->vfd); + + if (dev->radio_dev) { + if (video_is_registered(dev->radio_dev)) + video_unregister_device(dev->radio_dev); + else + video_device_release(dev->radio_dev); + dev->radio_dev = NULL; + } + + return 0; +} + +int tm6000_v4l2_exit(void) +{ + return 0; +} + +module_param(video_nr, int, 0); +MODULE_PARM_DESC(video_nr, "Allow changing video device number"); + +module_param_named(debug, tm6000_debug, int, 0444); +MODULE_PARM_DESC(debug, "activates debug info"); + +module_param(vid_limit, int, 0644); +MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); + diff --git a/drivers/media/video/tm6000/tm6000.h b/drivers/media/video/tm6000/tm6000.h new file mode 100644 index 0000000..2777e51 --- /dev/null +++ b/drivers/media/video/tm6000/tm6000.h @@ -0,0 +1,398 @@ +/* + * tm6000.h - driver for TM5600/TM6000/TM6010 USB video capture devices + * + * Copyright (C) 2006-2007 Mauro Carvalho Chehab + * + * Copyright (C) 2007 Michel Ludwig + * - DVB-T support + * + * 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 version 2 + * + * 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 +#include +#include +#include "tm6000-usb-isoc.h" +#include +#include +#include + +#include +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dmxdev.h" + +#define TM6000_VERSION KERNEL_VERSION(0, 0, 2) + +/* Inputs */ +enum tm6000_itype { + TM6000_INPUT_TV = 1, + TM6000_INPUT_COMPOSITE1, + TM6000_INPUT_COMPOSITE2, + TM6000_INPUT_SVIDEO, + TM6000_INPUT_DVB, + TM6000_INPUT_RADIO, +}; + +enum tm6000_mux { + TM6000_VMUX_VIDEO_A = 1, + TM6000_VMUX_VIDEO_B, + TM6000_VMUX_VIDEO_AB, + TM6000_AMUX_ADC1, + TM6000_AMUX_ADC2, + TM6000_AMUX_SIF1, + TM6000_AMUX_SIF2, + TM6000_AMUX_I2S, +}; + +enum tm6000_devtype { + TM6000 = 0, + TM5600, + TM6010, +}; + +struct tm6000_input { + enum tm6000_itype type; + enum tm6000_mux vmux; + enum tm6000_mux amux; + unsigned int v_gpio; + unsigned int a_gpio; +}; + +/* ------------------------------------------------------------------ + * Basic structures + * ------------------------------------------------------------------ + */ + +struct tm6000_fmt { + char *name; + u32 fourcc; /* v4l2 format id */ + int depth; +}; + +/* buffer for one video frame */ +struct tm6000_buffer { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + + struct tm6000_fmt *fmt; +}; + +struct tm6000_dmaqueue { + struct list_head active; + struct list_head queued; + + /* thread for generating video stream*/ + struct task_struct *kthread; + wait_queue_head_t wq; + /* Counters to control fps rate */ + int frame; + int ini_jiffies; +}; + +/* device states */ +enum tm6000_core_state { + DEV_INITIALIZED = 0x01, + DEV_DISCONNECTED = 0x02, + DEV_MISCONFIGURED = 0x04, +}; + +/* io methods */ +enum tm6000_io_method { + IO_NONE, + IO_READ, + IO_MMAP, +}; + +enum tm6000_mode { + TM6000_MODE_UNKNOWN = 0, + TM6000_MODE_ANALOG, + TM6000_MODE_DIGITAL, +}; + +struct tm6000_gpio { + int tuner_reset; + int tuner_on; + int demod_reset; + int demod_on; + int power_led; + int dvb_led; + int ir; +}; + +struct tm6000_capabilities { + unsigned int has_tuner:1; + unsigned int has_tda9874:1; + unsigned int has_dvb:1; + unsigned int has_zl10353:1; + unsigned int has_eeprom:1; + unsigned int has_remote:1; + unsigned int has_radio:1; +}; + +struct tm6000_dvb { + struct dvb_adapter adapter; + struct dvb_demux demux; + struct dvb_frontend *frontend; + struct dmxdev dmxdev; + unsigned int streams; + struct urb *bulk_urb; + struct mutex mutex; +}; + +struct snd_tm6000_card { + struct snd_card *card; + spinlock_t reg_lock; + struct tm6000_core *core; + struct snd_pcm_substream *substream; + + /* temporary data for buffer fill processing */ + unsigned buf_pos; + unsigned period_pos; +}; + +struct tm6000_endpoint { + struct usb_host_endpoint *endp; + __u8 bInterfaceNumber; + __u8 bAlternateSetting; + unsigned maxsize; +}; + +#define TM6000_QUIRK_NO_USB_DELAY (1 << 0) + +struct tm6000_core { + /* generic device properties */ + char name[30]; /* name (including minor) of the device */ + int model; /* index in the device_data struct */ + int devno; /* marks the number of this device */ + enum tm6000_devtype dev_type; /* type of device */ + unsigned char eedata[256]; /* Eeprom data */ + unsigned eedata_size; /* Size of the eeprom info */ + + v4l2_std_id norm; /* Current norm */ + int width, height; /* Selected resolution */ + + enum tm6000_core_state state; + + /* Device Capabilities*/ + struct tm6000_capabilities caps; + + /* Tuner configuration */ + int tuner_type; /* type of the tuner */ + int tuner_addr; /* tuner address */ + + struct tm6000_gpio gpio; + + char *ir_codes; + + __u8 radio; + + /* Demodulator configuration */ + int demod_addr; /* demodulator address */ + + int audio_bitrate; + /* i2c i/o */ + struct i2c_adapter i2c_adap; + struct i2c_client i2c_client; + + + /* extension */ + struct list_head devlist; + + /* video for linux */ + int users; + + /* various device info */ + struct tm6000_fh *resources; /* Points to fh that is streaming */ + bool is_res_read; + + struct video_device *vfd; + struct video_device *radio_dev; + struct tm6000_dmaqueue vidq; + struct v4l2_device v4l2_dev; + + int input; + struct tm6000_input vinput[3]; /* video input */ + struct tm6000_input rinput; /* radio input */ + + int freq; + unsigned int fourcc; + + enum tm6000_mode mode; + + int ctl_mute; /* audio */ + int ctl_volume; + int amode; + + /* DVB-T support */ + struct tm6000_dvb *dvb; + + /* audio support */ + struct snd_tm6000_card *adev; + struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */ + atomic_t stream_started; /* stream should be running if true */ + + struct tm6000_IR *ir; + + /* locks */ + struct mutex lock; + struct mutex usb_lock; + + /* usb transfer */ + struct usb_device *udev; /* the usb device */ + + struct tm6000_endpoint bulk_in, bulk_out, isoc_in, isoc_out; + struct tm6000_endpoint int_in, int_out; + + /* scaler!=0 if scaler is active*/ + int scaler; + + /* Isoc control struct */ + struct usb_isoc_ctl isoc_ctl; + + spinlock_t slock; + + unsigned long quirks; +}; + +enum tm6000_ops_type { + TM6000_AUDIO = 0x10, + TM6000_DVB = 0x20, +}; + +struct tm6000_ops { + struct list_head next; + char *name; + enum tm6000_ops_type type; + int (*init)(struct tm6000_core *); + int (*fini)(struct tm6000_core *); + int (*fillbuf)(struct tm6000_core *, char *buf, int size); +}; + +struct tm6000_fh { + struct tm6000_core *dev; + unsigned int radio; + + /* video capture */ + struct tm6000_fmt *fmt; + unsigned int width, height; + struct videobuf_queue vb_vidq; + + enum v4l2_buf_type type; +}; + +#define TM6000_STD (V4L2_STD_PAL|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc| \ + V4L2_STD_PAL_M|V4L2_STD_PAL_60|V4L2_STD_NTSC_M| \ + V4L2_STD_NTSC_M_JP|V4L2_STD_SECAM) + +/* In tm6000-cards.c */ + +int tm6000_tuner_callback(void *ptr, int component, int command, int arg); +int tm6000_xc5000_callback(void *ptr, int component, int command, int arg); +int tm6000_cards_setup(struct tm6000_core *dev); +void tm6000_flash_led(struct tm6000_core *dev, u8 state); + +/* In tm6000-core.c */ + +int tm6000_read_write_usb(struct tm6000_core *dev, u8 reqtype, u8 req, + u16 value, u16 index, u8 *buf, u16 len); +int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index); +int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index); +int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index); +int tm6000_set_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index); +int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value, + u16 index, u16 mask); +int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep); +int tm6000_init(struct tm6000_core *dev); +int tm6000_reset(struct tm6000_core *dev); + +int tm6000_init_analog_mode(struct tm6000_core *dev); +int tm6000_init_digital_mode(struct tm6000_core *dev); +int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate); +int tm6000_set_audio_rinput(struct tm6000_core *dev); +int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute); +void tm6000_set_volume(struct tm6000_core *dev, int vol); + +int tm6000_v4l2_register(struct tm6000_core *dev); +int tm6000_v4l2_unregister(struct tm6000_core *dev); +int tm6000_v4l2_exit(void); +void tm6000_set_fourcc_format(struct tm6000_core *dev); + +void tm6000_remove_from_devlist(struct tm6000_core *dev); +void tm6000_add_into_devlist(struct tm6000_core *dev); +int tm6000_register_extension(struct tm6000_ops *ops); +void tm6000_unregister_extension(struct tm6000_ops *ops); +void tm6000_init_extension(struct tm6000_core *dev); +void tm6000_close_extension(struct tm6000_core *dev); +int tm6000_call_fillbuf(struct tm6000_core *dev, enum tm6000_ops_type type, + char *buf, int size); + + +/* In tm6000-stds.c */ +void tm6000_get_std_res(struct tm6000_core *dev); +int tm6000_set_standard(struct tm6000_core *dev); + +/* In tm6000-i2c.c */ +int tm6000_i2c_register(struct tm6000_core *dev); +int tm6000_i2c_unregister(struct tm6000_core *dev); + +/* In tm6000-queue.c */ + +int tm6000_v4l2_mmap(struct file *filp, struct vm_area_struct *vma); + +int tm6000_vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type i); +int tm6000_vidioc_streamoff(struct file *file, void *priv, + enum v4l2_buf_type i); +int tm6000_vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *rb); +int tm6000_vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *b); +int tm6000_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b); +int tm6000_vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b); +ssize_t tm6000_v4l2_read(struct file *filp, char __user * buf, size_t count, + loff_t *f_pos); +unsigned int tm6000_v4l2_poll(struct file *file, + struct poll_table_struct *wait); +int tm6000_queue_init(struct tm6000_core *dev); + +/* In tm6000-alsa.c */ +/*int tm6000_audio_init(struct tm6000_core *dev, int idx);*/ + +/* In tm6000-input.c */ +int tm6000_ir_init(struct tm6000_core *dev); +int tm6000_ir_fini(struct tm6000_core *dev); +void tm6000_ir_wait(struct tm6000_core *dev, u8 state); +int tm6000_ir_int_start(struct tm6000_core *dev); +void tm6000_ir_int_stop(struct tm6000_core *dev); + +/* Debug stuff */ + +extern int tm6000_debug; + +#define dprintk(dev, level, fmt, arg...) do {\ + if (tm6000_debug & level) \ + printk(KERN_INFO "(%lu) %s %s :"fmt, jiffies, \ + dev->name, __func__ , ##arg); } while (0) + +#define V4L2_DEBUG_REG 0x0004 +#define V4L2_DEBUG_I2C 0x0008 +#define V4L2_DEBUG_QUEUE 0x0010 +#define V4L2_DEBUG_ISOC 0x0020 +#define V4L2_DEBUG_RES_LOCK 0x0040 /* Resource locking */ +#define V4L2_DEBUG_OPEN 0x0080 /* video open/close debug */ + +#define tm6000_err(fmt, arg...) do {\ + printk(KERN_ERR "tm6000 %s :"fmt, \ + __func__ , ##arg); } while (0) diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 06c9081..7209277 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -32,8 +32,6 @@ source "drivers/staging/go7007/Kconfig" source "drivers/staging/cx25821/Kconfig" -source "drivers/staging/tm6000/Kconfig" - source "drivers/staging/cxd2099/Kconfig" source "drivers/staging/usbip/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index f3c5e33..d44d25e 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -7,7 +7,6 @@ obj-$(CONFIG_ET131X) += et131x/ obj-$(CONFIG_SLICOSS) += slicoss/ obj-$(CONFIG_VIDEO_GO7007) += go7007/ obj-$(CONFIG_VIDEO_CX25821) += cx25821/ -obj-$(CONFIG_VIDEO_TM6000) += tm6000/ obj-$(CONFIG_DVB_CXD2099) += cxd2099/ obj-$(CONFIG_LIRC_STAGING) += lirc/ obj-$(CONFIG_USBIP_CORE) += usbip/ diff --git a/drivers/staging/tm6000/CARDLIST b/drivers/staging/tm6000/CARDLIST deleted file mode 100644 index b5edce4..0000000 --- a/drivers/staging/tm6000/CARDLIST +++ /dev/null @@ -1,16 +0,0 @@ - 1 -> Generic tm5600 board (tm5600) [6000:0001] - 2 -> Generic tm6000 board (tm6000) [6000:0001] - 3 -> Generic tm6010 board (tm6010) [6000:0002] - 4 -> 10Moons UT821 (tm5600) [6000:0001] - 5 -> 10Moons UT330 (tm5600) - 6 -> ADSTech Dual TV (tm6000) [06e1:f332] - 7 -> FreeCom and similar (tm6000) [14aa:0620] - 8 -> ADSTech Mini Dual TV (tm6000) [06e1:b339] - 9 -> Hauppauge WinTV HVR-900H/USB2 Stick (tm6010) [2040:6600,2040:6601,2040:6610,2040:6611] - 10 -> Beholder Wander (tm6010) [6000:dec0] - 11 -> Beholder Voyager (tm6010) [6000:dec1] - 12 -> TerraTec Cinergy Hybrid XE/Cinergy Hybrid Stick (tm6010) [0ccd:0086,0ccd:00a5] - 13 -> TwinHan TU501 (tm6010) [13d3:3240,13d3:3241,13d3:3243,13d3:3264] - 14 -> Beholder Wander Lite (tm6010) [6000:dec2] - 15 -> Beholder Voyager Lite (tm6010) [6000:dec3] - diff --git a/drivers/staging/tm6000/Kconfig b/drivers/staging/tm6000/Kconfig deleted file mode 100644 index 114eec8..0000000 --- a/drivers/staging/tm6000/Kconfig +++ /dev/null @@ -1,33 +0,0 @@ -config VIDEO_TM6000 - tristate "TV Master TM5600/6000/6010 driver" - depends on VIDEO_DEV && I2C && INPUT && RC_CORE && USB && EXPERIMENTAL - select VIDEO_TUNER - select MEDIA_TUNER_XC2028 - select MEDIA_TUNER_XC5000 - select VIDEOBUF_VMALLOC - help - Support for TM5600/TM6000/TM6010 USB Device - - Since these cards have no MPEG decoder onboard, they transmit - only compressed MPEG data over the usb bus, so you need - an external software decoder to watch TV on your computer. - - Say Y if you own such a device and want to use it. - -config VIDEO_TM6000_ALSA - tristate "TV Master TM5600/6000/6010 audio support" - depends on VIDEO_TM6000 && SND && EXPERIMENTAL - select SND_PCM - ---help--- - This is a video4linux driver for direct (DMA) audio for - TM5600/TM6000/TM6010 USB Devices. - - To compile this driver as a module, choose M here: the - module will be called tm6000-alsa. - -config VIDEO_TM6000_DVB - tristate "DVB Support for tm6000 based TV cards" - depends on VIDEO_TM6000 && DVB_CORE && USB && EXPERIMENTAL - select DVB_ZL10353 - ---help--- - This adds support for DVB cards based on the tm5600/tm6000 chip. diff --git a/drivers/staging/tm6000/Makefile b/drivers/staging/tm6000/Makefile deleted file mode 100644 index 395515b..0000000 --- a/drivers/staging/tm6000/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -tm6000-y := tm6000-cards.o \ - tm6000-core.o \ - tm6000-i2c.o \ - tm6000-video.o \ - tm6000-stds.o \ - tm6000-input.o - -obj-$(CONFIG_VIDEO_TM6000) += tm6000.o -obj-$(CONFIG_VIDEO_TM6000_ALSA) += tm6000-alsa.o -obj-$(CONFIG_VIDEO_TM6000_DVB) += tm6000-dvb.o - -ccflags-y := -Idrivers/media/video -ccflags-y += -Idrivers/media/common/tuners -ccflags-y += -Idrivers/media/dvb/dvb-core -ccflags-y += -Idrivers/media/dvb/frontends diff --git a/drivers/staging/tm6000/README b/drivers/staging/tm6000/README deleted file mode 100644 index c340ebc..0000000 --- a/drivers/staging/tm6000/README +++ /dev/null @@ -1,22 +0,0 @@ -Todo: - - Fix the loss of some blocks when receiving the video URB's - - Add a lock at tm6000_read_write_usb() to prevent two simultaneous access to the - URB control transfers - - Properly add the locks at tm6000-video - - Add audio support - - Add vbi support - - Add IR support - - Do several cleanups - - I think that frame1/frame0 are inverted. This causes a funny effect at the image. - the fix is trivial, but require some tests - - My tm6010 devices sometimes insist on stop working. I need to turn them off, removing - from my machine and wait for a while for it to work again. I'm starting to think that - it is an overheat issue - is there a workaround that we could do? - - Sometimes, tm6010 doesn't read eeprom at the proper time (hardware bug). So, the device - got miss-detected as a "generic" tm6000. This can be really bad if the tuner is the - Low Power one, as it may result on loading the high power firmware, that could damage - the device. Maybe we may read eeprom to double check, when the device is marked as "generic" - - Coding Style fixes - - sparse cleanups - -Please send patches to linux-media@vger.kernel.org diff --git a/drivers/staging/tm6000/TODO b/drivers/staging/tm6000/TODO deleted file mode 100644 index 135d0ea..0000000 --- a/drivers/staging/tm6000/TODO +++ /dev/null @@ -1,8 +0,0 @@ -There a few things to do before putting this driver in production: - - IR NEC with tm5600/6000 TV cards - - IR RC5 with tm5600/6000/6010 TV cards - - CodingStyle; - - Fix audio; - - Fix some panic/OOPS conditions. - -Please send patches to linux-media@vger.kernel.org diff --git a/drivers/staging/tm6000/tm6000-alsa.c b/drivers/staging/tm6000/tm6000-alsa.c deleted file mode 100644 index 7d675c7..0000000 --- a/drivers/staging/tm6000/tm6000-alsa.c +++ /dev/null @@ -1,513 +0,0 @@ -/* - * - * Support for audio capture for tm5600/6000/6010 - * (c) 2007-2008 Mauro Carvalho Chehab - * - * Based on cx88-alsa.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - - -#include "tm6000.h" -#include "tm6000-regs.h" - -#undef dprintk - -#define dprintk(level, fmt, arg...) do { \ - if (debug >= level) \ - printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg); \ - } while (0) - -/**************************************************************************** - Module global static vars - ****************************************************************************/ - -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ - -static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1}; - -module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "Enable tm6000x soundcard. default enabled."); - -module_param_array(index, int, NULL, 0444); -MODULE_PARM_DESC(index, "Index value for tm6000x capture interface(s)."); - - -/**************************************************************************** - Module macros - ****************************************************************************/ - -MODULE_DESCRIPTION("ALSA driver module for tm5600/tm6000/tm6010 based TV cards"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("{{Trident,tm5600}," - "{{Trident,tm6000}," - "{{Trident,tm6010}"); -static unsigned int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable debug messages"); - -/**************************************************************************** - Module specific funtions - ****************************************************************************/ - -/* - * BOARD Specific: Sets audio DMA - */ - -static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip) -{ - struct tm6000_core *core = chip->core; - - dprintk(1, "Starting audio DMA\n"); - - /* Enables audio */ - tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_IF, 0x40, 0x40); - - tm6000_set_audio_bitrate(core, 48000); - - return 0; -} - -/* - * BOARD Specific: Resets audio DMA - */ -static int _tm6000_stop_audio_dma(struct snd_tm6000_card *chip) -{ - struct tm6000_core *core = chip->core; - - dprintk(1, "Stopping audio DMA\n"); - - /* Disables audio */ - tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_IF, 0x00, 0x40); - - return 0; -} - -static void dsp_buffer_free(struct snd_pcm_substream *substream) -{ - struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); - - dprintk(2, "Freeing buffer\n"); - - vfree(substream->runtime->dma_area); - substream->runtime->dma_area = NULL; - substream->runtime->dma_bytes = 0; -} - -static int dsp_buffer_alloc(struct snd_pcm_substream *substream, int size) -{ - struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); - - dprintk(2, "Allocating buffer\n"); - - if (substream->runtime->dma_area) { - if (substream->runtime->dma_bytes > size) - return 0; - - dsp_buffer_free(substream); - } - - substream->runtime->dma_area = vmalloc(size); - if (!substream->runtime->dma_area) - return -ENOMEM; - - substream->runtime->dma_bytes = size; - - return 0; -} - - -/**************************************************************************** - ALSA PCM Interface - ****************************************************************************/ - -/* - * Digital hardware definition - */ -#define DEFAULT_FIFO_SIZE 4096 - -static struct snd_pcm_hardware snd_tm6000_digital_hw = { - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - - .rates = SNDRV_PCM_RATE_CONTINUOUS, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .period_bytes_min = 64, - .period_bytes_max = 12544, - .periods_min = 1, - .periods_max = 98, - .buffer_bytes_max = 62720 * 8, -}; - -/* - * audio pcm capture open callback - */ -static int snd_tm6000_pcm_open(struct snd_pcm_substream *substream) -{ - struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - int err; - - err = snd_pcm_hw_constraint_pow2(runtime, 0, - SNDRV_PCM_HW_PARAM_PERIODS); - if (err < 0) - goto _error; - - chip->substream = substream; - - runtime->hw = snd_tm6000_digital_hw; - - return 0; -_error: - dprintk(1, "Error opening PCM!\n"); - return err; -} - -/* - * audio close callback - */ -static int snd_tm6000_close(struct snd_pcm_substream *substream) -{ - struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); - struct tm6000_core *core = chip->core; - - if (atomic_read(&core->stream_started) > 0) { - atomic_set(&core->stream_started, 0); - schedule_work(&core->wq_trigger); - } - - return 0; -} - -static int tm6000_fillbuf(struct tm6000_core *core, char *buf, int size) -{ - struct snd_tm6000_card *chip = core->adev; - struct snd_pcm_substream *substream = chip->substream; - struct snd_pcm_runtime *runtime; - int period_elapsed = 0; - unsigned int stride, buf_pos; - int length; - - if (atomic_read(&core->stream_started) == 0) - return 0; - - if (!size || !substream) { - dprintk(1, "substream was NULL\n"); - return -EINVAL; - } - - runtime = substream->runtime; - if (!runtime || !runtime->dma_area) { - dprintk(1, "runtime was NULL\n"); - return -EINVAL; - } - - buf_pos = chip->buf_pos; - stride = runtime->frame_bits >> 3; - - if (stride == 0) { - dprintk(1, "stride is zero\n"); - return -EINVAL; - } - - length = size / stride; - if (length == 0) { - dprintk(1, "%s: length was zero\n", __func__); - return -EINVAL; - } - - dprintk(1, "Copying %d bytes at %p[%d] - buf size=%d x %d\n", size, - runtime->dma_area, buf_pos, - (unsigned int)runtime->buffer_size, stride); - - if (buf_pos + length >= runtime->buffer_size) { - unsigned int cnt = runtime->buffer_size - buf_pos; - memcpy(runtime->dma_area + buf_pos * stride, buf, cnt * stride); - memcpy(runtime->dma_area, buf + cnt * stride, - length * stride - cnt * stride); - } else - memcpy(runtime->dma_area + buf_pos * stride, buf, - length * stride); - - snd_pcm_stream_lock(substream); - - chip->buf_pos += length; - if (chip->buf_pos >= runtime->buffer_size) - chip->buf_pos -= runtime->buffer_size; - - chip->period_pos += length; - if (chip->period_pos >= runtime->period_size) { - chip->period_pos -= runtime->period_size; - period_elapsed = 1; - } - - snd_pcm_stream_unlock(substream); - - if (period_elapsed) - snd_pcm_period_elapsed(substream); - - return 0; -} - -/* - * hw_params callback - */ -static int snd_tm6000_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - int size, rc; - - size = params_period_bytes(hw_params) * params_periods(hw_params); - - rc = dsp_buffer_alloc(substream, size); - if (rc < 0) - return rc; - - return 0; -} - -/* - * hw free callback - */ -static int snd_tm6000_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); - struct tm6000_core *core = chip->core; - - if (atomic_read(&core->stream_started) > 0) { - atomic_set(&core->stream_started, 0); - schedule_work(&core->wq_trigger); - } - - dsp_buffer_free(substream); - return 0; -} - -/* - * prepare callback - */ -static int snd_tm6000_prepare(struct snd_pcm_substream *substream) -{ - struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); - - chip->buf_pos = 0; - chip->period_pos = 0; - - return 0; -} - - -/* - * trigger callback - */ -static void audio_trigger(struct work_struct *work) -{ - struct tm6000_core *core = container_of(work, struct tm6000_core, - wq_trigger); - struct snd_tm6000_card *chip = core->adev; - - if (atomic_read(&core->stream_started)) { - dprintk(1, "starting capture"); - _tm6000_start_audio_dma(chip); - } else { - dprintk(1, "stopping capture"); - _tm6000_stop_audio_dma(chip); - } -} - -static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); - struct tm6000_core *core = chip->core; - int err = 0; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - atomic_set(&core->stream_started, 1); - break; - case SNDRV_PCM_TRIGGER_STOP: - atomic_set(&core->stream_started, 0); - break; - default: - err = -EINVAL; - break; - } - schedule_work(&core->wq_trigger); - - return err; -} -/* - * pointer callback - */ -static snd_pcm_uframes_t snd_tm6000_pointer(struct snd_pcm_substream *substream) -{ - struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); - - return chip->buf_pos; -} - -/* - * operators - */ -static struct snd_pcm_ops snd_tm6000_pcm_ops = { - .open = snd_tm6000_pcm_open, - .close = snd_tm6000_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_tm6000_hw_params, - .hw_free = snd_tm6000_hw_free, - .prepare = snd_tm6000_prepare, - .trigger = snd_tm6000_card_trigger, - .pointer = snd_tm6000_pointer, -}; - -/* - * create a PCM device - */ - -/* FIXME: Control interface - How to control volume/mute? */ - -/**************************************************************************** - Basic Flow for Sound Devices - ****************************************************************************/ - -/* - * Alsa Constructor - Component probe - */ -static int tm6000_audio_init(struct tm6000_core *dev) -{ - struct snd_card *card; - struct snd_tm6000_card *chip; - int rc; - static int devnr; - char component[14]; - struct snd_pcm *pcm; - - if (!dev) - return 0; - - if (devnr >= SNDRV_CARDS) - return -ENODEV; - - if (!enable[devnr]) - return -ENOENT; - - rc = snd_card_create(index[devnr], "tm6000", THIS_MODULE, 0, &card); - if (rc < 0) { - snd_printk(KERN_ERR "cannot create card instance %d\n", devnr); - return rc; - } - strcpy(card->driver, "tm6000-alsa"); - strcpy(card->shortname, "TM5600/60x0"); - sprintf(card->longname, "TM5600/60x0 Audio at bus %d device %d", - dev->udev->bus->busnum, dev->udev->devnum); - - sprintf(component, "USB%04x:%04x", - le16_to_cpu(dev->udev->descriptor.idVendor), - le16_to_cpu(dev->udev->descriptor.idProduct)); - snd_component_add(card, component); - snd_card_set_dev(card, &dev->udev->dev); - - chip = kzalloc(sizeof(struct snd_tm6000_card), GFP_KERNEL); - if (!chip) { - rc = -ENOMEM; - goto error; - } - - chip->core = dev; - chip->card = card; - dev->adev = chip; - spin_lock_init(&chip->reg_lock); - - rc = snd_pcm_new(card, "TM6000 Audio", 0, 0, 1, &pcm); - if (rc < 0) - goto error_chip; - - pcm->info_flags = 0; - pcm->private_data = chip; - strcpy(pcm->name, "Trident TM5600/60x0"); - - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops); - - INIT_WORK(&dev->wq_trigger, audio_trigger); - rc = snd_card_register(card); - if (rc < 0) - goto error_chip; - - dprintk(1, "Registered audio driver for %s\n", card->longname); - - return 0; - -error_chip: - kfree(chip); - dev->adev = NULL; -error: - snd_card_free(card); - return rc; -} - -static int tm6000_audio_fini(struct tm6000_core *dev) -{ - struct snd_tm6000_card *chip = dev->adev; - - if (!dev) - return 0; - - if (!chip) - return 0; - - if (!chip->card) - return 0; - - snd_card_free(chip->card); - chip->card = NULL; - kfree(chip); - dev->adev = NULL; - - return 0; -} - -static struct tm6000_ops audio_ops = { - .type = TM6000_AUDIO, - .name = "TM6000 Audio Extension", - .init = tm6000_audio_init, - .fini = tm6000_audio_fini, - .fillbuf = tm6000_fillbuf, -}; - -static int __init tm6000_alsa_register(void) -{ - return tm6000_register_extension(&audio_ops); -} - -static void __exit tm6000_alsa_unregister(void) -{ - tm6000_unregister_extension(&audio_ops); -} - -module_init(tm6000_alsa_register); -module_exit(tm6000_alsa_unregister); diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c deleted file mode 100644 index ec2578a..0000000 --- a/drivers/staging/tm6000/tm6000-cards.c +++ /dev/null @@ -1,1402 +0,0 @@ -/* - * tm6000-cards.c - driver for TM5600/TM6000/TM6010 USB video capture devices - * - * Copyright (C) 2006-2007 Mauro Carvalho Chehab - * - * 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 version 2 - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tm6000.h" -#include "tm6000-regs.h" -#include "tuner-xc2028.h" -#include "xc5000.h" - -#define TM6000_BOARD_UNKNOWN 0 -#define TM5600_BOARD_GENERIC 1 -#define TM6000_BOARD_GENERIC 2 -#define TM6010_BOARD_GENERIC 3 -#define TM5600_BOARD_10MOONS_UT821 4 -#define TM5600_BOARD_10MOONS_UT330 5 -#define TM6000_BOARD_ADSTECH_DUAL_TV 6 -#define TM6000_BOARD_FREECOM_AND_SIMILAR 7 -#define TM6000_BOARD_ADSTECH_MINI_DUAL_TV 8 -#define TM6010_BOARD_HAUPPAUGE_900H 9 -#define TM6010_BOARD_BEHOLD_WANDER 10 -#define TM6010_BOARD_BEHOLD_VOYAGER 11 -#define TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE 12 -#define TM6010_BOARD_TWINHAN_TU501 13 -#define TM6010_BOARD_BEHOLD_WANDER_LITE 14 -#define TM6010_BOARD_BEHOLD_VOYAGER_LITE 15 -#define TM5600_BOARD_TERRATEC_GRABSTER 16 - -#define is_generic(model) ((model == TM6000_BOARD_UNKNOWN) || \ - (model == TM5600_BOARD_GENERIC) || \ - (model == TM6000_BOARD_GENERIC) || \ - (model == TM6010_BOARD_GENERIC)) - -#define TM6000_MAXBOARDS 16 -static unsigned int card[] = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET }; - -module_param_array(card, int, NULL, 0444); - -static unsigned long tm6000_devused; - - -struct tm6000_board { - char *name; - char eename[16]; /* EEPROM name */ - unsigned eename_size; /* size of EEPROM name */ - unsigned eename_pos; /* Position where it appears at ROM */ - - struct tm6000_capabilities caps; - - enum tm6000_devtype type; /* variant of the chipset */ - int tuner_type; /* type of the tuner */ - int tuner_addr; /* tuner address */ - int demod_addr; /* demodulator address */ - - struct tm6000_gpio gpio; - - struct tm6000_input vinput[3]; - struct tm6000_input rinput; - - char *ir_codes; -}; - -static struct tm6000_board tm6000_boards[] = { - [TM6000_BOARD_UNKNOWN] = { - .name = "Unknown tm6000 video grabber", - .caps = { - .has_tuner = 1, - .has_eeprom = 1, - }, - .gpio = { - .tuner_reset = TM6000_GPIO_1, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_ADC1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - }, - [TM5600_BOARD_GENERIC] = { - .name = "Generic tm5600 board", - .type = TM5600, - .tuner_type = TUNER_XC2028, - .tuner_addr = 0xc2 >> 1, - .caps = { - .has_tuner = 1, - .has_eeprom = 1, - }, - .gpio = { - .tuner_reset = TM6000_GPIO_1, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_ADC1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - }, - [TM6000_BOARD_GENERIC] = { - .name = "Generic tm6000 board", - .tuner_type = TUNER_XC2028, - .tuner_addr = 0xc2 >> 1, - .caps = { - .has_tuner = 1, - .has_eeprom = 1, - }, - .gpio = { - .tuner_reset = TM6000_GPIO_1, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_ADC1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - }, - [TM6010_BOARD_GENERIC] = { - .name = "Generic tm6010 board", - .type = TM6010, - .tuner_type = TUNER_XC2028, - .tuner_addr = 0xc2 >> 1, - .demod_addr = 0x1e >> 1, - .caps = { - .has_tuner = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 1, - .has_remote = 1, - }, - .gpio = { - .tuner_reset = TM6010_GPIO_2, - .tuner_on = TM6010_GPIO_3, - .demod_reset = TM6010_GPIO_1, - .demod_on = TM6010_GPIO_4, - .power_led = TM6010_GPIO_7, - .dvb_led = TM6010_GPIO_5, - .ir = TM6010_GPIO_0, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_SIF1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - }, - [TM5600_BOARD_10MOONS_UT821] = { - .name = "10Moons UT 821", - .tuner_type = TUNER_XC2028, - .eename = { '1', '0', 'M', 'O', 'O', 'N', 'S', '5', '6', '0', '0', 0xff, 0x45, 0x5b}, - .eename_size = 14, - .eename_pos = 0x14, - .type = TM5600, - .tuner_addr = 0xc2 >> 1, - .caps = { - .has_tuner = 1, - .has_eeprom = 1, - }, - .gpio = { - .tuner_reset = TM6000_GPIO_1, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_ADC1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - }, - [TM5600_BOARD_10MOONS_UT330] = { - .name = "10Moons UT 330", - .tuner_type = TUNER_PHILIPS_FQ1216AME_MK4, - .tuner_addr = 0xc8 >> 1, - .caps = { - .has_tuner = 1, - .has_dvb = 0, - .has_zl10353 = 0, - .has_eeprom = 1, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_ADC1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - }, - [TM6000_BOARD_ADSTECH_DUAL_TV] = { - .name = "ADSTECH Dual TV USB", - .tuner_type = TUNER_XC2028, - .tuner_addr = 0xc8 >> 1, - .caps = { - .has_tuner = 1, - .has_tda9874 = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 1, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_ADC1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - }, - [TM6000_BOARD_FREECOM_AND_SIMILAR] = { - .name = "Freecom Hybrid Stick / Moka DVB-T Receiver Dual", - .tuner_type = TUNER_XC2028, /* has a XC3028 */ - .tuner_addr = 0xc2 >> 1, - .demod_addr = 0x1e >> 1, - .caps = { - .has_tuner = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 0, - .has_remote = 1, - }, - .gpio = { - .tuner_reset = TM6000_GPIO_4, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_ADC1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - }, - [TM6000_BOARD_ADSTECH_MINI_DUAL_TV] = { - .name = "ADSTECH Mini Dual TV USB", - .tuner_type = TUNER_XC2028, /* has a XC3028 */ - .tuner_addr = 0xc8 >> 1, - .demod_addr = 0x1e >> 1, - .caps = { - .has_tuner = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 0, - }, - .gpio = { - .tuner_reset = TM6000_GPIO_4, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_ADC1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - }, - [TM6010_BOARD_HAUPPAUGE_900H] = { - .name = "Hauppauge WinTV HVR-900H / WinTV USB2-Stick", - .eename = { 'H', 0, 'V', 0, 'R', 0, '9', 0, '0', 0, '0', 0, 'H', 0 }, - .eename_size = 14, - .eename_pos = 0x42, - .tuner_type = TUNER_XC2028, /* has a XC3028 */ - .tuner_addr = 0xc2 >> 1, - .demod_addr = 0x1e >> 1, - .type = TM6010, - .caps = { - .has_tuner = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 1, - .has_remote = 1, - }, - .gpio = { - .tuner_reset = TM6010_GPIO_2, - .tuner_on = TM6010_GPIO_3, - .demod_reset = TM6010_GPIO_1, - .demod_on = TM6010_GPIO_4, - .power_led = TM6010_GPIO_7, - .dvb_led = TM6010_GPIO_5, - .ir = TM6010_GPIO_0, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_SIF1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - }, - [TM6010_BOARD_BEHOLD_WANDER] = { - .name = "Beholder Wander DVB-T/TV/FM USB2.0", - .tuner_type = TUNER_XC5000, - .tuner_addr = 0xc2 >> 1, - .demod_addr = 0x1e >> 1, - .type = TM6010, - .caps = { - .has_tuner = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 1, - .has_remote = 1, - .has_radio = 1, - }, - .gpio = { - .tuner_reset = TM6010_GPIO_0, - .demod_reset = TM6010_GPIO_1, - .power_led = TM6010_GPIO_6, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_SIF1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - .rinput = { - .type = TM6000_INPUT_RADIO, - .amux = TM6000_AMUX_ADC1, - }, - }, - [TM6010_BOARD_BEHOLD_VOYAGER] = { - .name = "Beholder Voyager TV/FM USB2.0", - .tuner_type = TUNER_XC5000, - .tuner_addr = 0xc2 >> 1, - .type = TM6010, - .caps = { - .has_tuner = 1, - .has_dvb = 0, - .has_zl10353 = 0, - .has_eeprom = 1, - .has_remote = 1, - .has_radio = 1, - }, - .gpio = { - .tuner_reset = TM6010_GPIO_0, - .power_led = TM6010_GPIO_6, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_SIF1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - .rinput = { - .type = TM6000_INPUT_RADIO, - .amux = TM6000_AMUX_ADC1, - }, - }, - [TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = { - .name = "Terratec Cinergy Hybrid XE / Cinergy Hybrid-Stick", - .tuner_type = TUNER_XC2028, /* has a XC3028 */ - .tuner_addr = 0xc2 >> 1, - .demod_addr = 0x1e >> 1, - .type = TM6010, - .caps = { - .has_tuner = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 1, - .has_remote = 1, - .has_radio = 1, - }, - .gpio = { - .tuner_reset = TM6010_GPIO_2, - .tuner_on = TM6010_GPIO_3, - .demod_reset = TM6010_GPIO_1, - .demod_on = TM6010_GPIO_4, - .power_led = TM6010_GPIO_7, - .dvb_led = TM6010_GPIO_5, - .ir = TM6010_GPIO_0, - }, - .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_SIF1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - .rinput = { - .type = TM6000_INPUT_RADIO, - .amux = TM6000_AMUX_SIF1, - }, - }, - [TM5600_BOARD_TERRATEC_GRABSTER] = { - .name = "Terratec Grabster AV 150/250 MX", - .type = TM5600, - .tuner_type = TUNER_ABSENT, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_ADC1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - }, - [TM6010_BOARD_TWINHAN_TU501] = { - .name = "Twinhan TU501(704D1)", - .tuner_type = TUNER_XC2028, /* has a XC3028 */ - .tuner_addr = 0xc2 >> 1, - .demod_addr = 0x1e >> 1, - .type = TM6010, - .caps = { - .has_tuner = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 1, - .has_remote = 1, - }, - .gpio = { - .tuner_reset = TM6010_GPIO_2, - .tuner_on = TM6010_GPIO_3, - .demod_reset = TM6010_GPIO_1, - .demod_on = TM6010_GPIO_4, - .power_led = TM6010_GPIO_7, - .dvb_led = TM6010_GPIO_5, - .ir = TM6010_GPIO_0, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_SIF1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - }, - [TM6010_BOARD_BEHOLD_WANDER_LITE] = { - .name = "Beholder Wander Lite DVB-T/TV/FM USB2.0", - .tuner_type = TUNER_XC5000, - .tuner_addr = 0xc2 >> 1, - .demod_addr = 0x1e >> 1, - .type = TM6010, - .caps = { - .has_tuner = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 1, - .has_remote = 0, - .has_radio = 1, - }, - .gpio = { - .tuner_reset = TM6010_GPIO_0, - .demod_reset = TM6010_GPIO_1, - .power_led = TM6010_GPIO_6, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_SIF1, - }, - }, - .rinput = { - .type = TM6000_INPUT_RADIO, - .amux = TM6000_AMUX_ADC1, - }, - }, - [TM6010_BOARD_BEHOLD_VOYAGER_LITE] = { - .name = "Beholder Voyager Lite TV/FM USB2.0", - .tuner_type = TUNER_XC5000, - .tuner_addr = 0xc2 >> 1, - .type = TM6010, - .caps = { - .has_tuner = 1, - .has_dvb = 0, - .has_zl10353 = 0, - .has_eeprom = 1, - .has_remote = 0, - .has_radio = 1, - }, - .gpio = { - .tuner_reset = TM6010_GPIO_0, - .power_led = TM6010_GPIO_6, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_SIF1, - }, - }, - .rinput = { - .type = TM6000_INPUT_RADIO, - .amux = TM6000_AMUX_ADC1, - }, - }, -}; - -/* table of devices that work with this driver */ -static struct usb_device_id tm6000_id_table[] = { - { USB_DEVICE(0x6000, 0x0001), .driver_info = TM5600_BOARD_GENERIC }, - { USB_DEVICE(0x6000, 0x0002), .driver_info = TM6010_BOARD_GENERIC }, - { USB_DEVICE(0x06e1, 0xf332), .driver_info = TM6000_BOARD_ADSTECH_DUAL_TV }, - { USB_DEVICE(0x14aa, 0x0620), .driver_info = TM6000_BOARD_FREECOM_AND_SIMILAR }, - { USB_DEVICE(0x06e1, 0xb339), .driver_info = TM6000_BOARD_ADSTECH_MINI_DUAL_TV }, - { USB_DEVICE(0x2040, 0x6600), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, - { USB_DEVICE(0x2040, 0x6601), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, - { USB_DEVICE(0x2040, 0x6610), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, - { USB_DEVICE(0x2040, 0x6611), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, - { USB_DEVICE(0x6000, 0xdec0), .driver_info = TM6010_BOARD_BEHOLD_WANDER }, - { USB_DEVICE(0x6000, 0xdec1), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER }, - { USB_DEVICE(0x0ccd, 0x0086), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE }, - { USB_DEVICE(0x0ccd, 0x00A5), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE }, - { USB_DEVICE(0x0ccd, 0x0079), .driver_info = TM5600_BOARD_TERRATEC_GRABSTER }, - { USB_DEVICE(0x13d3, 0x3240), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, - { USB_DEVICE(0x13d3, 0x3241), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, - { USB_DEVICE(0x13d3, 0x3243), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, - { USB_DEVICE(0x13d3, 0x3264), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, - { USB_DEVICE(0x6000, 0xdec2), .driver_info = TM6010_BOARD_BEHOLD_WANDER_LITE }, - { USB_DEVICE(0x6000, 0xdec3), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER_LITE }, - { } -}; - -/* Control power led for show some activity */ -void tm6000_flash_led(struct tm6000_core *dev, u8 state) -{ - /* Power LED unconfigured */ - if (!dev->gpio.power_led) - return; - - /* ON Power LED */ - if (state) { - switch (dev->model) { - case TM6010_BOARD_HAUPPAUGE_900H: - case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: - case TM6010_BOARD_TWINHAN_TU501: - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.power_led, 0x00); - break; - case TM6010_BOARD_BEHOLD_WANDER: - case TM6010_BOARD_BEHOLD_VOYAGER: - case TM6010_BOARD_BEHOLD_WANDER_LITE: - case TM6010_BOARD_BEHOLD_VOYAGER_LITE: - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.power_led, 0x01); - break; - } - } - /* OFF Power LED */ - else { - switch (dev->model) { - case TM6010_BOARD_HAUPPAUGE_900H: - case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: - case TM6010_BOARD_TWINHAN_TU501: - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.power_led, 0x01); - break; - case TM6010_BOARD_BEHOLD_WANDER: - case TM6010_BOARD_BEHOLD_VOYAGER: - case TM6010_BOARD_BEHOLD_WANDER_LITE: - case TM6010_BOARD_BEHOLD_VOYAGER_LITE: - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.power_led, 0x00); - break; - } - } -} - -/* Tuner callback to provide the proper gpio changes needed for xc5000 */ -int tm6000_xc5000_callback(void *ptr, int component, int command, int arg) -{ - int rc = 0; - struct tm6000_core *dev = ptr; - - if (dev->tuner_type != TUNER_XC5000) - return 0; - - switch (command) { - case XC5000_TUNER_RESET: - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x01); - msleep(15); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x00); - msleep(15); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x01); - break; - } - return rc; -} -EXPORT_SYMBOL_GPL(tm6000_xc5000_callback); - -/* Tuner callback to provide the proper gpio changes needed for xc2028 */ - -int tm6000_tuner_callback(void *ptr, int component, int command, int arg) -{ - int rc = 0; - struct tm6000_core *dev = ptr; - - if (dev->tuner_type != TUNER_XC2028) - return 0; - - switch (command) { - case XC2028_RESET_CLK: - tm6000_ir_wait(dev, 0); - - tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, - 0x02, arg); - msleep(10); - rc = tm6000_i2c_reset(dev, 10); - break; - case XC2028_TUNER_RESET: - /* Reset codes during load firmware */ - switch (arg) { - case 0: - /* newer tuner can faster reset */ - switch (dev->model) { - case TM5600_BOARD_10MOONS_UT821: - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x01); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - 0x300, 0x01); - msleep(10); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x00); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - 0x300, 0x00); - msleep(10); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x01); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - 0x300, 0x01); - break; - case TM6010_BOARD_HAUPPAUGE_900H: - case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: - case TM6010_BOARD_TWINHAN_TU501: - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x01); - msleep(60); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x00); - msleep(75); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x01); - msleep(60); - break; - default: - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x00); - msleep(130); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x01); - msleep(130); - break; - } - - tm6000_ir_wait(dev, 1); - break; - case 1: - tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, - 0x02, 0x01); - msleep(10); - break; - case 2: - rc = tm6000_i2c_reset(dev, 100); - break; - } - break; - case XC2028_I2C_FLUSH: - tm6000_set_reg(dev, REQ_50_SET_START, 0, 0); - tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0); - break; - } - return rc; -} -EXPORT_SYMBOL_GPL(tm6000_tuner_callback); - -int tm6000_cards_setup(struct tm6000_core *dev) -{ - /* - * Board-specific initialization sequence. Handles all GPIO - * initialization sequences that are board-specific. - * Up to now, all found devices use GPIO1 and GPIO4 at the same way. - * Probably, they're all based on some reference device. Due to that, - * there's a common routine at the end to handle those GPIO's. Devices - * that use different pinups or init sequences can just return at - * the board-specific session. - */ - switch (dev->model) { - case TM6010_BOARD_HAUPPAUGE_900H: - case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: - case TM6010_BOARD_TWINHAN_TU501: - case TM6010_BOARD_GENERIC: - /* Turn xceive 3028 on */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.tuner_on, 0x01); - msleep(15); - /* Turn zarlink zl10353 on */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00); - msleep(15); - /* Reset zarlink zl10353 */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00); - msleep(50); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01); - msleep(15); - /* Turn zarlink zl10353 off */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x01); - msleep(15); - /* ir ? */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.ir, 0x01); - msleep(15); - /* Power led on (blue) */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x00); - msleep(15); - /* DVB led off (orange) */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.dvb_led, 0x01); - msleep(15); - /* Turn zarlink zl10353 on */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00); - msleep(15); - break; - case TM6010_BOARD_BEHOLD_WANDER: - case TM6010_BOARD_BEHOLD_WANDER_LITE: - /* Power led on (blue) */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01); - msleep(15); - /* Reset zarlink zl10353 */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00); - msleep(50); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01); - msleep(15); - break; - case TM6010_BOARD_BEHOLD_VOYAGER: - case TM6010_BOARD_BEHOLD_VOYAGER_LITE: - /* Power led on (blue) */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01); - msleep(15); - break; - default: - break; - } - - /* - * Default initialization. Most of the devices seem to use GPIO1 - * and GPIO4.on the same way, so, this handles the common sequence - * used by most devices. - * If a device uses a different sequence or different GPIO pins for - * reset, just add the code at the board-specific part - */ - - if (dev->gpio.tuner_reset) { - int rc; - int i; - - for (i = 0; i < 2; i++) { - rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x00); - if (rc < 0) { - printk(KERN_ERR "Error %i doing tuner reset\n", rc); - return rc; - } - - msleep(10); /* Just to be conservative */ - rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x01); - if (rc < 0) { - printk(KERN_ERR "Error %i doing tuner reset\n", rc); - return rc; - } - } - } else { - printk(KERN_ERR "Tuner reset is not configured\n"); - return -1; - } - - msleep(50); - - return 0; -}; - -static void tm6000_config_tuner(struct tm6000_core *dev) -{ - struct tuner_setup tun_setup; - - /* Load tuner module */ - v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, - "tuner", dev->tuner_addr, NULL); - - memset(&tun_setup, 0, sizeof(tun_setup)); - tun_setup.type = dev->tuner_type; - tun_setup.addr = dev->tuner_addr; - - tun_setup.mode_mask = 0; - if (dev->caps.has_tuner) - tun_setup.mode_mask |= (T_ANALOG_TV | T_RADIO); - - switch (dev->tuner_type) { - case TUNER_XC2028: - tun_setup.tuner_callback = tm6000_tuner_callback; - break; - case TUNER_XC5000: - tun_setup.tuner_callback = tm6000_xc5000_callback; - break; - } - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup); - - switch (dev->tuner_type) { - case TUNER_XC2028: { - struct v4l2_priv_tun_config xc2028_cfg; - struct xc2028_ctrl ctl; - - memset(&xc2028_cfg, 0, sizeof(xc2028_cfg)); - memset(&ctl, 0, sizeof(ctl)); - - ctl.demod = XC3028_FE_ZARLINK456; - - xc2028_cfg.tuner = TUNER_XC2028; - xc2028_cfg.priv = &ctl; - - switch (dev->model) { - case TM6010_BOARD_HAUPPAUGE_900H: - case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: - case TM6010_BOARD_TWINHAN_TU501: - ctl.fname = "xc3028L-v36.fw"; - break; - default: - if (dev->dev_type == TM6010) - ctl.fname = "xc3028-v27.fw"; - else - ctl.fname = "xc3028-v24.fw"; - } - - printk(KERN_INFO "Setting firmware parameters for xc2028\n"); - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, - &xc2028_cfg); - - } - break; - case TUNER_XC5000: - { - struct v4l2_priv_tun_config xc5000_cfg; - struct xc5000_config ctl = { - .i2c_address = dev->tuner_addr, - .if_khz = 4570, - .radio_input = XC5000_RADIO_FM1_MONO, - }; - - xc5000_cfg.tuner = TUNER_XC5000; - xc5000_cfg.priv = &ctl; - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, - &xc5000_cfg); - } - break; - default: - printk(KERN_INFO "Unknown tuner type. Tuner is not configured.\n"); - break; - } -} - -static int fill_board_specific_data(struct tm6000_core *dev) -{ - int rc; - - dev->dev_type = tm6000_boards[dev->model].type; - dev->tuner_type = tm6000_boards[dev->model].tuner_type; - dev->tuner_addr = tm6000_boards[dev->model].tuner_addr; - - dev->gpio = tm6000_boards[dev->model].gpio; - - dev->ir_codes = tm6000_boards[dev->model].ir_codes; - - dev->demod_addr = tm6000_boards[dev->model].demod_addr; - - dev->caps = tm6000_boards[dev->model].caps; - - dev->vinput[0] = tm6000_boards[dev->model].vinput[0]; - dev->vinput[1] = tm6000_boards[dev->model].vinput[1]; - dev->vinput[2] = tm6000_boards[dev->model].vinput[2]; - dev->rinput = tm6000_boards[dev->model].rinput; - - /* setup per-model quirks */ - switch (dev->model) { - case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: - dev->quirks |= TM6000_QUIRK_NO_USB_DELAY; - break; - - default: - break; - } - - /* initialize hardware */ - rc = tm6000_init(dev); - if (rc < 0) - return rc; - - return v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev); -} - - -static void use_alternative_detection_method(struct tm6000_core *dev) -{ - int i, model = -1; - - if (!dev->eedata_size) - return; - - for (i = 0; i < ARRAY_SIZE(tm6000_boards); i++) { - if (!tm6000_boards[i].eename_size) - continue; - if (dev->eedata_size < tm6000_boards[i].eename_pos + - tm6000_boards[i].eename_size) - continue; - - if (!memcmp(&dev->eedata[tm6000_boards[i].eename_pos], - tm6000_boards[i].eename, - tm6000_boards[i].eename_size)) { - model = i; - break; - } - } - if (model < 0) { - printk(KERN_INFO "Device has eeprom but is currently unknown\n"); - return; - } - - dev->model = model; - - printk(KERN_INFO "Device identified via eeprom as %s (type = %d)\n", - tm6000_boards[model].name, model); -} - -static int tm6000_init_dev(struct tm6000_core *dev) -{ - struct v4l2_frequency f; - int rc = 0; - - mutex_init(&dev->lock); - mutex_lock(&dev->lock); - - if (!is_generic(dev->model)) { - rc = fill_board_specific_data(dev); - if (rc < 0) - goto err; - - /* register i2c bus */ - rc = tm6000_i2c_register(dev); - if (rc < 0) - goto err; - } else { - /* register i2c bus */ - rc = tm6000_i2c_register(dev); - if (rc < 0) - goto err; - - use_alternative_detection_method(dev); - - rc = fill_board_specific_data(dev); - if (rc < 0) - goto err; - } - - /* Default values for STD and resolutions */ - dev->width = 720; - dev->height = 480; - dev->norm = V4L2_STD_PAL_M; - - /* Configure tuner */ - tm6000_config_tuner(dev); - - /* Set video standard */ - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm); - - /* Set tuner frequency - also loads firmware on xc2028/xc3028 */ - f.tuner = 0; - f.type = V4L2_TUNER_ANALOG_TV; - f.frequency = 3092; /* 193.25 MHz */ - dev->freq = f.frequency; - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f); - - if (dev->caps.has_tda9874) - v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, - "tvaudio", I2C_ADDR_TDA9874, NULL); - - /* register and initialize V4L2 */ - rc = tm6000_v4l2_register(dev); - if (rc < 0) - goto err; - - tm6000_add_into_devlist(dev); - tm6000_init_extension(dev); - - tm6000_ir_init(dev); - - mutex_unlock(&dev->lock); - return 0; - -err: - mutex_unlock(&dev->lock); - return rc; -} - -/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */ -#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03)) - -static void get_max_endpoint(struct usb_device *udev, - struct usb_host_interface *alt, - char *msgtype, - struct usb_host_endpoint *curr_e, - struct tm6000_endpoint *tm_ep) -{ - u16 tmp = le16_to_cpu(curr_e->desc.wMaxPacketSize); - unsigned int size = tmp & 0x7ff; - - if (udev->speed == USB_SPEED_HIGH) - size = size * hb_mult(tmp); - - if (size > tm_ep->maxsize) { - tm_ep->endp = curr_e; - tm_ep->maxsize = size; - tm_ep->bInterfaceNumber = alt->desc.bInterfaceNumber; - tm_ep->bAlternateSetting = alt->desc.bAlternateSetting; - - printk(KERN_INFO "tm6000: %s endpoint: 0x%02x (max size=%u bytes)\n", - msgtype, curr_e->desc.bEndpointAddress, - size); - } -} - -/* - * tm6000_usb_probe() - * checks for supported devices - */ -static int tm6000_usb_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_device *usbdev; - struct tm6000_core *dev = NULL; - int i, rc = 0; - int nr = 0; - char *speed; - - usbdev = usb_get_dev(interface_to_usbdev(interface)); - - /* Selects the proper interface */ - rc = usb_set_interface(usbdev, 0, 1); - if (rc < 0) - goto err; - - /* Check to see next free device and mark as used */ - nr = find_first_zero_bit(&tm6000_devused, TM6000_MAXBOARDS); - if (nr >= TM6000_MAXBOARDS) { - printk(KERN_ERR "tm6000: Supports only %i tm60xx boards.\n", TM6000_MAXBOARDS); - usb_put_dev(usbdev); - return -ENOMEM; - } - - /* Create and initialize dev struct */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - printk(KERN_ERR "tm6000" ": out of memory!\n"); - usb_put_dev(usbdev); - return -ENOMEM; - } - spin_lock_init(&dev->slock); - mutex_init(&dev->usb_lock); - - /* Increment usage count */ - set_bit(nr, &tm6000_devused); - snprintf(dev->name, 29, "tm6000 #%d", nr); - - dev->model = id->driver_info; - if (card[nr] < ARRAY_SIZE(tm6000_boards)) - dev->model = card[nr]; - - dev->udev = usbdev; - dev->devno = nr; - - switch (usbdev->speed) { - case USB_SPEED_LOW: - speed = "1.5"; - break; - case USB_SPEED_UNKNOWN: - case USB_SPEED_FULL: - speed = "12"; - break; - case USB_SPEED_HIGH: - speed = "480"; - break; - default: - speed = "unknown"; - } - - /* Get endpoints */ - for (i = 0; i < interface->num_altsetting; i++) { - int ep; - - for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) { - struct usb_host_endpoint *e; - int dir_out; - - e = &interface->altsetting[i].endpoint[ep]; - - dir_out = ((e->desc.bEndpointAddress & - USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT); - - printk(KERN_INFO "tm6000: alt %d, interface %i, class %i\n", - i, - interface->altsetting[i].desc.bInterfaceNumber, - interface->altsetting[i].desc.bInterfaceClass); - - switch (e->desc.bmAttributes) { - case USB_ENDPOINT_XFER_BULK: - if (!dir_out) { - get_max_endpoint(usbdev, - &interface->altsetting[i], - "Bulk IN", e, - &dev->bulk_in); - } else { - get_max_endpoint(usbdev, - &interface->altsetting[i], - "Bulk OUT", e, - &dev->bulk_out); - } - break; - case USB_ENDPOINT_XFER_ISOC: - if (!dir_out) { - get_max_endpoint(usbdev, - &interface->altsetting[i], - "ISOC IN", e, - &dev->isoc_in); - } else { - get_max_endpoint(usbdev, - &interface->altsetting[i], - "ISOC OUT", e, - &dev->isoc_out); - } - break; - case USB_ENDPOINT_XFER_INT: - if (!dir_out) { - get_max_endpoint(usbdev, - &interface->altsetting[i], - "INT IN", e, - &dev->int_in); - } else { - get_max_endpoint(usbdev, - &interface->altsetting[i], - "INT OUT", e, - &dev->int_out); - } - break; - } - } - } - - - printk(KERN_INFO "tm6000: New video device @ %s Mbps (%04x:%04x, ifnum %d)\n", - speed, - le16_to_cpu(dev->udev->descriptor.idVendor), - le16_to_cpu(dev->udev->descriptor.idProduct), - interface->altsetting->desc.bInterfaceNumber); - -/* check if the the device has the iso in endpoint at the correct place */ - if (!dev->isoc_in.endp) { - printk(KERN_ERR "tm6000: probing error: no IN ISOC endpoint!\n"); - rc = -ENODEV; - - goto err; - } - - /* save our data pointer in this interface device */ - usb_set_intfdata(interface, dev); - - printk(KERN_INFO "tm6000: Found %s\n", tm6000_boards[dev->model].name); - - rc = tm6000_init_dev(dev); - if (rc < 0) - goto err; - - return 0; - -err: - printk(KERN_ERR "tm6000: Error %d while registering\n", rc); - - clear_bit(nr, &tm6000_devused); - usb_put_dev(usbdev); - - kfree(dev); - return rc; -} - -/* - * tm6000_usb_disconnect() - * called when the device gets diconencted - * video device will be unregistered on v4l2_close in case it is still open - */ -static void tm6000_usb_disconnect(struct usb_interface *interface) -{ - struct tm6000_core *dev = usb_get_intfdata(interface); - usb_set_intfdata(interface, NULL); - - if (!dev) - return; - - printk(KERN_INFO "tm6000: disconnecting %s\n", dev->name); - - tm6000_ir_fini(dev); - - if (dev->gpio.power_led) { - switch (dev->model) { - case TM6010_BOARD_HAUPPAUGE_900H: - case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: - case TM6010_BOARD_TWINHAN_TU501: - /* Power led off */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.power_led, 0x01); - msleep(15); - break; - case TM6010_BOARD_BEHOLD_WANDER: - case TM6010_BOARD_BEHOLD_VOYAGER: - case TM6010_BOARD_BEHOLD_WANDER_LITE: - case TM6010_BOARD_BEHOLD_VOYAGER_LITE: - /* Power led off */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.power_led, 0x00); - msleep(15); - break; - } - } - tm6000_v4l2_unregister(dev); - - tm6000_i2c_unregister(dev); - - v4l2_device_unregister(&dev->v4l2_dev); - - dev->state |= DEV_DISCONNECTED; - - usb_put_dev(dev->udev); - - tm6000_close_extension(dev); - tm6000_remove_from_devlist(dev); - - clear_bit(dev->devno, &tm6000_devused); - kfree(dev); -} - -static struct usb_driver tm6000_usb_driver = { - .name = "tm6000", - .probe = tm6000_usb_probe, - .disconnect = tm6000_usb_disconnect, - .id_table = tm6000_id_table, -}; - -static int __init tm6000_module_init(void) -{ - int result; - - printk(KERN_INFO "tm6000" " v4l2 driver version %d.%d.%d loaded\n", - (TM6000_VERSION >> 16) & 0xff, - (TM6000_VERSION >> 8) & 0xff, TM6000_VERSION & 0xff); - - /* register this driver with the USB subsystem */ - result = usb_register(&tm6000_usb_driver); - if (result) - printk(KERN_ERR "tm6000" - " usb_register failed. Error number %d.\n", result); - - return result; -} - -static void __exit tm6000_module_exit(void) -{ - /* deregister at USB subsystem */ - usb_deregister(&tm6000_usb_driver); -} - -module_init(tm6000_module_init); -module_exit(tm6000_module_exit); - -MODULE_DESCRIPTION("Trident TVMaster TM5600/TM6000/TM6010 USB2 adapter"); -MODULE_AUTHOR("Mauro Carvalho Chehab"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/tm6000/tm6000-core.c b/drivers/staging/tm6000/tm6000-core.c deleted file mode 100644 index 9783616..0000000 --- a/drivers/staging/tm6000/tm6000-core.c +++ /dev/null @@ -1,965 +0,0 @@ -/* - * tm6000-core.c - driver for TM5600/TM6000/TM6010 USB video capture devices - * - * Copyright (C) 2006-2007 Mauro Carvalho Chehab - * - * Copyright (C) 2007 Michel Ludwig - * - DVB-T support - * - * 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 version 2 - * - * 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 -#include -#include -#include -#include -#include "tm6000.h" -#include "tm6000-regs.h" -#include -#include - -#define USB_TIMEOUT (5 * HZ) /* ms */ - -int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req, - u16 value, u16 index, u8 *buf, u16 len) -{ - int ret, i; - unsigned int pipe; - u8 *data = NULL; - - mutex_lock(&dev->usb_lock); - - if (len) - data = kzalloc(len, GFP_KERNEL); - - if (req_type & USB_DIR_IN) - pipe = usb_rcvctrlpipe(dev->udev, 0); - else { - pipe = usb_sndctrlpipe(dev->udev, 0); - memcpy(data, buf, len); - } - - if (tm6000_debug & V4L2_DEBUG_I2C) { - printk(KERN_DEBUG "(dev %p, pipe %08x): ", dev->udev, pipe); - - printk(KERN_CONT "%s: %02x %02x %02x %02x %02x %02x %02x %02x ", - (req_type & USB_DIR_IN) ? " IN" : "OUT", - req_type, req, value&0xff, value>>8, index&0xff, - index>>8, len&0xff, len>>8); - - if (!(req_type & USB_DIR_IN)) { - printk(KERN_CONT ">>> "); - for (i = 0; i < len; i++) - printk(KERN_CONT " %02x", buf[i]); - printk(KERN_CONT "\n"); - } - } - - ret = usb_control_msg(dev->udev, pipe, req, req_type, value, index, - data, len, USB_TIMEOUT); - - if (req_type & USB_DIR_IN) - memcpy(buf, data, len); - - if (tm6000_debug & V4L2_DEBUG_I2C) { - if (ret < 0) { - if (req_type & USB_DIR_IN) - printk(KERN_DEBUG "<<< (len=%d)\n", len); - - printk(KERN_CONT "%s: Error #%d\n", __func__, ret); - } else if (req_type & USB_DIR_IN) { - printk(KERN_CONT "<<< "); - for (i = 0; i < len; i++) - printk(KERN_CONT " %02x", buf[i]); - printk(KERN_CONT "\n"); - } - } - - kfree(data); - msleep(5); - - mutex_unlock(&dev->usb_lock); - return ret; -} - -int tm6000_set_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index) -{ - return - tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR, - req, value, index, NULL, 0); -} -EXPORT_SYMBOL_GPL(tm6000_set_reg); - -int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index) -{ - int rc; - u8 buf[1]; - - rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req, - value, index, buf, 1); - - if (rc < 0) - return rc; - - return *buf; -} -EXPORT_SYMBOL_GPL(tm6000_get_reg); - -int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value, - u16 index, u16 mask) -{ - int rc; - u8 buf[1]; - u8 new_index; - - rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req, - value, index, buf, 1); - - if (rc < 0) - return rc; - - new_index = (buf[0] & ~mask) | (index & mask); - - if (new_index == index) - return 0; - - return tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR, - req, value, new_index, NULL, 0); -} -EXPORT_SYMBOL_GPL(tm6000_set_reg_mask); - -int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index) -{ - int rc; - u8 buf[2]; - - rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req, - value, index, buf, 2); - - if (rc < 0) - return rc; - - return buf[1]|buf[0]<<8; -} - -int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index) -{ - int rc; - u8 buf[4]; - - rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req, - value, index, buf, 4); - - if (rc < 0) - return rc; - - return buf[3] | buf[2] << 8 | buf[1] << 16 | buf[0] << 24; -} - -int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep) -{ - int rc; - - rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_CLK, 0); - if (rc < 0) - return rc; - - msleep(tsleep); - - rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_CLK, 1); - msleep(tsleep); - - return rc; -} - -void tm6000_set_fourcc_format(struct tm6000_core *dev) -{ - if (dev->dev_type == TM6010) { - int val; - - val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_IF, 0) & 0xfc; - if (dev->fourcc == V4L2_PIX_FMT_UYVY) - tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_IF, val); - else - tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_IF, val | 1); - } else { - if (dev->fourcc == V4L2_PIX_FMT_UYVY) - tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0); - else - tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0x90); - } -} - -static void tm6000_set_vbi(struct tm6000_core *dev) -{ - /* - * FIXME: - * VBI lines and start/end are different between 60Hz and 50Hz - * So, it is very likely that we need to change the config to - * something that takes it into account, doing something different - * if (dev->norm & V4L2_STD_525_60) - */ - - if (dev->dev_type == TM6010) { - tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01); - tm6000_set_reg(dev, TM6010_REQ07_R41_TELETEXT_VBI_CODE1, 0x27); - tm6000_set_reg(dev, TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55); - tm6000_set_reg(dev, TM6010_REQ07_R43_VBI_DATA_TYPE_LINE7, 0x66); - tm6000_set_reg(dev, TM6010_REQ07_R44_VBI_DATA_TYPE_LINE8, 0x66); - tm6000_set_reg(dev, TM6010_REQ07_R45_VBI_DATA_TYPE_LINE9, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R46_VBI_DATA_TYPE_LINE10, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R47_VBI_DATA_TYPE_LINE11, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R48_VBI_DATA_TYPE_LINE12, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R49_VBI_DATA_TYPE_LINE13, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R4A_VBI_DATA_TYPE_LINE14, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R4B_VBI_DATA_TYPE_LINE15, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R4C_VBI_DATA_TYPE_LINE16, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R4D_VBI_DATA_TYPE_LINE17, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R4E_VBI_DATA_TYPE_LINE18, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R4F_VBI_DATA_TYPE_LINE19, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R50_VBI_DATA_TYPE_LINE20, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R52_VBI_DATA_TYPE_LINE22, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R53_VBI_DATA_TYPE_LINE23, 0x00); - tm6000_set_reg(dev, - TM6010_REQ07_R54_VBI_DATA_TYPE_RLINES, 0x00); - tm6000_set_reg(dev, - TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01); - tm6000_set_reg(dev, - TM6010_REQ07_R56_VBI_LOOP_FILTER_I_GAIN, 0x00); - tm6000_set_reg(dev, - TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02); - tm6000_set_reg(dev, TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35); - tm6000_set_reg(dev, TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0); - tm6000_set_reg(dev, TM6010_REQ07_R5A_VBI_TELETEXT_DTO1, 0x11); - tm6000_set_reg(dev, TM6010_REQ07_R5B_VBI_TELETEXT_DTO0, 0x4c); - tm6000_set_reg(dev, TM6010_REQ07_R40_TELETEXT_VBI_CODE0, 0x01); - tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00); - } -} - -int tm6000_init_analog_mode(struct tm6000_core *dev) -{ - struct v4l2_frequency f; - - if (dev->dev_type == TM6010) { - u8 active = TM6010_REQ07_RCC_ACTIVE_IF_AUDIO_ENABLE; - - if (!dev->radio) - active |= TM6010_REQ07_RCC_ACTIVE_IF_VIDEO_ENABLE; - - /* Enable video and audio */ - tm6000_set_reg_mask(dev, TM6010_REQ07_RCC_ACTIVE_IF, - active, 0x60); - /* Disable TS input */ - tm6000_set_reg_mask(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, - 0x00, 0x40); - } else { - /* Enables soft reset */ - tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01); - - if (dev->scaler) - /* Disable Hfilter and Enable TS Drop err */ - tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x20); - else /* Enable Hfilter and disable TS Drop err */ - tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x80); - - tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x88); - tm6000_set_reg(dev, TM6000_REQ07_RDA_CLK_SEL, 0x23); - tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xc0); - tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xd8); - tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x06); - tm6000_set_reg(dev, TM6000_REQ07_RDF_PWDOWN_ACLK, 0x1f); - - /* AP Software reset */ - tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08); - tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00); - - tm6000_set_fourcc_format(dev); - - /* Disables soft reset */ - tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00); - } - msleep(20); - - /* Tuner firmware can now be loaded */ - - /* - * FIXME: This is a hack! xc3028 "sleeps" when no channel is detected - * for more than a few seconds. Not sure why, as this behavior does - * not happen on other devices with xc3028. So, I suspect that it - * is yet another bug at tm6000. After start sleeping, decoding - * doesn't start automatically. Instead, it requires some - * I2C commands to wake it up. As we want to have image at the - * beginning, we needed to add this hack. The better would be to - * discover some way to make tm6000 to wake up without this hack. - */ - f.frequency = dev->freq; - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f); - - msleep(100); - tm6000_set_standard(dev); - tm6000_set_vbi(dev); - tm6000_set_audio_bitrate(dev, 48000); - - /* switch dvb led off */ - if (dev->gpio.dvb_led) { - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.dvb_led, 0x01); - } - - return 0; -} - -int tm6000_init_digital_mode(struct tm6000_core *dev) -{ - if (dev->dev_type == TM6010) { - /* Disable video and audio */ - tm6000_set_reg_mask(dev, TM6010_REQ07_RCC_ACTIVE_IF, - 0x00, 0x60); - /* Enable TS input */ - tm6000_set_reg_mask(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, - 0x40, 0x40); - /* all power down, but not the digital data port */ - tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, 0x28); - tm6000_set_reg(dev, TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xfc); - tm6000_set_reg(dev, TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0xff); - } else { - tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08); - tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00); - tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01); - tm6000_set_reg(dev, TM6000_REQ07_RDF_PWDOWN_ACLK, 0x08); - tm6000_set_reg(dev, TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x0c); - tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0xff); - tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0xd8); - tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x40); - tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0); - tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x09); - tm6000_set_reg(dev, TM6000_REQ07_RDA_CLK_SEL, 0x37); - tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xd8); - tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xc0); - tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x60); - - tm6000_set_reg(dev, TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x0c); - tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0xff); - tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0x08); - msleep(50); - - tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00); - msleep(50); - tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x01); - msleep(50); - tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00); - msleep(100); - } - - /* switch dvb led on */ - if (dev->gpio.dvb_led) { - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.dvb_led, 0x00); - } - - return 0; -} -EXPORT_SYMBOL(tm6000_init_digital_mode); - -struct reg_init { - u8 req; - u8 reg; - u8 val; -}; - -/* The meaning of those initializations are unknown */ -static struct reg_init tm6000_init_tab[] = { - /* REG VALUE */ - { TM6000_REQ07_RDF_PWDOWN_ACLK, 0x1f }, - { TM6010_REQ07_RFF_SOFT_RESET, 0x08 }, - { TM6010_REQ07_RFF_SOFT_RESET, 0x00 }, - { TM6010_REQ07_RD5_POWERSAVE, 0x4f }, - { TM6000_REQ07_RDA_CLK_SEL, 0x23 }, - { TM6000_REQ07_RDB_OUT_SEL, 0x08 }, - { TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x00 }, - { TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10 }, - { TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00 }, - { TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x00 }, - { TM6000_REQ07_REB_VADC_AADC_MODE, 0x64 }, /* 48000 bits/sample, external input */ - { TM6000_REQ07_REE_VADC_CTRL_SEL_CONTROL, 0xc2 }, - - { TM6010_REQ07_R3F_RESET, 0x01 }, /* Start of soft reset */ - { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 }, - { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x07 }, - { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, - { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 }, - { TM6010_REQ07_R05_NOISE_THRESHOLD, 0x64 }, - { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01 }, - { TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0x82 }, - { TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0x36 }, - { TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0x50 }, - { TM6010_REQ07_R0C_CHROMA_AGC_CONTROL, 0x6a }, - { TM6010_REQ07_R11_AGC_PEAK_CONTROL, 0xc9 }, - { TM6010_REQ07_R12_AGC_GATE_STARTH, 0x07 }, - { TM6010_REQ07_R13_AGC_GATE_STARTL, 0x3b }, - { TM6010_REQ07_R14_AGC_GATE_WIDTH, 0x47 }, - { TM6010_REQ07_R15_AGC_BP_DELAY, 0x6f }, - { TM6010_REQ07_R17_HLOOP_MAXSTATE, 0xcd }, - { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, - { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b }, - { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 }, - { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 }, - { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, - { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, - { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, - { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, - { TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME, 0x3c }, - { TM6010_REQ07_R21_HSYNC_PHASE_OFFSET, 0x3c }, - { TM6010_REQ07_R2D_CHROMA_BURST_END, 0x48 }, - { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, - { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 }, - { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 }, - { TM6010_REQ07_R32_VSYNC_HLOCK_MIN, 0x74 }, - { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c }, - { TM6010_REQ07_R34_VSYNC_AGC_MIN, 0x74 }, - { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, - { TM6010_REQ07_R36_VSYNC_VBI_MIN, 0x7a }, - { TM6010_REQ07_R37_VSYNC_VBI_MAX, 0x26 }, - { TM6010_REQ07_R38_VSYNC_THRESHOLD, 0x40 }, - { TM6010_REQ07_R39_VSYNC_TIME_CONSTANT, 0x0a }, - { TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55 }, - { TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x11 }, - { TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01 }, - { TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02 }, - { TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35 }, - { TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0 }, - { TM6010_REQ07_R80_COMB_FILTER_TRESHOLD, 0x15 }, - { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 }, - { TM6010_REQ07_RC1_TRESHOLD, 0xd0 }, - { TM6010_REQ07_RC3_HSTART1, 0x88 }, - { TM6010_REQ07_R3F_RESET, 0x00 }, /* End of the soft reset */ - { TM6010_REQ05_R18_IMASK7, 0x00 }, -}; - -static struct reg_init tm6010_init_tab[] = { - { TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x00 }, - { TM6010_REQ07_RC4_HSTART0, 0xa0 }, - { TM6010_REQ07_RC6_HEND0, 0x40 }, - { TM6010_REQ07_RCA_VEND0, 0x31 }, - { TM6010_REQ07_RCC_ACTIVE_IF, 0xe1 }, - { TM6010_REQ07_RE0_DVIDEO_SOURCE, 0x03 }, - { TM6010_REQ07_RFE_POWER_DOWN, 0x7f }, - - { TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0 }, - { TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4 }, - { TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8 }, - { TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x00 }, - { TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2 }, - { TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0 }, - { TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2 }, - { TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60 }, - { TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc }, - - { TM6010_REQ07_R3F_RESET, 0x01 }, - { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 }, - { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x07 }, - { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, - { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 }, - { TM6010_REQ07_R05_NOISE_THRESHOLD, 0x64 }, - { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01 }, - { TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0x82 }, - { TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0x36 }, - { TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0x50 }, - { TM6010_REQ07_R0C_CHROMA_AGC_CONTROL, 0x6a }, - { TM6010_REQ07_R11_AGC_PEAK_CONTROL, 0xc9 }, - { TM6010_REQ07_R12_AGC_GATE_STARTH, 0x07 }, - { TM6010_REQ07_R13_AGC_GATE_STARTL, 0x3b }, - { TM6010_REQ07_R14_AGC_GATE_WIDTH, 0x47 }, - { TM6010_REQ07_R15_AGC_BP_DELAY, 0x6f }, - { TM6010_REQ07_R17_HLOOP_MAXSTATE, 0xcd }, - { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, - { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b }, - { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 }, - { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 }, - { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, - { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, - { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, - { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, - { TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME, 0x3c }, - { TM6010_REQ07_R21_HSYNC_PHASE_OFFSET, 0x3c }, - { TM6010_REQ07_R2D_CHROMA_BURST_END, 0x48 }, - { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, - { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 }, - { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 }, - { TM6010_REQ07_R32_VSYNC_HLOCK_MIN, 0x74 }, - { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c }, - { TM6010_REQ07_R34_VSYNC_AGC_MIN, 0x74 }, - { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, - { TM6010_REQ07_R36_VSYNC_VBI_MIN, 0x7a }, - { TM6010_REQ07_R37_VSYNC_VBI_MAX, 0x26 }, - { TM6010_REQ07_R38_VSYNC_THRESHOLD, 0x40 }, - { TM6010_REQ07_R39_VSYNC_TIME_CONSTANT, 0x0a }, - { TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55 }, - { TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x11 }, - { TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01 }, - { TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02 }, - { TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35 }, - { TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0 }, - { TM6010_REQ07_R80_COMB_FILTER_TRESHOLD, 0x15 }, - { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 }, - { TM6010_REQ07_RC1_TRESHOLD, 0xd0 }, - { TM6010_REQ07_RC3_HSTART1, 0x88 }, - { TM6010_REQ07_R3F_RESET, 0x00 }, - - { TM6010_REQ05_R18_IMASK7, 0x00 }, - - { TM6010_REQ07_RD8_IR_LEADER1, 0xaa }, - { TM6010_REQ07_RD8_IR_LEADER0, 0x30 }, - { TM6010_REQ07_RD8_IR_PULSE_CNT1, 0x20 }, - { TM6010_REQ07_RD8_IR_PULSE_CNT0, 0xd0 }, - { REQ_04_EN_DISABLE_MCU_INT, 0x02, 0x00 }, - { TM6010_REQ07_RD8_IR, 0x2f }, - - /* set remote wakeup key:any key wakeup */ - { TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe }, - { TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0xff }, -}; - -int tm6000_init(struct tm6000_core *dev) -{ - int board, rc = 0, i, size; - struct reg_init *tab; - - /* Check board revision */ - board = tm6000_get_reg32(dev, REQ_40_GET_VERSION, 0, 0); - if (board >= 0) { - switch (board & 0xff) { - case 0xf3: - printk(KERN_INFO "Found tm6000\n"); - if (dev->dev_type != TM6000) - dev->dev_type = TM6000; - break; - case 0xf4: - printk(KERN_INFO "Found tm6010\n"); - if (dev->dev_type != TM6010) - dev->dev_type = TM6010; - break; - default: - printk(KERN_INFO "Unknown board version = 0x%08x\n", board); - } - } else - printk(KERN_ERR "Error %i while retrieving board version\n", board); - - if (dev->dev_type == TM6010) { - tab = tm6010_init_tab; - size = ARRAY_SIZE(tm6010_init_tab); - } else { - tab = tm6000_init_tab; - size = ARRAY_SIZE(tm6000_init_tab); - } - - /* Load board's initialization table */ - for (i = 0; i < size; i++) { - rc = tm6000_set_reg(dev, tab[i].req, tab[i].reg, tab[i].val); - if (rc < 0) { - printk(KERN_ERR "Error %i while setting req %d, " - "reg %d to value %d\n", rc, - tab[i].req, tab[i].reg, tab[i].val); - return rc; - } - } - - msleep(5); /* Just to be conservative */ - - rc = tm6000_cards_setup(dev); - - return rc; -} - -int tm6000_reset(struct tm6000_core *dev) -{ - int pipe; - int err; - - msleep(500); - - err = usb_set_interface(dev->udev, dev->isoc_in.bInterfaceNumber, 0); - if (err < 0) { - tm6000_err("failed to select interface %d, alt. setting 0\n", - dev->isoc_in.bInterfaceNumber); - return err; - } - - err = usb_reset_configuration(dev->udev); - if (err < 0) { - tm6000_err("failed to reset configuration\n"); - return err; - } - - if ((dev->quirks & TM6000_QUIRK_NO_USB_DELAY) == 0) - msleep(5); - - /* - * Not all devices have int_in defined - */ - if (!dev->int_in.endp) - return 0; - - err = usb_set_interface(dev->udev, dev->isoc_in.bInterfaceNumber, 2); - if (err < 0) { - tm6000_err("failed to select interface %d, alt. setting 2\n", - dev->isoc_in.bInterfaceNumber); - return err; - } - - msleep(5); - - pipe = usb_rcvintpipe(dev->udev, - dev->int_in.endp->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); - - err = usb_clear_halt(dev->udev, pipe); - if (err < 0) { - tm6000_err("usb_clear_halt failed: %d\n", err); - return err; - } - - return 0; -} - -int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate) -{ - int val = 0; - u8 areg_f0 = 0x60; /* ADC MCLK = 250 Fs */ - u8 areg_0a = 0x91; /* SIF 48KHz */ - - switch (bitrate) { - case 48000: - areg_f0 = 0x60; /* ADC MCLK = 250 Fs */ - areg_0a = 0x91; /* SIF 48KHz */ - dev->audio_bitrate = bitrate; - break; - case 32000: - areg_f0 = 0x00; /* ADC MCLK = 375 Fs */ - areg_0a = 0x90; /* SIF 32KHz */ - dev->audio_bitrate = bitrate; - break; - default: - return -EINVAL; - } - - - /* enable I2S, if we use sif or external I2S device */ - if (dev->dev_type == TM6010) { - val = tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, areg_0a); - if (val < 0) - return val; - - val = tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, - areg_f0, 0xf0); - if (val < 0) - return val; - } else { - val = tm6000_set_reg_mask(dev, TM6000_REQ07_REB_VADC_AADC_MODE, - areg_f0, 0xf0); - if (val < 0) - return val; - } - return 0; -} -EXPORT_SYMBOL_GPL(tm6000_set_audio_bitrate); - -int tm6000_set_audio_rinput(struct tm6000_core *dev) -{ - if (dev->dev_type == TM6010) { - /* Audio crossbar setting, default SIF1 */ - u8 areg_f0; - - switch (dev->rinput.amux) { - case TM6000_AMUX_SIF1: - case TM6000_AMUX_SIF2: - areg_f0 = 0x03; - break; - case TM6000_AMUX_ADC1: - areg_f0 = 0x00; - break; - case TM6000_AMUX_ADC2: - areg_f0 = 0x08; - break; - case TM6000_AMUX_I2S: - areg_f0 = 0x04; - break; - default: - printk(KERN_INFO "%s: audio input dosn't support\n", - dev->name); - return 0; - break; - } - /* Set audio input crossbar */ - tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, - areg_f0, 0x0f); - } else { - u8 areg_eb; - /* Audio setting, default LINE1 */ - switch (dev->rinput.amux) { - case TM6000_AMUX_ADC1: - areg_eb = 0x00; - break; - case TM6000_AMUX_ADC2: - areg_eb = 0x04; - break; - default: - printk(KERN_INFO "%s: audio input dosn't support\n", - dev->name); - return 0; - break; - } - /* Set audio input */ - tm6000_set_reg_mask(dev, TM6000_REQ07_REB_VADC_AADC_MODE, - areg_eb, 0x0f); - } - return 0; -} - -static void tm6010_set_mute_sif(struct tm6000_core *dev, u8 mute) -{ - u8 mute_reg = 0; - - if (mute) - mute_reg = 0x08; - - tm6000_set_reg_mask(dev, TM6010_REQ08_R0A_A_I2S_MOD, mute_reg, 0x08); -} - -static void tm6010_set_mute_adc(struct tm6000_core *dev, u8 mute) -{ - u8 mute_reg = 0; - - if (mute) - mute_reg = 0x20; - - if (dev->dev_type == TM6010) { - tm6000_set_reg_mask(dev, TM6010_REQ08_RF2_LEFT_CHANNEL_VOL, - mute_reg, 0x20); - tm6000_set_reg_mask(dev, TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL, - mute_reg, 0x20); - } else { - tm6000_set_reg_mask(dev, TM6000_REQ07_REC_VADC_AADC_LVOL, - mute_reg, 0x20); - tm6000_set_reg_mask(dev, TM6000_REQ07_RED_VADC_AADC_RVOL, - mute_reg, 0x20); - } -} - -int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute) -{ - enum tm6000_mux mux; - - if (dev->radio) - mux = dev->rinput.amux; - else - mux = dev->vinput[dev->input].amux; - - switch (mux) { - case TM6000_AMUX_SIF1: - case TM6000_AMUX_SIF2: - if (dev->dev_type == TM6010) - tm6010_set_mute_sif(dev, mute); - else { - printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has" - " SIF audio inputs. Please check the %s" - " configuration.\n", dev->name); - return -EINVAL; - } - break; - case TM6000_AMUX_ADC1: - case TM6000_AMUX_ADC2: - tm6010_set_mute_adc(dev, mute); - break; - default: - return -EINVAL; - break; - } - return 0; -} - -static void tm6010_set_volume_sif(struct tm6000_core *dev, int vol) -{ - u8 vol_reg; - - vol_reg = vol & 0x0F; - - if (vol < 0) - vol_reg |= 0x40; - - tm6000_set_reg(dev, TM6010_REQ08_R07_A_LEFT_VOL, vol_reg); - tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, vol_reg); -} - -static void tm6010_set_volume_adc(struct tm6000_core *dev, int vol) -{ - u8 vol_reg; - - vol_reg = (vol + 0x10) & 0x1f; - - if (dev->dev_type == TM6010) { - tm6000_set_reg(dev, TM6010_REQ08_RF2_LEFT_CHANNEL_VOL, vol_reg); - tm6000_set_reg(dev, TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL, vol_reg); - } else { - tm6000_set_reg(dev, TM6000_REQ07_REC_VADC_AADC_LVOL, vol_reg); - tm6000_set_reg(dev, TM6000_REQ07_RED_VADC_AADC_RVOL, vol_reg); - } -} - -void tm6000_set_volume(struct tm6000_core *dev, int vol) -{ - enum tm6000_mux mux; - - if (dev->radio) { - mux = dev->rinput.amux; - vol += 8; /* Offset to 0 dB */ - } else - mux = dev->vinput[dev->input].amux; - - switch (mux) { - case TM6000_AMUX_SIF1: - case TM6000_AMUX_SIF2: - if (dev->dev_type == TM6010) - tm6010_set_volume_sif(dev, vol); - else - printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has" - " SIF audio inputs. Please check the %s" - " configuration.\n", dev->name); - break; - case TM6000_AMUX_ADC1: - case TM6000_AMUX_ADC2: - tm6010_set_volume_adc(dev, vol); - break; - default: - break; - } -} - -static LIST_HEAD(tm6000_devlist); -static DEFINE_MUTEX(tm6000_devlist_mutex); - -/* - * tm6000_realease_resource() - */ - -void tm6000_remove_from_devlist(struct tm6000_core *dev) -{ - mutex_lock(&tm6000_devlist_mutex); - list_del(&dev->devlist); - mutex_unlock(&tm6000_devlist_mutex); -}; - -void tm6000_add_into_devlist(struct tm6000_core *dev) -{ - mutex_lock(&tm6000_devlist_mutex); - list_add_tail(&dev->devlist, &tm6000_devlist); - mutex_unlock(&tm6000_devlist_mutex); -}; - -/* - * Extension interface - */ - -static LIST_HEAD(tm6000_extension_devlist); - -int tm6000_call_fillbuf(struct tm6000_core *dev, enum tm6000_ops_type type, - char *buf, int size) -{ - struct tm6000_ops *ops = NULL; - - /* FIXME: tm6000_extension_devlist_lock should be a spinlock */ - - if (!list_empty(&tm6000_extension_devlist)) { - list_for_each_entry(ops, &tm6000_extension_devlist, next) { - if (ops->fillbuf && ops->type == type) - ops->fillbuf(dev, buf, size); - } - } - - return 0; -} - -int tm6000_register_extension(struct tm6000_ops *ops) -{ - struct tm6000_core *dev = NULL; - - mutex_lock(&tm6000_devlist_mutex); - list_add_tail(&ops->next, &tm6000_extension_devlist); - list_for_each_entry(dev, &tm6000_devlist, devlist) { - ops->init(dev); - printk(KERN_INFO "%s: Initialized (%s) extension\n", - dev->name, ops->name); - } - mutex_unlock(&tm6000_devlist_mutex); - return 0; -} -EXPORT_SYMBOL(tm6000_register_extension); - -void tm6000_unregister_extension(struct tm6000_ops *ops) -{ - struct tm6000_core *dev = NULL; - - mutex_lock(&tm6000_devlist_mutex); - list_for_each_entry(dev, &tm6000_devlist, devlist) - ops->fini(dev); - - printk(KERN_INFO "tm6000: Remove (%s) extension\n", ops->name); - list_del(&ops->next); - mutex_unlock(&tm6000_devlist_mutex); -} -EXPORT_SYMBOL(tm6000_unregister_extension); - -void tm6000_init_extension(struct tm6000_core *dev) -{ - struct tm6000_ops *ops = NULL; - - mutex_lock(&tm6000_devlist_mutex); - if (!list_empty(&tm6000_extension_devlist)) { - list_for_each_entry(ops, &tm6000_extension_devlist, next) { - if (ops->init) - ops->init(dev); - } - } - mutex_unlock(&tm6000_devlist_mutex); -} - -void tm6000_close_extension(struct tm6000_core *dev) -{ - struct tm6000_ops *ops = NULL; - - mutex_lock(&tm6000_devlist_mutex); - if (!list_empty(&tm6000_extension_devlist)) { - list_for_each_entry(ops, &tm6000_extension_devlist, next) { - if (ops->fini) - ops->fini(dev); - } - } - mutex_unlock(&tm6000_devlist_mutex); -} diff --git a/drivers/staging/tm6000/tm6000-dvb.c b/drivers/staging/tm6000/tm6000-dvb.c deleted file mode 100644 index 5e6c129..0000000 --- a/drivers/staging/tm6000/tm6000-dvb.c +++ /dev/null @@ -1,452 +0,0 @@ -/* - * tm6000-dvb.c - dvb-t support for TM5600/TM6000/TM6010 USB video capture devices - * - * Copyright (C) 2007 Michel Ludwig - * - * 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 version 2 - * - * 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 -#include -#include - -#include "tm6000.h" -#include "tm6000-regs.h" - -#include "zl10353.h" - -#include - -#include "tuner-xc2028.h" -#include "xc5000.h" - -MODULE_DESCRIPTION("DVB driver extension module for tm5600/6000/6010 based TV cards"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_LICENSE("GPL"); - -MODULE_SUPPORTED_DEVICE("{{Trident, tm5600}," - "{{Trident, tm6000}," - "{{Trident, tm6010}"); - -static int debug; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable debug message"); - -static inline void print_err_status(struct tm6000_core *dev, - int packet, int status) -{ - char *errmsg = "Unknown"; - - switch (status) { - case -ENOENT: - errmsg = "unlinked synchronuously"; - break; - case -ECONNRESET: - errmsg = "unlinked asynchronuously"; - break; - case -ENOSR: - errmsg = "Buffer error (overrun)"; - break; - case -EPIPE: - errmsg = "Stalled (device not responding)"; - break; - case -EOVERFLOW: - errmsg = "Babble (bad cable?)"; - break; - case -EPROTO: - errmsg = "Bit-stuff error (bad cable?)"; - break; - case -EILSEQ: - errmsg = "CRC/Timeout (could be anything)"; - break; - case -ETIME: - errmsg = "Device does not respond"; - break; - } - if (packet < 0) { - dprintk(dev, 1, "URB status %d [%s].\n", - status, errmsg); - } else { - dprintk(dev, 1, "URB packet %d, status %d [%s].\n", - packet, status, errmsg); - } -} - -static void tm6000_urb_received(struct urb *urb) -{ - int ret; - struct tm6000_core *dev = urb->context; - - if (urb->status != 0) - print_err_status(dev, 0, urb->status); - else if (urb->actual_length > 0) - dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer, - urb->actual_length); - - if (dev->dvb->streams > 0) { - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret < 0) { - printk(KERN_ERR "tm6000: error %s\n", __func__); - kfree(urb->transfer_buffer); - usb_free_urb(urb); - } - } -} - -static int tm6000_start_stream(struct tm6000_core *dev) -{ - int ret; - unsigned int pipe, size; - struct tm6000_dvb *dvb = dev->dvb; - - printk(KERN_INFO "tm6000: got start stream request %s\n", __func__); - - if (dev->mode != TM6000_MODE_DIGITAL) { - tm6000_init_digital_mode(dev); - dev->mode = TM6000_MODE_DIGITAL; - } - - dvb->bulk_urb = usb_alloc_urb(0, GFP_KERNEL); - if (dvb->bulk_urb == NULL) { - printk(KERN_ERR "tm6000: couldn't allocate urb\n"); - return -ENOMEM; - } - - pipe = usb_rcvbulkpipe(dev->udev, dev->bulk_in.endp->desc.bEndpointAddress - & USB_ENDPOINT_NUMBER_MASK); - - size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe)); - size = size * 15; /* 512 x 8 or 12 or 15 */ - - dvb->bulk_urb->transfer_buffer = kzalloc(size, GFP_KERNEL); - if (dvb->bulk_urb->transfer_buffer == NULL) { - usb_free_urb(dvb->bulk_urb); - printk(KERN_ERR "tm6000: couldn't allocate transfer buffer!\n"); - return -ENOMEM; - } - - usb_fill_bulk_urb(dvb->bulk_urb, dev->udev, pipe, - dvb->bulk_urb->transfer_buffer, - size, - tm6000_urb_received, dev); - - ret = usb_clear_halt(dev->udev, pipe); - if (ret < 0) { - printk(KERN_ERR "tm6000: error %i in %s during pipe reset\n", - ret, __func__); - return ret; - } else - printk(KERN_ERR "tm6000: pipe resetted\n"); - -/* mutex_lock(&tm6000_driver.open_close_mutex); */ - ret = usb_submit_urb(dvb->bulk_urb, GFP_KERNEL); - -/* mutex_unlock(&tm6000_driver.open_close_mutex); */ - if (ret) { - printk(KERN_ERR "tm6000: submit of urb failed (error=%i)\n", - ret); - - kfree(dvb->bulk_urb->transfer_buffer); - usb_free_urb(dvb->bulk_urb); - return ret; - } - - return 0; -} - -static void tm6000_stop_stream(struct tm6000_core *dev) -{ - struct tm6000_dvb *dvb = dev->dvb; - - if (dvb->bulk_urb) { - printk(KERN_INFO "urb killing\n"); - usb_kill_urb(dvb->bulk_urb); - printk(KERN_INFO "urb buffer free\n"); - kfree(dvb->bulk_urb->transfer_buffer); - usb_free_urb(dvb->bulk_urb); - dvb->bulk_urb = NULL; - } -} - -static int tm6000_start_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct tm6000_core *dev = demux->priv; - struct tm6000_dvb *dvb = dev->dvb; - printk(KERN_INFO "tm6000: got start feed request %s\n", __func__); - - mutex_lock(&dvb->mutex); - if (dvb->streams == 0) { - dvb->streams = 1; -/* mutex_init(&tm6000_dev->streming_mutex); */ - tm6000_start_stream(dev); - } else - ++(dvb->streams); - mutex_unlock(&dvb->mutex); - - return 0; -} - -static int tm6000_stop_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct tm6000_core *dev = demux->priv; - struct tm6000_dvb *dvb = dev->dvb; - - printk(KERN_INFO "tm6000: got stop feed request %s\n", __func__); - - mutex_lock(&dvb->mutex); - - printk(KERN_INFO "stream %#x\n", dvb->streams); - --(dvb->streams); - if (dvb->streams == 0) { - printk(KERN_INFO "stop stream\n"); - tm6000_stop_stream(dev); -/* mutex_destroy(&tm6000_dev->streaming_mutex); */ - } - mutex_unlock(&dvb->mutex); -/* mutex_destroy(&tm6000_dev->streaming_mutex); */ - - return 0; -} - -static int tm6000_dvb_attach_frontend(struct tm6000_core *dev) -{ - struct tm6000_dvb *dvb = dev->dvb; - - if (dev->caps.has_zl10353) { - struct zl10353_config config = { - .demod_address = dev->demod_addr, - .no_tuner = 1, - .parallel_ts = 1, - .if2 = 45700, - .disable_i2c_gate_ctrl = 1, - }; - - dvb->frontend = dvb_attach(zl10353_attach, &config, - &dev->i2c_adap); - } else { - printk(KERN_ERR "tm6000: no frontend defined for the device!\n"); - return -1; - } - - return (!dvb->frontend) ? -1 : 0; -} - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int register_dvb(struct tm6000_core *dev) -{ - int ret = -1; - struct tm6000_dvb *dvb = dev->dvb; - - mutex_init(&dvb->mutex); - - dvb->streams = 0; - - /* attach the frontend */ - ret = tm6000_dvb_attach_frontend(dev); - if (ret < 0) { - printk(KERN_ERR "tm6000: couldn't attach the frontend!\n"); - goto err; - } - - ret = dvb_register_adapter(&dvb->adapter, "Trident TVMaster 6000 DVB-T", - THIS_MODULE, &dev->udev->dev, adapter_nr); - dvb->adapter.priv = dev; - - if (dvb->frontend) { - switch (dev->tuner_type) { - case TUNER_XC2028: { - struct xc2028_config cfg = { - .i2c_adap = &dev->i2c_adap, - .i2c_addr = dev->tuner_addr, - }; - - dvb->frontend->callback = tm6000_tuner_callback; - ret = dvb_register_frontend(&dvb->adapter, dvb->frontend); - if (ret < 0) { - printk(KERN_ERR - "tm6000: couldn't register frontend\n"); - goto adapter_err; - } - - if (!dvb_attach(xc2028_attach, dvb->frontend, &cfg)) { - printk(KERN_ERR "tm6000: couldn't register " - "frontend (xc3028)\n"); - ret = -EINVAL; - goto frontend_err; - } - printk(KERN_INFO "tm6000: XC2028/3028 asked to be " - "attached to frontend!\n"); - break; - } - case TUNER_XC5000: { - struct xc5000_config cfg = { - .i2c_address = dev->tuner_addr, - }; - - dvb->frontend->callback = tm6000_xc5000_callback; - ret = dvb_register_frontend(&dvb->adapter, dvb->frontend); - if (ret < 0) { - printk(KERN_ERR - "tm6000: couldn't register frontend\n"); - goto adapter_err; - } - - if (!dvb_attach(xc5000_attach, dvb->frontend, &dev->i2c_adap, &cfg)) { - printk(KERN_ERR "tm6000: couldn't register " - "frontend (xc5000)\n"); - ret = -EINVAL; - goto frontend_err; - } - printk(KERN_INFO "tm6000: XC5000 asked to be " - "attached to frontend!\n"); - break; - } - } - } else - printk(KERN_ERR "tm6000: no frontend found\n"); - - dvb->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING - | DMX_MEMORY_BASED_FILTERING; - dvb->demux.priv = dev; - dvb->demux.filternum = 8; - dvb->demux.feednum = 8; - dvb->demux.start_feed = tm6000_start_feed; - dvb->demux.stop_feed = tm6000_stop_feed; - dvb->demux.write_to_decoder = NULL; - ret = dvb_dmx_init(&dvb->demux); - if (ret < 0) { - printk(KERN_ERR "tm6000: dvb_dmx_init failed (errno = %d)\n", ret); - goto frontend_err; - } - - dvb->dmxdev.filternum = dev->dvb->demux.filternum; - dvb->dmxdev.demux = &dev->dvb->demux.dmx; - dvb->dmxdev.capabilities = 0; - - ret = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); - if (ret < 0) { - printk(KERN_ERR "tm6000: dvb_dmxdev_init failed (errno = %d)\n", ret); - goto dvb_dmx_err; - } - - return 0; - -dvb_dmx_err: - dvb_dmx_release(&dvb->demux); -frontend_err: - if (dvb->frontend) { - dvb_frontend_detach(dvb->frontend); - dvb_unregister_frontend(dvb->frontend); - } -adapter_err: - dvb_unregister_adapter(&dvb->adapter); -err: - return ret; -} - -static void unregister_dvb(struct tm6000_core *dev) -{ - struct tm6000_dvb *dvb = dev->dvb; - - if (dvb->bulk_urb != NULL) { - struct urb *bulk_urb = dvb->bulk_urb; - - kfree(bulk_urb->transfer_buffer); - bulk_urb->transfer_buffer = NULL; - usb_unlink_urb(bulk_urb); - usb_free_urb(bulk_urb); - } - -/* mutex_lock(&tm6000_driver.open_close_mutex); */ - if (dvb->frontend) { - dvb_frontend_detach(dvb->frontend); - dvb_unregister_frontend(dvb->frontend); - } - - dvb_dmxdev_release(&dvb->dmxdev); - dvb_dmx_release(&dvb->demux); - dvb_unregister_adapter(&dvb->adapter); - mutex_destroy(&dvb->mutex); -/* mutex_unlock(&tm6000_driver.open_close_mutex); */ -} - -static int dvb_init(struct tm6000_core *dev) -{ - struct tm6000_dvb *dvb; - int rc; - - if (!dev) - return 0; - - if (!dev->caps.has_dvb) - return 0; - - dvb = kzalloc(sizeof(struct tm6000_dvb), GFP_KERNEL); - if (!dvb) { - printk(KERN_INFO "Cannot allocate memory\n"); - return -ENOMEM; - } - - dev->dvb = dvb; - - rc = register_dvb(dev); - if (rc < 0) { - kfree(dvb); - dev->dvb = NULL; - return 0; - } - - return 0; -} - -static int dvb_fini(struct tm6000_core *dev) -{ - if (!dev) - return 0; - - if (!dev->caps.has_dvb) - return 0; - - if (dev->dvb) { - unregister_dvb(dev); - kfree(dev->dvb); - dev->dvb = NULL; - } - - return 0; -} - -static struct tm6000_ops dvb_ops = { - .type = TM6000_DVB, - .name = "TM6000 dvb Extension", - .init = dvb_init, - .fini = dvb_fini, -}; - -static int __init tm6000_dvb_register(void) -{ - return tm6000_register_extension(&dvb_ops); -} - -static void __exit tm6000_dvb_unregister(void) -{ - tm6000_unregister_extension(&dvb_ops); -} - -module_init(tm6000_dvb_register); -module_exit(tm6000_dvb_unregister); diff --git a/drivers/staging/tm6000/tm6000-i2c.c b/drivers/staging/tm6000/tm6000-i2c.c deleted file mode 100644 index 0290bbf..0000000 --- a/drivers/staging/tm6000/tm6000-i2c.c +++ /dev/null @@ -1,340 +0,0 @@ -/* - * tm6000-i2c.c - driver for TM5600/TM6000/TM6010 USB video capture devices - * - * Copyright (C) 2006-2007 Mauro Carvalho Chehab - * - * Copyright (C) 2007 Michel Ludwig - * - Fix SMBus Read Byte command - * - * 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 version 2 - * - * 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 -#include -#include -#include - -#include "tm6000.h" -#include "tm6000-regs.h" -#include -#include -#include "tuner-xc2028.h" - - -/* ----------------------------------------------------------- */ - -static unsigned int i2c_debug; -module_param(i2c_debug, int, 0644); -MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); - -#define i2c_dprintk(lvl, fmt, args...) if (i2c_debug >= lvl) do { \ - printk(KERN_DEBUG "%s at %s: " fmt, \ - dev->name, __func__, ##args); } while (0) - -static int tm6000_i2c_send_regs(struct tm6000_core *dev, unsigned char addr, - __u8 reg, char *buf, int len) -{ - int rc; - unsigned int tsleep; - unsigned int i2c_packet_limit = 16; - - if (dev->dev_type == TM6010) - i2c_packet_limit = 64; - - if (!buf) - return -1; - - if (len < 1 || len > i2c_packet_limit) { - printk(KERN_ERR "Incorrect length of i2c packet = %d, limit set to %d\n", - len, i2c_packet_limit); - return -1; - } - - /* capture mutex */ - rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, REQ_16_SET_GET_I2C_WR1_RDN, - addr | reg << 8, 0, buf, len); - - if (rc < 0) { - /* release mutex */ - return rc; - } - - /* Calculate delay time, 14000us for 64 bytes */ - tsleep = ((len * 200) + 200 + 1000) / 1000; - msleep(tsleep); - - /* release mutex */ - return rc; -} - -/* Generic read - doesn't work fine with 16bit registers */ -static int tm6000_i2c_recv_regs(struct tm6000_core *dev, unsigned char addr, - __u8 reg, char *buf, int len) -{ - int rc; - u8 b[2]; - unsigned int i2c_packet_limit = 16; - - if (dev->dev_type == TM6010) - i2c_packet_limit = 64; - - if (!buf) - return -1; - - if (len < 1 || len > i2c_packet_limit) { - printk(KERN_ERR "Incorrect length of i2c packet = %d, limit set to %d\n", - len, i2c_packet_limit); - return -1; - } - - /* capture mutex */ - if ((dev->caps.has_zl10353) && (dev->demod_addr << 1 == addr) && (reg % 2 == 0)) { - /* - * Workaround an I2C bug when reading from zl10353 - */ - reg -= 1; - len += 1; - - rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - REQ_16_SET_GET_I2C_WR1_RDN, addr | reg << 8, 0, b, len); - - *buf = b[1]; - } else { - rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - REQ_16_SET_GET_I2C_WR1_RDN, addr | reg << 8, 0, buf, len); - } - - /* release mutex */ - return rc; -} - -/* - * read from a 16bit register - * for example xc2028, xc3028 or xc3028L - */ -static int tm6000_i2c_recv_regs16(struct tm6000_core *dev, unsigned char addr, - __u16 reg, char *buf, int len) -{ - int rc; - unsigned char ureg; - - if (!buf || len != 2) - return -1; - - /* capture mutex */ - if (dev->dev_type == TM6010) { - ureg = reg & 0xFF; - rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, REQ_16_SET_GET_I2C_WR1_RDN, - addr | (reg & 0xFF00), 0, &ureg, 1); - - if (rc < 0) { - /* release mutex */ - return rc; - } - - msleep(1400 / 1000); - rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, REQ_35_AFTEK_TUNER_READ, - reg, 0, buf, len); - } else { - rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, REQ_14_SET_GET_I2C_WR2_RDN, - addr, reg, buf, len); - } - - /* release mutex */ - return rc; -} - -static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg msgs[], int num) -{ - struct tm6000_core *dev = i2c_adap->algo_data; - int addr, rc, i, byte; - - if (num <= 0) - return 0; - for (i = 0; i < num; i++) { - addr = (msgs[i].addr << 1) & 0xff; - i2c_dprintk(2, "%s %s addr=0x%x len=%d:", - (msgs[i].flags & I2C_M_RD) ? "read" : "write", - i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len); - if (msgs[i].flags & I2C_M_RD) { - /* read request without preceding register selection */ - /* - * The TM6000 only supports a read transaction - * immediately after a 1 or 2 byte write to select - * a register. We cannot fulfil this request. - */ - i2c_dprintk(2, " read without preceding write not" - " supported"); - rc = -EOPNOTSUPP; - goto err; - } else if (i + 1 < num && msgs[i].len <= 2 && - (msgs[i + 1].flags & I2C_M_RD) && - msgs[i].addr == msgs[i + 1].addr) { - /* 1 or 2 byte write followed by a read */ - if (i2c_debug >= 2) - for (byte = 0; byte < msgs[i].len; byte++) - printk(KERN_CONT " %02x", msgs[i].buf[byte]); - i2c_dprintk(2, "; joined to read %s len=%d:", - i == num - 2 ? "stop" : "nonstop", - msgs[i + 1].len); - - if (msgs[i].len == 2) { - rc = tm6000_i2c_recv_regs16(dev, addr, - msgs[i].buf[0] << 8 | msgs[i].buf[1], - msgs[i + 1].buf, msgs[i + 1].len); - } else { - rc = tm6000_i2c_recv_regs(dev, addr, msgs[i].buf[0], - msgs[i + 1].buf, msgs[i + 1].len); - } - - i++; - - if (addr == dev->tuner_addr << 1) { - tm6000_set_reg(dev, REQ_50_SET_START, 0, 0); - tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0); - } - if (i2c_debug >= 2) - for (byte = 0; byte < msgs[i].len; byte++) - printk(KERN_CONT " %02x", msgs[i].buf[byte]); - } else { - /* write bytes */ - if (i2c_debug >= 2) - for (byte = 0; byte < msgs[i].len; byte++) - printk(KERN_CONT " %02x", msgs[i].buf[byte]); - rc = tm6000_i2c_send_regs(dev, addr, msgs[i].buf[0], - msgs[i].buf + 1, msgs[i].len - 1); - } - if (i2c_debug >= 2) - printk(KERN_CONT "\n"); - if (rc < 0) - goto err; - } - - return num; -err: - i2c_dprintk(2, " ERROR: %i\n", rc); - return rc; -} - -static int tm6000_i2c_eeprom(struct tm6000_core *dev) -{ - int i, rc; - unsigned char *p = dev->eedata; - unsigned char bytes[17]; - - dev->i2c_client.addr = 0xa0 >> 1; - dev->eedata_size = 0; - - bytes[16] = '\0'; - for (i = 0; i < sizeof(dev->eedata); ) { - *p = i; - rc = tm6000_i2c_recv_regs(dev, 0xa0, i, p, 1); - if (rc < 1) { - if (p == dev->eedata) - goto noeeprom; - else { - printk(KERN_WARNING - "%s: i2c eeprom read error (err=%d)\n", - dev->name, rc); - } - return -EINVAL; - } - dev->eedata_size++; - p++; - if (0 == (i % 16)) - printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i); - printk(KERN_CONT " %02x", dev->eedata[i]); - if ((dev->eedata[i] >= ' ') && (dev->eedata[i] <= 'z')) - bytes[i%16] = dev->eedata[i]; - else - bytes[i%16] = '.'; - - i++; - - if (0 == (i % 16)) { - bytes[16] = '\0'; - printk(KERN_CONT " %s\n", bytes); - } - } - if (0 != (i%16)) { - bytes[i%16] = '\0'; - for (i %= 16; i < 16; i++) - printk(KERN_CONT " "); - printk(KERN_CONT " %s\n", bytes); - } - - return 0; - -noeeprom: - printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n", - dev->name, rc); - return -EINVAL; -} - -/* ----------------------------------------------------------- */ - -/* - * functionality() - */ -static u32 functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_SMBUS_EMUL; -} - -static const struct i2c_algorithm tm6000_algo = { - .master_xfer = tm6000_i2c_xfer, - .functionality = functionality, -}; - -/* ----------------------------------------------------------- */ - -/* - * tm6000_i2c_register() - * register i2c bus - */ -int tm6000_i2c_register(struct tm6000_core *dev) -{ - int rc; - - dev->i2c_adap.owner = THIS_MODULE; - dev->i2c_adap.algo = &tm6000_algo; - dev->i2c_adap.dev.parent = &dev->udev->dev; - strlcpy(dev->i2c_adap.name, dev->name, sizeof(dev->i2c_adap.name)); - dev->i2c_adap.algo_data = dev; - i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev); - rc = i2c_add_adapter(&dev->i2c_adap); - if (rc) - return rc; - - dev->i2c_client.adapter = &dev->i2c_adap; - strlcpy(dev->i2c_client.name, "tm6000 internal", I2C_NAME_SIZE); - tm6000_i2c_eeprom(dev); - - return 0; -} - -/* - * tm6000_i2c_unregister() - * unregister i2c_bus - */ -int tm6000_i2c_unregister(struct tm6000_core *dev) -{ - i2c_del_adapter(&dev->i2c_adap); - return 0; -} diff --git a/drivers/staging/tm6000/tm6000-input.c b/drivers/staging/tm6000/tm6000-input.c deleted file mode 100644 index 405d127..0000000 --- a/drivers/staging/tm6000/tm6000-input.c +++ /dev/null @@ -1,459 +0,0 @@ -/* - * tm6000-input.c - driver for TM5600/TM6000/TM6010 USB video capture devices - * - * Copyright (C) 2010 Stefan Ringel - * - * 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 version 2 - * - * 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 -#include -#include - -#include -#include - -#include - -#include "tm6000.h" -#include "tm6000-regs.h" - -static unsigned int ir_debug; -module_param(ir_debug, int, 0644); -MODULE_PARM_DESC(ir_debug, "enable debug message [IR]"); - -static unsigned int enable_ir = 1; -module_param(enable_ir, int, 0644); -MODULE_PARM_DESC(enable_ir, "enable ir (default is enable)"); - -/* number of 50ms for ON-OFF-ON power led */ -/* show IR activity */ -#define PWLED_OFF 2 - -#undef dprintk - -#define dprintk(fmt, arg...) \ - if (ir_debug) { \ - printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \ - } - -struct tm6000_ir_poll_result { - u16 rc_data; -}; - -struct tm6000_IR { - struct tm6000_core *dev; - struct rc_dev *rc; - char name[32]; - char phys[32]; - - /* poll expernal decoder */ - int polling; - struct delayed_work work; - u8 wait:1; - u8 key:1; - u8 pwled:1; - u8 pwledcnt; - u16 key_addr; - struct urb *int_urb; - u8 *urb_data; - - int (*get_key) (struct tm6000_IR *, struct tm6000_ir_poll_result *); - - /* IR device properties */ - u64 rc_type; -}; - - -void tm6000_ir_wait(struct tm6000_core *dev, u8 state) -{ - struct tm6000_IR *ir = dev->ir; - - if (!dev->ir) - return; - - if (state) - ir->wait = 1; - else - ir->wait = 0; -} - - -static int tm6000_ir_config(struct tm6000_IR *ir) -{ - struct tm6000_core *dev = ir->dev; - u8 buf[10]; - int rc; - - switch (ir->rc_type) { - case RC_TYPE_NEC: - /* Setup IR decoder for NEC standard 12MHz system clock */ - /* IR_LEADER_CNT = 0.9ms */ - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER1, 0xaa); - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER0, 0x30); - /* IR_PULSE_CNT = 0.7ms */ - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT1, 0x20); - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0xd0); - /* Remote WAKEUP = enable */ - tm6000_set_reg(dev, TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe); - /* IR_WKUP_SEL = Low byte in decoded IR data */ - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0xff); - /* IR_WKU_ADD code */ - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_ADD, 0xff); - tm6000_flash_led(dev, 0); - msleep(100); - tm6000_flash_led(dev, 1); - break; - default: - /* hack */ - buf[0] = 0xff; - buf[1] = 0xff; - buf[2] = 0xf2; - buf[3] = 0x2b; - buf[4] = 0x20; - buf[5] = 0x35; - buf[6] = 0x60; - buf[7] = 0x04; - buf[8] = 0xc0; - buf[9] = 0x08; - - rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, REQ_00_SET_IR_VALUE, 0, 0, buf, 0x0a); - msleep(100); - - if (rc < 0) { - printk(KERN_INFO "IR configuration failed"); - return rc; - } - break; - } - - return 0; -} - -static void tm6000_ir_urb_received(struct urb *urb) -{ - struct tm6000_core *dev = urb->context; - struct tm6000_IR *ir = dev->ir; - int rc; - - if (urb->status != 0) - printk(KERN_INFO "not ready\n"); - else if (urb->actual_length > 0) { - memcpy(ir->urb_data, urb->transfer_buffer, urb->actual_length); - - dprintk("data %02x %02x %02x %02x\n", ir->urb_data[0], - ir->urb_data[1], ir->urb_data[2], ir->urb_data[3]); - - ir->key = 1; - } - - rc = usb_submit_urb(urb, GFP_ATOMIC); -} - -static int default_polling_getkey(struct tm6000_IR *ir, - struct tm6000_ir_poll_result *poll_result) -{ - struct tm6000_core *dev = ir->dev; - int rc; - u8 buf[2]; - - if (ir->wait && !&dev->int_in) - return 0; - - if (&dev->int_in) { - switch (ir->rc_type) { - case RC_TYPE_RC5: - poll_result->rc_data = ir->urb_data[0]; - break; - case RC_TYPE_NEC: - if (ir->urb_data[1] == ((ir->key_addr >> 8) & 0xff)) { - poll_result->rc_data = ir->urb_data[0] - | ir->urb_data[1] << 8; - } - break; - default: - poll_result->rc_data = ir->urb_data[0] - | ir->urb_data[1] << 8; - break; - } - } else { - tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0); - msleep(10); - tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 1); - msleep(10); - - if (ir->rc_type == RC_TYPE_RC5) { - rc = tm6000_read_write_usb(dev, USB_DIR_IN | - USB_TYPE_VENDOR | USB_RECIP_DEVICE, - REQ_02_GET_IR_CODE, 0, 0, buf, 1); - - msleep(10); - - dprintk("read data=%02x\n", buf[0]); - if (rc < 0) - return rc; - - poll_result->rc_data = buf[0]; - } else { - rc = tm6000_read_write_usb(dev, USB_DIR_IN | - USB_TYPE_VENDOR | USB_RECIP_DEVICE, - REQ_02_GET_IR_CODE, 0, 0, buf, 2); - - msleep(10); - - dprintk("read data=%04x\n", buf[0] | buf[1] << 8); - if (rc < 0) - return rc; - - poll_result->rc_data = buf[0] | buf[1] << 8; - } - if ((poll_result->rc_data & 0x00ff) != 0xff) - ir->key = 1; - } - return 0; -} - -static void tm6000_ir_handle_key(struct tm6000_IR *ir) -{ - struct tm6000_core *dev = ir->dev; - int result; - struct tm6000_ir_poll_result poll_result; - - /* read the registers containing the IR status */ - result = ir->get_key(ir, &poll_result); - if (result < 0) { - printk(KERN_INFO "ir->get_key() failed %d\n", result); - return; - } - - dprintk("ir->get_key result data=%04x\n", poll_result.rc_data); - - if (ir->pwled) { - if (ir->pwledcnt >= PWLED_OFF) { - ir->pwled = 0; - ir->pwledcnt = 0; - tm6000_flash_led(dev, 1); - } else - ir->pwledcnt += 1; - } - - if (ir->key) { - rc_keydown(ir->rc, poll_result.rc_data, 0); - ir->key = 0; - ir->pwled = 1; - ir->pwledcnt = 0; - tm6000_flash_led(dev, 0); - } - return; -} - -static void tm6000_ir_work(struct work_struct *work) -{ - struct tm6000_IR *ir = container_of(work, struct tm6000_IR, work.work); - - tm6000_ir_handle_key(ir); - schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling)); -} - -static int tm6000_ir_start(struct rc_dev *rc) -{ - struct tm6000_IR *ir = rc->priv; - - INIT_DELAYED_WORK(&ir->work, tm6000_ir_work); - schedule_delayed_work(&ir->work, 0); - - return 0; -} - -static void tm6000_ir_stop(struct rc_dev *rc) -{ - struct tm6000_IR *ir = rc->priv; - - cancel_delayed_work_sync(&ir->work); -} - -static int tm6000_ir_change_protocol(struct rc_dev *rc, u64 rc_type) -{ - struct tm6000_IR *ir = rc->priv; - - if (!ir) - return 0; - - if ((rc->rc_map.scan) && (rc_type == RC_TYPE_NEC)) - ir->key_addr = ((rc->rc_map.scan[0].scancode >> 8) & 0xffff); - - ir->get_key = default_polling_getkey; - ir->rc_type = rc_type; - - tm6000_ir_config(ir); - /* TODO */ - return 0; -} - -int tm6000_ir_int_start(struct tm6000_core *dev) -{ - struct tm6000_IR *ir = dev->ir; - int pipe, size; - int err = -ENOMEM; - - - if (!ir) - return -ENODEV; - - ir->int_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!ir->int_urb) - return -ENOMEM; - - pipe = usb_rcvintpipe(dev->udev, - dev->int_in.endp->desc.bEndpointAddress - & USB_ENDPOINT_NUMBER_MASK); - - size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe)); - dprintk("IR max size: %d\n", size); - - ir->int_urb->transfer_buffer = kzalloc(size, GFP_KERNEL); - if (ir->int_urb->transfer_buffer == NULL) { - usb_free_urb(ir->int_urb); - return err; - } - dprintk("int interval: %d\n", dev->int_in.endp->desc.bInterval); - usb_fill_int_urb(ir->int_urb, dev->udev, pipe, - ir->int_urb->transfer_buffer, size, - tm6000_ir_urb_received, dev, - dev->int_in.endp->desc.bInterval); - err = usb_submit_urb(ir->int_urb, GFP_KERNEL); - if (err) { - kfree(ir->int_urb->transfer_buffer); - usb_free_urb(ir->int_urb); - return err; - } - ir->urb_data = kzalloc(size, GFP_KERNEL); - - return 0; -} - -void tm6000_ir_int_stop(struct tm6000_core *dev) -{ - struct tm6000_IR *ir = dev->ir; - - if (!ir) - return; - - usb_kill_urb(ir->int_urb); - kfree(ir->int_urb->transfer_buffer); - usb_free_urb(ir->int_urb); - ir->int_urb = NULL; - kfree(ir->urb_data); - ir->urb_data = NULL; -} - -int tm6000_ir_init(struct tm6000_core *dev) -{ - struct tm6000_IR *ir; - struct rc_dev *rc; - int err = -ENOMEM; - - if (!enable_ir) - return -ENODEV; - - if (!dev->caps.has_remote) - return 0; - - if (!dev->ir_codes) - return 0; - - ir = kzalloc(sizeof(*ir), GFP_KERNEL); - rc = rc_allocate_device(); - if (!ir || !rc) - goto out; - - /* record handles to ourself */ - ir->dev = dev; - dev->ir = ir; - ir->rc = rc; - - /* input einrichten */ - rc->allowed_protos = RC_TYPE_RC5 | RC_TYPE_NEC; - rc->priv = ir; - rc->change_protocol = tm6000_ir_change_protocol; - rc->open = tm6000_ir_start; - rc->close = tm6000_ir_stop; - rc->driver_type = RC_DRIVER_SCANCODE; - - ir->polling = 50; - ir->pwled = 0; - ir->pwledcnt = 0; - - - snprintf(ir->name, sizeof(ir->name), "tm5600/60x0 IR (%s)", - dev->name); - - usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); - strlcat(ir->phys, "/input0", sizeof(ir->phys)); - - tm6000_ir_change_protocol(rc, RC_TYPE_UNKNOWN); - - rc->input_name = ir->name; - rc->input_phys = ir->phys; - rc->input_id.bustype = BUS_USB; - rc->input_id.version = 1; - rc->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); - rc->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct); - rc->map_name = dev->ir_codes; - rc->driver_name = "tm6000"; - rc->dev.parent = &dev->udev->dev; - - if (&dev->int_in) { - dprintk("IR over int\n"); - - err = tm6000_ir_int_start(dev); - - if (err) - goto out; - } - - /* ir register */ - err = rc_register_device(rc); - if (err) - goto out; - - return 0; - -out: - dev->ir = NULL; - rc_free_device(rc); - kfree(ir); - return err; -} - -int tm6000_ir_fini(struct tm6000_core *dev) -{ - struct tm6000_IR *ir = dev->ir; - - /* skip detach on non attached board */ - - if (!ir) - return 0; - - rc_unregister_device(ir->rc); - - if (ir->int_urb) - tm6000_ir_int_stop(dev); - - kfree(ir); - dev->ir = NULL; - - return 0; -} diff --git a/drivers/staging/tm6000/tm6000-regs.h b/drivers/staging/tm6000/tm6000-regs.h deleted file mode 100644 index 7f491b6..0000000 --- a/drivers/staging/tm6000/tm6000-regs.h +++ /dev/null @@ -1,600 +0,0 @@ -/* - * tm6000-regs.h - driver for TM5600/TM6000/TM6010 USB video capture devices - * - * Copyright (C) 2006-2007 Mauro Carvalho Chehab - * - * 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 version 2 - * - * 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. - */ - -/* - * Define TV Master TM5600/TM6000/TM6010 Request codes - */ -#define REQ_00_SET_IR_VALUE 0 -#define REQ_01_SET_WAKEUP_IRCODE 1 -#define REQ_02_GET_IR_CODE 2 -#define REQ_03_SET_GET_MCU_PIN 3 -#define REQ_04_EN_DISABLE_MCU_INT 4 -#define REQ_05_SET_GET_USBREG 5 - /* Write: RegNum, Value, 0 */ - /* Read : RegNum, Value, 1, RegStatus */ -#define REQ_06_SET_GET_USBREG_BIT 6 -#define REQ_07_SET_GET_AVREG 7 - /* Write: RegNum, Value, 0 */ - /* Read : RegNum, Value, 1, RegStatus */ -#define REQ_08_SET_GET_AVREG_BIT 8 -#define REQ_09_SET_GET_TUNER_FQ 9 -#define REQ_10_SET_TUNER_SYSTEM 10 -#define REQ_11_SET_EEPROM_ADDR 11 -#define REQ_12_SET_GET_EEPROMBYTE 12 -#define REQ_13_GET_EEPROM_SEQREAD 13 -#define REQ_14_SET_GET_I2C_WR2_RDN 14 -#define REQ_15_SET_GET_I2CBYTE 15 - /* Write: Subaddr, Slave Addr, value, 0 */ - /* Read : Subaddr, Slave Addr, value, 1 */ -#define REQ_16_SET_GET_I2C_WR1_RDN 16 - /* Subaddr, Slave Addr, 0, length */ -#define REQ_17_SET_GET_I2CFP 17 - /* Write: Slave Addr, register, value */ - /* Read : Slave Addr, register, 2, data */ -#define REQ_20_DATA_TRANSFER 20 -#define REQ_30_I2C_WRITE 30 -#define REQ_31_I2C_READ 31 -#define REQ_35_AFTEK_TUNER_READ 35 -#define REQ_40_GET_VERSION 40 -#define REQ_50_SET_START 50 -#define REQ_51_SET_STOP 51 -#define REQ_52_TRANSMIT_DATA 52 -#define REQ_53_SPI_INITIAL 53 -#define REQ_54_SPI_SETSTART 54 -#define REQ_55_SPI_INOUTDATA 55 -#define REQ_56_SPI_SETSTOP 56 - -/* - * Define TV Master TM5600/TM6000/TM6010 GPIO lines - */ - -#define TM6000_GPIO_CLK 0x101 -#define TM6000_GPIO_DATA 0x100 - -#define TM6000_GPIO_1 0x102 -#define TM6000_GPIO_2 0x103 -#define TM6000_GPIO_3 0x104 -#define TM6000_GPIO_4 0x300 -#define TM6000_GPIO_5 0x301 -#define TM6000_GPIO_6 0x304 -#define TM6000_GPIO_7 0x305 - -/* tm6010 defines GPIO with different values */ -#define TM6010_GPIO_0 0x0102 -#define TM6010_GPIO_1 0x0103 -#define TM6010_GPIO_2 0x0104 -#define TM6010_GPIO_3 0x0105 -#define TM6010_GPIO_4 0x0106 -#define TM6010_GPIO_5 0x0107 -#define TM6010_GPIO_6 0x0300 -#define TM6010_GPIO_7 0x0301 -#define TM6010_GPIO_9 0x0305 -/* - * Define TV Master TM5600/TM6000/TM6010 URB message codes and length - */ - -enum { - TM6000_URB_MSG_VIDEO = 1, - TM6000_URB_MSG_AUDIO, - TM6000_URB_MSG_VBI, - TM6000_URB_MSG_PTS, - TM6000_URB_MSG_ERR, -}; - -/* Define specific TM6000 Video decoder registers */ -#define TM6000_REQ07_RD8_TEST_SEL 0x07, 0xd8 -#define TM6000_REQ07_RD9_A_SIM_SEL 0x07, 0xd9 -#define TM6000_REQ07_RDA_CLK_SEL 0x07, 0xda -#define TM6000_REQ07_RDB_OUT_SEL 0x07, 0xdb -#define TM6000_REQ07_RDC_NSEL_I2S 0x07, 0xdc -#define TM6000_REQ07_RDD_GPIO2_MDRV 0x07, 0xdd -#define TM6000_REQ07_RDE_GPIO1_MDRV 0x07, 0xde -#define TM6000_REQ07_RDF_PWDOWN_ACLK 0x07, 0xdf -#define TM6000_REQ07_RE0_VADC_REF_CTL 0x07, 0xe0 -#define TM6000_REQ07_RE1_VADC_DACLIMP 0x07, 0xe1 -#define TM6000_REQ07_RE2_VADC_STATUS_CTL 0x07, 0xe2 -#define TM6000_REQ07_RE3_VADC_INP_LPF_SEL1 0x07, 0xe3 -#define TM6000_REQ07_RE4_VADC_TARGET1 0x07, 0xe4 -#define TM6000_REQ07_RE5_VADC_INP_LPF_SEL2 0x07, 0xe5 -#define TM6000_REQ07_RE6_VADC_TARGET2 0x07, 0xe6 -#define TM6000_REQ07_RE7_VADC_AGAIN_CTL 0x07, 0xe7 -#define TM6000_REQ07_RE8_VADC_PWDOWN_CTL 0x07, 0xe8 -#define TM6000_REQ07_RE9_VADC_INPUT_CTL1 0x07, 0xe9 -#define TM6000_REQ07_REA_VADC_INPUT_CTL2 0x07, 0xea -#define TM6000_REQ07_REB_VADC_AADC_MODE 0x07, 0xeb -#define TM6000_REQ07_REC_VADC_AADC_LVOL 0x07, 0xec -#define TM6000_REQ07_RED_VADC_AADC_RVOL 0x07, 0xed -#define TM6000_REQ07_REE_VADC_CTRL_SEL_CONTROL 0x07, 0xee -#define TM6000_REQ07_REF_VADC_GAIN_MAP_CTL 0x07, 0xef -#define TM6000_REQ07_RFD_BIST_ERR_VST_LOW 0x07, 0xfd -#define TM6000_REQ07_RFE_BIST_ERR_VST_HIGH 0x07, 0xfe - -/* Define TM6000/TM6010 Video decoder registers */ -#define TM6010_REQ07_R00_VIDEO_CONTROL0 0x07, 0x00 -#define TM6010_REQ07_R01_VIDEO_CONTROL1 0x07, 0x01 -#define TM6010_REQ07_R02_VIDEO_CONTROL2 0x07, 0x02 -#define TM6010_REQ07_R03_YC_SEP_CONTROL 0x07, 0x03 -#define TM6010_REQ07_R04_LUMA_HAGC_CONTROL 0x07, 0x04 -#define TM6010_REQ07_R05_NOISE_THRESHOLD 0x07, 0x05 -#define TM6010_REQ07_R06_AGC_GATE_THRESHOLD 0x07, 0x06 -#define TM6010_REQ07_R07_OUTPUT_CONTROL 0x07, 0x07 -#define TM6010_REQ07_R08_LUMA_CONTRAST_ADJ 0x07, 0x08 -#define TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ 0x07, 0x09 -#define TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ 0x07, 0x0a -#define TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ 0x07, 0x0b -#define TM6010_REQ07_R0C_CHROMA_AGC_CONTROL 0x07, 0x0c -#define TM6010_REQ07_R0D_CHROMA_KILL_LEVEL 0x07, 0x0d -#define TM6010_REQ07_R0F_CHROMA_AUTO_POSITION 0x07, 0x0f -#define TM6010_REQ07_R10_AGC_PEAK_NOMINAL 0x07, 0x10 -#define TM6010_REQ07_R11_AGC_PEAK_CONTROL 0x07, 0x11 -#define TM6010_REQ07_R12_AGC_GATE_STARTH 0x07, 0x12 -#define TM6010_REQ07_R13_AGC_GATE_STARTL 0x07, 0x13 -#define TM6010_REQ07_R14_AGC_GATE_WIDTH 0x07, 0x14 -#define TM6010_REQ07_R15_AGC_BP_DELAY 0x07, 0x15 -#define TM6010_REQ07_R16_LOCK_COUNT 0x07, 0x16 -#define TM6010_REQ07_R17_HLOOP_MAXSTATE 0x07, 0x17 -#define TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3 0x07, 0x18 -#define TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2 0x07, 0x19 -#define TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1 0x07, 0x1a -#define TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0 0x07, 0x1b -#define TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3 0x07, 0x1c -#define TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2 0x07, 0x1d -#define TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1 0x07, 0x1e -#define TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0 0x07, 0x1f -#define TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME 0x07, 0x20 -#define TM6010_REQ07_R21_HSYNC_PHASE_OFFSET 0x07, 0x21 -#define TM6010_REQ07_R22_HSYNC_PLL_START_TIME 0x07, 0x22 -#define TM6010_REQ07_R23_HSYNC_PLL_END_TIME 0x07, 0x23 -#define TM6010_REQ07_R24_HSYNC_TIP_START_TIME 0x07, 0x24 -#define TM6010_REQ07_R25_HSYNC_TIP_END_TIME 0x07, 0x25 -#define TM6010_REQ07_R26_HSYNC_RISING_EDGE_START 0x07, 0x26 -#define TM6010_REQ07_R27_HSYNC_RISING_EDGE_END 0x07, 0x27 -#define TM6010_REQ07_R28_BACKPORCH_START 0x07, 0x28 -#define TM6010_REQ07_R29_BACKPORCH_END 0x07, 0x29 -#define TM6010_REQ07_R2A_HSYNC_FILTER_START 0x07, 0x2a -#define TM6010_REQ07_R2B_HSYNC_FILTER_END 0x07, 0x2b -#define TM6010_REQ07_R2C_CHROMA_BURST_START 0x07, 0x2c -#define TM6010_REQ07_R2D_CHROMA_BURST_END 0x07, 0x2d -#define TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART 0x07, 0x2e -#define TM6010_REQ07_R2F_ACTIVE_VIDEO_HWIDTH 0x07, 0x2f -#define TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART 0x07, 0x30 -#define TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT 0x07, 0x31 -#define TM6010_REQ07_R32_VSYNC_HLOCK_MIN 0x07, 0x32 -#define TM6010_REQ07_R33_VSYNC_HLOCK_MAX 0x07, 0x33 -#define TM6010_REQ07_R34_VSYNC_AGC_MIN 0x07, 0x34 -#define TM6010_REQ07_R35_VSYNC_AGC_MAX 0x07, 0x35 -#define TM6010_REQ07_R36_VSYNC_VBI_MIN 0x07, 0x36 -#define TM6010_REQ07_R37_VSYNC_VBI_MAX 0x07, 0x37 -#define TM6010_REQ07_R38_VSYNC_THRESHOLD 0x07, 0x38 -#define TM6010_REQ07_R39_VSYNC_TIME_CONSTANT 0x07, 0x39 -#define TM6010_REQ07_R3A_STATUS1 0x07, 0x3a -#define TM6010_REQ07_R3B_STATUS2 0x07, 0x3b -#define TM6010_REQ07_R3C_STATUS3 0x07, 0x3c -#define TM6010_REQ07_R3F_RESET 0x07, 0x3f -#define TM6010_REQ07_R40_TELETEXT_VBI_CODE0 0x07, 0x40 -#define TM6010_REQ07_R41_TELETEXT_VBI_CODE1 0x07, 0x41 -#define TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL 0x07, 0x42 -#define TM6010_REQ07_R43_VBI_DATA_TYPE_LINE7 0x07, 0x43 -#define TM6010_REQ07_R44_VBI_DATA_TYPE_LINE8 0x07, 0x44 -#define TM6010_REQ07_R45_VBI_DATA_TYPE_LINE9 0x07, 0x45 -#define TM6010_REQ07_R46_VBI_DATA_TYPE_LINE10 0x07, 0x46 -#define TM6010_REQ07_R47_VBI_DATA_TYPE_LINE11 0x07, 0x47 -#define TM6010_REQ07_R48_VBI_DATA_TYPE_LINE12 0x07, 0x48 -#define TM6010_REQ07_R49_VBI_DATA_TYPE_LINE13 0x07, 0x49 -#define TM6010_REQ07_R4A_VBI_DATA_TYPE_LINE14 0x07, 0x4a -#define TM6010_REQ07_R4B_VBI_DATA_TYPE_LINE15 0x07, 0x4b -#define TM6010_REQ07_R4C_VBI_DATA_TYPE_LINE16 0x07, 0x4c -#define TM6010_REQ07_R4D_VBI_DATA_TYPE_LINE17 0x07, 0x4d -#define TM6010_REQ07_R4E_VBI_DATA_TYPE_LINE18 0x07, 0x4e -#define TM6010_REQ07_R4F_VBI_DATA_TYPE_LINE19 0x07, 0x4f -#define TM6010_REQ07_R50_VBI_DATA_TYPE_LINE20 0x07, 0x50 -#define TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21 0x07, 0x51 -#define TM6010_REQ07_R52_VBI_DATA_TYPE_LINE22 0x07, 0x52 -#define TM6010_REQ07_R53_VBI_DATA_TYPE_LINE23 0x07, 0x53 -#define TM6010_REQ07_R54_VBI_DATA_TYPE_RLINES 0x07, 0x54 -#define TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN 0x07, 0x55 -#define TM6010_REQ07_R56_VBI_LOOP_FILTER_I_GAIN 0x07, 0x56 -#define TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN 0x07, 0x57 -#define TM6010_REQ07_R58_VBI_CAPTION_DTO1 0x07, 0x58 -#define TM6010_REQ07_R59_VBI_CAPTION_DTO0 0x07, 0x59 -#define TM6010_REQ07_R5A_VBI_TELETEXT_DTO1 0x07, 0x5a -#define TM6010_REQ07_R5B_VBI_TELETEXT_DTO0 0x07, 0x5b -#define TM6010_REQ07_R5C_VBI_WSS625_DTO1 0x07, 0x5c -#define TM6010_REQ07_R5D_VBI_WSS625_DTO0 0x07, 0x5d -#define TM6010_REQ07_R5E_VBI_CAPTION_FRAME_START 0x07, 0x5e -#define TM6010_REQ07_R5F_VBI_WSS625_FRAME_START 0x07, 0x5f -#define TM6010_REQ07_R60_TELETEXT_FRAME_START 0x07, 0x60 -#define TM6010_REQ07_R61_VBI_CCDATA1 0x07, 0x61 -#define TM6010_REQ07_R62_VBI_CCDATA2 0x07, 0x62 -#define TM6010_REQ07_R63_VBI_WSS625_DATA1 0x07, 0x63 -#define TM6010_REQ07_R64_VBI_WSS625_DATA2 0x07, 0x64 -#define TM6010_REQ07_R65_VBI_DATA_STATUS 0x07, 0x65 -#define TM6010_REQ07_R66_VBI_CAPTION_START 0x07, 0x66 -#define TM6010_REQ07_R67_VBI_WSS625_START 0x07, 0x67 -#define TM6010_REQ07_R68_VBI_TELETEXT_START 0x07, 0x68 -#define TM6010_REQ07_R70_HSYNC_DTO_INC_STATUS3 0x07, 0x70 -#define TM6010_REQ07_R71_HSYNC_DTO_INC_STATUS2 0x07, 0x71 -#define TM6010_REQ07_R72_HSYNC_DTO_INC_STATUS1 0x07, 0x72 -#define TM6010_REQ07_R73_HSYNC_DTO_INC_STATUS0 0x07, 0x73 -#define TM6010_REQ07_R74_CHROMA_DTO_INC_STATUS3 0x07, 0x74 -#define TM6010_REQ07_R75_CHROMA_DTO_INC_STATUS2 0x07, 0x75 -#define TM6010_REQ07_R76_CHROMA_DTO_INC_STATUS1 0x07, 0x76 -#define TM6010_REQ07_R77_CHROMA_DTO_INC_STATUS0 0x07, 0x77 -#define TM6010_REQ07_R78_AGC_AGAIN_STATUS 0x07, 0x78 -#define TM6010_REQ07_R79_AGC_DGAIN_STATUS 0x07, 0x79 -#define TM6010_REQ07_R7A_CHROMA_MAG_STATUS 0x07, 0x7a -#define TM6010_REQ07_R7B_CHROMA_GAIN_STATUS1 0x07, 0x7b -#define TM6010_REQ07_R7C_CHROMA_GAIN_STATUS0 0x07, 0x7c -#define TM6010_REQ07_R7D_CORDIC_FREQ_STATUS 0x07, 0x7d -#define TM6010_REQ07_R7F_STATUS_NOISE 0x07, 0x7f -#define TM6010_REQ07_R80_COMB_FILTER_TRESHOLD 0x07, 0x80 -#define TM6010_REQ07_R82_COMB_FILTER_CONFIG 0x07, 0x82 -#define TM6010_REQ07_R83_CHROMA_LOCK_CONFIG 0x07, 0x83 -#define TM6010_REQ07_R84_NOISE_NTSC_C 0x07, 0x84 -#define TM6010_REQ07_R85_NOISE_PAL_C 0x07, 0x85 -#define TM6010_REQ07_R86_NOISE_PHASE_C 0x07, 0x86 -#define TM6010_REQ07_R87_NOISE_PHASE_Y 0x07, 0x87 -#define TM6010_REQ07_R8A_CHROMA_LOOPFILTER_STATE 0x07, 0x8a -#define TM6010_REQ07_R8B_CHROMA_HRESAMPLER 0x07, 0x8b -#define TM6010_REQ07_R8D_CPUMP_DELAY_ADJ 0x07, 0x8d -#define TM6010_REQ07_R8E_CPUMP_ADJ 0x07, 0x8e -#define TM6010_REQ07_R8F_CPUMP_DELAY 0x07, 0x8f - -/* Define TM6000/TM6010 Miscellaneous registers */ -#define TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE 0x07, 0xc0 -#define TM6010_REQ07_RC1_TRESHOLD 0x07, 0xc1 -#define TM6010_REQ07_RC2_HSYNC_WIDTH 0x07, 0xc2 -#define TM6010_REQ07_RC3_HSTART1 0x07, 0xc3 -#define TM6010_REQ07_RC4_HSTART0 0x07, 0xc4 -#define TM6010_REQ07_RC5_HEND1 0x07, 0xc5 -#define TM6010_REQ07_RC6_HEND0 0x07, 0xc6 -#define TM6010_REQ07_RC7_VSTART1 0x07, 0xc7 -#define TM6010_REQ07_RC8_VSTART0 0x07, 0xc8 -#define TM6010_REQ07_RC9_VEND1 0x07, 0xc9 -#define TM6010_REQ07_RCA_VEND0 0x07, 0xca -#define TM6010_REQ07_RCB_DELAY 0x07, 0xcb -/* ONLY for TM6010 */ -#define TM6010_REQ07_RCC_ACTIVE_IF 0x07, 0xcc -#define TM6010_REQ07_RCC_ACTIVE_IF_VIDEO_ENABLE (1 << 5) -#define TM6010_REQ07_RCC_ACTIVE_IF_AUDIO_ENABLE (1 << 6) -#define TM6010_REQ07_RD0_USB_PERIPHERY_CONTROL 0x07, 0xd0 -#define TM6010_REQ07_RD1_ADDR_FOR_REQ1 0x07, 0xd1 -#define TM6010_REQ07_RD2_ADDR_FOR_REQ2 0x07, 0xd2 -#define TM6010_REQ07_RD3_ADDR_FOR_REQ3 0x07, 0xd3 -#define TM6010_REQ07_RD4_ADDR_FOR_REQ4 0x07, 0xd4 -#define TM6010_REQ07_RD5_POWERSAVE 0x07, 0xd5 -#define TM6010_REQ07_RD6_ENDP_REQ1_REQ2 0x07, 0xd6 -#define TM6010_REQ07_RD7_ENDP_REQ3_REQ4 0x07, 0xd7 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR 0x07, 0xd8 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_BSIZE 0x07, 0xd9 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_WAKEUP_SEL 0x07, 0xda -/* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_WAKEUP_ADD 0x07, 0xdb -/* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_LEADER1 0x07, 0xdc -/* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_LEADER0 0x07, 0xdd -/* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_PULSE_CNT1 0x07, 0xde -/* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_PULSE_CNT0 0x07, 0xdf -/* ONLY for TM6010 */ -#define TM6010_REQ07_RE0_DVIDEO_SOURCE 0x07, 0xe0 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RE0_DVIDEO_SOURCE_IF 0x07, 0xe1 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RE2_OUT_SEL2 0x07, 0xe2 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RE3_OUT_SEL1 0x07, 0xe3 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RE4_OUT_SEL0 0x07, 0xe4 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RE5_REMOTE_WAKEUP 0x07, 0xe5 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RE7_PUB_GPIO 0x07, 0xe7 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RE8_TYPESEL_MOS_I2S 0x07, 0xe8 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RE9_TYPESEL_MOS_TS 0x07, 0xe9 -/* ONLY for TM6010 */ -#define TM6010_REQ07_REA_TYPESEL_MOS_CCIR 0x07, 0xea -/* ONLY for TM6010 */ -#define TM6010_REQ07_RF0_BIST_CRC_RESULT0 0x07, 0xf0 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RF1_BIST_CRC_RESULT1 0x07, 0xf1 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RF2_BIST_CRC_RESULT2 0x07, 0xf2 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RF3_BIST_CRC_RESULT3 0x07, 0xf3 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RF4_BIST_ERR_VST2 0x07, 0xf4 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RF5_BIST_ERR_VST1 0x07, 0xf5 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RF6_BIST_ERR_VST0 0x07, 0xf6 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RF7_BIST 0x07, 0xf7 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RFE_POWER_DOWN 0x07, 0xfe -#define TM6010_REQ07_RFF_SOFT_RESET 0x07, 0xff - -/* Define TM6000/TM6010 USB registers */ -#define TM6010_REQ05_R00_MAIN_CTRL 0x05, 0x00 -#define TM6010_REQ05_R01_DEVADDR 0x05, 0x01 -#define TM6010_REQ05_R02_TEST 0x05, 0x02 -#define TM6010_REQ05_R04_SOFN0 0x05, 0x04 -#define TM6010_REQ05_R05_SOFN1 0x05, 0x05 -#define TM6010_REQ05_R06_SOFTM0 0x05, 0x06 -#define TM6010_REQ05_R07_SOFTM1 0x05, 0x07 -#define TM6010_REQ05_R08_PHY_TEST 0x05, 0x08 -#define TM6010_REQ05_R09_VCTL 0x05, 0x09 -#define TM6010_REQ05_R0A_VSTA 0x05, 0x0a -#define TM6010_REQ05_R0B_CX_CFG 0x05, 0x0b -#define TM6010_REQ05_R0C_ENDP0_REG0 0x05, 0x0c -#define TM6010_REQ05_R10_GMASK 0x05, 0x10 -#define TM6010_REQ05_R11_IMASK0 0x05, 0x11 -#define TM6010_REQ05_R12_IMASK1 0x05, 0x12 -#define TM6010_REQ05_R13_IMASK2 0x05, 0x13 -#define TM6010_REQ05_R14_IMASK3 0x05, 0x14 -#define TM6010_REQ05_R15_IMASK4 0x05, 0x15 -#define TM6010_REQ05_R16_IMASK5 0x05, 0x16 -#define TM6010_REQ05_R17_IMASK6 0x05, 0x17 -#define TM6010_REQ05_R18_IMASK7 0x05, 0x18 -#define TM6010_REQ05_R19_ZEROP0 0x05, 0x19 -#define TM6010_REQ05_R1A_ZEROP1 0x05, 0x1a -#define TM6010_REQ05_R1C_FIFO_EMP0 0x05, 0x1c -#define TM6010_REQ05_R1D_FIFO_EMP1 0x05, 0x1d -#define TM6010_REQ05_R20_IRQ_GROUP 0x05, 0x20 -#define TM6010_REQ05_R21_IRQ_SOURCE0 0x05, 0x21 -#define TM6010_REQ05_R22_IRQ_SOURCE1 0x05, 0x22 -#define TM6010_REQ05_R23_IRQ_SOURCE2 0x05, 0x23 -#define TM6010_REQ05_R24_IRQ_SOURCE3 0x05, 0x24 -#define TM6010_REQ05_R25_IRQ_SOURCE4 0x05, 0x25 -#define TM6010_REQ05_R26_IRQ_SOURCE5 0x05, 0x26 -#define TM6010_REQ05_R27_IRQ_SOURCE6 0x05, 0x27 -#define TM6010_REQ05_R28_IRQ_SOURCE7 0x05, 0x28 -#define TM6010_REQ05_R29_SEQ_ERR0 0x05, 0x29 -#define TM6010_REQ05_R2A_SEQ_ERR1 0x05, 0x2a -#define TM6010_REQ05_R2B_SEQ_ABORT0 0x05, 0x2b -#define TM6010_REQ05_R2C_SEQ_ABORT1 0x05, 0x2c -#define TM6010_REQ05_R2D_TX_ZERO0 0x05, 0x2d -#define TM6010_REQ05_R2E_TX_ZERO1 0x05, 0x2e -#define TM6010_REQ05_R2F_IDLE_CNT 0x05, 0x2f -#define TM6010_REQ05_R30_FNO_P1 0x05, 0x30 -#define TM6010_REQ05_R31_FNO_P2 0x05, 0x31 -#define TM6010_REQ05_R32_FNO_P3 0x05, 0x32 -#define TM6010_REQ05_R33_FNO_P4 0x05, 0x33 -#define TM6010_REQ05_R34_FNO_P5 0x05, 0x34 -#define TM6010_REQ05_R35_FNO_P6 0x05, 0x35 -#define TM6010_REQ05_R36_FNO_P7 0x05, 0x36 -#define TM6010_REQ05_R37_FNO_P8 0x05, 0x37 -#define TM6010_REQ05_R38_FNO_P9 0x05, 0x38 -#define TM6010_REQ05_R30_FNO_P10 0x05, 0x39 -#define TM6010_REQ05_R30_FNO_P11 0x05, 0x3a -#define TM6010_REQ05_R30_FNO_P12 0x05, 0x3b -#define TM6010_REQ05_R30_FNO_P13 0x05, 0x3c -#define TM6010_REQ05_R30_FNO_P14 0x05, 0x3d -#define TM6010_REQ05_R30_FNO_P15 0x05, 0x3e -#define TM6010_REQ05_R40_IN_MAXPS_LOW1 0x05, 0x40 -#define TM6010_REQ05_R41_IN_MAXPS_HIGH1 0x05, 0x41 -#define TM6010_REQ05_R42_IN_MAXPS_LOW2 0x05, 0x42 -#define TM6010_REQ05_R43_IN_MAXPS_HIGH2 0x05, 0x43 -#define TM6010_REQ05_R44_IN_MAXPS_LOW3 0x05, 0x44 -#define TM6010_REQ05_R45_IN_MAXPS_HIGH3 0x05, 0x45 -#define TM6010_REQ05_R46_IN_MAXPS_LOW4 0x05, 0x46 -#define TM6010_REQ05_R47_IN_MAXPS_HIGH4 0x05, 0x47 -#define TM6010_REQ05_R48_IN_MAXPS_LOW5 0x05, 0x48 -#define TM6010_REQ05_R49_IN_MAXPS_HIGH5 0x05, 0x49 -#define TM6010_REQ05_R4A_IN_MAXPS_LOW6 0x05, 0x4a -#define TM6010_REQ05_R4B_IN_MAXPS_HIGH6 0x05, 0x4b -#define TM6010_REQ05_R4C_IN_MAXPS_LOW7 0x05, 0x4c -#define TM6010_REQ05_R4D_IN_MAXPS_HIGH7 0x05, 0x4d -#define TM6010_REQ05_R4E_IN_MAXPS_LOW8 0x05, 0x4e -#define TM6010_REQ05_R4F_IN_MAXPS_HIGH8 0x05, 0x4f -#define TM6010_REQ05_R50_IN_MAXPS_LOW9 0x05, 0x50 -#define TM6010_REQ05_R51_IN_MAXPS_HIGH9 0x05, 0x51 -#define TM6010_REQ05_R40_IN_MAXPS_LOW10 0x05, 0x52 -#define TM6010_REQ05_R41_IN_MAXPS_HIGH10 0x05, 0x53 -#define TM6010_REQ05_R40_IN_MAXPS_LOW11 0x05, 0x54 -#define TM6010_REQ05_R41_IN_MAXPS_HIGH11 0x05, 0x55 -#define TM6010_REQ05_R40_IN_MAXPS_LOW12 0x05, 0x56 -#define TM6010_REQ05_R41_IN_MAXPS_HIGH12 0x05, 0x57 -#define TM6010_REQ05_R40_IN_MAXPS_LOW13 0x05, 0x58 -#define TM6010_REQ05_R41_IN_MAXPS_HIGH13 0x05, 0x59 -#define TM6010_REQ05_R40_IN_MAXPS_LOW14 0x05, 0x5a -#define TM6010_REQ05_R41_IN_MAXPS_HIGH14 0x05, 0x5b -#define TM6010_REQ05_R40_IN_MAXPS_LOW15 0x05, 0x5c -#define TM6010_REQ05_R41_IN_MAXPS_HIGH15 0x05, 0x5d -#define TM6010_REQ05_R60_OUT_MAXPS_LOW1 0x05, 0x60 -#define TM6010_REQ05_R61_OUT_MAXPS_HIGH1 0x05, 0x61 -#define TM6010_REQ05_R62_OUT_MAXPS_LOW2 0x05, 0x62 -#define TM6010_REQ05_R63_OUT_MAXPS_HIGH2 0x05, 0x63 -#define TM6010_REQ05_R64_OUT_MAXPS_LOW3 0x05, 0x64 -#define TM6010_REQ05_R65_OUT_MAXPS_HIGH3 0x05, 0x65 -#define TM6010_REQ05_R66_OUT_MAXPS_LOW4 0x05, 0x66 -#define TM6010_REQ05_R67_OUT_MAXPS_HIGH4 0x05, 0x67 -#define TM6010_REQ05_R68_OUT_MAXPS_LOW5 0x05, 0x68 -#define TM6010_REQ05_R69_OUT_MAXPS_HIGH5 0x05, 0x69 -#define TM6010_REQ05_R6A_OUT_MAXPS_LOW6 0x05, 0x6a -#define TM6010_REQ05_R6B_OUT_MAXPS_HIGH6 0x05, 0x6b -#define TM6010_REQ05_R6C_OUT_MAXPS_LOW7 0x05, 0x6c -#define TM6010_REQ05_R6D_OUT_MAXPS_HIGH7 0x05, 0x6d -#define TM6010_REQ05_R6E_OUT_MAXPS_LOW8 0x05, 0x6e -#define TM6010_REQ05_R6F_OUT_MAXPS_HIGH8 0x05, 0x6f -#define TM6010_REQ05_R70_OUT_MAXPS_LOW9 0x05, 0x70 -#define TM6010_REQ05_R71_OUT_MAXPS_HIGH9 0x05, 0x71 -#define TM6010_REQ05_R60_OUT_MAXPS_LOW10 0x05, 0x72 -#define TM6010_REQ05_R61_OUT_MAXPS_HIGH10 0x05, 0x73 -#define TM6010_REQ05_R60_OUT_MAXPS_LOW11 0x05, 0x74 -#define TM6010_REQ05_R61_OUT_MAXPS_HIGH11 0x05, 0x75 -#define TM6010_REQ05_R60_OUT_MAXPS_LOW12 0x05, 0x76 -#define TM6010_REQ05_R61_OUT_MAXPS_HIGH12 0x05, 0x77 -#define TM6010_REQ05_R60_OUT_MAXPS_LOW13 0x05, 0x78 -#define TM6010_REQ05_R61_OUT_MAXPS_HIGH13 0x05, 0x79 -#define TM6010_REQ05_R60_OUT_MAXPS_LOW14 0x05, 0x7a -#define TM6010_REQ05_R61_OUT_MAXPS_HIGH14 0x05, 0x7b -#define TM6010_REQ05_R60_OUT_MAXPS_LOW15 0x05, 0x7c -#define TM6010_REQ05_R61_OUT_MAXPS_HIGH15 0x05, 0x7d -#define TM6010_REQ05_R80_FIFO0 0x05, 0x80 -#define TM6010_REQ05_R81_FIFO1 0x05, 0x81 -#define TM6010_REQ05_R82_FIFO2 0x05, 0x82 -#define TM6010_REQ05_R83_FIFO3 0x05, 0x83 -#define TM6010_REQ05_R84_FIFO4 0x05, 0x84 -#define TM6010_REQ05_R85_FIFO5 0x05, 0x85 -#define TM6010_REQ05_R86_FIFO6 0x05, 0x86 -#define TM6010_REQ05_R87_FIFO7 0x05, 0x87 -#define TM6010_REQ05_R88_FIFO8 0x05, 0x88 -#define TM6010_REQ05_R89_FIFO9 0x05, 0x89 -#define TM6010_REQ05_R81_FIFO10 0x05, 0x8a -#define TM6010_REQ05_R81_FIFO11 0x05, 0x8b -#define TM6010_REQ05_R81_FIFO12 0x05, 0x8c -#define TM6010_REQ05_R81_FIFO13 0x05, 0x8d -#define TM6010_REQ05_R81_FIFO14 0x05, 0x8e -#define TM6010_REQ05_R81_FIFO15 0x05, 0x8f -#define TM6010_REQ05_R90_CFG_FIFO0 0x05, 0x90 -#define TM6010_REQ05_R91_CFG_FIFO1 0x05, 0x91 -#define TM6010_REQ05_R92_CFG_FIFO2 0x05, 0x92 -#define TM6010_REQ05_R93_CFG_FIFO3 0x05, 0x93 -#define TM6010_REQ05_R94_CFG_FIFO4 0x05, 0x94 -#define TM6010_REQ05_R95_CFG_FIFO5 0x05, 0x95 -#define TM6010_REQ05_R96_CFG_FIFO6 0x05, 0x96 -#define TM6010_REQ05_R97_CFG_FIFO7 0x05, 0x97 -#define TM6010_REQ05_R98_CFG_FIFO8 0x05, 0x98 -#define TM6010_REQ05_R99_CFG_FIFO9 0x05, 0x99 -#define TM6010_REQ05_R91_CFG_FIFO10 0x05, 0x9a -#define TM6010_REQ05_R91_CFG_FIFO11 0x05, 0x9b -#define TM6010_REQ05_R91_CFG_FIFO12 0x05, 0x9c -#define TM6010_REQ05_R91_CFG_FIFO13 0x05, 0x9d -#define TM6010_REQ05_R91_CFG_FIFO14 0x05, 0x9e -#define TM6010_REQ05_R91_CFG_FIFO15 0x05, 0x9f -#define TM6010_REQ05_RA0_CTL_FIFO0 0x05, 0xa0 -#define TM6010_REQ05_RA1_CTL_FIFO1 0x05, 0xa1 -#define TM6010_REQ05_RA2_CTL_FIFO2 0x05, 0xa2 -#define TM6010_REQ05_RA3_CTL_FIFO3 0x05, 0xa3 -#define TM6010_REQ05_RA4_CTL_FIFO4 0x05, 0xa4 -#define TM6010_REQ05_RA5_CTL_FIFO5 0x05, 0xa5 -#define TM6010_REQ05_RA6_CTL_FIFO6 0x05, 0xa6 -#define TM6010_REQ05_RA7_CTL_FIFO7 0x05, 0xa7 -#define TM6010_REQ05_RA8_CTL_FIFO8 0x05, 0xa8 -#define TM6010_REQ05_RA9_CTL_FIFO9 0x05, 0xa9 -#define TM6010_REQ05_RA1_CTL_FIFO10 0x05, 0xaa -#define TM6010_REQ05_RA1_CTL_FIFO11 0x05, 0xab -#define TM6010_REQ05_RA1_CTL_FIFO12 0x05, 0xac -#define TM6010_REQ05_RA1_CTL_FIFO13 0x05, 0xad -#define TM6010_REQ05_RA1_CTL_FIFO14 0x05, 0xae -#define TM6010_REQ05_RA1_CTL_FIFO15 0x05, 0xaf -#define TM6010_REQ05_RB0_BC_LOW_FIFO0 0x05, 0xb0 -#define TM6010_REQ05_RB1_BC_LOW_FIFO1 0x05, 0xb1 -#define TM6010_REQ05_RB2_BC_LOW_FIFO2 0x05, 0xb2 -#define TM6010_REQ05_RB3_BC_LOW_FIFO3 0x05, 0xb3 -#define TM6010_REQ05_RB4_BC_LOW_FIFO4 0x05, 0xb4 -#define TM6010_REQ05_RB5_BC_LOW_FIFO5 0x05, 0xb5 -#define TM6010_REQ05_RB6_BC_LOW_FIFO6 0x05, 0xb6 -#define TM6010_REQ05_RB7_BC_LOW_FIFO7 0x05, 0xb7 -#define TM6010_REQ05_RB8_BC_LOW_FIFO8 0x05, 0xb8 -#define TM6010_REQ05_RB9_BC_LOW_FIFO9 0x05, 0xb9 -#define TM6010_REQ05_RB1_BC_LOW_FIFO10 0x05, 0xba -#define TM6010_REQ05_RB1_BC_LOW_FIFO11 0x05, 0xbb -#define TM6010_REQ05_RB1_BC_LOW_FIFO12 0x05, 0xbc -#define TM6010_REQ05_RB1_BC_LOW_FIFO13 0x05, 0xbd -#define TM6010_REQ05_RB1_BC_LOW_FIFO14 0x05, 0xbe -#define TM6010_REQ05_RB1_BC_LOW_FIFO15 0x05, 0xbf -#define TM6010_REQ05_RC0_DATA_FIFO0 0x05, 0xc0 -#define TM6010_REQ05_RC4_DATA_FIFO1 0x05, 0xc4 -#define TM6010_REQ05_RC8_DATA_FIFO2 0x05, 0xc8 -#define TM6010_REQ05_RCC_DATA_FIFO3 0x05, 0xcc -#define TM6010_REQ05_RD0_DATA_FIFO4 0x05, 0xd0 -#define TM6010_REQ05_RD4_DATA_FIFO5 0x05, 0xd4 -#define TM6010_REQ05_RD8_DATA_FIFO6 0x05, 0xd8 -#define TM6010_REQ05_RDC_DATA_FIFO7 0x05, 0xdc -#define TM6010_REQ05_RE0_DATA_FIFO8 0x05, 0xe0 -#define TM6010_REQ05_RE4_DATA_FIFO9 0x05, 0xe4 -#define TM6010_REQ05_RC4_DATA_FIFO10 0x05, 0xe8 -#define TM6010_REQ05_RC4_DATA_FIFO11 0x05, 0xec -#define TM6010_REQ05_RC4_DATA_FIFO12 0x05, 0xf0 -#define TM6010_REQ05_RC4_DATA_FIFO13 0x05, 0xf4 -#define TM6010_REQ05_RC4_DATA_FIFO14 0x05, 0xf8 -#define TM6010_REQ05_RC4_DATA_FIFO15 0x05, 0xfc - -/* Define TM6010 Audio decoder registers */ -/* This core available only in TM6010 */ -#define TM6010_REQ08_R00_A_VERSION 0x08, 0x00 -#define TM6010_REQ08_R01_A_INIT 0x08, 0x01 -#define TM6010_REQ08_R02_A_FIX_GAIN_CTRL 0x08, 0x02 -#define TM6010_REQ08_R03_A_AUTO_GAIN_CTRL 0x08, 0x03 -#define TM6010_REQ08_R04_A_SIF_AMP_CTRL 0x08, 0x04 -#define TM6010_REQ08_R05_A_STANDARD_MOD 0x08, 0x05 -#define TM6010_REQ08_R06_A_SOUND_MOD 0x08, 0x06 -#define TM6010_REQ08_R07_A_LEFT_VOL 0x08, 0x07 -#define TM6010_REQ08_R08_A_RIGHT_VOL 0x08, 0x08 -#define TM6010_REQ08_R09_A_MAIN_VOL 0x08, 0x09 -#define TM6010_REQ08_R0A_A_I2S_MOD 0x08, 0x0a -#define TM6010_REQ08_R0B_A_ASD_THRES1 0x08, 0x0b -#define TM6010_REQ08_R0C_A_ASD_THRES2 0x08, 0x0c -#define TM6010_REQ08_R0D_A_AMD_THRES 0x08, 0x0d -#define TM6010_REQ08_R0E_A_MONO_THRES1 0x08, 0x0e -#define TM6010_REQ08_R0F_A_MONO_THRES2 0x08, 0x0f -#define TM6010_REQ08_R10_A_MUTE_THRES1 0x08, 0x10 -#define TM6010_REQ08_R11_A_MUTE_THRES2 0x08, 0x11 -#define TM6010_REQ08_R12_A_AGC_U 0x08, 0x12 -#define TM6010_REQ08_R13_A_AGC_ERR_T 0x08, 0x13 -#define TM6010_REQ08_R14_A_AGC_GAIN_INIT 0x08, 0x14 -#define TM6010_REQ08_R15_A_AGC_STEP_THR 0x08, 0x15 -#define TM6010_REQ08_R16_A_AGC_GAIN_MAX 0x08, 0x16 -#define TM6010_REQ08_R17_A_AGC_GAIN_MIN 0x08, 0x17 -#define TM6010_REQ08_R18_A_TR_CTRL 0x08, 0x18 -#define TM6010_REQ08_R19_A_FH_2FH_GAIN 0x08, 0x19 -#define TM6010_REQ08_R1A_A_NICAM_SER_MAX 0x08, 0x1a -#define TM6010_REQ08_R1B_A_NICAM_SER_MIN 0x08, 0x1b -#define TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT 0x08, 0x1e -#define TM6010_REQ08_R1F_A_TEST_INTF_SEL 0x08, 0x1f -#define TM6010_REQ08_R20_A_TEST_PIN_SEL 0x08, 0x20 -#define TM6010_REQ08_R21_A_AGC_ERR 0x08, 0x21 -#define TM6010_REQ08_R22_A_AGC_GAIN 0x08, 0x22 -#define TM6010_REQ08_R23_A_NICAM_INFO 0x08, 0x23 -#define TM6010_REQ08_R24_A_SER 0x08, 0x24 -#define TM6010_REQ08_R25_A_C1_AMP 0x08, 0x25 -#define TM6010_REQ08_R26_A_C2_AMP 0x08, 0x26 -#define TM6010_REQ08_R27_A_NOISE_AMP 0x08, 0x27 -#define TM6010_REQ08_R28_A_AUDIO_MODE_RES 0x08, 0x28 - -/* Define TM6010 Video ADC registers */ -#define TM6010_REQ08_RE0_ADC_REF 0x08, 0xe0 -#define TM6010_REQ08_RE1_DAC_CLMP 0x08, 0xe1 -#define TM6010_REQ08_RE2_POWER_DOWN_CTRL1 0x08, 0xe2 -#define TM6010_REQ08_RE3_ADC_IN1_SEL 0x08, 0xe3 -#define TM6010_REQ08_RE4_ADC_IN2_SEL 0x08, 0xe4 -#define TM6010_REQ08_RE5_GAIN_PARAM 0x08, 0xe5 -#define TM6010_REQ08_RE6_POWER_DOWN_CTRL2 0x08, 0xe6 -#define TM6010_REQ08_RE7_REG_GAIN_Y 0x08, 0xe7 -#define TM6010_REQ08_RE8_REG_GAIN_C 0x08, 0xe8 -#define TM6010_REQ08_RE9_BIAS_CTRL 0x08, 0xe9 -#define TM6010_REQ08_REA_BUFF_DRV_CTRL 0x08, 0xea -#define TM6010_REQ08_REB_SIF_GAIN_CTRL 0x08, 0xeb -#define TM6010_REQ08_REC_REVERSE_YC_CTRL 0x08, 0xec -#define TM6010_REQ08_RED_GAIN_SEL 0x08, 0xed - -/* Define TM6010 Audio ADC registers */ -#define TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG 0x08, 0xf0 -#define TM6010_REQ08_RF1_AADC_POWER_DOWN 0x08, 0xf1 -#define TM6010_REQ08_RF2_LEFT_CHANNEL_VOL 0x08, 0xf2 -#define TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL 0x08, 0xf3 diff --git a/drivers/staging/tm6000/tm6000-stds.c b/drivers/staging/tm6000/tm6000-stds.c deleted file mode 100644 index 9a4145d..0000000 --- a/drivers/staging/tm6000/tm6000-stds.c +++ /dev/null @@ -1,659 +0,0 @@ -/* - * tm6000-stds.c - driver for TM5600/TM6000/TM6010 USB video capture devices - * - * Copyright (C) 2007 Mauro Carvalho Chehab - * - * 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 version 2 - * - * 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 -#include -#include "tm6000.h" -#include "tm6000-regs.h" - -static unsigned int tm6010_a_mode; -module_param(tm6010_a_mode, int, 0644); -MODULE_PARM_DESC(tm6010_a_mode, "set tm6010 sif audio mode"); - -struct tm6000_reg_settings { - unsigned char req; - unsigned char reg; - unsigned char value; -}; - - -struct tm6000_std_settings { - v4l2_std_id id; - struct tm6000_reg_settings *common; -}; - -static struct tm6000_reg_settings composite_pal_m[] = { - { TM6010_REQ07_R3F_RESET, 0x01 }, - { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x04 }, - { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, - { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, - { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 }, - { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, - { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, - { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83 }, - { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a }, - { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe0 }, - { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, - { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, - { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, - { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, - { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, - { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x20 }, - { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 }, - { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c }, - { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, - { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 }, - { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, - { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc }, - { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, - { TM6010_REQ07_R3F_RESET, 0x00 }, - { 0, 0, 0 } -}; - -static struct tm6000_reg_settings composite_pal_nc[] = { - { TM6010_REQ07_R3F_RESET, 0x01 }, - { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x36 }, - { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, - { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, - { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02 }, - { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, - { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, - { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91 }, - { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f }, - { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x0c }, - { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, - { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, - { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, - { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, - { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c }, - { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c }, - { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 }, - { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c }, - { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, - { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 }, - { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, - { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc }, - { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, - { TM6010_REQ07_R3F_RESET, 0x00 }, - { 0, 0, 0 } -}; - -static struct tm6000_reg_settings composite_pal[] = { - { TM6010_REQ07_R3F_RESET, 0x01 }, - { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x32 }, - { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, - { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, - { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02 }, - { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, - { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25 }, - { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5 }, - { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63 }, - { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x50 }, - { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, - { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, - { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, - { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, - { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c }, - { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c }, - { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 }, - { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c }, - { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, - { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 }, - { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, - { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc }, - { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, - { TM6010_REQ07_R3F_RESET, 0x00 }, - { 0, 0, 0 } -}; - -static struct tm6000_reg_settings composite_secam[] = { - { TM6010_REQ07_R3F_RESET, 0x01 }, - { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x38 }, - { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, - { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, - { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02 }, - { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, - { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24 }, - { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92 }, - { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8 }, - { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed }, - { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, - { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, - { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, - { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, - { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c }, - { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c }, - { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 }, - { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c }, - { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18 }, - { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 }, - { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xff }, - { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, - { TM6010_REQ07_R3F_RESET, 0x00 }, - { 0, 0, 0 } -}; - -static struct tm6000_reg_settings composite_ntsc[] = { - { TM6010_REQ07_R3F_RESET, 0x01 }, - { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 }, - { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f }, - { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, - { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 }, - { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, - { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, - { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b }, - { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 }, - { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 }, - { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, - { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, - { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, - { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, - { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, - { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 }, - { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 }, - { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c }, - { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, - { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 }, - { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, - { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdd }, - { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, - { TM6010_REQ07_R3F_RESET, 0x00 }, - { 0, 0, 0 } -}; - -static struct tm6000_std_settings composite_stds[] = { - { .id = V4L2_STD_PAL_M, .common = composite_pal_m, }, - { .id = V4L2_STD_PAL_Nc, .common = composite_pal_nc, }, - { .id = V4L2_STD_PAL, .common = composite_pal, }, - { .id = V4L2_STD_SECAM, .common = composite_secam, }, - { .id = V4L2_STD_NTSC, .common = composite_ntsc, }, -}; - -static struct tm6000_reg_settings svideo_pal_m[] = { - { TM6010_REQ07_R3F_RESET, 0x01 }, - { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x05 }, - { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, - { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, - { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04 }, - { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, - { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, - { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83 }, - { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a }, - { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe0 }, - { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, - { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, - { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, - { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, - { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, - { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 }, - { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 }, - { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c }, - { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, - { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 }, - { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, - { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc }, - { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, - { TM6010_REQ07_R3F_RESET, 0x00 }, - { 0, 0, 0 } -}; - -static struct tm6000_reg_settings svideo_pal_nc[] = { - { TM6010_REQ07_R3F_RESET, 0x01 }, - { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x37 }, - { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, - { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, - { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04 }, - { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, - { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, - { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91 }, - { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f }, - { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x0c }, - { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, - { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, - { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, - { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, - { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, - { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 }, - { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 }, - { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c }, - { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, - { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 }, - { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, - { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc }, - { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, - { TM6010_REQ07_R3F_RESET, 0x00 }, - { 0, 0, 0 } -}; - -static struct tm6000_reg_settings svideo_pal[] = { - { TM6010_REQ07_R3F_RESET, 0x01 }, - { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x33 }, - { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, - { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, - { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04 }, - { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x30 }, - { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25 }, - { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5 }, - { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63 }, - { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x50 }, - { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, - { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, - { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, - { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, - { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c }, - { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2a }, - { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 }, - { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c }, - { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, - { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 }, - { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, - { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc }, - { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, - { TM6010_REQ07_R3F_RESET, 0x00 }, - { 0, 0, 0 } -}; - -static struct tm6000_reg_settings svideo_secam[] = { - { TM6010_REQ07_R3F_RESET, 0x01 }, - { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x39 }, - { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, - { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, - { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03 }, - { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, - { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24 }, - { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92 }, - { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8 }, - { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed }, - { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, - { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, - { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, - { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, - { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c }, - { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2a }, - { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 }, - { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c }, - { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18 }, - { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 }, - { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xff }, - { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, - { TM6010_REQ07_R3F_RESET, 0x00 }, - { 0, 0, 0 } -}; - -static struct tm6000_reg_settings svideo_ntsc[] = { - { TM6010_REQ07_R3F_RESET, 0x01 }, - { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x01 }, - { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f }, - { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, - { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03 }, - { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x30 }, - { TM6010_REQ07_R17_HLOOP_MAXSTATE, 0x8b }, - { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, - { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b }, - { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 }, - { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 }, - { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, - { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, - { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, - { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, - { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, - { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 }, - { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 }, - { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c }, - { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, - { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 }, - { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, - { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdd }, - { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, - { TM6010_REQ07_R3F_RESET, 0x00 }, - { 0, 0, 0 } -}; - -static struct tm6000_std_settings svideo_stds[] = { - { .id = V4L2_STD_PAL_M, .common = svideo_pal_m, }, - { .id = V4L2_STD_PAL_Nc, .common = svideo_pal_nc, }, - { .id = V4L2_STD_PAL, .common = svideo_pal, }, - { .id = V4L2_STD_SECAM, .common = svideo_secam, }, - { .id = V4L2_STD_NTSC, .common = svideo_ntsc, }, -}; - -static int tm6000_set_audio_std(struct tm6000_core *dev) -{ - uint8_t areg_02 = 0x04; /* GC1 Fixed gain 0dB */ - uint8_t areg_05 = 0x01; /* Auto 4.5 = M Japan, Auto 6.5 = DK */ - uint8_t areg_06 = 0x02; /* Auto de-emphasis, mannual channel mode */ - uint8_t nicam_flag = 0; /* No NICAM */ - - if (dev->radio) { - tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, 0x04); - tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0x80); - tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, 0x0c); - /* set mono or stereo */ - if (dev->amode == V4L2_TUNER_MODE_MONO) - tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x00); - else if (dev->amode == V4L2_TUNER_MODE_STEREO) - tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x02); - tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x18); - tm6000_set_reg(dev, TM6010_REQ08_R0C_A_ASD_THRES2, 0x0a); - tm6000_set_reg(dev, TM6010_REQ08_R0D_A_AMD_THRES, 0x40); - tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe); - tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13); - tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80); - tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, 0xff); - return 0; - } - - switch (tm6010_a_mode) { - /* auto */ - case 0: - switch (dev->norm) { - case V4L2_STD_NTSC_M_KR: - areg_05 |= 0x00; - break; - case V4L2_STD_NTSC_M_JP: - areg_05 |= 0x40; - break; - case V4L2_STD_NTSC_M: - case V4L2_STD_PAL_M: - case V4L2_STD_PAL_N: - areg_05 |= 0x20; - break; - case V4L2_STD_PAL_Nc: - areg_05 |= 0x60; - break; - case V4L2_STD_SECAM_L: - areg_05 |= 0x00; - break; - case V4L2_STD_DK: - areg_05 |= 0x10; - break; - } - break; - /* A2 */ - case 1: - switch (dev->norm) { - case V4L2_STD_B: - case V4L2_STD_GH: - areg_05 = 0x05; - break; - case V4L2_STD_DK: - areg_05 = 0x09; - break; - } - break; - /* NICAM */ - case 2: - switch (dev->norm) { - case V4L2_STD_B: - case V4L2_STD_GH: - areg_05 = 0x07; - break; - case V4L2_STD_DK: - areg_05 = 0x06; - break; - case V4L2_STD_PAL_I: - areg_05 = 0x08; - break; - case V4L2_STD_SECAM_L: - areg_05 = 0x0a; - areg_02 = 0x02; - break; - } - nicam_flag = 1; - break; - /* other */ - case 3: - switch (dev->norm) { - /* DK3_A2 */ - case V4L2_STD_DK: - areg_05 = 0x0b; - break; - /* Korea */ - case V4L2_STD_NTSC_M_KR: - areg_05 = 0x04; - break; - /* EIAJ */ - case V4L2_STD_NTSC_M_JP: - areg_05 = 0x03; - break; - default: - areg_05 = 0x02; - break; - } - break; - } - - tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, areg_02); - tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0xa0); - tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, areg_05); - tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, areg_06); - tm6000_set_reg(dev, TM6010_REQ08_R07_A_LEFT_VOL, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x08); - tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0x91); - tm6000_set_reg(dev, TM6010_REQ08_R0B_A_ASD_THRES1, 0x20); - tm6000_set_reg(dev, TM6010_REQ08_R0C_A_ASD_THRES2, 0x12); - tm6000_set_reg(dev, TM6010_REQ08_R0D_A_AMD_THRES, 0x20); - tm6000_set_reg(dev, TM6010_REQ08_R0E_A_MONO_THRES1, 0xf0); - tm6000_set_reg(dev, TM6010_REQ08_R0F_A_MONO_THRES2, 0x80); - tm6000_set_reg(dev, TM6010_REQ08_R10_A_MUTE_THRES1, 0xc0); - tm6000_set_reg(dev, TM6010_REQ08_R11_A_MUTE_THRES2, 0x80); - tm6000_set_reg(dev, TM6010_REQ08_R12_A_AGC_U, 0x12); - tm6000_set_reg(dev, TM6010_REQ08_R13_A_AGC_ERR_T, 0xfe); - tm6000_set_reg(dev, TM6010_REQ08_R14_A_AGC_GAIN_INIT, 0x20); - tm6000_set_reg(dev, TM6010_REQ08_R15_A_AGC_STEP_THR, 0x14); - tm6000_set_reg(dev, TM6010_REQ08_R16_A_AGC_GAIN_MAX, 0xfe); - tm6000_set_reg(dev, TM6010_REQ08_R17_A_AGC_GAIN_MIN, 0x01); - tm6000_set_reg(dev, TM6010_REQ08_R18_A_TR_CTRL, 0xa0); - tm6000_set_reg(dev, TM6010_REQ08_R19_A_FH_2FH_GAIN, 0x32); - tm6000_set_reg(dev, TM6010_REQ08_R1A_A_NICAM_SER_MAX, 0x64); - tm6000_set_reg(dev, TM6010_REQ08_R1B_A_NICAM_SER_MIN, 0x20); - tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1c, 0x00); - tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1d, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13); - tm6000_set_reg(dev, TM6010_REQ08_R1F_A_TEST_INTF_SEL, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R20_A_TEST_PIN_SEL, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80); - - return 0; -} - -void tm6000_get_std_res(struct tm6000_core *dev) -{ - /* Currently, those are the only supported resoltions */ - if (dev->norm & V4L2_STD_525_60) - dev->height = 480; - else - dev->height = 576; - - dev->width = 720; -} - -static int tm6000_load_std(struct tm6000_core *dev, struct tm6000_reg_settings *set) -{ - int i, rc; - - /* Load board's initialization table */ - for (i = 0; set[i].req; i++) { - rc = tm6000_set_reg(dev, set[i].req, set[i].reg, set[i].value); - if (rc < 0) { - printk(KERN_ERR "Error %i while setting " - "req %d, reg %d to value %d\n", - rc, set[i].req, set[i].reg, set[i].value); - return rc; - } - } - - return 0; -} - -int tm6000_set_standard(struct tm6000_core *dev) -{ - struct tm6000_input *input; - int i, rc = 0; - u8 reg_07_fe = 0x8a; - u8 reg_08_f1 = 0xfc; - u8 reg_08_e2 = 0xf0; - u8 reg_08_e6 = 0x0f; - - tm6000_get_std_res(dev); - - if (!dev->radio) - input = &dev->vinput[dev->input]; - else - input = &dev->rinput; - - if (dev->dev_type == TM6010) { - switch (input->vmux) { - case TM6000_VMUX_VIDEO_A: - tm6000_set_reg(dev, TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4); - tm6000_set_reg(dev, TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1); - tm6000_set_reg(dev, TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0); - tm6000_set_reg(dev, TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2); - tm6000_set_reg(dev, TM6010_REQ08_RED_GAIN_SEL, 0xe8); - reg_07_fe |= 0x01; - break; - case TM6000_VMUX_VIDEO_B: - tm6000_set_reg(dev, TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8); - tm6000_set_reg(dev, TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1); - tm6000_set_reg(dev, TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0); - tm6000_set_reg(dev, TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2); - tm6000_set_reg(dev, TM6010_REQ08_RED_GAIN_SEL, 0xe8); - reg_07_fe |= 0x01; - break; - case TM6000_VMUX_VIDEO_AB: - tm6000_set_reg(dev, TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc); - tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8); - reg_08_e6 = 0x00; - tm6000_set_reg(dev, TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2); - tm6000_set_reg(dev, TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0); - tm6000_set_reg(dev, TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2); - tm6000_set_reg(dev, TM6010_REQ08_RED_GAIN_SEL, 0xe0); - break; - default: - break; - } - switch (input->amux) { - case TM6000_AMUX_ADC1: - tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, - 0x00, 0x0f); - break; - case TM6000_AMUX_ADC2: - tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, - 0x08, 0x0f); - break; - case TM6000_AMUX_SIF1: - reg_08_e2 |= 0x02; - reg_08_e6 = 0x08; - reg_07_fe |= 0x40; - reg_08_f1 |= 0x02; - tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3); - tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, - 0x02, 0x0f); - break; - case TM6000_AMUX_SIF2: - reg_08_e2 |= 0x02; - reg_08_e6 = 0x08; - reg_07_fe |= 0x40; - reg_08_f1 |= 0x02; - tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf7); - tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, - 0x02, 0x0f); - break; - default: - break; - } - tm6000_set_reg(dev, TM6010_REQ08_RE2_POWER_DOWN_CTRL1, reg_08_e2); - tm6000_set_reg(dev, TM6010_REQ08_RE6_POWER_DOWN_CTRL2, reg_08_e6); - tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, reg_08_f1); - tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, reg_07_fe); - } else { - switch (input->vmux) { - case TM6000_VMUX_VIDEO_A: - tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10); - tm6000_set_reg(dev, TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00); - tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x0f); - tm6000_set_reg(dev, - REQ_03_SET_GET_MCU_PIN, input->v_gpio, 0); - break; - case TM6000_VMUX_VIDEO_B: - tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x00); - tm6000_set_reg(dev, TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00); - tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x0f); - tm6000_set_reg(dev, - REQ_03_SET_GET_MCU_PIN, input->v_gpio, 0); - break; - case TM6000_VMUX_VIDEO_AB: - tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10); - tm6000_set_reg(dev, TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x10); - tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x00); - tm6000_set_reg(dev, - REQ_03_SET_GET_MCU_PIN, input->v_gpio, 1); - break; - default: - break; - } - switch (input->amux) { - case TM6000_AMUX_ADC1: - tm6000_set_reg_mask(dev, - TM6000_REQ07_REB_VADC_AADC_MODE, 0x00, 0x0f); - break; - case TM6000_AMUX_ADC2: - tm6000_set_reg_mask(dev, - TM6000_REQ07_REB_VADC_AADC_MODE, 0x04, 0x0f); - break; - default: - break; - } - } - if (input->type == TM6000_INPUT_SVIDEO) { - for (i = 0; i < ARRAY_SIZE(svideo_stds); i++) { - if (dev->norm & svideo_stds[i].id) { - rc = tm6000_load_std(dev, svideo_stds[i].common); - goto ret; - } - } - return -EINVAL; - } else { - for (i = 0; i < ARRAY_SIZE(composite_stds); i++) { - if (dev->norm & composite_stds[i].id) { - rc = tm6000_load_std(dev, composite_stds[i].common); - goto ret; - } - } - return -EINVAL; - } - -ret: - if (rc < 0) - return rc; - - if ((dev->dev_type == TM6010) && - ((input->amux == TM6000_AMUX_SIF1) || - (input->amux == TM6000_AMUX_SIF2))) - tm6000_set_audio_std(dev); - - msleep(40); - - return 0; -} diff --git a/drivers/staging/tm6000/tm6000-usb-isoc.h b/drivers/staging/tm6000/tm6000-usb-isoc.h deleted file mode 100644 index 99d15a5..0000000 --- a/drivers/staging/tm6000/tm6000-usb-isoc.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * tm6000-buf.c - driver for TM5600/TM6000/TM6010 USB video capture devices - * - * Copyright (C) 2006-2007 Mauro Carvalho Chehab - * - * 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 version 2 - * - * 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 - -#define TM6000_URB_MSG_LEN 180 - -struct usb_isoc_ctl { - /* max packet size of isoc transaction */ - int max_pkt_size; - - /* number of allocated urbs */ - int num_bufs; - - /* urb for isoc transfers */ - struct urb **urb; - - /* transfer buffers for isoc transfer */ - char **transfer_buffer; - - /* Last buffer command and region */ - u8 cmd; - int pos, size, pktsize; - - /* Last field: ODD or EVEN? */ - int vfield, field; - - /* Stores incomplete commands */ - u32 tmp_buf; - int tmp_buf_len; - - /* Stores already requested buffers */ - struct tm6000_buffer *buf; -}; diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c deleted file mode 100644 index 1e5ace0..0000000 --- a/drivers/staging/tm6000/tm6000-video.c +++ /dev/null @@ -1,1813 +0,0 @@ -/* - * tm6000-video.c - driver for TM5600/TM6000/TM6010 USB video capture devices - * - * Copyright (C) 2006-2007 Mauro Carvalho Chehab - * - * Copyright (C) 2007 Michel Ludwig - * - Fixed module load/unload - * - * 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 version 2 - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tm6000-regs.h" -#include "tm6000.h" - -#define BUFFER_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ - -/* Limits minimum and default number of buffers */ -#define TM6000_MIN_BUF 4 -#define TM6000_DEF_BUF 8 - -#define TM6000_MAX_ISO_PACKETS 46 /* Max number of ISO packets */ - -/* Declare static vars that will be used as parameters */ -static unsigned int vid_limit = 16; /* Video memory limit, in Mb */ -static int video_nr = -1; /* /dev/videoN, -1 for autodetect */ -static int radio_nr = -1; /* /dev/radioN, -1 for autodetect */ - -/* Debug level */ -int tm6000_debug; -EXPORT_SYMBOL_GPL(tm6000_debug); - -static const struct v4l2_queryctrl no_ctrl = { - .name = "42", - .flags = V4L2_CTRL_FLAG_DISABLED, -}; - -/* supported controls */ -static struct v4l2_queryctrl tm6000_qctrl[] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 54, - .flags = 0, - }, { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 255, - .step = 0x1, - .default_value = 119, - .flags = 0, - }, { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 255, - .step = 0x1, - .default_value = 112, - .flags = 0, - }, { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Hue", - .minimum = -128, - .maximum = 127, - .step = 0x1, - .default_value = 0, - .flags = 0, - }, - /* --- audio --- */ - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, { - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = -15, - .maximum = 15, - .step = 1, - .default_value = 0, - .type = V4L2_CTRL_TYPE_INTEGER, - } -}; - -static const unsigned int CTRLS = ARRAY_SIZE(tm6000_qctrl); -static int qctl_regs[ARRAY_SIZE(tm6000_qctrl)]; - -static struct tm6000_fmt format[] = { - { - .name = "4:2:2, packed, YVY2", - .fourcc = V4L2_PIX_FMT_YUYV, - .depth = 16, - }, { - .name = "4:2:2, packed, UYVY", - .fourcc = V4L2_PIX_FMT_UYVY, - .depth = 16, - }, { - .name = "A/V + VBI mux packet", - .fourcc = V4L2_PIX_FMT_TM6000, - .depth = 16, - } -}; - -static const struct v4l2_queryctrl *ctrl_by_id(unsigned int id) -{ - unsigned int i; - - for (i = 0; i < CTRLS; i++) - if (tm6000_qctrl[i].id == id) - return tm6000_qctrl+i; - return NULL; -} - -/* ------------------------------------------------------------------ - * DMA and thread functions - * ------------------------------------------------------------------ - */ - -#define norm_maxw(a) 720 -#define norm_maxh(a) 576 - -#define norm_minw(a) norm_maxw(a) -#define norm_minh(a) norm_maxh(a) - -/* - * video-buf generic routine to get the next available buffer - */ -static inline void get_next_buf(struct tm6000_dmaqueue *dma_q, - struct tm6000_buffer **buf) -{ - struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq); - char *outp; - - if (list_empty(&dma_q->active)) { - dprintk(dev, V4L2_DEBUG_QUEUE, "No active queue to serve\n"); - *buf = NULL; - return; - } - - *buf = list_entry(dma_q->active.next, - struct tm6000_buffer, vb.queue); - - /* Cleans up buffer - Useful for testing for frame/URB loss */ - outp = videobuf_to_vmalloc(&(*buf)->vb); - - return; -} - -/* - * Announces that a buffer were filled and request the next - */ -static inline void buffer_filled(struct tm6000_core *dev, - struct tm6000_dmaqueue *dma_q, - struct tm6000_buffer *buf) -{ - /* Advice that buffer was filled */ - dprintk(dev, V4L2_DEBUG_ISOC, "[%p/%d] wakeup\n", buf, buf->vb.i); - buf->vb.state = VIDEOBUF_DONE; - buf->vb.field_count++; - do_gettimeofday(&buf->vb.ts); - - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); -} - -/* - * Identify the tm5600/6000 buffer header type and properly handles - */ -static int copy_streams(u8 *data, unsigned long len, - struct urb *urb) -{ - struct tm6000_dmaqueue *dma_q = urb->context; - struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq); - u8 *ptr = data, *endp = data+len, c; - unsigned long header = 0; - int rc = 0; - unsigned int cmd, cpysize, pktsize, size, field, block, line, pos = 0; - struct tm6000_buffer *vbuf = NULL; - char *voutp = NULL; - unsigned int linewidth; - - if (!dev->radio) { - /* get video buffer */ - get_next_buf(dma_q, &vbuf); - - if (!vbuf) - return rc; - voutp = videobuf_to_vmalloc(&vbuf->vb); - - if (!voutp) - return 0; - } - - for (ptr = data; ptr < endp;) { - if (!dev->isoc_ctl.cmd) { - /* Header */ - if (dev->isoc_ctl.tmp_buf_len > 0) { - /* from last urb or packet */ - header = dev->isoc_ctl.tmp_buf; - if (4 - dev->isoc_ctl.tmp_buf_len > 0) { - memcpy((u8 *)&header + - dev->isoc_ctl.tmp_buf_len, - ptr, - 4 - dev->isoc_ctl.tmp_buf_len); - ptr += 4 - dev->isoc_ctl.tmp_buf_len; - } - dev->isoc_ctl.tmp_buf_len = 0; - } else { - if (ptr + 3 >= endp) { - /* have incomplete header */ - dev->isoc_ctl.tmp_buf_len = endp - ptr; - memcpy(&dev->isoc_ctl.tmp_buf, ptr, - dev->isoc_ctl.tmp_buf_len); - return rc; - } - /* Seek for sync */ - for (; ptr < endp - 3; ptr++) { - if (*(ptr + 3) == 0x47) - break; - } - /* Get message header */ - header = *(unsigned long *)ptr; - ptr += 4; - } - - /* split the header fields */ - c = (header >> 24) & 0xff; - size = ((header & 0x7e) << 1); - if (size > 0) - size -= 4; - block = (header >> 7) & 0xf; - field = (header >> 11) & 0x1; - line = (header >> 12) & 0x1ff; - cmd = (header >> 21) & 0x7; - /* Validates haeder fields */ - if (size > TM6000_URB_MSG_LEN) - size = TM6000_URB_MSG_LEN; - pktsize = TM6000_URB_MSG_LEN; - /* - * calculate position in buffer and change the buffer - */ - switch (cmd) { - case TM6000_URB_MSG_VIDEO: - if (!dev->radio) { - if ((dev->isoc_ctl.vfield != field) && - (field == 1)) { - /* - * Announces that a new buffer - * were filled - */ - buffer_filled(dev, dma_q, vbuf); - dprintk(dev, V4L2_DEBUG_ISOC, - "new buffer filled\n"); - get_next_buf(dma_q, &vbuf); - if (!vbuf) - return rc; - voutp = videobuf_to_vmalloc(&vbuf->vb); - if (!voutp) - return rc; - memset(voutp, 0, vbuf->vb.size); - } - linewidth = vbuf->vb.width << 1; - pos = ((line << 1) - field - 1) * - linewidth + block * TM6000_URB_MSG_LEN; - /* Don't allow to write out of the buffer */ - if (pos + size > vbuf->vb.size) - cmd = TM6000_URB_MSG_ERR; - dev->isoc_ctl.vfield = field; - } - break; - case TM6000_URB_MSG_VBI: - break; - case TM6000_URB_MSG_AUDIO: - case TM6000_URB_MSG_PTS: - size = pktsize; /* Size is always 180 bytes */ - break; - } - } else { - /* Continue the last copy */ - cmd = dev->isoc_ctl.cmd; - size = dev->isoc_ctl.size; - pos = dev->isoc_ctl.pos; - pktsize = dev->isoc_ctl.pktsize; - field = dev->isoc_ctl.field; - } - cpysize = (endp - ptr > size) ? size : endp - ptr; - if (cpysize) { - /* copy data in different buffers */ - switch (cmd) { - case TM6000_URB_MSG_VIDEO: - /* Fills video buffer */ - if (vbuf) - memcpy(&voutp[pos], ptr, cpysize); - break; - case TM6000_URB_MSG_AUDIO: { - int i; - for (i = 0; i < cpysize; i += 2) - swab16s((u16 *)(ptr + i)); - - tm6000_call_fillbuf(dev, TM6000_AUDIO, ptr, cpysize); - break; - } - case TM6000_URB_MSG_VBI: - /* Need some code to copy vbi buffer */ - break; - case TM6000_URB_MSG_PTS: { - /* Need some code to copy pts */ - u32 pts; - pts = *(u32 *)ptr; - dprintk(dev, V4L2_DEBUG_ISOC, "field %d, PTS %x", - field, pts); - break; - } - } - } - if (ptr + pktsize > endp) { - /* - * End of URB packet, but cmd processing is not - * complete. Preserve the state for a next packet - */ - dev->isoc_ctl.pos = pos + cpysize; - dev->isoc_ctl.size = size - cpysize; - dev->isoc_ctl.cmd = cmd; - dev->isoc_ctl.field = field; - dev->isoc_ctl.pktsize = pktsize - (endp - ptr); - ptr += endp - ptr; - } else { - dev->isoc_ctl.cmd = 0; - ptr += pktsize; - } - } - return 0; -} - -/* - * Identify the tm5600/6000 buffer header type and properly handles - */ -static int copy_multiplexed(u8 *ptr, unsigned long len, - struct urb *urb) -{ - struct tm6000_dmaqueue *dma_q = urb->context; - struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq); - unsigned int pos = dev->isoc_ctl.pos, cpysize; - int rc = 1; - struct tm6000_buffer *buf; - char *outp = NULL; - - get_next_buf(dma_q, &buf); - if (buf) - outp = videobuf_to_vmalloc(&buf->vb); - - if (!outp) - return 0; - - while (len > 0) { - cpysize = min(len, buf->vb.size-pos); - memcpy(&outp[pos], ptr, cpysize); - pos += cpysize; - ptr += cpysize; - len -= cpysize; - if (pos >= buf->vb.size) { - pos = 0; - /* Announces that a new buffer were filled */ - buffer_filled(dev, dma_q, buf); - dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n"); - get_next_buf(dma_q, &buf); - if (!buf) - break; - outp = videobuf_to_vmalloc(&(buf->vb)); - if (!outp) - return rc; - pos = 0; - } - } - - dev->isoc_ctl.pos = pos; - return rc; -} - -static inline void print_err_status(struct tm6000_core *dev, - int packet, int status) -{ - char *errmsg = "Unknown"; - - switch (status) { - case -ENOENT: - errmsg = "unlinked synchronuously"; - break; - case -ECONNRESET: - errmsg = "unlinked asynchronuously"; - break; - case -ENOSR: - errmsg = "Buffer error (overrun)"; - break; - case -EPIPE: - errmsg = "Stalled (device not responding)"; - break; - case -EOVERFLOW: - errmsg = "Babble (bad cable?)"; - break; - case -EPROTO: - errmsg = "Bit-stuff error (bad cable?)"; - break; - case -EILSEQ: - errmsg = "CRC/Timeout (could be anything)"; - break; - case -ETIME: - errmsg = "Device does not respond"; - break; - } - if (packet < 0) { - dprintk(dev, V4L2_DEBUG_QUEUE, "URB status %d [%s].\n", - status, errmsg); - } else { - dprintk(dev, V4L2_DEBUG_QUEUE, "URB packet %d, status %d [%s].\n", - packet, status, errmsg); - } -} - - -/* - * Controls the isoc copy of each urb packet - */ -static inline int tm6000_isoc_copy(struct urb *urb) -{ - struct tm6000_dmaqueue *dma_q = urb->context; - struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq); - int i, len = 0, rc = 1, status; - char *p; - - if (urb->status < 0) { - print_err_status(dev, -1, urb->status); - return 0; - } - - for (i = 0; i < urb->number_of_packets; i++) { - status = urb->iso_frame_desc[i].status; - - if (status < 0) { - print_err_status(dev, i, status); - continue; - } - - len = urb->iso_frame_desc[i].actual_length; - - if (len > 0) { - p = urb->transfer_buffer + urb->iso_frame_desc[i].offset; - if (!urb->iso_frame_desc[i].status) { - if ((dev->fourcc) == V4L2_PIX_FMT_TM6000) { - rc = copy_multiplexed(p, len, urb); - if (rc <= 0) - return rc; - } else { - copy_streams(p, len, urb); - } - } - } - } - return rc; -} - -/* ------------------------------------------------------------------ - * URB control - * ------------------------------------------------------------------ - */ - -/* - * IRQ callback, called by URB callback - */ -static void tm6000_irq_callback(struct urb *urb) -{ - struct tm6000_dmaqueue *dma_q = urb->context; - struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq); - int i; - - switch (urb->status) { - case 0: - case -ETIMEDOUT: - break; - - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - return; - - default: - tm6000_err("urb completion error %d.\n", urb->status); - break; - } - - spin_lock(&dev->slock); - tm6000_isoc_copy(urb); - spin_unlock(&dev->slock); - - /* Reset urb buffers */ - for (i = 0; i < urb->number_of_packets; i++) { - urb->iso_frame_desc[i].status = 0; - urb->iso_frame_desc[i].actual_length = 0; - } - - urb->status = usb_submit_urb(urb, GFP_ATOMIC); - if (urb->status) - tm6000_err("urb resubmit failed (error=%i)\n", - urb->status); -} - -/* - * Stop and Deallocate URBs - */ -static void tm6000_uninit_isoc(struct tm6000_core *dev) -{ - struct urb *urb; - int i; - - dev->isoc_ctl.buf = NULL; - for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { - urb = dev->isoc_ctl.urb[i]; - if (urb) { - usb_kill_urb(urb); - usb_unlink_urb(urb); - if (dev->isoc_ctl.transfer_buffer[i]) { - usb_free_coherent(dev->udev, - urb->transfer_buffer_length, - dev->isoc_ctl.transfer_buffer[i], - urb->transfer_dma); - } - usb_free_urb(urb); - dev->isoc_ctl.urb[i] = NULL; - } - dev->isoc_ctl.transfer_buffer[i] = NULL; - } - - kfree(dev->isoc_ctl.urb); - kfree(dev->isoc_ctl.transfer_buffer); - - dev->isoc_ctl.urb = NULL; - dev->isoc_ctl.transfer_buffer = NULL; - dev->isoc_ctl.num_bufs = 0; -} - -/* - * Allocate URBs and start IRQ - */ -static int tm6000_prepare_isoc(struct tm6000_core *dev) -{ - struct tm6000_dmaqueue *dma_q = &dev->vidq; - int i, j, sb_size, pipe, size, max_packets, num_bufs = 8; - struct urb *urb; - - /* De-allocates all pending stuff */ - tm6000_uninit_isoc(dev); - /* Stop interrupt USB pipe */ - tm6000_ir_int_stop(dev); - - usb_set_interface(dev->udev, - dev->isoc_in.bInterfaceNumber, - dev->isoc_in.bAlternateSetting); - - /* Start interrupt USB pipe */ - tm6000_ir_int_start(dev); - - pipe = usb_rcvisocpipe(dev->udev, - dev->isoc_in.endp->desc.bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK); - - size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe)); - - if (size > dev->isoc_in.maxsize) - size = dev->isoc_in.maxsize; - - dev->isoc_ctl.max_pkt_size = size; - - max_packets = TM6000_MAX_ISO_PACKETS; - sb_size = max_packets * size; - - dev->isoc_ctl.num_bufs = num_bufs; - - dev->isoc_ctl.urb = kmalloc(sizeof(void *)*num_bufs, GFP_KERNEL); - if (!dev->isoc_ctl.urb) { - tm6000_err("cannot alloc memory for usb buffers\n"); - return -ENOMEM; - } - - dev->isoc_ctl.transfer_buffer = kmalloc(sizeof(void *)*num_bufs, - GFP_KERNEL); - if (!dev->isoc_ctl.transfer_buffer) { - tm6000_err("cannot allocate memory for usbtransfer\n"); - kfree(dev->isoc_ctl.urb); - return -ENOMEM; - } - - dprintk(dev, V4L2_DEBUG_QUEUE, "Allocating %d x %d packets" - " (%d bytes) of %d bytes each to handle %u size\n", - max_packets, num_bufs, sb_size, - dev->isoc_in.maxsize, size); - - /* allocate urbs and transfer buffers */ - for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { - urb = usb_alloc_urb(max_packets, GFP_KERNEL); - if (!urb) { - tm6000_err("cannot alloc isoc_ctl.urb %i\n", i); - tm6000_uninit_isoc(dev); - usb_free_urb(urb); - return -ENOMEM; - } - dev->isoc_ctl.urb[i] = urb; - - dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev, - sb_size, GFP_KERNEL, &urb->transfer_dma); - if (!dev->isoc_ctl.transfer_buffer[i]) { - tm6000_err("unable to allocate %i bytes for transfer" - " buffer %i%s\n", - sb_size, i, - in_interrupt() ? " while in int" : ""); - tm6000_uninit_isoc(dev); - return -ENOMEM; - } - memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size); - - usb_fill_bulk_urb(urb, dev->udev, pipe, - dev->isoc_ctl.transfer_buffer[i], sb_size, - tm6000_irq_callback, dma_q); - urb->interval = dev->isoc_in.endp->desc.bInterval; - urb->number_of_packets = max_packets; - urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - - for (j = 0; j < max_packets; j++) { - urb->iso_frame_desc[j].offset = size * j; - urb->iso_frame_desc[j].length = size; - } - } - - return 0; -} - -static int tm6000_start_thread(struct tm6000_core *dev) -{ - struct tm6000_dmaqueue *dma_q = &dev->vidq; - int i; - - dma_q->frame = 0; - dma_q->ini_jiffies = jiffies; - - init_waitqueue_head(&dma_q->wq); - - /* submit urbs and enables IRQ */ - for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { - int rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC); - if (rc) { - tm6000_err("submit of urb %i failed (error=%i)\n", i, - rc); - tm6000_uninit_isoc(dev); - return rc; - } - } - - return 0; -} - -/* ------------------------------------------------------------------ - * Videobuf operations - * ------------------------------------------------------------------ - */ - -static int -buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) -{ - struct tm6000_fh *fh = vq->priv_data; - - *size = fh->fmt->depth * fh->width * fh->height >> 3; - if (0 == *count) - *count = TM6000_DEF_BUF; - - if (*count < TM6000_MIN_BUF) - *count = TM6000_MIN_BUF; - - while (*size * *count > vid_limit * 1024 * 1024) - (*count)--; - - return 0; -} - -static void free_buffer(struct videobuf_queue *vq, struct tm6000_buffer *buf) -{ - struct tm6000_fh *fh = vq->priv_data; - struct tm6000_core *dev = fh->dev; - unsigned long flags; - - if (in_interrupt()) - BUG(); - - /* We used to wait for the buffer to finish here, but this didn't work - because, as we were keeping the state as VIDEOBUF_QUEUED, - videobuf_queue_cancel marked it as finished for us. - (Also, it could wedge forever if the hardware was misconfigured.) - - This should be safe; by the time we get here, the buffer isn't - queued anymore. If we ever start marking the buffers as - VIDEOBUF_ACTIVE, it won't be, though. - */ - spin_lock_irqsave(&dev->slock, flags); - if (dev->isoc_ctl.buf == buf) - dev->isoc_ctl.buf = NULL; - spin_unlock_irqrestore(&dev->slock, flags); - - videobuf_vmalloc_free(&buf->vb); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -static int -buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct tm6000_fh *fh = vq->priv_data; - struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb); - struct tm6000_core *dev = fh->dev; - int rc = 0; - - BUG_ON(NULL == fh->fmt); - - - /* FIXME: It assumes depth=2 */ - /* The only currently supported format is 16 bits/pixel */ - buf->vb.size = fh->fmt->depth*fh->width*fh->height >> 3; - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) - return -EINVAL; - - if (buf->fmt != fh->fmt || - buf->vb.width != fh->width || - buf->vb.height != fh->height || - buf->vb.field != field) { - buf->fmt = fh->fmt; - buf->vb.width = fh->width; - buf->vb.height = fh->height; - buf->vb.field = field; - buf->vb.state = VIDEOBUF_NEEDS_INIT; - } - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - rc = videobuf_iolock(vq, &buf->vb, NULL); - if (rc != 0) - goto fail; - } - - if (!dev->isoc_ctl.num_bufs) { - rc = tm6000_prepare_isoc(dev); - if (rc < 0) - goto fail; - - rc = tm6000_start_thread(dev); - if (rc < 0) - goto fail; - - } - - buf->vb.state = VIDEOBUF_PREPARED; - return 0; - -fail: - free_buffer(vq, buf); - return rc; -} - -static void -buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb); - struct tm6000_fh *fh = vq->priv_data; - struct tm6000_core *dev = fh->dev; - struct tm6000_dmaqueue *vidq = &dev->vidq; - - buf->vb.state = VIDEOBUF_QUEUED; - list_add_tail(&buf->vb.queue, &vidq->active); -} - -static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb); - - free_buffer(vq, buf); -} - -static struct videobuf_queue_ops tm6000_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -/* ------------------------------------------------------------------ - * IOCTL handling - * ------------------------------------------------------------------ - */ - -static bool is_res_read(struct tm6000_core *dev, struct tm6000_fh *fh) -{ - /* Is the current fh handling it? if so, that's OK */ - if (dev->resources == fh && dev->is_res_read) - return true; - - return false; -} - -static bool is_res_streaming(struct tm6000_core *dev, struct tm6000_fh *fh) -{ - /* Is the current fh handling it? if so, that's OK */ - if (dev->resources == fh) - return true; - - return false; -} - -static bool res_get(struct tm6000_core *dev, struct tm6000_fh *fh, - bool is_res_read) -{ - /* Is the current fh handling it? if so, that's OK */ - if (dev->resources == fh && dev->is_res_read == is_res_read) - return true; - - /* is it free? */ - if (dev->resources) - return false; - - /* grab it */ - dev->resources = fh; - dev->is_res_read = is_res_read; - dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: get\n"); - return true; -} - -static void res_free(struct tm6000_core *dev, struct tm6000_fh *fh) -{ - /* Is the current fh handling it? if so, that's OK */ - if (dev->resources != fh) - return; - - dev->resources = NULL; - dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: put\n"); -} - -/* ------------------------------------------------------------------ - * IOCTL vidioc handling - * ------------------------------------------------------------------ - */ -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev; - - strlcpy(cap->driver, "tm6000", sizeof(cap->driver)); - strlcpy(cap->card, "Trident TVMaster TM5600/6000/6010", sizeof(cap->card)); - cap->version = TM6000_VERSION; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_STREAMING | - V4L2_CAP_AUDIO | - V4L2_CAP_READWRITE; - - if (dev->tuner_type != TUNER_ABSENT) - cap->capabilities |= V4L2_CAP_TUNER; - - return 0; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (unlikely(f->index >= ARRAY_SIZE(format))) - return -EINVAL; - - strlcpy(f->description, format[f->index].name, sizeof(f->description)); - f->pixelformat = format[f->index].fourcc; - return 0; -} - -static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct tm6000_fh *fh = priv; - - f->fmt.pix.width = fh->width; - f->fmt.pix.height = fh->height; - f->fmt.pix.field = fh->vb_vidq.field; - f->fmt.pix.pixelformat = fh->fmt->fourcc; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fh->fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; - - return 0; -} - -static struct tm6000_fmt *format_by_fourcc(unsigned int fourcc) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(format); i++) - if (format[i].fourcc == fourcc) - return format+i; - return NULL; -} - -static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev; - struct tm6000_fmt *fmt; - enum v4l2_field field; - - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (NULL == fmt) { - dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Fourcc format (0x%08x)" - " invalid.\n", f->fmt.pix.pixelformat); - return -EINVAL; - } - - field = f->fmt.pix.field; - - if (field == V4L2_FIELD_ANY) - field = V4L2_FIELD_SEQ_TB; - else if (V4L2_FIELD_INTERLACED != field) { - dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Field type invalid.\n"); - return -EINVAL; - } - - tm6000_get_std_res(dev); - - f->fmt.pix.width = dev->width; - f->fmt.pix.height = dev->height; - - f->fmt.pix.width &= ~0x01; - - f->fmt.pix.field = field; - - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; - - return 0; -} - -/*FIXME: This seems to be generic enough to be at videodev2 */ -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - int ret = vidioc_try_fmt_vid_cap(file, fh, f); - if (ret < 0) - return ret; - - fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); - fh->width = f->fmt.pix.width; - fh->height = f->fmt.pix.height; - fh->vb_vidq.field = f->fmt.pix.field; - fh->type = f->type; - - dev->fourcc = f->fmt.pix.pixelformat; - - tm6000_set_fourcc_format(dev); - - return 0; -} - -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct tm6000_fh *fh = priv; - - return videobuf_reqbufs(&fh->vb_vidq, p); -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct tm6000_fh *fh = priv; - - return videobuf_querybuf(&fh->vb_vidq, p); -} - -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct tm6000_fh *fh = priv; - - return videobuf_qbuf(&fh->vb_vidq, p); -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct tm6000_fh *fh = priv; - - return videobuf_dqbuf(&fh->vb_vidq, p, - file->f_flags & O_NONBLOCK); -} - -static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - - if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (i != fh->type) - return -EINVAL; - - if (!res_get(dev, fh, false)) - return -EBUSY; - return videobuf_streamon(&fh->vb_vidq); -} - -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - - if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (i != fh->type) - return -EINVAL; - - videobuf_streamoff(&fh->vb_vidq); - res_free(dev, fh); - - return 0; -} - -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) -{ - int rc = 0; - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - - dev->norm = *norm; - rc = tm6000_init_analog_mode(dev); - - fh->width = dev->width; - fh->height = dev->height; - - if (rc < 0) - return rc; - - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm); - - return 0; -} - -static const char *iname[] = { - [TM6000_INPUT_TV] = "Television", - [TM6000_INPUT_COMPOSITE1] = "Composite 1", - [TM6000_INPUT_COMPOSITE2] = "Composite 2", - [TM6000_INPUT_SVIDEO] = "S-Video", -}; - -static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - unsigned int n; - - n = i->index; - if (n >= 3) - return -EINVAL; - - if (!dev->vinput[n].type) - return -EINVAL; - - i->index = n; - - if (dev->vinput[n].type == TM6000_INPUT_TV) - i->type = V4L2_INPUT_TYPE_TUNER; - else - i->type = V4L2_INPUT_TYPE_CAMERA; - - strcpy(i->name, iname[dev->vinput[n].type]); - - i->std = TM6000_STD; - - return 0; -} - -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - - *i = dev->input; - - return 0; -} - -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - int rc = 0; - - if (i >= 3) - return -EINVAL; - if (!dev->vinput[i].type) - return -EINVAL; - - dev->input = i; - - rc = vidioc_s_std(file, priv, &dev->vfd->current_norm); - - return rc; -} - -/* --- controls ---------------------------------------------- */ -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(tm6000_qctrl); i++) - if (qc->id && qc->id == tm6000_qctrl[i].id) { - memcpy(qc, &(tm6000_qctrl[i]), - sizeof(*qc)); - return 0; - } - - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - int val; - - /* FIXME: Probably, those won't work! Maybe we need shadow regs */ - switch (ctrl->id) { - case V4L2_CID_CONTRAST: - val = tm6000_get_reg(dev, TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0); - break; - case V4L2_CID_BRIGHTNESS: - val = tm6000_get_reg(dev, TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0); - return 0; - case V4L2_CID_SATURATION: - val = tm6000_get_reg(dev, TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0); - return 0; - case V4L2_CID_HUE: - val = tm6000_get_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, 0); - return 0; - case V4L2_CID_AUDIO_MUTE: - val = dev->ctl_mute; - return 0; - case V4L2_CID_AUDIO_VOLUME: - val = dev->ctl_volume; - return 0; - default: - return -EINVAL; - } - - if (val < 0) - return val; - - ctrl->value = val; - - return 0; -} -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - u8 val = ctrl->value; - - switch (ctrl->id) { - case V4L2_CID_CONTRAST: - tm6000_set_reg(dev, TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, val); - return 0; - case V4L2_CID_BRIGHTNESS: - tm6000_set_reg(dev, TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, val); - return 0; - case V4L2_CID_SATURATION: - tm6000_set_reg(dev, TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, val); - return 0; - case V4L2_CID_HUE: - tm6000_set_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, val); - return 0; - case V4L2_CID_AUDIO_MUTE: - dev->ctl_mute = val; - tm6000_tvaudio_set_mute(dev, val); - return 0; - case V4L2_CID_AUDIO_VOLUME: - dev->ctl_volume = val; - tm6000_set_volume(dev, val); - return 0; - } - return -EINVAL; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - - if (unlikely(UNSET == dev->tuner_type)) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - - strcpy(t->name, "Television"); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM; - t->rangehigh = 0xffffffffUL; - t->rxsubchans = V4L2_TUNER_SUB_STEREO; - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t); - - t->audmode = dev->amode; - - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - - if (UNSET == dev->tuner_type) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - - dev->amode = t->audmode; - dprintk(dev, 3, "audio mode: %x\n", t->audmode); - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t); - - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - - if (unlikely(UNSET == dev->tuner_type)) - return -EINVAL; - - f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - f->frequency = dev->freq; - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, f); - - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - - if (unlikely(UNSET == dev->tuner_type)) - return -EINVAL; - if (unlikely(f->tuner != 0)) - return -EINVAL; - if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type) - return -EINVAL; - if (1 == fh->radio && V4L2_TUNER_RADIO != f->type) - return -EINVAL; - - dev->freq = f->frequency; - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f); - - return 0; -} - -static int radio_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct tm6000_fh *fh = file->private_data; - struct tm6000_core *dev = fh->dev; - - strcpy(cap->driver, "tm6000"); - strlcpy(cap->card, dev->name, sizeof(dev->name)); - sprintf(cap->bus_info, "USB%04x:%04x", - le16_to_cpu(dev->udev->descriptor.idVendor), - le16_to_cpu(dev->udev->descriptor.idProduct)); - cap->version = dev->dev_type; - cap->capabilities = V4L2_CAP_TUNER | - V4L2_CAP_AUDIO | - V4L2_CAP_RADIO | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - - return 0; -} - -static int radio_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct tm6000_fh *fh = file->private_data; - struct tm6000_core *dev = fh->dev; - - if (0 != t->index) - return -EINVAL; - - memset(t, 0, sizeof(*t)); - strcpy(t->name, "Radio"); - t->type = V4L2_TUNER_RADIO; - t->rxsubchans = V4L2_TUNER_SUB_STEREO; - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t); - - return 0; -} - -static int radio_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct tm6000_fh *fh = file->private_data; - struct tm6000_core *dev = fh->dev; - - if (0 != t->index) - return -EINVAL; - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t); - - return 0; -} - -static int radio_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - - if (i->index != 0) - return -EINVAL; - - if (!dev->rinput.type) - return -EINVAL; - - strcpy(i->name, "Radio"); - i->type = V4L2_INPUT_TYPE_TUNER; - - return 0; -} - -static int radio_g_input(struct file *filp, void *priv, unsigned int *i) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - - if (dev->input != 5) - return -EINVAL; - - *i = dev->input - 5; - - return 0; -} - -static int radio_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - memset(a, 0, sizeof(*a)); - strcpy(a->name, "Radio"); - return 0; -} - -static int radio_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - return 0; -} - -static int radio_s_input(struct file *filp, void *priv, unsigned int i) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - - if (i) - return -EINVAL; - - if (!dev->rinput.type) - return -EINVAL; - - dev->input = i + 5; - - return 0; -} - -static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm) -{ - return 0; -} - -static int radio_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - const struct v4l2_queryctrl *ctrl; - - if (c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) - return -EINVAL; - if (c->id == V4L2_CID_AUDIO_MUTE) { - ctrl = ctrl_by_id(c->id); - *c = *ctrl; - } else - *c = no_ctrl; - - return 0; -} - -/* ------------------------------------------------------------------ - File operations for the device - ------------------------------------------------------------------*/ - -static int tm6000_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct tm6000_core *dev = video_drvdata(file); - struct tm6000_fh *fh; - enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - int i, rc; - int radio = 0; - - dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: open called (dev=%s)\n", - video_device_node_name(vdev)); - - switch (vdev->vfl_type) { - case VFL_TYPE_GRABBER: - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - break; - case VFL_TYPE_VBI: - type = V4L2_BUF_TYPE_VBI_CAPTURE; - break; - case VFL_TYPE_RADIO: - radio = 1; - break; - } - - /* If more than one user, mutex should be added */ - dev->users++; - - dprintk(dev, V4L2_DEBUG_OPEN, "open dev=%s type=%s users=%d\n", - video_device_node_name(vdev), v4l2_type_names[type], - dev->users); - - /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (NULL == fh) { - dev->users--; - return -ENOMEM; - } - - file->private_data = fh; - fh->dev = dev; - fh->radio = radio; - dev->radio = radio; - fh->type = type; - dev->fourcc = format[0].fourcc; - - fh->fmt = format_by_fourcc(dev->fourcc); - - tm6000_get_std_res(dev); - - fh->width = dev->width; - fh->height = dev->height; - - dprintk(dev, V4L2_DEBUG_OPEN, "Open: fh=0x%08lx, dev=0x%08lx, " - "dev->vidq=0x%08lx\n", - (unsigned long)fh, (unsigned long)dev, - (unsigned long)&dev->vidq); - dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty " - "queued=%d\n", list_empty(&dev->vidq.queued)); - dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty " - "active=%d\n", list_empty(&dev->vidq.active)); - - /* initialize hardware on analog mode */ - rc = tm6000_init_analog_mode(dev); - if (rc < 0) - return rc; - - if (dev->mode != TM6000_MODE_ANALOG) { - /* Put all controls at a sane state */ - for (i = 0; i < ARRAY_SIZE(tm6000_qctrl); i++) - qctl_regs[i] = tm6000_qctrl[i].default_value; - - dev->mode = TM6000_MODE_ANALOG; - } - - if (!fh->radio) { - videobuf_queue_vmalloc_init(&fh->vb_vidq, &tm6000_video_qops, - NULL, &dev->slock, - fh->type, - V4L2_FIELD_INTERLACED, - sizeof(struct tm6000_buffer), fh, &dev->lock); - } else { - dprintk(dev, V4L2_DEBUG_OPEN, "video_open: setting radio device\n"); - dev->input = 5; - tm6000_set_audio_rinput(dev); - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio); - tm6000_prepare_isoc(dev); - tm6000_start_thread(dev); - } - - return 0; -} - -static ssize_t -tm6000_read(struct file *file, char __user *data, size_t count, loff_t *pos) -{ - struct tm6000_fh *fh = file->private_data; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - if (!res_get(fh->dev, fh, true)) - return -EBUSY; - - return videobuf_read_stream(&fh->vb_vidq, data, count, pos, 0, - file->f_flags & O_NONBLOCK); - } - return 0; -} - -static unsigned int -tm6000_poll(struct file *file, struct poll_table_struct *wait) -{ - struct tm6000_fh *fh = file->private_data; - struct tm6000_buffer *buf; - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) - return POLLERR; - - if (!!is_res_streaming(fh->dev, fh)) - return POLLERR; - - if (!is_res_read(fh->dev, fh)) { - /* streaming capture */ - if (list_empty(&fh->vb_vidq.stream)) - return POLLERR; - buf = list_entry(fh->vb_vidq.stream.next, struct tm6000_buffer, vb.stream); - } else { - /* read() capture */ - return videobuf_poll_stream(file, &fh->vb_vidq, wait); - } - poll_wait(file, &buf->vb.done, wait); - if (buf->vb.state == VIDEOBUF_DONE || - buf->vb.state == VIDEOBUF_ERROR) - return POLLIN | POLLRDNORM; - return 0; -} - -static int tm6000_release(struct file *file) -{ - struct tm6000_fh *fh = file->private_data; - struct tm6000_core *dev = fh->dev; - struct video_device *vdev = video_devdata(file); - - dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: close called (dev=%s, users=%d)\n", - video_device_node_name(vdev), dev->users); - - dev->users--; - - res_free(dev, fh); - - if (!dev->users) { - int err; - - tm6000_uninit_isoc(dev); - - if (!fh->radio) - videobuf_mmap_free(&fh->vb_vidq); - - err = tm6000_reset(dev); - if (err < 0) - dev_err(&vdev->dev, "reset failed: %d\n", err); - } - - kfree(fh); - - return 0; -} - -static int tm6000_mmap(struct file *file, struct vm_area_struct * vma) -{ - struct tm6000_fh *fh = file->private_data; - - return videobuf_mmap_mapper(&fh->vb_vidq, vma); -} - -static struct v4l2_file_operations tm6000_fops = { - .owner = THIS_MODULE, - .open = tm6000_open, - .release = tm6000_release, - .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ - .read = tm6000_read, - .poll = tm6000_poll, - .mmap = tm6000_mmap, -}; - -static const struct v4l2_ioctl_ops video_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_s_std = vidioc_s_std, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, -}; - -static struct video_device tm6000_template = { - .name = "tm6000", - .fops = &tm6000_fops, - .ioctl_ops = &video_ioctl_ops, - .release = video_device_release, - .tvnorms = TM6000_STD, - .current_norm = V4L2_STD_NTSC_M, -}; - -static const struct v4l2_file_operations radio_fops = { - .owner = THIS_MODULE, - .open = tm6000_open, - .release = tm6000_release, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops radio_ioctl_ops = { - .vidioc_querycap = radio_querycap, - .vidioc_g_tuner = radio_g_tuner, - .vidioc_enum_input = radio_enum_input, - .vidioc_g_audio = radio_g_audio, - .vidioc_s_tuner = radio_s_tuner, - .vidioc_s_audio = radio_s_audio, - .vidioc_s_input = radio_s_input, - .vidioc_s_std = radio_s_std, - .vidioc_queryctrl = radio_queryctrl, - .vidioc_g_input = radio_g_input, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, -}; - -static struct video_device tm6000_radio_template = { - .name = "tm6000", - .fops = &radio_fops, - .ioctl_ops = &radio_ioctl_ops, -}; - -/* ----------------------------------------------------------------- - * Initialization and module stuff - * ------------------------------------------------------------------ - */ - -static struct video_device *vdev_init(struct tm6000_core *dev, - const struct video_device - *template, const char *type_name) -{ - struct video_device *vfd; - - vfd = video_device_alloc(); - if (NULL == vfd) - return NULL; - - *vfd = *template; - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->release = video_device_release; - vfd->debug = tm6000_debug; - vfd->lock = &dev->lock; - - snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name); - - video_set_drvdata(vfd, dev); - return vfd; -} - -int tm6000_v4l2_register(struct tm6000_core *dev) -{ - int ret = -1; - - dev->vfd = vdev_init(dev, &tm6000_template, "video"); - - if (!dev->vfd) { - printk(KERN_INFO "%s: can't register video device\n", - dev->name); - return -ENOMEM; - } - - /* init video dma queues */ - INIT_LIST_HEAD(&dev->vidq.active); - INIT_LIST_HEAD(&dev->vidq.queued); - - ret = video_register_device(dev->vfd, VFL_TYPE_GRABBER, video_nr); - - if (ret < 0) { - printk(KERN_INFO "%s: can't register video device\n", - dev->name); - return ret; - } - - printk(KERN_INFO "%s: registered device %s\n", - dev->name, video_device_node_name(dev->vfd)); - - if (dev->caps.has_radio) { - dev->radio_dev = vdev_init(dev, &tm6000_radio_template, - "radio"); - if (!dev->radio_dev) { - printk(KERN_INFO "%s: can't register radio device\n", - dev->name); - return ret; /* FIXME release resource */ - } - - ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, - radio_nr); - if (ret < 0) { - printk(KERN_INFO "%s: can't register radio device\n", - dev->name); - return ret; /* FIXME release resource */ - } - - printk(KERN_INFO "%s: registered device %s\n", - dev->name, video_device_node_name(dev->radio_dev)); - } - - printk(KERN_INFO "Trident TVMaster TM5600/TM6000/TM6010 USB2 board (Load status: %d)\n", ret); - return ret; -} - -int tm6000_v4l2_unregister(struct tm6000_core *dev) -{ - video_unregister_device(dev->vfd); - - if (dev->radio_dev) { - if (video_is_registered(dev->radio_dev)) - video_unregister_device(dev->radio_dev); - else - video_device_release(dev->radio_dev); - dev->radio_dev = NULL; - } - - return 0; -} - -int tm6000_v4l2_exit(void) -{ - return 0; -} - -module_param(video_nr, int, 0); -MODULE_PARM_DESC(video_nr, "Allow changing video device number"); - -module_param_named(debug, tm6000_debug, int, 0444); -MODULE_PARM_DESC(debug, "activates debug info"); - -module_param(vid_limit, int, 0644); -MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); - diff --git a/drivers/staging/tm6000/tm6000.h b/drivers/staging/tm6000/tm6000.h deleted file mode 100644 index 2777e51..0000000 --- a/drivers/staging/tm6000/tm6000.h +++ /dev/null @@ -1,398 +0,0 @@ -/* - * tm6000.h - driver for TM5600/TM6000/TM6010 USB video capture devices - * - * Copyright (C) 2006-2007 Mauro Carvalho Chehab - * - * Copyright (C) 2007 Michel Ludwig - * - DVB-T support - * - * 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 version 2 - * - * 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 -#include -#include -#include "tm6000-usb-isoc.h" -#include -#include -#include - -#include -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dmxdev.h" - -#define TM6000_VERSION KERNEL_VERSION(0, 0, 2) - -/* Inputs */ -enum tm6000_itype { - TM6000_INPUT_TV = 1, - TM6000_INPUT_COMPOSITE1, - TM6000_INPUT_COMPOSITE2, - TM6000_INPUT_SVIDEO, - TM6000_INPUT_DVB, - TM6000_INPUT_RADIO, -}; - -enum tm6000_mux { - TM6000_VMUX_VIDEO_A = 1, - TM6000_VMUX_VIDEO_B, - TM6000_VMUX_VIDEO_AB, - TM6000_AMUX_ADC1, - TM6000_AMUX_ADC2, - TM6000_AMUX_SIF1, - TM6000_AMUX_SIF2, - TM6000_AMUX_I2S, -}; - -enum tm6000_devtype { - TM6000 = 0, - TM5600, - TM6010, -}; - -struct tm6000_input { - enum tm6000_itype type; - enum tm6000_mux vmux; - enum tm6000_mux amux; - unsigned int v_gpio; - unsigned int a_gpio; -}; - -/* ------------------------------------------------------------------ - * Basic structures - * ------------------------------------------------------------------ - */ - -struct tm6000_fmt { - char *name; - u32 fourcc; /* v4l2 format id */ - int depth; -}; - -/* buffer for one video frame */ -struct tm6000_buffer { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - - struct tm6000_fmt *fmt; -}; - -struct tm6000_dmaqueue { - struct list_head active; - struct list_head queued; - - /* thread for generating video stream*/ - struct task_struct *kthread; - wait_queue_head_t wq; - /* Counters to control fps rate */ - int frame; - int ini_jiffies; -}; - -/* device states */ -enum tm6000_core_state { - DEV_INITIALIZED = 0x01, - DEV_DISCONNECTED = 0x02, - DEV_MISCONFIGURED = 0x04, -}; - -/* io methods */ -enum tm6000_io_method { - IO_NONE, - IO_READ, - IO_MMAP, -}; - -enum tm6000_mode { - TM6000_MODE_UNKNOWN = 0, - TM6000_MODE_ANALOG, - TM6000_MODE_DIGITAL, -}; - -struct tm6000_gpio { - int tuner_reset; - int tuner_on; - int demod_reset; - int demod_on; - int power_led; - int dvb_led; - int ir; -}; - -struct tm6000_capabilities { - unsigned int has_tuner:1; - unsigned int has_tda9874:1; - unsigned int has_dvb:1; - unsigned int has_zl10353:1; - unsigned int has_eeprom:1; - unsigned int has_remote:1; - unsigned int has_radio:1; -}; - -struct tm6000_dvb { - struct dvb_adapter adapter; - struct dvb_demux demux; - struct dvb_frontend *frontend; - struct dmxdev dmxdev; - unsigned int streams; - struct urb *bulk_urb; - struct mutex mutex; -}; - -struct snd_tm6000_card { - struct snd_card *card; - spinlock_t reg_lock; - struct tm6000_core *core; - struct snd_pcm_substream *substream; - - /* temporary data for buffer fill processing */ - unsigned buf_pos; - unsigned period_pos; -}; - -struct tm6000_endpoint { - struct usb_host_endpoint *endp; - __u8 bInterfaceNumber; - __u8 bAlternateSetting; - unsigned maxsize; -}; - -#define TM6000_QUIRK_NO_USB_DELAY (1 << 0) - -struct tm6000_core { - /* generic device properties */ - char name[30]; /* name (including minor) of the device */ - int model; /* index in the device_data struct */ - int devno; /* marks the number of this device */ - enum tm6000_devtype dev_type; /* type of device */ - unsigned char eedata[256]; /* Eeprom data */ - unsigned eedata_size; /* Size of the eeprom info */ - - v4l2_std_id norm; /* Current norm */ - int width, height; /* Selected resolution */ - - enum tm6000_core_state state; - - /* Device Capabilities*/ - struct tm6000_capabilities caps; - - /* Tuner configuration */ - int tuner_type; /* type of the tuner */ - int tuner_addr; /* tuner address */ - - struct tm6000_gpio gpio; - - char *ir_codes; - - __u8 radio; - - /* Demodulator configuration */ - int demod_addr; /* demodulator address */ - - int audio_bitrate; - /* i2c i/o */ - struct i2c_adapter i2c_adap; - struct i2c_client i2c_client; - - - /* extension */ - struct list_head devlist; - - /* video for linux */ - int users; - - /* various device info */ - struct tm6000_fh *resources; /* Points to fh that is streaming */ - bool is_res_read; - - struct video_device *vfd; - struct video_device *radio_dev; - struct tm6000_dmaqueue vidq; - struct v4l2_device v4l2_dev; - - int input; - struct tm6000_input vinput[3]; /* video input */ - struct tm6000_input rinput; /* radio input */ - - int freq; - unsigned int fourcc; - - enum tm6000_mode mode; - - int ctl_mute; /* audio */ - int ctl_volume; - int amode; - - /* DVB-T support */ - struct tm6000_dvb *dvb; - - /* audio support */ - struct snd_tm6000_card *adev; - struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */ - atomic_t stream_started; /* stream should be running if true */ - - struct tm6000_IR *ir; - - /* locks */ - struct mutex lock; - struct mutex usb_lock; - - /* usb transfer */ - struct usb_device *udev; /* the usb device */ - - struct tm6000_endpoint bulk_in, bulk_out, isoc_in, isoc_out; - struct tm6000_endpoint int_in, int_out; - - /* scaler!=0 if scaler is active*/ - int scaler; - - /* Isoc control struct */ - struct usb_isoc_ctl isoc_ctl; - - spinlock_t slock; - - unsigned long quirks; -}; - -enum tm6000_ops_type { - TM6000_AUDIO = 0x10, - TM6000_DVB = 0x20, -}; - -struct tm6000_ops { - struct list_head next; - char *name; - enum tm6000_ops_type type; - int (*init)(struct tm6000_core *); - int (*fini)(struct tm6000_core *); - int (*fillbuf)(struct tm6000_core *, char *buf, int size); -}; - -struct tm6000_fh { - struct tm6000_core *dev; - unsigned int radio; - - /* video capture */ - struct tm6000_fmt *fmt; - unsigned int width, height; - struct videobuf_queue vb_vidq; - - enum v4l2_buf_type type; -}; - -#define TM6000_STD (V4L2_STD_PAL|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc| \ - V4L2_STD_PAL_M|V4L2_STD_PAL_60|V4L2_STD_NTSC_M| \ - V4L2_STD_NTSC_M_JP|V4L2_STD_SECAM) - -/* In tm6000-cards.c */ - -int tm6000_tuner_callback(void *ptr, int component, int command, int arg); -int tm6000_xc5000_callback(void *ptr, int component, int command, int arg); -int tm6000_cards_setup(struct tm6000_core *dev); -void tm6000_flash_led(struct tm6000_core *dev, u8 state); - -/* In tm6000-core.c */ - -int tm6000_read_write_usb(struct tm6000_core *dev, u8 reqtype, u8 req, - u16 value, u16 index, u8 *buf, u16 len); -int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index); -int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index); -int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index); -int tm6000_set_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index); -int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value, - u16 index, u16 mask); -int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep); -int tm6000_init(struct tm6000_core *dev); -int tm6000_reset(struct tm6000_core *dev); - -int tm6000_init_analog_mode(struct tm6000_core *dev); -int tm6000_init_digital_mode(struct tm6000_core *dev); -int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate); -int tm6000_set_audio_rinput(struct tm6000_core *dev); -int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute); -void tm6000_set_volume(struct tm6000_core *dev, int vol); - -int tm6000_v4l2_register(struct tm6000_core *dev); -int tm6000_v4l2_unregister(struct tm6000_core *dev); -int tm6000_v4l2_exit(void); -void tm6000_set_fourcc_format(struct tm6000_core *dev); - -void tm6000_remove_from_devlist(struct tm6000_core *dev); -void tm6000_add_into_devlist(struct tm6000_core *dev); -int tm6000_register_extension(struct tm6000_ops *ops); -void tm6000_unregister_extension(struct tm6000_ops *ops); -void tm6000_init_extension(struct tm6000_core *dev); -void tm6000_close_extension(struct tm6000_core *dev); -int tm6000_call_fillbuf(struct tm6000_core *dev, enum tm6000_ops_type type, - char *buf, int size); - - -/* In tm6000-stds.c */ -void tm6000_get_std_res(struct tm6000_core *dev); -int tm6000_set_standard(struct tm6000_core *dev); - -/* In tm6000-i2c.c */ -int tm6000_i2c_register(struct tm6000_core *dev); -int tm6000_i2c_unregister(struct tm6000_core *dev); - -/* In tm6000-queue.c */ - -int tm6000_v4l2_mmap(struct file *filp, struct vm_area_struct *vma); - -int tm6000_vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type i); -int tm6000_vidioc_streamoff(struct file *file, void *priv, - enum v4l2_buf_type i); -int tm6000_vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *rb); -int tm6000_vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *b); -int tm6000_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b); -int tm6000_vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b); -ssize_t tm6000_v4l2_read(struct file *filp, char __user * buf, size_t count, - loff_t *f_pos); -unsigned int tm6000_v4l2_poll(struct file *file, - struct poll_table_struct *wait); -int tm6000_queue_init(struct tm6000_core *dev); - -/* In tm6000-alsa.c */ -/*int tm6000_audio_init(struct tm6000_core *dev, int idx);*/ - -/* In tm6000-input.c */ -int tm6000_ir_init(struct tm6000_core *dev); -int tm6000_ir_fini(struct tm6000_core *dev); -void tm6000_ir_wait(struct tm6000_core *dev, u8 state); -int tm6000_ir_int_start(struct tm6000_core *dev); -void tm6000_ir_int_stop(struct tm6000_core *dev); - -/* Debug stuff */ - -extern int tm6000_debug; - -#define dprintk(dev, level, fmt, arg...) do {\ - if (tm6000_debug & level) \ - printk(KERN_INFO "(%lu) %s %s :"fmt, jiffies, \ - dev->name, __func__ , ##arg); } while (0) - -#define V4L2_DEBUG_REG 0x0004 -#define V4L2_DEBUG_I2C 0x0008 -#define V4L2_DEBUG_QUEUE 0x0010 -#define V4L2_DEBUG_ISOC 0x0020 -#define V4L2_DEBUG_RES_LOCK 0x0040 /* Resource locking */ -#define V4L2_DEBUG_OPEN 0x0080 /* video open/close debug */ - -#define tm6000_err(fmt, arg...) do {\ - printk(KERN_ERR "tm6000 %s :"fmt, \ - __func__ , ##arg); } while (0) -- cgit v0.10.2 From 08347cdd2d745cdcd82e8c4aa2804923df298f33 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Fri, 23 Sep 2011 10:09:36 -0300 Subject: [media] cx23885: fix type error Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index caab1bf..b391e9b 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -38,7 +38,7 @@ config VIDEO_CX23885 config MEDIA_ALTERA_CI tristate "Altera FPGA based CI module" depends on VIDEO_CX23885 && DVB_CORE - select STAPL_ALTERA + select ALTERA_STAPL ---help--- An Altera FPGA CI module for NetUP Dual DVB-T/C RF CI card. -- cgit v0.10.2 From cff4fa8415a3224a5abdd2b1dd7f431e4ea49366 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Fri, 23 Sep 2011 11:17:41 -0300 Subject: [media] altera-stapl: it is time to move out from staging [mchehab@redhat.com: Fix a merge conflict] Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 76b7563..62fd25e 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -25,8 +25,8 @@ #include #include #include +#include -#include "../../../staging/altera-stapl/altera.h" #include "cx23885.h" #include "tuner-xc2028.h" #include "netup-eeprom.h" diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 2d6423c..50d5f27 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -506,5 +506,6 @@ source "drivers/misc/iwmc3200top/Kconfig" source "drivers/misc/ti-st/Kconfig" source "drivers/misc/lis3lv02d/Kconfig" source "drivers/misc/carma/Kconfig" +source "drivers/misc/altera-stapl/Kconfig" endif # MISC_DEVICES diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 8f3efb6..b26495a 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -47,3 +47,4 @@ obj-$(CONFIG_AB8500_PWM) += ab8500-pwm.o obj-y += lis3lv02d/ obj-y += carma/ obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o +obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/ diff --git a/drivers/misc/altera-stapl/Kconfig b/drivers/misc/altera-stapl/Kconfig new file mode 100644 index 0000000..7f01d8e --- /dev/null +++ b/drivers/misc/altera-stapl/Kconfig @@ -0,0 +1,8 @@ +comment "Altera FPGA firmware download module" + +config ALTERA_STAPL + tristate "Altera FPGA firmware download module" + depends on I2C + default n + help + An Altera FPGA module. Say Y when you want to support this tool. diff --git a/drivers/misc/altera-stapl/Makefile b/drivers/misc/altera-stapl/Makefile new file mode 100644 index 0000000..055f61ee --- /dev/null +++ b/drivers/misc/altera-stapl/Makefile @@ -0,0 +1,3 @@ +altera-stapl-objs = altera-lpt.o altera-jtag.o altera-comp.o altera.o + +obj-$(CONFIG_ALTERA_STAPL) += altera-stapl.o diff --git a/drivers/misc/altera-stapl/altera-comp.c b/drivers/misc/altera-stapl/altera-comp.c new file mode 100644 index 0000000..49b103b --- /dev/null +++ b/drivers/misc/altera-stapl/altera-comp.c @@ -0,0 +1,142 @@ +/* + * altera-comp.c + * + * altera FPGA driver + * + * Copyright (C) Altera Corporation 1998-2001 + * Copyright (C) 2010 NetUP Inc. + * Copyright (C) 2010 Igor M. Liplianin + * + * 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 of the License, 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 +#include "altera-exprt.h" + +#define SHORT_BITS 16 +#define CHAR_BITS 8 +#define DATA_BLOB_LENGTH 3 +#define MATCH_DATA_LENGTH 8192 +#define ALTERA_REQUEST_SIZE 1024 +#define ALTERA_BUFFER_SIZE (MATCH_DATA_LENGTH + ALTERA_REQUEST_SIZE) + +static u32 altera_bits_req(u32 n) +{ + u32 result = SHORT_BITS; + + if (n == 0) + result = 1; + else { + /* Look for the highest non-zero bit position */ + while ((n & (1 << (SHORT_BITS - 1))) == 0) { + n <<= 1; + --result; + } + } + + return result; +} + +static u32 altera_read_packed(u8 *buffer, u32 bits, u32 *bits_avail, + u32 *in_index) +{ + u32 result = 0; + u32 shift = 0; + u32 databyte = 0; + + while (bits > 0) { + databyte = buffer[*in_index]; + result |= (((databyte >> (CHAR_BITS - *bits_avail)) + & (0xff >> (CHAR_BITS - *bits_avail))) << shift); + + if (bits <= *bits_avail) { + result &= (0xffff >> (SHORT_BITS - (bits + shift))); + *bits_avail -= bits; + bits = 0; + } else { + ++(*in_index); + shift += *bits_avail; + bits -= *bits_avail; + *bits_avail = CHAR_BITS; + } + } + + return result; +} + +u32 altera_shrink(u8 *in, u32 in_length, u8 *out, u32 out_length, s32 version) +{ + u32 i, j, data_length = 0L; + u32 offset, length; + u32 match_data_length = MATCH_DATA_LENGTH; + u32 bits_avail = CHAR_BITS; + u32 in_index = 0L; + + if (version > 0) + --match_data_length; + + for (i = 0; i < out_length; ++i) + out[i] = 0; + + /* Read number of bytes in data. */ + for (i = 0; i < sizeof(in_length); ++i) { + data_length = data_length | ( + altera_read_packed(in, + CHAR_BITS, + &bits_avail, + &in_index) << (i * CHAR_BITS)); + } + + if (data_length > out_length) { + data_length = 0L; + return data_length; + } + + i = 0; + while (i < data_length) { + /* A 0 bit indicates literal data. */ + if (altera_read_packed(in, 1, &bits_avail, + &in_index) == 0) { + for (j = 0; j < DATA_BLOB_LENGTH; ++j) { + if (i < data_length) { + out[i] = (u8)altera_read_packed(in, + CHAR_BITS, + &bits_avail, + &in_index); + i++; + } + } + } else { + /* A 1 bit indicates offset/length to follow. */ + offset = altera_read_packed(in, altera_bits_req((s16) + (i > match_data_length ? + match_data_length : i)), + &bits_avail, + &in_index); + length = altera_read_packed(in, CHAR_BITS, + &bits_avail, + &in_index); + for (j = 0; j < length; ++j) { + if (i < data_length) { + out[i] = out[i - offset]; + i++; + } + } + } + } + + return data_length; +} diff --git a/drivers/misc/altera-stapl/altera-exprt.h b/drivers/misc/altera-stapl/altera-exprt.h new file mode 100644 index 0000000..39c38d8 --- /dev/null +++ b/drivers/misc/altera-stapl/altera-exprt.h @@ -0,0 +1,33 @@ +/* + * altera-exprt.h + * + * altera FPGA driver + * + * Copyright (C) Altera Corporation 1998-2001 + * Copyright (C) 2010 NetUP Inc. + * Copyright (C) 2010 Igor M. Liplianin + * + * 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 of the License, 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. + */ + +#ifndef ALTERA_EXPRT_H +#define ALTERA_EXPRT_H + + +u32 altera_shrink(u8 *in, u32 in_length, u8 *out, u32 out_length, s32 version); +int netup_jtag_io_lpt(void *device, int tms, int tdi, int read_tdo); + +#endif /* ALTERA_EXPRT_H */ diff --git a/drivers/misc/altera-stapl/altera-jtag.c b/drivers/misc/altera-stapl/altera-jtag.c new file mode 100644 index 0000000..f4bf200 --- /dev/null +++ b/drivers/misc/altera-stapl/altera-jtag.c @@ -0,0 +1,1021 @@ +/* + * altera-jtag.c + * + * altera FPGA driver + * + * Copyright (C) Altera Corporation 1998-2001 + * Copyright (C) 2010 NetUP Inc. + * Copyright (C) 2010 Igor M. Liplianin + * + * 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 of the License, 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 +#include +#include +#include +#include "altera-exprt.h" +#include "altera-jtag.h" + +#define alt_jtag_io(a, b, c)\ + astate->config->jtag_io(astate->config->dev, a, b, c); + +#define alt_malloc(a) kzalloc(a, GFP_KERNEL); + +/* + * This structure shows, for each JTAG state, which state is reached after + * a single TCK clock cycle with TMS high or TMS low, respectively. This + * describes all possible state transitions in the JTAG state machine. + */ +struct altera_jtag_machine { + enum altera_jtag_state tms_high; + enum altera_jtag_state tms_low; +}; + +static const struct altera_jtag_machine altera_transitions[] = { + /* RESET */ { RESET, IDLE }, + /* IDLE */ { DRSELECT, IDLE }, + /* DRSELECT */ { IRSELECT, DRCAPTURE }, + /* DRCAPTURE */ { DREXIT1, DRSHIFT }, + /* DRSHIFT */ { DREXIT1, DRSHIFT }, + /* DREXIT1 */ { DRUPDATE, DRPAUSE }, + /* DRPAUSE */ { DREXIT2, DRPAUSE }, + /* DREXIT2 */ { DRUPDATE, DRSHIFT }, + /* DRUPDATE */ { DRSELECT, IDLE }, + /* IRSELECT */ { RESET, IRCAPTURE }, + /* IRCAPTURE */ { IREXIT1, IRSHIFT }, + /* IRSHIFT */ { IREXIT1, IRSHIFT }, + /* IREXIT1 */ { IRUPDATE, IRPAUSE }, + /* IRPAUSE */ { IREXIT2, IRPAUSE }, + /* IREXIT2 */ { IRUPDATE, IRSHIFT }, + /* IRUPDATE */ { DRSELECT, IDLE } +}; + +/* + * This table contains the TMS value to be used to take the NEXT STEP on + * the path to the desired state. The array index is the current state, + * and the bit position is the desired endstate. To find out which state + * is used as the intermediate state, look up the TMS value in the + * altera_transitions[] table. + */ +static const u16 altera_jtag_path_map[16] = { + /* RST RTI SDRS CDR SDR E1DR PDR E2DR */ + 0x0001, 0xFFFD, 0xFE01, 0xFFE7, 0xFFEF, 0xFF0F, 0xFFBF, 0xFFFF, + /* UDR SIRS CIR SIR E1IR PIR E2IR UIR */ + 0xFEFD, 0x0001, 0xF3FF, 0xF7FF, 0x87FF, 0xDFFF, 0xFFFF, 0x7FFD +}; + +/* Flag bits for alt_jtag_io() function */ +#define TMS_HIGH 1 +#define TMS_LOW 0 +#define TDI_HIGH 1 +#define TDI_LOW 0 +#define READ_TDO 1 +#define IGNORE_TDO 0 + +int altera_jinit(struct altera_state *astate) +{ + struct altera_jtag *js = &astate->js; + + /* initial JTAG state is unknown */ + js->jtag_state = ILLEGAL_JTAG_STATE; + + /* initialize to default state */ + js->drstop_state = IDLE; + js->irstop_state = IDLE; + js->dr_pre = 0; + js->dr_post = 0; + js->ir_pre = 0; + js->ir_post = 0; + js->dr_length = 0; + js->ir_length = 0; + + js->dr_pre_data = NULL; + js->dr_post_data = NULL; + js->ir_pre_data = NULL; + js->ir_post_data = NULL; + js->dr_buffer = NULL; + js->ir_buffer = NULL; + + return 0; +} + +int altera_set_drstop(struct altera_jtag *js, enum altera_jtag_state state) +{ + js->drstop_state = state; + + return 0; +} + +int altera_set_irstop(struct altera_jtag *js, enum altera_jtag_state state) +{ + js->irstop_state = state; + + return 0; +} + +int altera_set_dr_pre(struct altera_jtag *js, + u32 count, u32 start_index, + u8 *preamble_data) +{ + int status = 0; + u32 i; + u32 j; + + if (count > js->dr_pre) { + kfree(js->dr_pre_data); + js->dr_pre_data = (u8 *)alt_malloc((count + 7) >> 3); + if (js->dr_pre_data == NULL) + status = -ENOMEM; + else + js->dr_pre = count; + } else + js->dr_pre = count; + + if (status == 0) { + for (i = 0; i < count; ++i) { + j = i + start_index; + + if (preamble_data == NULL) + js->dr_pre_data[i >> 3] |= (1 << (i & 7)); + else { + if (preamble_data[j >> 3] & (1 << (j & 7))) + js->dr_pre_data[i >> 3] |= + (1 << (i & 7)); + else + js->dr_pre_data[i >> 3] &= + ~(u32)(1 << (i & 7)); + + } + } + } + + return status; +} + +int altera_set_ir_pre(struct altera_jtag *js, u32 count, u32 start_index, + u8 *preamble_data) +{ + int status = 0; + u32 i; + u32 j; + + if (count > js->ir_pre) { + kfree(js->ir_pre_data); + js->ir_pre_data = (u8 *)alt_malloc((count + 7) >> 3); + if (js->ir_pre_data == NULL) + status = -ENOMEM; + else + js->ir_pre = count; + + } else + js->ir_pre = count; + + if (status == 0) { + for (i = 0; i < count; ++i) { + j = i + start_index; + if (preamble_data == NULL) + js->ir_pre_data[i >> 3] |= (1 << (i & 7)); + else { + if (preamble_data[j >> 3] & (1 << (j & 7))) + js->ir_pre_data[i >> 3] |= + (1 << (i & 7)); + else + js->ir_pre_data[i >> 3] &= + ~(u32)(1 << (i & 7)); + + } + } + } + + return status; +} + +int altera_set_dr_post(struct altera_jtag *js, u32 count, u32 start_index, + u8 *postamble_data) +{ + int status = 0; + u32 i; + u32 j; + + if (count > js->dr_post) { + kfree(js->dr_post_data); + js->dr_post_data = (u8 *)alt_malloc((count + 7) >> 3); + + if (js->dr_post_data == NULL) + status = -ENOMEM; + else + js->dr_post = count; + + } else + js->dr_post = count; + + if (status == 0) { + for (i = 0; i < count; ++i) { + j = i + start_index; + + if (postamble_data == NULL) + js->dr_post_data[i >> 3] |= (1 << (i & 7)); + else { + if (postamble_data[j >> 3] & (1 << (j & 7))) + js->dr_post_data[i >> 3] |= + (1 << (i & 7)); + else + js->dr_post_data[i >> 3] &= + ~(u32)(1 << (i & 7)); + + } + } + } + + return status; +} + +int altera_set_ir_post(struct altera_jtag *js, u32 count, u32 start_index, + u8 *postamble_data) +{ + int status = 0; + u32 i; + u32 j; + + if (count > js->ir_post) { + kfree(js->ir_post_data); + js->ir_post_data = (u8 *)alt_malloc((count + 7) >> 3); + if (js->ir_post_data == NULL) + status = -ENOMEM; + else + js->ir_post = count; + + } else + js->ir_post = count; + + if (status != 0) + return status; + + for (i = 0; i < count; ++i) { + j = i + start_index; + + if (postamble_data == NULL) + js->ir_post_data[i >> 3] |= (1 << (i & 7)); + else { + if (postamble_data[j >> 3] & (1 << (j & 7))) + js->ir_post_data[i >> 3] |= (1 << (i & 7)); + else + js->ir_post_data[i >> 3] &= + ~(u32)(1 << (i & 7)); + + } + } + + return status; +} + +static void altera_jreset_idle(struct altera_state *astate) +{ + struct altera_jtag *js = &astate->js; + int i; + /* Go to Test Logic Reset (no matter what the starting state may be) */ + for (i = 0; i < 5; ++i) + alt_jtag_io(TMS_HIGH, TDI_LOW, IGNORE_TDO); + + /* Now step to Run Test / Idle */ + alt_jtag_io(TMS_LOW, TDI_LOW, IGNORE_TDO); + js->jtag_state = IDLE; +} + +int altera_goto_jstate(struct altera_state *astate, + enum altera_jtag_state state) +{ + struct altera_jtag *js = &astate->js; + int tms; + int count = 0; + int status = 0; + + if (js->jtag_state == ILLEGAL_JTAG_STATE) + /* initialize JTAG chain to known state */ + altera_jreset_idle(astate); + + if (js->jtag_state == state) { + /* + * We are already in the desired state. + * If it is a stable state, loop here. + * Otherwise do nothing (no clock cycles). + */ + if ((state == IDLE) || (state == DRSHIFT) || + (state == DRPAUSE) || (state == IRSHIFT) || + (state == IRPAUSE)) { + alt_jtag_io(TMS_LOW, TDI_LOW, IGNORE_TDO); + } else if (state == RESET) + alt_jtag_io(TMS_HIGH, TDI_LOW, IGNORE_TDO); + + } else { + while ((js->jtag_state != state) && (count < 9)) { + /* Get TMS value to take a step toward desired state */ + tms = (altera_jtag_path_map[js->jtag_state] & + (1 << state)) + ? TMS_HIGH : TMS_LOW; + + /* Take a step */ + alt_jtag_io(tms, TDI_LOW, IGNORE_TDO); + + if (tms) + js->jtag_state = + altera_transitions[js->jtag_state].tms_high; + else + js->jtag_state = + altera_transitions[js->jtag_state].tms_low; + + ++count; + } + } + + if (js->jtag_state != state) + status = -EREMOTEIO; + + return status; +} + +int altera_wait_cycles(struct altera_state *astate, + s32 cycles, + enum altera_jtag_state wait_state) +{ + struct altera_jtag *js = &astate->js; + int tms; + s32 count; + int status = 0; + + if (js->jtag_state != wait_state) + status = altera_goto_jstate(astate, wait_state); + + if (status == 0) { + /* + * Set TMS high to loop in RESET state + * Set TMS low to loop in any other stable state + */ + tms = (wait_state == RESET) ? TMS_HIGH : TMS_LOW; + + for (count = 0L; count < cycles; count++) + alt_jtag_io(tms, TDI_LOW, IGNORE_TDO); + + } + + return status; +} + +int altera_wait_msecs(struct altera_state *astate, + s32 microseconds, enum altera_jtag_state wait_state) +/* + * Causes JTAG hardware to sit in the specified stable + * state for the specified duration of real time. If + * no JTAG operations have been performed yet, then only + * a delay is performed. This permits the WAIT USECS + * statement to be used in VECTOR programs without causing + * any JTAG operations. + * Returns 0 for success, else appropriate error code. + */ +{ + struct altera_jtag *js = &astate->js; + int status = 0; + + if ((js->jtag_state != ILLEGAL_JTAG_STATE) && + (js->jtag_state != wait_state)) + status = altera_goto_jstate(astate, wait_state); + + if (status == 0) + /* Wait for specified time interval */ + udelay(microseconds); + + return status; +} + +static void altera_concatenate_data(u8 *buffer, + u8 *preamble_data, + u32 preamble_count, + u8 *target_data, + u32 start_index, + u32 target_count, + u8 *postamble_data, + u32 postamble_count) +/* + * Copies preamble data, target data, and postamble data + * into one buffer for IR or DR scans. + */ +{ + u32 i, j, k; + + for (i = 0L; i < preamble_count; ++i) { + if (preamble_data[i >> 3L] & (1L << (i & 7L))) + buffer[i >> 3L] |= (1L << (i & 7L)); + else + buffer[i >> 3L] &= ~(u32)(1L << (i & 7L)); + + } + + j = start_index; + k = preamble_count + target_count; + for (; i < k; ++i, ++j) { + if (target_data[j >> 3L] & (1L << (j & 7L))) + buffer[i >> 3L] |= (1L << (i & 7L)); + else + buffer[i >> 3L] &= ~(u32)(1L << (i & 7L)); + + } + + j = 0L; + k = preamble_count + target_count + postamble_count; + for (; i < k; ++i, ++j) { + if (postamble_data[j >> 3L] & (1L << (j & 7L))) + buffer[i >> 3L] |= (1L << (i & 7L)); + else + buffer[i >> 3L] &= ~(u32)(1L << (i & 7L)); + + } +} + +static int alt_jtag_drscan(struct altera_state *astate, + int start_state, + int count, + u8 *tdi, + u8 *tdo) +{ + int i = 0; + int tdo_bit = 0; + int status = 1; + + /* First go to DRSHIFT state */ + switch (start_state) { + case 0: /* IDLE */ + alt_jtag_io(1, 0, 0); /* DRSELECT */ + alt_jtag_io(0, 0, 0); /* DRCAPTURE */ + alt_jtag_io(0, 0, 0); /* DRSHIFT */ + break; + + case 1: /* DRPAUSE */ + alt_jtag_io(1, 0, 0); /* DREXIT2 */ + alt_jtag_io(1, 0, 0); /* DRUPDATE */ + alt_jtag_io(1, 0, 0); /* DRSELECT */ + alt_jtag_io(0, 0, 0); /* DRCAPTURE */ + alt_jtag_io(0, 0, 0); /* DRSHIFT */ + break; + + case 2: /* IRPAUSE */ + alt_jtag_io(1, 0, 0); /* IREXIT2 */ + alt_jtag_io(1, 0, 0); /* IRUPDATE */ + alt_jtag_io(1, 0, 0); /* DRSELECT */ + alt_jtag_io(0, 0, 0); /* DRCAPTURE */ + alt_jtag_io(0, 0, 0); /* DRSHIFT */ + break; + + default: + status = 0; + } + + if (status) { + /* loop in the SHIFT-DR state */ + for (i = 0; i < count; i++) { + tdo_bit = alt_jtag_io( + (i == count - 1), + tdi[i >> 3] & (1 << (i & 7)), + (tdo != NULL)); + + if (tdo != NULL) { + if (tdo_bit) + tdo[i >> 3] |= (1 << (i & 7)); + else + tdo[i >> 3] &= ~(u32)(1 << (i & 7)); + + } + } + + alt_jtag_io(0, 0, 0); /* DRPAUSE */ + } + + return status; +} + +static int alt_jtag_irscan(struct altera_state *astate, + int start_state, + int count, + u8 *tdi, + u8 *tdo) +{ + int i = 0; + int tdo_bit = 0; + int status = 1; + + /* First go to IRSHIFT state */ + switch (start_state) { + case 0: /* IDLE */ + alt_jtag_io(1, 0, 0); /* DRSELECT */ + alt_jtag_io(1, 0, 0); /* IRSELECT */ + alt_jtag_io(0, 0, 0); /* IRCAPTURE */ + alt_jtag_io(0, 0, 0); /* IRSHIFT */ + break; + + case 1: /* DRPAUSE */ + alt_jtag_io(1, 0, 0); /* DREXIT2 */ + alt_jtag_io(1, 0, 0); /* DRUPDATE */ + alt_jtag_io(1, 0, 0); /* DRSELECT */ + alt_jtag_io(1, 0, 0); /* IRSELECT */ + alt_jtag_io(0, 0, 0); /* IRCAPTURE */ + alt_jtag_io(0, 0, 0); /* IRSHIFT */ + break; + + case 2: /* IRPAUSE */ + alt_jtag_io(1, 0, 0); /* IREXIT2 */ + alt_jtag_io(1, 0, 0); /* IRUPDATE */ + alt_jtag_io(1, 0, 0); /* DRSELECT */ + alt_jtag_io(1, 0, 0); /* IRSELECT */ + alt_jtag_io(0, 0, 0); /* IRCAPTURE */ + alt_jtag_io(0, 0, 0); /* IRSHIFT */ + break; + + default: + status = 0; + } + + if (status) { + /* loop in the SHIFT-IR state */ + for (i = 0; i < count; i++) { + tdo_bit = alt_jtag_io( + (i == count - 1), + tdi[i >> 3] & (1 << (i & 7)), + (tdo != NULL)); + if (tdo != NULL) { + if (tdo_bit) + tdo[i >> 3] |= (1 << (i & 7)); + else + tdo[i >> 3] &= ~(u32)(1 << (i & 7)); + + } + } + + alt_jtag_io(0, 0, 0); /* IRPAUSE */ + } + + return status; +} + +static void altera_extract_target_data(u8 *buffer, + u8 *target_data, + u32 start_index, + u32 preamble_count, + u32 target_count) +/* + * Copies target data from scan buffer, filtering out + * preamble and postamble data. + */ +{ + u32 i; + u32 j; + u32 k; + + j = preamble_count; + k = start_index + target_count; + for (i = start_index; i < k; ++i, ++j) { + if (buffer[j >> 3] & (1 << (j & 7))) + target_data[i >> 3] |= (1 << (i & 7)); + else + target_data[i >> 3] &= ~(u32)(1 << (i & 7)); + + } +} + +int altera_irscan(struct altera_state *astate, + u32 count, + u8 *tdi_data, + u32 start_index) +/* Shifts data into instruction register */ +{ + struct altera_jtag *js = &astate->js; + int start_code = 0; + u32 alloc_chars = 0; + u32 shift_count = js->ir_pre + count + js->ir_post; + int status = 0; + enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE; + + switch (js->jtag_state) { + case ILLEGAL_JTAG_STATE: + case RESET: + case IDLE: + start_code = 0; + start_state = IDLE; + break; + + case DRSELECT: + case DRCAPTURE: + case DRSHIFT: + case DREXIT1: + case DRPAUSE: + case DREXIT2: + case DRUPDATE: + start_code = 1; + start_state = DRPAUSE; + break; + + case IRSELECT: + case IRCAPTURE: + case IRSHIFT: + case IREXIT1: + case IRPAUSE: + case IREXIT2: + case IRUPDATE: + start_code = 2; + start_state = IRPAUSE; + break; + + default: + status = -EREMOTEIO; + break; + } + + if (status == 0) + if (js->jtag_state != start_state) + status = altera_goto_jstate(astate, start_state); + + if (status == 0) { + if (shift_count > js->ir_length) { + alloc_chars = (shift_count + 7) >> 3; + kfree(js->ir_buffer); + js->ir_buffer = (u8 *)alt_malloc(alloc_chars); + if (js->ir_buffer == NULL) + status = -ENOMEM; + else + js->ir_length = alloc_chars * 8; + + } + } + + if (status == 0) { + /* + * Copy preamble data, IR data, + * and postamble data into a buffer + */ + altera_concatenate_data(js->ir_buffer, + js->ir_pre_data, + js->ir_pre, + tdi_data, + start_index, + count, + js->ir_post_data, + js->ir_post); + /* Do the IRSCAN */ + alt_jtag_irscan(astate, + start_code, + shift_count, + js->ir_buffer, + NULL); + + /* alt_jtag_irscan() always ends in IRPAUSE state */ + js->jtag_state = IRPAUSE; + } + + if (status == 0) + if (js->irstop_state != IRPAUSE) + status = altera_goto_jstate(astate, js->irstop_state); + + + return status; +} + +int altera_swap_ir(struct altera_state *astate, + u32 count, + u8 *in_data, + u32 in_index, + u8 *out_data, + u32 out_index) +/* Shifts data into instruction register, capturing output data */ +{ + struct altera_jtag *js = &astate->js; + int start_code = 0; + u32 alloc_chars = 0; + u32 shift_count = js->ir_pre + count + js->ir_post; + int status = 0; + enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE; + + switch (js->jtag_state) { + case ILLEGAL_JTAG_STATE: + case RESET: + case IDLE: + start_code = 0; + start_state = IDLE; + break; + + case DRSELECT: + case DRCAPTURE: + case DRSHIFT: + case DREXIT1: + case DRPAUSE: + case DREXIT2: + case DRUPDATE: + start_code = 1; + start_state = DRPAUSE; + break; + + case IRSELECT: + case IRCAPTURE: + case IRSHIFT: + case IREXIT1: + case IRPAUSE: + case IREXIT2: + case IRUPDATE: + start_code = 2; + start_state = IRPAUSE; + break; + + default: + status = -EREMOTEIO; + break; + } + + if (status == 0) + if (js->jtag_state != start_state) + status = altera_goto_jstate(astate, start_state); + + if (status == 0) { + if (shift_count > js->ir_length) { + alloc_chars = (shift_count + 7) >> 3; + kfree(js->ir_buffer); + js->ir_buffer = (u8 *)alt_malloc(alloc_chars); + if (js->ir_buffer == NULL) + status = -ENOMEM; + else + js->ir_length = alloc_chars * 8; + + } + } + + if (status == 0) { + /* + * Copy preamble data, IR data, + * and postamble data into a buffer + */ + altera_concatenate_data(js->ir_buffer, + js->ir_pre_data, + js->ir_pre, + in_data, + in_index, + count, + js->ir_post_data, + js->ir_post); + + /* Do the IRSCAN */ + alt_jtag_irscan(astate, + start_code, + shift_count, + js->ir_buffer, + js->ir_buffer); + + /* alt_jtag_irscan() always ends in IRPAUSE state */ + js->jtag_state = IRPAUSE; + } + + if (status == 0) + if (js->irstop_state != IRPAUSE) + status = altera_goto_jstate(astate, js->irstop_state); + + + if (status == 0) + /* Now extract the returned data from the buffer */ + altera_extract_target_data(js->ir_buffer, + out_data, out_index, + js->ir_pre, count); + + return status; +} + +int altera_drscan(struct altera_state *astate, + u32 count, + u8 *tdi_data, + u32 start_index) +/* Shifts data into data register (ignoring output data) */ +{ + struct altera_jtag *js = &astate->js; + int start_code = 0; + u32 alloc_chars = 0; + u32 shift_count = js->dr_pre + count + js->dr_post; + int status = 0; + enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE; + + switch (js->jtag_state) { + case ILLEGAL_JTAG_STATE: + case RESET: + case IDLE: + start_code = 0; + start_state = IDLE; + break; + + case DRSELECT: + case DRCAPTURE: + case DRSHIFT: + case DREXIT1: + case DRPAUSE: + case DREXIT2: + case DRUPDATE: + start_code = 1; + start_state = DRPAUSE; + break; + + case IRSELECT: + case IRCAPTURE: + case IRSHIFT: + case IREXIT1: + case IRPAUSE: + case IREXIT2: + case IRUPDATE: + start_code = 2; + start_state = IRPAUSE; + break; + + default: + status = -EREMOTEIO; + break; + } + + if (status == 0) + if (js->jtag_state != start_state) + status = altera_goto_jstate(astate, start_state); + + if (status == 0) { + if (shift_count > js->dr_length) { + alloc_chars = (shift_count + 7) >> 3; + kfree(js->dr_buffer); + js->dr_buffer = (u8 *)alt_malloc(alloc_chars); + if (js->dr_buffer == NULL) + status = -ENOMEM; + else + js->dr_length = alloc_chars * 8; + + } + } + + if (status == 0) { + /* + * Copy preamble data, DR data, + * and postamble data into a buffer + */ + altera_concatenate_data(js->dr_buffer, + js->dr_pre_data, + js->dr_pre, + tdi_data, + start_index, + count, + js->dr_post_data, + js->dr_post); + /* Do the DRSCAN */ + alt_jtag_drscan(astate, start_code, shift_count, + js->dr_buffer, NULL); + /* alt_jtag_drscan() always ends in DRPAUSE state */ + js->jtag_state = DRPAUSE; + } + + if (status == 0) + if (js->drstop_state != DRPAUSE) + status = altera_goto_jstate(astate, js->drstop_state); + + return status; +} + +int altera_swap_dr(struct altera_state *astate, u32 count, + u8 *in_data, u32 in_index, + u8 *out_data, u32 out_index) +/* Shifts data into data register, capturing output data */ +{ + struct altera_jtag *js = &astate->js; + int start_code = 0; + u32 alloc_chars = 0; + u32 shift_count = js->dr_pre + count + js->dr_post; + int status = 0; + enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE; + + switch (js->jtag_state) { + case ILLEGAL_JTAG_STATE: + case RESET: + case IDLE: + start_code = 0; + start_state = IDLE; + break; + + case DRSELECT: + case DRCAPTURE: + case DRSHIFT: + case DREXIT1: + case DRPAUSE: + case DREXIT2: + case DRUPDATE: + start_code = 1; + start_state = DRPAUSE; + break; + + case IRSELECT: + case IRCAPTURE: + case IRSHIFT: + case IREXIT1: + case IRPAUSE: + case IREXIT2: + case IRUPDATE: + start_code = 2; + start_state = IRPAUSE; + break; + + default: + status = -EREMOTEIO; + break; + } + + if (status == 0) + if (js->jtag_state != start_state) + status = altera_goto_jstate(astate, start_state); + + if (status == 0) { + if (shift_count > js->dr_length) { + alloc_chars = (shift_count + 7) >> 3; + kfree(js->dr_buffer); + js->dr_buffer = (u8 *)alt_malloc(alloc_chars); + + if (js->dr_buffer == NULL) + status = -ENOMEM; + else + js->dr_length = alloc_chars * 8; + + } + } + + if (status == 0) { + /* + * Copy preamble data, DR data, + * and postamble data into a buffer + */ + altera_concatenate_data(js->dr_buffer, + js->dr_pre_data, + js->dr_pre, + in_data, + in_index, + count, + js->dr_post_data, + js->dr_post); + + /* Do the DRSCAN */ + alt_jtag_drscan(astate, + start_code, + shift_count, + js->dr_buffer, + js->dr_buffer); + + /* alt_jtag_drscan() always ends in DRPAUSE state */ + js->jtag_state = DRPAUSE; + } + + if (status == 0) + if (js->drstop_state != DRPAUSE) + status = altera_goto_jstate(astate, js->drstop_state); + + if (status == 0) + /* Now extract the returned data from the buffer */ + altera_extract_target_data(js->dr_buffer, + out_data, + out_index, + js->dr_pre, + count); + + return status; +} + +void altera_free_buffers(struct altera_state *astate) +{ + struct altera_jtag *js = &astate->js; + /* If the JTAG interface was used, reset it to TLR */ + if (js->jtag_state != ILLEGAL_JTAG_STATE) + altera_jreset_idle(astate); + + kfree(js->dr_pre_data); + js->dr_pre_data = NULL; + + kfree(js->dr_post_data); + js->dr_post_data = NULL; + + kfree(js->dr_buffer); + js->dr_buffer = NULL; + + kfree(js->ir_pre_data); + js->ir_pre_data = NULL; + + kfree(js->ir_post_data); + js->ir_post_data = NULL; + + kfree(js->ir_buffer); + js->ir_buffer = NULL; +} diff --git a/drivers/misc/altera-stapl/altera-jtag.h b/drivers/misc/altera-stapl/altera-jtag.h new file mode 100644 index 0000000..2f97e36 --- /dev/null +++ b/drivers/misc/altera-stapl/altera-jtag.h @@ -0,0 +1,113 @@ +/* + * altera-jtag.h + * + * altera FPGA driver + * + * Copyright (C) Altera Corporation 1998-2001 + * Copyright (C) 2010 NetUP Inc. + * Copyright (C) 2010 Igor M. Liplianin + * + * 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 of the License, 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. + */ + +#ifndef ALTERA_JTAG_H +#define ALTERA_JTAG_H + +/* Function Prototypes */ +enum altera_jtag_state { + ILLEGAL_JTAG_STATE = -1, + RESET = 0, + IDLE = 1, + DRSELECT = 2, + DRCAPTURE = 3, + DRSHIFT = 4, + DREXIT1 = 5, + DRPAUSE = 6, + DREXIT2 = 7, + DRUPDATE = 8, + IRSELECT = 9, + IRCAPTURE = 10, + IRSHIFT = 11, + IREXIT1 = 12, + IRPAUSE = 13, + IREXIT2 = 14, + IRUPDATE = 15 + +}; + +struct altera_jtag { + /* Global variable to store the current JTAG state */ + enum altera_jtag_state jtag_state; + + /* Store current stop-state for DR and IR scan commands */ + enum altera_jtag_state drstop_state; + enum altera_jtag_state irstop_state; + + /* Store current padding values */ + u32 dr_pre; + u32 dr_post; + u32 ir_pre; + u32 ir_post; + u32 dr_length; + u32 ir_length; + u8 *dr_pre_data; + u8 *dr_post_data; + u8 *ir_pre_data; + u8 *ir_post_data; + u8 *dr_buffer; + u8 *ir_buffer; +}; + +#define ALTERA_STACK_SIZE 128 +#define ALTERA_MESSAGE_LENGTH 1024 + +struct altera_state { + struct altera_config *config; + struct altera_jtag js; + char msg_buff[ALTERA_MESSAGE_LENGTH + 1]; + long stack[ALTERA_STACK_SIZE]; +}; + +int altera_jinit(struct altera_state *astate); +int altera_set_drstop(struct altera_jtag *js, enum altera_jtag_state state); +int altera_set_irstop(struct altera_jtag *js, enum altera_jtag_state state); +int altera_set_dr_pre(struct altera_jtag *js, u32 count, u32 start_index, + u8 *preamble_data); +int altera_set_ir_pre(struct altera_jtag *js, u32 count, u32 start_index, + u8 *preamble_data); +int altera_set_dr_post(struct altera_jtag *js, u32 count, u32 start_index, + u8 *postamble_data); +int altera_set_ir_post(struct altera_jtag *js, u32 count, u32 start_index, + u8 *postamble_data); +int altera_goto_jstate(struct altera_state *astate, + enum altera_jtag_state state); +int altera_wait_cycles(struct altera_state *astate, s32 cycles, + enum altera_jtag_state wait_state); +int altera_wait_msecs(struct altera_state *astate, s32 microseconds, + enum altera_jtag_state wait_state); +int altera_irscan(struct altera_state *astate, u32 count, + u8 *tdi_data, u32 start_index); +int altera_swap_ir(struct altera_state *astate, + u32 count, u8 *in_data, + u32 in_index, u8 *out_data, + u32 out_index); +int altera_drscan(struct altera_state *astate, u32 count, + u8 *tdi_data, u32 start_index); +int altera_swap_dr(struct altera_state *astate, u32 count, + u8 *in_data, u32 in_index, + u8 *out_data, u32 out_index); +void altera_free_buffers(struct altera_state *astate); +#endif /* ALTERA_JTAG_H */ diff --git a/drivers/misc/altera-stapl/altera-lpt.c b/drivers/misc/altera-stapl/altera-lpt.c new file mode 100644 index 0000000..91456a0 --- /dev/null +++ b/drivers/misc/altera-stapl/altera-lpt.c @@ -0,0 +1,70 @@ +/* + * altera-lpt.c + * + * altera FPGA driver + * + * Copyright (C) Altera Corporation 1998-2001 + * Copyright (C) 2010 NetUP Inc. + * Copyright (C) 2010 Abylay Ospan + * + * 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 of the License, 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 +#include +#include "altera-exprt.h" + +static int lpt_hardware_initialized; + +static void byteblaster_write(int port, int data) +{ + outb((u8)data, (u16)(port + 0x378)); +}; + +static int byteblaster_read(int port) +{ + int data = 0; + data = inb((u16)(port + 0x378)); + return data & 0xff; +}; + +int netup_jtag_io_lpt(void *device, int tms, int tdi, int read_tdo) +{ + int data = 0; + int tdo = 0; + int initial_lpt_ctrl = 0; + + if (!lpt_hardware_initialized) { + initial_lpt_ctrl = byteblaster_read(2); + byteblaster_write(2, (initial_lpt_ctrl | 0x02) & 0xdf); + lpt_hardware_initialized = 1; + } + + data = ((tdi ? 0x40 : 0) | (tms ? 0x02 : 0)); + + byteblaster_write(0, data); + + if (read_tdo) { + tdo = byteblaster_read(1); + tdo = ((tdo & 0x80) ? 0 : 1); + } + + byteblaster_write(0, data | 0x01); + + byteblaster_write(0, data); + + return tdo; +} diff --git a/drivers/misc/altera-stapl/altera.c b/drivers/misc/altera-stapl/altera.c new file mode 100644 index 0000000..1a2c50b --- /dev/null +++ b/drivers/misc/altera-stapl/altera.c @@ -0,0 +1,2536 @@ +/* + * altera.c + * + * altera FPGA driver + * + * Copyright (C) Altera Corporation 1998-2001 + * Copyright (C) 2010,2011 NetUP Inc. + * Copyright (C) 2010,2011 Igor M. Liplianin + * + * 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 of the License, 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 +#include +#include +#include +#include +#include +#include "altera-exprt.h" +#include "altera-jtag.h" + +static int debug = 1; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable debugging information"); + +MODULE_DESCRIPTION("altera FPGA kernel module"); +MODULE_AUTHOR("Igor M. Liplianin "); +MODULE_LICENSE("GPL"); + +#define dprintk(args...) \ + if (debug) { \ + printk(KERN_DEBUG args); \ + } + +enum altera_fpga_opcode { + OP_NOP = 0, + OP_DUP, + OP_SWP, + OP_ADD, + OP_SUB, + OP_MULT, + OP_DIV, + OP_MOD, + OP_SHL, + OP_SHR, + OP_NOT, + OP_AND, + OP_OR, + OP_XOR, + OP_INV, + OP_GT, + OP_LT, + OP_RET, + OP_CMPS, + OP_PINT, + OP_PRNT, + OP_DSS, + OP_DSSC, + OP_ISS, + OP_ISSC, + OP_DPR = 0x1c, + OP_DPRL, + OP_DPO, + OP_DPOL, + OP_IPR, + OP_IPRL, + OP_IPO, + OP_IPOL, + OP_PCHR, + OP_EXIT, + OP_EQU, + OP_POPT, + OP_ABS = 0x2c, + OP_BCH0, + OP_PSH0 = 0x2f, + OP_PSHL = 0x40, + OP_PSHV, + OP_JMP, + OP_CALL, + OP_NEXT, + OP_PSTR, + OP_SINT = 0x47, + OP_ST, + OP_ISTP, + OP_DSTP, + OP_SWPN, + OP_DUPN, + OP_POPV, + OP_POPE, + OP_POPA, + OP_JMPZ, + OP_DS, + OP_IS, + OP_DPRA, + OP_DPOA, + OP_IPRA, + OP_IPOA, + OP_EXPT, + OP_PSHE, + OP_PSHA, + OP_DYNA, + OP_EXPV = 0x5c, + OP_COPY = 0x80, + OP_REVA, + OP_DSC, + OP_ISC, + OP_WAIT, + OP_VS, + OP_CMPA = 0xc0, + OP_VSC, +}; + +struct altera_procinfo { + char *name; + u8 attrs; + struct altera_procinfo *next; +}; + +/* This function checks if enough parameters are available on the stack. */ +static int altera_check_stack(int stack_ptr, int count, int *status) +{ + if (stack_ptr < count) { + *status = -EOVERFLOW; + return 0; + } + + return 1; +} + +static void altera_export_int(char *key, s32 value) +{ + dprintk("Export: key = \"%s\", value = %d\n", key, value); +} + +#define HEX_LINE_CHARS 72 +#define HEX_LINE_BITS (HEX_LINE_CHARS * 4) + +static void altera_export_bool_array(char *key, u8 *data, s32 count) +{ + char string[HEX_LINE_CHARS + 1]; + s32 i, offset; + u32 size, line, lines, linebits, value, j, k; + + if (count > HEX_LINE_BITS) { + dprintk("Export: key = \"%s\", %d bits, value = HEX\n", + key, count); + lines = (count + (HEX_LINE_BITS - 1)) / HEX_LINE_BITS; + + for (line = 0; line < lines; ++line) { + if (line < (lines - 1)) { + linebits = HEX_LINE_BITS; + size = HEX_LINE_CHARS; + offset = count - ((line + 1) * HEX_LINE_BITS); + } else { + linebits = + count - ((lines - 1) * HEX_LINE_BITS); + size = (linebits + 3) / 4; + offset = 0L; + } + + string[size] = '\0'; + j = size - 1; + value = 0; + + for (k = 0; k < linebits; ++k) { + i = k + offset; + if (data[i >> 3] & (1 << (i & 7))) + value |= (1 << (i & 3)); + if ((i & 3) == 3) { + sprintf(&string[j], "%1x", value); + value = 0; + --j; + } + } + if ((k & 3) > 0) + sprintf(&string[j], "%1x", value); + + dprintk("%s\n", string); + } + + } else { + size = (count + 3) / 4; + string[size] = '\0'; + j = size - 1; + value = 0; + + for (i = 0; i < count; ++i) { + if (data[i >> 3] & (1 << (i & 7))) + value |= (1 << (i & 3)); + if ((i & 3) == 3) { + sprintf(&string[j], "%1x", value); + value = 0; + --j; + } + } + if ((i & 3) > 0) + sprintf(&string[j], "%1x", value); + + dprintk("Export: key = \"%s\", %d bits, value = HEX %s\n", + key, count, string); + } +} + +static int altera_execute(struct altera_state *astate, + u8 *p, + s32 program_size, + s32 *error_address, + int *exit_code, + int *format_version) +{ + struct altera_config *aconf = astate->config; + char *msg_buff = astate->msg_buff; + long *stack = astate->stack; + int status = 0; + u32 first_word = 0L; + u32 action_table = 0L; + u32 proc_table = 0L; + u32 str_table = 0L; + u32 sym_table = 0L; + u32 data_sect = 0L; + u32 code_sect = 0L; + u32 debug_sect = 0L; + u32 action_count = 0L; + u32 proc_count = 0L; + u32 sym_count = 0L; + long *vars = NULL; + s32 *var_size = NULL; + char *attrs = NULL; + u8 *proc_attributes = NULL; + u32 pc; + u32 opcode_address; + u32 args[3]; + u32 opcode; + u32 name_id; + u8 charbuf[4]; + long long_tmp; + u32 variable_id; + u8 *charptr_tmp; + u8 *charptr_tmp2; + long *longptr_tmp; + int version = 0; + int delta = 0; + int stack_ptr = 0; + u32 arg_count; + int done = 0; + int bad_opcode = 0; + u32 count; + u32 index; + u32 index2; + s32 long_count; + s32 long_idx; + s32 long_idx2; + u32 i; + u32 j; + u32 uncomp_size; + u32 offset; + u32 value; + int current_proc = 0; + int reverse; + + char *name; + + dprintk("%s\n", __func__); + + /* Read header information */ + if (program_size > 52L) { + first_word = get_unaligned_be32(&p[0]); + version = (first_word & 1L); + *format_version = version + 1; + delta = version * 8; + + action_table = get_unaligned_be32(&p[4]); + proc_table = get_unaligned_be32(&p[8]); + str_table = get_unaligned_be32(&p[4 + delta]); + sym_table = get_unaligned_be32(&p[16 + delta]); + data_sect = get_unaligned_be32(&p[20 + delta]); + code_sect = get_unaligned_be32(&p[24 + delta]); + debug_sect = get_unaligned_be32(&p[28 + delta]); + action_count = get_unaligned_be32(&p[40 + delta]); + proc_count = get_unaligned_be32(&p[44 + delta]); + sym_count = get_unaligned_be32(&p[48 + (2 * delta)]); + } + + if ((first_word != 0x4A414D00L) && (first_word != 0x4A414D01L)) { + done = 1; + status = -EIO; + goto exit_done; + } + + if (sym_count <= 0) + goto exit_done; + + vars = kzalloc(sym_count * sizeof(long), GFP_KERNEL); + + if (vars == NULL) + status = -ENOMEM; + + if (status == 0) { + var_size = kzalloc(sym_count * sizeof(s32), GFP_KERNEL); + + if (var_size == NULL) + status = -ENOMEM; + } + + if (status == 0) { + attrs = kzalloc(sym_count, GFP_KERNEL); + + if (attrs == NULL) + status = -ENOMEM; + } + + if ((status == 0) && (version > 0)) { + proc_attributes = kzalloc(proc_count, GFP_KERNEL); + + if (proc_attributes == NULL) + status = -ENOMEM; + } + + if (status != 0) + goto exit_done; + + delta = version * 2; + + for (i = 0; i < sym_count; ++i) { + offset = (sym_table + ((11 + delta) * i)); + + value = get_unaligned_be32(&p[offset + 3 + delta]); + + attrs[i] = p[offset]; + + /* + * use bit 7 of attribute byte to indicate that + * this buffer was dynamically allocated + * and should be freed later + */ + attrs[i] &= 0x7f; + + var_size[i] = get_unaligned_be32(&p[offset + 7 + delta]); + + /* + * Attribute bits: + * bit 0: 0 = read-only, 1 = read-write + * bit 1: 0 = not compressed, 1 = compressed + * bit 2: 0 = not initialized, 1 = initialized + * bit 3: 0 = scalar, 1 = array + * bit 4: 0 = Boolean, 1 = integer + * bit 5: 0 = declared variable, + * 1 = compiler created temporary variable + */ + + if ((attrs[i] & 0x0c) == 0x04) + /* initialized scalar variable */ + vars[i] = value; + else if ((attrs[i] & 0x1e) == 0x0e) { + /* initialized compressed Boolean array */ + uncomp_size = get_unaligned_le32(&p[data_sect + value]); + + /* allocate a buffer for the uncompressed data */ + vars[i] = (long)kzalloc(uncomp_size, GFP_KERNEL); + if (vars[i] == 0L) + status = -ENOMEM; + else { + /* set flag so buffer will be freed later */ + attrs[i] |= 0x80; + + /* uncompress the data */ + if (altera_shrink(&p[data_sect + value], + var_size[i], + (u8 *)vars[i], + uncomp_size, + version) != uncomp_size) + /* decompression failed */ + status = -EIO; + else + var_size[i] = uncomp_size * 8L; + + } + } else if ((attrs[i] & 0x1e) == 0x0c) { + /* initialized Boolean array */ + vars[i] = value + data_sect + (long)p; + } else if ((attrs[i] & 0x1c) == 0x1c) { + /* initialized integer array */ + vars[i] = value + data_sect; + } else if ((attrs[i] & 0x0c) == 0x08) { + /* uninitialized array */ + + /* flag attrs so that memory is freed */ + attrs[i] |= 0x80; + + if (var_size[i] > 0) { + u32 size; + + if (attrs[i] & 0x10) + /* integer array */ + size = (var_size[i] * sizeof(s32)); + else + /* Boolean array */ + size = ((var_size[i] + 7L) / 8L); + + vars[i] = (long)kzalloc(size, GFP_KERNEL); + + if (vars[i] == 0) { + status = -ENOMEM; + } else { + /* zero out memory */ + for (j = 0; j < size; ++j) + ((u8 *)(vars[i]))[j] = 0; + + } + } else + vars[i] = 0; + + } else + vars[i] = 0; + + } + +exit_done: + if (status != 0) + done = 1; + + altera_jinit(astate); + + pc = code_sect; + msg_buff[0] = '\0'; + + /* + * For JBC version 2, we will execute the procedures corresponding to + * the selected ACTION + */ + if (version > 0) { + if (aconf->action == NULL) { + status = -EINVAL; + done = 1; + } else { + int action_found = 0; + for (i = 0; (i < action_count) && !action_found; ++i) { + name_id = get_unaligned_be32(&p[action_table + + (12 * i)]); + + name = &p[str_table + name_id]; + + if (strnicmp(aconf->action, name, strlen(name)) == 0) { + action_found = 1; + current_proc = + get_unaligned_be32(&p[action_table + + (12 * i) + 8]); + } + } + + if (!action_found) { + status = -EINVAL; + done = 1; + } + } + + if (status == 0) { + int first_time = 1; + i = current_proc; + while ((i != 0) || first_time) { + first_time = 0; + /* check procedure attribute byte */ + proc_attributes[i] = + (p[proc_table + + (13 * i) + 8] & + 0x03); + + /* + * BIT0 - OPTIONAL + * BIT1 - RECOMMENDED + * BIT6 - FORCED OFF + * BIT7 - FORCED ON + */ + + i = get_unaligned_be32(&p[proc_table + + (13 * i) + 4]); + } + + /* + * Set current_proc to the first procedure + * to be executed + */ + i = current_proc; + while ((i != 0) && + ((proc_attributes[i] == 1) || + ((proc_attributes[i] & 0xc0) == 0x40))) { + i = get_unaligned_be32(&p[proc_table + + (13 * i) + 4]); + } + + if ((i != 0) || ((i == 0) && (current_proc == 0) && + ((proc_attributes[0] != 1) && + ((proc_attributes[0] & 0xc0) != 0x40)))) { + current_proc = i; + pc = code_sect + + get_unaligned_be32(&p[proc_table + + (13 * i) + 9]); + if ((pc < code_sect) || (pc >= debug_sect)) + status = -ERANGE; + } else + /* there are no procedures to execute! */ + done = 1; + + } + } + + msg_buff[0] = '\0'; + + while (!done) { + opcode = (p[pc] & 0xff); + opcode_address = pc; + ++pc; + + if (debug > 1) + printk("opcode: %02x\n", opcode); + + arg_count = (opcode >> 6) & 3; + for (i = 0; i < arg_count; ++i) { + args[i] = get_unaligned_be32(&p[pc]); + pc += 4; + } + + switch (opcode) { + case OP_NOP: + break; + case OP_DUP: + if (altera_check_stack(stack_ptr, 1, &status)) { + stack[stack_ptr] = stack[stack_ptr - 1]; + ++stack_ptr; + } + break; + case OP_SWP: + if (altera_check_stack(stack_ptr, 2, &status)) { + long_tmp = stack[stack_ptr - 2]; + stack[stack_ptr - 2] = stack[stack_ptr - 1]; + stack[stack_ptr - 1] = long_tmp; + } + break; + case OP_ADD: + if (altera_check_stack(stack_ptr, 2, &status)) { + --stack_ptr; + stack[stack_ptr - 1] += stack[stack_ptr]; + } + break; + case OP_SUB: + if (altera_check_stack(stack_ptr, 2, &status)) { + --stack_ptr; + stack[stack_ptr - 1] -= stack[stack_ptr]; + } + break; + case OP_MULT: + if (altera_check_stack(stack_ptr, 2, &status)) { + --stack_ptr; + stack[stack_ptr - 1] *= stack[stack_ptr]; + } + break; + case OP_DIV: + if (altera_check_stack(stack_ptr, 2, &status)) { + --stack_ptr; + stack[stack_ptr - 1] /= stack[stack_ptr]; + } + break; + case OP_MOD: + if (altera_check_stack(stack_ptr, 2, &status)) { + --stack_ptr; + stack[stack_ptr - 1] %= stack[stack_ptr]; + } + break; + case OP_SHL: + if (altera_check_stack(stack_ptr, 2, &status)) { + --stack_ptr; + stack[stack_ptr - 1] <<= stack[stack_ptr]; + } + break; + case OP_SHR: + if (altera_check_stack(stack_ptr, 2, &status)) { + --stack_ptr; + stack[stack_ptr - 1] >>= stack[stack_ptr]; + } + break; + case OP_NOT: + if (altera_check_stack(stack_ptr, 1, &status)) + stack[stack_ptr - 1] ^= (-1L); + + break; + case OP_AND: + if (altera_check_stack(stack_ptr, 2, &status)) { + --stack_ptr; + stack[stack_ptr - 1] &= stack[stack_ptr]; + } + break; + case OP_OR: + if (altera_check_stack(stack_ptr, 2, &status)) { + --stack_ptr; + stack[stack_ptr - 1] |= stack[stack_ptr]; + } + break; + case OP_XOR: + if (altera_check_stack(stack_ptr, 2, &status)) { + --stack_ptr; + stack[stack_ptr - 1] ^= stack[stack_ptr]; + } + break; + case OP_INV: + if (!altera_check_stack(stack_ptr, 1, &status)) + break; + stack[stack_ptr - 1] = stack[stack_ptr - 1] ? 0L : 1L; + break; + case OP_GT: + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + --stack_ptr; + stack[stack_ptr - 1] = + (stack[stack_ptr - 1] > stack[stack_ptr]) ? + 1L : 0L; + + break; + case OP_LT: + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + --stack_ptr; + stack[stack_ptr - 1] = + (stack[stack_ptr - 1] < stack[stack_ptr]) ? + 1L : 0L; + + break; + case OP_RET: + if ((version > 0) && (stack_ptr == 0)) { + /* + * We completed one of the main procedures + * of an ACTION. + * Find the next procedure + * to be executed and jump to it. + * If there are no more procedures, then EXIT. + */ + i = get_unaligned_be32(&p[proc_table + + (13 * current_proc) + 4]); + while ((i != 0) && + ((proc_attributes[i] == 1) || + ((proc_attributes[i] & 0xc0) == 0x40))) + i = get_unaligned_be32(&p[proc_table + + (13 * i) + 4]); + + if (i == 0) { + /* no procedures to execute! */ + done = 1; + *exit_code = 0; /* success */ + } else { + current_proc = i; + pc = code_sect + get_unaligned_be32( + &p[proc_table + + (13 * i) + 9]); + if ((pc < code_sect) || + (pc >= debug_sect)) + status = -ERANGE; + } + + } else + if (altera_check_stack(stack_ptr, 1, &status)) { + pc = stack[--stack_ptr] + code_sect; + if ((pc <= code_sect) || + (pc >= debug_sect)) + status = -ERANGE; + + } + + break; + case OP_CMPS: + /* + * Array short compare + * ...stack 0 is source 1 value + * ...stack 1 is source 2 value + * ...stack 2 is mask value + * ...stack 3 is count + */ + if (altera_check_stack(stack_ptr, 4, &status)) { + s32 a = stack[--stack_ptr]; + s32 b = stack[--stack_ptr]; + long_tmp = stack[--stack_ptr]; + count = stack[stack_ptr - 1]; + + if ((count < 1) || (count > 32)) + status = -ERANGE; + else { + long_tmp &= ((-1L) >> (32 - count)); + + stack[stack_ptr - 1] = + ((a & long_tmp) == (b & long_tmp)) + ? 1L : 0L; + } + } + break; + case OP_PINT: + /* + * PRINT add integer + * ...stack 0 is integer value + */ + if (!altera_check_stack(stack_ptr, 1, &status)) + break; + sprintf(&msg_buff[strlen(msg_buff)], + "%ld", stack[--stack_ptr]); + break; + case OP_PRNT: + /* PRINT finish */ + if (debug) + printk(msg_buff, "\n"); + + msg_buff[0] = '\0'; + break; + case OP_DSS: + /* + * DRSCAN short + * ...stack 0 is scan data + * ...stack 1 is count + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + long_tmp = stack[--stack_ptr]; + count = stack[--stack_ptr]; + put_unaligned_le32(long_tmp, &charbuf[0]); + status = altera_drscan(astate, count, charbuf, 0); + break; + case OP_DSSC: + /* + * DRSCAN short with capture + * ...stack 0 is scan data + * ...stack 1 is count + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + long_tmp = stack[--stack_ptr]; + count = stack[stack_ptr - 1]; + put_unaligned_le32(long_tmp, &charbuf[0]); + status = altera_swap_dr(astate, count, charbuf, + 0, charbuf, 0); + stack[stack_ptr - 1] = get_unaligned_le32(&charbuf[0]); + break; + case OP_ISS: + /* + * IRSCAN short + * ...stack 0 is scan data + * ...stack 1 is count + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + long_tmp = stack[--stack_ptr]; + count = stack[--stack_ptr]; + put_unaligned_le32(long_tmp, &charbuf[0]); + status = altera_irscan(astate, count, charbuf, 0); + break; + case OP_ISSC: + /* + * IRSCAN short with capture + * ...stack 0 is scan data + * ...stack 1 is count + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + long_tmp = stack[--stack_ptr]; + count = stack[stack_ptr - 1]; + put_unaligned_le32(long_tmp, &charbuf[0]); + status = altera_swap_ir(astate, count, charbuf, + 0, charbuf, 0); + stack[stack_ptr - 1] = get_unaligned_le32(&charbuf[0]); + break; + case OP_DPR: + if (!altera_check_stack(stack_ptr, 1, &status)) + break; + count = stack[--stack_ptr]; + status = altera_set_dr_pre(&astate->js, count, 0, NULL); + break; + case OP_DPRL: + /* + * DRPRE with literal data + * ...stack 0 is count + * ...stack 1 is literal data + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + count = stack[--stack_ptr]; + long_tmp = stack[--stack_ptr]; + put_unaligned_le32(long_tmp, &charbuf[0]); + status = altera_set_dr_pre(&astate->js, count, 0, + charbuf); + break; + case OP_DPO: + /* + * DRPOST + * ...stack 0 is count + */ + if (altera_check_stack(stack_ptr, 1, &status)) { + count = stack[--stack_ptr]; + status = altera_set_dr_post(&astate->js, count, + 0, NULL); + } + break; + case OP_DPOL: + /* + * DRPOST with literal data + * ...stack 0 is count + * ...stack 1 is literal data + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + count = stack[--stack_ptr]; + long_tmp = stack[--stack_ptr]; + put_unaligned_le32(long_tmp, &charbuf[0]); + status = altera_set_dr_post(&astate->js, count, 0, + charbuf); + break; + case OP_IPR: + if (altera_check_stack(stack_ptr, 1, &status)) { + count = stack[--stack_ptr]; + status = altera_set_ir_pre(&astate->js, count, + 0, NULL); + } + break; + case OP_IPRL: + /* + * IRPRE with literal data + * ...stack 0 is count + * ...stack 1 is literal data + */ + if (altera_check_stack(stack_ptr, 2, &status)) { + count = stack[--stack_ptr]; + long_tmp = stack[--stack_ptr]; + put_unaligned_le32(long_tmp, &charbuf[0]); + status = altera_set_ir_pre(&astate->js, count, + 0, charbuf); + } + break; + case OP_IPO: + /* + * IRPOST + * ...stack 0 is count + */ + if (altera_check_stack(stack_ptr, 1, &status)) { + count = stack[--stack_ptr]; + status = altera_set_ir_post(&astate->js, count, + 0, NULL); + } + break; + case OP_IPOL: + /* + * IRPOST with literal data + * ...stack 0 is count + * ...stack 1 is literal data + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + count = stack[--stack_ptr]; + long_tmp = stack[--stack_ptr]; + put_unaligned_le32(long_tmp, &charbuf[0]); + status = altera_set_ir_post(&astate->js, count, 0, + charbuf); + break; + case OP_PCHR: + if (altera_check_stack(stack_ptr, 1, &status)) { + u8 ch; + count = strlen(msg_buff); + ch = (char) stack[--stack_ptr]; + if ((ch < 1) || (ch > 127)) { + /* + * character code out of range + * instead of flagging an error, + * force the value to 127 + */ + ch = 127; + } + msg_buff[count] = ch; + msg_buff[count + 1] = '\0'; + } + break; + case OP_EXIT: + if (altera_check_stack(stack_ptr, 1, &status)) + *exit_code = stack[--stack_ptr]; + + done = 1; + break; + case OP_EQU: + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + --stack_ptr; + stack[stack_ptr - 1] = + (stack[stack_ptr - 1] == stack[stack_ptr]) ? + 1L : 0L; + break; + case OP_POPT: + if (altera_check_stack(stack_ptr, 1, &status)) + --stack_ptr; + + break; + case OP_ABS: + if (!altera_check_stack(stack_ptr, 1, &status)) + break; + if (stack[stack_ptr - 1] < 0) + stack[stack_ptr - 1] = 0 - stack[stack_ptr - 1]; + + break; + case OP_BCH0: + /* + * Batch operation 0 + * SWP + * SWPN 7 + * SWP + * SWPN 6 + * DUPN 8 + * SWPN 2 + * SWP + * DUPN 6 + * DUPN 6 + */ + + /* SWP */ + if (altera_check_stack(stack_ptr, 2, &status)) { + long_tmp = stack[stack_ptr - 2]; + stack[stack_ptr - 2] = stack[stack_ptr - 1]; + stack[stack_ptr - 1] = long_tmp; + } + + /* SWPN 7 */ + index = 7 + 1; + if (altera_check_stack(stack_ptr, index, &status)) { + long_tmp = stack[stack_ptr - index]; + stack[stack_ptr - index] = stack[stack_ptr - 1]; + stack[stack_ptr - 1] = long_tmp; + } + + /* SWP */ + if (altera_check_stack(stack_ptr, 2, &status)) { + long_tmp = stack[stack_ptr - 2]; + stack[stack_ptr - 2] = stack[stack_ptr - 1]; + stack[stack_ptr - 1] = long_tmp; + } + + /* SWPN 6 */ + index = 6 + 1; + if (altera_check_stack(stack_ptr, index, &status)) { + long_tmp = stack[stack_ptr - index]; + stack[stack_ptr - index] = stack[stack_ptr - 1]; + stack[stack_ptr - 1] = long_tmp; + } + + /* DUPN 8 */ + index = 8 + 1; + if (altera_check_stack(stack_ptr, index, &status)) { + stack[stack_ptr] = stack[stack_ptr - index]; + ++stack_ptr; + } + + /* SWPN 2 */ + index = 2 + 1; + if (altera_check_stack(stack_ptr, index, &status)) { + long_tmp = stack[stack_ptr - index]; + stack[stack_ptr - index] = stack[stack_ptr - 1]; + stack[stack_ptr - 1] = long_tmp; + } + + /* SWP */ + if (altera_check_stack(stack_ptr, 2, &status)) { + long_tmp = stack[stack_ptr - 2]; + stack[stack_ptr - 2] = stack[stack_ptr - 1]; + stack[stack_ptr - 1] = long_tmp; + } + + /* DUPN 6 */ + index = 6 + 1; + if (altera_check_stack(stack_ptr, index, &status)) { + stack[stack_ptr] = stack[stack_ptr - index]; + ++stack_ptr; + } + + /* DUPN 6 */ + index = 6 + 1; + if (altera_check_stack(stack_ptr, index, &status)) { + stack[stack_ptr] = stack[stack_ptr - index]; + ++stack_ptr; + } + break; + case OP_PSH0: + stack[stack_ptr++] = 0; + break; + case OP_PSHL: + stack[stack_ptr++] = (s32) args[0]; + break; + case OP_PSHV: + stack[stack_ptr++] = vars[args[0]]; + break; + case OP_JMP: + pc = args[0] + code_sect; + if ((pc < code_sect) || (pc >= debug_sect)) + status = -ERANGE; + break; + case OP_CALL: + stack[stack_ptr++] = pc; + pc = args[0] + code_sect; + if ((pc < code_sect) || (pc >= debug_sect)) + status = -ERANGE; + break; + case OP_NEXT: + /* + * Process FOR / NEXT loop + * ...argument 0 is variable ID + * ...stack 0 is step value + * ...stack 1 is end value + * ...stack 2 is top address + */ + if (altera_check_stack(stack_ptr, 3, &status)) { + s32 step = stack[stack_ptr - 1]; + s32 end = stack[stack_ptr - 2]; + s32 top = stack[stack_ptr - 3]; + s32 iterator = vars[args[0]]; + int break_out = 0; + + if (step < 0) { + if (iterator <= end) + break_out = 1; + } else if (iterator >= end) + break_out = 1; + + if (break_out) { + stack_ptr -= 3; + } else { + vars[args[0]] = iterator + step; + pc = top + code_sect; + if ((pc < code_sect) || + (pc >= debug_sect)) + status = -ERANGE; + } + } + break; + case OP_PSTR: + /* + * PRINT add string + * ...argument 0 is string ID + */ + count = strlen(msg_buff); + strlcpy(&msg_buff[count], + &p[str_table + args[0]], + ALTERA_MESSAGE_LENGTH - count); + break; + case OP_SINT: + /* + * STATE intermediate state + * ...argument 0 is state code + */ + status = altera_goto_jstate(astate, args[0]); + break; + case OP_ST: + /* + * STATE final state + * ...argument 0 is state code + */ + status = altera_goto_jstate(astate, args[0]); + break; + case OP_ISTP: + /* + * IRSTOP state + * ...argument 0 is state code + */ + status = altera_set_irstop(&astate->js, args[0]); + break; + case OP_DSTP: + /* + * DRSTOP state + * ...argument 0 is state code + */ + status = altera_set_drstop(&astate->js, args[0]); + break; + + case OP_SWPN: + /* + * Exchange top with Nth stack value + * ...argument 0 is 0-based stack entry + * to swap with top element + */ + index = (args[0]) + 1; + if (altera_check_stack(stack_ptr, index, &status)) { + long_tmp = stack[stack_ptr - index]; + stack[stack_ptr - index] = stack[stack_ptr - 1]; + stack[stack_ptr - 1] = long_tmp; + } + break; + case OP_DUPN: + /* + * Duplicate Nth stack value + * ...argument 0 is 0-based stack entry to duplicate + */ + index = (args[0]) + 1; + if (altera_check_stack(stack_ptr, index, &status)) { + stack[stack_ptr] = stack[stack_ptr - index]; + ++stack_ptr; + } + break; + case OP_POPV: + /* + * Pop stack into scalar variable + * ...argument 0 is variable ID + * ...stack 0 is value + */ + if (altera_check_stack(stack_ptr, 1, &status)) + vars[args[0]] = stack[--stack_ptr]; + + break; + case OP_POPE: + /* + * Pop stack into integer array element + * ...argument 0 is variable ID + * ...stack 0 is array index + * ...stack 1 is value + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + variable_id = args[0]; + + /* + * If variable is read-only, + * convert to writable array + */ + if ((version > 0) && + ((attrs[variable_id] & 0x9c) == 0x1c)) { + /* Allocate a writable buffer for this array */ + count = var_size[variable_id]; + long_tmp = vars[variable_id]; + longptr_tmp = kzalloc(count * sizeof(long), + GFP_KERNEL); + vars[variable_id] = (long)longptr_tmp; + + if (vars[variable_id] == 0) { + status = -ENOMEM; + break; + } + + /* copy previous contents into buffer */ + for (i = 0; i < count; ++i) { + longptr_tmp[i] = + get_unaligned_be32(&p[long_tmp]); + long_tmp += sizeof(long); + } + + /* + * set bit 7 - buffer was + * dynamically allocated + */ + attrs[variable_id] |= 0x80; + + /* clear bit 2 - variable is writable */ + attrs[variable_id] &= ~0x04; + attrs[variable_id] |= 0x01; + + } + + /* check that variable is a writable integer array */ + if ((attrs[variable_id] & 0x1c) != 0x18) + status = -ERANGE; + else { + longptr_tmp = (long *)vars[variable_id]; + + /* pop the array index */ + index = stack[--stack_ptr]; + + /* pop the value and store it into the array */ + longptr_tmp[index] = stack[--stack_ptr]; + } + + break; + case OP_POPA: + /* + * Pop stack into Boolean array + * ...argument 0 is variable ID + * ...stack 0 is count + * ...stack 1 is array index + * ...stack 2 is value + */ + if (!altera_check_stack(stack_ptr, 3, &status)) + break; + variable_id = args[0]; + + /* + * If variable is read-only, + * convert to writable array + */ + if ((version > 0) && + ((attrs[variable_id] & 0x9c) == 0x0c)) { + /* Allocate a writable buffer for this array */ + long_tmp = + (var_size[variable_id] + 7L) >> 3L; + charptr_tmp2 = (u8 *)vars[variable_id]; + charptr_tmp = + kzalloc(long_tmp, GFP_KERNEL); + vars[variable_id] = (long)charptr_tmp; + + if (vars[variable_id] == 0) { + status = -ENOMEM; + break; + } + + /* zero the buffer */ + for (long_idx = 0L; + long_idx < long_tmp; + ++long_idx) { + charptr_tmp[long_idx] = 0; + } + + /* copy previous contents into buffer */ + for (long_idx = 0L; + long_idx < var_size[variable_id]; + ++long_idx) { + long_idx2 = long_idx; + + if (charptr_tmp2[long_idx2 >> 3] & + (1 << (long_idx2 & 7))) { + charptr_tmp[long_idx >> 3] |= + (1 << (long_idx & 7)); + } + } + + /* + * set bit 7 - buffer was + * dynamically allocated + */ + attrs[variable_id] |= 0x80; + + /* clear bit 2 - variable is writable */ + attrs[variable_id] &= ~0x04; + attrs[variable_id] |= 0x01; + + } + + /* + * check that variable is + * a writable Boolean array + */ + if ((attrs[variable_id] & 0x1c) != 0x08) { + status = -ERANGE; + break; + } + + charptr_tmp = (u8 *)vars[variable_id]; + + /* pop the count (number of bits to copy) */ + long_count = stack[--stack_ptr]; + + /* pop the array index */ + long_idx = stack[--stack_ptr]; + + reverse = 0; + + if (version > 0) { + /* + * stack 0 = array right index + * stack 1 = array left index + */ + + if (long_idx > long_count) { + reverse = 1; + long_tmp = long_count; + long_count = 1 + long_idx - + long_count; + long_idx = long_tmp; + + /* reverse POPA is not supported */ + status = -ERANGE; + break; + } else + long_count = 1 + long_count - + long_idx; + + } + + /* pop the data */ + long_tmp = stack[--stack_ptr]; + + if (long_count < 1) { + status = -ERANGE; + break; + } + + for (i = 0; i < long_count; ++i) { + if (long_tmp & (1L << (s32) i)) + charptr_tmp[long_idx >> 3L] |= + (1L << (long_idx & 7L)); + else + charptr_tmp[long_idx >> 3L] &= + ~(1L << (long_idx & 7L)); + + ++long_idx; + } + + break; + case OP_JMPZ: + /* + * Pop stack and branch if zero + * ...argument 0 is address + * ...stack 0 is condition value + */ + if (altera_check_stack(stack_ptr, 1, &status)) { + if (stack[--stack_ptr] == 0) { + pc = args[0] + code_sect; + if ((pc < code_sect) || + (pc >= debug_sect)) + status = -ERANGE; + } + } + break; + case OP_DS: + case OP_IS: + /* + * DRSCAN + * IRSCAN + * ...argument 0 is scan data variable ID + * ...stack 0 is array index + * ...stack 1 is count + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + long_idx = stack[--stack_ptr]; + long_count = stack[--stack_ptr]; + reverse = 0; + if (version > 0) { + /* + * stack 0 = array right index + * stack 1 = array left index + * stack 2 = count + */ + long_tmp = long_count; + long_count = stack[--stack_ptr]; + + if (long_idx > long_tmp) { + reverse = 1; + long_idx = long_tmp; + } + } + + charptr_tmp = (u8 *)vars[args[0]]; + + if (reverse) { + /* + * allocate a buffer + * and reverse the data order + */ + charptr_tmp2 = charptr_tmp; + charptr_tmp = kzalloc((long_count >> 3) + 1, + GFP_KERNEL); + if (charptr_tmp == NULL) { + status = -ENOMEM; + break; + } + + long_tmp = long_idx + long_count - 1; + long_idx2 = 0; + while (long_idx2 < long_count) { + if (charptr_tmp2[long_tmp >> 3] & + (1 << (long_tmp & 7))) + charptr_tmp[long_idx2 >> 3] |= + (1 << (long_idx2 & 7)); + else + charptr_tmp[long_idx2 >> 3] &= + ~(1 << (long_idx2 & 7)); + + --long_tmp; + ++long_idx2; + } + } + + if (opcode == 0x51) /* DS */ + status = altera_drscan(astate, long_count, + charptr_tmp, long_idx); + else /* IS */ + status = altera_irscan(astate, long_count, + charptr_tmp, long_idx); + + if (reverse) + kfree(charptr_tmp); + + break; + case OP_DPRA: + /* + * DRPRE with array data + * ...argument 0 is variable ID + * ...stack 0 is array index + * ...stack 1 is count + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + index = stack[--stack_ptr]; + count = stack[--stack_ptr]; + + if (version > 0) + /* + * stack 0 = array right index + * stack 1 = array left index + */ + count = 1 + count - index; + + charptr_tmp = (u8 *)vars[args[0]]; + status = altera_set_dr_pre(&astate->js, count, index, + charptr_tmp); + break; + case OP_DPOA: + /* + * DRPOST with array data + * ...argument 0 is variable ID + * ...stack 0 is array index + * ...stack 1 is count + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + index = stack[--stack_ptr]; + count = stack[--stack_ptr]; + + if (version > 0) + /* + * stack 0 = array right index + * stack 1 = array left index + */ + count = 1 + count - index; + + charptr_tmp = (u8 *)vars[args[0]]; + status = altera_set_dr_post(&astate->js, count, index, + charptr_tmp); + break; + case OP_IPRA: + /* + * IRPRE with array data + * ...argument 0 is variable ID + * ...stack 0 is array index + * ...stack 1 is count + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + index = stack[--stack_ptr]; + count = stack[--stack_ptr]; + + if (version > 0) + /* + * stack 0 = array right index + * stack 1 = array left index + */ + count = 1 + count - index; + + charptr_tmp = (u8 *)vars[args[0]]; + status = altera_set_ir_pre(&astate->js, count, index, + charptr_tmp); + + break; + case OP_IPOA: + /* + * IRPOST with array data + * ...argument 0 is variable ID + * ...stack 0 is array index + * ...stack 1 is count + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + index = stack[--stack_ptr]; + count = stack[--stack_ptr]; + + if (version > 0) + /* + * stack 0 = array right index + * stack 1 = array left index + */ + count = 1 + count - index; + + charptr_tmp = (u8 *)vars[args[0]]; + status = altera_set_ir_post(&astate->js, count, index, + charptr_tmp); + + break; + case OP_EXPT: + /* + * EXPORT + * ...argument 0 is string ID + * ...stack 0 is integer expression + */ + if (altera_check_stack(stack_ptr, 1, &status)) { + name = &p[str_table + args[0]]; + long_tmp = stack[--stack_ptr]; + altera_export_int(name, long_tmp); + } + break; + case OP_PSHE: + /* + * Push integer array element + * ...argument 0 is variable ID + * ...stack 0 is array index + */ + if (!altera_check_stack(stack_ptr, 1, &status)) + break; + variable_id = args[0]; + index = stack[stack_ptr - 1]; + + /* check variable type */ + if ((attrs[variable_id] & 0x1f) == 0x19) { + /* writable integer array */ + longptr_tmp = (long *)vars[variable_id]; + stack[stack_ptr - 1] = longptr_tmp[index]; + } else if ((attrs[variable_id] & 0x1f) == 0x1c) { + /* read-only integer array */ + long_tmp = vars[variable_id] + + (index * sizeof(long)); + stack[stack_ptr - 1] = + get_unaligned_be32(&p[long_tmp]); + } else + status = -ERANGE; + + break; + case OP_PSHA: + /* + * Push Boolean array + * ...argument 0 is variable ID + * ...stack 0 is count + * ...stack 1 is array index + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + variable_id = args[0]; + + /* check that variable is a Boolean array */ + if ((attrs[variable_id] & 0x18) != 0x08) { + status = -ERANGE; + break; + } + + charptr_tmp = (u8 *)vars[variable_id]; + + /* pop the count (number of bits to copy) */ + count = stack[--stack_ptr]; + + /* pop the array index */ + index = stack[stack_ptr - 1]; + + if (version > 0) + /* + * stack 0 = array right index + * stack 1 = array left index + */ + count = 1 + count - index; + + if ((count < 1) || (count > 32)) { + status = -ERANGE; + break; + } + + long_tmp = 0L; + + for (i = 0; i < count; ++i) + if (charptr_tmp[(i + index) >> 3] & + (1 << ((i + index) & 7))) + long_tmp |= (1L << i); + + stack[stack_ptr - 1] = long_tmp; + + break; + case OP_DYNA: + /* + * Dynamically change size of array + * ...argument 0 is variable ID + * ...stack 0 is new size + */ + if (!altera_check_stack(stack_ptr, 1, &status)) + break; + variable_id = args[0]; + long_tmp = stack[--stack_ptr]; + + if (long_tmp > var_size[variable_id]) { + var_size[variable_id] = long_tmp; + + if (attrs[variable_id] & 0x10) + /* allocate integer array */ + long_tmp *= sizeof(long); + else + /* allocate Boolean array */ + long_tmp = (long_tmp + 7) >> 3; + + /* + * If the buffer was previously allocated, + * free it + */ + if (attrs[variable_id] & 0x80) { + kfree((void *)vars[variable_id]); + vars[variable_id] = 0; + } + + /* + * Allocate a new buffer + * of the requested size + */ + vars[variable_id] = (long) + kzalloc(long_tmp, GFP_KERNEL); + + if (vars[variable_id] == 0) { + status = -ENOMEM; + break; + } + + /* + * Set the attribute bit to indicate that + * this buffer was dynamically allocated and + * should be freed later + */ + attrs[variable_id] |= 0x80; + + /* zero out memory */ + count = ((var_size[variable_id] + 7L) / + 8L); + charptr_tmp = (u8 *)(vars[variable_id]); + for (index = 0; index < count; ++index) + charptr_tmp[index] = 0; + + } + + break; + case OP_EXPV: + /* + * Export Boolean array + * ...argument 0 is string ID + * ...stack 0 is variable ID + * ...stack 1 is array right index + * ...stack 2 is array left index + */ + if (!altera_check_stack(stack_ptr, 3, &status)) + break; + if (version == 0) { + /* EXPV is not supported in JBC 1.0 */ + bad_opcode = 1; + break; + } + name = &p[str_table + args[0]]; + variable_id = stack[--stack_ptr]; + long_idx = stack[--stack_ptr];/* right indx */ + long_idx2 = stack[--stack_ptr];/* left indx */ + + if (long_idx > long_idx2) { + /* reverse indices not supported */ + status = -ERANGE; + break; + } + + long_count = 1 + long_idx2 - long_idx; + + charptr_tmp = (u8 *)vars[variable_id]; + charptr_tmp2 = NULL; + + if ((long_idx & 7L) != 0) { + s32 k = long_idx; + charptr_tmp2 = + kzalloc(((long_count + 7L) / 8L), + GFP_KERNEL); + if (charptr_tmp2 == NULL) { + status = -ENOMEM; + break; + } + + for (i = 0; i < long_count; ++i) { + if (charptr_tmp[k >> 3] & + (1 << (k & 7))) + charptr_tmp2[i >> 3] |= + (1 << (i & 7)); + else + charptr_tmp2[i >> 3] &= + ~(1 << (i & 7)); + + ++k; + } + charptr_tmp = charptr_tmp2; + + } else if (long_idx != 0) + charptr_tmp = &charptr_tmp[long_idx >> 3]; + + altera_export_bool_array(name, charptr_tmp, + long_count); + + /* free allocated buffer */ + if ((long_idx & 7L) != 0) + kfree(charptr_tmp2); + + break; + case OP_COPY: { + /* + * Array copy + * ...argument 0 is dest ID + * ...argument 1 is source ID + * ...stack 0 is count + * ...stack 1 is dest index + * ...stack 2 is source index + */ + s32 copy_count; + s32 copy_index; + s32 copy_index2; + s32 destleft; + s32 src_count; + s32 dest_count; + int src_reverse = 0; + int dest_reverse = 0; + + if (!altera_check_stack(stack_ptr, 3, &status)) + break; + + copy_count = stack[--stack_ptr]; + copy_index = stack[--stack_ptr]; + copy_index2 = stack[--stack_ptr]; + reverse = 0; + + if (version > 0) { + /* + * stack 0 = source right index + * stack 1 = source left index + * stack 2 = destination right index + * stack 3 = destination left index + */ + destleft = stack[--stack_ptr]; + + if (copy_count > copy_index) { + src_reverse = 1; + reverse = 1; + src_count = 1 + copy_count - copy_index; + /* copy_index = source start index */ + } else { + src_count = 1 + copy_index - copy_count; + /* source start index */ + copy_index = copy_count; + } + + if (copy_index2 > destleft) { + dest_reverse = 1; + reverse = !reverse; + dest_count = 1 + copy_index2 - destleft; + /* destination start index */ + copy_index2 = destleft; + } else + dest_count = 1 + destleft - copy_index2; + + copy_count = (src_count < dest_count) ? + src_count : dest_count; + + if ((src_reverse || dest_reverse) && + (src_count != dest_count)) + /* + * If either the source or destination + * is reversed, we can't tolerate + * a length mismatch, because we + * "left justify" arrays when copying. + * This won't work correctly + * with reversed arrays. + */ + status = -ERANGE; + + } + + count = copy_count; + index = copy_index; + index2 = copy_index2; + + /* + * If destination is a read-only array, + * allocate a buffer and convert it to a writable array + */ + variable_id = args[1]; + if ((version > 0) && + ((attrs[variable_id] & 0x9c) == 0x0c)) { + /* Allocate a writable buffer for this array */ + long_tmp = + (var_size[variable_id] + 7L) >> 3L; + charptr_tmp2 = (u8 *)vars[variable_id]; + charptr_tmp = + kzalloc(long_tmp, GFP_KERNEL); + vars[variable_id] = (long)charptr_tmp; + + if (vars[variable_id] == 0) { + status = -ENOMEM; + break; + } + + /* zero the buffer */ + for (long_idx = 0L; long_idx < long_tmp; + ++long_idx) + charptr_tmp[long_idx] = 0; + + /* copy previous contents into buffer */ + for (long_idx = 0L; + long_idx < var_size[variable_id]; + ++long_idx) { + long_idx2 = long_idx; + + if (charptr_tmp2[long_idx2 >> 3] & + (1 << (long_idx2 & 7))) + charptr_tmp[long_idx >> 3] |= + (1 << (long_idx & 7)); + + } + + /* + set bit 7 - buffer was dynamically allocated */ + attrs[variable_id] |= 0x80; + + /* clear bit 2 - variable is writable */ + attrs[variable_id] &= ~0x04; + attrs[variable_id] |= 0x01; + } + + charptr_tmp = (u8 *)vars[args[1]]; + charptr_tmp2 = (u8 *)vars[args[0]]; + + /* check if destination is a writable Boolean array */ + if ((attrs[args[1]] & 0x1c) != 0x08) { + status = -ERANGE; + break; + } + + if (count < 1) { + status = -ERANGE; + break; + } + + if (reverse) + index2 += (count - 1); + + for (i = 0; i < count; ++i) { + if (charptr_tmp2[index >> 3] & + (1 << (index & 7))) + charptr_tmp[index2 >> 3] |= + (1 << (index2 & 7)); + else + charptr_tmp[index2 >> 3] &= + ~(1 << (index2 & 7)); + + ++index; + if (reverse) + --index2; + else + ++index2; + } + + break; + } + case OP_DSC: + case OP_ISC: { + /* + * DRSCAN with capture + * IRSCAN with capture + * ...argument 0 is scan data variable ID + * ...argument 1 is capture variable ID + * ...stack 0 is capture index + * ...stack 1 is scan data index + * ...stack 2 is count + */ + s32 scan_right, scan_left; + s32 capture_count = 0; + s32 scan_count = 0; + s32 capture_index; + s32 scan_index; + + if (!altera_check_stack(stack_ptr, 3, &status)) + break; + + capture_index = stack[--stack_ptr]; + scan_index = stack[--stack_ptr]; + + if (version > 0) { + /* + * stack 0 = capture right index + * stack 1 = capture left index + * stack 2 = scan right index + * stack 3 = scan left index + * stack 4 = count + */ + scan_right = stack[--stack_ptr]; + scan_left = stack[--stack_ptr]; + capture_count = 1 + scan_index - capture_index; + scan_count = 1 + scan_left - scan_right; + scan_index = scan_right; + } + + long_count = stack[--stack_ptr]; + /* + * If capture array is read-only, allocate a buffer + * and convert it to a writable array + */ + variable_id = args[1]; + if ((version > 0) && + ((attrs[variable_id] & 0x9c) == 0x0c)) { + /* Allocate a writable buffer for this array */ + long_tmp = + (var_size[variable_id] + 7L) >> 3L; + charptr_tmp2 = (u8 *)vars[variable_id]; + charptr_tmp = + kzalloc(long_tmp, GFP_KERNEL); + vars[variable_id] = (long)charptr_tmp; + + if (vars[variable_id] == 0) { + status = -ENOMEM; + break; + } + + /* zero the buffer */ + for (long_idx = 0L; long_idx < long_tmp; + ++long_idx) + charptr_tmp[long_idx] = 0; + + /* copy previous contents into buffer */ + for (long_idx = 0L; + long_idx < var_size[variable_id]; + ++long_idx) { + long_idx2 = long_idx; + + if (charptr_tmp2[long_idx2 >> 3] & + (1 << (long_idx2 & 7))) + charptr_tmp[long_idx >> 3] |= + (1 << (long_idx & 7)); + + } + + /* + * set bit 7 - buffer was + * dynamically allocated + */ + attrs[variable_id] |= 0x80; + + /* clear bit 2 - variable is writable */ + attrs[variable_id] &= ~0x04; + attrs[variable_id] |= 0x01; + + } + + charptr_tmp = (u8 *)vars[args[0]]; + charptr_tmp2 = (u8 *)vars[args[1]]; + + if ((version > 0) && + ((long_count > capture_count) || + (long_count > scan_count))) { + status = -ERANGE; + break; + } + + /* + * check that capture array + * is a writable Boolean array + */ + if ((attrs[args[1]] & 0x1c) != 0x08) { + status = -ERANGE; + break; + } + + if (status == 0) { + if (opcode == 0x82) /* DSC */ + status = altera_swap_dr(astate, + long_count, + charptr_tmp, + scan_index, + charptr_tmp2, + capture_index); + else /* ISC */ + status = altera_swap_ir(astate, + long_count, + charptr_tmp, + scan_index, + charptr_tmp2, + capture_index); + + } + + break; + } + case OP_WAIT: + /* + * WAIT + * ...argument 0 is wait state + * ...argument 1 is end state + * ...stack 0 is cycles + * ...stack 1 is microseconds + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + long_tmp = stack[--stack_ptr]; + + if (long_tmp != 0L) + status = altera_wait_cycles(astate, long_tmp, + args[0]); + + long_tmp = stack[--stack_ptr]; + + if ((status == 0) && (long_tmp != 0L)) + status = altera_wait_msecs(astate, + long_tmp, + args[0]); + + if ((status == 0) && (args[1] != args[0])) + status = altera_goto_jstate(astate, + args[1]); + + if (version > 0) { + --stack_ptr; /* throw away MAX cycles */ + --stack_ptr; /* throw away MAX microseconds */ + } + break; + case OP_CMPA: { + /* + * Array compare + * ...argument 0 is source 1 ID + * ...argument 1 is source 2 ID + * ...argument 2 is mask ID + * ...stack 0 is source 1 index + * ...stack 1 is source 2 index + * ...stack 2 is mask index + * ...stack 3 is count + */ + s32 a, b; + u8 *source1 = (u8 *)vars[args[0]]; + u8 *source2 = (u8 *)vars[args[1]]; + u8 *mask = (u8 *)vars[args[2]]; + u32 index1; + u32 index2; + u32 mask_index; + + if (!altera_check_stack(stack_ptr, 4, &status)) + break; + + index1 = stack[--stack_ptr]; + index2 = stack[--stack_ptr]; + mask_index = stack[--stack_ptr]; + long_count = stack[--stack_ptr]; + + if (version > 0) { + /* + * stack 0 = source 1 right index + * stack 1 = source 1 left index + * stack 2 = source 2 right index + * stack 3 = source 2 left index + * stack 4 = mask right index + * stack 5 = mask left index + */ + s32 mask_right = stack[--stack_ptr]; + s32 mask_left = stack[--stack_ptr]; + /* source 1 count */ + a = 1 + index2 - index1; + /* source 2 count */ + b = 1 + long_count - mask_index; + a = (a < b) ? a : b; + /* mask count */ + b = 1 + mask_left - mask_right; + a = (a < b) ? a : b; + /* source 2 start index */ + index2 = mask_index; + /* mask start index */ + mask_index = mask_right; + long_count = a; + } + + long_tmp = 1L; + + if (long_count < 1) + status = -ERANGE; + else { + count = long_count; + + for (i = 0; i < count; ++i) { + if (mask[mask_index >> 3] & + (1 << (mask_index & 7))) { + a = source1[index1 >> 3] & + (1 << (index1 & 7)) + ? 1 : 0; + b = source2[index2 >> 3] & + (1 << (index2 & 7)) + ? 1 : 0; + + if (a != b) /* failure */ + long_tmp = 0L; + } + ++index1; + ++index2; + ++mask_index; + } + } + + stack[stack_ptr++] = long_tmp; + + break; + } + default: + /* Unrecognized opcode -- ERROR! */ + bad_opcode = 1; + break; + } + + if (bad_opcode) + status = -ENOSYS; + + if ((stack_ptr < 0) || (stack_ptr >= ALTERA_STACK_SIZE)) + status = -EOVERFLOW; + + if (status != 0) { + done = 1; + *error_address = (s32)(opcode_address - code_sect); + } + } + + altera_free_buffers(astate); + + /* Free all dynamically allocated arrays */ + if ((attrs != NULL) && (vars != NULL)) + for (i = 0; i < sym_count; ++i) + if (attrs[i] & 0x80) + kfree((void *)vars[i]); + + kfree(vars); + kfree(var_size); + kfree(attrs); + kfree(proc_attributes); + + return status; +} + +static int altera_get_note(u8 *p, s32 program_size, + s32 *offset, char *key, char *value, int length) +/* + * Gets key and value of NOTE fields in the JBC file. + * Can be called in two modes: if offset pointer is NULL, + * then the function searches for note fields which match + * the key string provided. If offset is not NULL, then + * the function finds the next note field of any key, + * starting at the offset specified by the offset pointer. + * Returns 0 for success, else appropriate error code + */ +{ + int status = -ENODATA; + u32 note_strings = 0L; + u32 note_table = 0L; + u32 note_count = 0L; + u32 first_word = 0L; + int version = 0; + int delta = 0; + char *key_ptr; + char *value_ptr; + int i; + + /* Read header information */ + if (program_size > 52L) { + first_word = get_unaligned_be32(&p[0]); + version = (first_word & 1L); + delta = version * 8; + + note_strings = get_unaligned_be32(&p[8 + delta]); + note_table = get_unaligned_be32(&p[12 + delta]); + note_count = get_unaligned_be32(&p[44 + (2 * delta)]); + } + + if ((first_word != 0x4A414D00L) && (first_word != 0x4A414D01L)) + return -EIO; + + if (note_count <= 0L) + return status; + + if (offset == NULL) { + /* + * We will search for the first note with a specific key, + * and return only the value + */ + for (i = 0; (i < note_count) && + (status != 0); ++i) { + key_ptr = &p[note_strings + + get_unaligned_be32( + &p[note_table + (8 * i)])]; + if ((strnicmp(key, key_ptr, strlen(key_ptr)) == 0) && + (key != NULL)) { + status = 0; + + value_ptr = &p[note_strings + + get_unaligned_be32( + &p[note_table + (8 * i) + 4])]; + + if (value != NULL) + strlcpy(value, value_ptr, length); + + } + } + } else { + /* + * We will search for the next note, regardless of the key, + * and return both the value and the key + */ + + i = *offset; + + if ((i >= 0) && (i < note_count)) { + status = 0; + + if (key != NULL) + strlcpy(key, &p[note_strings + + get_unaligned_be32( + &p[note_table + (8 * i)])], + length); + + if (value != NULL) + strlcpy(value, &p[note_strings + + get_unaligned_be32( + &p[note_table + (8 * i) + 4])], + length); + + *offset = i + 1; + } + } + + return status; +} + +static int altera_check_crc(u8 *p, s32 program_size) +{ + int status = 0; + u16 local_expected = 0, + local_actual = 0, + shift_reg = 0xffff; + int bit, feedback; + u8 databyte; + u32 i; + u32 crc_section = 0L; + u32 first_word = 0L; + int version = 0; + int delta = 0; + + if (program_size > 52L) { + first_word = get_unaligned_be32(&p[0]); + version = (first_word & 1L); + delta = version * 8; + + crc_section = get_unaligned_be32(&p[32 + delta]); + } + + if ((first_word != 0x4A414D00L) && (first_word != 0x4A414D01L)) + status = -EIO; + + if (crc_section >= program_size) + status = -EIO; + + if (status == 0) { + local_expected = (u16)get_unaligned_be16(&p[crc_section]); + + for (i = 0; i < crc_section; ++i) { + databyte = p[i]; + for (bit = 0; bit < 8; bit++) { + feedback = (databyte ^ shift_reg) & 0x01; + shift_reg >>= 1; + if (feedback) + shift_reg ^= 0x8408; + + databyte >>= 1; + } + } + + local_actual = (u16)~shift_reg; + + if (local_expected != local_actual) + status = -EILSEQ; + + } + + if (debug || status) { + switch (status) { + case 0: + printk(KERN_INFO "%s: CRC matched: %04x\n", __func__, + local_actual); + break; + case -EILSEQ: + printk(KERN_ERR "%s: CRC mismatch: expected %04x, " + "actual %04x\n", __func__, local_expected, + local_actual); + break; + case -ENODATA: + printk(KERN_ERR "%s: expected CRC not found, " + "actual CRC = %04x\n", __func__, + local_actual); + break; + case -EIO: + printk(KERN_ERR "%s: error: format isn't " + "recognized.\n", __func__); + break; + default: + printk(KERN_ERR "%s: CRC function returned error " + "code %d\n", __func__, status); + break; + } + } + + return status; +} + +static int altera_get_file_info(u8 *p, + s32 program_size, + int *format_version, + int *action_count, + int *procedure_count) +{ + int status = -EIO; + u32 first_word = 0; + int version = 0; + + if (program_size <= 52L) + return status; + + first_word = get_unaligned_be32(&p[0]); + + if ((first_word == 0x4A414D00L) || (first_word == 0x4A414D01L)) { + status = 0; + + version = (first_word & 1L); + *format_version = version + 1; + + if (version > 0) { + *action_count = get_unaligned_be32(&p[48]); + *procedure_count = get_unaligned_be32(&p[52]); + } + } + + return status; +} + +static int altera_get_act_info(u8 *p, + s32 program_size, + int index, + char **name, + char **description, + struct altera_procinfo **proc_list) +{ + int status = -EIO; + struct altera_procinfo *procptr = NULL; + struct altera_procinfo *tmpptr = NULL; + u32 first_word = 0L; + u32 action_table = 0L; + u32 proc_table = 0L; + u32 str_table = 0L; + u32 note_strings = 0L; + u32 action_count = 0L; + u32 proc_count = 0L; + u32 act_name_id = 0L; + u32 act_desc_id = 0L; + u32 act_proc_id = 0L; + u32 act_proc_name = 0L; + u8 act_proc_attribute = 0; + + if (program_size <= 52L) + return status; + /* Read header information */ + first_word = get_unaligned_be32(&p[0]); + + if (first_word != 0x4A414D01L) + return status; + + action_table = get_unaligned_be32(&p[4]); + proc_table = get_unaligned_be32(&p[8]); + str_table = get_unaligned_be32(&p[12]); + note_strings = get_unaligned_be32(&p[16]); + action_count = get_unaligned_be32(&p[48]); + proc_count = get_unaligned_be32(&p[52]); + + if (index >= action_count) + return status; + + act_name_id = get_unaligned_be32(&p[action_table + (12 * index)]); + act_desc_id = get_unaligned_be32(&p[action_table + (12 * index) + 4]); + act_proc_id = get_unaligned_be32(&p[action_table + (12 * index) + 8]); + + *name = &p[str_table + act_name_id]; + + if (act_desc_id < (note_strings - str_table)) + *description = &p[str_table + act_desc_id]; + + do { + act_proc_name = get_unaligned_be32( + &p[proc_table + (13 * act_proc_id)]); + act_proc_attribute = + (p[proc_table + (13 * act_proc_id) + 8] & 0x03); + + procptr = (struct altera_procinfo *) + kzalloc(sizeof(struct altera_procinfo), + GFP_KERNEL); + + if (procptr == NULL) + status = -ENOMEM; + else { + procptr->name = &p[str_table + act_proc_name]; + procptr->attrs = act_proc_attribute; + procptr->next = NULL; + + /* add record to end of linked list */ + if (*proc_list == NULL) + *proc_list = procptr; + else { + tmpptr = *proc_list; + while (tmpptr->next != NULL) + tmpptr = tmpptr->next; + tmpptr->next = procptr; + } + } + + act_proc_id = get_unaligned_be32( + &p[proc_table + (13 * act_proc_id) + 4]); + } while ((act_proc_id != 0) && (act_proc_id < proc_count)); + + return status; +} + +int altera_init(struct altera_config *config, const struct firmware *fw) +{ + struct altera_state *astate = NULL; + struct altera_procinfo *proc_list = NULL; + struct altera_procinfo *procptr = NULL; + char *key = NULL; + char *value = NULL; + char *action_name = NULL; + char *description = NULL; + int exec_result = 0; + int exit_code = 0; + int format_version = 0; + int action_count = 0; + int procedure_count = 0; + int index = 0; + s32 offset = 0L; + s32 error_address = 0L; + int retval = 0; + + key = kzalloc(33, GFP_KERNEL); + if (!key) { + retval = -ENOMEM; + goto out; + } + value = kzalloc(257, GFP_KERNEL); + if (!value) { + retval = -ENOMEM; + goto free_key; + } + astate = kzalloc(sizeof(struct altera_state), GFP_KERNEL); + if (!astate) { + retval = -ENOMEM; + goto free_value; + } + + astate->config = config; + if (!astate->config->jtag_io) { + dprintk(KERN_INFO "%s: using byteblaster!\n", __func__); + astate->config->jtag_io = netup_jtag_io_lpt; + } + + altera_check_crc((u8 *)fw->data, fw->size); + + if (debug) { + altera_get_file_info((u8 *)fw->data, fw->size, &format_version, + &action_count, &procedure_count); + printk(KERN_INFO "%s: File format is %s ByteCode format\n", + __func__, (format_version == 2) ? "Jam STAPL" : + "pre-standardized Jam 1.1"); + while (altera_get_note((u8 *)fw->data, fw->size, + &offset, key, value, 256) == 0) + printk(KERN_INFO "%s: NOTE \"%s\" = \"%s\"\n", + __func__, key, value); + } + + if (debug && (format_version == 2) && (action_count > 0)) { + printk(KERN_INFO "%s: Actions available:\n", __func__); + for (index = 0; index < action_count; ++index) { + altera_get_act_info((u8 *)fw->data, fw->size, + index, &action_name, + &description, + &proc_list); + + if (description == NULL) + printk(KERN_INFO "%s: %s\n", + __func__, + action_name); + else + printk(KERN_INFO "%s: %s \"%s\"\n", + __func__, + action_name, + description); + + procptr = proc_list; + while (procptr != NULL) { + if (procptr->attrs != 0) + printk(KERN_INFO "%s: %s (%s)\n", + __func__, + procptr->name, + (procptr->attrs == 1) ? + "optional" : "recommended"); + + proc_list = procptr->next; + kfree(procptr); + procptr = proc_list; + } + } + + printk(KERN_INFO "\n"); + } + + exec_result = altera_execute(astate, (u8 *)fw->data, fw->size, + &error_address, &exit_code, &format_version); + + if (exit_code) + exec_result = -EREMOTEIO; + + if ((format_version == 2) && (exec_result == -EINVAL)) { + if (astate->config->action == NULL) + printk(KERN_ERR "%s: error: no action specified for " + "Jam STAPL file.\nprogram terminated.\n", + __func__); + else + printk(KERN_ERR "%s: error: action \"%s\"" + " is not supported " + "for this Jam STAPL file.\n" + "Program terminated.\n", __func__, + astate->config->action); + + } else if (exec_result) + printk(KERN_ERR "%s: error %d\n", __func__, exec_result); + + kfree(astate); +free_value: + kfree(value); +free_key: + kfree(key); +out: + return retval; +} +EXPORT_SYMBOL(altera_init); diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 7209277..e9aa688 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -142,8 +142,6 @@ source "drivers/staging/ste_rmi4/Kconfig" source "drivers/staging/gma500/Kconfig" -source "drivers/staging/altera-stapl/Kconfig" - source "drivers/staging/mei/Kconfig" source "drivers/staging/nvec/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index d44d25e..a2e77cf 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -59,7 +59,6 @@ obj-$(CONFIG_BCM_WIMAX) += bcm/ obj-$(CONFIG_FT1000) += ft1000/ obj-$(CONFIG_SND_INTEL_SST) += intel_sst/ obj-$(CONFIG_SPEAKUP) += speakup/ -obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/ obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_TM1217) += cptm1217/ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += ste_rmi4/ obj-$(CONFIG_DRM_PSB) += gma500/ diff --git a/drivers/staging/altera-stapl/Kconfig b/drivers/staging/altera-stapl/Kconfig deleted file mode 100644 index b653732..0000000 --- a/drivers/staging/altera-stapl/Kconfig +++ /dev/null @@ -1,6 +0,0 @@ -config ALTERA_STAPL - tristate "Altera FPGA firmware download module" - depends on I2C - default n - help - An Altera FPGA module. Say Y when you want to support this tool. diff --git a/drivers/staging/altera-stapl/Makefile b/drivers/staging/altera-stapl/Makefile deleted file mode 100644 index ddeede3..0000000 --- a/drivers/staging/altera-stapl/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -altera-stapl-y := altera-lpt.o altera-jtag.o altera-comp.o altera.o - -obj-$(CONFIG_ALTERA_STAPL) += altera-stapl.o diff --git a/drivers/staging/altera-stapl/altera-comp.c b/drivers/staging/altera-stapl/altera-comp.c deleted file mode 100644 index 49b103b..0000000 --- a/drivers/staging/altera-stapl/altera-comp.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * altera-comp.c - * - * altera FPGA driver - * - * Copyright (C) Altera Corporation 1998-2001 - * Copyright (C) 2010 NetUP Inc. - * Copyright (C) 2010 Igor M. Liplianin - * - * 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 of the License, 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 -#include "altera-exprt.h" - -#define SHORT_BITS 16 -#define CHAR_BITS 8 -#define DATA_BLOB_LENGTH 3 -#define MATCH_DATA_LENGTH 8192 -#define ALTERA_REQUEST_SIZE 1024 -#define ALTERA_BUFFER_SIZE (MATCH_DATA_LENGTH + ALTERA_REQUEST_SIZE) - -static u32 altera_bits_req(u32 n) -{ - u32 result = SHORT_BITS; - - if (n == 0) - result = 1; - else { - /* Look for the highest non-zero bit position */ - while ((n & (1 << (SHORT_BITS - 1))) == 0) { - n <<= 1; - --result; - } - } - - return result; -} - -static u32 altera_read_packed(u8 *buffer, u32 bits, u32 *bits_avail, - u32 *in_index) -{ - u32 result = 0; - u32 shift = 0; - u32 databyte = 0; - - while (bits > 0) { - databyte = buffer[*in_index]; - result |= (((databyte >> (CHAR_BITS - *bits_avail)) - & (0xff >> (CHAR_BITS - *bits_avail))) << shift); - - if (bits <= *bits_avail) { - result &= (0xffff >> (SHORT_BITS - (bits + shift))); - *bits_avail -= bits; - bits = 0; - } else { - ++(*in_index); - shift += *bits_avail; - bits -= *bits_avail; - *bits_avail = CHAR_BITS; - } - } - - return result; -} - -u32 altera_shrink(u8 *in, u32 in_length, u8 *out, u32 out_length, s32 version) -{ - u32 i, j, data_length = 0L; - u32 offset, length; - u32 match_data_length = MATCH_DATA_LENGTH; - u32 bits_avail = CHAR_BITS; - u32 in_index = 0L; - - if (version > 0) - --match_data_length; - - for (i = 0; i < out_length; ++i) - out[i] = 0; - - /* Read number of bytes in data. */ - for (i = 0; i < sizeof(in_length); ++i) { - data_length = data_length | ( - altera_read_packed(in, - CHAR_BITS, - &bits_avail, - &in_index) << (i * CHAR_BITS)); - } - - if (data_length > out_length) { - data_length = 0L; - return data_length; - } - - i = 0; - while (i < data_length) { - /* A 0 bit indicates literal data. */ - if (altera_read_packed(in, 1, &bits_avail, - &in_index) == 0) { - for (j = 0; j < DATA_BLOB_LENGTH; ++j) { - if (i < data_length) { - out[i] = (u8)altera_read_packed(in, - CHAR_BITS, - &bits_avail, - &in_index); - i++; - } - } - } else { - /* A 1 bit indicates offset/length to follow. */ - offset = altera_read_packed(in, altera_bits_req((s16) - (i > match_data_length ? - match_data_length : i)), - &bits_avail, - &in_index); - length = altera_read_packed(in, CHAR_BITS, - &bits_avail, - &in_index); - for (j = 0; j < length; ++j) { - if (i < data_length) { - out[i] = out[i - offset]; - i++; - } - } - } - } - - return data_length; -} diff --git a/drivers/staging/altera-stapl/altera-exprt.h b/drivers/staging/altera-stapl/altera-exprt.h deleted file mode 100644 index 39c38d8..0000000 --- a/drivers/staging/altera-stapl/altera-exprt.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * altera-exprt.h - * - * altera FPGA driver - * - * Copyright (C) Altera Corporation 1998-2001 - * Copyright (C) 2010 NetUP Inc. - * Copyright (C) 2010 Igor M. Liplianin - * - * 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 of the License, 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. - */ - -#ifndef ALTERA_EXPRT_H -#define ALTERA_EXPRT_H - - -u32 altera_shrink(u8 *in, u32 in_length, u8 *out, u32 out_length, s32 version); -int netup_jtag_io_lpt(void *device, int tms, int tdi, int read_tdo); - -#endif /* ALTERA_EXPRT_H */ diff --git a/drivers/staging/altera-stapl/altera-jtag.c b/drivers/staging/altera-stapl/altera-jtag.c deleted file mode 100644 index 8b1620b..0000000 --- a/drivers/staging/altera-stapl/altera-jtag.c +++ /dev/null @@ -1,1021 +0,0 @@ -/* - * altera-jtag.c - * - * altera FPGA driver - * - * Copyright (C) Altera Corporation 1998-2001 - * Copyright (C) 2010 NetUP Inc. - * Copyright (C) 2010 Igor M. Liplianin - * - * 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 of the License, 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 -#include -#include -#include "altera.h" -#include "altera-exprt.h" -#include "altera-jtag.h" - -#define alt_jtag_io(a, b, c)\ - astate->config->jtag_io(astate->config->dev, a, b, c); - -#define alt_malloc(a) kzalloc(a, GFP_KERNEL); - -/* - * This structure shows, for each JTAG state, which state is reached after - * a single TCK clock cycle with TMS high or TMS low, respectively. This - * describes all possible state transitions in the JTAG state machine. - */ -struct altera_jtag_machine { - enum altera_jtag_state tms_high; - enum altera_jtag_state tms_low; -}; - -static const struct altera_jtag_machine altera_transitions[] = { - /* RESET */ { RESET, IDLE }, - /* IDLE */ { DRSELECT, IDLE }, - /* DRSELECT */ { IRSELECT, DRCAPTURE }, - /* DRCAPTURE */ { DREXIT1, DRSHIFT }, - /* DRSHIFT */ { DREXIT1, DRSHIFT }, - /* DREXIT1 */ { DRUPDATE, DRPAUSE }, - /* DRPAUSE */ { DREXIT2, DRPAUSE }, - /* DREXIT2 */ { DRUPDATE, DRSHIFT }, - /* DRUPDATE */ { DRSELECT, IDLE }, - /* IRSELECT */ { RESET, IRCAPTURE }, - /* IRCAPTURE */ { IREXIT1, IRSHIFT }, - /* IRSHIFT */ { IREXIT1, IRSHIFT }, - /* IREXIT1 */ { IRUPDATE, IRPAUSE }, - /* IRPAUSE */ { IREXIT2, IRPAUSE }, - /* IREXIT2 */ { IRUPDATE, IRSHIFT }, - /* IRUPDATE */ { DRSELECT, IDLE } -}; - -/* - * This table contains the TMS value to be used to take the NEXT STEP on - * the path to the desired state. The array index is the current state, - * and the bit position is the desired endstate. To find out which state - * is used as the intermediate state, look up the TMS value in the - * altera_transitions[] table. - */ -static const u16 altera_jtag_path_map[16] = { - /* RST RTI SDRS CDR SDR E1DR PDR E2DR */ - 0x0001, 0xFFFD, 0xFE01, 0xFFE7, 0xFFEF, 0xFF0F, 0xFFBF, 0xFFFF, - /* UDR SIRS CIR SIR E1IR PIR E2IR UIR */ - 0xFEFD, 0x0001, 0xF3FF, 0xF7FF, 0x87FF, 0xDFFF, 0xFFFF, 0x7FFD -}; - -/* Flag bits for alt_jtag_io() function */ -#define TMS_HIGH 1 -#define TMS_LOW 0 -#define TDI_HIGH 1 -#define TDI_LOW 0 -#define READ_TDO 1 -#define IGNORE_TDO 0 - -int altera_jinit(struct altera_state *astate) -{ - struct altera_jtag *js = &astate->js; - - /* initial JTAG state is unknown */ - js->jtag_state = ILLEGAL_JTAG_STATE; - - /* initialize to default state */ - js->drstop_state = IDLE; - js->irstop_state = IDLE; - js->dr_pre = 0; - js->dr_post = 0; - js->ir_pre = 0; - js->ir_post = 0; - js->dr_length = 0; - js->ir_length = 0; - - js->dr_pre_data = NULL; - js->dr_post_data = NULL; - js->ir_pre_data = NULL; - js->ir_post_data = NULL; - js->dr_buffer = NULL; - js->ir_buffer = NULL; - - return 0; -} - -int altera_set_drstop(struct altera_jtag *js, enum altera_jtag_state state) -{ - js->drstop_state = state; - - return 0; -} - -int altera_set_irstop(struct altera_jtag *js, enum altera_jtag_state state) -{ - js->irstop_state = state; - - return 0; -} - -int altera_set_dr_pre(struct altera_jtag *js, - u32 count, u32 start_index, - u8 *preamble_data) -{ - int status = 0; - u32 i; - u32 j; - - if (count > js->dr_pre) { - kfree(js->dr_pre_data); - js->dr_pre_data = (u8 *)alt_malloc((count + 7) >> 3); - if (js->dr_pre_data == NULL) - status = -ENOMEM; - else - js->dr_pre = count; - } else - js->dr_pre = count; - - if (status == 0) { - for (i = 0; i < count; ++i) { - j = i + start_index; - - if (preamble_data == NULL) - js->dr_pre_data[i >> 3] |= (1 << (i & 7)); - else { - if (preamble_data[j >> 3] & (1 << (j & 7))) - js->dr_pre_data[i >> 3] |= - (1 << (i & 7)); - else - js->dr_pre_data[i >> 3] &= - ~(u32)(1 << (i & 7)); - - } - } - } - - return status; -} - -int altera_set_ir_pre(struct altera_jtag *js, u32 count, u32 start_index, - u8 *preamble_data) -{ - int status = 0; - u32 i; - u32 j; - - if (count > js->ir_pre) { - kfree(js->ir_pre_data); - js->ir_pre_data = (u8 *)alt_malloc((count + 7) >> 3); - if (js->ir_pre_data == NULL) - status = -ENOMEM; - else - js->ir_pre = count; - - } else - js->ir_pre = count; - - if (status == 0) { - for (i = 0; i < count; ++i) { - j = i + start_index; - if (preamble_data == NULL) - js->ir_pre_data[i >> 3] |= (1 << (i & 7)); - else { - if (preamble_data[j >> 3] & (1 << (j & 7))) - js->ir_pre_data[i >> 3] |= - (1 << (i & 7)); - else - js->ir_pre_data[i >> 3] &= - ~(u32)(1 << (i & 7)); - - } - } - } - - return status; -} - -int altera_set_dr_post(struct altera_jtag *js, u32 count, u32 start_index, - u8 *postamble_data) -{ - int status = 0; - u32 i; - u32 j; - - if (count > js->dr_post) { - kfree(js->dr_post_data); - js->dr_post_data = (u8 *)alt_malloc((count + 7) >> 3); - - if (js->dr_post_data == NULL) - status = -ENOMEM; - else - js->dr_post = count; - - } else - js->dr_post = count; - - if (status == 0) { - for (i = 0; i < count; ++i) { - j = i + start_index; - - if (postamble_data == NULL) - js->dr_post_data[i >> 3] |= (1 << (i & 7)); - else { - if (postamble_data[j >> 3] & (1 << (j & 7))) - js->dr_post_data[i >> 3] |= - (1 << (i & 7)); - else - js->dr_post_data[i >> 3] &= - ~(u32)(1 << (i & 7)); - - } - } - } - - return status; -} - -int altera_set_ir_post(struct altera_jtag *js, u32 count, u32 start_index, - u8 *postamble_data) -{ - int status = 0; - u32 i; - u32 j; - - if (count > js->ir_post) { - kfree(js->ir_post_data); - js->ir_post_data = (u8 *)alt_malloc((count + 7) >> 3); - if (js->ir_post_data == NULL) - status = -ENOMEM; - else - js->ir_post = count; - - } else - js->ir_post = count; - - if (status != 0) - return status; - - for (i = 0; i < count; ++i) { - j = i + start_index; - - if (postamble_data == NULL) - js->ir_post_data[i >> 3] |= (1 << (i & 7)); - else { - if (postamble_data[j >> 3] & (1 << (j & 7))) - js->ir_post_data[i >> 3] |= (1 << (i & 7)); - else - js->ir_post_data[i >> 3] &= - ~(u32)(1 << (i & 7)); - - } - } - - return status; -} - -static void altera_jreset_idle(struct altera_state *astate) -{ - struct altera_jtag *js = &astate->js; - int i; - /* Go to Test Logic Reset (no matter what the starting state may be) */ - for (i = 0; i < 5; ++i) - alt_jtag_io(TMS_HIGH, TDI_LOW, IGNORE_TDO); - - /* Now step to Run Test / Idle */ - alt_jtag_io(TMS_LOW, TDI_LOW, IGNORE_TDO); - js->jtag_state = IDLE; -} - -int altera_goto_jstate(struct altera_state *astate, - enum altera_jtag_state state) -{ - struct altera_jtag *js = &astate->js; - int tms; - int count = 0; - int status = 0; - - if (js->jtag_state == ILLEGAL_JTAG_STATE) - /* initialize JTAG chain to known state */ - altera_jreset_idle(astate); - - if (js->jtag_state == state) { - /* - * We are already in the desired state. - * If it is a stable state, loop here. - * Otherwise do nothing (no clock cycles). - */ - if ((state == IDLE) || (state == DRSHIFT) || - (state == DRPAUSE) || (state == IRSHIFT) || - (state == IRPAUSE)) { - alt_jtag_io(TMS_LOW, TDI_LOW, IGNORE_TDO); - } else if (state == RESET) - alt_jtag_io(TMS_HIGH, TDI_LOW, IGNORE_TDO); - - } else { - while ((js->jtag_state != state) && (count < 9)) { - /* Get TMS value to take a step toward desired state */ - tms = (altera_jtag_path_map[js->jtag_state] & - (1 << state)) - ? TMS_HIGH : TMS_LOW; - - /* Take a step */ - alt_jtag_io(tms, TDI_LOW, IGNORE_TDO); - - if (tms) - js->jtag_state = - altera_transitions[js->jtag_state].tms_high; - else - js->jtag_state = - altera_transitions[js->jtag_state].tms_low; - - ++count; - } - } - - if (js->jtag_state != state) - status = -EREMOTEIO; - - return status; -} - -int altera_wait_cycles(struct altera_state *astate, - s32 cycles, - enum altera_jtag_state wait_state) -{ - struct altera_jtag *js = &astate->js; - int tms; - s32 count; - int status = 0; - - if (js->jtag_state != wait_state) - status = altera_goto_jstate(astate, wait_state); - - if (status == 0) { - /* - * Set TMS high to loop in RESET state - * Set TMS low to loop in any other stable state - */ - tms = (wait_state == RESET) ? TMS_HIGH : TMS_LOW; - - for (count = 0L; count < cycles; count++) - alt_jtag_io(tms, TDI_LOW, IGNORE_TDO); - - } - - return status; -} - -int altera_wait_msecs(struct altera_state *astate, - s32 microseconds, enum altera_jtag_state wait_state) -/* - * Causes JTAG hardware to sit in the specified stable - * state for the specified duration of real time. If - * no JTAG operations have been performed yet, then only - * a delay is performed. This permits the WAIT USECS - * statement to be used in VECTOR programs without causing - * any JTAG operations. - * Returns 0 for success, else appropriate error code. - */ -{ - struct altera_jtag *js = &astate->js; - int status = 0; - - if ((js->jtag_state != ILLEGAL_JTAG_STATE) && - (js->jtag_state != wait_state)) - status = altera_goto_jstate(astate, wait_state); - - if (status == 0) - /* Wait for specified time interval */ - udelay(microseconds); - - return status; -} - -static void altera_concatenate_data(u8 *buffer, - u8 *preamble_data, - u32 preamble_count, - u8 *target_data, - u32 start_index, - u32 target_count, - u8 *postamble_data, - u32 postamble_count) -/* - * Copies preamble data, target data, and postamble data - * into one buffer for IR or DR scans. - */ -{ - u32 i, j, k; - - for (i = 0L; i < preamble_count; ++i) { - if (preamble_data[i >> 3L] & (1L << (i & 7L))) - buffer[i >> 3L] |= (1L << (i & 7L)); - else - buffer[i >> 3L] &= ~(u32)(1L << (i & 7L)); - - } - - j = start_index; - k = preamble_count + target_count; - for (; i < k; ++i, ++j) { - if (target_data[j >> 3L] & (1L << (j & 7L))) - buffer[i >> 3L] |= (1L << (i & 7L)); - else - buffer[i >> 3L] &= ~(u32)(1L << (i & 7L)); - - } - - j = 0L; - k = preamble_count + target_count + postamble_count; - for (; i < k; ++i, ++j) { - if (postamble_data[j >> 3L] & (1L << (j & 7L))) - buffer[i >> 3L] |= (1L << (i & 7L)); - else - buffer[i >> 3L] &= ~(u32)(1L << (i & 7L)); - - } -} - -static int alt_jtag_drscan(struct altera_state *astate, - int start_state, - int count, - u8 *tdi, - u8 *tdo) -{ - int i = 0; - int tdo_bit = 0; - int status = 1; - - /* First go to DRSHIFT state */ - switch (start_state) { - case 0: /* IDLE */ - alt_jtag_io(1, 0, 0); /* DRSELECT */ - alt_jtag_io(0, 0, 0); /* DRCAPTURE */ - alt_jtag_io(0, 0, 0); /* DRSHIFT */ - break; - - case 1: /* DRPAUSE */ - alt_jtag_io(1, 0, 0); /* DREXIT2 */ - alt_jtag_io(1, 0, 0); /* DRUPDATE */ - alt_jtag_io(1, 0, 0); /* DRSELECT */ - alt_jtag_io(0, 0, 0); /* DRCAPTURE */ - alt_jtag_io(0, 0, 0); /* DRSHIFT */ - break; - - case 2: /* IRPAUSE */ - alt_jtag_io(1, 0, 0); /* IREXIT2 */ - alt_jtag_io(1, 0, 0); /* IRUPDATE */ - alt_jtag_io(1, 0, 0); /* DRSELECT */ - alt_jtag_io(0, 0, 0); /* DRCAPTURE */ - alt_jtag_io(0, 0, 0); /* DRSHIFT */ - break; - - default: - status = 0; - } - - if (status) { - /* loop in the SHIFT-DR state */ - for (i = 0; i < count; i++) { - tdo_bit = alt_jtag_io( - (i == count - 1), - tdi[i >> 3] & (1 << (i & 7)), - (tdo != NULL)); - - if (tdo != NULL) { - if (tdo_bit) - tdo[i >> 3] |= (1 << (i & 7)); - else - tdo[i >> 3] &= ~(u32)(1 << (i & 7)); - - } - } - - alt_jtag_io(0, 0, 0); /* DRPAUSE */ - } - - return status; -} - -static int alt_jtag_irscan(struct altera_state *astate, - int start_state, - int count, - u8 *tdi, - u8 *tdo) -{ - int i = 0; - int tdo_bit = 0; - int status = 1; - - /* First go to IRSHIFT state */ - switch (start_state) { - case 0: /* IDLE */ - alt_jtag_io(1, 0, 0); /* DRSELECT */ - alt_jtag_io(1, 0, 0); /* IRSELECT */ - alt_jtag_io(0, 0, 0); /* IRCAPTURE */ - alt_jtag_io(0, 0, 0); /* IRSHIFT */ - break; - - case 1: /* DRPAUSE */ - alt_jtag_io(1, 0, 0); /* DREXIT2 */ - alt_jtag_io(1, 0, 0); /* DRUPDATE */ - alt_jtag_io(1, 0, 0); /* DRSELECT */ - alt_jtag_io(1, 0, 0); /* IRSELECT */ - alt_jtag_io(0, 0, 0); /* IRCAPTURE */ - alt_jtag_io(0, 0, 0); /* IRSHIFT */ - break; - - case 2: /* IRPAUSE */ - alt_jtag_io(1, 0, 0); /* IREXIT2 */ - alt_jtag_io(1, 0, 0); /* IRUPDATE */ - alt_jtag_io(1, 0, 0); /* DRSELECT */ - alt_jtag_io(1, 0, 0); /* IRSELECT */ - alt_jtag_io(0, 0, 0); /* IRCAPTURE */ - alt_jtag_io(0, 0, 0); /* IRSHIFT */ - break; - - default: - status = 0; - } - - if (status) { - /* loop in the SHIFT-IR state */ - for (i = 0; i < count; i++) { - tdo_bit = alt_jtag_io( - (i == count - 1), - tdi[i >> 3] & (1 << (i & 7)), - (tdo != NULL)); - if (tdo != NULL) { - if (tdo_bit) - tdo[i >> 3] |= (1 << (i & 7)); - else - tdo[i >> 3] &= ~(u32)(1 << (i & 7)); - - } - } - - alt_jtag_io(0, 0, 0); /* IRPAUSE */ - } - - return status; -} - -static void altera_extract_target_data(u8 *buffer, - u8 *target_data, - u32 start_index, - u32 preamble_count, - u32 target_count) -/* - * Copies target data from scan buffer, filtering out - * preamble and postamble data. - */ -{ - u32 i; - u32 j; - u32 k; - - j = preamble_count; - k = start_index + target_count; - for (i = start_index; i < k; ++i, ++j) { - if (buffer[j >> 3] & (1 << (j & 7))) - target_data[i >> 3] |= (1 << (i & 7)); - else - target_data[i >> 3] &= ~(u32)(1 << (i & 7)); - - } -} - -int altera_irscan(struct altera_state *astate, - u32 count, - u8 *tdi_data, - u32 start_index) -/* Shifts data into instruction register */ -{ - struct altera_jtag *js = &astate->js; - int start_code = 0; - u32 alloc_chars = 0; - u32 shift_count = js->ir_pre + count + js->ir_post; - int status = 0; - enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE; - - switch (js->jtag_state) { - case ILLEGAL_JTAG_STATE: - case RESET: - case IDLE: - start_code = 0; - start_state = IDLE; - break; - - case DRSELECT: - case DRCAPTURE: - case DRSHIFT: - case DREXIT1: - case DRPAUSE: - case DREXIT2: - case DRUPDATE: - start_code = 1; - start_state = DRPAUSE; - break; - - case IRSELECT: - case IRCAPTURE: - case IRSHIFT: - case IREXIT1: - case IRPAUSE: - case IREXIT2: - case IRUPDATE: - start_code = 2; - start_state = IRPAUSE; - break; - - default: - status = -EREMOTEIO; - break; - } - - if (status == 0) - if (js->jtag_state != start_state) - status = altera_goto_jstate(astate, start_state); - - if (status == 0) { - if (shift_count > js->ir_length) { - alloc_chars = (shift_count + 7) >> 3; - kfree(js->ir_buffer); - js->ir_buffer = (u8 *)alt_malloc(alloc_chars); - if (js->ir_buffer == NULL) - status = -ENOMEM; - else - js->ir_length = alloc_chars * 8; - - } - } - - if (status == 0) { - /* - * Copy preamble data, IR data, - * and postamble data into a buffer - */ - altera_concatenate_data(js->ir_buffer, - js->ir_pre_data, - js->ir_pre, - tdi_data, - start_index, - count, - js->ir_post_data, - js->ir_post); - /* Do the IRSCAN */ - alt_jtag_irscan(astate, - start_code, - shift_count, - js->ir_buffer, - NULL); - - /* alt_jtag_irscan() always ends in IRPAUSE state */ - js->jtag_state = IRPAUSE; - } - - if (status == 0) - if (js->irstop_state != IRPAUSE) - status = altera_goto_jstate(astate, js->irstop_state); - - - return status; -} - -int altera_swap_ir(struct altera_state *astate, - u32 count, - u8 *in_data, - u32 in_index, - u8 *out_data, - u32 out_index) -/* Shifts data into instruction register, capturing output data */ -{ - struct altera_jtag *js = &astate->js; - int start_code = 0; - u32 alloc_chars = 0; - u32 shift_count = js->ir_pre + count + js->ir_post; - int status = 0; - enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE; - - switch (js->jtag_state) { - case ILLEGAL_JTAG_STATE: - case RESET: - case IDLE: - start_code = 0; - start_state = IDLE; - break; - - case DRSELECT: - case DRCAPTURE: - case DRSHIFT: - case DREXIT1: - case DRPAUSE: - case DREXIT2: - case DRUPDATE: - start_code = 1; - start_state = DRPAUSE; - break; - - case IRSELECT: - case IRCAPTURE: - case IRSHIFT: - case IREXIT1: - case IRPAUSE: - case IREXIT2: - case IRUPDATE: - start_code = 2; - start_state = IRPAUSE; - break; - - default: - status = -EREMOTEIO; - break; - } - - if (status == 0) - if (js->jtag_state != start_state) - status = altera_goto_jstate(astate, start_state); - - if (status == 0) { - if (shift_count > js->ir_length) { - alloc_chars = (shift_count + 7) >> 3; - kfree(js->ir_buffer); - js->ir_buffer = (u8 *)alt_malloc(alloc_chars); - if (js->ir_buffer == NULL) - status = -ENOMEM; - else - js->ir_length = alloc_chars * 8; - - } - } - - if (status == 0) { - /* - * Copy preamble data, IR data, - * and postamble data into a buffer - */ - altera_concatenate_data(js->ir_buffer, - js->ir_pre_data, - js->ir_pre, - in_data, - in_index, - count, - js->ir_post_data, - js->ir_post); - - /* Do the IRSCAN */ - alt_jtag_irscan(astate, - start_code, - shift_count, - js->ir_buffer, - js->ir_buffer); - - /* alt_jtag_irscan() always ends in IRPAUSE state */ - js->jtag_state = IRPAUSE; - } - - if (status == 0) - if (js->irstop_state != IRPAUSE) - status = altera_goto_jstate(astate, js->irstop_state); - - - if (status == 0) - /* Now extract the returned data from the buffer */ - altera_extract_target_data(js->ir_buffer, - out_data, out_index, - js->ir_pre, count); - - return status; -} - -int altera_drscan(struct altera_state *astate, - u32 count, - u8 *tdi_data, - u32 start_index) -/* Shifts data into data register (ignoring output data) */ -{ - struct altera_jtag *js = &astate->js; - int start_code = 0; - u32 alloc_chars = 0; - u32 shift_count = js->dr_pre + count + js->dr_post; - int status = 0; - enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE; - - switch (js->jtag_state) { - case ILLEGAL_JTAG_STATE: - case RESET: - case IDLE: - start_code = 0; - start_state = IDLE; - break; - - case DRSELECT: - case DRCAPTURE: - case DRSHIFT: - case DREXIT1: - case DRPAUSE: - case DREXIT2: - case DRUPDATE: - start_code = 1; - start_state = DRPAUSE; - break; - - case IRSELECT: - case IRCAPTURE: - case IRSHIFT: - case IREXIT1: - case IRPAUSE: - case IREXIT2: - case IRUPDATE: - start_code = 2; - start_state = IRPAUSE; - break; - - default: - status = -EREMOTEIO; - break; - } - - if (status == 0) - if (js->jtag_state != start_state) - status = altera_goto_jstate(astate, start_state); - - if (status == 0) { - if (shift_count > js->dr_length) { - alloc_chars = (shift_count + 7) >> 3; - kfree(js->dr_buffer); - js->dr_buffer = (u8 *)alt_malloc(alloc_chars); - if (js->dr_buffer == NULL) - status = -ENOMEM; - else - js->dr_length = alloc_chars * 8; - - } - } - - if (status == 0) { - /* - * Copy preamble data, DR data, - * and postamble data into a buffer - */ - altera_concatenate_data(js->dr_buffer, - js->dr_pre_data, - js->dr_pre, - tdi_data, - start_index, - count, - js->dr_post_data, - js->dr_post); - /* Do the DRSCAN */ - alt_jtag_drscan(astate, start_code, shift_count, - js->dr_buffer, NULL); - /* alt_jtag_drscan() always ends in DRPAUSE state */ - js->jtag_state = DRPAUSE; - } - - if (status == 0) - if (js->drstop_state != DRPAUSE) - status = altera_goto_jstate(astate, js->drstop_state); - - return status; -} - -int altera_swap_dr(struct altera_state *astate, u32 count, - u8 *in_data, u32 in_index, - u8 *out_data, u32 out_index) -/* Shifts data into data register, capturing output data */ -{ - struct altera_jtag *js = &astate->js; - int start_code = 0; - u32 alloc_chars = 0; - u32 shift_count = js->dr_pre + count + js->dr_post; - int status = 0; - enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE; - - switch (js->jtag_state) { - case ILLEGAL_JTAG_STATE: - case RESET: - case IDLE: - start_code = 0; - start_state = IDLE; - break; - - case DRSELECT: - case DRCAPTURE: - case DRSHIFT: - case DREXIT1: - case DRPAUSE: - case DREXIT2: - case DRUPDATE: - start_code = 1; - start_state = DRPAUSE; - break; - - case IRSELECT: - case IRCAPTURE: - case IRSHIFT: - case IREXIT1: - case IRPAUSE: - case IREXIT2: - case IRUPDATE: - start_code = 2; - start_state = IRPAUSE; - break; - - default: - status = -EREMOTEIO; - break; - } - - if (status == 0) - if (js->jtag_state != start_state) - status = altera_goto_jstate(astate, start_state); - - if (status == 0) { - if (shift_count > js->dr_length) { - alloc_chars = (shift_count + 7) >> 3; - kfree(js->dr_buffer); - js->dr_buffer = (u8 *)alt_malloc(alloc_chars); - - if (js->dr_buffer == NULL) - status = -ENOMEM; - else - js->dr_length = alloc_chars * 8; - - } - } - - if (status == 0) { - /* - * Copy preamble data, DR data, - * and postamble data into a buffer - */ - altera_concatenate_data(js->dr_buffer, - js->dr_pre_data, - js->dr_pre, - in_data, - in_index, - count, - js->dr_post_data, - js->dr_post); - - /* Do the DRSCAN */ - alt_jtag_drscan(astate, - start_code, - shift_count, - js->dr_buffer, - js->dr_buffer); - - /* alt_jtag_drscan() always ends in DRPAUSE state */ - js->jtag_state = DRPAUSE; - } - - if (status == 0) - if (js->drstop_state != DRPAUSE) - status = altera_goto_jstate(astate, js->drstop_state); - - if (status == 0) - /* Now extract the returned data from the buffer */ - altera_extract_target_data(js->dr_buffer, - out_data, - out_index, - js->dr_pre, - count); - - return status; -} - -void altera_free_buffers(struct altera_state *astate) -{ - struct altera_jtag *js = &astate->js; - /* If the JTAG interface was used, reset it to TLR */ - if (js->jtag_state != ILLEGAL_JTAG_STATE) - altera_jreset_idle(astate); - - kfree(js->dr_pre_data); - js->dr_pre_data = NULL; - - kfree(js->dr_post_data); - js->dr_post_data = NULL; - - kfree(js->dr_buffer); - js->dr_buffer = NULL; - - kfree(js->ir_pre_data); - js->ir_pre_data = NULL; - - kfree(js->ir_post_data); - js->ir_post_data = NULL; - - kfree(js->ir_buffer); - js->ir_buffer = NULL; -} diff --git a/drivers/staging/altera-stapl/altera-jtag.h b/drivers/staging/altera-stapl/altera-jtag.h deleted file mode 100644 index 2f97e36..0000000 --- a/drivers/staging/altera-stapl/altera-jtag.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * altera-jtag.h - * - * altera FPGA driver - * - * Copyright (C) Altera Corporation 1998-2001 - * Copyright (C) 2010 NetUP Inc. - * Copyright (C) 2010 Igor M. Liplianin - * - * 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 of the License, 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. - */ - -#ifndef ALTERA_JTAG_H -#define ALTERA_JTAG_H - -/* Function Prototypes */ -enum altera_jtag_state { - ILLEGAL_JTAG_STATE = -1, - RESET = 0, - IDLE = 1, - DRSELECT = 2, - DRCAPTURE = 3, - DRSHIFT = 4, - DREXIT1 = 5, - DRPAUSE = 6, - DREXIT2 = 7, - DRUPDATE = 8, - IRSELECT = 9, - IRCAPTURE = 10, - IRSHIFT = 11, - IREXIT1 = 12, - IRPAUSE = 13, - IREXIT2 = 14, - IRUPDATE = 15 - -}; - -struct altera_jtag { - /* Global variable to store the current JTAG state */ - enum altera_jtag_state jtag_state; - - /* Store current stop-state for DR and IR scan commands */ - enum altera_jtag_state drstop_state; - enum altera_jtag_state irstop_state; - - /* Store current padding values */ - u32 dr_pre; - u32 dr_post; - u32 ir_pre; - u32 ir_post; - u32 dr_length; - u32 ir_length; - u8 *dr_pre_data; - u8 *dr_post_data; - u8 *ir_pre_data; - u8 *ir_post_data; - u8 *dr_buffer; - u8 *ir_buffer; -}; - -#define ALTERA_STACK_SIZE 128 -#define ALTERA_MESSAGE_LENGTH 1024 - -struct altera_state { - struct altera_config *config; - struct altera_jtag js; - char msg_buff[ALTERA_MESSAGE_LENGTH + 1]; - long stack[ALTERA_STACK_SIZE]; -}; - -int altera_jinit(struct altera_state *astate); -int altera_set_drstop(struct altera_jtag *js, enum altera_jtag_state state); -int altera_set_irstop(struct altera_jtag *js, enum altera_jtag_state state); -int altera_set_dr_pre(struct altera_jtag *js, u32 count, u32 start_index, - u8 *preamble_data); -int altera_set_ir_pre(struct altera_jtag *js, u32 count, u32 start_index, - u8 *preamble_data); -int altera_set_dr_post(struct altera_jtag *js, u32 count, u32 start_index, - u8 *postamble_data); -int altera_set_ir_post(struct altera_jtag *js, u32 count, u32 start_index, - u8 *postamble_data); -int altera_goto_jstate(struct altera_state *astate, - enum altera_jtag_state state); -int altera_wait_cycles(struct altera_state *astate, s32 cycles, - enum altera_jtag_state wait_state); -int altera_wait_msecs(struct altera_state *astate, s32 microseconds, - enum altera_jtag_state wait_state); -int altera_irscan(struct altera_state *astate, u32 count, - u8 *tdi_data, u32 start_index); -int altera_swap_ir(struct altera_state *astate, - u32 count, u8 *in_data, - u32 in_index, u8 *out_data, - u32 out_index); -int altera_drscan(struct altera_state *astate, u32 count, - u8 *tdi_data, u32 start_index); -int altera_swap_dr(struct altera_state *astate, u32 count, - u8 *in_data, u32 in_index, - u8 *out_data, u32 out_index); -void altera_free_buffers(struct altera_state *astate); -#endif /* ALTERA_JTAG_H */ diff --git a/drivers/staging/altera-stapl/altera-lpt.c b/drivers/staging/altera-stapl/altera-lpt.c deleted file mode 100644 index 91456a0..0000000 --- a/drivers/staging/altera-stapl/altera-lpt.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * altera-lpt.c - * - * altera FPGA driver - * - * Copyright (C) Altera Corporation 1998-2001 - * Copyright (C) 2010 NetUP Inc. - * Copyright (C) 2010 Abylay Ospan - * - * 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 of the License, 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 -#include -#include "altera-exprt.h" - -static int lpt_hardware_initialized; - -static void byteblaster_write(int port, int data) -{ - outb((u8)data, (u16)(port + 0x378)); -}; - -static int byteblaster_read(int port) -{ - int data = 0; - data = inb((u16)(port + 0x378)); - return data & 0xff; -}; - -int netup_jtag_io_lpt(void *device, int tms, int tdi, int read_tdo) -{ - int data = 0; - int tdo = 0; - int initial_lpt_ctrl = 0; - - if (!lpt_hardware_initialized) { - initial_lpt_ctrl = byteblaster_read(2); - byteblaster_write(2, (initial_lpt_ctrl | 0x02) & 0xdf); - lpt_hardware_initialized = 1; - } - - data = ((tdi ? 0x40 : 0) | (tms ? 0x02 : 0)); - - byteblaster_write(0, data); - - if (read_tdo) { - tdo = byteblaster_read(1); - tdo = ((tdo & 0x80) ? 0 : 1); - } - - byteblaster_write(0, data | 0x01); - - byteblaster_write(0, data); - - return tdo; -} diff --git a/drivers/staging/altera-stapl/altera.c b/drivers/staging/altera-stapl/altera.c deleted file mode 100644 index 8d73a86..0000000 --- a/drivers/staging/altera-stapl/altera.c +++ /dev/null @@ -1,2536 +0,0 @@ -/* - * altera.c - * - * altera FPGA driver - * - * Copyright (C) Altera Corporation 1998-2001 - * Copyright (C) 2010,2011 NetUP Inc. - * Copyright (C) 2010,2011 Igor M. Liplianin - * - * 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 of the License, 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 -#include -#include -#include -#include -#include "altera.h" -#include "altera-exprt.h" -#include "altera-jtag.h" - -static int debug = 1; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable debugging information"); - -MODULE_DESCRIPTION("altera FPGA kernel module"); -MODULE_AUTHOR("Igor M. Liplianin "); -MODULE_LICENSE("GPL"); - -#define dprintk(args...) \ - if (debug) { \ - printk(KERN_DEBUG args); \ - } - -enum altera_fpga_opcode { - OP_NOP = 0, - OP_DUP, - OP_SWP, - OP_ADD, - OP_SUB, - OP_MULT, - OP_DIV, - OP_MOD, - OP_SHL, - OP_SHR, - OP_NOT, - OP_AND, - OP_OR, - OP_XOR, - OP_INV, - OP_GT, - OP_LT, - OP_RET, - OP_CMPS, - OP_PINT, - OP_PRNT, - OP_DSS, - OP_DSSC, - OP_ISS, - OP_ISSC, - OP_DPR = 0x1c, - OP_DPRL, - OP_DPO, - OP_DPOL, - OP_IPR, - OP_IPRL, - OP_IPO, - OP_IPOL, - OP_PCHR, - OP_EXIT, - OP_EQU, - OP_POPT, - OP_ABS = 0x2c, - OP_BCH0, - OP_PSH0 = 0x2f, - OP_PSHL = 0x40, - OP_PSHV, - OP_JMP, - OP_CALL, - OP_NEXT, - OP_PSTR, - OP_SINT = 0x47, - OP_ST, - OP_ISTP, - OP_DSTP, - OP_SWPN, - OP_DUPN, - OP_POPV, - OP_POPE, - OP_POPA, - OP_JMPZ, - OP_DS, - OP_IS, - OP_DPRA, - OP_DPOA, - OP_IPRA, - OP_IPOA, - OP_EXPT, - OP_PSHE, - OP_PSHA, - OP_DYNA, - OP_EXPV = 0x5c, - OP_COPY = 0x80, - OP_REVA, - OP_DSC, - OP_ISC, - OP_WAIT, - OP_VS, - OP_CMPA = 0xc0, - OP_VSC, -}; - -struct altera_procinfo { - char *name; - u8 attrs; - struct altera_procinfo *next; -}; - -/* This function checks if enough parameters are available on the stack. */ -static int altera_check_stack(int stack_ptr, int count, int *status) -{ - if (stack_ptr < count) { - *status = -EOVERFLOW; - return 0; - } - - return 1; -} - -static void altera_export_int(char *key, s32 value) -{ - dprintk("Export: key = \"%s\", value = %d\n", key, value); -} - -#define HEX_LINE_CHARS 72 -#define HEX_LINE_BITS (HEX_LINE_CHARS * 4) - -static void altera_export_bool_array(char *key, u8 *data, s32 count) -{ - char string[HEX_LINE_CHARS + 1]; - s32 i, offset; - u32 size, line, lines, linebits, value, j, k; - - if (count > HEX_LINE_BITS) { - dprintk("Export: key = \"%s\", %d bits, value = HEX\n", - key, count); - lines = (count + (HEX_LINE_BITS - 1)) / HEX_LINE_BITS; - - for (line = 0; line < lines; ++line) { - if (line < (lines - 1)) { - linebits = HEX_LINE_BITS; - size = HEX_LINE_CHARS; - offset = count - ((line + 1) * HEX_LINE_BITS); - } else { - linebits = - count - ((lines - 1) * HEX_LINE_BITS); - size = (linebits + 3) / 4; - offset = 0L; - } - - string[size] = '\0'; - j = size - 1; - value = 0; - - for (k = 0; k < linebits; ++k) { - i = k + offset; - if (data[i >> 3] & (1 << (i & 7))) - value |= (1 << (i & 3)); - if ((i & 3) == 3) { - sprintf(&string[j], "%1x", value); - value = 0; - --j; - } - } - if ((k & 3) > 0) - sprintf(&string[j], "%1x", value); - - dprintk("%s\n", string); - } - - } else { - size = (count + 3) / 4; - string[size] = '\0'; - j = size - 1; - value = 0; - - for (i = 0; i < count; ++i) { - if (data[i >> 3] & (1 << (i & 7))) - value |= (1 << (i & 3)); - if ((i & 3) == 3) { - sprintf(&string[j], "%1x", value); - value = 0; - --j; - } - } - if ((i & 3) > 0) - sprintf(&string[j], "%1x", value); - - dprintk("Export: key = \"%s\", %d bits, value = HEX %s\n", - key, count, string); - } -} - -static int altera_execute(struct altera_state *astate, - u8 *p, - s32 program_size, - s32 *error_address, - int *exit_code, - int *format_version) -{ - struct altera_config *aconf = astate->config; - char *msg_buff = astate->msg_buff; - long *stack = astate->stack; - int status = 0; - u32 first_word = 0L; - u32 action_table = 0L; - u32 proc_table = 0L; - u32 str_table = 0L; - u32 sym_table = 0L; - u32 data_sect = 0L; - u32 code_sect = 0L; - u32 debug_sect = 0L; - u32 action_count = 0L; - u32 proc_count = 0L; - u32 sym_count = 0L; - long *vars = NULL; - s32 *var_size = NULL; - char *attrs = NULL; - u8 *proc_attributes = NULL; - u32 pc; - u32 opcode_address; - u32 args[3]; - u32 opcode; - u32 name_id; - u8 charbuf[4]; - long long_tmp; - u32 variable_id; - u8 *charptr_tmp; - u8 *charptr_tmp2; - long *longptr_tmp; - int version = 0; - int delta = 0; - int stack_ptr = 0; - u32 arg_count; - int done = 0; - int bad_opcode = 0; - u32 count; - u32 index; - u32 index2; - s32 long_count; - s32 long_idx; - s32 long_idx2; - u32 i; - u32 j; - u32 uncomp_size; - u32 offset; - u32 value; - int current_proc = 0; - int reverse; - - char *name; - - dprintk("%s\n", __func__); - - /* Read header information */ - if (program_size > 52L) { - first_word = get_unaligned_be32(&p[0]); - version = (first_word & 1L); - *format_version = version + 1; - delta = version * 8; - - action_table = get_unaligned_be32(&p[4]); - proc_table = get_unaligned_be32(&p[8]); - str_table = get_unaligned_be32(&p[4 + delta]); - sym_table = get_unaligned_be32(&p[16 + delta]); - data_sect = get_unaligned_be32(&p[20 + delta]); - code_sect = get_unaligned_be32(&p[24 + delta]); - debug_sect = get_unaligned_be32(&p[28 + delta]); - action_count = get_unaligned_be32(&p[40 + delta]); - proc_count = get_unaligned_be32(&p[44 + delta]); - sym_count = get_unaligned_be32(&p[48 + (2 * delta)]); - } - - if ((first_word != 0x4A414D00L) && (first_word != 0x4A414D01L)) { - done = 1; - status = -EIO; - goto exit_done; - } - - if (sym_count <= 0) - goto exit_done; - - vars = kzalloc(sym_count * sizeof(long), GFP_KERNEL); - - if (vars == NULL) - status = -ENOMEM; - - if (status == 0) { - var_size = kzalloc(sym_count * sizeof(s32), GFP_KERNEL); - - if (var_size == NULL) - status = -ENOMEM; - } - - if (status == 0) { - attrs = kzalloc(sym_count, GFP_KERNEL); - - if (attrs == NULL) - status = -ENOMEM; - } - - if ((status == 0) && (version > 0)) { - proc_attributes = kzalloc(proc_count, GFP_KERNEL); - - if (proc_attributes == NULL) - status = -ENOMEM; - } - - if (status != 0) - goto exit_done; - - delta = version * 2; - - for (i = 0; i < sym_count; ++i) { - offset = (sym_table + ((11 + delta) * i)); - - value = get_unaligned_be32(&p[offset + 3 + delta]); - - attrs[i] = p[offset]; - - /* - * use bit 7 of attribute byte to indicate that - * this buffer was dynamically allocated - * and should be freed later - */ - attrs[i] &= 0x7f; - - var_size[i] = get_unaligned_be32(&p[offset + 7 + delta]); - - /* - * Attribute bits: - * bit 0: 0 = read-only, 1 = read-write - * bit 1: 0 = not compressed, 1 = compressed - * bit 2: 0 = not initialized, 1 = initialized - * bit 3: 0 = scalar, 1 = array - * bit 4: 0 = Boolean, 1 = integer - * bit 5: 0 = declared variable, - * 1 = compiler created temporary variable - */ - - if ((attrs[i] & 0x0c) == 0x04) - /* initialized scalar variable */ - vars[i] = value; - else if ((attrs[i] & 0x1e) == 0x0e) { - /* initialized compressed Boolean array */ - uncomp_size = get_unaligned_le32(&p[data_sect + value]); - - /* allocate a buffer for the uncompressed data */ - vars[i] = (long)kzalloc(uncomp_size, GFP_KERNEL); - if (vars[i] == 0L) - status = -ENOMEM; - else { - /* set flag so buffer will be freed later */ - attrs[i] |= 0x80; - - /* uncompress the data */ - if (altera_shrink(&p[data_sect + value], - var_size[i], - (u8 *)vars[i], - uncomp_size, - version) != uncomp_size) - /* decompression failed */ - status = -EIO; - else - var_size[i] = uncomp_size * 8L; - - } - } else if ((attrs[i] & 0x1e) == 0x0c) { - /* initialized Boolean array */ - vars[i] = value + data_sect + (long)p; - } else if ((attrs[i] & 0x1c) == 0x1c) { - /* initialized integer array */ - vars[i] = value + data_sect; - } else if ((attrs[i] & 0x0c) == 0x08) { - /* uninitialized array */ - - /* flag attrs so that memory is freed */ - attrs[i] |= 0x80; - - if (var_size[i] > 0) { - u32 size; - - if (attrs[i] & 0x10) - /* integer array */ - size = (var_size[i] * sizeof(s32)); - else - /* Boolean array */ - size = ((var_size[i] + 7L) / 8L); - - vars[i] = (long)kzalloc(size, GFP_KERNEL); - - if (vars[i] == 0) { - status = -ENOMEM; - } else { - /* zero out memory */ - for (j = 0; j < size; ++j) - ((u8 *)(vars[i]))[j] = 0; - - } - } else - vars[i] = 0; - - } else - vars[i] = 0; - - } - -exit_done: - if (status != 0) - done = 1; - - altera_jinit(astate); - - pc = code_sect; - msg_buff[0] = '\0'; - - /* - * For JBC version 2, we will execute the procedures corresponding to - * the selected ACTION - */ - if (version > 0) { - if (aconf->action == NULL) { - status = -EINVAL; - done = 1; - } else { - int action_found = 0; - for (i = 0; (i < action_count) && !action_found; ++i) { - name_id = get_unaligned_be32(&p[action_table + - (12 * i)]); - - name = &p[str_table + name_id]; - - if (strnicmp(aconf->action, name, strlen(name)) == 0) { - action_found = 1; - current_proc = - get_unaligned_be32(&p[action_table + - (12 * i) + 8]); - } - } - - if (!action_found) { - status = -EINVAL; - done = 1; - } - } - - if (status == 0) { - int first_time = 1; - i = current_proc; - while ((i != 0) || first_time) { - first_time = 0; - /* check procedure attribute byte */ - proc_attributes[i] = - (p[proc_table + - (13 * i) + 8] & - 0x03); - - /* - * BIT0 - OPTIONAL - * BIT1 - RECOMMENDED - * BIT6 - FORCED OFF - * BIT7 - FORCED ON - */ - - i = get_unaligned_be32(&p[proc_table + - (13 * i) + 4]); - } - - /* - * Set current_proc to the first procedure - * to be executed - */ - i = current_proc; - while ((i != 0) && - ((proc_attributes[i] == 1) || - ((proc_attributes[i] & 0xc0) == 0x40))) { - i = get_unaligned_be32(&p[proc_table + - (13 * i) + 4]); - } - - if ((i != 0) || ((i == 0) && (current_proc == 0) && - ((proc_attributes[0] != 1) && - ((proc_attributes[0] & 0xc0) != 0x40)))) { - current_proc = i; - pc = code_sect + - get_unaligned_be32(&p[proc_table + - (13 * i) + 9]); - if ((pc < code_sect) || (pc >= debug_sect)) - status = -ERANGE; - } else - /* there are no procedures to execute! */ - done = 1; - - } - } - - msg_buff[0] = '\0'; - - while (!done) { - opcode = (p[pc] & 0xff); - opcode_address = pc; - ++pc; - - if (debug > 1) - printk("opcode: %02x\n", opcode); - - arg_count = (opcode >> 6) & 3; - for (i = 0; i < arg_count; ++i) { - args[i] = get_unaligned_be32(&p[pc]); - pc += 4; - } - - switch (opcode) { - case OP_NOP: - break; - case OP_DUP: - if (altera_check_stack(stack_ptr, 1, &status)) { - stack[stack_ptr] = stack[stack_ptr - 1]; - ++stack_ptr; - } - break; - case OP_SWP: - if (altera_check_stack(stack_ptr, 2, &status)) { - long_tmp = stack[stack_ptr - 2]; - stack[stack_ptr - 2] = stack[stack_ptr - 1]; - stack[stack_ptr - 1] = long_tmp; - } - break; - case OP_ADD: - if (altera_check_stack(stack_ptr, 2, &status)) { - --stack_ptr; - stack[stack_ptr - 1] += stack[stack_ptr]; - } - break; - case OP_SUB: - if (altera_check_stack(stack_ptr, 2, &status)) { - --stack_ptr; - stack[stack_ptr - 1] -= stack[stack_ptr]; - } - break; - case OP_MULT: - if (altera_check_stack(stack_ptr, 2, &status)) { - --stack_ptr; - stack[stack_ptr - 1] *= stack[stack_ptr]; - } - break; - case OP_DIV: - if (altera_check_stack(stack_ptr, 2, &status)) { - --stack_ptr; - stack[stack_ptr - 1] /= stack[stack_ptr]; - } - break; - case OP_MOD: - if (altera_check_stack(stack_ptr, 2, &status)) { - --stack_ptr; - stack[stack_ptr - 1] %= stack[stack_ptr]; - } - break; - case OP_SHL: - if (altera_check_stack(stack_ptr, 2, &status)) { - --stack_ptr; - stack[stack_ptr - 1] <<= stack[stack_ptr]; - } - break; - case OP_SHR: - if (altera_check_stack(stack_ptr, 2, &status)) { - --stack_ptr; - stack[stack_ptr - 1] >>= stack[stack_ptr]; - } - break; - case OP_NOT: - if (altera_check_stack(stack_ptr, 1, &status)) - stack[stack_ptr - 1] ^= (-1L); - - break; - case OP_AND: - if (altera_check_stack(stack_ptr, 2, &status)) { - --stack_ptr; - stack[stack_ptr - 1] &= stack[stack_ptr]; - } - break; - case OP_OR: - if (altera_check_stack(stack_ptr, 2, &status)) { - --stack_ptr; - stack[stack_ptr - 1] |= stack[stack_ptr]; - } - break; - case OP_XOR: - if (altera_check_stack(stack_ptr, 2, &status)) { - --stack_ptr; - stack[stack_ptr - 1] ^= stack[stack_ptr]; - } - break; - case OP_INV: - if (!altera_check_stack(stack_ptr, 1, &status)) - break; - stack[stack_ptr - 1] = stack[stack_ptr - 1] ? 0L : 1L; - break; - case OP_GT: - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - --stack_ptr; - stack[stack_ptr - 1] = - (stack[stack_ptr - 1] > stack[stack_ptr]) ? - 1L : 0L; - - break; - case OP_LT: - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - --stack_ptr; - stack[stack_ptr - 1] = - (stack[stack_ptr - 1] < stack[stack_ptr]) ? - 1L : 0L; - - break; - case OP_RET: - if ((version > 0) && (stack_ptr == 0)) { - /* - * We completed one of the main procedures - * of an ACTION. - * Find the next procedure - * to be executed and jump to it. - * If there are no more procedures, then EXIT. - */ - i = get_unaligned_be32(&p[proc_table + - (13 * current_proc) + 4]); - while ((i != 0) && - ((proc_attributes[i] == 1) || - ((proc_attributes[i] & 0xc0) == 0x40))) - i = get_unaligned_be32(&p[proc_table + - (13 * i) + 4]); - - if (i == 0) { - /* no procedures to execute! */ - done = 1; - *exit_code = 0; /* success */ - } else { - current_proc = i; - pc = code_sect + get_unaligned_be32( - &p[proc_table + - (13 * i) + 9]); - if ((pc < code_sect) || - (pc >= debug_sect)) - status = -ERANGE; - } - - } else - if (altera_check_stack(stack_ptr, 1, &status)) { - pc = stack[--stack_ptr] + code_sect; - if ((pc <= code_sect) || - (pc >= debug_sect)) - status = -ERANGE; - - } - - break; - case OP_CMPS: - /* - * Array short compare - * ...stack 0 is source 1 value - * ...stack 1 is source 2 value - * ...stack 2 is mask value - * ...stack 3 is count - */ - if (altera_check_stack(stack_ptr, 4, &status)) { - s32 a = stack[--stack_ptr]; - s32 b = stack[--stack_ptr]; - long_tmp = stack[--stack_ptr]; - count = stack[stack_ptr - 1]; - - if ((count < 1) || (count > 32)) - status = -ERANGE; - else { - long_tmp &= ((-1L) >> (32 - count)); - - stack[stack_ptr - 1] = - ((a & long_tmp) == (b & long_tmp)) - ? 1L : 0L; - } - } - break; - case OP_PINT: - /* - * PRINT add integer - * ...stack 0 is integer value - */ - if (!altera_check_stack(stack_ptr, 1, &status)) - break; - sprintf(&msg_buff[strlen(msg_buff)], - "%ld", stack[--stack_ptr]); - break; - case OP_PRNT: - /* PRINT finish */ - if (debug) - printk(msg_buff, "\n"); - - msg_buff[0] = '\0'; - break; - case OP_DSS: - /* - * DRSCAN short - * ...stack 0 is scan data - * ...stack 1 is count - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - long_tmp = stack[--stack_ptr]; - count = stack[--stack_ptr]; - put_unaligned_le32(long_tmp, &charbuf[0]); - status = altera_drscan(astate, count, charbuf, 0); - break; - case OP_DSSC: - /* - * DRSCAN short with capture - * ...stack 0 is scan data - * ...stack 1 is count - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - long_tmp = stack[--stack_ptr]; - count = stack[stack_ptr - 1]; - put_unaligned_le32(long_tmp, &charbuf[0]); - status = altera_swap_dr(astate, count, charbuf, - 0, charbuf, 0); - stack[stack_ptr - 1] = get_unaligned_le32(&charbuf[0]); - break; - case OP_ISS: - /* - * IRSCAN short - * ...stack 0 is scan data - * ...stack 1 is count - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - long_tmp = stack[--stack_ptr]; - count = stack[--stack_ptr]; - put_unaligned_le32(long_tmp, &charbuf[0]); - status = altera_irscan(astate, count, charbuf, 0); - break; - case OP_ISSC: - /* - * IRSCAN short with capture - * ...stack 0 is scan data - * ...stack 1 is count - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - long_tmp = stack[--stack_ptr]; - count = stack[stack_ptr - 1]; - put_unaligned_le32(long_tmp, &charbuf[0]); - status = altera_swap_ir(astate, count, charbuf, - 0, charbuf, 0); - stack[stack_ptr - 1] = get_unaligned_le32(&charbuf[0]); - break; - case OP_DPR: - if (!altera_check_stack(stack_ptr, 1, &status)) - break; - count = stack[--stack_ptr]; - status = altera_set_dr_pre(&astate->js, count, 0, NULL); - break; - case OP_DPRL: - /* - * DRPRE with literal data - * ...stack 0 is count - * ...stack 1 is literal data - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - count = stack[--stack_ptr]; - long_tmp = stack[--stack_ptr]; - put_unaligned_le32(long_tmp, &charbuf[0]); - status = altera_set_dr_pre(&astate->js, count, 0, - charbuf); - break; - case OP_DPO: - /* - * DRPOST - * ...stack 0 is count - */ - if (altera_check_stack(stack_ptr, 1, &status)) { - count = stack[--stack_ptr]; - status = altera_set_dr_post(&astate->js, count, - 0, NULL); - } - break; - case OP_DPOL: - /* - * DRPOST with literal data - * ...stack 0 is count - * ...stack 1 is literal data - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - count = stack[--stack_ptr]; - long_tmp = stack[--stack_ptr]; - put_unaligned_le32(long_tmp, &charbuf[0]); - status = altera_set_dr_post(&astate->js, count, 0, - charbuf); - break; - case OP_IPR: - if (altera_check_stack(stack_ptr, 1, &status)) { - count = stack[--stack_ptr]; - status = altera_set_ir_pre(&astate->js, count, - 0, NULL); - } - break; - case OP_IPRL: - /* - * IRPRE with literal data - * ...stack 0 is count - * ...stack 1 is literal data - */ - if (altera_check_stack(stack_ptr, 2, &status)) { - count = stack[--stack_ptr]; - long_tmp = stack[--stack_ptr]; - put_unaligned_le32(long_tmp, &charbuf[0]); - status = altera_set_ir_pre(&astate->js, count, - 0, charbuf); - } - break; - case OP_IPO: - /* - * IRPOST - * ...stack 0 is count - */ - if (altera_check_stack(stack_ptr, 1, &status)) { - count = stack[--stack_ptr]; - status = altera_set_ir_post(&astate->js, count, - 0, NULL); - } - break; - case OP_IPOL: - /* - * IRPOST with literal data - * ...stack 0 is count - * ...stack 1 is literal data - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - count = stack[--stack_ptr]; - long_tmp = stack[--stack_ptr]; - put_unaligned_le32(long_tmp, &charbuf[0]); - status = altera_set_ir_post(&astate->js, count, 0, - charbuf); - break; - case OP_PCHR: - if (altera_check_stack(stack_ptr, 1, &status)) { - u8 ch; - count = strlen(msg_buff); - ch = (char) stack[--stack_ptr]; - if ((ch < 1) || (ch > 127)) { - /* - * character code out of range - * instead of flagging an error, - * force the value to 127 - */ - ch = 127; - } - msg_buff[count] = ch; - msg_buff[count + 1] = '\0'; - } - break; - case OP_EXIT: - if (altera_check_stack(stack_ptr, 1, &status)) - *exit_code = stack[--stack_ptr]; - - done = 1; - break; - case OP_EQU: - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - --stack_ptr; - stack[stack_ptr - 1] = - (stack[stack_ptr - 1] == stack[stack_ptr]) ? - 1L : 0L; - break; - case OP_POPT: - if (altera_check_stack(stack_ptr, 1, &status)) - --stack_ptr; - - break; - case OP_ABS: - if (!altera_check_stack(stack_ptr, 1, &status)) - break; - if (stack[stack_ptr - 1] < 0) - stack[stack_ptr - 1] = 0 - stack[stack_ptr - 1]; - - break; - case OP_BCH0: - /* - * Batch operation 0 - * SWP - * SWPN 7 - * SWP - * SWPN 6 - * DUPN 8 - * SWPN 2 - * SWP - * DUPN 6 - * DUPN 6 - */ - - /* SWP */ - if (altera_check_stack(stack_ptr, 2, &status)) { - long_tmp = stack[stack_ptr - 2]; - stack[stack_ptr - 2] = stack[stack_ptr - 1]; - stack[stack_ptr - 1] = long_tmp; - } - - /* SWPN 7 */ - index = 7 + 1; - if (altera_check_stack(stack_ptr, index, &status)) { - long_tmp = stack[stack_ptr - index]; - stack[stack_ptr - index] = stack[stack_ptr - 1]; - stack[stack_ptr - 1] = long_tmp; - } - - /* SWP */ - if (altera_check_stack(stack_ptr, 2, &status)) { - long_tmp = stack[stack_ptr - 2]; - stack[stack_ptr - 2] = stack[stack_ptr - 1]; - stack[stack_ptr - 1] = long_tmp; - } - - /* SWPN 6 */ - index = 6 + 1; - if (altera_check_stack(stack_ptr, index, &status)) { - long_tmp = stack[stack_ptr - index]; - stack[stack_ptr - index] = stack[stack_ptr - 1]; - stack[stack_ptr - 1] = long_tmp; - } - - /* DUPN 8 */ - index = 8 + 1; - if (altera_check_stack(stack_ptr, index, &status)) { - stack[stack_ptr] = stack[stack_ptr - index]; - ++stack_ptr; - } - - /* SWPN 2 */ - index = 2 + 1; - if (altera_check_stack(stack_ptr, index, &status)) { - long_tmp = stack[stack_ptr - index]; - stack[stack_ptr - index] = stack[stack_ptr - 1]; - stack[stack_ptr - 1] = long_tmp; - } - - /* SWP */ - if (altera_check_stack(stack_ptr, 2, &status)) { - long_tmp = stack[stack_ptr - 2]; - stack[stack_ptr - 2] = stack[stack_ptr - 1]; - stack[stack_ptr - 1] = long_tmp; - } - - /* DUPN 6 */ - index = 6 + 1; - if (altera_check_stack(stack_ptr, index, &status)) { - stack[stack_ptr] = stack[stack_ptr - index]; - ++stack_ptr; - } - - /* DUPN 6 */ - index = 6 + 1; - if (altera_check_stack(stack_ptr, index, &status)) { - stack[stack_ptr] = stack[stack_ptr - index]; - ++stack_ptr; - } - break; - case OP_PSH0: - stack[stack_ptr++] = 0; - break; - case OP_PSHL: - stack[stack_ptr++] = (s32) args[0]; - break; - case OP_PSHV: - stack[stack_ptr++] = vars[args[0]]; - break; - case OP_JMP: - pc = args[0] + code_sect; - if ((pc < code_sect) || (pc >= debug_sect)) - status = -ERANGE; - break; - case OP_CALL: - stack[stack_ptr++] = pc; - pc = args[0] + code_sect; - if ((pc < code_sect) || (pc >= debug_sect)) - status = -ERANGE; - break; - case OP_NEXT: - /* - * Process FOR / NEXT loop - * ...argument 0 is variable ID - * ...stack 0 is step value - * ...stack 1 is end value - * ...stack 2 is top address - */ - if (altera_check_stack(stack_ptr, 3, &status)) { - s32 step = stack[stack_ptr - 1]; - s32 end = stack[stack_ptr - 2]; - s32 top = stack[stack_ptr - 3]; - s32 iterator = vars[args[0]]; - int break_out = 0; - - if (step < 0) { - if (iterator <= end) - break_out = 1; - } else if (iterator >= end) - break_out = 1; - - if (break_out) { - stack_ptr -= 3; - } else { - vars[args[0]] = iterator + step; - pc = top + code_sect; - if ((pc < code_sect) || - (pc >= debug_sect)) - status = -ERANGE; - } - } - break; - case OP_PSTR: - /* - * PRINT add string - * ...argument 0 is string ID - */ - count = strlen(msg_buff); - strlcpy(&msg_buff[count], - &p[str_table + args[0]], - ALTERA_MESSAGE_LENGTH - count); - break; - case OP_SINT: - /* - * STATE intermediate state - * ...argument 0 is state code - */ - status = altera_goto_jstate(astate, args[0]); - break; - case OP_ST: - /* - * STATE final state - * ...argument 0 is state code - */ - status = altera_goto_jstate(astate, args[0]); - break; - case OP_ISTP: - /* - * IRSTOP state - * ...argument 0 is state code - */ - status = altera_set_irstop(&astate->js, args[0]); - break; - case OP_DSTP: - /* - * DRSTOP state - * ...argument 0 is state code - */ - status = altera_set_drstop(&astate->js, args[0]); - break; - - case OP_SWPN: - /* - * Exchange top with Nth stack value - * ...argument 0 is 0-based stack entry - * to swap with top element - */ - index = (args[0]) + 1; - if (altera_check_stack(stack_ptr, index, &status)) { - long_tmp = stack[stack_ptr - index]; - stack[stack_ptr - index] = stack[stack_ptr - 1]; - stack[stack_ptr - 1] = long_tmp; - } - break; - case OP_DUPN: - /* - * Duplicate Nth stack value - * ...argument 0 is 0-based stack entry to duplicate - */ - index = (args[0]) + 1; - if (altera_check_stack(stack_ptr, index, &status)) { - stack[stack_ptr] = stack[stack_ptr - index]; - ++stack_ptr; - } - break; - case OP_POPV: - /* - * Pop stack into scalar variable - * ...argument 0 is variable ID - * ...stack 0 is value - */ - if (altera_check_stack(stack_ptr, 1, &status)) - vars[args[0]] = stack[--stack_ptr]; - - break; - case OP_POPE: - /* - * Pop stack into integer array element - * ...argument 0 is variable ID - * ...stack 0 is array index - * ...stack 1 is value - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - variable_id = args[0]; - - /* - * If variable is read-only, - * convert to writable array - */ - if ((version > 0) && - ((attrs[variable_id] & 0x9c) == 0x1c)) { - /* Allocate a writable buffer for this array */ - count = var_size[variable_id]; - long_tmp = vars[variable_id]; - longptr_tmp = kzalloc(count * sizeof(long), - GFP_KERNEL); - vars[variable_id] = (long)longptr_tmp; - - if (vars[variable_id] == 0) { - status = -ENOMEM; - break; - } - - /* copy previous contents into buffer */ - for (i = 0; i < count; ++i) { - longptr_tmp[i] = - get_unaligned_be32(&p[long_tmp]); - long_tmp += sizeof(long); - } - - /* - * set bit 7 - buffer was - * dynamically allocated - */ - attrs[variable_id] |= 0x80; - - /* clear bit 2 - variable is writable */ - attrs[variable_id] &= ~0x04; - attrs[variable_id] |= 0x01; - - } - - /* check that variable is a writable integer array */ - if ((attrs[variable_id] & 0x1c) != 0x18) - status = -ERANGE; - else { - longptr_tmp = (long *)vars[variable_id]; - - /* pop the array index */ - index = stack[--stack_ptr]; - - /* pop the value and store it into the array */ - longptr_tmp[index] = stack[--stack_ptr]; - } - - break; - case OP_POPA: - /* - * Pop stack into Boolean array - * ...argument 0 is variable ID - * ...stack 0 is count - * ...stack 1 is array index - * ...stack 2 is value - */ - if (!altera_check_stack(stack_ptr, 3, &status)) - break; - variable_id = args[0]; - - /* - * If variable is read-only, - * convert to writable array - */ - if ((version > 0) && - ((attrs[variable_id] & 0x9c) == 0x0c)) { - /* Allocate a writable buffer for this array */ - long_tmp = - (var_size[variable_id] + 7L) >> 3L; - charptr_tmp2 = (u8 *)vars[variable_id]; - charptr_tmp = - kzalloc(long_tmp, GFP_KERNEL); - vars[variable_id] = (long)charptr_tmp; - - if (vars[variable_id] == 0) { - status = -ENOMEM; - break; - } - - /* zero the buffer */ - for (long_idx = 0L; - long_idx < long_tmp; - ++long_idx) { - charptr_tmp[long_idx] = 0; - } - - /* copy previous contents into buffer */ - for (long_idx = 0L; - long_idx < var_size[variable_id]; - ++long_idx) { - long_idx2 = long_idx; - - if (charptr_tmp2[long_idx2 >> 3] & - (1 << (long_idx2 & 7))) { - charptr_tmp[long_idx >> 3] |= - (1 << (long_idx & 7)); - } - } - - /* - * set bit 7 - buffer was - * dynamically allocated - */ - attrs[variable_id] |= 0x80; - - /* clear bit 2 - variable is writable */ - attrs[variable_id] &= ~0x04; - attrs[variable_id] |= 0x01; - - } - - /* - * check that variable is - * a writable Boolean array - */ - if ((attrs[variable_id] & 0x1c) != 0x08) { - status = -ERANGE; - break; - } - - charptr_tmp = (u8 *)vars[variable_id]; - - /* pop the count (number of bits to copy) */ - long_count = stack[--stack_ptr]; - - /* pop the array index */ - long_idx = stack[--stack_ptr]; - - reverse = 0; - - if (version > 0) { - /* - * stack 0 = array right index - * stack 1 = array left index - */ - - if (long_idx > long_count) { - reverse = 1; - long_tmp = long_count; - long_count = 1 + long_idx - - long_count; - long_idx = long_tmp; - - /* reverse POPA is not supported */ - status = -ERANGE; - break; - } else - long_count = 1 + long_count - - long_idx; - - } - - /* pop the data */ - long_tmp = stack[--stack_ptr]; - - if (long_count < 1) { - status = -ERANGE; - break; - } - - for (i = 0; i < long_count; ++i) { - if (long_tmp & (1L << (s32) i)) - charptr_tmp[long_idx >> 3L] |= - (1L << (long_idx & 7L)); - else - charptr_tmp[long_idx >> 3L] &= - ~(1L << (long_idx & 7L)); - - ++long_idx; - } - - break; - case OP_JMPZ: - /* - * Pop stack and branch if zero - * ...argument 0 is address - * ...stack 0 is condition value - */ - if (altera_check_stack(stack_ptr, 1, &status)) { - if (stack[--stack_ptr] == 0) { - pc = args[0] + code_sect; - if ((pc < code_sect) || - (pc >= debug_sect)) - status = -ERANGE; - } - } - break; - case OP_DS: - case OP_IS: - /* - * DRSCAN - * IRSCAN - * ...argument 0 is scan data variable ID - * ...stack 0 is array index - * ...stack 1 is count - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - long_idx = stack[--stack_ptr]; - long_count = stack[--stack_ptr]; - reverse = 0; - if (version > 0) { - /* - * stack 0 = array right index - * stack 1 = array left index - * stack 2 = count - */ - long_tmp = long_count; - long_count = stack[--stack_ptr]; - - if (long_idx > long_tmp) { - reverse = 1; - long_idx = long_tmp; - } - } - - charptr_tmp = (u8 *)vars[args[0]]; - - if (reverse) { - /* - * allocate a buffer - * and reverse the data order - */ - charptr_tmp2 = charptr_tmp; - charptr_tmp = kzalloc((long_count >> 3) + 1, - GFP_KERNEL); - if (charptr_tmp == NULL) { - status = -ENOMEM; - break; - } - - long_tmp = long_idx + long_count - 1; - long_idx2 = 0; - while (long_idx2 < long_count) { - if (charptr_tmp2[long_tmp >> 3] & - (1 << (long_tmp & 7))) - charptr_tmp[long_idx2 >> 3] |= - (1 << (long_idx2 & 7)); - else - charptr_tmp[long_idx2 >> 3] &= - ~(1 << (long_idx2 & 7)); - - --long_tmp; - ++long_idx2; - } - } - - if (opcode == 0x51) /* DS */ - status = altera_drscan(astate, long_count, - charptr_tmp, long_idx); - else /* IS */ - status = altera_irscan(astate, long_count, - charptr_tmp, long_idx); - - if (reverse) - kfree(charptr_tmp); - - break; - case OP_DPRA: - /* - * DRPRE with array data - * ...argument 0 is variable ID - * ...stack 0 is array index - * ...stack 1 is count - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - index = stack[--stack_ptr]; - count = stack[--stack_ptr]; - - if (version > 0) - /* - * stack 0 = array right index - * stack 1 = array left index - */ - count = 1 + count - index; - - charptr_tmp = (u8 *)vars[args[0]]; - status = altera_set_dr_pre(&astate->js, count, index, - charptr_tmp); - break; - case OP_DPOA: - /* - * DRPOST with array data - * ...argument 0 is variable ID - * ...stack 0 is array index - * ...stack 1 is count - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - index = stack[--stack_ptr]; - count = stack[--stack_ptr]; - - if (version > 0) - /* - * stack 0 = array right index - * stack 1 = array left index - */ - count = 1 + count - index; - - charptr_tmp = (u8 *)vars[args[0]]; - status = altera_set_dr_post(&astate->js, count, index, - charptr_tmp); - break; - case OP_IPRA: - /* - * IRPRE with array data - * ...argument 0 is variable ID - * ...stack 0 is array index - * ...stack 1 is count - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - index = stack[--stack_ptr]; - count = stack[--stack_ptr]; - - if (version > 0) - /* - * stack 0 = array right index - * stack 1 = array left index - */ - count = 1 + count - index; - - charptr_tmp = (u8 *)vars[args[0]]; - status = altera_set_ir_pre(&astate->js, count, index, - charptr_tmp); - - break; - case OP_IPOA: - /* - * IRPOST with array data - * ...argument 0 is variable ID - * ...stack 0 is array index - * ...stack 1 is count - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - index = stack[--stack_ptr]; - count = stack[--stack_ptr]; - - if (version > 0) - /* - * stack 0 = array right index - * stack 1 = array left index - */ - count = 1 + count - index; - - charptr_tmp = (u8 *)vars[args[0]]; - status = altera_set_ir_post(&astate->js, count, index, - charptr_tmp); - - break; - case OP_EXPT: - /* - * EXPORT - * ...argument 0 is string ID - * ...stack 0 is integer expression - */ - if (altera_check_stack(stack_ptr, 1, &status)) { - name = &p[str_table + args[0]]; - long_tmp = stack[--stack_ptr]; - altera_export_int(name, long_tmp); - } - break; - case OP_PSHE: - /* - * Push integer array element - * ...argument 0 is variable ID - * ...stack 0 is array index - */ - if (!altera_check_stack(stack_ptr, 1, &status)) - break; - variable_id = args[0]; - index = stack[stack_ptr - 1]; - - /* check variable type */ - if ((attrs[variable_id] & 0x1f) == 0x19) { - /* writable integer array */ - longptr_tmp = (long *)vars[variable_id]; - stack[stack_ptr - 1] = longptr_tmp[index]; - } else if ((attrs[variable_id] & 0x1f) == 0x1c) { - /* read-only integer array */ - long_tmp = vars[variable_id] + - (index * sizeof(long)); - stack[stack_ptr - 1] = - get_unaligned_be32(&p[long_tmp]); - } else - status = -ERANGE; - - break; - case OP_PSHA: - /* - * Push Boolean array - * ...argument 0 is variable ID - * ...stack 0 is count - * ...stack 1 is array index - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - variable_id = args[0]; - - /* check that variable is a Boolean array */ - if ((attrs[variable_id] & 0x18) != 0x08) { - status = -ERANGE; - break; - } - - charptr_tmp = (u8 *)vars[variable_id]; - - /* pop the count (number of bits to copy) */ - count = stack[--stack_ptr]; - - /* pop the array index */ - index = stack[stack_ptr - 1]; - - if (version > 0) - /* - * stack 0 = array right index - * stack 1 = array left index - */ - count = 1 + count - index; - - if ((count < 1) || (count > 32)) { - status = -ERANGE; - break; - } - - long_tmp = 0L; - - for (i = 0; i < count; ++i) - if (charptr_tmp[(i + index) >> 3] & - (1 << ((i + index) & 7))) - long_tmp |= (1L << i); - - stack[stack_ptr - 1] = long_tmp; - - break; - case OP_DYNA: - /* - * Dynamically change size of array - * ...argument 0 is variable ID - * ...stack 0 is new size - */ - if (!altera_check_stack(stack_ptr, 1, &status)) - break; - variable_id = args[0]; - long_tmp = stack[--stack_ptr]; - - if (long_tmp > var_size[variable_id]) { - var_size[variable_id] = long_tmp; - - if (attrs[variable_id] & 0x10) - /* allocate integer array */ - long_tmp *= sizeof(long); - else - /* allocate Boolean array */ - long_tmp = (long_tmp + 7) >> 3; - - /* - * If the buffer was previously allocated, - * free it - */ - if (attrs[variable_id] & 0x80) { - kfree((void *)vars[variable_id]); - vars[variable_id] = 0; - } - - /* - * Allocate a new buffer - * of the requested size - */ - vars[variable_id] = (long) - kzalloc(long_tmp, GFP_KERNEL); - - if (vars[variable_id] == 0) { - status = -ENOMEM; - break; - } - - /* - * Set the attribute bit to indicate that - * this buffer was dynamically allocated and - * should be freed later - */ - attrs[variable_id] |= 0x80; - - /* zero out memory */ - count = ((var_size[variable_id] + 7L) / - 8L); - charptr_tmp = (u8 *)(vars[variable_id]); - for (index = 0; index < count; ++index) - charptr_tmp[index] = 0; - - } - - break; - case OP_EXPV: - /* - * Export Boolean array - * ...argument 0 is string ID - * ...stack 0 is variable ID - * ...stack 1 is array right index - * ...stack 2 is array left index - */ - if (!altera_check_stack(stack_ptr, 3, &status)) - break; - if (version == 0) { - /* EXPV is not supported in JBC 1.0 */ - bad_opcode = 1; - break; - } - name = &p[str_table + args[0]]; - variable_id = stack[--stack_ptr]; - long_idx = stack[--stack_ptr];/* right indx */ - long_idx2 = stack[--stack_ptr];/* left indx */ - - if (long_idx > long_idx2) { - /* reverse indices not supported */ - status = -ERANGE; - break; - } - - long_count = 1 + long_idx2 - long_idx; - - charptr_tmp = (u8 *)vars[variable_id]; - charptr_tmp2 = NULL; - - if ((long_idx & 7L) != 0) { - s32 k = long_idx; - charptr_tmp2 = - kzalloc(((long_count + 7L) / 8L), - GFP_KERNEL); - if (charptr_tmp2 == NULL) { - status = -ENOMEM; - break; - } - - for (i = 0; i < long_count; ++i) { - if (charptr_tmp[k >> 3] & - (1 << (k & 7))) - charptr_tmp2[i >> 3] |= - (1 << (i & 7)); - else - charptr_tmp2[i >> 3] &= - ~(1 << (i & 7)); - - ++k; - } - charptr_tmp = charptr_tmp2; - - } else if (long_idx != 0) - charptr_tmp = &charptr_tmp[long_idx >> 3]; - - altera_export_bool_array(name, charptr_tmp, - long_count); - - /* free allocated buffer */ - if ((long_idx & 7L) != 0) - kfree(charptr_tmp2); - - break; - case OP_COPY: { - /* - * Array copy - * ...argument 0 is dest ID - * ...argument 1 is source ID - * ...stack 0 is count - * ...stack 1 is dest index - * ...stack 2 is source index - */ - s32 copy_count; - s32 copy_index; - s32 copy_index2; - s32 destleft; - s32 src_count; - s32 dest_count; - int src_reverse = 0; - int dest_reverse = 0; - - if (!altera_check_stack(stack_ptr, 3, &status)) - break; - - copy_count = stack[--stack_ptr]; - copy_index = stack[--stack_ptr]; - copy_index2 = stack[--stack_ptr]; - reverse = 0; - - if (version > 0) { - /* - * stack 0 = source right index - * stack 1 = source left index - * stack 2 = destination right index - * stack 3 = destination left index - */ - destleft = stack[--stack_ptr]; - - if (copy_count > copy_index) { - src_reverse = 1; - reverse = 1; - src_count = 1 + copy_count - copy_index; - /* copy_index = source start index */ - } else { - src_count = 1 + copy_index - copy_count; - /* source start index */ - copy_index = copy_count; - } - - if (copy_index2 > destleft) { - dest_reverse = 1; - reverse = !reverse; - dest_count = 1 + copy_index2 - destleft; - /* destination start index */ - copy_index2 = destleft; - } else - dest_count = 1 + destleft - copy_index2; - - copy_count = (src_count < dest_count) ? - src_count : dest_count; - - if ((src_reverse || dest_reverse) && - (src_count != dest_count)) - /* - * If either the source or destination - * is reversed, we can't tolerate - * a length mismatch, because we - * "left justify" arrays when copying. - * This won't work correctly - * with reversed arrays. - */ - status = -ERANGE; - - } - - count = copy_count; - index = copy_index; - index2 = copy_index2; - - /* - * If destination is a read-only array, - * allocate a buffer and convert it to a writable array - */ - variable_id = args[1]; - if ((version > 0) && - ((attrs[variable_id] & 0x9c) == 0x0c)) { - /* Allocate a writable buffer for this array */ - long_tmp = - (var_size[variable_id] + 7L) >> 3L; - charptr_tmp2 = (u8 *)vars[variable_id]; - charptr_tmp = - kzalloc(long_tmp, GFP_KERNEL); - vars[variable_id] = (long)charptr_tmp; - - if (vars[variable_id] == 0) { - status = -ENOMEM; - break; - } - - /* zero the buffer */ - for (long_idx = 0L; long_idx < long_tmp; - ++long_idx) - charptr_tmp[long_idx] = 0; - - /* copy previous contents into buffer */ - for (long_idx = 0L; - long_idx < var_size[variable_id]; - ++long_idx) { - long_idx2 = long_idx; - - if (charptr_tmp2[long_idx2 >> 3] & - (1 << (long_idx2 & 7))) - charptr_tmp[long_idx >> 3] |= - (1 << (long_idx & 7)); - - } - - /* - set bit 7 - buffer was dynamically allocated */ - attrs[variable_id] |= 0x80; - - /* clear bit 2 - variable is writable */ - attrs[variable_id] &= ~0x04; - attrs[variable_id] |= 0x01; - } - - charptr_tmp = (u8 *)vars[args[1]]; - charptr_tmp2 = (u8 *)vars[args[0]]; - - /* check if destination is a writable Boolean array */ - if ((attrs[args[1]] & 0x1c) != 0x08) { - status = -ERANGE; - break; - } - - if (count < 1) { - status = -ERANGE; - break; - } - - if (reverse) - index2 += (count - 1); - - for (i = 0; i < count; ++i) { - if (charptr_tmp2[index >> 3] & - (1 << (index & 7))) - charptr_tmp[index2 >> 3] |= - (1 << (index2 & 7)); - else - charptr_tmp[index2 >> 3] &= - ~(1 << (index2 & 7)); - - ++index; - if (reverse) - --index2; - else - ++index2; - } - - break; - } - case OP_DSC: - case OP_ISC: { - /* - * DRSCAN with capture - * IRSCAN with capture - * ...argument 0 is scan data variable ID - * ...argument 1 is capture variable ID - * ...stack 0 is capture index - * ...stack 1 is scan data index - * ...stack 2 is count - */ - s32 scan_right, scan_left; - s32 capture_count = 0; - s32 scan_count = 0; - s32 capture_index; - s32 scan_index; - - if (!altera_check_stack(stack_ptr, 3, &status)) - break; - - capture_index = stack[--stack_ptr]; - scan_index = stack[--stack_ptr]; - - if (version > 0) { - /* - * stack 0 = capture right index - * stack 1 = capture left index - * stack 2 = scan right index - * stack 3 = scan left index - * stack 4 = count - */ - scan_right = stack[--stack_ptr]; - scan_left = stack[--stack_ptr]; - capture_count = 1 + scan_index - capture_index; - scan_count = 1 + scan_left - scan_right; - scan_index = scan_right; - } - - long_count = stack[--stack_ptr]; - /* - * If capture array is read-only, allocate a buffer - * and convert it to a writable array - */ - variable_id = args[1]; - if ((version > 0) && - ((attrs[variable_id] & 0x9c) == 0x0c)) { - /* Allocate a writable buffer for this array */ - long_tmp = - (var_size[variable_id] + 7L) >> 3L; - charptr_tmp2 = (u8 *)vars[variable_id]; - charptr_tmp = - kzalloc(long_tmp, GFP_KERNEL); - vars[variable_id] = (long)charptr_tmp; - - if (vars[variable_id] == 0) { - status = -ENOMEM; - break; - } - - /* zero the buffer */ - for (long_idx = 0L; long_idx < long_tmp; - ++long_idx) - charptr_tmp[long_idx] = 0; - - /* copy previous contents into buffer */ - for (long_idx = 0L; - long_idx < var_size[variable_id]; - ++long_idx) { - long_idx2 = long_idx; - - if (charptr_tmp2[long_idx2 >> 3] & - (1 << (long_idx2 & 7))) - charptr_tmp[long_idx >> 3] |= - (1 << (long_idx & 7)); - - } - - /* - * set bit 7 - buffer was - * dynamically allocated - */ - attrs[variable_id] |= 0x80; - - /* clear bit 2 - variable is writable */ - attrs[variable_id] &= ~0x04; - attrs[variable_id] |= 0x01; - - } - - charptr_tmp = (u8 *)vars[args[0]]; - charptr_tmp2 = (u8 *)vars[args[1]]; - - if ((version > 0) && - ((long_count > capture_count) || - (long_count > scan_count))) { - status = -ERANGE; - break; - } - - /* - * check that capture array - * is a writable Boolean array - */ - if ((attrs[args[1]] & 0x1c) != 0x08) { - status = -ERANGE; - break; - } - - if (status == 0) { - if (opcode == 0x82) /* DSC */ - status = altera_swap_dr(astate, - long_count, - charptr_tmp, - scan_index, - charptr_tmp2, - capture_index); - else /* ISC */ - status = altera_swap_ir(astate, - long_count, - charptr_tmp, - scan_index, - charptr_tmp2, - capture_index); - - } - - break; - } - case OP_WAIT: - /* - * WAIT - * ...argument 0 is wait state - * ...argument 1 is end state - * ...stack 0 is cycles - * ...stack 1 is microseconds - */ - if (!altera_check_stack(stack_ptr, 2, &status)) - break; - long_tmp = stack[--stack_ptr]; - - if (long_tmp != 0L) - status = altera_wait_cycles(astate, long_tmp, - args[0]); - - long_tmp = stack[--stack_ptr]; - - if ((status == 0) && (long_tmp != 0L)) - status = altera_wait_msecs(astate, - long_tmp, - args[0]); - - if ((status == 0) && (args[1] != args[0])) - status = altera_goto_jstate(astate, - args[1]); - - if (version > 0) { - --stack_ptr; /* throw away MAX cycles */ - --stack_ptr; /* throw away MAX microseconds */ - } - break; - case OP_CMPA: { - /* - * Array compare - * ...argument 0 is source 1 ID - * ...argument 1 is source 2 ID - * ...argument 2 is mask ID - * ...stack 0 is source 1 index - * ...stack 1 is source 2 index - * ...stack 2 is mask index - * ...stack 3 is count - */ - s32 a, b; - u8 *source1 = (u8 *)vars[args[0]]; - u8 *source2 = (u8 *)vars[args[1]]; - u8 *mask = (u8 *)vars[args[2]]; - u32 index1; - u32 index2; - u32 mask_index; - - if (!altera_check_stack(stack_ptr, 4, &status)) - break; - - index1 = stack[--stack_ptr]; - index2 = stack[--stack_ptr]; - mask_index = stack[--stack_ptr]; - long_count = stack[--stack_ptr]; - - if (version > 0) { - /* - * stack 0 = source 1 right index - * stack 1 = source 1 left index - * stack 2 = source 2 right index - * stack 3 = source 2 left index - * stack 4 = mask right index - * stack 5 = mask left index - */ - s32 mask_right = stack[--stack_ptr]; - s32 mask_left = stack[--stack_ptr]; - /* source 1 count */ - a = 1 + index2 - index1; - /* source 2 count */ - b = 1 + long_count - mask_index; - a = (a < b) ? a : b; - /* mask count */ - b = 1 + mask_left - mask_right; - a = (a < b) ? a : b; - /* source 2 start index */ - index2 = mask_index; - /* mask start index */ - mask_index = mask_right; - long_count = a; - } - - long_tmp = 1L; - - if (long_count < 1) - status = -ERANGE; - else { - count = long_count; - - for (i = 0; i < count; ++i) { - if (mask[mask_index >> 3] & - (1 << (mask_index & 7))) { - a = source1[index1 >> 3] & - (1 << (index1 & 7)) - ? 1 : 0; - b = source2[index2 >> 3] & - (1 << (index2 & 7)) - ? 1 : 0; - - if (a != b) /* failure */ - long_tmp = 0L; - } - ++index1; - ++index2; - ++mask_index; - } - } - - stack[stack_ptr++] = long_tmp; - - break; - } - default: - /* Unrecognized opcode -- ERROR! */ - bad_opcode = 1; - break; - } - - if (bad_opcode) - status = -ENOSYS; - - if ((stack_ptr < 0) || (stack_ptr >= ALTERA_STACK_SIZE)) - status = -EOVERFLOW; - - if (status != 0) { - done = 1; - *error_address = (s32)(opcode_address - code_sect); - } - } - - altera_free_buffers(astate); - - /* Free all dynamically allocated arrays */ - if ((attrs != NULL) && (vars != NULL)) - for (i = 0; i < sym_count; ++i) - if (attrs[i] & 0x80) - kfree((void *)vars[i]); - - kfree(vars); - kfree(var_size); - kfree(attrs); - kfree(proc_attributes); - - return status; -} - -static int altera_get_note(u8 *p, s32 program_size, - s32 *offset, char *key, char *value, int length) -/* - * Gets key and value of NOTE fields in the JBC file. - * Can be called in two modes: if offset pointer is NULL, - * then the function searches for note fields which match - * the key string provided. If offset is not NULL, then - * the function finds the next note field of any key, - * starting at the offset specified by the offset pointer. - * Returns 0 for success, else appropriate error code - */ -{ - int status = -ENODATA; - u32 note_strings = 0L; - u32 note_table = 0L; - u32 note_count = 0L; - u32 first_word = 0L; - int version = 0; - int delta = 0; - char *key_ptr; - char *value_ptr; - int i; - - /* Read header information */ - if (program_size > 52L) { - first_word = get_unaligned_be32(&p[0]); - version = (first_word & 1L); - delta = version * 8; - - note_strings = get_unaligned_be32(&p[8 + delta]); - note_table = get_unaligned_be32(&p[12 + delta]); - note_count = get_unaligned_be32(&p[44 + (2 * delta)]); - } - - if ((first_word != 0x4A414D00L) && (first_word != 0x4A414D01L)) - return -EIO; - - if (note_count <= 0L) - return status; - - if (offset == NULL) { - /* - * We will search for the first note with a specific key, - * and return only the value - */ - for (i = 0; (i < note_count) && - (status != 0); ++i) { - key_ptr = &p[note_strings + - get_unaligned_be32( - &p[note_table + (8 * i)])]; - if ((strnicmp(key, key_ptr, strlen(key_ptr)) == 0) && - (key != NULL)) { - status = 0; - - value_ptr = &p[note_strings + - get_unaligned_be32( - &p[note_table + (8 * i) + 4])]; - - if (value != NULL) - strlcpy(value, value_ptr, length); - - } - } - } else { - /* - * We will search for the next note, regardless of the key, - * and return both the value and the key - */ - - i = *offset; - - if ((i >= 0) && (i < note_count)) { - status = 0; - - if (key != NULL) - strlcpy(key, &p[note_strings + - get_unaligned_be32( - &p[note_table + (8 * i)])], - length); - - if (value != NULL) - strlcpy(value, &p[note_strings + - get_unaligned_be32( - &p[note_table + (8 * i) + 4])], - length); - - *offset = i + 1; - } - } - - return status; -} - -static int altera_check_crc(u8 *p, s32 program_size) -{ - int status = 0; - u16 local_expected = 0, - local_actual = 0, - shift_reg = 0xffff; - int bit, feedback; - u8 databyte; - u32 i; - u32 crc_section = 0L; - u32 first_word = 0L; - int version = 0; - int delta = 0; - - if (program_size > 52L) { - first_word = get_unaligned_be32(&p[0]); - version = (first_word & 1L); - delta = version * 8; - - crc_section = get_unaligned_be32(&p[32 + delta]); - } - - if ((first_word != 0x4A414D00L) && (first_word != 0x4A414D01L)) - status = -EIO; - - if (crc_section >= program_size) - status = -EIO; - - if (status == 0) { - local_expected = (u16)get_unaligned_be16(&p[crc_section]); - - for (i = 0; i < crc_section; ++i) { - databyte = p[i]; - for (bit = 0; bit < 8; bit++) { - feedback = (databyte ^ shift_reg) & 0x01; - shift_reg >>= 1; - if (feedback) - shift_reg ^= 0x8408; - - databyte >>= 1; - } - } - - local_actual = (u16)~shift_reg; - - if (local_expected != local_actual) - status = -EILSEQ; - - } - - if (debug || status) { - switch (status) { - case 0: - printk(KERN_INFO "%s: CRC matched: %04x\n", __func__, - local_actual); - break; - case -EILSEQ: - printk(KERN_ERR "%s: CRC mismatch: expected %04x, " - "actual %04x\n", __func__, local_expected, - local_actual); - break; - case -ENODATA: - printk(KERN_ERR "%s: expected CRC not found, " - "actual CRC = %04x\n", __func__, - local_actual); - break; - case -EIO: - printk(KERN_ERR "%s: error: format isn't " - "recognized.\n", __func__); - break; - default: - printk(KERN_ERR "%s: CRC function returned error " - "code %d\n", __func__, status); - break; - } - } - - return status; -} - -static int altera_get_file_info(u8 *p, - s32 program_size, - int *format_version, - int *action_count, - int *procedure_count) -{ - int status = -EIO; - u32 first_word = 0; - int version = 0; - - if (program_size <= 52L) - return status; - - first_word = get_unaligned_be32(&p[0]); - - if ((first_word == 0x4A414D00L) || (first_word == 0x4A414D01L)) { - status = 0; - - version = (first_word & 1L); - *format_version = version + 1; - - if (version > 0) { - *action_count = get_unaligned_be32(&p[48]); - *procedure_count = get_unaligned_be32(&p[52]); - } - } - - return status; -} - -static int altera_get_act_info(u8 *p, - s32 program_size, - int index, - char **name, - char **description, - struct altera_procinfo **proc_list) -{ - int status = -EIO; - struct altera_procinfo *procptr = NULL; - struct altera_procinfo *tmpptr = NULL; - u32 first_word = 0L; - u32 action_table = 0L; - u32 proc_table = 0L; - u32 str_table = 0L; - u32 note_strings = 0L; - u32 action_count = 0L; - u32 proc_count = 0L; - u32 act_name_id = 0L; - u32 act_desc_id = 0L; - u32 act_proc_id = 0L; - u32 act_proc_name = 0L; - u8 act_proc_attribute = 0; - - if (program_size <= 52L) - return status; - /* Read header information */ - first_word = get_unaligned_be32(&p[0]); - - if (first_word != 0x4A414D01L) - return status; - - action_table = get_unaligned_be32(&p[4]); - proc_table = get_unaligned_be32(&p[8]); - str_table = get_unaligned_be32(&p[12]); - note_strings = get_unaligned_be32(&p[16]); - action_count = get_unaligned_be32(&p[48]); - proc_count = get_unaligned_be32(&p[52]); - - if (index >= action_count) - return status; - - act_name_id = get_unaligned_be32(&p[action_table + (12 * index)]); - act_desc_id = get_unaligned_be32(&p[action_table + (12 * index) + 4]); - act_proc_id = get_unaligned_be32(&p[action_table + (12 * index) + 8]); - - *name = &p[str_table + act_name_id]; - - if (act_desc_id < (note_strings - str_table)) - *description = &p[str_table + act_desc_id]; - - do { - act_proc_name = get_unaligned_be32( - &p[proc_table + (13 * act_proc_id)]); - act_proc_attribute = - (p[proc_table + (13 * act_proc_id) + 8] & 0x03); - - procptr = (struct altera_procinfo *) - kzalloc(sizeof(struct altera_procinfo), - GFP_KERNEL); - - if (procptr == NULL) - status = -ENOMEM; - else { - procptr->name = &p[str_table + act_proc_name]; - procptr->attrs = act_proc_attribute; - procptr->next = NULL; - - /* add record to end of linked list */ - if (*proc_list == NULL) - *proc_list = procptr; - else { - tmpptr = *proc_list; - while (tmpptr->next != NULL) - tmpptr = tmpptr->next; - tmpptr->next = procptr; - } - } - - act_proc_id = get_unaligned_be32( - &p[proc_table + (13 * act_proc_id) + 4]); - } while ((act_proc_id != 0) && (act_proc_id < proc_count)); - - return status; -} - -int altera_init(struct altera_config *config, const struct firmware *fw) -{ - struct altera_state *astate = NULL; - struct altera_procinfo *proc_list = NULL; - struct altera_procinfo *procptr = NULL; - char *key = NULL; - char *value = NULL; - char *action_name = NULL; - char *description = NULL; - int exec_result = 0; - int exit_code = 0; - int format_version = 0; - int action_count = 0; - int procedure_count = 0; - int index = 0; - s32 offset = 0L; - s32 error_address = 0L; - int retval = 0; - - key = kzalloc(33, GFP_KERNEL); - if (!key) { - retval = -ENOMEM; - goto out; - } - value = kzalloc(257, GFP_KERNEL); - if (!value) { - retval = -ENOMEM; - goto free_key; - } - astate = kzalloc(sizeof(struct altera_state), GFP_KERNEL); - if (!astate) { - retval = -ENOMEM; - goto free_value; - } - - astate->config = config; - if (!astate->config->jtag_io) { - dprintk(KERN_INFO "%s: using byteblaster!\n", __func__); - astate->config->jtag_io = netup_jtag_io_lpt; - } - - altera_check_crc((u8 *)fw->data, fw->size); - - if (debug) { - altera_get_file_info((u8 *)fw->data, fw->size, &format_version, - &action_count, &procedure_count); - printk(KERN_INFO "%s: File format is %s ByteCode format\n", - __func__, (format_version == 2) ? "Jam STAPL" : - "pre-standardized Jam 1.1"); - while (altera_get_note((u8 *)fw->data, fw->size, - &offset, key, value, 256) == 0) - printk(KERN_INFO "%s: NOTE \"%s\" = \"%s\"\n", - __func__, key, value); - } - - if (debug && (format_version == 2) && (action_count > 0)) { - printk(KERN_INFO "%s: Actions available:\n", __func__); - for (index = 0; index < action_count; ++index) { - altera_get_act_info((u8 *)fw->data, fw->size, - index, &action_name, - &description, - &proc_list); - - if (description == NULL) - printk(KERN_INFO "%s: %s\n", - __func__, - action_name); - else - printk(KERN_INFO "%s: %s \"%s\"\n", - __func__, - action_name, - description); - - procptr = proc_list; - while (procptr != NULL) { - if (procptr->attrs != 0) - printk(KERN_INFO "%s: %s (%s)\n", - __func__, - procptr->name, - (procptr->attrs == 1) ? - "optional" : "recommended"); - - proc_list = procptr->next; - kfree(procptr); - procptr = proc_list; - } - } - - printk(KERN_INFO "\n"); - } - - exec_result = altera_execute(astate, (u8 *)fw->data, fw->size, - &error_address, &exit_code, &format_version); - - if (exit_code) - exec_result = -EREMOTEIO; - - if ((format_version == 2) && (exec_result == -EINVAL)) { - if (astate->config->action == NULL) - printk(KERN_ERR "%s: error: no action specified for " - "Jam STAPL file.\nprogram terminated.\n", - __func__); - else - printk(KERN_ERR "%s: error: action \"%s\"" - " is not supported " - "for this Jam STAPL file.\n" - "Program terminated.\n", __func__, - astate->config->action); - - } else if (exec_result) - printk(KERN_ERR "%s: error %d\n", __func__, exec_result); - - kfree(astate); -free_value: - kfree(value); -free_key: - kfree(key); -out: - return retval; -} -EXPORT_SYMBOL(altera_init); diff --git a/drivers/staging/altera-stapl/altera.h b/drivers/staging/altera-stapl/altera.h deleted file mode 100644 index 94c0c61..0000000 --- a/drivers/staging/altera-stapl/altera.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * altera.h - * - * altera FPGA driver - * - * Copyright (C) Altera Corporation 1998-2001 - * Copyright (C) 2010 NetUP Inc. - * Copyright (C) 2010 Igor M. Liplianin - * - * 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 of the License, 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. - */ - -#ifndef _ALTERA_H_ -#define _ALTERA_H_ - -struct altera_config { - void *dev; - u8 *action; - int (*jtag_io) (void *dev, int tms, int tdi, int tdo); -}; - -#if defined(CONFIG_ALTERA_STAPL) || \ - (defined(CONFIG_ALTERA_STAPL_MODULE) && defined(MODULE)) - -extern int altera_init(struct altera_config *config, const struct firmware *fw); -#else - -static inline int altera_init(struct altera_config *config, - const struct firmware *fw) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return 0; -} -#endif /* CONFIG_ALTERA_STAPL */ - -#endif /* _ALTERA_H_ */ diff --git a/include/misc/altera.h b/include/misc/altera.h new file mode 100644 index 0000000..94c0c61 --- /dev/null +++ b/include/misc/altera.h @@ -0,0 +1,49 @@ +/* + * altera.h + * + * altera FPGA driver + * + * Copyright (C) Altera Corporation 1998-2001 + * Copyright (C) 2010 NetUP Inc. + * Copyright (C) 2010 Igor M. Liplianin + * + * 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 of the License, 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. + */ + +#ifndef _ALTERA_H_ +#define _ALTERA_H_ + +struct altera_config { + void *dev; + u8 *action; + int (*jtag_io) (void *dev, int tms, int tdi, int tdo); +}; + +#if defined(CONFIG_ALTERA_STAPL) || \ + (defined(CONFIG_ALTERA_STAPL_MODULE) && defined(MODULE)) + +extern int altera_init(struct altera_config *config, const struct firmware *fw); +#else + +static inline int altera_init(struct altera_config *config, + const struct firmware *fw) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} +#endif /* CONFIG_ALTERA_STAPL */ + +#endif /* _ALTERA_H_ */ -- cgit v0.10.2 From 1f28291c2cf41e1078e9d1306044e0d4bac41795 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Thu, 22 Sep 2011 03:44:57 -0300 Subject: [media] staging: dt3155v4l: fix build break This patch fixes build break caused by commit ba7fcb0c9549 ("[media] media: vb2: dma contig allocator: use dma_addr instread of paddr"). Signed-off-by: Marek Szyprowski Cc: Greg KH Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/dt3155v4l/dt3155v4l.c b/drivers/staging/dt3155v4l/dt3155v4l.c index 05aa41c..0ede5d1 100644 --- a/drivers/staging/dt3155v4l/dt3155v4l.c +++ b/drivers/staging/dt3155v4l/dt3155v4l.c @@ -207,7 +207,7 @@ dt3155_start_acq(struct dt3155_priv *pd) struct vb2_buffer *vb = pd->curr_buf; dma_addr_t dma_addr; - dma_addr = vb2_dma_contig_plane_paddr(vb, 0); + dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); iowrite32(dma_addr, pd->regs + EVEN_DMA_START); iowrite32(dma_addr + img_width, pd->regs + ODD_DMA_START); iowrite32(img_width, pd->regs + EVEN_DMA_STRIDE); @@ -374,7 +374,7 @@ dt3155_irq_handler_even(int irq, void *dev_id) ivb = list_first_entry(&ipd->dmaq, typeof(*ivb), done_entry); list_del(&ivb->done_entry); ipd->curr_buf = ivb; - dma_addr = vb2_dma_contig_plane_paddr(ivb, 0); + dma_addr = vb2_dma_contig_plane_dma_addr(ivb, 0); iowrite32(dma_addr, ipd->regs + EVEN_DMA_START); iowrite32(dma_addr + img_width, ipd->regs + ODD_DMA_START); iowrite32(img_width, ipd->regs + EVEN_DMA_STRIDE); -- cgit v0.10.2 From 547d42eac107f027e6101b828f9e4075f2fbcc7c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Sep 2011 15:33:27 -0300 Subject: [media] rc tables: include linux/module.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prevents errors when merging with -next: drivers/media/rc/keymaps/rc-snapstream-firefly.c:105:16: error: expected declaration specifiers or ‘...’ before string constant drivers/media/rc/keymaps/rc-snapstream-firefly.c:106:15: error: expected declaration specifiers or ‘...’ before string constant Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/keymaps/rc-ati-x10.c b/drivers/media/rc/keymaps/rc-ati-x10.c index f3397f8..e1b8b26 100644 --- a/drivers/media/rc/keymaps/rc-ati-x10.c +++ b/drivers/media/rc/keymaps/rc-ati-x10.c @@ -23,6 +23,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #include static struct rc_map_table ati_x10[] = { diff --git a/drivers/media/rc/keymaps/rc-medion-x10.c b/drivers/media/rc/keymaps/rc-medion-x10.c index 5fc57468..09e2cc0 100644 --- a/drivers/media/rc/keymaps/rc-medion-x10.c +++ b/drivers/media/rc/keymaps/rc-medion-x10.c @@ -21,6 +21,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #include static struct rc_map_table medion_x10[] = { diff --git a/drivers/media/rc/keymaps/rc-snapstream-firefly.c b/drivers/media/rc/keymaps/rc-snapstream-firefly.c index 5836aa2..ef14652 100644 --- a/drivers/media/rc/keymaps/rc-snapstream-firefly.c +++ b/drivers/media/rc/keymaps/rc-snapstream-firefly.c @@ -18,6 +18,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #include static struct rc_map_table snapstream_firefly[] = { -- cgit v0.10.2 From fd3e9f2f9a4c46f5d67d384c78b2d364c99d3de6 Mon Sep 17 00:00:00 2001 From: Arne Caspari Date: Sat, 30 Jul 2011 08:29:11 -0300 Subject: [media] uvcvideo: Detect The Imaging Source CCD cameras by vendor and product ID The Imaging Source CCD cameras use a vendor specific interface class even though they are actually UVC compliant. Signed-off-by: Arne Caspari Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index e4100b1..a3c24dd 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c @@ -2331,6 +2331,14 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_PROBE_DEF }, + /* The Imaging Source USB CCD cameras */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x199e, + .idProduct = 0x8102, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0 }, /* Bodelin ProScopeHR */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_HI -- cgit v0.10.2 From 227bd5b3539a50290ec48b90c42c40cc7ae27191 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 30 Jul 2011 16:19:49 -0300 Subject: [media] uvcvideo: Remove deprecated UVCIOC ioctls The UVCIOC_CTRL_ADD, UVCIOC_CTRL_MAP_OLD, UVCIOC_CTRL_GET and UVCIOC_CTRL_SET ioctls are deprecated and were scheduled for removal for v2.6.42. As v2.6.42 == v3.2, remove them. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 4dc4654..ead08f1 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -495,29 +495,6 @@ Who: Jean Delvare ---------------------------- -What: Support for UVCIOC_CTRL_ADD in the uvcvideo driver -When: 3.2 -Why: The information passed to the driver by this ioctl is now queried - dynamically from the device. -Who: Laurent Pinchart - ----------------------------- - -What: Support for UVCIOC_CTRL_MAP_OLD in the uvcvideo driver -When: 3.2 -Why: Used only by applications compiled against older driver versions. - Superseded by UVCIOC_CTRL_MAP which supports V4L2 menu controls. -Who: Laurent Pinchart - ----------------------------- - -What: Support for UVCIOC_CTRL_GET and UVCIOC_CTRL_SET in the uvcvideo driver -When: 3.2 -Why: Superseded by the UVCIOC_CTRL_QUERY ioctl. -Who: Laurent Pinchart - ----------------------------- - What: Support for driver specific ioctls in the pwc driver (everything defined in media/pwc-ioctl.h) When: 3.3 diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c index ea71d5f..dadf11f 100644 --- a/drivers/media/video/uvc/uvc_v4l2.c +++ b/drivers/media/video/uvc/uvc_v4l2.c @@ -32,7 +32,7 @@ * UVC ioctls */ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain, - struct uvc_xu_control_mapping *xmap, int old) + struct uvc_xu_control_mapping *xmap) { struct uvc_control_mapping *map; unsigned int size; @@ -58,13 +58,6 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain, break; case V4L2_CTRL_TYPE_MENU: - if (old) { - uvc_trace(UVC_TRACE_CONTROL, "V4L2_CTRL_TYPE_MENU not " - "supported for UVCIOC_CTRL_MAP_OLD.\n"); - ret = -EINVAL; - goto done; - } - size = xmap->menu_count * sizeof(*map->menu_info); map->menu_info = kmalloc(size, GFP_KERNEL); if (map->menu_info == NULL) { @@ -538,20 +531,6 @@ static int uvc_v4l2_release(struct file *file) return 0; } -static void uvc_v4l2_ioctl_warn(void) -{ - static int warned; - - if (warned) - return; - - uvc_printk(KERN_INFO, "Deprecated UVCIOC_CTRL_{ADD,MAP_OLD,GET,SET} " - "ioctls will be removed in 2.6.42.\n"); - uvc_printk(KERN_INFO, "See http://www.ideasonboard.org/uvc/upgrade/ " - "for upgrade instructions.\n"); - warned = 1; -} - static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct video_device *vdev = video_devdata(file); @@ -1032,37 +1011,8 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) uvc_trace(UVC_TRACE_IOCTL, "Unsupported ioctl 0x%08x\n", cmd); return -EINVAL; - /* Dynamic controls. UVCIOC_CTRL_ADD, UVCIOC_CTRL_MAP_OLD, - * UVCIOC_CTRL_GET and UVCIOC_CTRL_SET are deprecated and scheduled for - * removal in 2.6.42. - */ - case __UVCIOC_CTRL_ADD: - uvc_v4l2_ioctl_warn(); - return -EEXIST; - - case __UVCIOC_CTRL_MAP_OLD: - uvc_v4l2_ioctl_warn(); - case __UVCIOC_CTRL_MAP: case UVCIOC_CTRL_MAP: - return uvc_ioctl_ctrl_map(chain, arg, - cmd == __UVCIOC_CTRL_MAP_OLD); - - case __UVCIOC_CTRL_GET: - case __UVCIOC_CTRL_SET: - { - struct uvc_xu_control *xctrl = arg; - struct uvc_xu_control_query xqry = { - .unit = xctrl->unit, - .selector = xctrl->selector, - .query = cmd == __UVCIOC_CTRL_GET - ? UVC_GET_CUR : UVC_SET_CUR, - .size = xctrl->size, - .data = xctrl->data, - }; - - uvc_v4l2_ioctl_warn(); - return uvc_xu_ctrl_query(chain, &xqry); - } + return uvc_ioctl_ctrl_map(chain, arg); case UVCIOC_CTRL_QUERY: return uvc_xu_ctrl_query(chain, arg); diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index cbdd49b..e3aec87 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h @@ -1,106 +1,16 @@ #ifndef _USB_VIDEO_H_ #define _USB_VIDEO_H_ -#include -#include - -#ifndef __KERNEL__ -/* - * This header provides binary compatibility with applications using the private - * uvcvideo API. This API is deprecated and will be removed in 2.6.42. - * Applications should be recompiled against the public linux/uvcvideo.h header. - */ -#warn "The uvcvideo.h header is deprecated, use linux/uvcvideo.h instead." - -/* - * Dynamic controls - */ - -/* Data types for UVC control data */ -#define UVC_CTRL_DATA_TYPE_RAW 0 -#define UVC_CTRL_DATA_TYPE_SIGNED 1 -#define UVC_CTRL_DATA_TYPE_UNSIGNED 2 -#define UVC_CTRL_DATA_TYPE_BOOLEAN 3 -#define UVC_CTRL_DATA_TYPE_ENUM 4 -#define UVC_CTRL_DATA_TYPE_BITMASK 5 - -/* Control flags */ -#define UVC_CONTROL_SET_CUR (1 << 0) -#define UVC_CONTROL_GET_CUR (1 << 1) -#define UVC_CONTROL_GET_MIN (1 << 2) -#define UVC_CONTROL_GET_MAX (1 << 3) -#define UVC_CONTROL_GET_RES (1 << 4) -#define UVC_CONTROL_GET_DEF (1 << 5) -#define UVC_CONTROL_RESTORE (1 << 6) -#define UVC_CONTROL_AUTO_UPDATE (1 << 7) - -#define UVC_CONTROL_GET_RANGE (UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_MIN | \ - UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | \ - UVC_CONTROL_GET_DEF) - -struct uvc_menu_info { - __u32 value; - __u8 name[32]; -}; - -struct uvc_xu_control_mapping { - __u32 id; - __u8 name[32]; - __u8 entity[16]; - __u8 selector; - - __u8 size; - __u8 offset; - __u32 v4l2_type; - __u32 data_type; - - struct uvc_menu_info __user *menu_info; - __u32 menu_count; - - __u32 reserved[4]; -}; - -#endif - -struct uvc_xu_control_info { - __u8 entity[16]; - __u8 index; - __u8 selector; - __u16 size; - __u32 flags; -}; - -struct uvc_xu_control_mapping_old { - __u8 reserved[64]; -}; - -struct uvc_xu_control { - __u8 unit; - __u8 selector; - __u16 size; - __u8 __user *data; -}; - #ifndef __KERNEL__ -#define UVCIOC_CTRL_ADD _IOW('U', 1, struct uvc_xu_control_info) -#define UVCIOC_CTRL_MAP_OLD _IOWR('U', 2, struct uvc_xu_control_mapping_old) -#define UVCIOC_CTRL_MAP _IOWR('U', 2, struct uvc_xu_control_mapping) -#define UVCIOC_CTRL_GET _IOWR('U', 3, struct uvc_xu_control) -#define UVCIOC_CTRL_SET _IOW('U', 4, struct uvc_xu_control) -#else -#define __UVCIOC_CTRL_ADD _IOW('U', 1, struct uvc_xu_control_info) -#define __UVCIOC_CTRL_MAP_OLD _IOWR('U', 2, struct uvc_xu_control_mapping_old) -#define __UVCIOC_CTRL_MAP _IOWR('U', 2, struct uvc_xu_control_mapping) -#define __UVCIOC_CTRL_GET _IOWR('U', 3, struct uvc_xu_control) -#define __UVCIOC_CTRL_SET _IOW('U', 4, struct uvc_xu_control) -#endif - -#ifdef __KERNEL__ +#error "The uvcvideo.h header is deprecated, use linux/uvcvideo.h instead." +#endif /* __KERNEL__ */ +#include #include #include #include #include +#include #include #include @@ -698,6 +608,4 @@ extern struct usb_host_endpoint *uvc_find_endpoint( void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream, struct uvc_buffer *buf); -#endif /* __KERNEL__ */ - #endif -- cgit v0.10.2 From 3e0ac6717b0a2593243ef3850025a42cb199880f Mon Sep 17 00:00:00 2001 From: Al Cooper Date: Thu, 18 Aug 2011 10:28:29 -0300 Subject: [media] media: Fix a UVC performance problem on systems with non-coherent DMA The UVC driver uses usb_alloc_coherent() to allocate DMA data buffers. On systems without coherent DMA this ends up allocating buffers in uncached memory. The subsequent memcpy's done to coalesce the DMA chunks into contiguous buffers then run VERY slowly. On a MIPS test system the memcpy is about 200 times slower. This issue prevents the system from keeping up with 720p YUYV data at 10fps. The following patch uses kmalloc to alloc the DMA buffers instead of usb_alloc_coherent on systems without coherent DMA. With this patch the system was easily able to keep up with 720p at 10fps. Signed-off-by: Al Cooper Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index ffd1158..b015e8e 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c @@ -790,8 +790,12 @@ static void uvc_free_urb_buffers(struct uvc_streaming *stream) for (i = 0; i < UVC_URBS; ++i) { if (stream->urb_buffer[i]) { +#ifndef CONFIG_DMA_NONCOHERENT usb_free_coherent(stream->dev->udev, stream->urb_size, stream->urb_buffer[i], stream->urb_dma[i]); +#else + kfree(stream->urb_buffer[i]); +#endif stream->urb_buffer[i] = NULL; } } @@ -831,9 +835,14 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream, for (; npackets > 1; npackets /= 2) { for (i = 0; i < UVC_URBS; ++i) { stream->urb_size = psize * npackets; +#ifndef CONFIG_DMA_NONCOHERENT stream->urb_buffer[i] = usb_alloc_coherent( stream->dev->udev, stream->urb_size, gfp_flags | __GFP_NOWARN, &stream->urb_dma[i]); +#else + stream->urb_buffer[i] = + kmalloc(stream->urb_size, gfp_flags | __GFP_NOWARN); +#endif if (!stream->urb_buffer[i]) { uvc_free_urb_buffers(stream); break; @@ -908,10 +917,14 @@ static int uvc_init_video_isoc(struct uvc_streaming *stream, urb->context = stream; urb->pipe = usb_rcvisocpipe(stream->dev->udev, ep->desc.bEndpointAddress); +#ifndef CONFIG_DMA_NONCOHERENT urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; + urb->transfer_dma = stream->urb_dma[i]; +#else + urb->transfer_flags = URB_ISO_ASAP; +#endif urb->interval = ep->desc.bInterval; urb->transfer_buffer = stream->urb_buffer[i]; - urb->transfer_dma = stream->urb_dma[i]; urb->complete = uvc_video_complete; urb->number_of_packets = npackets; urb->transfer_buffer_length = size; @@ -969,8 +982,10 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream, usb_fill_bulk_urb(urb, stream->dev->udev, pipe, stream->urb_buffer[i], size, uvc_video_complete, stream); +#ifndef CONFIG_DMA_NONCOHERENT urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; urb->transfer_dma = stream->urb_dma[i]; +#endif stream->urb[i] = urb; } -- cgit v0.10.2 From 25ad8a8ddeeb26c77728c806a5f66608c9baa986 Mon Sep 17 00:00:00 2001 From: Stephan Lachowsky Date: Fri, 28 Jan 2011 16:38:58 -0300 Subject: [media] uvcvideo: Add a mapping for H.264 payloads Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index a3c24dd..656d4c9 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c @@ -114,6 +114,11 @@ static struct uvc_format_desc uvc_fmts[] = { .guid = UVC_GUID_FORMAT_RGBP, .fcc = V4L2_PIX_FMT_RGB565, }, + { + .name = "H.264", + .guid = UVC_GUID_FORMAT_H264, + .fcc = V4L2_PIX_FMT_H264, + }, }; /* ------------------------------------------------------------------------ diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index e3aec87..4c1392e 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h @@ -89,6 +89,10 @@ { 'M', '4', '2', '0', 0x00, 0x00, 0x10, 0x00, \ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_H264 \ + { 'H', '2', '6', '4', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} + /* ------------------------------------------------------------------------ * Driver specific constants. */ -- cgit v0.10.2 From 1cd7acc4ef5459dd92d0d04430d353de0a54b393 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 28 Jan 2011 06:23:57 -0300 Subject: USB: export video.h to the includes available for userspace The uvcvideo extension unit API requires constants defined in the video.h header. Add it to the list of includes exported to userspace. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/include/linux/usb/Kbuild b/include/linux/usb/Kbuild index ed91fb6..b607f35 100644 --- a/include/linux/usb/Kbuild +++ b/include/linux/usb/Kbuild @@ -7,3 +7,4 @@ header-y += gadgetfs.h header-y += midi.h header-y += g_printer.h header-y += tmc.h +header-y += video.h -- cgit v0.10.2 From 8c0bc03c80952e81db8cb11082c0c6375e9083ab Mon Sep 17 00:00:00 2001 From: Jose Alberto Reguero Date: Sun, 18 Sep 2011 07:59:05 -0300 Subject: [media] ttusb2: TT CT-3650 CI support Signed-off-by: Jose Alberto Reguero Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c index 7b07cf6..ea4eab8 100644 --- a/drivers/media/dvb/dvb-usb/ttusb2.c +++ b/drivers/media/dvb/dvb-usb/ttusb2.c @@ -33,16 +33,40 @@ #include "tda10048.h" #include "tda827x.h" #include "lnbp21.h" +/* CA */ +#include "dvb_ca_en50221.h" /* debug */ static int dvb_usb_ttusb2_debug; #define deb_info(args...) dprintk(dvb_usb_ttusb2_debug,0x01,args) module_param_named(debug,dvb_usb_ttusb2_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))." DVB_USB_DEBUG_STATUS); +static int dvb_usb_ttusb2_debug_ci; +module_param_named(debug_ci,dvb_usb_ttusb2_debug_ci, int, 0644); +MODULE_PARM_DESC(debug_ci, "set debugging ci." DVB_USB_DEBUG_STATUS); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); +#define ci_dbg(format, arg...) \ +do { \ + if (dvb_usb_ttusb2_debug_ci) \ + printk(KERN_DEBUG DVB_USB_LOG_PREFIX \ + ": %s " format "\n" , __func__, ## arg); \ +} while (0) + +enum { + TT3650_CMD_CI_TEST = 0x40, + TT3650_CMD_CI_RD_CTRL, + TT3650_CMD_CI_WR_CTRL, + TT3650_CMD_CI_RD_ATTR, + TT3650_CMD_CI_WR_ATTR, + TT3650_CMD_CI_RESET, + TT3650_CMD_CI_SET_VIDEO_PORT +}; + struct ttusb2_state { + struct dvb_ca_en50221 ca; + struct mutex ca_mutex; u8 id; u16 last_rc_key; }; @@ -79,6 +103,255 @@ static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd, return 0; } +/* ci */ +static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len) +{ + int ret; + u8 rx[60];/* (64 -4) */ + ret = ttusb2_msg(d, cmd, data, write_len, rx, read_len); + if (!ret) + memcpy(data, rx, read_len); + return ret; +} + +static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca, u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len) +{ + struct dvb_usb_device *d = ca->data; + struct ttusb2_state *state = d->priv; + int ret; + + mutex_lock(&state->ca_mutex); + ret = tt3650_ci_msg(d, cmd, data, write_len, read_len); + mutex_unlock(&state->ca_mutex); + + return ret; +} + +static int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) +{ + u8 buf[3]; + int ret = 0; + + if (slot) + return -EINVAL; + + buf[0] = (address >> 8) & 0x0F; + buf[1] = address; + + + ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3); + + ci_dbg("%04x -> %d 0x%02x", address, ret, buf[2]); + + if (ret < 0) + return ret; + + return buf[2]; +} + +static int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value) +{ + u8 buf[3]; + + ci_dbg("%d 0x%04x 0x%02x", slot, address, value); + + if (slot) + return -EINVAL; + + buf[0] = (address >> 8) & 0x0F; + buf[1] = address; + buf[2] = value; + + return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3); +} + +static int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address) +{ + u8 buf[2]; + int ret; + + if (slot) + return -EINVAL; + + buf[0] = address & 3; + + ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2); + + ci_dbg("0x%02x -> %d 0x%02x", address, ret, buf[1]); + + if (ret < 0) + return ret; + + return buf[1]; +} + +static int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value) +{ + u8 buf[2]; + + ci_dbg("%d 0x%02x 0x%02x", slot, address, value); + + if (slot) + return -EINVAL; + + buf[0] = address; + buf[1] = value; + + return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2); +} + +static int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca, int slot, int enable) +{ + u8 buf[1]; + int ret; + + ci_dbg("%d %d", slot, enable); + + if (slot) + return -EINVAL; + + buf[0] = enable; + + ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1); + if (ret < 0) + return ret; + + if (enable != buf[0]) { + err("CI not %sabled.", enable ? "en" : "dis"); + return -EIO; + } + + return 0; +} + +static int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) +{ + return tt3650_ci_set_video_port(ca, slot, 0); +} + +static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) +{ + return tt3650_ci_set_video_port(ca, slot, 1); +} + +static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot) +{ + struct dvb_usb_device *d = ca->data; + struct ttusb2_state *state = d->priv; + u8 buf[1]; + int ret; + + ci_dbg("%d", slot); + + if (slot) + return -EINVAL; + + buf[0] = 0; + + mutex_lock(&state->ca_mutex); + + ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1); + if (ret) + goto failed; + + msleep(500); + + buf[0] = 1; + + ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1); + if (ret) + goto failed; + + msleep(500); + + buf[0] = 0; /* FTA */ + + ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1); + + msleep(1100); + + failed: + mutex_unlock(&state->ca_mutex); + + return ret; +} + +static int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) +{ + u8 buf[1]; + int ret; + + if (slot) + return -EINVAL; + + ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1); + if (ret) + return ret; + + if (1 == buf[0]) { + return DVB_CA_EN50221_POLL_CAM_PRESENT | + DVB_CA_EN50221_POLL_CAM_READY; + } + return 0; +} + +static void tt3650_ci_uninit(struct dvb_usb_device *d) +{ + struct ttusb2_state *state; + + ci_dbg(""); + + if (NULL == d) + return; + + state = d->priv; + if (NULL == state) + return; + + if (NULL == state->ca.data) + return; + + dvb_ca_en50221_release(&state->ca); + + memset(&state->ca, 0, sizeof(state->ca)); +} + +static int tt3650_ci_init(struct dvb_usb_adapter *a) +{ + struct dvb_usb_device *d = a->dev; + struct ttusb2_state *state = d->priv; + int ret; + + ci_dbg(""); + + mutex_init(&state->ca_mutex); + + state->ca.owner = THIS_MODULE; + state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem; + state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem; + state->ca.read_cam_control = tt3650_ci_read_cam_control; + state->ca.write_cam_control = tt3650_ci_write_cam_control; + state->ca.slot_reset = tt3650_ci_slot_reset; + state->ca.slot_shutdown = tt3650_ci_slot_shutdown; + state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable; + state->ca.poll_slot_status = tt3650_ci_poll_slot_status; + state->ca.data = d; + + ret = dvb_ca_en50221_init(&a->dvb_adap, + &state->ca, + /* flags */ 0, + /* n_slots */ 1); + if (ret) { + err("Cannot initialize CI: Error %d.", ret); + memset(&state->ca, 0, sizeof(state->ca)); + return ret; + } + + info("CI initialized."); + + return 0; +} + static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); @@ -251,6 +524,7 @@ static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap) deb_info("TDA10023 attach failed\n"); return -ENODEV; } + tt3650_ci_init(adap); } else { adap->fe_adap[1].fe = dvb_attach(tda10048_attach, &tda10048_config, &adap->dev->i2c_adap); @@ -305,6 +579,14 @@ static struct dvb_usb_device_properties ttusb2_properties; static struct dvb_usb_device_properties ttusb2_properties_s2400; static struct dvb_usb_device_properties ttusb2_properties_ct3650; +static void ttusb2_usb_disconnect(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + + tt3650_ci_uninit(d); + dvb_usb_device_exit(intf); +} + static int ttusb2_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -513,7 +795,7 @@ static struct dvb_usb_device_properties ttusb2_properties_ct3650 = { static struct usb_driver ttusb2_driver = { .name = "dvb_usb_ttusb2", .probe = ttusb2_probe, - .disconnect = dvb_usb_device_exit, + .disconnect = ttusb2_usb_disconnect, .id_table = ttusb2_table, }; -- cgit v0.10.2 From eb39a303d5561dd7d07af9052f6dd596dfdcf275 Mon Sep 17 00:00:00 2001 From: Manjunath Hadli Date: Mon, 19 Sep 2011 01:35:26 -0300 Subject: [media] davinci vpbe: remove unused macro remove VPBE_DISPLAY_SD_BUF_SIZE as it is no longer used. Signed-off-by: Manjunath Hadli Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/davinci/vpbe_display.c b/drivers/media/video/davinci/vpbe_display.c index 7f1d83a..8588a86 100644 --- a/drivers/media/video/davinci/vpbe_display.c +++ b/drivers/media/video/davinci/vpbe_display.c @@ -43,7 +43,6 @@ static int debug; -#define VPBE_DISPLAY_SD_BUF_SIZE (720*576*2) #define VPBE_DEFAULT_NUM_BUFS 3 module_param(debug, int, 0644); -- cgit v0.10.2 From 69967a71ae6ebe7aace94ef15f269b8bf2b5ce1e Mon Sep 17 00:00:00 2001 From: Martin Hostettler Date: Mon, 19 Sep 2011 02:04:56 -0300 Subject: [media] v4l subdev: add dispatching for VIDIOC_DBG_G_REGISTER and VIDIOC_DBG_S_REGISTER Ioctls on the subdevs node currently don't dispatch the register access debug driver callbacks. Add the dispatching with the same security checks are for non subdev video nodes (i.e. only capable(CAP_SYS_ADMIN may call the register access ioctls). Signed-off-by: Martin Hostettler Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c index b7967c9..179e20e 100644 --- a/drivers/media/video/v4l2-subdev.c +++ b/drivers/media/video/v4l2-subdev.c @@ -173,6 +173,25 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_UNSUBSCRIBE_EVENT: return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg); + +#ifdef CONFIG_VIDEO_ADV_DEBUG + case VIDIOC_DBG_G_REGISTER: + { + struct v4l2_dbg_register *p = arg; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + return v4l2_subdev_call(sd, core, g_register, p); + } + case VIDIOC_DBG_S_REGISTER: + { + struct v4l2_dbg_register *p = arg; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + return v4l2_subdev_call(sd, core, s_register, p); + } +#endif #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) case VIDIOC_SUBDEV_G_FMT: { struct v4l2_subdev_format *format = arg; -- cgit v0.10.2 From 7b1c8f58fcdbed75903943705ef41816e9648c1b Mon Sep 17 00:00:00 2001 From: Arvydas Sidorenko Date: Wed, 21 Sep 2011 10:58:31 -0300 Subject: [media] stk-webcam.c: webcam LED bug fix This is an improved version of the patch I sent a little ago. The problem was: On my DC-1125 webcam chip from Syntek, whenever the webcam turns on, the LED light on it is turned on also and never turns off again unless system is shut downed or restarted. The previous version seemed to break some other laptop webcam work. Thanks to Andrea Anacleto for the bug report and solution. Signed-off-by: Andrea Anacleto Signed-off-by: Arvydas Sidorenko Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c index 5fc6bbc..cbc105f 100644 --- a/drivers/media/video/stk-webcam.c +++ b/drivers/media/video/stk-webcam.c @@ -55,6 +55,8 @@ MODULE_AUTHOR("Jaime Velasco Juan and Nicolas VIVIEN"); MODULE_DESCRIPTION("Syntek DC1125 webcam driver"); +/* bool for webcam LED management */ +int first_init = 1; /* Some cameras have audio interfaces, we aren't interested in those */ static struct usb_device_id stkwebcam_table[] = { @@ -560,6 +562,12 @@ static int v4l_stk_open(struct file *fp) if (dev == NULL || !is_present(dev)) return -ENXIO; + + if (!first_init) + stk_camera_write_reg(dev, 0x0, 0x24); + else + first_init = 0; + fp->private_data = dev; usb_autopm_get_interface(dev->interface); @@ -573,7 +581,7 @@ static int v4l_stk_release(struct file *fp) if (dev->owner == fp) { stk_stop_stream(dev); stk_free_buffers(dev); - stk_camera_write_reg(dev, 0x0, 0x48); /* turn off the LED */ + stk_camera_write_reg(dev, 0x0, 0x49); /* turn off the LED */ unset_initialised(dev); dev->owner = NULL; } @@ -1350,6 +1358,7 @@ static int stk_camera_resume(struct usb_interface *intf) return 0; unset_initialised(dev); stk_initialise(dev); + stk_camera_write_reg(dev, 0x0, 0x49); stk_setup_format(dev); if (is_streaming(dev)) stk_start_stream(dev); -- cgit v0.10.2 From 2ba0f94796febc26bbb12095f6ad15c2397de474 Mon Sep 17 00:00:00 2001 From: tvboxspy Date: Wed, 21 Sep 2011 18:57:41 -0300 Subject: [media] it913x: add remote control support Add remote support for KWORLD UB499-2T-T09 The remote supplied is the same as KWORLD_315U. Signed-off-by: Malcolm Priestley Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/it913x.c b/drivers/media/dvb/dvb-usb/it913x.c index 6d2f281..f027a2c 100644 --- a/drivers/media/dvb/dvb-usb/it913x.c +++ b/drivers/media/dvb/dvb-usb/it913x.c @@ -306,6 +306,30 @@ static struct i2c_algorithm it913x_i2c_algo = { }; /* Callbacks for DVB USB */ +#define IT913X_POLL 250 +static int it913x_rc_query(struct dvb_usb_device *d) +{ + u8 ibuf[4]; + int ret; + u32 key; + /* Avoid conflict with frontends*/ + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + ret = it913x_io(d->udev, READ_LONG, PRO_LINK, CMD_IR_GET, + 0, 0, &ibuf[0], sizeof(ibuf)); + + if ((ibuf[2] + ibuf[3]) == 0xff) { + key = ibuf[2]; + key += ibuf[0] << 8; + deb_info(1, "INT Key =%08x", key); + if (d->rc_dev != NULL) + rc_keydown(d->rc_dev, key, 0); + } + mutex_unlock(&d->i2c_mutex); + + return ret; +} static int it913x_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props, struct dvb_usb_device_description **desc, @@ -575,6 +599,14 @@ static struct dvb_usb_device_properties it913x_properties = { } }, .identify_state = it913x_identify_state, + .rc.core = { + .protocol = RC_TYPE_NEC, + .module_name = "it913x", + .rc_query = it913x_rc_query, + .rc_interval = IT913X_POLL, + .allowed_protos = RC_TYPE_NEC, + .rc_codes = RC_MAP_KWORLD_315U, + }, .i2c_algo = &it913x_i2c_algo, .num_device_descs = 1, .devices = { @@ -615,5 +647,5 @@ module_exit(it913x_module_exit); MODULE_AUTHOR("Malcolm Priestley "); MODULE_DESCRIPTION("it913x USB 2 Driver"); -MODULE_VERSION("1.05"); +MODULE_VERSION("1.06"); MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 7c2808e2fd4c30a19268215c2958d4a340f057c5 Mon Sep 17 00:00:00 2001 From: tvboxspy Date: Wed, 21 Sep 2011 19:06:58 -0300 Subject: [media] it913x-fe: correct tuner settings Correct tuner settings for more accuracy. This now makes the tuner section more compatible with other versions of the IT913X series. TODOs Version 2 chip Signed-off-by: Malcolm Priestley Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/frontends/it913x-fe-priv.h b/drivers/media/dvb/frontends/it913x-fe-priv.h index b80634ab..40e1d9b 100644 --- a/drivers/media/dvb/frontends/it913x-fe-priv.h +++ b/drivers/media/dvb/frontends/it913x-fe-priv.h @@ -316,27 +316,13 @@ static struct it913xset it9137_set[] = { {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ }; -static struct it913xset it9137_tuner[] = { - {PRO_DMOD, 0xec57, {0x00}, 0x01}, - {PRO_DMOD, 0xec58, {0x00}, 0x01}, - {PRO_DMOD, 0xec40, {0x00}, 0x01}, - {PRO_DMOD, 0xec02, { 0x00, 0x0c, 0x00, 0x40, 0x00, 0x80, 0x80, - 0x00, 0x00, 0x00, 0x00 }, 0x0b}, - {PRO_DMOD, 0xec0d, { 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 }, 0x0b}, - {PRO_DMOD, 0xec19, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00}, 0x08}, - {PRO_DMOD, 0xec22, { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00 }, 0x0a}, - {PRO_DMOD, 0xec3f, {0x01}, 0x01}, - /* Clear any existing tune */ - {PRO_DMOD, 0xec4c, {0xa8, 0x00, 0x00, 0x00, 0x00}, 0x05}, - {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ -}; - static struct it913xset set_it9137_template[] = { {PRO_DMOD, 0xee06, {0x00}, 0x01}, {PRO_DMOD, 0xec56, {0x00}, 0x01}, - {PRO_DMOD, 0xec4c, {0x00, 0x00, 0x00, 0x00, 0x00}, 0x05}, + {PRO_DMOD, 0xec4c, {0x00}, 0x01}, + {PRO_DMOD, 0xec4d, {0x00}, 0x01}, + {PRO_DMOD, 0xec4e, {0x00}, 0x01}, + {PRO_DMOD, 0xec4f, {0x00}, 0x01}, + {PRO_DMOD, 0xec50, {0x00}, 0x01}, {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ }; diff --git a/drivers/media/dvb/frontends/it913x-fe.c b/drivers/media/dvb/frontends/it913x-fe.c index c92b3ec..02839a8b7 100644 --- a/drivers/media/dvb/frontends/it913x-fe.c +++ b/drivers/media/dvb/frontends/it913x-fe.c @@ -58,6 +58,10 @@ struct it913x_fe_state { u8 tuner_type; struct adctable *table; fe_status_t it913x_status; + u16 tun_xtal; + u8 tun_fdiv; + u8 tun_clk_mode; + u32 tun_fn_min; }; static int it913x_read_reg(struct it913x_fe_state *state, @@ -159,13 +163,74 @@ static int it913x_fe_script_loader(struct it913x_fe_state *state, return 0; } +static int it913x_init_tuner(struct it913x_fe_state *state) +{ + int ret, i, reg; + u8 val, nv_val; + u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2}; + u8 b[2]; + + reg = it913x_read_reg_u8(state, 0xec86); + switch (reg) { + case 0: + state->tun_clk_mode = reg; + state->tun_xtal = 2000; + state->tun_fdiv = 3; + val = 16; + break; + case -ENODEV: + return -ENODEV; + case 1: + default: + state->tun_clk_mode = reg; + state->tun_xtal = 640; + state->tun_fdiv = 1; + val = 6; + break; + } + + reg = it913x_read_reg_u8(state, 0xed03); + + if (reg < 0) + return -ENODEV; + else if (reg < sizeof(nv)) + nv_val = nv[reg]; + else + nv_val = 2; + + for (i = 0; i < 50; i++) { + ret = it913x_read_reg(state, 0xed23, &b[0], sizeof(b)); + reg = (b[1] << 8) + b[0]; + if (reg > 0) + break; + if (ret < 0) + return -ENODEV; + udelay(2000); + } + state->tun_fn_min = state->tun_xtal * reg; + state->tun_fn_min /= (state->tun_fdiv * nv_val); + deb_info("Tuner fn_min %d", state->tun_fn_min); + + for (i = 0; i < 50; i++) { + reg = it913x_read_reg_u8(state, 0xec82); + if (reg > 0) + break; + if (reg < 0) + return -ENODEV; + udelay(2000); + } + + return it913x_write_reg(state, PRO_DMOD, 0xed81, val); +} + static int it9137_set_tuner(struct it913x_fe_state *state, enum fe_bandwidth bandwidth, u32 frequency_m) { struct it913xset *set_tuner = set_it9137_template; - int ret; + int ret, reg; u32 frequency = frequency_m / 1000; - u32 freq; + u32 freq, temp_f, tmp; + u16 iqik_m_cal; u16 n_div; u8 n; u8 l_band; @@ -218,10 +283,11 @@ static int it9137_set_tuner(struct it913x_fe_state *state, bw = 6; else bw = 6; + set_tuner[1].reg[0] = bw; set_tuner[2].reg[0] = 0xa0 | (l_band << 3); - if (frequency > 49000 && frequency <= 74000) { + if (frequency > 53000 && frequency <= 74000) { n_div = 48; n = 0; } else if (frequency > 74000 && frequency <= 111000) { @@ -239,10 +305,10 @@ static int it9137_set_tuner(struct it913x_fe_state *state, } else if (frequency > 296000 && frequency <= 445000) { n_div = 8; n = 5; - } else if (frequency > 445000 && frequency <= 560000) { + } else if (frequency > 445000 && frequency <= state->tun_fn_min) { n_div = 6; n = 6; - } else if (frequency > 560000 && frequency <= 860000) { + } else if (frequency > state->tun_fn_min && frequency <= 950000) { n_div = 4; n = 7; } else if (frequency > 1450000 && frequency <= 1680000) { @@ -251,26 +317,47 @@ static int it9137_set_tuner(struct it913x_fe_state *state, } else return -EINVAL; + reg = it913x_read_reg_u8(state, 0xed81); + iqik_m_cal = (u16)reg * n_div; - /* Frequency + 3000 TODO not sure this is bandwidth setting */ - /* Xtal frequency 21327? but it works */ - freq = (u32) (n_div * 32 * (frequency + 3000) / 21327); - freq += (u32) n << 13; - set_tuner[2].reg[1] = freq & 0xff; - set_tuner[2].reg[2] = (freq >> 8) & 0xff; + if (reg < 0x20) { + if (state->tun_clk_mode == 0) + iqik_m_cal = (iqik_m_cal * 9) >> 5; + else + iqik_m_cal >>= 1; + } else { + iqik_m_cal = 0x40 - iqik_m_cal; + if (state->tun_clk_mode == 0) + iqik_m_cal = ~((iqik_m_cal * 9) >> 5); + else + iqik_m_cal = ~(iqik_m_cal >> 1); + } + + temp_f = frequency * (u32)n_div * (u32)state->tun_fdiv; + freq = temp_f / state->tun_xtal; + tmp = freq * state->tun_xtal; + + if ((temp_f - tmp) >= (state->tun_xtal >> 1)) + freq++; - /* frequency */ - freq = (u32) (n_div * 32 * frequency / 21327); freq += (u32) n << 13; - set_tuner[2].reg[3] = freq & 0xff; - set_tuner[2].reg[4] = (freq >> 8) & 0xff; + /* Frequency OMEGA_IQIK_M_CAL_MID*/ + temp_f = freq + (u32)iqik_m_cal; - deb_info("Frequency = %08x, Bandwidth = %02x, ", freq, bw); + set_tuner[3].reg[0] = temp_f & 0xff; + set_tuner[4].reg[0] = (temp_f >> 8) & 0xff; + + deb_info("High Frequency = %04x", temp_f); + + /* Lower frequency */ + set_tuner[5].reg[0] = freq & 0xff; + set_tuner[6].reg[0] = (freq >> 8) & 0xff; + + deb_info("low Frequency = %04x", freq); ret = it913x_fe_script_loader(state, set_tuner); return (ret < 0) ? -ENODEV : 0; - } static int it913x_fe_select_bw(struct it913x_fe_state *state, @@ -593,6 +680,8 @@ static int it913x_fe_start(struct it913x_fe_state *state) u32 adc, xtal; u8 b[4]; + ret = it913x_init_tuner(state); + if (adf < 12) { state->crystalFrequency = fe_clockTable[adf].xtal ; state->table = fe_clockTable[adf].table; @@ -612,7 +701,6 @@ static int it913x_fe_start(struct it913x_fe_state *state) ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_ON, 0x1); ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x1); - ret |= it913x_write_reg(state, PRO_DMOD, 0xed81, 0x10); ret |= it913x_write_reg(state, PRO_LINK, 0xf641, state->tuner_type); ret |= it913x_write_reg(state, PRO_DMOD, 0xf5ca, 0x01); ret |= it913x_write_reg(state, PRO_DMOD, 0xf715, 0x01); @@ -635,6 +723,7 @@ static int it913x_fe_start(struct it913x_fe_state *state) default: return -EINVAL; } + /* set the demod */ ret = it913x_fe_script_loader(state, set_fe); /* Always solo frontend */ @@ -648,20 +737,8 @@ static int it913x_fe_start(struct it913x_fe_state *state) static int it913x_fe_init(struct dvb_frontend *fe) { struct it913x_fe_state *state = fe->demodulator_priv; - struct it913xset *set_tuner; int ret = 0; - switch (state->tuner_type) { - case IT9137: /* Tuner type 0x38 */ - set_tuner = it9137_tuner; - break; - default: - return -EINVAL; - } - - /* set any tuner reg(s) */ - ret = it913x_fe_script_loader(state, set_tuner); - it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x0); ret |= it913x_fe_script_loader(state, init_1); @@ -743,5 +820,5 @@ static struct dvb_frontend_ops it913x_fe_ofdm_ops = { MODULE_DESCRIPTION("it913x Frontend and it9137 tuner"); MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); -MODULE_VERSION("1.05"); +MODULE_VERSION("1.06"); MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 2d06d5dd2d945780f24169af0ac86e1e03ffee19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Wed, 10 Aug 2011 05:59:15 -0300 Subject: [media] gspca - benq: Remove the useless function sd_isoc_init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sd_isoc_init() did only a set interface which is done in gspca main. Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/benq.c b/drivers/media/video/gspca/benq.c index f4357f7..6ae2616 100644 --- a/drivers/media/video/gspca/benq.c +++ b/drivers/media/video/gspca/benq.c @@ -86,20 +86,6 @@ static int sd_init(struct gspca_dev *gspca_dev) return 0; } -static int sd_isoc_init(struct gspca_dev *gspca_dev) -{ - int ret; - - ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, - gspca_dev->nbalt - 1); - if (ret < 0) { - pr_err("usb_set_interface failed\n"); - return ret; - } -/* reg_w(gspca_dev, 0x0003, 0x0002); */ - return 0; -} - /* -- start the camera -- */ static int sd_start(struct gspca_dev *gspca_dev) { @@ -271,7 +257,6 @@ static const struct sd_desc sd_desc = { .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, - .isoc_init = sd_isoc_init, .start = sd_start, .stopN = sd_stopN, .pkt_scan = sd_pkt_scan, -- cgit v0.10.2 From 27b12023d72207b2d0b38bb9ef4fdb0a3325b682 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Wed, 10 Aug 2011 07:38:48 -0300 Subject: [media] gspca - main: Use a better altsetting for image transfer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously image transfer used to use the highest altsetting, which, most of the time, took the whole USB bandwidth. Now, the altsetting is chosen according to an estimation of the bandwidth needed for image transfer. Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 3ff26ba..ee95448 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -629,53 +629,104 @@ static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt, return NULL; } +/* compute the minimum bandwidth for the current transfer */ +static u32 which_bandwidth(struct gspca_dev *gspca_dev) +{ + u32 bandwidth; + int i; + + i = gspca_dev->curr_mode; + bandwidth = gspca_dev->cam.cam_mode[i].sizeimage; + + /* if the image is compressed, estimate the mean image size */ + if (bandwidth < gspca_dev->cam.cam_mode[i].width * + gspca_dev->cam.cam_mode[i].height) + bandwidth /= 3; + + /* estimate the frame rate */ + if (gspca_dev->sd_desc->get_streamparm) { + struct v4l2_streamparm parm; + + parm.parm.capture.timeperframe.denominator = 15; + gspca_dev->sd_desc->get_streamparm(gspca_dev, &parm); + bandwidth *= parm.parm.capture.timeperframe.denominator; + } else { + bandwidth *= 15; /* 15 fps */ + } + + PDEBUG(D_STREAM, "min bandwidth: %d", bandwidth); + return bandwidth; +} + +/* endpoint table */ +#define MAX_ALT 16 +struct ep_tb_s { + u32 alt; + u32 bandwidth; +}; + /* - * look for an input (isoc or bulk) endpoint - * - * The endpoint is defined by the subdriver. - * Use only the first isoc (some Zoran - 0x0572:0x0001 - have two such ep). - * This routine may be called many times when the bandwidth is too small - * (the bandwidth is checked on urb submit). + * build the table of the endpoints + * and compute the minimum bandwidth for the image transfer */ -static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev) +static int build_ep_tb(struct gspca_dev *gspca_dev, + struct usb_interface *intf, + int xfer, + struct ep_tb_s *ep_tb) { - struct usb_interface *intf; struct usb_host_endpoint *ep; - int xfer, i, ret; + int i, j, nbalt, psize, found; + u32 bandwidth, last_bw; - intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface); - ep = NULL; - xfer = gspca_dev->cam.bulk ? USB_ENDPOINT_XFER_BULK - : USB_ENDPOINT_XFER_ISOC; - i = gspca_dev->alt; /* previous alt setting */ - if (gspca_dev->cam.reverse_alts) { - while (++i < gspca_dev->nbalt) { - ep = alt_xfer(&intf->altsetting[i], xfer); - if (ep) - break; - } - } else { - while (--i >= 0) { - ep = alt_xfer(&intf->altsetting[i], xfer); - if (ep) - break; - } - } - if (ep == NULL) { - pr_err("no transfer endpoint found\n"); - return NULL; - } - PDEBUG(D_STREAM, "use alt %d ep 0x%02x", - i, ep->desc.bEndpointAddress); - gspca_dev->alt = i; /* memorize the current alt setting */ - if (gspca_dev->nbalt > 1) { - ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i); - if (ret < 0) { - pr_err("set alt %d err %d\n", i, ret); - ep = NULL; + nbalt = intf->num_altsetting; + if (nbalt > MAX_ALT) + nbalt = MAX_ALT; /* fixme: should warn */ + + /* build the endpoint table */ + i = 0; + last_bw = 0; + for (;;) { + ep_tb->bandwidth = 2000 * 2000 * 120; + found = 0; + for (j = 0; j < nbalt; j++) { + ep = alt_xfer(&intf->altsetting[j], xfer); + if (ep == NULL) + continue; + psize = le16_to_cpu(ep->desc.wMaxPacketSize); + if (!gspca_dev->cam.bulk) /* isoc */ + psize = (psize & 0x07ff) * + (1 + ((psize >> 11) & 3)); + bandwidth = psize * ep->desc.bInterval * 1000; + if (gspca_dev->dev->speed == USB_SPEED_HIGH + || gspca_dev->dev->speed == USB_SPEED_SUPER) + bandwidth *= 8; + if (bandwidth <= last_bw) + continue; + if (bandwidth < ep_tb->bandwidth) { + ep_tb->bandwidth = bandwidth; + ep_tb->alt = j; + found = 1; + } } + if (!found) + break; + PDEBUG(D_STREAM, "alt %d bandwidth %d", + ep_tb->alt, ep_tb->bandwidth); + last_bw = ep_tb->bandwidth; + i++; + ep_tb++; + } + + /* get the requested bandwidth and start at the highest atlsetting */ + bandwidth = which_bandwidth(gspca_dev); + ep_tb--; + while (i > 1) { + ep_tb--; + if (ep_tb->bandwidth < bandwidth) + break; + i--; } - return ep; + return i; } /* @@ -766,9 +817,11 @@ static int create_urbs(struct gspca_dev *gspca_dev, */ static int gspca_init_transfer(struct gspca_dev *gspca_dev) { + struct usb_interface *intf; struct usb_host_endpoint *ep; struct urb *urb; - int n, ret; + struct ep_tb_s ep_tb[MAX_ALT]; + int n, ret, xfer, alt, alt_idx; if (mutex_lock_interruptible(&gspca_dev->usb_lock)) return -ERESTARTSYS; @@ -786,30 +839,63 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) gspca_dev->usb_err = 0; - /* set the higher alternate setting and - * loop until urb submit succeeds */ - if (gspca_dev->cam.reverse_alts) - gspca_dev->alt = 0; - else - gspca_dev->alt = gspca_dev->nbalt; - + /* do the specific subdriver stuff before endpoint selection */ + gspca_dev->alt = 0; if (gspca_dev->sd_desc->isoc_init) { ret = gspca_dev->sd_desc->isoc_init(gspca_dev); if (ret < 0) goto unlock; } + intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface); + xfer = gspca_dev->cam.bulk ? USB_ENDPOINT_XFER_BULK + : USB_ENDPOINT_XFER_ISOC; - gspca_input_destroy_urb(gspca_dev); - ep = get_ep(gspca_dev); - if (ep == NULL) { - ret = -EIO; - goto out; + /* if the subdriver forced an altsetting, get the endpoint */ + if (gspca_dev->alt != 0) { + gspca_dev->alt--; /* (previous version compatibility) */ + ep = alt_xfer(&intf->altsetting[gspca_dev->alt], xfer); + if (ep == NULL) { + pr_err("bad altsetting %d\n", gspca_dev->alt); + ret = -EIO; + goto out; + } + ep_tb[0].alt = gspca_dev->alt; + alt_idx = 1; + } else { + + /* else, compute the minimum bandwidth + * and build the endpoint table */ + alt_idx = build_ep_tb(gspca_dev, intf, xfer, ep_tb); + if (alt_idx <= 0) { + pr_err("no transfer endpoint found\n"); + ret = -EIO; + goto unlock; + } } + + /* set the highest alternate setting and + * loop until urb submit succeeds */ + gspca_input_destroy_urb(gspca_dev); + + gspca_dev->alt = ep_tb[--alt_idx].alt; + alt = -1; for (;;) { + if (alt != gspca_dev->alt) { + alt = gspca_dev->alt; + if (gspca_dev->nbalt > 1) { + ret = usb_set_interface(gspca_dev->dev, + gspca_dev->iface, + alt); + if (ret < 0) { + pr_err("set alt %d err %d\n", alt, ret); + goto out; + } + } + } if (!gspca_dev->cam.no_urb_create) { - PDEBUG(D_STREAM, "init transfer alt %d", - gspca_dev->alt); - ret = create_urbs(gspca_dev, ep); + PDEBUG(D_STREAM, "init transfer alt %d", alt); + ret = create_urbs(gspca_dev, + alt_xfer(&intf->altsetting[alt], xfer)); if (ret < 0) { destroy_urbs(gspca_dev); goto out; @@ -843,7 +929,10 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) break; } if (ret >= 0) - break; + break; /* transfer is started */ + + /* something when wrong + * stop the webcam and free the transfer resources */ gspca_stream_off(gspca_dev); if (ret != -ENOSPC) { pr_err("usb_submit_urb alt %d err %d\n", @@ -854,18 +943,20 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) /* the bandwidth is not wide enough * negotiate or try a lower alternate setting */ PDEBUG(D_ERR|D_STREAM, - "bandwidth not wide enough - trying again"); + "alt %d - bandwidth not wide enough - trying again", + alt); msleep(20); /* wait for kill complete */ if (gspca_dev->sd_desc->isoc_nego) { ret = gspca_dev->sd_desc->isoc_nego(gspca_dev); if (ret < 0) goto out; } else { - ep = get_ep(gspca_dev); - if (ep == NULL) { + if (alt_idx <= 0) { + pr_err("no transfer endpoint found\n"); ret = -EIO; goto out; } + alt = ep_tb[--alt_idx].alt; } } out: -- cgit v0.10.2 From 4274d84ce801b763615152b276e2a341a30c3a82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Wed, 10 Aug 2011 07:40:47 -0300 Subject: [media] gspca - main: Handle the xHCI error on usb_set_interface() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch is adapted from a patch from Sarah Sharp (2010/05/03). The xHCD handler checks the USB bandwidth on usb_set_interface() instead of on usb_submit_urb(). Now, the same treatment is applied in case of error of both functions. Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index ee95448..e41dfe2 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -887,6 +887,8 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) gspca_dev->iface, alt); if (ret < 0) { + if (ret == -ENOSPC) + goto retry; /*fixme: ugly*/ pr_err("set alt %d err %d\n", alt, ret); goto out; } @@ -942,6 +944,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) /* the bandwidth is not wide enough * negotiate or try a lower alternate setting */ +retry: PDEBUG(D_ERR|D_STREAM, "alt %d - bandwidth not wide enough - trying again", alt); -- cgit v0.10.2 From 8f12b1ab2fac0edbc5d8ad64f962fe40662c5b72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Thu, 22 Sep 2011 07:49:35 -0300 Subject: [media] gspca - topro: New subdriver for Topro webcams MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver is based on Anders Blomdell's source proposed in april 2009. It has been extended to handle the tp6810 bridge and the soi763a sensor. Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt index 49102fb..58d0082 100644 --- a/Documentation/video4linux/gspca.txt +++ b/Documentation/video4linux/gspca.txt @@ -200,6 +200,8 @@ gl860 05e3:0503 Genesys Logic PC Camera gl860 05e3:f191 Genesys Logic PC Camera spca561 060b:a001 Maxell Compact Pc PM3 zc3xx 0698:2003 CTX M730V built in +topro 06a2:0003 TP6800 PC Camera, CmoX CX0342 webcam +topro 06a2:6810 Creative Qmax nw80x 06a5:0000 Typhoon Webcam 100 USB nw80x 06a5:d001 Divio based webcams nw80x 06a5:d800 Divio Chicony TwinkleCam, Trust SpaceCam diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig index 43d9a20..103af3f 100644 --- a/drivers/media/video/gspca/Kconfig +++ b/drivers/media/video/gspca/Kconfig @@ -356,6 +356,16 @@ config USB_GSPCA_T613 To compile this driver as a module, choose M here: the module will be called gspca_t613. +config USB_GSPCA_TOPRO + tristate "TOPRO USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the + TP6800 and TP6810 Topro chips. + + To compile this driver as a module, choose M here: the + module will be called gspca_topro. + config USB_GSPCA_TV8532 tristate "TV8532 USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile index d6364a8..f345f49 100644 --- a/drivers/media/video/gspca/Makefile +++ b/drivers/media/video/gspca/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_USB_GSPCA_SUNPLUS) += gspca_sunplus.o obj-$(CONFIG_USB_GSPCA_STK014) += gspca_stk014.o obj-$(CONFIG_USB_GSPCA_STV0680) += gspca_stv0680.o obj-$(CONFIG_USB_GSPCA_T613) += gspca_t613.o +obj-$(CONFIG_USB_GSPCA_TOPRO) += gspca_topro.o obj-$(CONFIG_USB_GSPCA_TV8532) += gspca_tv8532.o obj-$(CONFIG_USB_GSPCA_VC032X) += gspca_vc032x.o obj-$(CONFIG_USB_GSPCA_VICAM) += gspca_vicam.o @@ -78,6 +79,7 @@ gspca_stk014-objs := stk014.o gspca_stv0680-objs := stv0680.o gspca_sunplus-objs := sunplus.o gspca_t613-objs := t613.o +gspca_topro-objs := topro.o gspca_tv8532-objs := tv8532.o gspca_vc032x-objs := vc032x.o gspca_vicam-objs := vicam.o diff --git a/drivers/media/video/gspca/topro.c b/drivers/media/video/gspca/topro.c new file mode 100644 index 0000000..29596c5 --- /dev/null +++ b/drivers/media/video/gspca/topro.c @@ -0,0 +1,4989 @@ +/* + * Topro TP6800/6810 webcam driver. + * + * Copyright (C) 2011 Jean-François Moine (http://moinejf.free.fr) + * Copyright (C) 2009 Anders Blomdell (anders.blomdell@control.lth.se) + * Copyright (C) 2008 Thomas Champagne (lafeuil@gmail.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 of the License, 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, see . + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include "gspca.h" + +MODULE_DESCRIPTION("Topro TP6800/6810 gspca webcam driver"); +MODULE_AUTHOR("Jean-Francois Moine , " + "Anders Blomdell "); +MODULE_LICENSE("GPL"); + +static int force_sensor = -1; + +/* JPEG header */ +static const u8 jpeg_head[] = { + 0xff, 0xd8, /* jpeg */ + +/* quantization table quality 50% */ + 0xff, 0xdb, 0x00, 0x84, /* DQT */ +0, +#define JPEG_QT0_OFFSET 7 + 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, + 0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, + 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, + 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33, + 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44, + 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, + 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, + 0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63, +1, +#define JPEG_QT1_OFFSET 72 + 0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a, + 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + + /* Define Huffman table (thanks to Thomas Kaiser) */ + 0xff, 0xc4, 0x01, 0x5e, + 0x00, 0x00, 0x02, 0x03, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, + 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, + 0x07, 0x05, 0x04, 0x06, 0x01, 0x00, 0x00, 0x57, + 0x01, 0x02, 0x03, 0x00, 0x11, 0x04, 0x12, 0x21, + 0x31, 0x13, 0x41, 0x51, 0x61, 0x05, 0x22, 0x32, + 0x14, 0x71, 0x81, 0x91, 0x15, 0x23, 0x42, 0x52, + 0x62, 0xa1, 0xb1, 0x06, 0x33, 0x72, 0xc1, 0xd1, + 0x24, 0x43, 0x53, 0x82, 0x16, 0x34, 0x92, 0xa2, + 0xe1, 0xf1, 0xf0, 0x07, 0x08, 0x17, 0x18, 0x25, + 0x26, 0x27, 0x28, 0x35, 0x36, 0x37, 0x38, 0x44, + 0x45, 0x46, 0x47, 0x48, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x73, + 0x74, 0x75, 0x76, 0x77, 0x78, 0x83, 0x84, 0x85, + 0x86, 0x87, 0x88, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xb2, + 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xe2, 0xe3, 0xe4, 0xe5, + 0xe6, 0xe7, 0xe8, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, + 0xf7, 0xf8, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, 0x09, 0x11, 0x00, 0x02, + 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, + 0x04, 0x06, 0x01, 0x00, 0x00, 0x57, 0x00, 0x01, + 0x11, 0x02, 0x21, 0x03, 0x12, 0x31, 0x41, 0x13, + 0x22, 0x51, 0x61, 0x04, 0x32, 0x71, 0x05, 0x14, + 0x23, 0x42, 0x33, 0x52, 0x81, 0x91, 0xa1, 0xb1, + 0xf0, 0x06, 0x15, 0xc1, 0xd1, 0xe1, 0x24, 0x43, + 0x62, 0xf1, 0x16, 0x25, 0x34, 0x53, 0x72, 0x82, + 0x92, 0x07, 0x08, 0x17, 0x18, 0x26, 0x27, 0x28, + 0x35, 0x36, 0x37, 0x38, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x54, 0x55, 0x56, 0x57, 0x58, 0x63, 0x64, + 0x65, 0x66, 0x67, 0x68, 0x73, 0x74, 0x75, 0x76, + 0x77, 0x78, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, + 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, 0xb8, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, + 0xd7, 0xd8, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xff, 0xc0, 0x00, 0x11, /* SOF0 (start of frame 0 */ + 0x08, /* data precision */ +#define JPEG_HEIGHT_OFFSET 493 + 0x01, 0xe0, /* height */ + 0x02, 0x80, /* width */ + 0x03, /* component number */ + 0x01, + 0x21, /* samples Y = jpeg 422 */ + 0x00, /* quant Y */ + 0x02, 0x11, 0x01, /* samples CbCr - quant CbCr */ + 0x03, 0x11, 0x01, + + 0xff, 0xda, 0x00, 0x0c, /* SOS (start of scan) */ + 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00 +#define JPEG_HDR_SZ 521 +}; + +enum e_ctrl { + EXPOSURE, + QUALITY, + SHARPNESS, + RGAIN, + GAIN, + BGAIN, + GAMMA, + AUTOGAIN, + NCTRLS /* number of controls */ +}; + +#define AUTOGAIN_DEF 1 + +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + struct gspca_ctrl ctrls[NCTRLS]; + + u8 framerate; + u8 quality; /* webcam current JPEG quality (0..16) */ + s8 ag_cnt; /* autogain / start counter for tp6810 */ +#define AG_CNT_START 13 /* check gain every N frames */ + + u8 bridge; + u8 sensor; + + u8 jpeg_hdr[JPEG_HDR_SZ]; +}; + +enum bridges { + BRIDGE_TP6800, + BRIDGE_TP6810, +}; + +enum sensors { + SENSOR_CX0342, + SENSOR_SOI763A, /* ~= ov7630 / ov7648 */ + NSENSORS +}; + +static const struct v4l2_pix_format vga_mode[] = { + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 4 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG} +}; + +/* + * JPEG quality + * index: webcam compression + * value: JPEG quality in % + */ +static const u8 jpeg_q[17] = { + 88, 77, 67, 57, 55, 55, 45, 45, 36, 36, 30, 30, 26, 26, 22, 22, 94 +}; + +#define BULK_OUT_SIZE 0x20 +#if BULK_OUT_SIZE > USB_BUF_SZ +#error "USB buffer too small" +#endif + +static const u8 rates[] = {30, 20, 15, 10, 7, 5}; +static const struct framerates framerates[] = { + { + .rates = rates, + .nrates = ARRAY_SIZE(rates) + }, + { + .rates = rates, + .nrates = ARRAY_SIZE(rates) + } +}; +static const u8 rates_6810[] = {30, 15, 10, 7, 5}; +static const struct framerates framerates_6810[] = { + { + .rates = rates_6810, + .nrates = ARRAY_SIZE(rates_6810) + }, + { + .rates = rates_6810, + .nrates = ARRAY_SIZE(rates_6810) + } +}; + +/* + * webcam quality in % + * the last value is the ultra fine quality + */ + +/* TP6800 register offsets */ +#define TP6800_R10_SIF_TYPE 0x10 +#define TP6800_R11_SIF_CONTROL 0x11 +#define TP6800_R12_SIF_ADDR_S 0x12 +#define TP6800_R13_SIF_TX_DATA 0x13 +#define TP6800_R14_SIF_RX_DATA 0x14 +#define TP6800_R15_GPIO_PU 0x15 +#define TP6800_R16_GPIO_PD 0x16 +#define TP6800_R17_GPIO_IO 0x17 +#define TP6800_R18_GPIO_DATA 0x18 +#define TP6800_R19_SIF_ADDR_S2 0x19 +#define TP6800_R1A_SIF_TX_DATA2 0x1a +#define TP6800_R1B_SIF_RX_DATA2 0x1b +#define TP6800_R21_ENDP_1_CTL 0x21 +#define TP6800_R2F_TIMING_CFG 0x2f +#define TP6800_R30_SENSOR_CFG 0x30 +#define TP6800_R31_PIXEL_START 0x31 +#define TP6800_R32_PIXEL_END_L 0x32 +#define TP6800_R33_PIXEL_END_H 0x33 +#define TP6800_R34_LINE_START 0x34 +#define TP6800_R35_LINE_END_L 0x35 +#define TP6800_R36_LINE_END_H 0x36 +#define TP6800_R37_FRONT_DARK_ST 0x37 +#define TP6800_R38_FRONT_DARK_END 0x38 +#define TP6800_R39_REAR_DARK_ST_L 0x39 +#define TP6800_R3A_REAR_DARK_ST_H 0x3a +#define TP6800_R3B_REAR_DARK_END_L 0x3b +#define TP6800_R3C_REAR_DARK_END_H 0x3c +#define TP6800_R3D_HORIZ_DARK_LINE_L 0x3d +#define TP6800_R3E_HORIZ_DARK_LINE_H 0x3e +#define TP6800_R3F_FRAME_RATE 0x3f +#define TP6800_R50 0x50 +#define TP6800_R51 0x51 +#define TP6800_R52 0x52 +#define TP6800_R53 0x53 +#define TP6800_R54_DARK_CFG 0x54 +#define TP6800_R55_GAMMA_R 0x55 +#define TP6800_R56_GAMMA_G 0x56 +#define TP6800_R57_GAMMA_B 0x57 +#define TP6800_R5C_EDGE_THRLD 0x5c +#define TP6800_R5D_DEMOSAIC_CFG 0x5d +#define TP6800_R78_FORMAT 0x78 +#define TP6800_R79_QUALITY 0x79 +#define TP6800_R7A_BLK_THRLD 0x7a + +/* CX0342 register offsets */ + +#define CX0342_SENSOR_ID 0x00 +#define CX0342_VERSION_NO 0x01 +#define CX0342_ORG_X_L 0x02 +#define CX0342_ORG_X_H 0x03 +#define CX0342_ORG_Y_L 0x04 +#define CX0342_ORG_Y_H 0x05 +#define CX0342_STOP_X_L 0x06 +#define CX0342_STOP_X_H 0x07 +#define CX0342_STOP_Y_L 0x08 +#define CX0342_STOP_Y_H 0x09 +#define CX0342_FRAME_WIDTH_L 0x0a +#define CX0342_FRAME_WIDTH_H 0x0b +#define CX0342_FRAME_HEIGH_L 0x0c +#define CX0342_FRAME_HEIGH_H 0x0d +#define CX0342_EXPO_LINE_L 0x10 +#define CX0342_EXPO_LINE_H 0x11 +#define CX0342_EXPO_CLK_L 0x12 +#define CX0342_EXPO_CLK_H 0x13 +#define CX0342_RAW_GRGAIN_L 0x14 +#define CX0342_RAW_GRGAIN_H 0x15 +#define CX0342_RAW_GBGAIN_L 0x16 +#define CX0342_RAW_GBGAIN_H 0x17 +#define CX0342_RAW_RGAIN_L 0x18 +#define CX0342_RAW_RGAIN_H 0x19 +#define CX0342_RAW_BGAIN_L 0x1a +#define CX0342_RAW_BGAIN_H 0x1b +#define CX0342_GLOBAL_GAIN 0x1c +#define CX0342_SYS_CTRL_0 0x20 +#define CX0342_SYS_CTRL_1 0x21 +#define CX0342_SYS_CTRL_2 0x22 +#define CX0342_BYPASS_MODE 0x23 +#define CX0342_SYS_CTRL_3 0x24 +#define CX0342_TIMING_EN 0x25 +#define CX0342_OUTPUT_CTRL 0x26 +#define CX0342_AUTO_ADC_CALIB 0x27 +#define CX0342_SYS_CTRL_4 0x28 +#define CX0342_ADCGN 0x30 +#define CX0342_SLPCR 0x31 +#define CX0342_SLPFN_LO 0x32 +#define CX0342_ADC_CTL 0x33 +#define CX0342_LVRST_BLBIAS 0x34 +#define CX0342_VTHSEL 0x35 +#define CX0342_RAMP_RIV 0x36 +#define CX0342_LDOSEL 0x37 +#define CX0342_CLOCK_GEN 0x40 +#define CX0342_SOFT_RESET 0x41 +#define CX0342_PLL 0x42 +#define CX0342_DR_ENH_PULSE_OFFSET_L 0x43 +#define CX0342_DR_ENH_PULSE_OFFSET_H 0x44 +#define CX0342_DR_ENH_PULSE_POS_L 0x45 +#define CX0342_DR_ENH_PULSE_POS_H 0x46 +#define CX0342_DR_ENH_PULSE_WIDTH 0x47 +#define CX0342_AS_CURRENT_CNT_L 0x48 +#define CX0342_AS_CURRENT_CNT_H 0x49 +#define CX0342_AS_PREVIOUS_CNT_L 0x4a +#define CX0342_AS_PREVIOUS_CNT_H 0x4b +#define CX0342_SPV_VALUE_L 0x4c +#define CX0342_SPV_VALUE_H 0x4d +#define CX0342_GPXLTHD_L 0x50 +#define CX0342_GPXLTHD_H 0x51 +#define CX0342_RBPXLTHD_L 0x52 +#define CX0342_RBPXLTHD_H 0x53 +#define CX0342_PLANETHD_L 0x54 +#define CX0342_PLANETHD_H 0x55 +#define CX0342_ROWDARK_TH 0x56 +#define CX0342_ROWDARK_TOL 0x57 +#define CX0342_RB_GAP_L 0x58 +#define CX0342_RB_GAP_H 0x59 +#define CX0342_G_GAP_L 0x5a +#define CX0342_G_GAP_H 0x5b +#define CX0342_AUTO_ROW_DARK 0x60 +#define CX0342_MANUAL_DARK_VALUE 0x61 +#define CX0342_GB_DARK_OFFSET 0x62 +#define CX0342_GR_DARK_OFFSET 0x63 +#define CX0342_RED_DARK_OFFSET 0x64 +#define CX0342_BLUE_DARK_OFFSET 0x65 +#define CX0342_DATA_SCALING_MULTI 0x66 +#define CX0342_AUTOD_Q_FRAME 0x67 +#define CX0342_AUTOD_ALLOW_VARI 0x68 +#define CX0342_AUTO_DARK_VALUE_L 0x69 +#define CX0342_AUTO_DARK_VALUE_H 0x6a +#define CX0342_IO_CTRL_0 0x70 +#define CX0342_IO_CTRL_1 0x71 +#define CX0342_IO_CTRL_2 0x72 +#define CX0342_IDLE_CTRL 0x73 +#define CX0342_TEST_MODE 0x74 +#define CX0342_FRAME_FIX_DATA_TEST 0x75 +#define CX0342_FRAME_CNT_TEST 0x76 +#define CX0342_RST_OVERFLOW_L 0x80 +#define CX0342_RST_OVERFLOW_H 0x81 +#define CX0342_RST_UNDERFLOW_L 0x82 +#define CX0342_RST_UNDERFLOW_H 0x83 +#define CX0342_DATA_OVERFLOW_L 0x84 +#define CX0342_DATA_OVERFLOW_H 0x85 +#define CX0342_DATA_UNDERFLOW_L 0x86 +#define CX0342_DATA_UNDERFLOW_H 0x87 +#define CX0342_CHANNEL_0_0_L_irst 0x90 +#define CX0342_CHANNEL_0_0_H_irst 0x91 +#define CX0342_CHANNEL_0_1_L_irst 0x92 +#define CX0342_CHANNEL_0_1_H_irst 0x93 +#define CX0342_CHANNEL_0_2_L_irst 0x94 +#define CX0342_CHANNEL_0_2_H_irst 0x95 +#define CX0342_CHANNEL_0_3_L_irst 0x96 +#define CX0342_CHANNEL_0_3_H_irst 0x97 +#define CX0342_CHANNEL_0_4_L_irst 0x98 +#define CX0342_CHANNEL_0_4_H_irst 0x99 +#define CX0342_CHANNEL_0_5_L_irst 0x9a +#define CX0342_CHANNEL_0_5_H_irst 0x9b +#define CX0342_CHANNEL_0_6_L_irst 0x9c +#define CX0342_CHANNEL_0_6_H_irst 0x9d +#define CX0342_CHANNEL_0_7_L_irst 0x9e +#define CX0342_CHANNEL_0_7_H_irst 0x9f +#define CX0342_CHANNEL_1_0_L_itx 0xa0 +#define CX0342_CHANNEL_1_0_H_itx 0xa1 +#define CX0342_CHANNEL_1_1_L_itx 0xa2 +#define CX0342_CHANNEL_1_1_H_itx 0xa3 +#define CX0342_CHANNEL_1_2_L_itx 0xa4 +#define CX0342_CHANNEL_1_2_H_itx 0xa5 +#define CX0342_CHANNEL_1_3_L_itx 0xa6 +#define CX0342_CHANNEL_1_3_H_itx 0xa7 +#define CX0342_CHANNEL_1_4_L_itx 0xa8 +#define CX0342_CHANNEL_1_4_H_itx 0xa9 +#define CX0342_CHANNEL_1_5_L_itx 0xaa +#define CX0342_CHANNEL_1_5_H_itx 0xab +#define CX0342_CHANNEL_1_6_L_itx 0xac +#define CX0342_CHANNEL_1_6_H_itx 0xad +#define CX0342_CHANNEL_1_7_L_itx 0xae +#define CX0342_CHANNEL_1_7_H_itx 0xaf +#define CX0342_CHANNEL_2_0_L_iwl 0xb0 +#define CX0342_CHANNEL_2_0_H_iwl 0xb1 +#define CX0342_CHANNEL_2_1_L_iwl 0xb2 +#define CX0342_CHANNEL_2_1_H_iwl 0xb3 +#define CX0342_CHANNEL_2_2_L_iwl 0xb4 +#define CX0342_CHANNEL_2_2_H_iwl 0xb5 +#define CX0342_CHANNEL_2_3_L_iwl 0xb6 +#define CX0342_CHANNEL_2_3_H_iwl 0xb7 +#define CX0342_CHANNEL_2_4_L_iwl 0xb8 +#define CX0342_CHANNEL_2_4_H_iwl 0xb9 +#define CX0342_CHANNEL_2_5_L_iwl 0xba +#define CX0342_CHANNEL_2_5_H_iwl 0xbb +#define CX0342_CHANNEL_2_6_L_iwl 0xbc +#define CX0342_CHANNEL_2_6_H_iwl 0xbd +#define CX0342_CHANNEL_2_7_L_iwl 0xbe +#define CX0342_CHANNEL_2_7_H_iwl 0xbf +#define CX0342_CHANNEL_3_0_L_ensp 0xc0 +#define CX0342_CHANNEL_3_0_H_ensp 0xc1 +#define CX0342_CHANNEL_3_1_L_ensp 0xc2 +#define CX0342_CHANNEL_3_1_H_ensp 0xc3 +#define CX0342_CHANNEL_3_2_L_ensp 0xc4 +#define CX0342_CHANNEL_3_2_H_ensp 0xc5 +#define CX0342_CHANNEL_3_3_L_ensp 0xc6 +#define CX0342_CHANNEL_3_3_H_ensp 0xc7 +#define CX0342_CHANNEL_3_4_L_ensp 0xc8 +#define CX0342_CHANNEL_3_4_H_ensp 0xc9 +#define CX0342_CHANNEL_3_5_L_ensp 0xca +#define CX0342_CHANNEL_3_5_H_ensp 0xcb +#define CX0342_CHANNEL_3_6_L_ensp 0xcc +#define CX0342_CHANNEL_3_6_H_ensp 0xcd +#define CX0342_CHANNEL_3_7_L_ensp 0xce +#define CX0342_CHANNEL_3_7_H_ensp 0xcf +#define CX0342_CHANNEL_4_0_L_sela 0xd0 +#define CX0342_CHANNEL_4_0_H_sela 0xd1 +#define CX0342_CHANNEL_4_1_L_sela 0xd2 +#define CX0342_CHANNEL_4_1_H_sela 0xd3 +#define CX0342_CHANNEL_5_0_L_intla 0xe0 +#define CX0342_CHANNEL_5_0_H_intla 0xe1 +#define CX0342_CHANNEL_5_1_L_intla 0xe2 +#define CX0342_CHANNEL_5_1_H_intla 0xe3 +#define CX0342_CHANNEL_5_2_L_intla 0xe4 +#define CX0342_CHANNEL_5_2_H_intla 0xe5 +#define CX0342_CHANNEL_5_3_L_intla 0xe6 +#define CX0342_CHANNEL_5_3_H_intla 0xe7 +#define CX0342_CHANNEL_6_0_L_xa_sel_pos 0xf0 +#define CX0342_CHANNEL_6_0_H_xa_sel_pos 0xf1 +#define CX0342_CHANNEL_7_1_L_cds_pos 0xf2 +#define CX0342_CHANNEL_7_1_H_cds_pos 0xf3 +#define CX0342_SENSOR_HEIGHT_L 0xfb +#define CX0342_SENSOR_HEIGHT_H 0xfc +#define CX0342_SENSOR_WIDTH_L 0xfd +#define CX0342_SENSOR_WIDTH_H 0xfe +#define CX0342_VSYNC_HSYNC_READ 0xff + +struct cmd { + u8 reg; + u8 val; +}; + +static const u8 DQT[17][130] = { + /* Define quantization table (thanks to Thomas Kaiser) */ + { /* Quality 0 */ + 0x00, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x01, + 0x04, 0x04, 0x04, 0x06, 0x05, 0x06, 0x0b, 0x06, + 0x06, 0x0b, 0x18, 0x10, 0x0e, 0x10, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + }, + { /* Quality 1 */ + 0x00, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x01, + 0x08, 0x09, 0x09, 0x0c, 0x0a, 0x0c, 0x17, 0x0d, + 0x0d, 0x17, 0x31, 0x21, 0x1c, 0x21, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + }, + { /* Quality 2 */ + 0x00, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x06, 0x06, 0x06, 0x04, 0x04, 0x04, + 0x04, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x01, + 0x0c, 0x0d, 0x0d, 0x12, 0x0f, 0x12, 0x23, 0x13, + 0x13, 0x23, 0x4a, 0x31, 0x2a, 0x31, 0x4a, 0x4a, + 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, + 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, + 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, + 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, + 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, + 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, + }, + { /* Quality 3 */ + 0x00, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, + 0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x01, + 0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a, + 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + }, + { /* Quality 4 */ + 0x00, + 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x0a, 0x0a, 0x0a, 0x05, 0x05, 0x05, + 0x05, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x01, + 0x11, 0x16, 0x16, 0x1e, 0x1a, 0x1e, 0x3a, 0x20, + 0x20, 0x3a, 0x7b, 0x52, 0x46, 0x52, 0x7b, 0x7b, + 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, + 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, + 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, + 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, + 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, + 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, + }, + { /* Quality 5 */ + 0x00, + 0x04, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x0c, 0x0c, 0x0c, 0x06, 0x06, 0x06, + 0x06, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x01, + 0x11, 0x1b, 0x1b, 0x24, 0x1f, 0x24, 0x46, 0x27, + 0x27, 0x46, 0x94, 0x63, 0x54, 0x63, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + }, + { /* Quality 6 */ + 0x00, + 0x05, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x0e, 0x0e, 0x0e, 0x07, 0x07, 0x07, + 0x07, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x01, + 0x15, 0x1f, 0x1f, 0x2a, 0x24, 0x2a, 0x52, 0x2d, + 0x2d, 0x52, 0xad, 0x73, 0x62, 0x73, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + }, + { /* Quality 7 */ + 0x00, + 0x05, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, + 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x01, + 0x15, 0x24, 0x24, 0x30, 0x2a, 0x30, 0x5e, 0x34, + 0x34, 0x5e, 0xc6, 0x84, 0x70, 0x84, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, + }, + { /* Quality 8 */ + 0x00, + 0x06, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x14, 0x14, 0x14, 0x0a, 0x0a, 0x0a, + 0x0a, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x01, + 0x19, 0x2d, 0x2d, 0x3c, 0x34, 0x3c, 0x75, 0x41, + 0x41, 0x75, 0xf7, 0xa5, 0x8c, 0xa5, 0xf7, 0xf7, + 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, + 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, + 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, + 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, + 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, + 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, + }, + { /* Quality 9 */ + 0x00, + 0x06, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x18, 0x18, 0x18, 0x0c, 0x0c, 0x0c, + 0x0c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x01, + 0x19, 0x36, 0x36, 0x48, 0x3f, 0x48, 0x8d, 0x4e, + 0x4e, 0x8d, 0xff, 0xc6, 0xa8, 0xc6, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + { /* Quality 10 */ + 0x00, + 0x07, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x1c, 0x1c, 0x1c, 0x0e, 0x0e, 0x0e, + 0x0e, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x01, + 0x1d, 0x3f, 0x3f, 0x54, 0x49, 0x54, 0xa4, 0x5b, + 0x5b, 0xa4, 0xff, 0xe7, 0xc4, 0xe7, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + { /* Quality 11 */ + 0x00, + 0x07, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, + 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, + 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, + 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, + 0x01, + 0x1d, 0x48, 0x48, 0x60, 0x54, 0x60, 0xbc, 0x68, + 0x68, 0xbc, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + { /* Quality 12 */ + 0x00, + 0x08, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x28, 0x28, 0x28, 0x14, 0x14, 0x14, + 0x14, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, + 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, + 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, + 0x01, + 0x22, 0x5a, 0x5a, 0x78, 0x69, 0x78, 0xeb, 0x82, + 0x82, 0xeb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + { /* Quality 13 */ + 0x00, + 0x08, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x30, 0x30, 0x30, 0x18, 0x18, 0x18, + 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x72, 0x72, 0x72, 0x72, 0x72, + 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, + 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, + 0x01, + 0x22, 0x6c, 0x6c, 0x90, 0x7e, 0x90, 0xff, 0x9c, + 0x9c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + { /* Quality 14 */ + 0x00, + 0x0a, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x38, 0x38, 0x38, 0x1c, 0x1c, 0x1c, + 0x1c, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x01, + 0x2a, 0x7e, 0x7e, 0xa8, 0x93, 0xa8, 0xff, 0xb6, + 0xb6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + { /* Quality 15 */ + 0x00, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, + 0x20, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x01, + 0x2a, 0x90, 0x90, 0xc0, 0xa8, 0xc0, 0xff, 0xd0, + 0xd0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + { /* Quality 16-31 */ + 0x00, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x01, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + } +}; + +static const struct cmd tp6810_cx_init_common[] = { + {0x1c, 0x00}, + {TP6800_R10_SIF_TYPE, 0x00}, + {0x4e, 0x00}, + {0x4f, 0x00}, + {TP6800_R50, 0xff}, + {TP6800_R51, 0x03}, + {0x00, 0x07}, + {TP6800_R79_QUALITY, 0x03}, + {TP6800_R2F_TIMING_CFG, 0x37}, + {TP6800_R30_SENSOR_CFG, 0x10}, + {TP6800_R21_ENDP_1_CTL, 0x00}, + {TP6800_R52, 0x40}, + {TP6800_R53, 0x40}, + {TP6800_R54_DARK_CFG, 0x40}, + {TP6800_R30_SENSOR_CFG, 0x18}, + {0x4b, 0x00}, + {TP6800_R3F_FRAME_RATE, 0x83}, + {TP6800_R79_QUALITY, 0x05}, + {TP6800_R21_ENDP_1_CTL, 0x00}, + {0x7c, 0x04}, + {0x25, 0x14}, + {0x26, 0x0f}, + {0x7b, 0x10}, +}; + +static const struct cmd tp6810_ov_init_common[] = { + {0x1c, 0x00}, + {TP6800_R10_SIF_TYPE, 0x00}, + {0x4e, 0x00}, + {0x4f, 0x00}, + {TP6800_R50, 0xff}, + {TP6800_R51, 0x03}, + {0x00, 0x07}, + {TP6800_R52, 0x40}, + {TP6800_R53, 0x40}, + {TP6800_R54_DARK_CFG, 0x40}, + {TP6800_R79_QUALITY, 0x03}, + {TP6800_R2F_TIMING_CFG, 0x17}, + {TP6800_R30_SENSOR_CFG, 0x18}, + {TP6800_R21_ENDP_1_CTL, 0x00}, + {TP6800_R3F_FRAME_RATE, 0x86}, + {0x25, 0x18}, + {0x26, 0x0f}, + {0x7b, 0x90}, +}; + +static const struct cmd tp6810_bridge_start[] = { + {0x59, 0x88}, + {0x5a, 0x0f}, + {0x5b, 0x4e}, + {TP6800_R5C_EDGE_THRLD, 0x63}, + {TP6800_R5D_DEMOSAIC_CFG, 0x00}, + {0x03, 0x7f}, + {0x04, 0x80}, + {0x06, 0x00}, + {0x00, 0x00}, +}; + +static const struct cmd tp6810_late_start[] = { + {0x7d, 0x01}, + {0xb0, 0x04}, + {0xb1, 0x04}, + {0xb2, 0x04}, + {0xb3, 0x04}, + {0xb4, 0x04}, + {0xb5, 0x04}, + {0xb6, 0x08}, + {0xb7, 0x08}, + {0xb8, 0x04}, + {0xb9, 0x04}, + {0xba, 0x04}, + {0xbb, 0x04}, + {0xbc, 0x04}, + {0xbd, 0x08}, + {0xbe, 0x08}, + {0xbf, 0x08}, + {0xc0, 0x04}, + {0xc1, 0x04}, + {0xc2, 0x08}, + {0xc3, 0x08}, + {0xc4, 0x08}, + {0xc5, 0x08}, + {0xc6, 0x08}, + {0xc7, 0x13}, + {0xc8, 0x04}, + {0xc9, 0x08}, + {0xca, 0x08}, + {0xcb, 0x08}, + {0xcc, 0x08}, + {0xcd, 0x08}, + {0xce, 0x13}, + {0xcf, 0x13}, + {0xd0, 0x08}, + {0xd1, 0x08}, + {0xd2, 0x08}, + {0xd3, 0x08}, + {0xd4, 0x08}, + {0xd5, 0x13}, + {0xd6, 0x13}, + {0xd7, 0x13}, + {0xd8, 0x08}, + {0xd9, 0x08}, + {0xda, 0x08}, + {0xdb, 0x08}, + {0xdc, 0x13}, + {0xdd, 0x13}, + {0xde, 0x13}, + {0xdf, 0x13}, + {0xe0, 0x08}, + {0xe1, 0x08}, + {0xe2, 0x08}, + {0xe3, 0x13}, + {0xe4, 0x13}, + {0xe5, 0x13}, + {0xe6, 0x13}, + {0xe7, 0x13}, + {0xe8, 0x08}, + {0xe9, 0x08}, + {0xea, 0x13}, + {0xeb, 0x13}, + {0xec, 0x13}, + {0xed, 0x13}, + {0xee, 0x13}, + {0xef, 0x13}, + {0x7d, 0x02}, + + /* later after isoc start */ + {0x7d, 0x08}, + {0x7d, 0x00}, +}; + +static const struct cmd cx0342_timing_seq[] = { + {CX0342_CHANNEL_0_1_L_irst, 0x20}, + {CX0342_CHANNEL_0_2_L_irst, 0x24}, + {CX0342_CHANNEL_0_2_H_irst, 0x00}, + {CX0342_CHANNEL_0_3_L_irst, 0x2f}, + {CX0342_CHANNEL_0_3_H_irst, 0x00}, + {CX0342_CHANNEL_1_0_L_itx, 0x02}, + {CX0342_CHANNEL_1_0_H_itx, 0x00}, + {CX0342_CHANNEL_1_1_L_itx, 0x20}, + {CX0342_CHANNEL_1_1_H_itx, 0x00}, + {CX0342_CHANNEL_1_2_L_itx, 0xe4}, + {CX0342_CHANNEL_1_2_H_itx, 0x00}, + {CX0342_CHANNEL_1_3_L_itx, 0xee}, + {CX0342_CHANNEL_1_3_H_itx, 0x00}, + {CX0342_CHANNEL_2_0_L_iwl, 0x30}, + {CX0342_CHANNEL_2_0_H_iwl, 0x00}, + {CX0342_CHANNEL_3_0_L_ensp, 0x34}, + {CX0342_CHANNEL_3_1_L_ensp, 0xe2}, + {CX0342_CHANNEL_3_1_H_ensp, 0x00}, + {CX0342_CHANNEL_3_2_L_ensp, 0xf6}, + {CX0342_CHANNEL_3_2_H_ensp, 0x00}, + {CX0342_CHANNEL_3_3_L_ensp, 0xf4}, + {CX0342_CHANNEL_3_3_H_ensp, 0x02}, + {CX0342_CHANNEL_4_0_L_sela, 0x26}, + {CX0342_CHANNEL_4_0_H_sela, 0x00}, + {CX0342_CHANNEL_4_1_L_sela, 0xe2}, + {CX0342_CHANNEL_4_1_H_sela, 0x00}, + {CX0342_CHANNEL_5_0_L_intla, 0x26}, + {CX0342_CHANNEL_5_1_L_intla, 0x29}, + {CX0342_CHANNEL_5_2_L_intla, 0xf0}, + {CX0342_CHANNEL_5_2_H_intla, 0x00}, + {CX0342_CHANNEL_5_3_L_intla, 0xf3}, + {CX0342_CHANNEL_5_3_H_intla, 0x00}, + {CX0342_CHANNEL_6_0_L_xa_sel_pos, 0x24}, + {CX0342_CHANNEL_7_1_L_cds_pos, 0x02}, + {CX0342_TIMING_EN, 0x01}, +}; + +/* define the JPEG header */ +static void jpeg_define(u8 *jpeg_hdr, + int height, + int width) +{ + memcpy(jpeg_hdr, jpeg_head, sizeof jpeg_head); + jpeg_hdr[JPEG_HEIGHT_OFFSET + 0] = height >> 8; + jpeg_hdr[JPEG_HEIGHT_OFFSET + 1] = height; + jpeg_hdr[JPEG_HEIGHT_OFFSET + 2] = width >> 8; + jpeg_hdr[JPEG_HEIGHT_OFFSET + 3] = width; +} + +/* set the JPEG quality for sensor soi763a */ +static void jpeg_set_qual(u8 *jpeg_hdr, + int quality) +{ + int i, sc; + + if (quality < 50) + sc = 5000 / quality; + else + sc = 200 - quality * 2; + for (i = 0; i < 64; i++) { + jpeg_hdr[JPEG_QT0_OFFSET + i] = + (jpeg_head[JPEG_QT0_OFFSET + i] * sc + 50) / 100; + jpeg_hdr[JPEG_QT1_OFFSET + i] = + (jpeg_head[JPEG_QT1_OFFSET + i] * sc + 50) / 100; + } +} + +static void reg_w(struct gspca_dev *gspca_dev, u8 index, u8 value) +{ + struct usb_device *dev = gspca_dev->dev; + int ret; + + if (gspca_dev->usb_err < 0) + return; + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 0x0e, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, NULL, 0, 500); + if (ret < 0) { + pr_err("reg_w err %d\n", ret); + gspca_dev->usb_err = ret; + } +} + +/* the returned value is in gspca_dev->usb_buf */ +static void reg_r(struct gspca_dev *gspca_dev, u8 index) +{ + struct usb_device *dev = gspca_dev->dev; + int ret; + + if (gspca_dev->usb_err < 0) + return; + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + 0x0d, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, index, gspca_dev->usb_buf, 1, 500); + if (ret < 0) { + pr_err("reg_r err %d\n", ret); + gspca_dev->usb_err = ret; + } +} + +static void reg_w_buf(struct gspca_dev *gspca_dev, + const struct cmd *p, int l) +{ + do { + reg_w(gspca_dev, p->reg, p->val); + p++; + } while (--l > 0); +} + +static int i2c_w(struct gspca_dev *gspca_dev, u8 index, u8 value) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_w(gspca_dev, TP6800_R11_SIF_CONTROL, 0x00); + reg_w(gspca_dev, TP6800_R19_SIF_ADDR_S2, index); + reg_w(gspca_dev, TP6800_R13_SIF_TX_DATA, value); + reg_w(gspca_dev, TP6800_R11_SIF_CONTROL, 0x01); + if (sd->bridge == BRIDGE_TP6800) + return 0; + msleep(5); + reg_r(gspca_dev, TP6800_R11_SIF_CONTROL); + if (gspca_dev->usb_buf[0] == 0) + return 0; + reg_w(gspca_dev, TP6800_R11_SIF_CONTROL, 0x00); + return -1; /* error */ +} + +static void i2c_w_buf(struct gspca_dev *gspca_dev, + const struct cmd *p, int l) +{ + do { + i2c_w(gspca_dev, p->reg, p->val); + p++; + } while (--l > 0); +} + +static int i2c_r(struct gspca_dev *gspca_dev, u8 index, int len) +{ + struct sd *sd = (struct sd *) gspca_dev; + int v; + + reg_w(gspca_dev, TP6800_R19_SIF_ADDR_S2, index); + reg_w(gspca_dev, TP6800_R11_SIF_CONTROL, 0x02); + msleep(5); + reg_r(gspca_dev, TP6800_R14_SIF_RX_DATA); + v = gspca_dev->usb_buf[0]; + if (sd->bridge == BRIDGE_TP6800) + return v; + if (len > 1) { + reg_r(gspca_dev, TP6800_R1B_SIF_RX_DATA2); + v |= (gspca_dev->usb_buf[0] << 8); + } + reg_r(gspca_dev, TP6800_R11_SIF_CONTROL); + if (gspca_dev->usb_buf[0] == 0) + return v; + reg_w(gspca_dev, TP6800_R11_SIF_CONTROL, 0x00); + return -1; +} + +static void bulk_w(struct gspca_dev *gspca_dev, + u8 tag, + const u8 *data, + int length) +{ + struct usb_device *dev = gspca_dev->dev; + int count, actual_count, ret; + + if (gspca_dev->usb_err < 0) + return; + for (;;) { + count = length > BULK_OUT_SIZE - 1 + ? BULK_OUT_SIZE - 1 : length; + gspca_dev->usb_buf[0] = tag; + memcpy(&gspca_dev->usb_buf[1], data, count); + ret = usb_bulk_msg(dev, + usb_sndbulkpipe(dev, 3), + gspca_dev->usb_buf, count + 1, + &actual_count, 500); + if (ret < 0) { + pr_err("bulk write error %d tag=%02x\n", + ret, tag); + gspca_dev->usb_err = ret; + return; + } + length -= count; + if (length <= 0) + break; + data += count; + } +} + +static int probe_6810(struct gspca_dev *gspca_dev) +{ + u8 gpio; + int ret; + + reg_r(gspca_dev, TP6800_R18_GPIO_DATA); + gpio = gspca_dev->usb_buf[0]; + reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio); + reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio | 0x20); + reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio); + reg_w(gspca_dev, TP6800_R10_SIF_TYPE, 0x04); /* i2c 16 bits */ + reg_w(gspca_dev, TP6800_R12_SIF_ADDR_S, 0x21); /* ov??? */ + reg_w(gspca_dev, TP6800_R1A_SIF_TX_DATA2, 0x00); + if (i2c_w(gspca_dev, 0x00, 0x00) >= 0) + return SENSOR_SOI763A; + + reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio | 0x20); + reg_w(gspca_dev, TP6800_R10_SIF_TYPE, 0x00); /* i2c 8 bits */ + reg_w(gspca_dev, TP6800_R12_SIF_ADDR_S, 0x7f); /* (unknown i2c) */ + if (i2c_w(gspca_dev, 0x00, 0x00) >= 0) + return -2; + + reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio | 0x20); + reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio); + reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio | 0x20); + reg_w(gspca_dev, TP6800_R10_SIF_TYPE, 0x00); /* i2c 8 bits */ + reg_w(gspca_dev, TP6800_R12_SIF_ADDR_S, 0x11); /* tas??? / hv??? */ + ret = i2c_r(gspca_dev, 0x00, 1); + if (ret > 0) + return -3; + + reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio | 0x20); + reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio); + reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio | 0x20); + reg_w(gspca_dev, TP6800_R12_SIF_ADDR_S, 0x6e); /* po??? */ + ret = i2c_r(gspca_dev, 0x00, 1); + if (ret > 0) + return -4; + + ret = i2c_r(gspca_dev, 0x01, 1); + if (ret > 0) + return -5; + + reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio | 0x20); + reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio); + reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio | 0x20); + reg_w(gspca_dev, TP6800_R10_SIF_TYPE, 0x04); /* i2c 16 bits */ + reg_w(gspca_dev, TP6800_R12_SIF_ADDR_S, 0x5d); /* mi/mt??? */ + ret = i2c_r(gspca_dev, 0x00, 2); + if (ret > 0) + return -6; + + reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio | 0x20); + reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio); + reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio | 0x20); + reg_w(gspca_dev, TP6800_R12_SIF_ADDR_S, 0x5c); /* mi/mt??? */ + ret = i2c_r(gspca_dev, 0x36, 2); + if (ret > 0) + return -7; + + reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio); + reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio | 0x20); + reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio); + reg_w(gspca_dev, TP6800_R12_SIF_ADDR_S, 0x61); /* (unknown i2c) */ + reg_w(gspca_dev, TP6800_R1A_SIF_TX_DATA2, 0x10); + if (i2c_w(gspca_dev, 0xff, 0x00) >= 0) + return -8; + + reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio | 0x20); + reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio); + reg_w(gspca_dev, TP6800_R18_GPIO_DATA, gpio | 0x20); + reg_w(gspca_dev, TP6800_R10_SIF_TYPE, 0x00); /* i2c 8 bits */ + reg_w(gspca_dev, TP6800_R12_SIF_ADDR_S, 0x20); /* cx0342 */ + ret = i2c_r(gspca_dev, 0x00, 1); + if (ret > 0) + return SENSOR_CX0342; + return -9; +} + +static void cx0342_6810_init(struct gspca_dev *gspca_dev) +{ + static const struct cmd reg_init_1[] = { + {TP6800_R2F_TIMING_CFG, 0x2f}, + {0x25, 0x02}, + {TP6800_R21_ENDP_1_CTL, 0x00}, + {TP6800_R3F_FRAME_RATE, 0x80}, + {TP6800_R2F_TIMING_CFG, 0x2f}, + {TP6800_R18_GPIO_DATA, 0xe1}, + {TP6800_R18_GPIO_DATA, 0xc1}, + {TP6800_R18_GPIO_DATA, 0xe1}, + {TP6800_R11_SIF_CONTROL, 0x00}, + }; + static const struct cmd reg_init_2[] = { + {TP6800_R78_FORMAT, 0x48}, + {TP6800_R11_SIF_CONTROL, 0x00}, + }; + static const struct cmd sensor_init[] = { + {CX0342_OUTPUT_CTRL, 0x07}, + {CX0342_BYPASS_MODE, 0x58}, + {CX0342_GPXLTHD_L, 0x28}, + {CX0342_RBPXLTHD_L, 0x28}, + {CX0342_PLANETHD_L, 0x50}, + {CX0342_PLANETHD_H, 0x03}, + {CX0342_RB_GAP_L, 0xff}, + {CX0342_RB_GAP_H, 0x07}, + {CX0342_G_GAP_L, 0xff}, + {CX0342_G_GAP_H, 0x07}, + {CX0342_RST_OVERFLOW_L, 0x5c}, + {CX0342_RST_OVERFLOW_H, 0x01}, + {CX0342_DATA_OVERFLOW_L, 0xfc}, + {CX0342_DATA_OVERFLOW_H, 0x03}, + {CX0342_DATA_UNDERFLOW_L, 0x00}, + {CX0342_DATA_UNDERFLOW_H, 0x00}, + {CX0342_SYS_CTRL_0, 0x40}, + {CX0342_GLOBAL_GAIN, 0x01}, + {CX0342_CLOCK_GEN, 0x00}, + {CX0342_SYS_CTRL_0, 0x02}, + {CX0342_IDLE_CTRL, 0x05}, + {CX0342_ADCGN, 0x00}, + {CX0342_ADC_CTL, 0x00}, + {CX0342_LVRST_BLBIAS, 0x01}, + {CX0342_VTHSEL, 0x0b}, + {CX0342_RAMP_RIV, 0x0b}, + {CX0342_LDOSEL, 0x07}, + {CX0342_SPV_VALUE_L, 0x40}, + {CX0342_SPV_VALUE_H, 0x02}, + + {CX0342_AUTO_ADC_CALIB, 0x81}, + {CX0342_TIMING_EN, 0x01}, + }; + + reg_w_buf(gspca_dev, reg_init_1, ARRAY_SIZE(reg_init_1)); + reg_w_buf(gspca_dev, tp6810_cx_init_common, + ARRAY_SIZE(tp6810_cx_init_common)); + reg_w_buf(gspca_dev, reg_init_2, ARRAY_SIZE(reg_init_2)); + + reg_w(gspca_dev, TP6800_R12_SIF_ADDR_S, 0x20); /* cx0342 I2C addr */ + i2c_w_buf(gspca_dev, sensor_init, ARRAY_SIZE(sensor_init)); + i2c_w_buf(gspca_dev, cx0342_timing_seq, ARRAY_SIZE(cx0342_timing_seq)); +} + +static void soi763a_6810_init(struct gspca_dev *gspca_dev) +{ + static const struct cmd reg_init_1[] = { + {TP6800_R2F_TIMING_CFG, 0x2f}, + {TP6800_R18_GPIO_DATA, 0xe1}, + {0x25, 0x02}, + {TP6800_R21_ENDP_1_CTL, 0x00}, + {TP6800_R3F_FRAME_RATE, 0x80}, + {TP6800_R2F_TIMING_CFG, 0x2f}, + {TP6800_R18_GPIO_DATA, 0xc1}, + }; + static const struct cmd reg_init_2[] = { + {TP6800_R78_FORMAT, 0x54}, + }; + static const struct cmd sensor_init[] = { + {0x00, 0x00}, + {0x01, 0x80}, + {0x02, 0x80}, + {0x03, 0x90}, + {0x04, 0x20}, + {0x05, 0x20}, + {0x06, 0x80}, + {0x07, 0x00}, + {0x08, 0xff}, + {0x09, 0xff}, + {0x0a, 0x76}, /* 7630 = soi673a */ + {0x0b, 0x30}, + {0x0c, 0x20}, + {0x0d, 0x20}, + {0x0e, 0xff}, + {0x0f, 0xff}, + {0x10, 0x41}, + {0x15, 0x14}, + {0x11, 0x40}, + {0x12, 0x48}, + {0x13, 0x80}, + {0x14, 0x80}, + {0x16, 0x03}, + {0x28, 0xb0}, + {0x71, 0x20}, + {0x75, 0x8e}, + {0x17, 0x1b}, + {0x18, 0xbd}, + {0x19, 0x05}, + {0x1a, 0xf6}, + {0x1b, 0x04}, + {0x1c, 0x7f}, /* omnivision */ + {0x1d, 0xa2}, + {0x1e, 0x00}, + {0x1f, 0x00}, + {0x20, 0x45}, + {0x21, 0x80}, + {0x22, 0x80}, + {0x23, 0xee}, + {0x24, 0x50}, + {0x25, 0x7a}, + {0x26, 0xa0}, + {0x27, 0x9a}, + {0x29, 0x30}, + {0x2a, 0x80}, + {0x2b, 0x00}, + {0x2c, 0xac}, + {0x2d, 0x05}, + {0x2e, 0x80}, + {0x2f, 0x3c}, + {0x30, 0x22}, + {0x31, 0x00}, + {0x32, 0x86}, + {0x33, 0x08}, + {0x34, 0xff}, + {0x35, 0xff}, + {0x36, 0xff}, + {0x37, 0xff}, + {0x38, 0xff}, + {0x39, 0xff}, + {0x3a, 0xfe}, + {0x3b, 0xfe}, + {0x3c, 0xfe}, + {0x3d, 0xfe}, + {0x3e, 0xfe}, + {0x3f, 0x71}, + {0x40, 0xff}, + {0x41, 0xff}, + {0x42, 0xff}, + {0x43, 0xff}, + {0x44, 0xff}, + {0x45, 0xff}, + {0x46, 0xff}, + {0x47, 0xff}, + {0x48, 0xff}, + {0x49, 0xff}, + {0x4a, 0xfe}, + {0x4b, 0xff}, + {0x4c, 0x00}, + {0x4d, 0x00}, + {0x4e, 0xff}, + {0x4f, 0xff}, + {0x50, 0xff}, + {0x51, 0xff}, + {0x52, 0xff}, + {0x53, 0xff}, + {0x54, 0xff}, + {0x55, 0xff}, + {0x56, 0xff}, + {0x57, 0xff}, + {0x58, 0xff}, + {0x59, 0xff}, + {0x5a, 0xff}, + {0x5b, 0xfe}, + {0x5c, 0xff}, + {0x5d, 0x8f}, + {0x5e, 0xff}, + {0x5f, 0x8f}, + {0x60, 0xa2}, + {0x61, 0x4a}, + {0x62, 0xf3}, + {0x63, 0x75}, + {0x64, 0xf0}, + {0x65, 0x00}, + {0x66, 0x55}, + {0x67, 0x92}, + {0x68, 0xa0}, + {0x69, 0x4a}, + {0x6a, 0x22}, + {0x6b, 0x00}, + {0x6c, 0x33}, + {0x6d, 0x44}, + {0x6e, 0x22}, + {0x6f, 0x84}, + {0x70, 0x0b}, + {0x72, 0x10}, + {0x73, 0x50}, + {0x74, 0x21}, + {0x76, 0x00}, + {0x77, 0xa5}, + {0x78, 0x80}, + {0x79, 0x80}, + {0x7a, 0x80}, + {0x7b, 0xe2}, + {0x7c, 0x00}, + {0x7d, 0xf7}, + {0x7e, 0x00}, + {0x7f, 0x00}, + }; + + reg_w_buf(gspca_dev, reg_init_1, ARRAY_SIZE(reg_init_1)); + reg_w_buf(gspca_dev, tp6810_ov_init_common, + ARRAY_SIZE(tp6810_ov_init_common)); + reg_w_buf(gspca_dev, reg_init_2, ARRAY_SIZE(reg_init_2)); + + i2c_w(gspca_dev, 0x12, 0x80); /* sensor reset */ + msleep(10); + i2c_w_buf(gspca_dev, sensor_init, ARRAY_SIZE(sensor_init)); +} + +/* set the gain and exposure */ +static void setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->sensor == SENSOR_CX0342) { + int expo; + + expo = (sd->ctrls[EXPOSURE].val << 2) - 1; + i2c_w(gspca_dev, CX0342_EXPO_LINE_L, expo); + i2c_w(gspca_dev, CX0342_EXPO_LINE_H, expo >> 8); + if (sd->bridge == BRIDGE_TP6800) + i2c_w(gspca_dev, CX0342_RAW_GBGAIN_H, + sd->ctrls[GAIN].val >> 8); + i2c_w(gspca_dev, CX0342_RAW_GBGAIN_L, sd->ctrls[GAIN].val); + if (sd->bridge == BRIDGE_TP6800) + i2c_w(gspca_dev, CX0342_RAW_GRGAIN_H, + sd->ctrls[GAIN].val >> 8); + i2c_w(gspca_dev, CX0342_RAW_GRGAIN_L, sd->ctrls[GAIN].val); + if (sd->bridge == BRIDGE_TP6800) + i2c_w(gspca_dev, CX0342_RAW_BGAIN_H, + sd->ctrls[BGAIN].val >> 8); + i2c_w(gspca_dev, CX0342_RAW_BGAIN_L, sd->ctrls[BGAIN].val); + if (sd->bridge == BRIDGE_TP6800) + i2c_w(gspca_dev, CX0342_RAW_RGAIN_H, + sd->ctrls[RGAIN].val >> 8); + i2c_w(gspca_dev, CX0342_RAW_RGAIN_L, sd->ctrls[RGAIN].val); + i2c_w(gspca_dev, CX0342_SYS_CTRL_0, + sd->bridge == BRIDGE_TP6800 ? 0x80 : 0x81); + return; + } + + /* soi763a */ + i2c_w(gspca_dev, 0x10, /* AEC_H (exposure time) */ + sd->ctrls[EXPOSURE].val); +/* i2c_w(gspca_dev, 0x76, 0x02); * AEC_L ([1:0] */ + i2c_w(gspca_dev, 0x00, /* gain */ + sd->ctrls[GAIN].val); +} + +/* set the JPEG quantization tables */ +static void set_dqt(struct gspca_dev *gspca_dev, u8 q) +{ + struct sd *sd = (struct sd *) gspca_dev; + + /* update the jpeg quantization tables */ + PDEBUG(D_STREAM, "q %d -> %d", sd->quality, q); + sd->quality = q; + if (q > 16) + q = 16; + if (sd->sensor == SENSOR_SOI763A) + jpeg_set_qual(sd->jpeg_hdr, jpeg_q[q]); + else + memcpy(&sd->jpeg_hdr[JPEG_QT0_OFFSET - 1], + DQT[q], sizeof DQT[0]); +} + +/* set the JPEG compression quality factor */ +static void setquality(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u16 q; + + q = sd->ctrls[QUALITY].val; + if (q != 16) + q = 15 - q; + + reg_w(gspca_dev, TP6800_R7A_BLK_THRLD, 0x00); + reg_w(gspca_dev, TP6800_R79_QUALITY, 0x04); + reg_w(gspca_dev, TP6800_R79_QUALITY, q); + + /* auto quality */ + if (q == 15 && sd->bridge == BRIDGE_TP6810) { + msleep(4); + reg_w(gspca_dev, TP6800_R7A_BLK_THRLD, 0x19); + } +} + +static const u8 color_null[18] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static const u8 color_gain[NSENSORS][18] = { +[SENSOR_CX0342] = + {0x4c, 0x00, 0xa9, 0x00, 0x31, 0x00, /* Y R/G/B (LE values) */ + 0xb6, 0x03, 0x6c, 0x03, 0xe0, 0x00, /* U R/G/B */ + 0xdf, 0x00, 0x46, 0x03, 0xdc, 0x03}, /* V R/G/B */ +[SENSOR_SOI763A] = + {0x4c, 0x00, 0x95, 0x00, 0x1d, 0x00, /* Y R/G/B (LE values) */ + 0xb6, 0x03, 0x6c, 0x03, 0xd7, 0x00, /* U R/G/B */ + 0xd5, 0x00, 0x46, 0x03, 0xdc, 0x03}, /* V R/G/B */ +}; + +static void setgamma(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int gamma; +#define NGAMMA 6 + static const u8 gamma_tb[NGAMMA][3][1024] = { + { /* gamma 0 - from tp6800 + soi763a */ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, + 0x02, 0x03, 0x05, 0x07, 0x07, 0x08, 0x09, 0x09, + 0x0a, 0x0c, 0x0c, 0x0d, 0x0e, 0x0e, 0x10, 0x11, + 0x11, 0x12, 0x14, 0x14, 0x15, 0x16, 0x16, 0x17, + 0x17, 0x18, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1e, + 0x1e, 0x1f, 0x1f, 0x20, 0x20, 0x22, 0x23, 0x23, + 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, 0x28, 0x28, + 0x29, 0x29, 0x2b, 0x2c, 0x2c, 0x2d, 0x2d, 0x2f, + 0x2f, 0x30, 0x30, 0x31, 0x31, 0x33, 0x33, 0x34, + 0x34, 0x34, 0x35, 0x35, 0x37, 0x37, 0x38, 0x38, + 0x39, 0x39, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3c, + 0x3c, 0x3d, 0x3d, 0x3f, 0x3f, 0x40, 0x40, 0x40, + 0x42, 0x42, 0x43, 0x43, 0x44, 0x44, 0x44, 0x45, + 0x45, 0x47, 0x47, 0x47, 0x48, 0x48, 0x49, 0x49, + 0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, + 0x4d, 0x4d, 0x4d, 0x4f, 0x4f, 0x50, 0x50, 0x50, + 0x52, 0x52, 0x52, 0x53, 0x53, 0x54, 0x54, 0x54, + 0x55, 0x55, 0x55, 0x56, 0x56, 0x58, 0x58, 0x58, + 0x59, 0x59, 0x59, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, + 0x5b, 0x5c, 0x5c, 0x5c, 0x5e, 0x5e, 0x5e, 0x5f, + 0x5f, 0x5f, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, + 0x62, 0x62, 0x62, 0x63, 0x63, 0x63, 0x65, 0x65, + 0x65, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x68, + 0x68, 0x68, 0x69, 0x69, 0x69, 0x69, 0x6a, 0x6a, + 0x6a, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6e, + 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x70, 0x70, + 0x70, 0x71, 0x71, 0x71, 0x71, 0x73, 0x73, 0x73, + 0x74, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x77, + 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79, 0x79, + 0x79, 0x79, 0x7a, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, + 0x7b, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, + 0x7d, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, + 0x81, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82, + 0x84, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85, 0x86, + 0x86, 0x86, 0x86, 0x88, 0x88, 0x88, 0x88, 0x89, + 0x89, 0x89, 0x89, 0x8a, 0x8a, 0x8a, 0x8a, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8d, 0x8d, 0x8d, 0x8d, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f, 0x8f, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x91, 0x91, 0x91, 0x91, + 0x92, 0x92, 0x92, 0x92, 0x93, 0x93, 0x93, 0x93, + 0x94, 0x94, 0x94, 0x94, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x97, 0x97, 0x97, 0x97, 0x98, 0x98, 0x98, + 0x98, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9b, 0x9b, 0x9b, 0x9b, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9d, 0x9d, 0x9d, 0x9d, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, 0xa5, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa9, 0xa9, 0xa9, 0xa9, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xac, 0xac, 0xac, 0xac, 0xac, 0xad, + 0xad, 0xad, 0xad, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xba, 0xba, 0xba, 0xba, 0xba, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, + 0xc2, 0xc2, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xc3, + 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc5, 0xc5, + 0xc5, 0xc5, 0xc5, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc9, 0xc9, 0xc9, + 0xc9, 0xc9, 0xc9, 0xca, 0xca, 0xca, 0xca, 0xca, + 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcc, 0xcc, 0xcc, + 0xcc, 0xcc, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xce, + 0xce, 0xce, 0xce, 0xce, 0xcf, 0xcf, 0xcf, 0xcf, + 0xcf, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd1, 0xd1, + 0xd1, 0xd1, 0xd1, 0xd1, 0xd3, 0xd3, 0xd3, 0xd3, + 0xd3, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd6, 0xd6, + 0xd6, 0xd6, 0xd6, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, + 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, + 0xd9, 0xd9, 0xda, 0xda, 0xda, 0xda, 0xda, 0xdb, + 0xdb, 0xdb, 0xdb, 0xdb, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xdf, + 0xdf, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe0, + 0xe0, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe2, 0xe2, + 0xe2, 0xe2, 0xe2, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, + 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe5, 0xe5, 0xe5, + 0xe5, 0xe5, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe7, + 0xe7, 0xe7, 0xe7, 0xe7, 0xe8, 0xe8, 0xe8, 0xe8, + 0xe8, 0xe9, 0xe9, 0xe9, 0xe9, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec, 0xec, 0xed, + 0xed, 0xed, 0xed, 0xed, 0xee, 0xee, 0xee, 0xee, + 0xee, 0xef, 0xef, 0xef, 0xef, 0xef, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf3, + 0xf3, 0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf4, + 0xf4, 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, + 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, + 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa, + 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, + 0x02, 0x03, 0x05, 0x07, 0x07, 0x08, 0x09, 0x09, + 0x0a, 0x0c, 0x0c, 0x0d, 0x0e, 0x0e, 0x10, 0x11, + 0x11, 0x12, 0x14, 0x14, 0x15, 0x16, 0x16, 0x17, + 0x17, 0x18, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1e, + 0x1e, 0x1f, 0x1f, 0x20, 0x20, 0x22, 0x23, 0x23, + 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, 0x28, 0x28, + 0x29, 0x29, 0x2b, 0x2c, 0x2c, 0x2d, 0x2d, 0x2f, + 0x2f, 0x30, 0x30, 0x31, 0x31, 0x33, 0x33, 0x34, + 0x34, 0x34, 0x35, 0x35, 0x37, 0x37, 0x38, 0x38, + 0x39, 0x39, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3c, + 0x3c, 0x3d, 0x3d, 0x3f, 0x3f, 0x40, 0x40, 0x40, + 0x42, 0x42, 0x43, 0x43, 0x44, 0x44, 0x44, 0x45, + 0x45, 0x47, 0x47, 0x47, 0x48, 0x48, 0x49, 0x49, + 0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, + 0x4d, 0x4d, 0x4d, 0x4f, 0x4f, 0x50, 0x50, 0x50, + 0x52, 0x52, 0x52, 0x53, 0x53, 0x54, 0x54, 0x54, + 0x55, 0x55, 0x55, 0x56, 0x56, 0x58, 0x58, 0x58, + 0x59, 0x59, 0x59, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, + 0x5b, 0x5c, 0x5c, 0x5c, 0x5e, 0x5e, 0x5e, 0x5f, + 0x5f, 0x5f, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, + 0x62, 0x62, 0x62, 0x63, 0x63, 0x63, 0x65, 0x65, + 0x65, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x68, + 0x68, 0x68, 0x69, 0x69, 0x69, 0x69, 0x6a, 0x6a, + 0x6a, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6e, + 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x70, 0x70, + 0x70, 0x71, 0x71, 0x71, 0x71, 0x73, 0x73, 0x73, + 0x74, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x77, + 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79, 0x79, + 0x79, 0x79, 0x7a, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, + 0x7b, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, + 0x7d, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, + 0x81, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82, + 0x84, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85, 0x86, + 0x86, 0x86, 0x86, 0x88, 0x88, 0x88, 0x88, 0x89, + 0x89, 0x89, 0x89, 0x8a, 0x8a, 0x8a, 0x8a, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8d, 0x8d, 0x8d, 0x8d, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f, 0x8f, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x91, 0x91, 0x91, 0x91, + 0x92, 0x92, 0x92, 0x92, 0x93, 0x93, 0x93, 0x93, + 0x94, 0x94, 0x94, 0x94, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x97, 0x97, 0x97, 0x97, 0x98, 0x98, 0x98, + 0x98, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9b, 0x9b, 0x9b, 0x9b, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9d, 0x9d, 0x9d, 0x9d, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, 0xa5, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa9, 0xa9, 0xa9, 0xa9, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xac, 0xac, 0xac, 0xac, 0xac, 0xad, + 0xad, 0xad, 0xad, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xba, 0xba, 0xba, 0xba, 0xba, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, + 0xc2, 0xc2, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xc3, + 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc5, 0xc5, + 0xc5, 0xc5, 0xc5, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc9, 0xc9, 0xc9, + 0xc9, 0xc9, 0xc9, 0xca, 0xca, 0xca, 0xca, 0xca, + 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcc, 0xcc, 0xcc, + 0xcc, 0xcc, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xce, + 0xce, 0xce, 0xce, 0xce, 0xcf, 0xcf, 0xcf, 0xcf, + 0xcf, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd1, 0xd1, + 0xd1, 0xd1, 0xd1, 0xd1, 0xd3, 0xd3, 0xd3, 0xd3, + 0xd3, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd6, 0xd6, + 0xd6, 0xd6, 0xd6, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, + 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, + 0xd9, 0xd9, 0xda, 0xda, 0xda, 0xda, 0xda, 0xdb, + 0xdb, 0xdb, 0xdb, 0xdb, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xdf, + 0xdf, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe0, + 0xe0, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe2, 0xe2, + 0xe2, 0xe2, 0xe2, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, + 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe5, 0xe5, 0xe5, + 0xe5, 0xe5, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe7, + 0xe7, 0xe7, 0xe7, 0xe7, 0xe8, 0xe8, 0xe8, 0xe8, + 0xe8, 0xe9, 0xe9, 0xe9, 0xe9, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec, 0xec, 0xed, + 0xed, 0xed, 0xed, 0xed, 0xee, 0xee, 0xee, 0xee, + 0xee, 0xef, 0xef, 0xef, 0xef, 0xef, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf3, + 0xf3, 0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf4, + 0xf4, 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, + 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, + 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa, + 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, + 0x02, 0x03, 0x05, 0x07, 0x07, 0x08, 0x09, 0x09, + 0x0a, 0x0c, 0x0c, 0x0d, 0x0e, 0x0e, 0x10, 0x11, + 0x11, 0x12, 0x14, 0x14, 0x15, 0x16, 0x16, 0x17, + 0x17, 0x18, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1e, + 0x1e, 0x1f, 0x1f, 0x20, 0x20, 0x22, 0x23, 0x23, + 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, 0x28, 0x28, + 0x29, 0x29, 0x2b, 0x2c, 0x2c, 0x2d, 0x2d, 0x2f, + 0x2f, 0x30, 0x30, 0x31, 0x31, 0x33, 0x33, 0x34, + 0x34, 0x34, 0x35, 0x35, 0x37, 0x37, 0x38, 0x38, + 0x39, 0x39, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3c, + 0x3c, 0x3d, 0x3d, 0x3f, 0x3f, 0x40, 0x40, 0x40, + 0x42, 0x42, 0x43, 0x43, 0x44, 0x44, 0x44, 0x45, + 0x45, 0x47, 0x47, 0x47, 0x48, 0x48, 0x49, 0x49, + 0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, + 0x4d, 0x4d, 0x4d, 0x4f, 0x4f, 0x50, 0x50, 0x50, + 0x52, 0x52, 0x52, 0x53, 0x53, 0x54, 0x54, 0x54, + 0x55, 0x55, 0x55, 0x56, 0x56, 0x58, 0x58, 0x58, + 0x59, 0x59, 0x59, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, + 0x5b, 0x5c, 0x5c, 0x5c, 0x5e, 0x5e, 0x5e, 0x5f, + 0x5f, 0x5f, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, + 0x62, 0x62, 0x62, 0x63, 0x63, 0x63, 0x65, 0x65, + 0x65, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x68, + 0x68, 0x68, 0x69, 0x69, 0x69, 0x69, 0x6a, 0x6a, + 0x6a, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6e, + 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x70, 0x70, + 0x70, 0x71, 0x71, 0x71, 0x71, 0x73, 0x73, 0x73, + 0x74, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x76, + 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79, 0x79, + 0x79, 0x79, 0x7a, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, + 0x7b, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, + 0x7d, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, + 0x81, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82, + 0x84, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85, 0x86, + 0x86, 0x86, 0x86, 0x88, 0x88, 0x88, 0x88, 0x89, + 0x89, 0x89, 0x89, 0x8a, 0x8a, 0x8a, 0x8a, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8d, 0x8d, 0x8d, 0x8d, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f, 0x8f, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x91, 0x91, 0x91, 0x91, + 0x92, 0x92, 0x92, 0x92, 0x93, 0x93, 0x93, 0x93, + 0x94, 0x94, 0x94, 0x94, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x97, 0x97, 0x97, 0x97, 0x98, 0x98, 0x98, + 0x98, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9b, 0x9b, 0x9b, 0x9b, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9d, 0x9d, 0x9d, 0x9d, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, 0xa5, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa9, 0xa9, 0xa9, 0xa9, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xac, 0xac, 0xac, 0xac, 0xac, 0xad, + 0xad, 0xad, 0xad, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xba, 0xba, 0xba, 0xba, 0xba, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, + 0xc2, 0xc2, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xc3, + 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc5, 0xc5, + 0xc5, 0xc5, 0xc5, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc9, 0xc9, 0xc9, + 0xc9, 0xc9, 0xc9, 0xca, 0xca, 0xca, 0xca, 0xca, + 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcc, 0xcc, 0xcc, + 0xcc, 0xcc, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xce, + 0xce, 0xce, 0xce, 0xce, 0xcf, 0xcf, 0xcf, 0xcf, + 0xcf, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd1, 0xd1, + 0xd1, 0xd1, 0xd1, 0xd1, 0xd3, 0xd3, 0xd3, 0xd3, + 0xd3, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd6, 0xd6, + 0xd6, 0xd6, 0xd6, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, + 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, + 0xd9, 0xd9, 0xda, 0xda, 0xda, 0xda, 0xda, 0xdb, + 0xdb, 0xdb, 0xdb, 0xdb, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xdf, + 0xdf, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe0, + 0xe0, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe2, 0xe2, + 0xe2, 0xe2, 0xe2, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, + 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe5, 0xe5, 0xe5, + 0xe5, 0xe5, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe7, + 0xe7, 0xe7, 0xe7, 0xe7, 0xe8, 0xe8, 0xe8, 0xe8, + 0xe8, 0xe9, 0xe9, 0xe9, 0xe9, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec, 0xec, 0xed, + 0xed, 0xed, 0xed, 0xed, 0xee, 0xee, 0xee, 0xee, + 0xee, 0xef, 0xef, 0xef, 0xef, 0xef, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf3, + 0xf3, 0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf4, + 0xf4, 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, + 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, + 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa, + 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb} + }, + { /* gamma 1 - from tp6810 + soi763a */ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x02, 0x03, 0x05, 0x07, 0x08, 0x09, 0x0a, + 0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x12, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x1a, 0x1a, 0x1b, 0x1c, 0x1e, + 0x1f, 0x20, 0x22, 0x22, 0x23, 0x25, 0x26, 0x27, + 0x27, 0x28, 0x29, 0x2b, 0x2b, 0x2c, 0x2d, 0x2f, + 0x2f, 0x30, 0x31, 0x33, 0x33, 0x34, 0x35, 0x35, + 0x37, 0x38, 0x38, 0x39, 0x3a, 0x3a, 0x3b, 0x3c, + 0x3c, 0x3d, 0x3f, 0x3f, 0x40, 0x42, 0x42, 0x43, + 0x43, 0x44, 0x45, 0x45, 0x47, 0x47, 0x48, 0x49, + 0x49, 0x4a, 0x4a, 0x4b, 0x4b, 0x4c, 0x4d, 0x4d, + 0x4f, 0x4f, 0x50, 0x50, 0x52, 0x52, 0x53, 0x53, + 0x54, 0x54, 0x55, 0x56, 0x56, 0x58, 0x58, 0x59, + 0x59, 0x5a, 0x5a, 0x5b, 0x5b, 0x5c, 0x5c, 0x5e, + 0x5e, 0x5e, 0x5f, 0x5f, 0x60, 0x60, 0x61, 0x61, + 0x62, 0x62, 0x63, 0x63, 0x65, 0x65, 0x65, 0x66, + 0x66, 0x67, 0x67, 0x68, 0x68, 0x69, 0x69, 0x69, + 0x6a, 0x6a, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6e, + 0x6e, 0x6f, 0x6f, 0x6f, 0x70, 0x70, 0x71, 0x71, + 0x73, 0x73, 0x73, 0x74, 0x74, 0x74, 0x75, 0x75, + 0x77, 0x77, 0x77, 0x78, 0x78, 0x79, 0x79, 0x79, + 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, + 0x7d, 0x7d, 0x7d, 0x7f, 0x7f, 0x80, 0x80, 0x80, + 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x84, 0x84, + 0x84, 0x85, 0x85, 0x85, 0x86, 0x86, 0x86, 0x88, + 0x88, 0x88, 0x89, 0x89, 0x89, 0x8a, 0x8a, 0x8a, + 0x8b, 0x8b, 0x8b, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, + 0x8e, 0x8f, 0x8f, 0x8f, 0x90, 0x90, 0x90, 0x91, + 0x91, 0x91, 0x92, 0x92, 0x92, 0x92, 0x93, 0x93, + 0x93, 0x94, 0x94, 0x94, 0x96, 0x96, 0x96, 0x97, + 0x97, 0x97, 0x97, 0x98, 0x98, 0x98, 0x99, 0x99, + 0x99, 0x9a, 0x9a, 0x9a, 0x9a, 0x9b, 0x9b, 0x9b, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9d, 0x9d, 0x9d, 0x9e, + 0x9e, 0x9e, 0x9e, 0xa0, 0xa0, 0xa0, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa2, 0xa2, 0xa2, 0xa2, 0xa3, 0xa3, + 0xa3, 0xa4, 0xa4, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa6, 0xa6, 0xa6, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa9, 0xa9, 0xa9, 0xa9, 0xab, 0xab, 0xab, 0xab, + 0xac, 0xac, 0xac, 0xad, 0xad, 0xad, 0xad, 0xae, + 0xae, 0xae, 0xae, 0xaf, 0xaf, 0xaf, 0xaf, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb1, 0xb1, 0xb1, 0xb1, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb3, 0xb3, 0xb3, 0xb3, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb6, 0xb6, 0xb6, 0xb6, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb9, 0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf, + 0xbf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0xc2, + 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xc3, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc5, 0xc5, 0xc5, 0xc5, 0xc6, + 0xc6, 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc7, + 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xca, 0xca, 0xca, + 0xca, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcc, 0xcc, + 0xcc, 0xcc, 0xcc, 0xcd, 0xcd, 0xcd, 0xcd, 0xce, + 0xce, 0xce, 0xce, 0xce, 0xcf, 0xcf, 0xcf, 0xcf, + 0xcf, 0xd0, 0xd0, 0xd0, 0xd0, 0xd1, 0xd1, 0xd1, + 0xd1, 0xd1, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd4, + 0xd4, 0xd4, 0xd4, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, + 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd8, 0xd8, 0xd8, + 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xda, + 0xda, 0xda, 0xda, 0xda, 0xdb, 0xdb, 0xdb, 0xdb, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xde, 0xde, 0xde, + 0xde, 0xde, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xe0, + 0xe0, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe1, 0xe1, + 0xe1, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe3, 0xe3, + 0xe3, 0xe3, 0xe3, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, + 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe6, 0xe6, 0xe6, + 0xe6, 0xe6, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe8, + 0xe8, 0xe8, 0xe8, 0xe8, 0xe9, 0xe9, 0xe9, 0xe9, + 0xe9, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xec, 0xec, + 0xec, 0xec, 0xec, 0xed, 0xed, 0xed, 0xed, 0xed, + 0xee, 0xee, 0xee, 0xee, 0xee, 0xef, 0xef, 0xef, + 0xef, 0xef, 0xef, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf3, 0xf3, 0xf3, + 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf5, + 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf6, + 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, + 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, + 0xf9, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, + 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, + 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, + 0x05, 0x07, 0x07, 0x08, 0x09, 0x0a, 0x0c, 0x0d, + 0x0e, 0x10, 0x10, 0x11, 0x12, 0x14, 0x15, 0x15, + 0x16, 0x17, 0x18, 0x1a, 0x1a, 0x1b, 0x1c, 0x1e, + 0x1e, 0x1f, 0x20, 0x20, 0x22, 0x23, 0x25, 0x25, + 0x26, 0x27, 0x27, 0x28, 0x29, 0x29, 0x2b, 0x2c, + 0x2c, 0x2d, 0x2d, 0x2f, 0x30, 0x30, 0x31, 0x31, + 0x33, 0x34, 0x34, 0x35, 0x35, 0x37, 0x38, 0x38, + 0x39, 0x39, 0x3a, 0x3a, 0x3b, 0x3b, 0x3c, 0x3d, + 0x3d, 0x3f, 0x3f, 0x40, 0x40, 0x42, 0x42, 0x43, + 0x43, 0x44, 0x44, 0x45, 0x45, 0x47, 0x47, 0x48, + 0x48, 0x49, 0x49, 0x4a, 0x4a, 0x4b, 0x4b, 0x4c, + 0x4c, 0x4d, 0x4d, 0x4d, 0x4f, 0x4f, 0x50, 0x50, + 0x52, 0x52, 0x53, 0x53, 0x53, 0x54, 0x54, 0x55, + 0x55, 0x56, 0x56, 0x56, 0x58, 0x58, 0x59, 0x59, + 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, 0x5c, 0x5c, 0x5c, + 0x5e, 0x5e, 0x5f, 0x5f, 0x5f, 0x60, 0x60, 0x60, + 0x61, 0x61, 0x62, 0x62, 0x62, 0x63, 0x63, 0x65, + 0x65, 0x65, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, + 0x68, 0x68, 0x69, 0x69, 0x69, 0x6a, 0x6a, 0x6a, + 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6e, 0x6e, + 0x6e, 0x6f, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x71, + 0x71, 0x71, 0x73, 0x73, 0x73, 0x74, 0x74, 0x74, + 0x75, 0x75, 0x75, 0x77, 0x77, 0x77, 0x78, 0x78, + 0x78, 0x79, 0x79, 0x79, 0x79, 0x7a, 0x7a, 0x7a, + 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, + 0x7d, 0x7d, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82, + 0x84, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85, 0x86, + 0x86, 0x86, 0x88, 0x88, 0x88, 0x88, 0x89, 0x89, + 0x89, 0x89, 0x8a, 0x8a, 0x8a, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8d, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8f, 0x8f, 0x8f, 0x90, 0x90, 0x90, 0x90, + 0x91, 0x91, 0x91, 0x91, 0x92, 0x92, 0x92, 0x92, + 0x93, 0x93, 0x93, 0x93, 0x94, 0x94, 0x94, 0x94, + 0x96, 0x96, 0x96, 0x96, 0x97, 0x97, 0x97, 0x97, + 0x98, 0x98, 0x98, 0x98, 0x99, 0x99, 0x99, 0x99, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9c, 0x9c, 0x9c, 0x9c, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa1, 0xa1, 0xa1, 0xa1, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xab, 0xab, + 0xab, 0xab, 0xac, 0xac, 0xac, 0xac, 0xac, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xae, 0xae, 0xae, 0xae, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xba, 0xba, 0xba, 0xba, 0xba, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, + 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, + 0xc3, 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc5, + 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc9, + 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xca, 0xca, 0xca, + 0xca, 0xca, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcc, + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xce, 0xce, 0xce, 0xce, 0xce, 0xcf, + 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xd0, 0xd0, 0xd0, + 0xd0, 0xd0, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, + 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd4, 0xd4, 0xd4, + 0xd4, 0xd4, 0xd4, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, + 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd8, 0xd8, + 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, + 0xd9, 0xda, 0xda, 0xda, 0xda, 0xda, 0xdb, 0xdb, + 0xdb, 0xdb, 0xdb, 0xdb, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xdf, + 0xdf, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe0, + 0xe0, 0xe0, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe2, + 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe3, 0xe3, 0xe3, + 0xe3, 0xe3, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, + 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe6, 0xe6, 0xe6, + 0xe6, 0xe6, 0xe6, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, + 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe9, 0xe9, + 0xe9, 0xe9, 0xe9, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xec, 0xec, 0xec, 0xec, 0xec, 0xed, 0xed, + 0xed, 0xed, 0xed, 0xed, 0xee, 0xee, 0xee, 0xee, + 0xee, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, + 0xf1, 0xf1, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf4, + 0xf4, 0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf5, + 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf7, + 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, 0xf8, + 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa, + 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, + 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, + 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x02, 0x03, 0x05, 0x05, 0x07, + 0x08, 0x09, 0x0a, 0x0a, 0x0c, 0x0d, 0x0e, 0x0e, + 0x10, 0x11, 0x12, 0x12, 0x14, 0x15, 0x16, 0x16, + 0x17, 0x18, 0x18, 0x1a, 0x1b, 0x1b, 0x1c, 0x1e, + 0x1e, 0x1f, 0x1f, 0x20, 0x22, 0x22, 0x23, 0x23, + 0x25, 0x26, 0x26, 0x27, 0x27, 0x28, 0x29, 0x29, + 0x2b, 0x2b, 0x2c, 0x2c, 0x2d, 0x2d, 0x2f, 0x30, + 0x30, 0x31, 0x31, 0x33, 0x33, 0x34, 0x34, 0x35, + 0x35, 0x37, 0x37, 0x38, 0x38, 0x39, 0x39, 0x3a, + 0x3a, 0x3b, 0x3b, 0x3b, 0x3c, 0x3c, 0x3d, 0x3d, + 0x3f, 0x3f, 0x40, 0x40, 0x42, 0x42, 0x42, 0x43, + 0x43, 0x44, 0x44, 0x45, 0x45, 0x47, 0x47, 0x47, + 0x48, 0x48, 0x49, 0x49, 0x49, 0x4a, 0x4a, 0x4b, + 0x4b, 0x4b, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4f, + 0x4f, 0x50, 0x50, 0x50, 0x52, 0x52, 0x52, 0x53, + 0x53, 0x54, 0x54, 0x54, 0x55, 0x55, 0x55, 0x56, + 0x56, 0x58, 0x58, 0x58, 0x59, 0x59, 0x59, 0x5a, + 0x5a, 0x5a, 0x5b, 0x5b, 0x5b, 0x5c, 0x5c, 0x5c, + 0x5e, 0x5e, 0x5e, 0x5f, 0x5f, 0x5f, 0x60, 0x60, + 0x60, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, 0x63, + 0x63, 0x63, 0x65, 0x65, 0x65, 0x66, 0x66, 0x66, + 0x66, 0x67, 0x67, 0x67, 0x68, 0x68, 0x68, 0x69, + 0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6a, 0x6c, 0x6c, + 0x6c, 0x6d, 0x6d, 0x6d, 0x6d, 0x6e, 0x6e, 0x6e, + 0x6f, 0x6f, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x71, + 0x71, 0x71, 0x71, 0x73, 0x73, 0x73, 0x74, 0x74, + 0x74, 0x74, 0x75, 0x75, 0x75, 0x75, 0x77, 0x77, + 0x77, 0x78, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, + 0x79, 0x7a, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, + 0x7b, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, + 0x7d, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, + 0x80, 0x81, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, + 0x82, 0x84, 0x84, 0x84, 0x84, 0x85, 0x85, 0x85, + 0x85, 0x86, 0x86, 0x86, 0x86, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x89, 0x89, 0x89, 0x89, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8f, 0x8f, 0x8f, 0x8f, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x91, 0x91, 0x91, 0x91, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x93, 0x93, 0x93, 0x93, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x98, 0x98, 0x98, + 0x98, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0xc2, + 0xc2, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, + 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc5, + 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, + 0xc7, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xca, 0xca, + 0xca, 0xca, 0xca, 0xca, 0xcb, 0xcb, 0xcb, 0xcb, + 0xcb, 0xcb, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xce, 0xce, + 0xce, 0xce, 0xce, 0xce, 0xcf, 0xcf, 0xcf, 0xcf, + 0xcf, 0xcf, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, + 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd3, 0xd3, + 0xd3, 0xd3, 0xd3, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, + 0xd4, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd7, + 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd8, 0xd8, 0xd8, + 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, + 0xd9, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xdb, + 0xdb, 0xdb, 0xdb, 0xdb, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, + 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, + 0xe0, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe1, 0xe1, + 0xe1, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe3, + 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe4, 0xe4, 0xe4, + 0xe4, 0xe4, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, + 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe7, 0xe7, + 0xe7, 0xe7, 0xe7, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, + 0xe8, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec, + 0xec, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xee, + 0xee, 0xee, 0xee, 0xee, 0xef, 0xef, 0xef, 0xef, + 0xef, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, + 0xf1, 0xf1, 0xf1, 0xf1, 0xf3, 0xf3, 0xf3, 0xf3, + 0xf3, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf5, 0xf5, + 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, + 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, + 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa, + 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, + 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + }, + { /* gamma 2 */ + {0x00, 0x01, 0x02, 0x05, 0x07, 0x08, 0x0a, 0x0c, + 0x0d, 0x0e, 0x10, 0x12, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x1a, 0x1b, 0x1c, 0x1e, 0x1f, 0x20, 0x22, + 0x23, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2b, 0x2c, + 0x2d, 0x2d, 0x2f, 0x30, 0x31, 0x33, 0x34, 0x34, + 0x35, 0x37, 0x38, 0x38, 0x39, 0x3a, 0x3b, 0x3b, + 0x3c, 0x3d, 0x3f, 0x3f, 0x40, 0x42, 0x42, 0x43, + 0x44, 0x44, 0x45, 0x47, 0x47, 0x48, 0x49, 0x49, + 0x4a, 0x4b, 0x4b, 0x4c, 0x4c, 0x4d, 0x4f, 0x4f, + 0x50, 0x50, 0x52, 0x53, 0x53, 0x54, 0x54, 0x55, + 0x55, 0x56, 0x56, 0x58, 0x58, 0x59, 0x5a, 0x5a, + 0x5b, 0x5b, 0x5c, 0x5c, 0x5e, 0x5e, 0x5f, 0x5f, + 0x60, 0x60, 0x61, 0x61, 0x62, 0x62, 0x63, 0x63, + 0x65, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67, 0x68, + 0x68, 0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6c, 0x6c, + 0x6d, 0x6d, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x70, + 0x70, 0x70, 0x71, 0x71, 0x73, 0x73, 0x73, 0x74, + 0x74, 0x75, 0x75, 0x75, 0x77, 0x77, 0x78, 0x78, + 0x78, 0x79, 0x79, 0x79, 0x7a, 0x7a, 0x7b, 0x7b, + 0x7b, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7f, 0x7f, + 0x7f, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x82, + 0x82, 0x82, 0x84, 0x84, 0x84, 0x85, 0x85, 0x85, + 0x86, 0x86, 0x86, 0x88, 0x88, 0x88, 0x89, 0x89, + 0x89, 0x8a, 0x8a, 0x8a, 0x8b, 0x8b, 0x8b, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e, 0x8f, 0x8f, + 0x8f, 0x90, 0x90, 0x90, 0x91, 0x91, 0x91, 0x91, + 0x92, 0x92, 0x92, 0x93, 0x93, 0x93, 0x93, 0x94, + 0x94, 0x94, 0x96, 0x96, 0x96, 0x97, 0x97, 0x97, + 0x97, 0x98, 0x98, 0x98, 0x98, 0x99, 0x99, 0x99, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9c, 0x9c, 0x9c, 0x9d, 0x9d, 0x9d, 0x9d, 0x9e, + 0x9e, 0x9e, 0x9e, 0xa0, 0xa0, 0xa0, 0xa0, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa2, 0xa2, 0xa2, 0xa2, 0xa3, + 0xa3, 0xa3, 0xa4, 0xa4, 0xa4, 0xa4, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa6, 0xa6, 0xa6, 0xa6, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa9, 0xa9, 0xa9, 0xa9, 0xab, + 0xab, 0xab, 0xab, 0xac, 0xac, 0xac, 0xac, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xae, 0xae, 0xae, 0xae, + 0xaf, 0xaf, 0xaf, 0xaf, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb1, 0xb1, 0xb1, 0xb1, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb3, 0xb3, 0xb3, 0xb3, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb6, 0xb6, 0xb6, 0xb6, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb9, 0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xc0, 0xc0, + 0xc0, 0xc0, 0xc0, 0xc2, 0xc2, 0xc2, 0xc2, 0xc3, + 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc6, + 0xc6, 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc7, + 0xc7, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xca, 0xca, + 0xca, 0xca, 0xca, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, + 0xcb, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xce, 0xce, 0xce, 0xce, 0xce, + 0xce, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xd0, 0xd0, + 0xd0, 0xd0, 0xd0, 0xd0, 0xd1, 0xd1, 0xd1, 0xd1, + 0xd1, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd4, 0xd4, + 0xd4, 0xd4, 0xd4, 0xd4, 0xd6, 0xd6, 0xd6, 0xd6, + 0xd6, 0xd6, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd8, + 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, + 0xd9, 0xd9, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, + 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xde, 0xde, 0xde, 0xde, 0xde, + 0xde, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xe0, + 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe1, + 0xe1, 0xe1, 0xe1, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, + 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe4, 0xe4, + 0xe4, 0xe4, 0xe4, 0xe4, 0xe5, 0xe5, 0xe5, 0xe5, + 0xe5, 0xe5, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, + 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe8, 0xe8, + 0xe8, 0xe8, 0xe8, 0xe8, 0xe9, 0xe9, 0xe9, 0xe9, + 0xe9, 0xe9, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xec, 0xec, 0xec, 0xec, 0xec, 0xed, 0xed, 0xed, + 0xed, 0xed, 0xed, 0xee, 0xee, 0xee, 0xee, 0xee, + 0xee, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, + 0xf1, 0xf1, 0xf1, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, + 0xf3, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf5, + 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, + 0xf6, 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, + 0xf7, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, + 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa, 0xfa, 0xfa, + 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, + 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb}, + {0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x05, + 0x07, 0x08, 0x09, 0x0a, 0x0d, 0x0e, 0x10, 0x11, + 0x12, 0x14, 0x15, 0x16, 0x16, 0x17, 0x18, 0x1a, + 0x1b, 0x1c, 0x1e, 0x1f, 0x20, 0x20, 0x22, 0x23, + 0x25, 0x26, 0x26, 0x27, 0x28, 0x29, 0x29, 0x2b, + 0x2c, 0x2d, 0x2d, 0x2f, 0x30, 0x30, 0x31, 0x33, + 0x33, 0x34, 0x35, 0x35, 0x37, 0x38, 0x38, 0x39, + 0x3a, 0x3a, 0x3b, 0x3b, 0x3c, 0x3d, 0x3d, 0x3f, + 0x3f, 0x40, 0x42, 0x42, 0x43, 0x43, 0x44, 0x44, + 0x45, 0x45, 0x47, 0x47, 0x48, 0x48, 0x49, 0x4a, + 0x4a, 0x4b, 0x4b, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, + 0x4f, 0x4f, 0x50, 0x50, 0x52, 0x52, 0x53, 0x53, + 0x54, 0x54, 0x55, 0x55, 0x56, 0x56, 0x56, 0x58, + 0x58, 0x59, 0x59, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, + 0x5c, 0x5c, 0x5c, 0x5e, 0x5e, 0x5f, 0x5f, 0x5f, + 0x60, 0x60, 0x61, 0x61, 0x61, 0x62, 0x62, 0x63, + 0x63, 0x63, 0x65, 0x65, 0x65, 0x66, 0x66, 0x67, + 0x67, 0x67, 0x68, 0x68, 0x68, 0x69, 0x69, 0x69, + 0x6a, 0x6a, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, + 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x70, 0x70, + 0x70, 0x71, 0x71, 0x71, 0x73, 0x73, 0x73, 0x73, + 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x77, 0x77, + 0x77, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x79, + 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7b, 0x7c, + 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7d, 0x7f, 0x7f, + 0x7f, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, + 0x82, 0x82, 0x82, 0x82, 0x84, 0x84, 0x84, 0x84, + 0x85, 0x85, 0x85, 0x85, 0x86, 0x86, 0x86, 0x88, + 0x88, 0x88, 0x88, 0x89, 0x89, 0x89, 0x89, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8b, 0x8b, 0x8b, 0x8b, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e, 0x8e, 0x8f, + 0x8f, 0x8f, 0x8f, 0x90, 0x90, 0x90, 0x90, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x92, 0x92, 0x92, 0x92, + 0x93, 0x93, 0x93, 0x93, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x96, 0x96, 0x96, 0x96, 0x97, 0x97, 0x97, + 0x97, 0x98, 0x98, 0x98, 0x98, 0x98, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x9a, 0x9a, 0x9a, 0x9a, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xad, 0xad, 0xad, 0xad, 0xad, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, + 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc3, 0xc3, + 0xc3, 0xc3, 0xc3, 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, + 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, + 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc9, 0xc9, 0xc9, + 0xc9, 0xc9, 0xc9, 0xca, 0xca, 0xca, 0xca, 0xca, + 0xca, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcc, + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xce, 0xce, 0xce, 0xce, + 0xce, 0xce, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, + 0xcf, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd1, + 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd3, 0xd3, + 0xd3, 0xd3, 0xd3, 0xd3, 0xd4, 0xd4, 0xd4, 0xd4, + 0xd4, 0xd4, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, + 0xd6, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd8, + 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, + 0xd9, 0xd9, 0xd9, 0xd9, 0xda, 0xda, 0xda, 0xda, + 0xda, 0xda, 0xda, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, + 0xdb, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xdf, 0xdf, + 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, + 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, + 0xe1, 0xe1, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, + 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe4, + 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe5, 0xe5, 0xe5, + 0xe5, 0xe5, 0xe5, 0xe5, 0xe6, 0xe6, 0xe6, 0xe6, + 0xe6, 0xe6, 0xe6, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, + 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe9, + 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec, + 0xec, 0xec, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, + 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xef, + 0xef, 0xef, 0xef, 0xef, 0xef, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, + 0xf1, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf4, + 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf5, 0xf5, + 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf6, + 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, + 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, + 0xf9, 0xf9, 0xf9, 0xf9, 0xfa, 0xfa, 0xfa, 0xfa, + 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb}, + {0x00, 0x00, 0x00, 0x01, 0x02, 0x05, 0x07, 0x08, + 0x09, 0x0a, 0x0c, 0x0e, 0x10, 0x11, 0x12, 0x14, + 0x15, 0x16, 0x17, 0x18, 0x1a, 0x1b, 0x1c, 0x1e, + 0x1f, 0x20, 0x20, 0x22, 0x23, 0x25, 0x26, 0x27, + 0x28, 0x28, 0x29, 0x2b, 0x2c, 0x2d, 0x2d, 0x2f, + 0x30, 0x31, 0x31, 0x33, 0x34, 0x35, 0x35, 0x37, + 0x38, 0x38, 0x39, 0x3a, 0x3a, 0x3b, 0x3c, 0x3c, + 0x3d, 0x3f, 0x3f, 0x40, 0x40, 0x42, 0x43, 0x43, + 0x44, 0x44, 0x45, 0x47, 0x47, 0x48, 0x48, 0x49, + 0x4a, 0x4a, 0x4b, 0x4b, 0x4c, 0x4c, 0x4d, 0x4d, + 0x4f, 0x4f, 0x50, 0x50, 0x52, 0x52, 0x53, 0x53, + 0x54, 0x54, 0x55, 0x55, 0x56, 0x56, 0x58, 0x58, + 0x59, 0x59, 0x5a, 0x5a, 0x5b, 0x5b, 0x5c, 0x5c, + 0x5c, 0x5e, 0x5e, 0x5f, 0x5f, 0x60, 0x60, 0x61, + 0x61, 0x61, 0x62, 0x62, 0x63, 0x63, 0x65, 0x65, + 0x65, 0x66, 0x66, 0x67, 0x67, 0x67, 0x68, 0x68, + 0x69, 0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6c, 0x6c, + 0x6d, 0x6d, 0x6d, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, + 0x70, 0x70, 0x70, 0x71, 0x71, 0x71, 0x73, 0x73, + 0x73, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x77, + 0x77, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x7a, + 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, + 0x7c, 0x7d, 0x7d, 0x7d, 0x7f, 0x7f, 0x7f, 0x80, + 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x82, 0x82, + 0x82, 0x84, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85, + 0x86, 0x86, 0x86, 0x88, 0x88, 0x88, 0x88, 0x89, + 0x89, 0x89, 0x8a, 0x8a, 0x8a, 0x8a, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8f, 0x8f, 0x8f, 0x8f, 0x90, 0x90, 0x90, + 0x91, 0x91, 0x91, 0x91, 0x92, 0x92, 0x92, 0x92, + 0x93, 0x93, 0x93, 0x93, 0x94, 0x94, 0x94, 0x94, + 0x96, 0x96, 0x96, 0x96, 0x97, 0x97, 0x97, 0x97, + 0x98, 0x98, 0x98, 0x98, 0x99, 0x99, 0x99, 0x99, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9c, 0x9c, 0x9c, 0x9c, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa1, 0xa1, 0xa1, 0xa1, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa6, 0xa6, 0xa6, 0xa6, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xac, 0xac, 0xac, 0xac, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb4, 0xb3, 0xb4, 0xb4, 0xb4, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0xc2, + 0xc2, 0xc2, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xc3, + 0xc3, 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc5, + 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, + 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xca, 0xca, + 0xca, 0xca, 0xca, 0xca, 0xcb, 0xcb, 0xcb, 0xcb, + 0xcb, 0xcb, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xce, 0xce, + 0xce, 0xce, 0xce, 0xce, 0xcf, 0xcf, 0xcf, 0xcf, + 0xcf, 0xcf, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, + 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd3, 0xd3, + 0xd3, 0xd3, 0xd3, 0xd3, 0xd4, 0xd4, 0xd4, 0xd4, + 0xd4, 0xd4, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, + 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd8, 0xd8, + 0xd8, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, 0xd9, + 0xd9, 0xd9, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, + 0xda, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xde, 0xde, 0xde, + 0xde, 0xde, 0xde, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, + 0xdf, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, + 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe2, 0xe2, + 0xe2, 0xe2, 0xe2, 0xe2, 0xe3, 0xe3, 0xe3, 0xe3, + 0xe3, 0xe3, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, + 0xe4, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe6, + 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe7, 0xe7, 0xe7, + 0xe7, 0xe7, 0xe7, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, + 0xe8, 0xe8, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xec, 0xec, + 0xec, 0xec, 0xec, 0xec, 0xec, 0xed, 0xed, 0xed, + 0xed, 0xed, 0xed, 0xee, 0xee, 0xee, 0xee, 0xee, + 0xee, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, 0xf1, + 0xf1, 0xf1, 0xf1, 0xf1, 0xf3, 0xf3, 0xf3, 0xf3, + 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, + 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, + 0xf6, 0xf6, 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, + 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, + 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa, + 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, + 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb} + }, + { /* gamma 3 - from tp6810 + cx0342 */ + {0x08, 0x09, 0x0c, 0x0d, 0x10, 0x11, 0x14, 0x15, + 0x17, 0x18, 0x1a, 0x1c, 0x1e, 0x1f, 0x20, 0x23, + 0x25, 0x26, 0x27, 0x28, 0x2b, 0x2c, 0x2d, 0x2f, + 0x30, 0x31, 0x33, 0x34, 0x35, 0x37, 0x38, 0x39, + 0x3a, 0x3b, 0x3c, 0x3d, 0x3f, 0x40, 0x42, 0x43, + 0x44, 0x45, 0x47, 0x48, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4d, 0x4f, 0x50, 0x52, 0x53, 0x53, + 0x54, 0x55, 0x56, 0x56, 0x58, 0x59, 0x5a, 0x5a, + 0x5b, 0x5c, 0x5c, 0x5e, 0x5f, 0x5f, 0x60, 0x61, + 0x61, 0x62, 0x63, 0x63, 0x65, 0x66, 0x66, 0x67, + 0x68, 0x68, 0x69, 0x69, 0x6a, 0x6c, 0x6c, 0x6d, + 0x6d, 0x6e, 0x6f, 0x6f, 0x70, 0x70, 0x71, 0x73, + 0x73, 0x74, 0x74, 0x75, 0x75, 0x77, 0x77, 0x78, + 0x78, 0x79, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, 0x7c, + 0x7d, 0x7d, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x81, + 0x82, 0x82, 0x84, 0x84, 0x85, 0x85, 0x86, 0x86, + 0x86, 0x88, 0x88, 0x89, 0x89, 0x8a, 0x8a, 0x8b, + 0x8b, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8f, 0x8f, + 0x90, 0x90, 0x91, 0x91, 0x91, 0x92, 0x92, 0x93, + 0x93, 0x93, 0x94, 0x94, 0x96, 0x96, 0x97, 0x97, + 0x97, 0x98, 0x98, 0x99, 0x99, 0x99, 0x9a, 0x9a, + 0x9a, 0x9b, 0x9b, 0x9c, 0x9c, 0x9c, 0x9d, 0x9d, + 0x9e, 0x9e, 0x9e, 0xa0, 0xa0, 0xa0, 0xa1, 0xa1, + 0xa2, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, + 0xa4, 0xa5, 0xa5, 0xa5, 0xa6, 0xa6, 0xa8, 0xa8, + 0xa8, 0xa9, 0xa9, 0xa9, 0xab, 0xab, 0xab, 0xac, + 0xac, 0xac, 0xad, 0xad, 0xad, 0xae, 0xae, 0xae, + 0xaf, 0xaf, 0xaf, 0xb0, 0xb0, 0xb0, 0xb1, 0xb1, + 0xb1, 0xb2, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3, 0xb3, + 0xb4, 0xb4, 0xb4, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, + 0xb7, 0xb8, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, + 0xba, 0xba, 0xba, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, + 0xbd, 0xbd, 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, + 0xbf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0xc2, 0xc2, + 0xc3, 0xc3, 0xc3, 0xc3, 0xc4, 0xc4, 0xc4, 0xc5, + 0xc5, 0xc5, 0xc5, 0xc6, 0xc6, 0xc6, 0xc6, 0xc7, + 0xc7, 0xc7, 0xc9, 0xc9, 0xc9, 0xc9, 0xca, 0xca, + 0xca, 0xca, 0xcb, 0xcb, 0xcb, 0xcb, 0xcc, 0xcc, + 0xcc, 0xcd, 0xcd, 0xcd, 0xcd, 0xce, 0xce, 0xce, + 0xce, 0xcf, 0xcf, 0xcf, 0xcf, 0xd0, 0xd0, 0xd0, + 0xd0, 0xd1, 0xd1, 0xd1, 0xd1, 0xd3, 0xd3, 0xd3, + 0xd3, 0xd4, 0xd4, 0xd4, 0xd4, 0xd6, 0xd6, 0xd6, + 0xd6, 0xd7, 0xd7, 0xd7, 0xd7, 0xd8, 0xd8, 0xd8, + 0xd8, 0xd9, 0xd9, 0xd9, 0xd9, 0xda, 0xda, 0xda, + 0xda, 0xda, 0xdb, 0xdb, 0xdb, 0xdb, 0xdd, 0xdd, + 0xdd, 0xdd, 0xde, 0xde, 0xde, 0xde, 0xdf, 0xdf, + 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe0, 0xe1, + 0xe1, 0xe1, 0xe1, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, + 0xe3, 0xe3, 0xe3, 0xe3, 0xe4, 0xe4, 0xe4, 0xe4, + 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe6, 0xe6, 0xe6, + 0xe6, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe8, 0xe8, + 0xe8, 0xe8, 0xe8, 0xe9, 0xe9, 0xe9, 0xe9, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec, + 0xed, 0xed, 0xed, 0xed, 0xed, 0xee, 0xee, 0xee, + 0xee, 0xee, 0xef, 0xef, 0xef, 0xef, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, + 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, + 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, + 0xf6, 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, + 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, + 0xf9, 0xf9, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, + 0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0x03, 0x05, 0x07, 0x09, 0x0a, 0x0c, 0x0d, 0x10, + 0x11, 0x12, 0x14, 0x15, 0x17, 0x18, 0x1a, 0x1b, + 0x1c, 0x1e, 0x1f, 0x20, 0x22, 0x23, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2b, 0x2c, 0x2c, 0x2d, 0x2f, + 0x30, 0x31, 0x33, 0x33, 0x34, 0x35, 0x37, 0x38, + 0x38, 0x39, 0x3a, 0x3b, 0x3b, 0x3c, 0x3d, 0x3f, + 0x3f, 0x40, 0x42, 0x42, 0x43, 0x44, 0x45, 0x45, + 0x47, 0x47, 0x48, 0x49, 0x49, 0x4a, 0x4b, 0x4b, + 0x4c, 0x4d, 0x4d, 0x4f, 0x4f, 0x50, 0x52, 0x52, + 0x53, 0x53, 0x54, 0x54, 0x55, 0x55, 0x56, 0x58, + 0x58, 0x59, 0x59, 0x5a, 0x5a, 0x5b, 0x5b, 0x5c, + 0x5c, 0x5e, 0x5e, 0x5f, 0x5f, 0x60, 0x60, 0x61, + 0x61, 0x62, 0x62, 0x63, 0x63, 0x65, 0x65, 0x66, + 0x66, 0x67, 0x67, 0x67, 0x68, 0x68, 0x69, 0x69, + 0x6a, 0x6a, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6e, + 0x6e, 0x6f, 0x6f, 0x6f, 0x70, 0x70, 0x71, 0x71, + 0x71, 0x73, 0x73, 0x74, 0x74, 0x74, 0x75, 0x75, + 0x77, 0x77, 0x77, 0x78, 0x78, 0x79, 0x79, 0x79, + 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, + 0x7d, 0x7d, 0x7d, 0x7f, 0x7f, 0x7f, 0x80, 0x80, + 0x80, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x84, + 0x84, 0x84, 0x85, 0x85, 0x85, 0x86, 0x86, 0x86, + 0x88, 0x88, 0x88, 0x89, 0x89, 0x89, 0x8a, 0x8a, + 0x8a, 0x8b, 0x8b, 0x8b, 0x8d, 0x8d, 0x8d, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f, 0x90, 0x90, + 0x90, 0x91, 0x91, 0x91, 0x91, 0x92, 0x92, 0x92, + 0x93, 0x93, 0x93, 0x93, 0x94, 0x94, 0x94, 0x96, + 0x96, 0x96, 0x96, 0x97, 0x97, 0x97, 0x98, 0x98, + 0x98, 0x98, 0x99, 0x99, 0x99, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9b, 0x9b, 0x9b, 0x9b, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9d, 0x9d, 0x9d, 0x9e, 0x9e, 0x9e, 0x9e, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xab, 0xab, 0xab, + 0xab, 0xac, 0xac, 0xac, 0xac, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xae, 0xae, 0xae, 0xae, 0xaf, 0xaf, + 0xaf, 0xaf, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb8, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xc0, 0xc0, 0xc0, + 0xc0, 0xc0, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc3, + 0xc3, 0xc3, 0xc3, 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, + 0xc7, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xca, 0xca, + 0xca, 0xca, 0xca, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, + 0xcb, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xce, 0xce, 0xce, 0xce, + 0xce, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xd0, + 0xd0, 0xd0, 0xd0, 0xd0, 0xd1, 0xd1, 0xd1, 0xd1, + 0xd1, 0xd1, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd4, + 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd6, 0xd6, 0xd6, + 0xd6, 0xd6, 0xd6, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, + 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, + 0xd9, 0xd9, 0xd9, 0xd9, 0xda, 0xda, 0xda, 0xda, + 0xda, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xde, 0xde, 0xde, + 0xde, 0xde, 0xde, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, + 0xdf, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe1, + 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe2, 0xe2, 0xe2, + 0xe2, 0xe2, 0xe2, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, + 0xe3, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe5, + 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe6, 0xe6, 0xe6, + 0xe6, 0xe6, 0xe6, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, + 0xe7, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe9, + 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec, 0xec, + 0xec, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xee, + 0xee, 0xee, 0xee, 0xee, 0xee, 0xef, 0xef, 0xef, + 0xef, 0xef, 0xef, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf3, + 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, + 0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, + 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, + 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, + 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, + 0xf9, 0xf9, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, + 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, + 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0x07, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, + 0x16, 0x17, 0x18, 0x1b, 0x1c, 0x1e, 0x1f, 0x20, + 0x23, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2b, 0x2d, + 0x2f, 0x30, 0x31, 0x33, 0x34, 0x35, 0x37, 0x38, + 0x39, 0x3a, 0x3b, 0x3b, 0x3c, 0x3d, 0x3f, 0x40, + 0x42, 0x43, 0x44, 0x44, 0x45, 0x47, 0x48, 0x49, + 0x4a, 0x4a, 0x4b, 0x4c, 0x4d, 0x4d, 0x4f, 0x50, + 0x52, 0x52, 0x53, 0x54, 0x55, 0x55, 0x56, 0x58, + 0x58, 0x59, 0x5a, 0x5b, 0x5b, 0x5c, 0x5e, 0x5e, + 0x5f, 0x5f, 0x60, 0x61, 0x61, 0x62, 0x63, 0x63, + 0x65, 0x65, 0x66, 0x67, 0x67, 0x68, 0x68, 0x69, + 0x6a, 0x6a, 0x6c, 0x6c, 0x6d, 0x6d, 0x6e, 0x6e, + 0x6f, 0x70, 0x70, 0x71, 0x71, 0x73, 0x73, 0x74, + 0x74, 0x75, 0x75, 0x77, 0x77, 0x78, 0x78, 0x79, + 0x79, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, 0x7c, 0x7d, + 0x7d, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x81, + 0x82, 0x82, 0x84, 0x84, 0x85, 0x85, 0x86, 0x86, + 0x88, 0x88, 0x88, 0x89, 0x89, 0x8a, 0x8a, 0x8b, + 0x8b, 0x8b, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e, 0x8f, + 0x8f, 0x90, 0x90, 0x90, 0x91, 0x91, 0x92, 0x92, + 0x92, 0x93, 0x93, 0x94, 0x94, 0x94, 0x96, 0x96, + 0x96, 0x97, 0x97, 0x98, 0x98, 0x98, 0x99, 0x99, + 0x99, 0x9a, 0x9a, 0x9b, 0x9b, 0x9b, 0x9c, 0x9c, + 0x9c, 0x9d, 0x9d, 0x9d, 0x9e, 0x9e, 0x9e, 0xa0, + 0xa0, 0xa1, 0xa1, 0xa1, 0xa2, 0xa2, 0xa2, 0xa3, + 0xa3, 0xa3, 0xa4, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, + 0xa6, 0xa6, 0xa6, 0xa8, 0xa8, 0xa8, 0xa8, 0xa9, + 0xa9, 0xa9, 0xab, 0xab, 0xab, 0xac, 0xac, 0xac, + 0xad, 0xad, 0xad, 0xae, 0xae, 0xae, 0xaf, 0xaf, + 0xaf, 0xaf, 0xb0, 0xb0, 0xb0, 0xb1, 0xb1, 0xb1, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3, 0xb3, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, + 0xb9, 0xba, 0xba, 0xba, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbe, 0xbf, + 0xbf, 0xbf, 0xbf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, + 0xc2, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xc3, 0xc4, + 0xc4, 0xc4, 0xc5, 0xc5, 0xc5, 0xc5, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc7, 0xc9, 0xc9, + 0xc9, 0xc9, 0xca, 0xca, 0xca, 0xca, 0xcb, 0xcb, + 0xcb, 0xcb, 0xcc, 0xcc, 0xcc, 0xcc, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xce, 0xce, 0xce, 0xce, 0xcf, + 0xcf, 0xcf, 0xcf, 0xd0, 0xd0, 0xd0, 0xd0, 0xd1, + 0xd1, 0xd1, 0xd1, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, + 0xd4, 0xd4, 0xd4, 0xd4, 0xd6, 0xd6, 0xd6, 0xd6, + 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd8, 0xd8, 0xd8, + 0xd8, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xda, 0xda, + 0xda, 0xda, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdd, + 0xdd, 0xdd, 0xdd, 0xde, 0xde, 0xde, 0xde, 0xde, + 0xdf, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe0, + 0xe0, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe2, 0xe2, + 0xe2, 0xe2, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe4, + 0xe4, 0xe4, 0xe4, 0xe4, 0xe5, 0xe5, 0xe5, 0xe5, + 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe7, 0xe7, 0xe7, + 0xe7, 0xe7, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe9, + 0xe9, 0xe9, 0xe9, 0xe9, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xec, 0xec, 0xec, 0xec, 0xec, 0xed, 0xed, + 0xed, 0xed, 0xed, 0xee, 0xee, 0xee, 0xee, 0xee, + 0xef, 0xef, 0xef, 0xef, 0xef, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf3, + 0xf3, 0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf4, + 0xf4, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, + 0xf6, 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, + 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, + 0xf9, 0xf9, 0xf9, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, + 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + }, + { /* gamma 4 - from tp6800 + soi763a */ + {0x11, 0x14, 0x15, 0x17, 0x1a, 0x1b, 0x1e, 0x1f, + 0x22, 0x23, 0x25, 0x27, 0x28, 0x2b, 0x2c, 0x2d, + 0x2f, 0x31, 0x33, 0x34, 0x35, 0x38, 0x39, 0x3a, + 0x3b, 0x3c, 0x3d, 0x40, 0x42, 0x43, 0x44, 0x45, + 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4f, + 0x50, 0x52, 0x53, 0x53, 0x54, 0x55, 0x56, 0x58, + 0x59, 0x5a, 0x5b, 0x5b, 0x5c, 0x5e, 0x5f, 0x60, + 0x61, 0x61, 0x62, 0x63, 0x65, 0x65, 0x66, 0x67, + 0x68, 0x68, 0x69, 0x6a, 0x6c, 0x6c, 0x6d, 0x6e, + 0x6f, 0x6f, 0x70, 0x71, 0x71, 0x73, 0x74, 0x74, + 0x75, 0x77, 0x77, 0x78, 0x79, 0x79, 0x7a, 0x7a, + 0x7b, 0x7c, 0x7c, 0x7d, 0x7f, 0x7f, 0x80, 0x80, + 0x81, 0x81, 0x82, 0x84, 0x84, 0x85, 0x85, 0x86, + 0x86, 0x88, 0x89, 0x89, 0x8a, 0x8a, 0x8b, 0x8b, + 0x8d, 0x8d, 0x8e, 0x8e, 0x8f, 0x90, 0x90, 0x91, + 0x91, 0x92, 0x92, 0x93, 0x93, 0x94, 0x94, 0x96, + 0x96, 0x97, 0x97, 0x98, 0x98, 0x98, 0x99, 0x99, + 0x9a, 0x9a, 0x9b, 0x9b, 0x9c, 0x9c, 0x9d, 0x9d, + 0x9e, 0x9e, 0xa0, 0xa0, 0xa0, 0xa1, 0xa1, 0xa2, + 0xa2, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa5, 0xa5, + 0xa6, 0xa6, 0xa6, 0xa8, 0xa8, 0xa9, 0xa9, 0xab, + 0xab, 0xab, 0xac, 0xac, 0xad, 0xad, 0xad, 0xae, + 0xae, 0xaf, 0xaf, 0xaf, 0xb0, 0xb0, 0xb1, 0xb1, + 0xb1, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, + 0xb4, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb8, 0xb8, + 0xb8, 0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xbc, + 0xbc, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbe, 0xbf, + 0xbf, 0xbf, 0xc0, 0xc0, 0xc0, 0xc2, 0xc2, 0xc2, + 0xc3, 0xc3, 0xc3, 0xc4, 0xc4, 0xc4, 0xc5, 0xc5, + 0xc5, 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc9, + 0xc9, 0xc9, 0xca, 0xca, 0xca, 0xcb, 0xcb, 0xcb, + 0xcb, 0xcc, 0xcc, 0xcc, 0xcd, 0xcd, 0xcd, 0xce, + 0xce, 0xce, 0xcf, 0xcf, 0xcf, 0xcf, 0xd0, 0xd0, + 0xd0, 0xd1, 0xd1, 0xd1, 0xd3, 0xd3, 0xd3, 0xd3, + 0xd4, 0xd4, 0xd4, 0xd6, 0xd6, 0xd6, 0xd7, 0xd7, + 0xd7, 0xd7, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, + 0xd9, 0xda, 0xda, 0xda, 0xdb, 0xdb, 0xdb, 0xdb, + 0xdd, 0xdd, 0xdd, 0xde, 0xde, 0xde, 0xde, 0xdf, + 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, + 0xe1, 0xe1, 0xe2, 0xe2, 0xe2, 0xe2, 0xe3, 0xe3, + 0xe3, 0xe3, 0xe4, 0xe4, 0xe4, 0xe5, 0xe5, 0xe5, + 0xe5, 0xe6, 0xe6, 0xe6, 0xe6, 0xe7, 0xe7, 0xe7, + 0xe7, 0xe8, 0xe8, 0xe8, 0xe8, 0xe9, 0xe9, 0xe9, + 0xe9, 0xeb, 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, + 0xec, 0xed, 0xed, 0xed, 0xed, 0xee, 0xee, 0xee, + 0xee, 0xef, 0xef, 0xef, 0xef, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf3, 0xf3, 0xf3, + 0xf3, 0xf4, 0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, + 0xf5, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf7, 0xf7, + 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, + 0xf9, 0xf9, 0xfa, 0xf9, 0xfa, 0xfa, 0xfa, 0xfa, + 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb}, + {0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x11, 0x14, 0x15, + 0x16, 0x17, 0x1a, 0x1b, 0x1c, 0x1e, 0x1f, 0x20, + 0x23, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2b, 0x2c, + 0x2d, 0x2f, 0x30, 0x31, 0x33, 0x34, 0x34, 0x35, + 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3c, 0x3d, + 0x3f, 0x40, 0x42, 0x42, 0x43, 0x44, 0x45, 0x45, + 0x47, 0x48, 0x49, 0x49, 0x4a, 0x4b, 0x4b, 0x4c, + 0x4d, 0x4f, 0x4f, 0x50, 0x52, 0x52, 0x53, 0x54, + 0x54, 0x55, 0x55, 0x56, 0x58, 0x58, 0x59, 0x5a, + 0x5a, 0x5b, 0x5b, 0x5c, 0x5e, 0x5e, 0x5f, 0x5f, + 0x60, 0x60, 0x61, 0x61, 0x62, 0x63, 0x63, 0x65, + 0x65, 0x66, 0x66, 0x67, 0x67, 0x68, 0x68, 0x69, + 0x69, 0x6a, 0x6a, 0x6c, 0x6c, 0x6d, 0x6d, 0x6e, + 0x6e, 0x6f, 0x6f, 0x70, 0x70, 0x71, 0x71, 0x73, + 0x73, 0x74, 0x74, 0x74, 0x75, 0x75, 0x77, 0x77, + 0x78, 0x78, 0x79, 0x79, 0x79, 0x7a, 0x7a, 0x7b, + 0x7b, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7f, 0x7f, + 0x7f, 0x80, 0x80, 0x81, 0x81, 0x81, 0x82, 0x82, + 0x84, 0x84, 0x84, 0x85, 0x85, 0x86, 0x86, 0x86, + 0x88, 0x88, 0x88, 0x89, 0x89, 0x8a, 0x8a, 0x8a, + 0x8b, 0x8b, 0x8b, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, + 0x8e, 0x8f, 0x8f, 0x90, 0x90, 0x90, 0x91, 0x91, + 0x91, 0x92, 0x92, 0x92, 0x93, 0x93, 0x93, 0x94, + 0x94, 0x94, 0x96, 0x96, 0x96, 0x97, 0x97, 0x97, + 0x98, 0x98, 0x98, 0x98, 0x99, 0x99, 0x99, 0x9a, + 0x9a, 0x9a, 0x9b, 0x9b, 0x9b, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9d, 0x9d, 0x9d, 0x9e, 0x9e, 0x9e, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa1, 0xa1, 0xa1, 0xa2, 0xa2, + 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa4, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa8, 0xa8, 0xa8, 0xa9, 0xa9, 0xa9, 0xa9, 0xab, + 0xaa, 0xab, 0xab, 0xac, 0xac, 0xac, 0xad, 0xad, + 0xad, 0xad, 0xae, 0xae, 0xae, 0xae, 0xaf, 0xaf, + 0xaf, 0xaf, 0xb0, 0xb0, 0xb0, 0xb0, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb2, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb4, 0xb4, 0xb4, 0xb4, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb7, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xb9, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbf, 0xbf, 0xbf, 0xbf, 0xc0, 0xc0, 0xc0, 0xc0, + 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, + 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc5, 0xc5, + 0xc5, 0xc5, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc7, + 0xc7, 0xc7, 0xc7, 0xc7, 0xc9, 0xc9, 0xc9, 0xc9, + 0xca, 0xca, 0xca, 0xca, 0xca, 0xcb, 0xcb, 0xcb, + 0xcb, 0xcb, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xce, 0xce, 0xce, 0xce, + 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xd0, 0xd0, 0xd0, + 0xd0, 0xd0, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd3, + 0xd3, 0xd3, 0xd3, 0xd3, 0xd4, 0xd4, 0xd4, 0xd4, + 0xd4, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd7, 0xd7, + 0xd7, 0xd7, 0xd7, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, + 0xd8, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xda, 0xda, + 0xda, 0xda, 0xda, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xde, 0xde, 0xde, + 0xde, 0xde, 0xde, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, + 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe1, + 0xe1, 0xe1, 0xe1, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, + 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe4, 0xe4, + 0xe4, 0xe4, 0xe4, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, + 0xe5, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe7, 0xe7, + 0xe7, 0xe7, 0xe7, 0xe7, 0xe8, 0xe8, 0xe8, 0xe8, + 0xe8, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec, + 0xec, 0xec, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, + 0xee, 0xee, 0xee, 0xee, 0xee, 0xef, 0xef, 0xef, + 0xef, 0xef, 0xef, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf3, + 0xf3, 0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf4, + 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, + 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf7, 0xf7, + 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, + 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa, + 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, + 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb}, + {0x0d, 0x10, 0x11, 0x14, 0x15, 0x17, 0x18, 0x1b, + 0x1c, 0x1e, 0x20, 0x22, 0x23, 0x26, 0x27, 0x28, + 0x29, 0x2b, 0x2d, 0x2f, 0x30, 0x31, 0x33, 0x34, + 0x35, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, + 0x3f, 0x40, 0x42, 0x43, 0x44, 0x45, 0x47, 0x48, + 0x49, 0x4a, 0x4b, 0x4b, 0x4c, 0x4d, 0x4f, 0x50, + 0x52, 0x52, 0x53, 0x54, 0x55, 0x56, 0x56, 0x58, + 0x59, 0x5a, 0x5a, 0x5b, 0x5c, 0x5e, 0x5e, 0x5f, + 0x60, 0x60, 0x61, 0x62, 0x62, 0x63, 0x65, 0x65, + 0x66, 0x67, 0x67, 0x68, 0x69, 0x69, 0x6a, 0x6c, + 0x6c, 0x6d, 0x6d, 0x6e, 0x6f, 0x6f, 0x70, 0x70, + 0x71, 0x73, 0x73, 0x74, 0x74, 0x75, 0x75, 0x77, + 0x78, 0x78, 0x79, 0x79, 0x7a, 0x7a, 0x7b, 0x7b, + 0x7c, 0x7c, 0x7d, 0x7d, 0x7f, 0x7f, 0x80, 0x80, + 0x81, 0x81, 0x82, 0x82, 0x84, 0x84, 0x85, 0x85, + 0x86, 0x86, 0x88, 0x88, 0x89, 0x89, 0x8a, 0x8a, + 0x8b, 0x8b, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8f, + 0x8f, 0x90, 0x90, 0x91, 0x91, 0x91, 0x92, 0x92, + 0x93, 0x93, 0x94, 0x94, 0x94, 0x96, 0x96, 0x97, + 0x97, 0x98, 0x98, 0x98, 0x99, 0x99, 0x9a, 0x9a, + 0x9a, 0x9b, 0x9b, 0x9c, 0x9c, 0x9c, 0x9d, 0x9d, + 0x9d, 0x9e, 0x9e, 0xa0, 0xa0, 0xa0, 0xa1, 0xa1, + 0xa1, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, + 0xa4, 0xa5, 0xa5, 0xa5, 0xa6, 0xa6, 0xa8, 0xa8, + 0xa8, 0xa9, 0xa9, 0xa9, 0xab, 0xab, 0xab, 0xac, + 0xac, 0xac, 0xad, 0xad, 0xad, 0xae, 0xae, 0xae, + 0xaf, 0xaf, 0xaf, 0xb0, 0xb0, 0xb0, 0xb1, 0xb1, + 0xb1, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3, 0xb3, 0xb4, + 0xb4, 0xb4, 0xb6, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, + 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xba, + 0xba, 0xba, 0xba, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, + 0xbd, 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf, + 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0xc2, 0xc2, 0xc3, + 0xc3, 0xc3, 0xc3, 0xc4, 0xc4, 0xc4, 0xc5, 0xc5, + 0xc5, 0xc5, 0xc6, 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, + 0xc7, 0xc9, 0xc9, 0xc9, 0xc9, 0xca, 0xca, 0xca, + 0xca, 0xcb, 0xcb, 0xcb, 0xcc, 0xcc, 0xcc, 0xcc, + 0xcd, 0xcd, 0xcd, 0xcd, 0xce, 0xce, 0xce, 0xce, + 0xcf, 0xcf, 0xcf, 0xcf, 0xd0, 0xd0, 0xd0, 0xd0, + 0xd1, 0xd1, 0xd1, 0xd1, 0xd3, 0xd3, 0xd3, 0xd3, + 0xd4, 0xd4, 0xd4, 0xd4, 0xd6, 0xd6, 0xd6, 0xd6, + 0xd7, 0xd7, 0xd7, 0xd7, 0xd8, 0xd8, 0xd8, 0xd8, + 0xd9, 0xd9, 0xd9, 0xd9, 0xda, 0xda, 0xda, 0xda, + 0xdb, 0xdb, 0xdb, 0xdb, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xde, 0xde, 0xde, 0xde, 0xdf, 0xdf, 0xdf, + 0xdf, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, + 0xe1, 0xe1, 0xe2, 0xe2, 0xe2, 0xe2, 0xe3, 0xe3, + 0xe3, 0xe3, 0xe3, 0xe4, 0xe4, 0xe4, 0xe4, 0xe5, + 0xe5, 0xe5, 0xe5, 0xe5, 0xe6, 0xe6, 0xe6, 0xe6, + 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe8, 0xe8, 0xe8, + 0xe8, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xeb, 0xeb, + 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec, 0xec, 0xed, + 0xed, 0xed, 0xed, 0xed, 0xee, 0xee, 0xee, 0xee, + 0xef, 0xef, 0xef, 0xef, 0xef, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf3, + 0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, + 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, + 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, + 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, + 0xf9, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, + 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb} + }, + { /* gamma 5 */ + {0x16, 0x18, 0x19, 0x1b, 0x1d, 0x1e, 0x20, 0x21, + 0x23, 0x24, 0x25, 0x27, 0x28, 0x2a, 0x2b, 0x2c, + 0x2d, 0x2f, 0x30, 0x31, 0x32, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, + 0x4f, 0x50, 0x51, 0x51, 0x52, 0x53, 0x54, 0x55, + 0x56, 0x56, 0x57, 0x58, 0x59, 0x59, 0x5a, 0x5b, + 0x5c, 0x5c, 0x5d, 0x5e, 0x5f, 0x5f, 0x60, 0x61, + 0x62, 0x62, 0x63, 0x64, 0x64, 0x65, 0x66, 0x66, + 0x67, 0x68, 0x68, 0x69, 0x6a, 0x6a, 0x6b, 0x6b, + 0x6c, 0x6d, 0x6d, 0x6e, 0x6f, 0x6f, 0x70, 0x70, + 0x71, 0x71, 0x72, 0x73, 0x73, 0x74, 0x74, 0x75, + 0x75, 0x76, 0x77, 0x77, 0x78, 0x78, 0x79, 0x79, + 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, 0x7d, 0x7d, 0x7e, + 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x82, + 0x82, 0x83, 0x83, 0x84, 0x84, 0x84, 0x85, 0x85, + 0x86, 0x86, 0x87, 0x87, 0x88, 0x88, 0x89, 0x89, + 0x8a, 0x8a, 0x8b, 0x8b, 0x8b, 0x8c, 0x8c, 0x8d, + 0x8d, 0x8e, 0x8e, 0x8e, 0x8f, 0x8f, 0x90, 0x90, + 0x91, 0x91, 0x91, 0x92, 0x92, 0x93, 0x93, 0x94, + 0x94, 0x94, 0x95, 0x95, 0x96, 0x96, 0x96, 0x97, + 0x97, 0x98, 0x98, 0x98, 0x99, 0x99, 0x9a, 0x9a, + 0x9a, 0x9b, 0x9b, 0x9b, 0x9c, 0x9c, 0x9d, 0x9d, + 0x9d, 0x9e, 0x9e, 0x9e, 0x9f, 0x9f, 0xa0, 0xa0, + 0xa0, 0xa1, 0xa1, 0xa1, 0xa2, 0xa2, 0xa2, 0xa3, + 0xa3, 0xa4, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, 0xa6, + 0xa6, 0xa6, 0xa7, 0xa7, 0xa7, 0xa8, 0xa8, 0xa8, + 0xa9, 0xa9, 0xa9, 0xaa, 0xaa, 0xaa, 0xab, 0xab, + 0xab, 0xac, 0xac, 0xac, 0xad, 0xad, 0xad, 0xae, + 0xae, 0xae, 0xaf, 0xaf, 0xaf, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb1, 0xb1, 0xb1, 0xb2, 0xb2, 0xb2, 0xb3, + 0xb3, 0xb3, 0xb4, 0xb4, 0xb4, 0xb4, 0xb5, 0xb5, + 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xba, 0xba, + 0xba, 0xba, 0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbf, 0xbf, 0xbf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, + 0xc1, 0xc1, 0xc1, 0xc2, 0xc2, 0xc2, 0xc3, 0xc3, + 0xc3, 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc5, 0xc5, + 0xc5, 0xc5, 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, + 0xc7, 0xc8, 0xc8, 0xc8, 0xc8, 0xc9, 0xc9, 0xc9, + 0xc9, 0xca, 0xca, 0xca, 0xca, 0xcb, 0xcb, 0xcb, + 0xcb, 0xcc, 0xcc, 0xcc, 0xcc, 0xcd, 0xcd, 0xcd, + 0xcd, 0xce, 0xce, 0xce, 0xce, 0xcf, 0xcf, 0xcf, + 0xcf, 0xd0, 0xd0, 0xd0, 0xd0, 0xd1, 0xd1, 0xd1, + 0xd1, 0xd2, 0xd2, 0xd2, 0xd2, 0xd3, 0xd3, 0xd3, + 0xd3, 0xd4, 0xd4, 0xd4, 0xd4, 0xd5, 0xd5, 0xd5, + 0xd5, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd7, 0xd7, + 0xd7, 0xd7, 0xd8, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, + 0xd9, 0xd9, 0xda, 0xda, 0xda, 0xda, 0xda, 0xdb, + 0xdb, 0xdb, 0xdb, 0xdc, 0xdc, 0xdc, 0xdc, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xde, 0xde, 0xde, 0xde, + 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, + 0xe0, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe2, 0xe2, + 0xe2, 0xe2, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe4, + 0xe4, 0xe4, 0xe4, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, + 0xe6, 0xe6, 0xe6, 0xe6, 0xe7, 0xe7, 0xe7, 0xe7, + 0xe7, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe9, 0xe9, + 0xe9, 0xe9, 0xea, 0xea, 0xea, 0xea, 0xea, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec, + 0xed, 0xed, 0xed, 0xed, 0xed, 0xee, 0xee, 0xee, + 0xee, 0xee, 0xef, 0xef, 0xef, 0xef, 0xef, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf3, 0xf3, 0xf3, + 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf5, + 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf6, + 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, + 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa, + 0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0x0f, 0x11, 0x12, 0x14, 0x15, 0x16, 0x18, 0x19, + 0x1a, 0x1b, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x31, 0x32, + 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x38, 0x39, + 0x3a, 0x3b, 0x3c, 0x3c, 0x3d, 0x3e, 0x3f, 0x3f, + 0x40, 0x41, 0x42, 0x42, 0x43, 0x44, 0x44, 0x45, + 0x46, 0x47, 0x47, 0x48, 0x49, 0x49, 0x4a, 0x4b, + 0x4b, 0x4c, 0x4c, 0x4d, 0x4e, 0x4e, 0x4f, 0x50, + 0x50, 0x51, 0x51, 0x52, 0x53, 0x53, 0x54, 0x54, + 0x55, 0x55, 0x56, 0x56, 0x57, 0x58, 0x58, 0x59, + 0x59, 0x5a, 0x5a, 0x5b, 0x5b, 0x5c, 0x5c, 0x5d, + 0x5d, 0x5e, 0x5e, 0x5f, 0x5f, 0x60, 0x60, 0x61, + 0x61, 0x62, 0x62, 0x63, 0x63, 0x64, 0x64, 0x65, + 0x65, 0x66, 0x66, 0x66, 0x67, 0x67, 0x68, 0x68, + 0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6c, + 0x6c, 0x6d, 0x6d, 0x6d, 0x6e, 0x6e, 0x6f, 0x6f, + 0x6f, 0x70, 0x70, 0x71, 0x71, 0x71, 0x72, 0x72, + 0x73, 0x73, 0x73, 0x74, 0x74, 0x75, 0x75, 0x75, + 0x76, 0x76, 0x76, 0x77, 0x77, 0x78, 0x78, 0x78, + 0x79, 0x79, 0x79, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, + 0x7b, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, + 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x81, + 0x81, 0x81, 0x82, 0x82, 0x82, 0x83, 0x83, 0x83, + 0x84, 0x84, 0x84, 0x84, 0x85, 0x85, 0x85, 0x86, + 0x86, 0x86, 0x87, 0x87, 0x87, 0x88, 0x88, 0x88, + 0x88, 0x89, 0x89, 0x89, 0x8a, 0x8a, 0x8a, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8c, 0x8c, 0x8c, 0x8d, 0x8d, + 0x8d, 0x8e, 0x8e, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f, + 0x90, 0x90, 0x90, 0x90, 0x91, 0x91, 0x91, 0x91, + 0x92, 0x92, 0x92, 0x93, 0x93, 0x93, 0x93, 0x94, + 0x94, 0x94, 0x94, 0x95, 0x95, 0x95, 0x96, 0x96, + 0x96, 0x96, 0x97, 0x97, 0x97, 0x97, 0x98, 0x98, + 0x98, 0x98, 0x99, 0x99, 0x99, 0x99, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9b, 0x9b, 0x9b, 0x9b, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9d, 0x9d, 0x9d, 0x9d, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9f, 0x9f, 0x9f, 0x9f, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa1, 0xa1, 0xa1, 0xa1, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa9, 0xa9, 0xa9, + 0xa9, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xab, + 0xab, 0xab, 0xac, 0xac, 0xac, 0xac, 0xac, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xae, 0xae, 0xae, 0xae, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xc0, 0xc0, 0xc0, + 0xc0, 0xc0, 0xc0, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, + 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, + 0xc3, 0xc3, 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, + 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, + 0xc7, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc9, 0xc9, + 0xc9, 0xc9, 0xc9, 0xc9, 0xca, 0xca, 0xca, 0xca, + 0xca, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcc, + 0xcc, 0xcc, 0xcc, 0xcc, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, + 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xd0, 0xd0, 0xd0, + 0xd0, 0xd0, 0xd0, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, + 0xd1, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd3, + 0xd3, 0xd3, 0xd3, 0xd3, 0xd4, 0xd4, 0xd4, 0xd4, + 0xd4, 0xd4, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, + 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd7, 0xd7, + 0xd7, 0xd7, 0xd7, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, + 0xd8, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xda, + 0xda, 0xda, 0xda, 0xda, 0xda, 0xdb, 0xdb, 0xdb, + 0xdb, 0xdb, 0xdb, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xde, 0xde, + 0xde, 0xde, 0xde, 0xde, 0xdf, 0xdf, 0xdf, 0xdf, + 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, + 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe2, 0xe2, + 0xe2, 0xe2, 0xe2, 0xe2, 0xe3, 0xe3, 0xe3, 0xe3, + 0xe3, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe5, + 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe6, 0xe6, 0xe6, + 0xe6, 0xe6, 0xe6, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, + 0xe7, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe9, 0xe9, + 0xe9, 0xe9, 0xe9, 0xe9, 0xea, 0xea, 0xea, 0xea, + 0xea, 0xea, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xed, 0xed, + 0xed, 0xed, 0xed, 0xee, 0xee, 0xee, 0xee, 0xee, + 0xee, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, + 0xf1, 0xf1, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, + 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, + 0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, + 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf7, 0xf7, + 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, + 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa, 0xfa, + 0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0x13, 0x15, 0x16, 0x18, 0x19, 0x1b, 0x1c, 0x1e, + 0x1f, 0x20, 0x22, 0x23, 0x24, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, + 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, + 0x42, 0x43, 0x44, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4d, 0x4e, + 0x4f, 0x50, 0x50, 0x51, 0x52, 0x53, 0x53, 0x54, + 0x55, 0x55, 0x56, 0x57, 0x57, 0x58, 0x59, 0x59, + 0x5a, 0x5b, 0x5b, 0x5c, 0x5d, 0x5d, 0x5e, 0x5f, + 0x5f, 0x60, 0x60, 0x61, 0x62, 0x62, 0x63, 0x63, + 0x64, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67, 0x68, + 0x69, 0x69, 0x6a, 0x6a, 0x6b, 0x6b, 0x6c, 0x6c, + 0x6d, 0x6d, 0x6e, 0x6e, 0x6f, 0x6f, 0x70, 0x70, + 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x74, 0x74, + 0x75, 0x75, 0x76, 0x76, 0x77, 0x77, 0x78, 0x78, + 0x79, 0x79, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, + 0x7c, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, + 0x80, 0x80, 0x81, 0x81, 0x81, 0x82, 0x82, 0x83, + 0x83, 0x84, 0x84, 0x84, 0x85, 0x85, 0x86, 0x86, + 0x86, 0x87, 0x87, 0x88, 0x88, 0x88, 0x89, 0x89, + 0x89, 0x8a, 0x8a, 0x8b, 0x8b, 0x8b, 0x8c, 0x8c, + 0x8c, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e, 0x8f, 0x8f, + 0x8f, 0x90, 0x90, 0x90, 0x91, 0x91, 0x92, 0x92, + 0x92, 0x93, 0x93, 0x93, 0x94, 0x94, 0x94, 0x95, + 0x95, 0x95, 0x96, 0x96, 0x96, 0x97, 0x97, 0x97, + 0x98, 0x98, 0x98, 0x99, 0x99, 0x99, 0x9a, 0x9a, + 0x9a, 0x9b, 0x9b, 0x9b, 0x9c, 0x9c, 0x9c, 0x9d, + 0x9d, 0x9d, 0x9e, 0x9e, 0x9e, 0x9e, 0x9f, 0x9f, + 0x9f, 0xa0, 0xa0, 0xa0, 0xa1, 0xa1, 0xa1, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, + 0xa4, 0xa5, 0xa5, 0xa5, 0xa5, 0xa6, 0xa6, 0xa6, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa8, 0xa8, 0xa8, 0xa9, + 0xa9, 0xa9, 0xa9, 0xaa, 0xaa, 0xaa, 0xab, 0xab, + 0xab, 0xab, 0xac, 0xac, 0xac, 0xac, 0xad, 0xad, + 0xad, 0xae, 0xae, 0xae, 0xae, 0xaf, 0xaf, 0xaf, + 0xaf, 0xb0, 0xb0, 0xb0, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xb9, + 0xba, 0xba, 0xba, 0xba, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, 0xc1, 0xc1, + 0xc1, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc3, 0xc3, + 0xc3, 0xc3, 0xc4, 0xc4, 0xc4, 0xc4, 0xc5, 0xc5, + 0xc5, 0xc5, 0xc5, 0xc6, 0xc6, 0xc6, 0xc6, 0xc7, + 0xc7, 0xc7, 0xc7, 0xc7, 0xc8, 0xc8, 0xc8, 0xc8, + 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xca, 0xca, 0xca, + 0xca, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcc, 0xcc, + 0xcc, 0xcc, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xce, + 0xce, 0xce, 0xce, 0xce, 0xcf, 0xcf, 0xcf, 0xcf, + 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd1, 0xd1, 0xd1, + 0xd1, 0xd1, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd3, + 0xd3, 0xd3, 0xd3, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, + 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd6, 0xd6, 0xd6, + 0xd6, 0xd6, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd8, + 0xd8, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, 0xd9, + 0xd9, 0xda, 0xda, 0xda, 0xda, 0xda, 0xdb, 0xdb, + 0xdb, 0xdb, 0xdb, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xde, 0xde, 0xde, + 0xde, 0xde, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xe0, + 0xe0, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe1, 0xe1, + 0xe1, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe3, 0xe3, + 0xe3, 0xe3, 0xe3, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, + 0xe4, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe6, 0xe6, + 0xe6, 0xe6, 0xe6, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, + 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe9, 0xe9, 0xe9, + 0xe9, 0xe9, 0xe9, 0xea, 0xea, 0xea, 0xea, 0xea, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, + 0xec, 0xec, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, + 0xee, 0xee, 0xee, 0xee, 0xee, 0xef, 0xef, 0xef, + 0xef, 0xef, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf2, 0xf2, 0xf2, + 0xf2, 0xf2, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, + 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, + 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, + 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, + 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, + 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, + 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + }, + }; + + reg_w(gspca_dev, TP6800_R21_ENDP_1_CTL, 0x00); + if (sd->bridge == BRIDGE_TP6810) + reg_w(gspca_dev, 0x02, 0x28); +/* msleep(50); */ + gamma = sd->ctrls[GAMMA].val; + bulk_w(gspca_dev, 0x00, gamma_tb[gamma][0], 1024); + bulk_w(gspca_dev, 0x01, gamma_tb[gamma][1], 1024); + bulk_w(gspca_dev, 0x02, gamma_tb[gamma][2], 1024); + if (sd->bridge == BRIDGE_TP6810) { + int i; + + reg_w(gspca_dev, 0x02, 0x2b); + reg_w(gspca_dev, 0x02, 0x28); + for (i = 0; i < 6; i++) + reg_w(gspca_dev, TP6800_R55_GAMMA_R, + gamma_tb[gamma][0][i]); + reg_w(gspca_dev, 0x02, 0x2b); + reg_w(gspca_dev, 0x02, 0x28); + for (i = 0; i < 6; i++) + reg_w(gspca_dev, TP6800_R56_GAMMA_G, + gamma_tb[gamma][1][i]); + reg_w(gspca_dev, 0x02, 0x2b); + reg_w(gspca_dev, 0x02, 0x28); + for (i = 0; i < 6; i++) + reg_w(gspca_dev, TP6800_R57_GAMMA_B, + gamma_tb[gamma][2][i]); + reg_w(gspca_dev, 0x02, 0x28); + } + reg_w(gspca_dev, TP6800_R21_ENDP_1_CTL, 0x03); +/* msleep(50); */ +} + +static void setsharpness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 val; + + if (sd->bridge == BRIDGE_TP6800) { + val = sd->ctrls[SHARPNESS].val + | 0x08; /* grid compensation enable */ + if (gspca_dev->width == 640) + reg_w(gspca_dev, TP6800_R78_FORMAT, 0x00); /* vga */ + else + val |= 0x04; /* scaling down enable */ + reg_w(gspca_dev, TP6800_R5D_DEMOSAIC_CFG, val); + } else { + val = (sd->ctrls[SHARPNESS].val << 5) | 0x08; + reg_w(gspca_dev, 0x59, val); + } +} + +static void setautogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (gspca_dev->ctrl_dis & (1 << AUTOGAIN)) + return; + if (sd->ctrls[AUTOGAIN].val) { + sd->ag_cnt = AG_CNT_START; + gspca_dev->ctrl_inac |= (1 << EXPOSURE) | (1 << GAIN); + } else { + sd->ag_cnt = -1; + gspca_dev->ctrl_inac &= ~((1 << EXPOSURE) | (1 << GAIN)); + } +} + +/* set the resolution for sensor cx0342 */ +static void set_resolution(struct gspca_dev *gspca_dev) +{ + reg_w(gspca_dev, TP6800_R21_ENDP_1_CTL, 0x00); + if (gspca_dev->width == 320) { + reg_w(gspca_dev, TP6800_R3F_FRAME_RATE, 0x06); + msleep(100); + i2c_w(gspca_dev, CX0342_AUTO_ADC_CALIB, 0x01); + msleep(100); + reg_w(gspca_dev, TP6800_R21_ENDP_1_CTL, 0x03); + reg_w(gspca_dev, TP6800_R78_FORMAT, 0x01); /* qvga */ + reg_w(gspca_dev, TP6800_R5D_DEMOSAIC_CFG, 0x0d); + i2c_w(gspca_dev, CX0342_EXPO_LINE_L, 0x37); + i2c_w(gspca_dev, CX0342_EXPO_LINE_H, 0x01); + } else { + reg_w(gspca_dev, TP6800_R3F_FRAME_RATE, 0x05); + msleep(100); + i2c_w(gspca_dev, CX0342_AUTO_ADC_CALIB, 0x01); + msleep(100); + reg_w(gspca_dev, TP6800_R21_ENDP_1_CTL, 0x03); + reg_w(gspca_dev, TP6800_R78_FORMAT, 0x00); /* vga */ + reg_w(gspca_dev, TP6800_R5D_DEMOSAIC_CFG, 0x09); + i2c_w(gspca_dev, CX0342_EXPO_LINE_L, 0xcf); + i2c_w(gspca_dev, CX0342_EXPO_LINE_H, 0x00); + } + i2c_w(gspca_dev, CX0342_SYS_CTRL_0, 0x01); + bulk_w(gspca_dev, 0x03, color_gain[SENSOR_CX0342], + ARRAY_SIZE(color_gain[0])); + setgamma(gspca_dev); + setquality(gspca_dev); +} + +/* convert the frame rate to a tp68x0 value */ +static int get_fr_idx(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + + if (sd->bridge == BRIDGE_TP6800) { + for (i = 0; i < ARRAY_SIZE(rates) - 1; i++) { + if (sd->framerate >= rates[i]) + break; + } + i = 6 - i; /* 1 = 5fps .. 6 = 30fps */ + + /* 640x480 * 30 fps does not work */ + if (i == 6 /* if 30 fps */ + && gspca_dev->width == 640) + i = 0x86; /* 15 fps */ + } else { + for (i = 0; i < ARRAY_SIZE(rates_6810) - 1; i++) { + if (sd->framerate >= rates_6810[i]) + break; + } + i = 7 - i; /* 3 = 5fps .. 7 = 30fps */ + + /* 640x480 * 30 fps does not work */ + if (i == 7 /* if 30 fps */ + && gspca_dev->width == 640) + i = 6; /* 15 fps */ + i |= 0x80; /* clock * 1 */ + } + return i; +} + +static void setframerate(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 fr_idx; + + fr_idx = get_fr_idx(gspca_dev); + + if (sd->bridge == BRIDGE_TP6810) { + reg_r(gspca_dev, 0x7b); + reg_w(gspca_dev, 0x7b, + sd->sensor == SENSOR_CX0342 ? 0x10 : 0x90); + if (sd->ctrls[EXPOSURE].val >= 128) + fr_idx = 0xf0; /* lower frame rate */ + } + + reg_w(gspca_dev, TP6800_R3F_FRAME_RATE, fr_idx); + + if (sd->sensor == SENSOR_CX0342) + i2c_w(gspca_dev, CX0342_AUTO_ADC_CALIB, 0x01); +} + +static void setrgain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int rgain; + + rgain = sd->ctrls[RGAIN].val; + i2c_w(gspca_dev, CX0342_RAW_RGAIN_H, rgain >> 8); + i2c_w(gspca_dev, CX0342_RAW_RGAIN_L, rgain); + i2c_w(gspca_dev, CX0342_SYS_CTRL_0, 0x80); +} + +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->sensor == SENSOR_CX0342) { + sd->ctrls[BGAIN].val = sd->ctrls[BGAIN].val + * val / sd->ctrls[GAIN].val; + if (sd->ctrls[BGAIN].val > 4095) + sd->ctrls[BGAIN].val = 4095; + sd->ctrls[RGAIN].val = sd->ctrls[RGAIN].val + * val / sd->ctrls[GAIN].val; + if (sd->ctrls[RGAIN].val > 4095) + sd->ctrls[RGAIN].val = 4095; + } + sd->ctrls[GAIN].val = val; + if (gspca_dev->streaming) + setexposure(gspca_dev); + return gspca_dev->usb_err; +} + +static void setbgain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int bgain; + + bgain = sd->ctrls[BGAIN].val; + i2c_w(gspca_dev, CX0342_RAW_BGAIN_H, bgain >> 8); + i2c_w(gspca_dev, CX0342_RAW_BGAIN_L, bgain); + i2c_w(gspca_dev, CX0342_SYS_CTRL_0, 0x80); +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->bridge = id->driver_info; + + gspca_dev->cam.cam_mode = vga_mode; + gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode); + gspca_dev->cam.mode_framerates = sd->bridge == BRIDGE_TP6800 ? + framerates : framerates_6810; + + sd->framerate = 30; /* default: 30 fps */ + gspca_dev->cam.ctrls = sd->ctrls; + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + static const struct cmd tp6800_preinit[] = { + {TP6800_R10_SIF_TYPE, 0x01}, /* sif */ + {TP6800_R11_SIF_CONTROL, 0x01}, + {TP6800_R15_GPIO_PU, 0x9f}, + {TP6800_R16_GPIO_PD, 0x9f}, + {TP6800_R17_GPIO_IO, 0x80}, + {TP6800_R18_GPIO_DATA, 0x40}, /* LED off */ + }; + static const struct cmd tp6810_preinit[] = { + {TP6800_R2F_TIMING_CFG, 0x2f}, + {TP6800_R15_GPIO_PU, 0x6f}, + {TP6800_R16_GPIO_PD, 0x40}, + {TP6800_R17_GPIO_IO, 0x9f}, + {TP6800_R18_GPIO_DATA, 0xc1}, /* LED off */ + }; + + if (sd->bridge == BRIDGE_TP6800) + reg_w_buf(gspca_dev, tp6800_preinit, + ARRAY_SIZE(tp6800_preinit)); + else + reg_w_buf(gspca_dev, tp6810_preinit, + ARRAY_SIZE(tp6810_preinit)); + msleep(15); + reg_r(gspca_dev, TP6800_R18_GPIO_DATA); + PDEBUG(D_PROBE, "gpio: %02x", gspca_dev->usb_buf[0]); +/* values: + * 0x80: snapshot button + * 0x40: LED + * 0x20: (bridge / sensor) reset for tp6810 ? + * 0x07: sensor type ? + */ + + /* guess the sensor type */ + if (force_sensor >= 0) { + sd->sensor = force_sensor; + } else { + if (sd->bridge == BRIDGE_TP6800) { +/*fixme: not sure this is working*/ + switch (gspca_dev->usb_buf[0] & 0x07) { + case 0: + sd->sensor = SENSOR_SOI763A; + break; + case 1: + sd->sensor = SENSOR_CX0342; + break; + } + } else { + int sensor; + + sensor = probe_6810(gspca_dev); + if (sensor < 0) { + pr_warn("Unknown sensor %d - forced to soi763a\n", + -sensor); + sensor = SENSOR_SOI763A; + } + sd->sensor = sensor; + } + } + if (sd->sensor == SENSOR_SOI763A) { + pr_info("Sensor soi763a\n"); + sd->ctrls[GAMMA].def = sd->bridge == BRIDGE_TP6800 ? 0 : 1; + sd->ctrls[GAIN].max = 15; + sd->ctrls[GAIN].def = 3; + gspca_dev->ctrl_dis = (1 << RGAIN) | (1 << BGAIN); + if (sd->bridge == BRIDGE_TP6810) { + soi763a_6810_init(gspca_dev); +#if AUTOGAIN_DEF + gspca_dev->ctrl_inac |= (1 << EXPOSURE) | (1 << GAIN); +#endif + } else { + gspca_dev->ctrl_dis |= (1 << AUTOGAIN); + } + } else { + pr_info("Sensor cx0342\n"); + if (sd->bridge == BRIDGE_TP6810) { + cx0342_6810_init(gspca_dev); +#if AUTOGAIN_DEF + gspca_dev->ctrl_inac |= (1 << EXPOSURE) | (1 << GAIN); +#endif + } else { + gspca_dev->ctrl_dis |= (1 << AUTOGAIN); + } + } + + if (sd->bridge == BRIDGE_TP6810) + sd->ctrls[QUALITY].def = 0; /* auto quality */ + set_dqt(gspca_dev, 0); + return 0; +} + +/* This function is called before choosing the alt setting */ +static int sd_isoc_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + static const struct cmd cx_sensor_init[] = { + {CX0342_AUTO_ADC_CALIB, 0x81}, + {CX0342_EXPO_LINE_L, 0x37}, + {CX0342_EXPO_LINE_H, 0x01}, + {CX0342_RAW_GRGAIN_L, 0x00}, + {CX0342_RAW_GBGAIN_L, 0x00}, + {CX0342_RAW_RGAIN_L, 0x00}, + {CX0342_RAW_BGAIN_L, 0x00}, + {CX0342_SYS_CTRL_0, 0x81}, + }; + static const struct cmd cx_bridge_init[] = { + {0x4d, 0x00}, + {0x4c, 0xff}, + {0x4e, 0xff}, + {0x4f, 0x00}, + }; + static const struct cmd ov_sensor_init[] = { + {0x10, 0x75}, /* exposure */ + {0x76, 0x03}, + {0x00, 0x00}, /* gain */ + }; + static const struct cmd ov_bridge_init[] = { + {0x7b, 0x90}, + {TP6800_R3F_FRAME_RATE, 0x87}, + }; + + if (sd->bridge == BRIDGE_TP6800) + return 0; + if (sd->sensor == SENSOR_CX0342) { + reg_w(gspca_dev, TP6800_R12_SIF_ADDR_S, 0x20); + reg_w(gspca_dev, TP6800_R3F_FRAME_RATE, 0x87); + i2c_w_buf(gspca_dev, cx_sensor_init, + ARRAY_SIZE(cx_sensor_init)); + reg_w_buf(gspca_dev, cx_bridge_init, + ARRAY_SIZE(cx_bridge_init)); + bulk_w(gspca_dev, 0x03, color_null, sizeof color_null); + reg_w(gspca_dev, 0x59, 0x40); + } else { + reg_w(gspca_dev, TP6800_R12_SIF_ADDR_S, 0x21); + i2c_w_buf(gspca_dev, ov_sensor_init, + ARRAY_SIZE(ov_sensor_init)); + reg_r(gspca_dev, 0x7b); + reg_w_buf(gspca_dev, ov_bridge_init, + ARRAY_SIZE(ov_bridge_init)); + } + reg_w(gspca_dev, TP6800_R78_FORMAT, + gspca_dev->curr_mode ? 0x00 : 0x01); + return gspca_dev->usb_err; +} + +static void set_led(struct gspca_dev *gspca_dev, int on) +{ + u8 data; + + reg_r(gspca_dev, TP6800_R18_GPIO_DATA); + data = gspca_dev->usb_buf[0]; + if (on) + data &= ~0x40; + else + data |= 0x40; + reg_w(gspca_dev, TP6800_R18_GPIO_DATA, data); +} + +static void cx0342_6800_start(struct gspca_dev *gspca_dev) +{ + static const struct cmd reg_init[] = { +/*fixme: is this usefull?*/ + {TP6800_R17_GPIO_IO, 0x9f}, + {TP6800_R16_GPIO_PD, 0x40}, + {TP6800_R10_SIF_TYPE, 0x00}, /* i2c 8 bits */ + {TP6800_R50, 0x00}, + {TP6800_R51, 0x00}, + {TP6800_R52, 0xff}, + {TP6800_R53, 0x03}, + {TP6800_R54_DARK_CFG, 0x07}, + {TP6800_R5C_EDGE_THRLD, 0x40}, + {TP6800_R7A_BLK_THRLD, 0x40}, + {TP6800_R2F_TIMING_CFG, 0x17}, + {TP6800_R30_SENSOR_CFG, 0x18}, /* G1B..RG0 */ + {TP6800_R37_FRONT_DARK_ST, 0x00}, + {TP6800_R38_FRONT_DARK_END, 0x00}, + {TP6800_R39_REAR_DARK_ST_L, 0x00}, + {TP6800_R3A_REAR_DARK_ST_H, 0x00}, + {TP6800_R3B_REAR_DARK_END_L, 0x00}, + {TP6800_R3C_REAR_DARK_END_H, 0x00}, + {TP6800_R3D_HORIZ_DARK_LINE_L, 0x00}, + {TP6800_R3E_HORIZ_DARK_LINE_H, 0x00}, + {TP6800_R21_ENDP_1_CTL, 0x03}, + + {TP6800_R31_PIXEL_START, 0x0b}, + {TP6800_R32_PIXEL_END_L, 0x8a}, + {TP6800_R33_PIXEL_END_H, 0x02}, + {TP6800_R34_LINE_START, 0x0e}, + {TP6800_R35_LINE_END_L, 0xf4}, + {TP6800_R36_LINE_END_H, 0x01}, + {TP6800_R78_FORMAT, 0x00}, + {TP6800_R12_SIF_ADDR_S, 0x20}, /* cx0342 i2c addr */ + }; + static const struct cmd sensor_init[] = { + {CX0342_OUTPUT_CTRL, 0x07}, + {CX0342_BYPASS_MODE, 0x58}, + {CX0342_GPXLTHD_L, 0x16}, + {CX0342_RBPXLTHD_L, 0x16}, + {CX0342_PLANETHD_L, 0xc0}, + {CX0342_PLANETHD_H, 0x03}, + {CX0342_RB_GAP_L, 0xff}, + {CX0342_RB_GAP_H, 0x07}, + {CX0342_G_GAP_L, 0xff}, + {CX0342_G_GAP_H, 0x07}, + {CX0342_RST_OVERFLOW_L, 0x5c}, + {CX0342_RST_OVERFLOW_H, 0x01}, + {CX0342_DATA_OVERFLOW_L, 0xfc}, + {CX0342_DATA_OVERFLOW_H, 0x03}, + {CX0342_DATA_UNDERFLOW_L, 0x00}, + {CX0342_DATA_UNDERFLOW_H, 0x00}, + {CX0342_SYS_CTRL_0, 0x40}, + {CX0342_GLOBAL_GAIN, 0x01}, + {CX0342_CLOCK_GEN, 0x00}, + {CX0342_SYS_CTRL_0, 0x02}, + {CX0342_IDLE_CTRL, 0x05}, + {CX0342_ADCGN, 0x00}, + {CX0342_ADC_CTL, 0x00}, + {CX0342_LVRST_BLBIAS, 0x01}, + {CX0342_VTHSEL, 0x0b}, + {CX0342_RAMP_RIV, 0x0b}, + {CX0342_LDOSEL, 0x07}, + {CX0342_SPV_VALUE_L, 0x40}, + {CX0342_SPV_VALUE_H, 0x02}, + }; + + reg_w_buf(gspca_dev, reg_init, ARRAY_SIZE(reg_init)); + i2c_w_buf(gspca_dev, sensor_init, ARRAY_SIZE(sensor_init)); + i2c_w_buf(gspca_dev, cx0342_timing_seq, ARRAY_SIZE(cx0342_timing_seq)); + reg_w(gspca_dev, TP6800_R5C_EDGE_THRLD, 0x10); + reg_w(gspca_dev, TP6800_R54_DARK_CFG, 0x00); + i2c_w(gspca_dev, CX0342_EXPO_LINE_H, 0x00); + i2c_w(gspca_dev, CX0342_SYS_CTRL_0, 0x01); + setexposure(gspca_dev); + set_led(gspca_dev, 1); + set_resolution(gspca_dev); +} + +static void cx0342_6810_start(struct gspca_dev *gspca_dev) +{ + static const struct cmd sensor_init_2[] = { + {CX0342_EXPO_LINE_L, 0x6f}, + {CX0342_EXPO_LINE_H, 0x02}, + {CX0342_RAW_GRGAIN_L, 0x00}, + {CX0342_RAW_GBGAIN_L, 0x00}, + {CX0342_RAW_RGAIN_L, 0x00}, + {CX0342_RAW_BGAIN_L, 0x00}, + {CX0342_SYS_CTRL_0, 0x81}, + }; + static const struct cmd bridge_init_2[] = { + {0x4d, 0x00}, + {0x4c, 0xff}, + {0x4e, 0xff}, + {0x4f, 0x00}, + {TP6800_R7A_BLK_THRLD, 0x00}, + {TP6800_R79_QUALITY, 0x04}, + {TP6800_R79_QUALITY, 0x01}, + }; + static const struct cmd bridge_init_3[] = { + {TP6800_R31_PIXEL_START, 0x08}, + {TP6800_R32_PIXEL_END_L, 0x87}, + {TP6800_R33_PIXEL_END_H, 0x02}, + {TP6800_R34_LINE_START, 0x0e}, + {TP6800_R35_LINE_END_L, 0xf4}, + {TP6800_R36_LINE_END_H, 0x01}, + }; + static const struct cmd sensor_init_3[] = { + {CX0342_AUTO_ADC_CALIB, 0x81}, + {CX0342_EXPO_LINE_L, 0x6f}, + {CX0342_EXPO_LINE_H, 0x02}, + {CX0342_RAW_GRGAIN_L, 0x00}, + {CX0342_RAW_GBGAIN_L, 0x00}, + {CX0342_RAW_RGAIN_L, 0x00}, + {CX0342_RAW_BGAIN_L, 0x00}, + {CX0342_SYS_CTRL_0, 0x81}, + }; + static const struct cmd bridge_init_5[] = { + {0x4d, 0x00}, + {0x4c, 0xff}, + {0x4e, 0xff}, + {0x4f, 0x00}, + }; + static const struct cmd sensor_init_4[] = { + {CX0342_EXPO_LINE_L, 0xd3}, + {CX0342_EXPO_LINE_H, 0x01}, +/*fixme: gains, but 00..80 only*/ + {CX0342_RAW_GRGAIN_L, 0x40}, + {CX0342_RAW_GBGAIN_L, 0x40}, + {CX0342_RAW_RGAIN_L, 0x40}, + {CX0342_RAW_BGAIN_L, 0x40}, + {CX0342_SYS_CTRL_0, 0x81}, + }; + static const struct cmd sensor_init_5[] = { + {CX0342_IDLE_CTRL, 0x05}, + {CX0342_ADCGN, 0x00}, + {CX0342_ADC_CTL, 0x00}, + {CX0342_LVRST_BLBIAS, 0x01}, + {CX0342_VTHSEL, 0x0b}, + {CX0342_RAMP_RIV, 0x0b}, + {CX0342_LDOSEL, 0x07}, + {CX0342_SPV_VALUE_L, 0x40}, + {CX0342_SPV_VALUE_H, 0x02}, + {CX0342_AUTO_ADC_CALIB, 0x81}, + }; + + reg_w(gspca_dev, 0x22, gspca_dev->alt); + i2c_w_buf(gspca_dev, sensor_init_2, ARRAY_SIZE(sensor_init_2)); + reg_w_buf(gspca_dev, bridge_init_2, ARRAY_SIZE(bridge_init_2)); + reg_w_buf(gspca_dev, tp6810_cx_init_common, + ARRAY_SIZE(tp6810_cx_init_common)); + reg_w_buf(gspca_dev, bridge_init_3, ARRAY_SIZE(bridge_init_3)); + if (gspca_dev->curr_mode) { + reg_w(gspca_dev, 0x4a, 0x7f); + reg_w(gspca_dev, 0x07, 0x05); + reg_w(gspca_dev, TP6800_R78_FORMAT, 0x00); /* vga */ + } else { + reg_w(gspca_dev, 0x4a, 0xff); + reg_w(gspca_dev, 0x07, 0x85); + reg_w(gspca_dev, TP6800_R78_FORMAT, 0x01); /* qvga */ + } + setgamma(gspca_dev); + reg_w_buf(gspca_dev, tp6810_bridge_start, + ARRAY_SIZE(tp6810_bridge_start)); + setsharpness(gspca_dev); + bulk_w(gspca_dev, 0x03, color_gain[SENSOR_CX0342], + ARRAY_SIZE(color_gain[0])); + reg_w(gspca_dev, TP6800_R3F_FRAME_RATE, 0x87); + i2c_w_buf(gspca_dev, sensor_init_3, ARRAY_SIZE(sensor_init_3)); + reg_w_buf(gspca_dev, bridge_init_5, ARRAY_SIZE(bridge_init_5)); + i2c_w_buf(gspca_dev, sensor_init_4, ARRAY_SIZE(sensor_init_4)); + reg_w_buf(gspca_dev, bridge_init_5, ARRAY_SIZE(bridge_init_5)); + i2c_w_buf(gspca_dev, sensor_init_5, ARRAY_SIZE(sensor_init_5)); + + set_led(gspca_dev, 1); +/* setquality(gspca_dev); */ +} + +static void soi763a_6800_start(struct gspca_dev *gspca_dev) +{ + static const struct cmd reg_init[] = { + {TP6800_R79_QUALITY, 0x04}, + {TP6800_R79_QUALITY, 0x01}, + {TP6800_R10_SIF_TYPE, 0x00}, /* i2c 8 bits */ + + {TP6800_R50, 0x00}, + {TP6800_R51, 0x00}, + {TP6800_R52, 0xff}, + {TP6800_R53, 0x03}, + {TP6800_R54_DARK_CFG, 0x07}, + {TP6800_R5C_EDGE_THRLD, 0x40}, + + {TP6800_R79_QUALITY, 0x03}, + {TP6800_R7A_BLK_THRLD, 0x40}, + + {TP6800_R2F_TIMING_CFG, 0x46}, + {TP6800_R30_SENSOR_CFG, 0x10}, /* BG1..G0R */ + {TP6800_R37_FRONT_DARK_ST, 0x00}, + {TP6800_R38_FRONT_DARK_END, 0x00}, + {TP6800_R39_REAR_DARK_ST_L, 0x00}, + {TP6800_R3A_REAR_DARK_ST_H, 0x00}, + {TP6800_R3B_REAR_DARK_END_L, 0x00}, + {TP6800_R3C_REAR_DARK_END_H, 0x00}, + {TP6800_R3D_HORIZ_DARK_LINE_L, 0x00}, + {TP6800_R3E_HORIZ_DARK_LINE_H, 0x00}, + {TP6800_R21_ENDP_1_CTL, 0x03}, + + {TP6800_R3F_FRAME_RATE, 0x04}, /* 15 fps */ + {TP6800_R5D_DEMOSAIC_CFG, 0x0e}, /* scale down - medium edge */ + + {TP6800_R31_PIXEL_START, 0x1b}, + {TP6800_R32_PIXEL_END_L, 0x9a}, + {TP6800_R33_PIXEL_END_H, 0x02}, + {TP6800_R34_LINE_START, 0x0f}, + {TP6800_R35_LINE_END_L, 0xf4}, + {TP6800_R36_LINE_END_H, 0x01}, + {TP6800_R78_FORMAT, 0x01}, /* qvga */ + {TP6800_R12_SIF_ADDR_S, 0x21}, /* soi763a i2c addr */ + {TP6800_R1A_SIF_TX_DATA2, 0x00}, + }; + static const struct cmd sensor_init[] = { + {0x12, 0x48}, /* mirror - RGB */ + {0x13, 0xa0}, /* clock - no AGC nor AEC */ + {0x03, 0xa4}, /* saturation */ + {0x04, 0x30}, /* hue */ + {0x05, 0x88}, /* contrast */ + {0x06, 0x60}, /* brightness */ + {0x10, 0x41}, /* AEC */ + {0x11, 0x40}, /* clock rate */ + {0x13, 0xa0}, + {0x14, 0x00}, /* 640x480 */ + {0x15, 0x14}, + {0x1f, 0x41}, + {0x20, 0x80}, + {0x23, 0xee}, + {0x24, 0x50}, + {0x25, 0x7a}, + {0x26, 0x00}, + {0x27, 0xe2}, + {0x28, 0xb0}, + {0x2a, 0x00}, + {0x2b, 0x00}, + {0x2d, 0x81}, + {0x2f, 0x9d}, + {0x60, 0x80}, + {0x61, 0x00}, + {0x62, 0x88}, + {0x63, 0x11}, + {0x64, 0x89}, + {0x65, 0x00}, + {0x67, 0x94}, + {0x68, 0x7a}, + {0x69, 0x0f}, + {0x6c, 0x80}, + {0x6d, 0x80}, + {0x6e, 0x80}, + {0x6f, 0xff}, + {0x71, 0x20}, + {0x74, 0x20}, + {0x75, 0x86}, + {0x77, 0xb5}, + {0x17, 0x18}, /* H href start */ + {0x18, 0xbf}, /* H href end */ + {0x19, 0x03}, /* V start */ + {0x1a, 0xf8}, /* V end */ + {0x01, 0x80}, /* blue gain */ + {0x02, 0x80}, /* red gain */ + }; + + reg_w_buf(gspca_dev, reg_init, ARRAY_SIZE(reg_init)); + + i2c_w(gspca_dev, 0x12, 0x80); /* sensor reset */ + msleep(10); + + i2c_w_buf(gspca_dev, sensor_init, ARRAY_SIZE(sensor_init)); + + reg_w(gspca_dev, TP6800_R5C_EDGE_THRLD, 0x10); + reg_w(gspca_dev, TP6800_R54_DARK_CFG, 0x00); + + setsharpness(gspca_dev); + + bulk_w(gspca_dev, 0x03, color_gain[SENSOR_SOI763A], + ARRAY_SIZE(color_gain[0])); + + set_led(gspca_dev, 1); + setexposure(gspca_dev); + setquality(gspca_dev); + setgamma(gspca_dev); +} + +static void soi763a_6810_start(struct gspca_dev *gspca_dev) +{ + static const struct cmd bridge_init_2[] = { + {TP6800_R7A_BLK_THRLD, 0x00}, + {TP6800_R79_QUALITY, 0x04}, + {TP6800_R79_QUALITY, 0x01}, + }; + static const struct cmd bridge_init_3[] = { + {TP6800_R31_PIXEL_START, 0x20}, + {TP6800_R32_PIXEL_END_L, 0x9f}, + {TP6800_R33_PIXEL_END_H, 0x02}, + {TP6800_R34_LINE_START, 0x13}, + {TP6800_R35_LINE_END_L, 0xf8}, + {TP6800_R36_LINE_END_H, 0x01}, + }; + static const struct cmd bridge_init_6[] = { + {0x08, 0xff}, + {0x09, 0xff}, + {0x0a, 0x5f}, + {0x0b, 0x80}, + }; + + reg_w(gspca_dev, 0x22, gspca_dev->alt); + bulk_w(gspca_dev, 0x03, color_null, sizeof color_null); + reg_w(gspca_dev, 0x59, 0x40); + setexposure(gspca_dev); + reg_w_buf(gspca_dev, bridge_init_2, ARRAY_SIZE(bridge_init_2)); + reg_w_buf(gspca_dev, tp6810_ov_init_common, + ARRAY_SIZE(tp6810_ov_init_common)); + reg_w_buf(gspca_dev, bridge_init_3, ARRAY_SIZE(bridge_init_3)); + if (gspca_dev->curr_mode) { + reg_w(gspca_dev, 0x4a, 0x7f); + reg_w(gspca_dev, 0x07, 0x05); + reg_w(gspca_dev, TP6800_R78_FORMAT, 0x00); /* vga */ + } else { + reg_w(gspca_dev, 0x4a, 0xff); + reg_w(gspca_dev, 0x07, 0x85); + reg_w(gspca_dev, TP6800_R78_FORMAT, 0x01); /* qvga */ + } + setgamma(gspca_dev); + reg_w_buf(gspca_dev, tp6810_bridge_start, + ARRAY_SIZE(tp6810_bridge_start)); + + if (gspca_dev->curr_mode) { + reg_w(gspca_dev, 0x4f, 0x00); + reg_w(gspca_dev, 0x4e, 0x7c); + } + + reg_w(gspca_dev, 0x00, 0x00); + + setsharpness(gspca_dev); + bulk_w(gspca_dev, 0x03, color_gain[SENSOR_SOI763A], + ARRAY_SIZE(color_gain[0])); + set_led(gspca_dev, 1); + reg_w(gspca_dev, TP6800_R3F_FRAME_RATE, 0xf0); + setexposure(gspca_dev); + reg_w_buf(gspca_dev, bridge_init_6, ARRAY_SIZE(bridge_init_6)); +} + +/* -- start the camera -- */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width); + set_dqt(gspca_dev, sd->quality); + if (sd->bridge == BRIDGE_TP6800) { + if (sd->sensor == SENSOR_CX0342) + cx0342_6800_start(gspca_dev); + else + soi763a_6800_start(gspca_dev); + } else { + if (sd->sensor == SENSOR_CX0342) + cx0342_6810_start(gspca_dev); + else + soi763a_6810_start(gspca_dev); + reg_w_buf(gspca_dev, tp6810_late_start, + ARRAY_SIZE(tp6810_late_start)); + reg_w(gspca_dev, 0x80, 0x03); + reg_w(gspca_dev, 0x82, gspca_dev->curr_mode ? 0x0a : 0x0e); + + setexposure(gspca_dev); + setquality(gspca_dev); + setautogain(gspca_dev); + } + + setframerate(gspca_dev); + + return gspca_dev->usb_err; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->bridge == BRIDGE_TP6800) + reg_w(gspca_dev, TP6800_R2F_TIMING_CFG, 0x03); + set_led(gspca_dev, 0); + reg_w(gspca_dev, TP6800_R21_ENDP_1_CTL, 0x00); +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, + int len) +{ + struct sd *sd = (struct sd *) gspca_dev; + + /* the start of frame contains: + * ff d8 + * ff fe + * width / 16 + * height / 8 + * quality + */ + if (sd->bridge == BRIDGE_TP6810) { + if (*data != 0x5a) { +/*fixme: don't discard the whole frame..*/ + if (*data == 0xaa || *data == 0x00) + return; + if (*data > 0xc0) { + PDEBUG(D_FRAM, "bad frame"); + gspca_dev->last_packet_type = DISCARD_PACKET; + return; + } + } + data++; + len--; + if (*data == 0xff && data[1] == 0xd8) { +/*fixme: there may be information in the 4 high bits*/ + if ((data[6] & 0x0f) != sd->quality) + set_dqt(gspca_dev, data[6] & 0x0f); + gspca_frame_add(gspca_dev, FIRST_PACKET, + sd->jpeg_hdr, JPEG_HDR_SZ); + gspca_frame_add(gspca_dev, INTER_PACKET, + data + 7, len - 7); + } else if (data[len - 2] == 0xff && data[len - 1] == 0xd9) { + gspca_frame_add(gspca_dev, LAST_PACKET, + data, len); + } else { + gspca_frame_add(gspca_dev, INTER_PACKET, + data, len); + } + return; + } + + switch (*data) { + case 0x55: + gspca_frame_add(gspca_dev, LAST_PACKET, data, 0); + + if (len < 8 + || data[1] != 0xff || data[2] != 0xd8 + || data[3] != 0xff || data[4] != 0xfe) { + + /* Have only seen this with corrupt frames */ + gspca_dev->last_packet_type = DISCARD_PACKET; + return; + } + if (data[7] != sd->quality) + set_dqt(gspca_dev, data[7]); + gspca_frame_add(gspca_dev, FIRST_PACKET, + sd->jpeg_hdr, JPEG_HDR_SZ); + gspca_frame_add(gspca_dev, INTER_PACKET, + data + 8, len - 8); + break; + case 0xaa: + gspca_dev->last_packet_type = DISCARD_PACKET; + break; + case 0xcc: + if (data[1] != 0xff || data[2] != 0xd8) + gspca_frame_add(gspca_dev, INTER_PACKET, + data + 1, len - 1); + else + gspca_dev->last_packet_type = DISCARD_PACKET; + break; + } +} + +/* -- do autogain -- */ +/* gain setting is done in setexposure() for tp6810 */ +static void setgain(struct gspca_dev *gspca_dev) {} +/* !! coarse_grained_expo_autogain is not used !! */ +#define exp_too_low_cnt bridge +#define exp_too_high_cnt sensor + +#include "autogain_functions.h" +static void sd_dq_callback(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int ret, alen; + int luma, expo; + + if (sd->ag_cnt < 0) + return; + if (--sd->ag_cnt > 5) + return; + switch (sd->ag_cnt) { +/* case 5: */ + default: + reg_w(gspca_dev, 0x7d, 0x00); + break; + case 4: + reg_w(gspca_dev, 0x27, 0xb0); + break; + case 3: + reg_w(gspca_dev, 0x0c, 0x01); + break; + case 2: + ret = usb_bulk_msg(gspca_dev->dev, + usb_rcvbulkpipe(gspca_dev->dev, 0x02), + gspca_dev->usb_buf, + 32, + &alen, + 500); + if (ret < 0) { + pr_err("bulk err %d\n", ret); + break; + } + /* values not used (unknown) */ + break; + case 1: + reg_w(gspca_dev, 0x27, 0xd0); + break; + case 0: + ret = usb_bulk_msg(gspca_dev->dev, + usb_rcvbulkpipe(gspca_dev->dev, 0x02), + gspca_dev->usb_buf, + 32, + &alen, + 500); + if (ret < 0) { + pr_err("bulk err %d\n", ret); + break; + } + luma = ((gspca_dev->usb_buf[8] << 8) + gspca_dev->usb_buf[7] + + (gspca_dev->usb_buf[11] << 8) + gspca_dev->usb_buf[10] + + (gspca_dev->usb_buf[14] << 8) + gspca_dev->usb_buf[13] + + (gspca_dev->usb_buf[17] << 8) + gspca_dev->usb_buf[16] + + (gspca_dev->usb_buf[20] << 8) + gspca_dev->usb_buf[19] + + (gspca_dev->usb_buf[23] << 8) + gspca_dev->usb_buf[22] + + (gspca_dev->usb_buf[26] << 8) + gspca_dev->usb_buf[25] + + (gspca_dev->usb_buf[29] << 8) + gspca_dev->usb_buf[28]) + / 8; + if (gspca_dev->width == 640) + luma /= 4; + reg_w(gspca_dev, 0x7d, 0x00); + + expo = sd->ctrls[EXPOSURE].val; + ret = auto_gain_n_exposure(gspca_dev, luma, + 60, /* desired luma */ + 6, /* dead zone */ + 2, /* gain knee */ + 70); /* expo knee */ + sd->ag_cnt = AG_CNT_START; + if (sd->bridge == BRIDGE_TP6810) { + if ((expo >= 128 && sd->ctrls[EXPOSURE].val < 128) + || (expo < 128 && sd->ctrls[EXPOSURE].val >= 128)) + setframerate(gspca_dev); + } + break; + } +} + +/* get stream parameters (framerate) */ +static void sd_get_streamparm(struct gspca_dev *gspca_dev, + struct v4l2_streamparm *parm) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct v4l2_captureparm *cp = &parm->parm.capture; + struct v4l2_fract *tpf = &cp->timeperframe; + int fr, i; + + cp->capability |= V4L2_CAP_TIMEPERFRAME; + tpf->numerator = 1; + i = get_fr_idx(gspca_dev); + if (i & 0x80) { + if (sd->bridge == BRIDGE_TP6800) + fr = rates[6 - (i & 0x07)]; + else + fr = rates_6810[7 - (i & 0x07)]; + } else { + fr = rates[6 - i]; + } + tpf->denominator = fr; +} + +/* set stream parameters (framerate) */ +static void sd_set_streamparm(struct gspca_dev *gspca_dev, + struct v4l2_streamparm *parm) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct v4l2_captureparm *cp = &parm->parm.capture; + struct v4l2_fract *tpf = &cp->timeperframe; + int fr, i; + + sd->framerate = tpf->denominator / tpf->numerator; + if (gspca_dev->streaming) + setframerate(gspca_dev); + + /* Return the actual framerate */ + i = get_fr_idx(gspca_dev); + if (i & 0x80) + fr = rates_6810[7 - (i & 0x07)]; + else + fr = rates[6 - i]; + tpf->numerator = 1; + tpf->denominator = fr; +} + +static int sd_set_jcomp(struct gspca_dev *gspca_dev, + struct v4l2_jpegcompression *jcomp) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->sensor == SENSOR_SOI763A) + jpeg_set_qual(sd->jpeg_hdr, jcomp->quality); +/* else + fixme: TODO +*/ + return gspca_dev->usb_err; +} + +static int sd_get_jcomp(struct gspca_dev *gspca_dev, + struct v4l2_jpegcompression *jcomp) +{ + struct sd *sd = (struct sd *) gspca_dev; + + memset(jcomp, 0, sizeof *jcomp); + jcomp->quality = jpeg_q[sd->quality]; + jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT + | V4L2_JPEG_MARKER_DQT; + return 0; +} + +static struct ctrl sd_ctrls[NCTRLS] = { +[EXPOSURE] = { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 0x01, + .maximum = 0xdc, + .step = 1, + .default_value = 0x4e, + }, + .set_control = setexposure + }, +[QUALITY] = { + { + .id = V4L2_CID_PRIVATE_BASE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Compression quality", + .minimum = 0, + .maximum = 15, + .step = 1, + .default_value = 13, + }, + .set_control = setquality + }, +[RGAIN] = { + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Red balance", + .minimum = 0, + .maximum = 4095, + .step = 1, + .default_value = 256, + }, + .set_control = setrgain + }, +[GAIN] = { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 4095, + .step = 1, + .default_value = 256, + }, + .set = sd_setgain + }, +[BGAIN] = { + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Blue balance", + .minimum = 0, + .maximum = 4095, + .step = 1, + .default_value = 256, + }, + .set_control = setbgain + }, +[SHARPNESS] = { + { + .id = V4L2_CID_SHARPNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Sharpness", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 2, + }, + .set_control = setsharpness + }, +[GAMMA] = { + { + .id = V4L2_CID_GAMMA, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gamma", + .minimum = 0, + .maximum = NGAMMA - 1, + .step = 1, + .default_value = 1, + }, + .set_control = setgamma + }, +[AUTOGAIN] = { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = AUTOGAIN_DEF + }, + .set_control = setautogain + }, +}; + +static const struct sd_desc sd_desc = { + .name = KBUILD_MODNAME, + .ctrls = sd_ctrls, + .nctrls = NCTRLS, + .config = sd_config, + .init = sd_init, + .isoc_init = sd_isoc_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, + .dq_callback = sd_dq_callback, + .get_streamparm = sd_get_streamparm, + .set_streamparm = sd_set_streamparm, + .get_jcomp = sd_get_jcomp, + .set_jcomp = sd_set_jcomp, +}; + +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x06a2, 0x0003), .driver_info = BRIDGE_TP6800}, + {USB_DEVICE(0x06a2, 0x6810), .driver_info = BRIDGE_TP6810}, + {} /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, device_table); + +static int sd_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + return gspca_dev_probe(interface, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = KBUILD_MODNAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, + .reset_resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); + +module_param(force_sensor, int, 0644); +MODULE_PARM_DESC(force_sensor, + "Force sensor. 0: cx0342, 1: soi763a"); -- cgit v0.10.2 From 9ba4a4ba3c170e618f75213fb03fe2deda754195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Fri, 23 Sep 2011 04:15:50 -0300 Subject: [media] gspca - spca1528: Increase the status waiting time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some webcams ask for a greater time to start. This patch increases the delay before timeout error on capture start. Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/spca1528.c b/drivers/media/video/gspca/spca1528.c index 4131be5..565c2f1 100644 --- a/drivers/media/video/gspca/spca1528.c +++ b/drivers/media/video/gspca/spca1528.c @@ -226,14 +226,16 @@ static void reg_wb(struct gspca_dev *gspca_dev, static void wait_status_0(struct gspca_dev *gspca_dev) { - int i; + int i, w; - i = 20; + i = 16; + w = 0; do { reg_r(gspca_dev, 0x21, 0x0000, 1); if (gspca_dev->usb_buf[0] == 0) return; - msleep(30); + w += 15; + msleep(w); } while (--i > 0); PDEBUG(D_ERR, "wait_status_0 timeout"); gspca_dev->usb_err = -ETIME; -- cgit v0.10.2 From 0dd826962716ff6984a14038d1604be816d759c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Fri, 23 Sep 2011 04:19:03 -0300 Subject: [media] gspca - spca1528: Add some comments and update copyright MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/spca1528.c b/drivers/media/video/gspca/spca1528.c index 565c2f1..f7c70a2 100644 --- a/drivers/media/video/gspca/spca1528.c +++ b/drivers/media/video/gspca/spca1528.c @@ -1,7 +1,7 @@ /* * spca1528 subdriver * - * Copyright (C) 2010 Jean-Francois Moine (http://moinejf.free.fr) + * Copyright (C) 2010-2011 Jean-Francois Moine (http://moinejf.free.fr) * * 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 @@ -351,7 +351,7 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev) mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; reg_wb(gspca_dev, 0x25, 0x0000, 0x0004, mode); reg_r(gspca_dev, 0x25, 0x0004, 1); - reg_wb(gspca_dev, 0x27, 0x0000, 0x0000, 0x06); + reg_wb(gspca_dev, 0x27, 0x0000, 0x0000, 0x06); /* 420 */ reg_r(gspca_dev, 0x27, 0x0000, 1); return gspca_dev->usb_err; } @@ -381,7 +381,7 @@ static int sd_start(struct gspca_dev *gspca_dev) /* start the capture */ wait_status_0(gspca_dev); - reg_w(gspca_dev, 0x31, 0x0000, 0x0004); + reg_w(gspca_dev, 0x31, 0x0000, 0x0004); /* start request */ wait_status_1(gspca_dev); wait_status_0(gspca_dev); msleep(200); @@ -394,7 +394,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev) { /* stop the capture */ wait_status_0(gspca_dev); - reg_w(gspca_dev, 0x31, 0x0000, 0x0000); + reg_w(gspca_dev, 0x31, 0x0000, 0x0000); /* stop request */ wait_status_1(gspca_dev); wait_status_0(gspca_dev); } -- cgit v0.10.2 From 3e12950d86d695bdaf762476446a60ed5073eedc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Fri, 23 Sep 2011 04:20:29 -0300 Subject: [media] gspca - spca1528: Change the JPEG quality of the images MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The JPEG quality was guessed as around 82%. Information in ms-win drivers says it should be 85%. Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/spca1528.c b/drivers/media/video/gspca/spca1528.c index f7c70a2..b7e8d40 100644 --- a/drivers/media/video/gspca/spca1528.c +++ b/drivers/media/video/gspca/spca1528.c @@ -365,8 +365,8 @@ static int sd_start(struct gspca_dev *gspca_dev) jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, 0x22); /* JPEG 411 */ - /* the JPEG quality seems to be 82% */ - jpeg_set_qual(sd->jpeg_hdr, 82); + /* the JPEG quality shall be 85% */ + jpeg_set_qual(sd->jpeg_hdr, 85); /* set the controls */ setbrightness(gspca_dev); -- cgit v0.10.2 From 6507b4232c2e136ccc338c3ed5c2f54b32b961b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Fri, 23 Sep 2011 04:23:52 -0300 Subject: [media] gspca - spca1528: Don't force the USB transfer alternate setting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As the choice of the alternate setting has been enhanced in the gspca main, forcing its number here is no more useful. Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/spca1528.c b/drivers/media/video/gspca/spca1528.c index b7e8d40..6956731 100644 --- a/drivers/media/video/gspca/spca1528.c +++ b/drivers/media/video/gspca/spca1528.c @@ -311,8 +311,6 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->color = COLOR_DEF; sd->sharpness = SHARPNESS_DEF; - gspca_dev->nbalt = 4; /* use alternate setting 3 */ - return 0; } @@ -353,6 +351,10 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev) reg_r(gspca_dev, 0x25, 0x0004, 1); reg_wb(gspca_dev, 0x27, 0x0000, 0x0000, 0x06); /* 420 */ reg_r(gspca_dev, 0x27, 0x0000, 1); + +/* not useful.. + gspca_dev->alt = 4; * use alternate setting 3 */ + return gspca_dev->usb_err; } -- cgit v0.10.2 From e1771299356ddabde6ff5c0e70a6b2af9f589e76 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 23 Sep 2011 04:47:58 -0300 Subject: [media] gspca - zc3xx: New webcam 03f0:1b07 HP Premium Starter Cam MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Wolfram Sang Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt index 58d0082..b15e29f 100644 --- a/Documentation/video4linux/gspca.txt +++ b/Documentation/video4linux/gspca.txt @@ -8,6 +8,7 @@ xxxx vend:prod ---- spca501 0000:0000 MystFromOri Unknown Camera spca508 0130:0130 Clone Digital Webcam 11043 +zc3xx 03f0:1b07 HP Premium Starter Cam m5602 0402:5602 ALi Video Camera Controller spca501 040a:0002 Kodak DVC-325 spca500 040a:0300 Kodak EZ200 diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c index 9d78fb8..30ea1e4 100644 --- a/drivers/media/video/gspca/zc3xx.c +++ b/drivers/media/video/gspca/zc3xx.c @@ -6972,6 +6972,7 @@ static const struct sd_desc sd_desc = { }; static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x03f0, 0x1b07)}, {USB_DEVICE(0x041e, 0x041e)}, {USB_DEVICE(0x041e, 0x4017)}, {USB_DEVICE(0x041e, 0x401c), .driver_info = SENSOR_PAS106}, -- cgit v0.10.2 From 114cfbdf49166d715d51d5c01c1fa4fcdba99e19 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Fri, 23 Sep 2011 05:05:37 -0300 Subject: [media] gspca - sn9c20x: Fix status LED device 0c45:62b3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tested with webcam "SilverCrest WC2130". Signed-off-by: Frank Schaefer Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c index 9b3a052..86e07a1 100644 --- a/drivers/media/video/gspca/sn9c20x.c +++ b/drivers/media/video/gspca/sn9c20x.c @@ -2515,7 +2515,7 @@ static const struct usb_device_id device_table[] = { {USB_DEVICE(0x0c45, 0x628f), SN9C20X(OV9650, 0x30, 0)}, {USB_DEVICE(0x0c45, 0x62a0), SN9C20X(OV7670, 0x21, 0)}, {USB_DEVICE(0x0c45, 0x62b0), SN9C20X(MT9VPRB, 0x00, 0)}, - {USB_DEVICE(0x0c45, 0x62b3), SN9C20X(OV9655, 0x30, 0)}, + {USB_DEVICE(0x0c45, 0x62b3), SN9C20X(OV9655, 0x30, LED_REVERSE)}, {USB_DEVICE(0x0c45, 0x62bb), SN9C20X(OV7660, 0x21, LED_REVERSE)}, {USB_DEVICE(0x0c45, 0x62bc), SN9C20X(HV7131R, 0x11, 0)}, {USB_DEVICE(0x045e, 0x00f4), SN9C20X(OV9650, 0x30, 0)}, -- cgit v0.10.2 From f22123faeda46cdd6a8586316a96543f90d9aba8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Fri, 23 Sep 2011 05:17:10 -0300 Subject: [media] gspca - main: Version change to 2.14.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index e41dfe2..137abe2 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -23,7 +23,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#define MODULE_NAME "gspca" +#define GSPCA_VERSION "2.14.0" #include #include @@ -52,12 +52,10 @@ #error "DEF_NURBS too big" #endif -#define DRIVER_VERSION_NUMBER "2.13.0" - MODULE_AUTHOR("Jean-François Moine "); MODULE_DESCRIPTION("GSPCA USB Camera Driver"); MODULE_LICENSE("GPL"); -MODULE_VERSION(DRIVER_VERSION_NUMBER); +MODULE_VERSION(GSPCA_VERSION); #ifdef GSPCA_DEBUG int gspca_debug = D_ERR | D_PROBE; @@ -2568,7 +2566,7 @@ EXPORT_SYMBOL(gspca_auto_gain_n_exposure); /* -- module insert / remove -- */ static int __init gspca_init(void) { - pr_info("v" DRIVER_VERSION_NUMBER " registered\n"); + pr_info("v" GSPCA_VERSION " registered\n"); return 0; } static void __exit gspca_exit(void) -- cgit v0.10.2 From ee7dd4e06e843ffb873418ee9bf449b18f1552f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Fri, 23 Sep 2011 05:25:28 -0300 Subject: [media] gspca - main: Display the subdriver name and version at probe time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 137abe2..881e04c 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -2281,7 +2281,8 @@ int gspca_dev_probe2(struct usb_interface *intf, struct usb_device *dev = interface_to_usbdev(intf); int ret; - PDEBUG(D_PROBE, "probing %04x:%04x", id->idVendor, id->idProduct); + pr_info("%s-" GSPCA_VERSION " probing %04x:%04x\n", + sd_desc->name, id->idVendor, id->idProduct); /* create the device */ if (dev_size < sizeof *gspca_dev) -- cgit v0.10.2 From 600836cc7b049f3eb47e9b39f379aa4b0926188a Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Fri, 23 Sep 2011 10:19:07 -0300 Subject: [media] media, rc: Use static inline functions to kill warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch converts some ifdef'd wrapper functions from macros to static inline functions to kill the following warnings issued by GCC: CC [M] drivers/media/rc/ir-raw.o drivers/media/rc/ir-raw.c: In function ‘init_decoders’: drivers/media/rc/ir-raw.c:353:2: warning: statement with no effect [-Wunused-value] drivers/media/rc/ir-raw.c:354:2: warning: statement with no effect [-Wunused-value] drivers/media/rc/ir-raw.c:355:2: warning: statement with no effect [-Wunused-value] drivers/media/rc/ir-raw.c:356:2: warning: statement with no effect [-Wunused-value] drivers/media/rc/ir-raw.c:357:2: warning: statement with no effect [-Wunused-value] drivers/media/rc/ir-raw.c:359:2: warning: statement with no effect [-Wunused-value] Cc: Mauro Carvalho Chehab Cc: "David Härdeman" Cc: Jarod Wilson Cc: Signed-off-by: Pekka Enberg Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index 04c2c72..c6ca870 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -162,49 +162,49 @@ void ir_raw_init(void); #ifdef CONFIG_IR_NEC_DECODER_MODULE #define load_nec_decode() request_module("ir-nec-decoder") #else -#define load_nec_decode() 0 +static inline void load_nec_decode(void) { } #endif /* from ir-rc5-decoder.c */ #ifdef CONFIG_IR_RC5_DECODER_MODULE #define load_rc5_decode() request_module("ir-rc5-decoder") #else -#define load_rc5_decode() 0 +static inline void load_rc5_decode(void) { } #endif /* from ir-rc6-decoder.c */ #ifdef CONFIG_IR_RC6_DECODER_MODULE #define load_rc6_decode() request_module("ir-rc6-decoder") #else -#define load_rc6_decode() 0 +static inline void load_rc6_decode(void) { } #endif /* from ir-jvc-decoder.c */ #ifdef CONFIG_IR_JVC_DECODER_MODULE #define load_jvc_decode() request_module("ir-jvc-decoder") #else -#define load_jvc_decode() 0 +static inline void load_jvc_decode(void) { } #endif /* from ir-sony-decoder.c */ #ifdef CONFIG_IR_SONY_DECODER_MODULE #define load_sony_decode() request_module("ir-sony-decoder") #else -#define load_sony_decode() 0 +static inline void load_sony_decode(void) { } #endif /* from ir-mce_kbd-decoder.c */ #ifdef CONFIG_IR_MCE_KBD_DECODER_MODULE #define load_mce_kbd_decode() request_module("ir-mce_kbd-decoder") #else -#define load_mce_kbd_decode() 0 +static inline void load_mce_kbd_decode(void) { } #endif /* from ir-lirc-codec.c */ #ifdef CONFIG_IR_LIRC_CODEC_MODULE #define load_lirc_codec() request_module("ir-lirc-codec") #else -#define load_lirc_codec() 0 +static inline void load_lirc_codec(void) { } #endif -- cgit v0.10.2 From 4e2c53fde651be6225d9f940c02b2eabc2f9591c Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Fri, 23 Sep 2011 18:33:50 -0300 Subject: [media] dvb: Add support for pctv452e Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 2c773827..5825716 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -258,6 +258,19 @@ config DVB_USB_AF9005_REMOTE Say Y here to support the default remote control decoding for the Afatech AF9005 based receiver. +config DVB_USB_PCTV452E + tristate "Pinnacle PCTV HDTV Pro USB device/TT Connect S2-3600" + depends on DVB_USB + select TTPCI_EEPROM + select DVB_LNBP22 if !DVB_FE_CUSTOMISE + select DVB_STB0899 if !DVB_FE_CUSTOMISE + select DVB_STB6100 if !DVB_FE_CUSTOMISE + help + Support for external USB adapter designed by Pinnacle, + shipped under the brand name 'PCTV HDTV Pro USB'. + Also supports TT Connect S2-3600/3650 cards. + Say Y if you own such a device and want to use it. + config DVB_USB_DW2102 tristate "DvbWorld & TeVii DVB-S/S2 USB2.0 support" depends on DVB_USB diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 06f75f6..7d0710b 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -64,6 +64,9 @@ obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o dvb-usb-anysee-objs = anysee.o obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o +dvb-usb-pctv452e-objs = pctv452e.o +obj-$(CONFIG_DVB_USB_PCTV452E) += dvb-usb-pctv452e.o + dvb-usb-dw2102-objs = dw2102.o obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o @@ -104,4 +107,5 @@ obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ # due to tuner-xc3028 ccflags-y += -Idrivers/media/common/tuners +EXTRA_CFLAGS += -Idrivers/media/dvb/ttpci diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 7433261..2ad33ba 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -241,6 +241,9 @@ #define USB_PID_PCTV_200E 0x020e #define USB_PID_PCTV_400E 0x020f #define USB_PID_PCTV_450E 0x0222 +#define USB_PID_PCTV_452E 0x021f +#define USB_PID_TECHNOTREND_CONNECT_S2_3600 0x3007 +#define USB_PID_TECHNOTREND_CONNECT_S2_3650_CI 0x300a #define USB_PID_NEBULA_DIGITV 0x0201 #define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820 #define USB_PID_DVICO_BLUEBIRD_LG064F_COLD 0xd500 diff --git a/drivers/media/dvb/dvb-usb/pctv452e.c b/drivers/media/dvb/dvb-usb/pctv452e.c new file mode 100644 index 0000000..9a5c811 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/pctv452e.c @@ -0,0 +1,1093 @@ +/* + * PCTV 452e DVB driver + * + * Copyright (c) 2006-2008 Dominik Kuhlen + * + * TT connect S2-3650-CI Common Interface support, MAC readout + * Copyright (C) 2008 Michael H. Schimek + * + * 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 of + * the License, or (at your option) any later version. + */ + +/* dvb usb framework */ +#define DVB_USB_LOG_PREFIX "pctv452e" +#include "dvb-usb.h" + +/* Demodulator */ +#include "stb0899_drv.h" +#include "stb0899_reg.h" +#include "stb0899_cfg.h" +/* Tuner */ +#include "stb6100.h" +#include "stb6100_cfg.h" +/* FE Power */ +#include "lnbp22.h" + +#include "dvb_ca_en50221.h" +#include "ttpci-eeprom.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define ISOC_INTERFACE_ALTERNATIVE 3 + +#define SYNC_BYTE_OUT 0xaa +#define SYNC_BYTE_IN 0x55 + +/* guessed: (copied from ttusb-budget) */ +#define PCTV_CMD_RESET 0x15 +/* command to poll IR receiver */ +#define PCTV_CMD_IR 0x1b +/* command to send I2C */ +#define PCTV_CMD_I2C 0x31 + +#define I2C_ADDR_STB0899 (0xd0 >> 1) +#define I2C_ADDR_STB6100 (0xc0 >> 1) +#define I2C_ADDR_LNBP22 (0x10 >> 1) +#define I2C_ADDR_24C16 (0xa0 >> 1) +#define I2C_ADDR_24C64 (0xa2 >> 1) + + +/* pctv452e sends us this amount of data for each issued usb-command */ +#define PCTV_ANSWER_LEN 64 +/* Wait up to 1000ms for device */ +#define PCTV_TIMEOUT 1000 + + +#define PCTV_LED_GPIO STB0899_GPIO01 +#define PCTV_LED_GREEN 0x82 +#define PCTV_LED_ORANGE 0x02 + +#define ci_dbg(format, arg...) \ +do { \ + if (0) \ + printk(KERN_DEBUG DVB_USB_LOG_PREFIX \ + ": " format "\n" , ## arg); \ +} while (0) + +enum { + TT3650_CMD_CI_TEST = 0x40, + TT3650_CMD_CI_RD_CTRL, + TT3650_CMD_CI_WR_CTRL, + TT3650_CMD_CI_RD_ATTR, + TT3650_CMD_CI_WR_ATTR, + TT3650_CMD_CI_RESET, + TT3650_CMD_CI_SET_VIDEO_PORT +}; + + +static struct stb0899_postproc pctv45e_postproc[] = { + { PCTV_LED_GPIO, STB0899_GPIOPULLUP }, + { 0, 0 } +}; + +/* + * stores all private variables for communication with the PCTV452e DVB-S2 + */ +struct pctv452e_state { + struct dvb_ca_en50221 ca; + struct mutex ca_mutex; + + u8 c; /* transaction counter, wraps around... */ + u8 initialized; /* set to 1 if 0x15 has been sent */ + u16 last_rc_key; +}; + +static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data, + unsigned int write_len, unsigned int read_len) +{ + struct pctv452e_state *state = (struct pctv452e_state *)d->priv; + u8 buf[64]; + u8 id; + unsigned int rlen; + int ret; + + BUG_ON(NULL == data && 0 != (write_len | read_len)); + BUG_ON(write_len > 64 - 4); + BUG_ON(read_len > 64 - 4); + + id = state->c++; + + buf[0] = SYNC_BYTE_OUT; + buf[1] = id; + buf[2] = cmd; + buf[3] = write_len; + + memcpy(buf + 4, data, write_len); + + rlen = (read_len > 0) ? 64 : 0; + ret = dvb_usb_generic_rw(d, buf, 4 + write_len, + buf, rlen, /* delay_ms */ 0); + if (0 != ret) + goto failed; + + ret = -EIO; + if (SYNC_BYTE_IN != buf[0] || id != buf[1]) + goto failed; + + memcpy(data, buf + 4, read_len); + + return 0; + +failed: + err("CI error %d; %02X %02X %02X -> %02X %02X %02X.", + ret, SYNC_BYTE_OUT, id, cmd, buf[0], buf[1], buf[2]); + + return ret; +} + +static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca, + u8 cmd, u8 *data, unsigned int write_len, + unsigned int read_len) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct pctv452e_state *state = (struct pctv452e_state *)d->priv; + int ret; + + mutex_lock(&state->ca_mutex); + ret = tt3650_ci_msg(d, cmd, data, write_len, read_len); + mutex_unlock(&state->ca_mutex); + + return ret; +} + +static int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, + int slot, int address) +{ + u8 buf[3]; + int ret; + + if (0 != slot) + return -EINVAL; + + buf[0] = (address >> 8) & 0x0F; + buf[1] = address; + + ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3); + + ci_dbg("%s %04x -> %d 0x%02x", + __func__, address, ret, buf[2]); + + if (ret < 0) + return ret; + + return buf[2]; +} + +static int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, + int slot, int address, u8 value) +{ + u8 buf[3]; + + ci_dbg("%s %d 0x%04x 0x%02x", + __func__, slot, address, value); + + if (0 != slot) + return -EINVAL; + + buf[0] = (address >> 8) & 0x0F; + buf[1] = address; + buf[2] = value; + + return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3); +} + +static int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca, + int slot, + u8 address) +{ + u8 buf[2]; + int ret; + + if (0 != slot) + return -EINVAL; + + buf[0] = address & 3; + + ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2); + + ci_dbg("%s 0x%02x -> %d 0x%02x", + __func__, address, ret, buf[1]); + + if (ret < 0) + return ret; + + return buf[1]; +} + +static int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca, + int slot, + u8 address, + u8 value) +{ + u8 buf[2]; + + ci_dbg("%s %d 0x%02x 0x%02x", + __func__, slot, address, value); + + if (0 != slot) + return -EINVAL; + + buf[0] = address; + buf[1] = value; + + return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2); +} + +static int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca, + int slot, + int enable) +{ + u8 buf[1]; + int ret; + + ci_dbg("%s %d %d", __func__, slot, enable); + + if (0 != slot) + return -EINVAL; + + enable = !!enable; + buf[0] = enable; + + ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1); + if (ret < 0) + return ret; + + if (enable != buf[0]) { + err("CI not %sabled.", enable ? "en" : "dis"); + return -EIO; + } + + return 0; +} + +static int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) +{ + return tt3650_ci_set_video_port(ca, slot, /* enable */ 0); +} + +static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) +{ + return tt3650_ci_set_video_port(ca, slot, /* enable */ 1); +} + +static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot) +{ + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; + struct pctv452e_state *state = (struct pctv452e_state *)d->priv; + u8 buf[1]; + int ret; + + ci_dbg("%s %d", __func__, slot); + + if (0 != slot) + return -EINVAL; + + buf[0] = 0; + + mutex_lock(&state->ca_mutex); + + ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1); + if (0 != ret) + goto failed; + + msleep(500); + + buf[0] = 1; + + ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1); + if (0 != ret) + goto failed; + + msleep(500); + + buf[0] = 0; /* FTA */ + + ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1); + + failed: + mutex_unlock(&state->ca_mutex); + + return ret; +} + +static int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca, + int slot, + int open) +{ + u8 buf[1]; + int ret; + + if (0 != slot) + return -EINVAL; + + ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1); + if (0 != ret) + return ret; + + if (1 == buf[0]) + return DVB_CA_EN50221_POLL_CAM_PRESENT | + DVB_CA_EN50221_POLL_CAM_READY; + + return 0; + +} + +static void tt3650_ci_uninit(struct dvb_usb_device *d) +{ + struct pctv452e_state *state; + + ci_dbg("%s", __func__); + + if (NULL == d) + return; + + state = (struct pctv452e_state *)d->priv; + if (NULL == state) + return; + + if (NULL == state->ca.data) + return; + + /* Error ignored. */ + tt3650_ci_set_video_port(&state->ca, /* slot */ 0, /* enable */ 0); + + dvb_ca_en50221_release(&state->ca); + + memset(&state->ca, 0, sizeof(state->ca)); +} + +static int tt3650_ci_init(struct dvb_usb_adapter *a) +{ + struct dvb_usb_device *d = a->dev; + struct pctv452e_state *state = (struct pctv452e_state *)d->priv; + int ret; + + ci_dbg("%s", __func__); + + mutex_init(&state->ca_mutex); + + state->ca.owner = THIS_MODULE; + state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem; + state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem; + state->ca.read_cam_control = tt3650_ci_read_cam_control; + state->ca.write_cam_control = tt3650_ci_write_cam_control; + state->ca.slot_reset = tt3650_ci_slot_reset; + state->ca.slot_shutdown = tt3650_ci_slot_shutdown; + state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable; + state->ca.poll_slot_status = tt3650_ci_poll_slot_status; + state->ca.data = d; + + ret = dvb_ca_en50221_init(&a->dvb_adap, + &state->ca, + /* flags */ 0, + /* n_slots */ 1); + if (0 != ret) { + err("Cannot initialize CI: Error %d.", ret); + memset(&state->ca, 0, sizeof(state->ca)); + return ret; + } + + info("CI initialized."); + + return 0; +} + +#define CMD_BUFFER_SIZE 0x28 +static int pctv452e_i2c_msg(struct dvb_usb_device *d, u8 addr, + const u8 *snd_buf, u8 snd_len, + u8 *rcv_buf, u8 rcv_len) +{ + struct pctv452e_state *state = (struct pctv452e_state *)d->priv; + u8 buf[64]; + u8 id; + int ret; + + id = state->c++; + + ret = -EINVAL; + if (snd_len > 64 - 7 || rcv_len > 64 - 7) + goto failed; + + buf[0] = SYNC_BYTE_OUT; + buf[1] = id; + buf[2] = PCTV_CMD_I2C; + buf[3] = snd_len + 3; + buf[4] = addr << 1; + buf[5] = snd_len; + buf[6] = rcv_len; + + memcpy(buf + 7, snd_buf, snd_len); + + ret = dvb_usb_generic_rw(d, buf, 7 + snd_len, + buf, /* rcv_len */ 64, + /* delay_ms */ 0); + if (ret < 0) + goto failed; + + /* TT USB protocol error. */ + ret = -EIO; + if (SYNC_BYTE_IN != buf[0] || id != buf[1]) + goto failed; + + /* I2C device didn't respond as expected. */ + ret = -EREMOTEIO; + if (buf[5] < snd_len || buf[6] < rcv_len) + goto failed; + + memcpy(rcv_buf, buf + 7, rcv_len); + + return rcv_len; + +failed: + err("I2C error %d; %02X %02X %02X %02X %02X -> " + "%02X %02X %02X %02X %02X.", + ret, SYNC_BYTE_OUT, id, addr << 1, snd_len, rcv_len, + buf[0], buf[1], buf[4], buf[5], buf[6]); + + return ret; +} + +static int pctv452e_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msg, + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adapter); + int i; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + u8 addr, snd_len, rcv_len, *snd_buf, *rcv_buf; + int ret; + + if (msg[i].flags & I2C_M_RD) { + addr = msg[i].addr; + snd_buf = NULL; + snd_len = 0; + rcv_buf = msg[i].buf; + rcv_len = msg[i].len; + } else { + addr = msg[i].addr; + snd_buf = msg[i].buf; + snd_len = msg[i].len; + rcv_buf = NULL; + rcv_len = 0; + } + + ret = pctv452e_i2c_msg(d, addr, snd_buf, snd_len, rcv_buf, + rcv_len); + if (ret < rcv_len) + break; + } + + mutex_unlock(&d->i2c_mutex); + return i; +} + +static u32 pctv452e_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static int pctv452e_power_ctrl(struct dvb_usb_device *d, int i) +{ + struct pctv452e_state *state = (struct pctv452e_state *)d->priv; + u8 b0[] = { 0xaa, 0, PCTV_CMD_RESET, 1, 0 }; + u8 rx[PCTV_ANSWER_LEN]; + int ret; + + info("%s: %d\n", __func__, i); + + if (!i) + return 0; + + if (state->initialized) + return 0; + + /* hmm where shoud this should go? */ + ret = usb_set_interface(d->udev, 0, ISOC_INTERFACE_ALTERNATIVE); + if (ret != 0) + info("%s: Warning set interface returned: %d\n", + __func__, ret); + + /* this is a one-time initialization, dont know where to put */ + b0[1] = state->c++; + /* reset board */ + ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0); + if (ret) + return ret; + + b0[1] = state->c++; + b0[4] = 1; + /* reset board (again?) */ + ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0); + if (ret) + return ret; + + state->initialized = 1; + + return 0; +} + +static int pctv452e_rc_query(struct dvb_usb_device *d) +{ + struct pctv452e_state *state = (struct pctv452e_state *)d->priv; + u8 b[CMD_BUFFER_SIZE]; + u8 rx[PCTV_ANSWER_LEN]; + int ret, i; + u8 id = state->c++; + + /* prepare command header */ + b[0] = SYNC_BYTE_OUT; + b[1] = id; + b[2] = PCTV_CMD_IR; + b[3] = 0; + + /* send ir request */ + ret = dvb_usb_generic_rw(d, b, 4, rx, PCTV_ANSWER_LEN, 0); + if (ret != 0) + return ret; + + if (debug > 3) { + info("%s: read: %2d: %02x %02x %02x: ", __func__, + ret, rx[0], rx[1], rx[2]); + for (i = 0; (i < rx[3]) && ((i+3) < PCTV_ANSWER_LEN); i++) + info(" %02x", rx[i+3]); + + info("\n"); + } + + if ((rx[3] == 9) && (rx[12] & 0x01)) { + /* got a "press" event */ + state->last_rc_key = (rx[7] << 8) | rx[6]; + if (debug > 2) + info("%s: cmd=0x%02x sys=0x%02x\n", + __func__, rx[6], rx[7]); + + rc_keydown(d->rc_dev, state->last_rc_key, 0); + } else if (state->last_rc_key) { + rc_keyup(d->rc_dev); + state->last_rc_key = 0; + } + + return 0; +} + +static int pctv452e_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) +{ + const u8 mem_addr[] = { 0x1f, 0xcc }; + u8 encoded_mac[20]; + int ret; + + ret = -EAGAIN; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + goto failed; + + ret = pctv452e_i2c_msg(d, I2C_ADDR_24C16, + mem_addr + 1, /* snd_len */ 1, + encoded_mac, /* rcv_len */ 20); + if (-EREMOTEIO == ret) + /* Caution! A 24C16 interprets 0xA2 0x1F 0xCC as a + byte write if /WC is low. */ + ret = pctv452e_i2c_msg(d, I2C_ADDR_24C64, + mem_addr, 2, + encoded_mac, 20); + + mutex_unlock(&d->i2c_mutex); + + if (20 != ret) + goto failed; + + ret = ttpci_eeprom_decode_mac(mac, encoded_mac); + if (0 != ret) + goto failed; + + return 0; + +failed: + memset(mac, 0, 6); + + return ret; +} + +static const struct stb0899_s1_reg pctv452e_init_dev[] = { + { STB0899_DISCNTRL1, 0x26 }, + { STB0899_DISCNTRL2, 0x80 }, + { STB0899_DISRX_ST0, 0x04 }, + { STB0899_DISRX_ST1, 0x20 }, + { STB0899_DISPARITY, 0x00 }, + { STB0899_DISFIFO, 0x00 }, + { STB0899_DISF22, 0x99 }, + { STB0899_DISF22RX, 0x85 }, /* 0xa8 */ + { STB0899_ACRPRESC, 0x11 }, + { STB0899_ACRDIV1, 0x0a }, + { STB0899_ACRDIV2, 0x05 }, + { STB0899_DACR1 , 0x00 }, + { STB0899_DACR2 , 0x00 }, + { STB0899_OUTCFG, 0x00 }, + { STB0899_MODECFG, 0x00 }, /* Inversion */ + { STB0899_IRQMSK_3, 0xf3 }, + { STB0899_IRQMSK_2, 0xfc }, + { STB0899_IRQMSK_1, 0xff }, + { STB0899_IRQMSK_0, 0xff }, + { STB0899_I2CCFG, 0x88 }, + { STB0899_I2CRPT, 0x58 }, + { STB0899_GPIO00CFG, 0x82 }, + { STB0899_GPIO01CFG, 0x82 }, /* LED: 0x02 green, 0x82 orange */ + { STB0899_GPIO02CFG, 0x82 }, + { STB0899_GPIO03CFG, 0x82 }, + { STB0899_GPIO04CFG, 0x82 }, + { STB0899_GPIO05CFG, 0x82 }, + { STB0899_GPIO06CFG, 0x82 }, + { STB0899_GPIO07CFG, 0x82 }, + { STB0899_GPIO08CFG, 0x82 }, + { STB0899_GPIO09CFG, 0x82 }, + { STB0899_GPIO10CFG, 0x82 }, + { STB0899_GPIO11CFG, 0x82 }, + { STB0899_GPIO12CFG, 0x82 }, + { STB0899_GPIO13CFG, 0x82 }, + { STB0899_GPIO14CFG, 0x82 }, + { STB0899_GPIO15CFG, 0x82 }, + { STB0899_GPIO16CFG, 0x82 }, + { STB0899_GPIO17CFG, 0x82 }, + { STB0899_GPIO18CFG, 0x82 }, + { STB0899_GPIO19CFG, 0x82 }, + { STB0899_GPIO20CFG, 0x82 }, + { STB0899_SDATCFG, 0xb8 }, + { STB0899_SCLTCFG, 0xba }, + { STB0899_AGCRFCFG, 0x1c }, /* 0x11 DVB-S; 0x1c DVB-S2 (1c, rjkm) */ + { STB0899_GPIO22, 0x82 }, + { STB0899_GPIO21, 0x91 }, + { STB0899_DIRCLKCFG, 0x82 }, + { STB0899_CLKOUT27CFG, 0x7e }, + { STB0899_STDBYCFG, 0x82 }, + { STB0899_CS0CFG, 0x82 }, + { STB0899_CS1CFG, 0x82 }, + { STB0899_DISEQCOCFG, 0x20 }, + { STB0899_NCOARSE, 0x15 }, /* 0x15 27Mhz, F/3 198MHz, F/6 108MHz */ + { STB0899_SYNTCTRL, 0x00 }, /* 0x00 CLKI, 0x02 XTALI */ + { STB0899_FILTCTRL, 0x00 }, + { STB0899_SYSCTRL, 0x00 }, + { STB0899_STOPCLK1, 0x20 }, /* orig: 0x00 budget-ci: 0x20 */ + { STB0899_STOPCLK2, 0x00 }, + { STB0899_INTBUFCTRL, 0x0a }, + { STB0899_AGC2I1, 0x00 }, + { STB0899_AGC2I2, 0x00 }, + { STB0899_AGCIQIN, 0x00 }, + { STB0899_TSTRES, 0x40 }, /* rjkm */ + { 0xffff, 0xff }, +}; + +static const struct stb0899_s1_reg pctv452e_init_s1_demod[] = { + { STB0899_DEMOD, 0x00 }, + { STB0899_RCOMPC, 0xc9 }, + { STB0899_AGC1CN, 0x01 }, + { STB0899_AGC1REF, 0x10 }, + { STB0899_RTC, 0x23 }, + { STB0899_TMGCFG, 0x4e }, + { STB0899_AGC2REF, 0x34 }, + { STB0899_TLSR, 0x84 }, + { STB0899_CFD, 0xf7 }, + { STB0899_ACLC, 0x87 }, + { STB0899_BCLC, 0x94 }, + { STB0899_EQON, 0x41 }, + { STB0899_LDT, 0xf1 }, + { STB0899_LDT2, 0xe3 }, + { STB0899_EQUALREF, 0xb4 }, + { STB0899_TMGRAMP, 0x10 }, + { STB0899_TMGTHD, 0x30 }, + { STB0899_IDCCOMP, 0xfd }, + { STB0899_QDCCOMP, 0xff }, + { STB0899_POWERI, 0x0c }, + { STB0899_POWERQ, 0x0f }, + { STB0899_RCOMP, 0x6c }, + { STB0899_AGCIQIN, 0x80 }, + { STB0899_AGC2I1, 0x06 }, + { STB0899_AGC2I2, 0x00 }, + { STB0899_TLIR, 0x30 }, + { STB0899_RTF, 0x7f }, + { STB0899_DSTATUS, 0x00 }, + { STB0899_LDI, 0xbc }, + { STB0899_CFRM, 0xea }, + { STB0899_CFRL, 0x31 }, + { STB0899_NIRM, 0x2b }, + { STB0899_NIRL, 0x80 }, + { STB0899_ISYMB, 0x1d }, + { STB0899_QSYMB, 0xa6 }, + { STB0899_SFRH, 0x2f }, + { STB0899_SFRM, 0x68 }, + { STB0899_SFRL, 0x40 }, + { STB0899_SFRUPH, 0x2f }, + { STB0899_SFRUPM, 0x68 }, + { STB0899_SFRUPL, 0x40 }, + { STB0899_EQUAI1, 0x02 }, + { STB0899_EQUAQ1, 0xff }, + { STB0899_EQUAI2, 0x04 }, + { STB0899_EQUAQ2, 0x05 }, + { STB0899_EQUAI3, 0x02 }, + { STB0899_EQUAQ3, 0xfd }, + { STB0899_EQUAI4, 0x03 }, + { STB0899_EQUAQ4, 0x07 }, + { STB0899_EQUAI5, 0x08 }, + { STB0899_EQUAQ5, 0xf5 }, + { STB0899_DSTATUS2, 0x00 }, + { STB0899_VSTATUS, 0x00 }, + { STB0899_VERROR, 0x86 }, + { STB0899_IQSWAP, 0x2a }, + { STB0899_ECNT1M, 0x00 }, + { STB0899_ECNT1L, 0x00 }, + { STB0899_ECNT2M, 0x00 }, + { STB0899_ECNT2L, 0x00 }, + { STB0899_ECNT3M, 0x0a }, + { STB0899_ECNT3L, 0xad }, + { STB0899_FECAUTO1, 0x06 }, + { STB0899_FECM, 0x01 }, + { STB0899_VTH12, 0xb0 }, + { STB0899_VTH23, 0x7a }, + { STB0899_VTH34, 0x58 }, + { STB0899_VTH56, 0x38 }, + { STB0899_VTH67, 0x34 }, + { STB0899_VTH78, 0x24 }, + { STB0899_PRVIT, 0xff }, + { STB0899_VITSYNC, 0x19 }, + { STB0899_RSULC, 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ + { STB0899_TSULC, 0x42 }, + { STB0899_RSLLC, 0x41 }, + { STB0899_TSLPL, 0x12 }, + { STB0899_TSCFGH, 0x0c }, + { STB0899_TSCFGM, 0x00 }, + { STB0899_TSCFGL, 0x00 }, + { STB0899_TSOUT, 0x69 }, /* 0x0d for CAM */ + { STB0899_RSSYNCDEL, 0x00 }, + { STB0899_TSINHDELH, 0x02 }, + { STB0899_TSINHDELM, 0x00 }, + { STB0899_TSINHDELL, 0x00 }, + { STB0899_TSLLSTKM, 0x1b }, + { STB0899_TSLLSTKL, 0xb3 }, + { STB0899_TSULSTKM, 0x00 }, + { STB0899_TSULSTKL, 0x00 }, + { STB0899_PCKLENUL, 0xbc }, + { STB0899_PCKLENLL, 0xcc }, + { STB0899_RSPCKLEN, 0xbd }, + { STB0899_TSSTATUS, 0x90 }, + { STB0899_ERRCTRL1, 0xb6 }, + { STB0899_ERRCTRL2, 0x95 }, + { STB0899_ERRCTRL3, 0x8d }, + { STB0899_DMONMSK1, 0x27 }, + { STB0899_DMONMSK0, 0x03 }, + { STB0899_DEMAPVIT, 0x5c }, + { STB0899_PLPARM, 0x19 }, + { STB0899_PDELCTRL, 0x48 }, + { STB0899_PDELCTRL2, 0x00 }, + { STB0899_BBHCTRL1, 0x00 }, + { STB0899_BBHCTRL2, 0x00 }, + { STB0899_HYSTTHRESH, 0x77 }, + { STB0899_MATCSTM, 0x00 }, + { STB0899_MATCSTL, 0x00 }, + { STB0899_UPLCSTM, 0x00 }, + { STB0899_UPLCSTL, 0x00 }, + { STB0899_DFLCSTM, 0x00 }, + { STB0899_DFLCSTL, 0x00 }, + { STB0899_SYNCCST, 0x00 }, + { STB0899_SYNCDCSTM, 0x00 }, + { STB0899_SYNCDCSTL, 0x00 }, + { STB0899_ISI_ENTRY, 0x00 }, + { STB0899_ISI_BIT_EN, 0x00 }, + { STB0899_MATSTRM, 0xf0 }, + { STB0899_MATSTRL, 0x02 }, + { STB0899_UPLSTRM, 0x45 }, + { STB0899_UPLSTRL, 0x60 }, + { STB0899_DFLSTRM, 0xe3 }, + { STB0899_DFLSTRL, 0x00 }, + { STB0899_SYNCSTR, 0x47 }, + { STB0899_SYNCDSTRM, 0x05 }, + { STB0899_SYNCDSTRL, 0x18 }, + { STB0899_CFGPDELSTATUS1, 0x19 }, + { STB0899_CFGPDELSTATUS2, 0x2b }, + { STB0899_BBFERRORM, 0x00 }, + { STB0899_BBFERRORL, 0x01 }, + { STB0899_UPKTERRORM, 0x00 }, + { STB0899_UPKTERRORL, 0x00 }, + { 0xffff, 0xff }, +}; + +static struct stb0899_config stb0899_config = { + .init_dev = pctv452e_init_dev, + .init_s2_demod = stb0899_s2_init_2, + .init_s1_demod = pctv452e_init_s1_demod, + .init_s2_fec = stb0899_s2_init_4, + .init_tst = stb0899_s1_init_5, + + .demod_address = I2C_ADDR_STB0899, /* I2C Address */ + .block_sync_mode = STB0899_SYNC_FORCED, /* ? */ + + .xtal_freq = 27000000, /* Assume Hz ? */ + .inversion = IQ_SWAP_ON, /* ? */ + + .lo_clk = 76500000, + .hi_clk = 99000000, + + .ts_output_mode = 0, /* Use parallel mode */ + .clock_polarity = 0, + .data_clk_parity = 0, + .fec_mode = 0, + + .esno_ave = STB0899_DVBS2_ESNO_AVE, + .esno_quant = STB0899_DVBS2_ESNO_QUANT, + .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, + .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, + .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, + .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, + .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, + .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, + .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, + + .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, + .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, + .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, + .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, + + .tuner_get_frequency = stb6100_get_frequency, + .tuner_set_frequency = stb6100_set_frequency, + .tuner_set_bandwidth = stb6100_set_bandwidth, + .tuner_get_bandwidth = stb6100_get_bandwidth, + .tuner_set_rfsiggain = NULL, + + /* helper for switching LED green/orange */ + .postproc = pctv45e_postproc +}; + +static struct stb6100_config stb6100_config = { + .tuner_address = I2C_ADDR_STB6100, + .refclock = 27000000 +}; + + +static struct i2c_algorithm pctv452e_i2c_algo = { + .master_xfer = pctv452e_i2c_xfer, + .functionality = pctv452e_i2c_func +}; + +static int pctv452e_frontend_attach(struct dvb_usb_adapter *a) +{ + struct usb_device_id *id; + + a->fe_adap[0].fe = dvb_attach(stb0899_attach, &stb0899_config, + &a->dev->i2c_adap); + if (!a->fe_adap[0].fe) + return -ENODEV; + if ((dvb_attach(lnbp22_attach, a->fe_adap[0].fe, + &a->dev->i2c_adap)) == 0) + err("Cannot attach lnbp22\n"); + + id = a->dev->desc->warm_ids[0]; + if (USB_VID_TECHNOTREND == id->idVendor + && USB_PID_TECHNOTREND_CONNECT_S2_3650_CI == id->idProduct) + /* Error ignored. */ + tt3650_ci_init(a); + + return 0; +} + +static int pctv452e_tuner_attach(struct dvb_usb_adapter *a) +{ + if (!a->fe_adap[0].fe) + return -ENODEV; + if (dvb_attach(stb6100_attach, a->fe_adap[0].fe, &stb6100_config, + &a->dev->i2c_adap) == 0) { + err("%s failed\n", __func__); + return -ENODEV; + } + + return 0; +} + +static struct usb_device_id pctv452e_usb_table[] = { + {USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_452E)}, + {USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_S2_3600)}, + {USB_DEVICE(USB_VID_TECHNOTREND, + USB_PID_TECHNOTREND_CONNECT_S2_3650_CI)}, + {} +}; +MODULE_DEVICE_TABLE(usb, pctv452e_usb_table); + +static struct dvb_usb_device_properties pctv452e_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */ + .usb_ctrl = DEVICE_SPECIFIC, + + .size_of_priv = sizeof(struct pctv452e_state), + + .power_ctrl = pctv452e_power_ctrl, + + .rc.core = { + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .allowed_protos = RC_TYPE_UNKNOWN, + .rc_query = pctv452e_rc_query, + .rc_interval = 100, + }, + + .num_adapters = 1, + .adapter = {{ + .num_frontends = 1, + .fe = {{ + .frontend_attach = pctv452e_frontend_attach, + .tuner_attach = pctv452e_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_ISOC, + .count = 4, + .endpoint = 0x02, + .u = { + .isoc = { + .framesperurb = 4, + .framesize = 940, + .interval = 1 + } + } + }, + } }, + } }, + + .i2c_algo = &pctv452e_i2c_algo, + + .generic_bulk_ctrl_endpoint = 1, /* allow generice rw function */ + + .num_device_descs = 1, + .devices = { + { .name = "PCTV HDTV USB", + .cold_ids = { NULL, NULL }, /* this is a warm only device */ + .warm_ids = { &pctv452e_usb_table[0], NULL } + }, + { 0 }, + } +}; + +static struct dvb_usb_device_properties tt_connect_s2_3600_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, /* more ? */ + .usb_ctrl = DEVICE_SPECIFIC, + + .size_of_priv = sizeof(struct pctv452e_state), + + .power_ctrl = pctv452e_power_ctrl, + .read_mac_address = pctv452e_read_mac_address, + + .rc.core = { + .rc_codes = RC_MAP_TT_1500, + .allowed_protos = RC_TYPE_UNKNOWN, + .rc_query = pctv452e_rc_query, + .rc_interval = 100, + }, + + .num_adapters = 1, + .adapter = {{ + .num_frontends = 1, + .fe = {{ + .frontend_attach = pctv452e_frontend_attach, + .tuner_attach = pctv452e_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_ISOC, + .count = 7, + .endpoint = 0x02, + .u = { + .isoc = { + .framesperurb = 4, + .framesize = 940, + .interval = 1 + } + } + }, + + } }, + } }, + + .i2c_algo = &pctv452e_i2c_algo, + + .generic_bulk_ctrl_endpoint = 1, /* allow generice rw function*/ + + .num_device_descs = 2, + .devices = { + { .name = "Technotrend TT Connect S2-3600", + .cold_ids = { NULL, NULL }, /* this is a warm only device */ + .warm_ids = { &pctv452e_usb_table[1], NULL } + }, + { .name = "Technotrend TT Connect S2-3650-CI", + .cold_ids = { NULL, NULL }, + .warm_ids = { &pctv452e_usb_table[2], NULL } + }, + { 0 }, + } +}; + +static void pctv452e_usb_disconnect(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + + tt3650_ci_uninit(d); + dvb_usb_device_exit(intf); +} + +static int pctv452e_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + if (0 == dvb_usb_device_init(intf, &pctv452e_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &tt_connect_s2_3600_properties, + THIS_MODULE, NULL, adapter_nr)) + return 0; + + return -ENODEV; +} + +static struct usb_driver pctv452e_usb_driver = { + .name = "pctv452e", + .probe = pctv452e_usb_probe, + .disconnect = pctv452e_usb_disconnect, + .id_table = pctv452e_usb_table, +}; + +static struct usb_driver tt_connects2_3600_usb_driver = { + .name = "dvb-usb-tt-connect-s2-3600-01.fw", + .probe = pctv452e_usb_probe, + .disconnect = pctv452e_usb_disconnect, + .id_table = pctv452e_usb_table, +}; + +static int __init pctv452e_usb_init(void) +{ + int ret = usb_register(&pctv452e_usb_driver); + + if (ret) { + err("%s: usb_register failed! Error %d", __FILE__, ret); + return ret; + } + ret = usb_register(&tt_connects2_3600_usb_driver); + if (ret) + err("%s: usb_register failed! Error %d", __FILE__, ret); + + return ret; +} + +static void __exit pctv452e_usb_exit(void) +{ + usb_deregister(&pctv452e_usb_driver); + usb_deregister(&tt_connects2_3600_usb_driver); +} + +module_init(pctv452e_usb_init); +module_exit(pctv452e_usb_exit); + +MODULE_AUTHOR("Dominik Kuhlen "); +MODULE_AUTHOR("Andre Weidemann "); +MODULE_AUTHOR("Michael H. Schimek "); +MODULE_DESCRIPTION("Pinnacle PCTV HDTV USB DVB / TT connect S2-3600 Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 28fbb5c..4a2d2e6 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -607,6 +607,16 @@ config DVB_LNBP21 help An SEC control chips. +config DVB_LNBP22 + tristate "LNBP22 SEC controllers" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + LNB power supply and control voltage + regulator chip with step-up converter + and I2C interface. + Say Y when you want to support this chip. + config DVB_ISL6405 tristate "ISL6405 SEC controller" depends on DVB_CORE && I2C diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 36c8d81..f639f67 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -52,6 +52,7 @@ obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o obj-$(CONFIG_DVB_CX24123) += cx24123.o obj-$(CONFIG_DVB_LNBP21) += lnbp21.o +obj-$(CONFIG_DVB_LNBP22) += lnbp22.o obj-$(CONFIG_DVB_ISL6405) += isl6405.o obj-$(CONFIG_DVB_ISL6421) += isl6421.o obj-$(CONFIG_DVB_TDA10086) += tda10086.o diff --git a/drivers/media/dvb/frontends/lnbp22.c b/drivers/media/dvb/frontends/lnbp22.c new file mode 100644 index 0000000..84ad039 --- /dev/null +++ b/drivers/media/dvb/frontends/lnbp22.c @@ -0,0 +1,148 @@ +/* + * lnbp22.h - driver for lnb supply and control ic lnbp22 + * + * Copyright (C) 2006 Dominik Kuhlen + * Based on lnbp21 driver + * + * 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 + * of the License, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "lnbp22.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + + +#define dprintk(lvl, arg...) if (debug >= (lvl)) printk(arg) + +struct lnbp22 { + u8 config[4]; + struct i2c_adapter *i2c; +}; + +static int lnbp22_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + struct lnbp22 *lnbp22 = (struct lnbp22 *)fe->sec_priv; + struct i2c_msg msg = { + .addr = 0x08, + .flags = 0, + .buf = (char *)&lnbp22->config, + .len = sizeof(lnbp22->config), + }; + + dprintk(1, "%s: %d (18V=%d 13V=%d)\n", __func__, voltage, + SEC_VOLTAGE_18, SEC_VOLTAGE_13); + + lnbp22->config[3] = 0x60; /* Power down */ + switch (voltage) { + case SEC_VOLTAGE_OFF: + break; + case SEC_VOLTAGE_13: + lnbp22->config[3] |= LNBP22_EN; + break; + case SEC_VOLTAGE_18: + lnbp22->config[3] |= (LNBP22_EN | LNBP22_VSEL); + break; + default: + return -EINVAL; + }; + + dprintk(1, "%s: 0x%02x)\n", __func__, lnbp22->config[3]); + return (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) ? 0 : -EIO; +} + +static int lnbp22_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) +{ + struct lnbp22 *lnbp22 = (struct lnbp22 *) fe->sec_priv; + struct i2c_msg msg = { + .addr = 0x08, + .flags = 0, + .buf = (char *)&lnbp22->config, + .len = sizeof(lnbp22->config), + }; + + dprintk(1, "%s: %d\n", __func__, (int)arg); + if (arg) + lnbp22->config[3] |= LNBP22_LLC; + else + lnbp22->config[3] &= ~LNBP22_LLC; + + return (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) ? 0 : -EIO; +} + +static void lnbp22_release(struct dvb_frontend *fe) +{ + dprintk(1, "%s\n", __func__); + /* LNBP power off */ + lnbp22_set_voltage(fe, SEC_VOLTAGE_OFF); + + /* free data */ + kfree(fe->sec_priv); + fe->sec_priv = NULL; +} + +struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c) +{ + struct lnbp22 *lnbp22 = kmalloc(sizeof(struct lnbp22), GFP_KERNEL); + if (!lnbp22) + return NULL; + + /* default configuration */ + lnbp22->config[0] = 0x00; /* ? */ + lnbp22->config[1] = 0x28; /* ? */ + lnbp22->config[2] = 0x48; /* ? */ + lnbp22->config[3] = 0x60; /* Power down */ + lnbp22->i2c = i2c; + fe->sec_priv = lnbp22; + + /* detect if it is present or not */ + if (lnbp22_set_voltage(fe, SEC_VOLTAGE_OFF)) { + dprintk(0, "%s LNBP22 not found\n", __func__); + kfree(lnbp22); + fe->sec_priv = NULL; + return NULL; + } + + /* install release callback */ + fe->ops.release_sec = lnbp22_release; + + /* override frontend ops */ + fe->ops.set_voltage = lnbp22_set_voltage; + fe->ops.enable_high_lnb_voltage = lnbp22_enable_high_lnb_voltage; + + return fe; +} +EXPORT_SYMBOL(lnbp22_attach); + +MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp22"); +MODULE_AUTHOR("Dominik Kuhlen"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/lnbp22.h b/drivers/media/dvb/frontends/lnbp22.h new file mode 100644 index 0000000..63e2dec --- /dev/null +++ b/drivers/media/dvb/frontends/lnbp22.h @@ -0,0 +1,57 @@ +/* + * lnbp22.h - driver for lnb supply and control ic lnbp22 + * + * Copyright (C) 2006 Dominik Kuhlen + * Based on lnbp21.h + * + * 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 + * of the License, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org + */ + +#ifndef _LNBP22_H +#define _LNBP22_H + +/* Enable */ +#define LNBP22_EN 0x10 +/* Voltage selection */ +#define LNBP22_VSEL 0x02 +/* Plus 1 Volt Bit */ +#define LNBP22_LLC 0x01 + +#include + +#if defined(CONFIG_DVB_LNBP22) || \ + (defined(CONFIG_DVB_LNBP22_MODULE) && defined(MODULE)) +/* + * override_set and override_clear control which system register bits (above) + * to always set & clear + */ +extern struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_LNBP22 */ + +#endif /* _LNBP22_H */ diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.c b/drivers/media/dvb/ttpci/ttpci-eeprom.c index 7dd54b3..32d4315 100644 --- a/drivers/media/dvb/ttpci/ttpci-eeprom.c +++ b/drivers/media/dvb/ttpci/ttpci-eeprom.c @@ -85,6 +85,35 @@ static int getmac_tt(u8 * decodedMAC, u8 * encodedMAC) return 0; } +int ttpci_eeprom_decode_mac(u8 *decodedMAC, u8 *encodedMAC) +{ + u8 xor[20] = { 0x72, 0x23, 0x68, 0x19, 0x5c, 0xa8, 0x71, 0x2c, + 0x54, 0xd3, 0x7b, 0xf1, 0x9E, 0x23, 0x16, 0xf6, + 0x1d, 0x36, 0x64, 0x78}; + u8 data[20]; + int i; + + memcpy(data, encodedMAC, 20); + + for (i = 0; i < 20; i++) + data[i] ^= xor[i]; + for (i = 0; i < 10; i++) + data[i] = ((data[2 * i + 1] << 8) | data[2 * i]) + >> ((data[2 * i + 1] >> 6) & 3); + + if (check_mac_tt(data)) + return -ENODEV; + + decodedMAC[0] = data[2]; + decodedMAC[1] = data[1]; + decodedMAC[2] = data[0]; + decodedMAC[3] = data[6]; + decodedMAC[4] = data[5]; + decodedMAC[5] = data[4]; + return 0; +} +EXPORT_SYMBOL(ttpci_eeprom_decode_mac); + static int ttpci_eeprom_read_encodedMAC(struct i2c_adapter *adapter, u8 * encodedMAC) { int ret; diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.h b/drivers/media/dvb/ttpci/ttpci-eeprom.h index e2dc6cf..dcc33d5 100644 --- a/drivers/media/dvb/ttpci/ttpci-eeprom.h +++ b/drivers/media/dvb/ttpci/ttpci-eeprom.h @@ -28,6 +28,7 @@ #include #include +extern int ttpci_eeprom_decode_mac(u8 *decodedMAC, u8 *encodedMAC); extern int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *propsed_mac); #endif -- cgit v0.10.2 From 3c6938f805c557b45c0b01c081901b44145221d2 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 19 Sep 2011 12:58:54 -0300 Subject: [media] v4l2: Add polarity flag definitions for the parallel bus FIELD signal FIELD signal is used for indicating frame field type to the frame grabber in interlaced scan mode, as specified in ITU-R BT.601 standard. In normal operation mode FIELD = 0 selects Field1 (odd) and FIELD = 1 selects Field2 (even). When the FIELD signal is inverted it's the other way around. Add corresponding flags for configuring the FIELD signal polarity, V4L2_MBUS_FIELD_EVEN_HIGH for the standard (non-inverted) case and V4L2_MBUS_FIELD_EVEN_LOW for inverted case. Also add a comment about usage of V4L2_MBUS_[HV]SYNC* flags for the hardware that uses [HV]REF signals. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h index 6114007..83ae07e 100644 --- a/include/media/v4l2-mediabus.h +++ b/include/media/v4l2-mediabus.h @@ -22,8 +22,12 @@ */ #define V4L2_MBUS_MASTER (1 << 0) #define V4L2_MBUS_SLAVE (1 << 1) -/* Which signal polarities it supports */ -/* Note: in BT.656 mode HSYNC and VSYNC are unused */ +/* + * Signal polarity flags + * Note: in BT.656 mode HSYNC, FIELD, and VSYNC are unused + * V4L2_MBUS_[HV]SYNC* flags should be also used for specifying + * configuration of hardware that uses [HV]REF signals + */ #define V4L2_MBUS_HSYNC_ACTIVE_HIGH (1 << 2) #define V4L2_MBUS_HSYNC_ACTIVE_LOW (1 << 3) #define V4L2_MBUS_VSYNC_ACTIVE_HIGH (1 << 4) @@ -32,6 +36,10 @@ #define V4L2_MBUS_PCLK_SAMPLE_FALLING (1 << 7) #define V4L2_MBUS_DATA_ACTIVE_HIGH (1 << 8) #define V4L2_MBUS_DATA_ACTIVE_LOW (1 << 9) +/* FIELD = 0/1 - Field1 (odd)/Field2 (even) */ +#define V4L2_MBUS_FIELD_EVEN_HIGH (1 << 10) +/* FIELD = 1/0 - Field1 (odd)/Field2 (even) */ +#define V4L2_MBUS_FIELD_EVEN_LOW (1 << 11) /* Serial flags */ /* How many lanes the client can use */ -- cgit v0.10.2 From 12ecf56d1a2f93b625ca30049072613cba2d96b1 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 19 Sep 2011 12:38:35 -0300 Subject: [media] s5p-fimc: Convert to use generic media bus polarity flags Switch to generic media bus signal polarity flags and allow configuring the FIELD signal polarity. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c index 2a1ae51..20e664e 100644 --- a/drivers/media/video/s5p-fimc/fimc-reg.c +++ b/drivers/media/video/s5p-fimc/fimc-reg.c @@ -533,20 +533,24 @@ int fimc_hw_set_camera_polarity(struct fimc_dev *fimc, u32 cfg = readl(fimc->regs + S5P_CIGCTRL); cfg &= ~(S5P_CIGCTRL_INVPOLPCLK | S5P_CIGCTRL_INVPOLVSYNC | - S5P_CIGCTRL_INVPOLHREF | S5P_CIGCTRL_INVPOLHSYNC); + S5P_CIGCTRL_INVPOLHREF | S5P_CIGCTRL_INVPOLHSYNC | + S5P_CIGCTRL_INVPOLFIELD); - if (cam->flags & FIMC_CLK_INV_PCLK) + if (cam->flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) cfg |= S5P_CIGCTRL_INVPOLPCLK; - if (cam->flags & FIMC_CLK_INV_VSYNC) + if (cam->flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) cfg |= S5P_CIGCTRL_INVPOLVSYNC; - if (cam->flags & FIMC_CLK_INV_HREF) + if (cam->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) cfg |= S5P_CIGCTRL_INVPOLHREF; - if (cam->flags & FIMC_CLK_INV_HSYNC) + if (cam->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) cfg |= S5P_CIGCTRL_INVPOLHSYNC; + if (cam->flags & V4L2_MBUS_FIELD_EVEN_LOW) + cfg |= S5P_CIGCTRL_INVPOLFIELD; + writel(cfg, fimc->regs + S5P_CIGCTRL); return 0; diff --git a/drivers/media/video/s5p-fimc/regs-fimc.h b/drivers/media/video/s5p-fimc/regs-fimc.h index 94d2302..c8e3b94 100644 --- a/drivers/media/video/s5p-fimc/regs-fimc.h +++ b/drivers/media/video/s5p-fimc/regs-fimc.h @@ -61,6 +61,7 @@ #define S5P_CIGCTRL_CSC_ITU601_709 (1 << 5) #define S5P_CIGCTRL_INVPOLHSYNC (1 << 4) #define S5P_CIGCTRL_SELCAM_MIPI (1 << 3) +#define S5P_CIGCTRL_INVPOLFIELD (1 << 1) #define S5P_CIGCTRL_INTERLACE (1 << 0) /* Window offset 2 */ diff --git a/include/media/s5p_fimc.h b/include/media/s5p_fimc.h index 2b58904..688fb3f 100644 --- a/include/media/s5p_fimc.h +++ b/include/media/s5p_fimc.h @@ -19,11 +19,6 @@ enum cam_bus_type { FIMC_LCD_WB, /* FIFO link from LCD mixer */ }; -#define FIMC_CLK_INV_PCLK (1 << 0) -#define FIMC_CLK_INV_VSYNC (1 << 1) -#define FIMC_CLK_INV_HREF (1 << 2) -#define FIMC_CLK_INV_HSYNC (1 << 3) - struct i2c_board_info; /** @@ -37,7 +32,7 @@ struct i2c_board_info; * @i2c_bus_num: i2c control bus id the sensor is attached to * @mux_id: FIMC camera interface multiplexer index (separate for MIPI and ITU) * @clk_id: index of the SoC peripheral clock for sensors - * @flags: flags defining bus signals polarity inversion (High by default) + * @flags: the parallel bus flags defining signals polarity (V4L2_MBUS_*) */ struct s5p_fimc_isp_info { struct i2c_board_info *board_info; -- cgit v0.10.2 From 5b3bdfce675040b65a8b97f8209d78a31935c48f Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 19 Sep 2011 09:16:01 -0300 Subject: [media] m5mols: Remove superfluous irq field from the platform data struct There is no need to put the IRQ number in driver's private platform data structure as this can also be passed in struct i2c_lient.irq. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/m5mols/m5mols_core.c b/drivers/media/video/m5mols/m5mols_core.c index fb8e4a7..5d21d05 100644 --- a/drivers/media/video/m5mols/m5mols_core.c +++ b/drivers/media/video/m5mols/m5mols_core.c @@ -936,7 +936,7 @@ static int __devinit m5mols_probe(struct i2c_client *client, return -EINVAL; } - if (!pdata->irq) { + if (!client->irq) { dev_err(&client->dev, "Interrupt not assigned\n"); return -EINVAL; } @@ -973,7 +973,7 @@ static int __devinit m5mols_probe(struct i2c_client *client, init_waitqueue_head(&info->irq_waitq); INIT_WORK(&info->work_irq, m5mols_irq_work); - ret = request_irq(pdata->irq, m5mols_irq_handler, + ret = request_irq(client->irq, m5mols_irq_handler, IRQF_TRIGGER_RISING, MODULE_NAME, sd); if (ret) { dev_err(&client->dev, "Interrupt request failed: %d\n", ret); @@ -998,7 +998,7 @@ static int __devexit m5mols_remove(struct i2c_client *client) struct m5mols_info *info = to_m5mols(sd); v4l2_device_unregister_subdev(sd); - free_irq(info->pdata->irq, sd); + free_irq(client->irq, sd); regulator_bulk_free(ARRAY_SIZE(supplies), supplies); gpio_free(info->pdata->gpio_reset); diff --git a/include/media/m5mols.h b/include/media/m5mols.h index aac2c0e..4a825ae 100644 --- a/include/media/m5mols.h +++ b/include/media/m5mols.h @@ -18,15 +18,13 @@ /** * struct m5mols_platform_data - platform data for M-5MOLS driver - * @irq: GPIO getting the irq pin of M-5MOLS * @gpio_reset: GPIO driving the reset pin of M-5MOLS - * @reset_polarity: active state for gpio_rst pin, 0 or 1 + * @reset_polarity: active state for gpio_reset pin, 0 or 1 * @set_power: an additional callback to the board setup code * to be called after enabling and before disabling * the sensor's supply regulators */ struct m5mols_platform_data { - int irq; int gpio_reset; u8 reset_polarity; int (*set_power)(struct device *dev, int on); -- cgit v0.10.2 From bd829e9d1d7de3178d67d94043f43527213a63a0 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Sun, 19 Dec 2010 19:10:28 -0300 Subject: [media] cx23885, cx25840: Provide IR Rx timeout event reports (Resending because Mauro reported losing some emails on IRC) Provide CX2388[578] IR receive timeout (RTO) reports in the final space raw event sent up the chain to the raw IR pulse decoders. This should allow the lirc decoder to actually measure the inter-transmission gap properly. Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23888-ir.c b/drivers/media/video/cx23885/cx23888-ir.c index e37be6f..bb1ce34 100644 --- a/drivers/media/video/cx23885/cx23888-ir.c +++ b/drivers/media/video/cx23885/cx23888-ir.c @@ -673,7 +673,7 @@ static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count, unsigned int i, n; union cx23888_ir_fifo_rec *p; - unsigned u, v; + unsigned u, v, w; n = count / sizeof(union cx23888_ir_fifo_rec) * sizeof(union cx23888_ir_fifo_rec); @@ -692,11 +692,12 @@ static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count, if ((p->hw_fifo_data & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) { /* Assume RTO was because of no IR light input */ u = 0; - v4l2_dbg(2, ir_888_debug, sd, "rx read: end of rx\n"); + w = 1; } else { u = (p->hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0; if (invert) u = u ? 0 : 1; + w = 0; } v = (unsigned) pulse_width_count_to_ns( @@ -707,9 +708,12 @@ static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count, init_ir_raw_event(&p->ir_core_data); p->ir_core_data.pulse = u; p->ir_core_data.duration = v; + p->ir_core_data.timeout = w; - v4l2_dbg(2, ir_888_debug, sd, "rx read: %10u ns %s\n", - v, u ? "mark" : "space"); + v4l2_dbg(2, ir_888_debug, sd, "rx read: %10u ns %s %s\n", + v, u ? "mark" : "space", w ? "(timed out)" : ""); + if (w) + v4l2_dbg(2, ir_888_debug, sd, "rx read: end of rx\n"); } return 0; } diff --git a/drivers/media/video/cx25840/cx25840-ir.c b/drivers/media/video/cx25840/cx25840-ir.c index 7eb79af..b718a3a 100644 --- a/drivers/media/video/cx25840/cx25840-ir.c +++ b/drivers/media/video/cx25840/cx25840-ir.c @@ -668,7 +668,7 @@ static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count, u16 divider; unsigned int i, n; union cx25840_ir_fifo_rec *p; - unsigned u, v; + unsigned u, v, w; if (ir_state == NULL) return -ENODEV; @@ -694,11 +694,12 @@ static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count, if ((p->hw_fifo_data & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) { /* Assume RTO was because of no IR light input */ u = 0; - v4l2_dbg(2, ir_debug, sd, "rx read: end of rx\n"); + w = 1; } else { u = (p->hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0; if (invert) u = u ? 0 : 1; + w = 0; } v = (unsigned) pulse_width_count_to_ns( @@ -709,9 +710,12 @@ static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count, init_ir_raw_event(&p->ir_core_data); p->ir_core_data.pulse = u; p->ir_core_data.duration = v; + p->ir_core_data.timeout = w; - v4l2_dbg(2, ir_debug, sd, "rx read: %10u ns %s\n", - v, u ? "mark" : "space"); + v4l2_dbg(2, ir_debug, sd, "rx read: %10u ns %s %s\n", + v, u ? "mark" : "space", w ? "(timed out)" : ""); + if (w) + v4l2_dbg(2, ir_debug, sd, "rx read: end of rx\n"); } return 0; } -- cgit v0.10.2 From d7222e7d6fb06ca3e7aa7a1ab07f8e6c6adb1d22 Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Sat, 24 Sep 2011 11:02:32 -0300 Subject: [media] em28xx: fix race on disconnect This patch closes the race on the device and extension lists at USB disconnect time. Previously, the device was removed from the device list during em28xx_release_resources(), and then passed to the em28xx_close_extension() function so that all extensions could run their fini() operations. However, this left a (brief, theoretical, highly unlikely ;-)) window between these two calls during which a new module could call em28xx_register_extension(). The result would have been that the em28xx_usb_disconnect() function would also have passed the device to the new extension's fini() function, despite never having called the extension's init() function. This patch also restores em28xx_close_extension()'s symmetry with em28xx_init_extension(), and establishes the property that every device in the device list must have been initialised for every extension in the extension list. Signed-off-by: Chris Rankin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 7425f92..7297d90 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -2800,9 +2800,9 @@ static void flush_request_modules(struct em28xx *dev) #endif /* CONFIG_MODULES */ /* - * em28xx_realease_resources() + * em28xx_release_resources() * unregisters the v4l2,i2c and usb devices - * called when the device gets disconected or at module unload + * called when the device gets disconnected or at module unload */ void em28xx_release_resources(struct em28xx *dev) { @@ -2816,8 +2816,6 @@ void em28xx_release_resources(struct em28xx *dev) em28xx_release_analog_resources(dev); - em28xx_remove_from_devlist(dev); - em28xx_i2c_unregister(dev); v4l2_device_unregister(&dev->v4l2_dev); @@ -3255,7 +3253,7 @@ err_no_slot: /* * em28xx_usb_disconnect() - * called when the device gets diconencted + * called when the device gets disconnected * video device will be unregistered on v4l2_close in case it is still open */ static void em28xx_usb_disconnect(struct usb_interface *interface) diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index bd481ab..804a4ab 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -1184,18 +1184,6 @@ static LIST_HEAD(em28xx_devlist); static DEFINE_MUTEX(em28xx_devlist_mutex); /* - * em28xx_realease_resources() - * unregisters the v4l2,i2c and usb devices - * called when the device gets disconected or at module unload -*/ -void em28xx_remove_from_devlist(struct em28xx *dev) -{ - mutex_lock(&em28xx_devlist_mutex); - list_del(&dev->devlist); - mutex_unlock(&em28xx_devlist_mutex); -}; - -/* * Extension interface */ @@ -1245,14 +1233,13 @@ void em28xx_init_extension(struct em28xx *dev) void em28xx_close_extension(struct em28xx *dev) { - struct em28xx_ops *ops = NULL; + const struct em28xx_ops *ops = NULL; mutex_lock(&em28xx_devlist_mutex); - if (!list_empty(&em28xx_extension_devlist)) { - list_for_each_entry(ops, &em28xx_extension_devlist, next) { - if (ops->fini) - ops->fini(dev); - } + list_for_each_entry(ops, &em28xx_extension_devlist, next) { + if (ops->fini) + ops->fini(dev); } + list_del(&dev->devlist); mutex_unlock(&em28xx_devlist_mutex); } -- cgit v0.10.2 From fa0d11873943b29d6c8f57a7d54f77d0439acfd9 Mon Sep 17 00:00:00 2001 From: Florent AUDEBERT Date: Fri, 11 Jun 2010 12:01:25 -0300 Subject: [media] stb0899: Removed an extra byte sent at init on DiSEqC bus I noticed a stray 0x00 at init on DiSEqC bus (KNC1 DVB-S2) with a DiSEqC tool analyzer. I removed the register from initialization table and all seem to go well (at least for my KNC board). Signed-off-by: Florent Audebert Acked-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/az6027.c b/drivers/media/dvb/dvb-usb/az6027.c index 2f42a81..bf67b4d 100644 --- a/drivers/media/dvb/dvb-usb/az6027.c +++ b/drivers/media/dvb/dvb-usb/az6027.c @@ -40,7 +40,6 @@ static const struct stb0899_s1_reg az6027_stb0899_s1_init_1[] = { { STB0899_DISRX_ST0 , 0x04 }, { STB0899_DISRX_ST1 , 0x00 }, { STB0899_DISPARITY , 0x00 }, - { STB0899_DISFIFO , 0x00 }, { STB0899_DISSTATUS , 0x20 }, { STB0899_DISF22 , 0x99 }, { STB0899_DISF22RX , 0xa8 }, diff --git a/drivers/media/dvb/mantis/mantis_vp1041.c b/drivers/media/dvb/mantis/mantis_vp1041.c index 38a436c..07aa887 100644 --- a/drivers/media/dvb/mantis/mantis_vp1041.c +++ b/drivers/media/dvb/mantis/mantis_vp1041.c @@ -51,7 +51,6 @@ static const struct stb0899_s1_reg vp1041_stb0899_s1_init_1[] = { { STB0899_DISRX_ST0 , 0x04 }, { STB0899_DISRX_ST1 , 0x00 }, { STB0899_DISPARITY , 0x00 }, - { STB0899_DISFIFO , 0x00 }, { STB0899_DISSTATUS , 0x20 }, { STB0899_DISF22 , 0x99 }, { STB0899_DISF22RX , 0xa8 }, diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 91b7d53..78d32f7 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -898,7 +898,6 @@ static const struct stb0899_s1_reg knc1_stb0899_s1_init_1[] = { { STB0899_DISRX_ST0 , 0x04 }, { STB0899_DISRX_ST1 , 0x00 }, { STB0899_DISPARITY , 0x00 }, - { STB0899_DISFIFO , 0x00 }, { STB0899_DISSTATUS , 0x20 }, { STB0899_DISF22 , 0x8c }, { STB0899_DISF22RX , 0x9a }, diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 926f299..ca02e97 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -1053,7 +1053,6 @@ static const struct stb0899_s1_reg tt3200_stb0899_s1_init_1[] = { { STB0899_DISRX_ST0 , 0x04 }, { STB0899_DISRX_ST1 , 0x00 }, { STB0899_DISPARITY , 0x00 }, - { STB0899_DISFIFO , 0x00 }, { STB0899_DISSTATUS , 0x20 }, { STB0899_DISF22 , 0x8c }, { STB0899_DISF22RX , 0x9a }, -- cgit v0.10.2 From 79d06d4dff733ee472e1f8933a33317a18195c0c Mon Sep 17 00:00:00 2001 From: Marko Ristola Date: Sat, 7 Aug 2010 08:16:15 -0300 Subject: [media] Refactor Mantis DMA transfer to deliver 16Kb TS data per interrupt With VDR streaming HDTV into network, generating an interrupt once per 16kb, implemented in this patch, seems to support more robust throughput with HDTV. Fix leaking almost 64kb data from the previous TS after changing the TS. One effect of the old version was, that the DMA transfer and driver's DMA buffer access might happen at the same time - a race condition. Signed-off-by: Marko M. Ristola Reviewed-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/mantis/hopper_cards.c b/drivers/media/dvb/mantis/hopper_cards.c index 8bbeebc..71622f6 100644 --- a/drivers/media/dvb/mantis/hopper_cards.c +++ b/drivers/media/dvb/mantis/hopper_cards.c @@ -126,7 +126,7 @@ static irqreturn_t hopper_irq_handler(int irq, void *dev_id) } if (stat & MANTIS_INT_RISCI) { dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]); - mantis->finished_block = (stat & MANTIS_INT_RISCSTAT) >> 28; + mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28; tasklet_schedule(&mantis->tasklet); } if (stat & MANTIS_INT_I2CDONE) { diff --git a/drivers/media/dvb/mantis/mantis_cards.c b/drivers/media/dvb/mantis/mantis_cards.c index e6c8368..c2bb90b 100644 --- a/drivers/media/dvb/mantis/mantis_cards.c +++ b/drivers/media/dvb/mantis/mantis_cards.c @@ -134,7 +134,7 @@ static irqreturn_t mantis_irq_handler(int irq, void *dev_id) } if (stat & MANTIS_INT_RISCI) { dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]); - mantis->finished_block = (stat & MANTIS_INT_RISCSTAT) >> 28; + mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28; tasklet_schedule(&mantis->tasklet); } if (stat & MANTIS_INT_I2CDONE) { diff --git a/drivers/media/dvb/mantis/mantis_common.h b/drivers/media/dvb/mantis/mantis_common.h index 49dbca1..f2410cf 100644 --- a/drivers/media/dvb/mantis/mantis_common.h +++ b/drivers/media/dvb/mantis/mantis_common.h @@ -123,11 +123,8 @@ struct mantis_pci { unsigned int num; /* RISC Core */ - u32 finished_block; + u32 busy_block; u32 last_block; - u32 line_bytes; - u32 line_count; - u32 risc_pos; u8 *buf_cpu; dma_addr_t buf_dma; u32 *risc_cpu; diff --git a/drivers/media/dvb/mantis/mantis_dma.c b/drivers/media/dvb/mantis/mantis_dma.c index 46202a4..c61ca7d 100644 --- a/drivers/media/dvb/mantis/mantis_dma.c +++ b/drivers/media/dvb/mantis/mantis_dma.c @@ -43,13 +43,17 @@ #define RISC_IRQ (0x01 << 24) #define RISC_STATUS(status) ((((~status) & 0x0f) << 20) | ((status & 0x0f) << 16)) -#define RISC_FLUSH() (mantis->risc_pos = 0) -#define RISC_INSTR(opcode) (mantis->risc_cpu[mantis->risc_pos++] = cpu_to_le32(opcode)) +#define RISC_FLUSH(risc_pos) (risc_pos = 0) +#define RISC_INSTR(risc_pos, opcode) (mantis->risc_cpu[risc_pos++] = cpu_to_le32(opcode)) #define MANTIS_BUF_SIZE (64 * 1024) -#define MANTIS_BLOCK_BYTES (MANTIS_BUF_SIZE >> 4) -#define MANTIS_BLOCK_COUNT (1 << 4) -#define MANTIS_RISC_SIZE PAGE_SIZE +#define MANTIS_BLOCK_BYTES (MANTIS_BUF_SIZE / 4) +#define MANTIS_DMA_TR_BYTES (2 * 1024) /* upper limit: 4095 bytes. */ +#define MANTIS_BLOCK_COUNT (MANTIS_BUF_SIZE / MANTIS_BLOCK_BYTES) + +#define MANTIS_DMA_TR_UNITS (MANTIS_BLOCK_BYTES / MANTIS_DMA_TR_BYTES) +/* MANTIS_BUF_SIZE / MANTIS_DMA_TR_UNITS must not exceed MANTIS_RISC_SIZE (4k RISC cmd buffer) */ +#define MANTIS_RISC_SIZE PAGE_SIZE /* RISC program must fit here. */ int mantis_dma_exit(struct mantis_pci *mantis) { @@ -124,27 +128,6 @@ err: return -ENOMEM; } -static inline int mantis_calc_lines(struct mantis_pci *mantis) -{ - mantis->line_bytes = MANTIS_BLOCK_BYTES; - mantis->line_count = MANTIS_BLOCK_COUNT; - - while (mantis->line_bytes > 4095) { - mantis->line_bytes >>= 1; - mantis->line_count <<= 1; - } - - dprintk(MANTIS_DEBUG, 1, "Mantis RISC block bytes=[%d], line bytes=[%d], line count=[%d]", - MANTIS_BLOCK_BYTES, mantis->line_bytes, mantis->line_count); - - if (mantis->line_count > 255) { - dprintk(MANTIS_ERROR, 1, "Buffer size error"); - return -EINVAL; - } - - return 0; -} - int mantis_dma_init(struct mantis_pci *mantis) { int err = 0; @@ -158,12 +141,6 @@ int mantis_dma_init(struct mantis_pci *mantis) goto err; } - err = mantis_calc_lines(mantis); - if (err < 0) { - dprintk(MANTIS_ERROR, 1, "Mantis calc lines failed"); - - goto err; - } return 0; err: @@ -174,31 +151,32 @@ EXPORT_SYMBOL_GPL(mantis_dma_init); static inline void mantis_risc_program(struct mantis_pci *mantis) { u32 buf_pos = 0; - u32 line; + u32 line, step; + u32 risc_pos; dprintk(MANTIS_DEBUG, 1, "Mantis create RISC program"); - RISC_FLUSH(); - - dprintk(MANTIS_DEBUG, 1, "risc len lines %u, bytes per line %u", - mantis->line_count, mantis->line_bytes); - - for (line = 0; line < mantis->line_count; line++) { - dprintk(MANTIS_DEBUG, 1, "RISC PROG line=[%d]", line); - if (!(buf_pos % MANTIS_BLOCK_BYTES)) { - RISC_INSTR(RISC_WRITE | - RISC_IRQ | - RISC_STATUS(((buf_pos / MANTIS_BLOCK_BYTES) + - (MANTIS_BLOCK_COUNT - 1)) % - MANTIS_BLOCK_COUNT) | - mantis->line_bytes); - } else { - RISC_INSTR(RISC_WRITE | mantis->line_bytes); - } - RISC_INSTR(mantis->buf_dma + buf_pos); - buf_pos += mantis->line_bytes; + RISC_FLUSH(risc_pos); + + dprintk(MANTIS_DEBUG, 1, "risc len lines %u, bytes per line %u, bytes per DMA tr %u", + MANTIS_BLOCK_COUNT, MANTIS_BLOCK_BYTES, MANTIS_DMA_TR_BYTES); + + for (line = 0; line < MANTIS_BLOCK_COUNT; line++) { + for (step = 0; step < MANTIS_DMA_TR_UNITS; step++) { + dprintk(MANTIS_DEBUG, 1, "RISC PROG line=[%d], step=[%d]", line, step); + if (step == 0) { + RISC_INSTR(risc_pos, RISC_WRITE | + RISC_IRQ | + RISC_STATUS(line) | + MANTIS_DMA_TR_BYTES); + } else { + RISC_INSTR(risc_pos, RISC_WRITE | MANTIS_DMA_TR_BYTES); + } + RISC_INSTR(risc_pos, mantis->buf_dma + buf_pos); + buf_pos += MANTIS_DMA_TR_BYTES; + } } - RISC_INSTR(RISC_JUMP); - RISC_INSTR(mantis->risc_dma); + RISC_INSTR(risc_pos, RISC_JUMP); + RISC_INSTR(risc_pos, mantis->risc_dma); } void mantis_dma_start(struct mantis_pci *mantis) @@ -210,7 +188,7 @@ void mantis_dma_start(struct mantis_pci *mantis) mmwrite(mmread(MANTIS_GPIF_ADDR) | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR); mmwrite(0, MANTIS_DMA_CTL); - mantis->last_block = mantis->finished_block = 0; + mantis->last_block = mantis->busy_block = 0; mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_RISCI, MANTIS_INT_MASK); @@ -245,9 +223,9 @@ void mantis_dma_xfer(unsigned long data) struct mantis_pci *mantis = (struct mantis_pci *) data; struct mantis_hwconfig *config = mantis->hwconfig; - while (mantis->last_block != mantis->finished_block) { + while (mantis->last_block != mantis->busy_block) { dprintk(MANTIS_DEBUG, 1, "last block=[%d] finished block=[%d]", - mantis->last_block, mantis->finished_block); + mantis->last_block, mantis->busy_block); (config->ts_size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter) (&mantis->demux, &mantis->buf_cpu[mantis->last_block * MANTIS_BLOCK_BYTES], MANTIS_BLOCK_BYTES); -- cgit v0.10.2 From aad04c774331890befcd7a77406c2b6f273ab7a9 Mon Sep 17 00:00:00 2001 From: Hans Petter Selasky Date: Mon, 23 May 2011 11:21:47 -0300 Subject: [media] Increase a timeout, so that bad scheduling does not accidentially cause a timeout --HPS >From 18faaafc9cbbe478bb49023bbeae490149048560 Mon Sep 17 00:00:00 2001 Signed-off-by: Hans Petter Selasky Acked-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/frontends/stb0899_drv.c b/drivers/media/dvb/frontends/stb0899_drv.c index 7691282..8408ef8 100644 --- a/drivers/media/dvb/frontends/stb0899_drv.c +++ b/drivers/media/dvb/frontends/stb0899_drv.c @@ -706,7 +706,7 @@ static int stb0899_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_ma stb0899_write_reg(state, STB0899_DISCNTRL1, reg); for (i = 0; i < cmd->msg_len; i++) { /* wait for FIFO empty */ - if (stb0899_wait_diseqc_fifo_empty(state, 10) < 0) + if (stb0899_wait_diseqc_fifo_empty(state, 100) < 0) return -ETIMEDOUT; stb0899_write_reg(state, STB0899_DISFIFO, cmd->msg[i]); -- cgit v0.10.2 From 4a6c4a9567aed23cf7e8134c63f3176a57e5572b Mon Sep 17 00:00:00 2001 From: Guy Martin Date: Wed, 1 Jun 2011 11:25:16 -0300 Subject: [media] stv090x: set status bits when there is no lock Currently, the stv090x driver only set the status bits to SCVYL when there is a lock. This patch set the right bits even if there is no lock. Signed-off-by: Guy Martin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c index 52d8712..ebda419 100644 --- a/drivers/media/dvb/frontends/stv090x.c +++ b/drivers/media/dvb/frontends/stv090x.c @@ -3463,9 +3463,15 @@ static enum dvbfe_search stv090x_search(struct dvb_frontend *fe, struct dvb_fron static int stv090x_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct stv090x_state *state = fe->demodulator_priv; - u32 reg; + u32 reg, dstatus; u8 search_state; + *status = 0; + + dstatus = STV090x_READ_DEMOD(state, DSTATUS); + if (STV090x_GETFIELD_Px(dstatus, CAR_LOCK_FIELD)) + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER; + reg = STV090x_READ_DEMOD(state, DMDSTATE); search_state = STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD); @@ -3474,41 +3480,30 @@ static int stv090x_read_status(struct dvb_frontend *fe, enum fe_status *status) case 1: /* first PLH detected */ default: dprintk(FE_DEBUG, 1, "Status: Unlocked (Searching ..)"); - *status = 0; break; case 2: /* DVB-S2 mode */ dprintk(FE_DEBUG, 1, "Delivery system: DVB-S2"); - reg = STV090x_READ_DEMOD(state, DSTATUS); - if (STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD)) { + if (STV090x_GETFIELD_Px(dstatus, LOCK_DEFINITIF_FIELD)) { reg = STV090x_READ_DEMOD(state, PDELSTATUS1); if (STV090x_GETFIELD_Px(reg, PKTDELIN_LOCK_FIELD)) { + *status |= FE_HAS_VITERBI; reg = STV090x_READ_DEMOD(state, TSSTATUS); - if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD)) { - *status = FE_HAS_SIGNAL | - FE_HAS_CARRIER | - FE_HAS_VITERBI | - FE_HAS_SYNC | - FE_HAS_LOCK; - } + if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD)) + *status |= FE_HAS_SYNC | FE_HAS_LOCK; } } break; case 3: /* DVB-S1/legacy mode */ dprintk(FE_DEBUG, 1, "Delivery system: DVB-S"); - reg = STV090x_READ_DEMOD(state, DSTATUS); - if (STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD)) { + if (STV090x_GETFIELD_Px(dstatus, LOCK_DEFINITIF_FIELD)) { reg = STV090x_READ_DEMOD(state, VSTATUSVIT); if (STV090x_GETFIELD_Px(reg, LOCKEDVIT_FIELD)) { + *status |= FE_HAS_VITERBI; reg = STV090x_READ_DEMOD(state, TSSTATUS); - if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD)) { - *status = FE_HAS_SIGNAL | - FE_HAS_CARRIER | - FE_HAS_VITERBI | - FE_HAS_SYNC | - FE_HAS_LOCK; - } + if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD)) + *status |= FE_HAS_SYNC | FE_HAS_LOCK; } } break; -- cgit v0.10.2 From b868a537b675eed2ba84bbeca4c8557ebf9e0156 Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Sat, 24 Sep 2011 16:54:58 -0300 Subject: [media] em28xx: fix deadlock when unplugging and replugging a DVB adapter This fixes the deadlock that occurs with either multiple PCTV 290e adapters or when a single PCTV 290e adapter is replugged. For DVB devices, the device lock must now *not* be held when adding/removing either a device or an extension to the respective lists. (Because em28xx_init_dvb() will want to take the lock instead). Conversely, for Audio-Only devices, the device lock *must* be held when adding/removing either a device or an extension to the respective lists. Signed-off-by: Chris Rankin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 7297d90..2e1c121 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -3005,7 +3005,9 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, goto fail; } + mutex_unlock(&dev->lock); em28xx_init_extension(dev); + mutex_lock(&dev->lock); /* Save some power by putting tuner to sleep */ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0); @@ -3301,10 +3303,10 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) em28xx_release_resources(dev); } - em28xx_close_extension(dev); - mutex_unlock(&dev->lock); + em28xx_close_extension(dev); + if (!dev->users) { kfree(dev->alt_max_pkt_size); kfree(dev); -- cgit v0.10.2 From f055815fd0e4dd22ffd523f0e5117132c0a49e3d Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Sun, 25 Sep 2011 09:53:25 -0300 Subject: [media] em28xx: remove unused prototypes This patch just removes the prototypes for the two functions that I've already deleted in my previous patches. Signed-off-by: Chris Rankin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 1626e4a..2a2cb7e 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -678,8 +678,6 @@ int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev); int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode); int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio); void em28xx_wake_i2c(struct em28xx *dev); -void em28xx_remove_from_devlist(struct em28xx *dev); -void em28xx_add_into_devlist(struct em28xx *dev); int em28xx_register_extension(struct em28xx_ops *dev); void em28xx_unregister_extension(struct em28xx_ops *dev); void em28xx_init_extension(struct em28xx *dev); -- cgit v0.10.2 From 778f295080b62cbce1af402e1704566531e01233 Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Sun, 25 Sep 2011 18:43:12 -0300 Subject: [media] em28xx: replug locking cleanup Simplifies the locking by moving the em28xx_init_extension() call until em28xx_usb_probe() has finished with the dev->lock mutex. It therefore makes the second and subsequent "plugging" events logically identical to the first "plugging" event when the em28xx-dvb and em28xx-alsa modules must be loaded (i.e. registered). Basically, em28xx_usb_probe() requests that em28xx-dvb be loaded and also triggers udev to initialise the V4L2 devices. These two events are serialised by the dev->lock mutex but the order that they happen in is undefined. But this has always been the case anyway. Signed-off-by: Chris Rankin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 2e1c121..4240f0b 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -3005,10 +3005,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, goto fail; } - mutex_unlock(&dev->lock); - em28xx_init_extension(dev); - mutex_lock(&dev->lock); - /* Save some power by putting tuner to sleep */ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0); @@ -3243,6 +3239,13 @@ static int em28xx_usb_probe(struct usb_interface *interface, */ mutex_unlock(&dev->lock); + /* + * These extensions can be modules. If the modules are already + * loaded then we can initialise the device now, otherwise we + * will initialise it when the modules load instead. + */ + em28xx_init_extension(dev); + return 0; err: -- cgit v0.10.2 From 0f6c5653f833be744ad46f46da8fd06ce05c2bd1 Mon Sep 17 00:00:00 2001 From: Hatim Ali Date: Thu, 22 Sep 2011 02:54:51 -0300 Subject: [media] s5p-tv: Add PM_RUNTIME dependency The TVOUT driver requires PM_RUNTIME support for proper clock enabling. Signed-off-by: Hatim Ali Signed-off-by: Marek Szyprowski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-tv/Kconfig b/drivers/media/video/s5p-tv/Kconfig index 9c37dee..f2a0977 100644 --- a/drivers/media/video/s5p-tv/Kconfig +++ b/drivers/media/video/s5p-tv/Kconfig @@ -8,7 +8,7 @@ config VIDEO_SAMSUNG_S5P_TV bool "Samsung TV driver for S5P platform (experimental)" - depends on PLAT_S5P + depends on PLAT_S5P && PM_RUNTIME depends on EXPERIMENTAL default n ---help--- -- cgit v0.10.2 From 17b27478ccdb5b6883032031b83f5cd2ce5f8cf9 Mon Sep 17 00:00:00 2001 From: Tomasz Stanislawski Date: Thu, 25 Aug 2011 12:45:22 -0300 Subject: [media] s5p-tv: hdmi: use DVI mode Current version of the driver does not support HDMI features not present in DVI standard. Therefore DVI mode is used to keep compatibility with DVI devices. Signed-off-by: Tomasz Stanislawski Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-tv/hdmi_drv.c b/drivers/media/video/s5p-tv/hdmi_drv.c index 06d6663..e1b29b4 100644 --- a/drivers/media/video/s5p-tv/hdmi_drv.c +++ b/drivers/media/video/s5p-tv/hdmi_drv.c @@ -210,20 +210,17 @@ static void hdmi_reg_init(struct hdmi_device *hdev) /* enable HPD interrupts */ hdmi_write_mask(hdev, HDMI_INTC_CON, ~0, HDMI_INTC_EN_GLOBAL | HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG); - /* choose HDMI mode */ + /* choose DVI mode */ hdmi_write_mask(hdev, HDMI_MODE_SEL, - HDMI_MODE_HDMI_EN, HDMI_MODE_MASK); + HDMI_MODE_DVI_EN, HDMI_MODE_MASK); + hdmi_write_mask(hdev, HDMI_CON_2, ~0, + HDMI_DVI_PERAMBLE_EN | HDMI_DVI_BAND_EN); /* disable bluescreen */ hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN); /* choose bluescreen (fecal) color */ hdmi_writeb(hdev, HDMI_BLUE_SCREEN_0, 0x12); hdmi_writeb(hdev, HDMI_BLUE_SCREEN_1, 0x34); hdmi_writeb(hdev, HDMI_BLUE_SCREEN_2, 0x56); - /* enable AVI packet every vsync, fixes purple line problem */ - hdmi_writeb(hdev, HDMI_AVI_CON, 0x02); - /* force YUV444, look to CEA-861-D, table 7 for more detail */ - hdmi_writeb(hdev, HDMI_AVI_BYTE(0), 2 << 5); - hdmi_write_mask(hdev, HDMI_CON_1, 2, 3 << 5); } static void hdmi_timing_apply(struct hdmi_device *hdev, diff --git a/drivers/media/video/s5p-tv/regs-hdmi.h b/drivers/media/video/s5p-tv/regs-hdmi.h index ac93ad6..33247d1 100644 --- a/drivers/media/video/s5p-tv/regs-hdmi.h +++ b/drivers/media/video/s5p-tv/regs-hdmi.h @@ -127,6 +127,10 @@ #define HDMI_BLUE_SCR_EN (1 << 5) #define HDMI_EN (1 << 0) +/* HDMI_CON_2 */ +#define HDMI_DVI_PERAMBLE_EN (1 << 5) +#define HDMI_DVI_BAND_EN (1 << 1) + /* HDMI_PHY_STATUS */ #define HDMI_PHY_STATUS_READY (1 << 0) -- cgit v0.10.2 From 0689133b7fadd2e10f4bddca36c895223a541c6c Mon Sep 17 00:00:00 2001 From: Tomasz Stanislawski Date: Thu, 25 Aug 2011 12:47:48 -0300 Subject: [media] s5p-tv: fix mbus configuration This patch fixes mbus configuration between Mixer, SDO and HDMI. The SDO accepts only YUV444 on input. The HDMI in DVI mode accepts only RGB888. Now Mixer is choosing proper output format depending on mbus format. Signed-off-by: Tomasz Stanislawski Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-tv/hdmi_drv.c b/drivers/media/video/s5p-tv/hdmi_drv.c index e1b29b4..0279e6e 100644 --- a/drivers/media/video/s5p-tv/hdmi_drv.c +++ b/drivers/media/video/s5p-tv/hdmi_drv.c @@ -440,6 +440,7 @@ static const struct hdmi_preset_conf hdmi_conf_480p = { .height = 480, .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */ .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_SRGB, }, }; @@ -472,6 +473,7 @@ static const struct hdmi_preset_conf hdmi_conf_720p60 = { .height = 720, .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */ .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_SRGB, }, }; @@ -504,6 +506,7 @@ static const struct hdmi_preset_conf hdmi_conf_1080p50 = { .height = 1080, .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */ .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_SRGB, }, }; @@ -536,6 +539,7 @@ static const struct hdmi_preset_conf hdmi_conf_1080p60 = { .height = 1080, .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */ .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_SRGB, }, }; diff --git a/drivers/media/video/s5p-tv/mixer_reg.c b/drivers/media/video/s5p-tv/mixer_reg.c index 38dac67..4800a3c 100644 --- a/drivers/media/video/s5p-tv/mixer_reg.c +++ b/drivers/media/video/s5p-tv/mixer_reg.c @@ -90,7 +90,7 @@ void mxr_reg_reset(struct mxr_device *mdev) mxr_vsync_set_update(mdev, MXR_DISABLE); /* set output in RGB888 mode */ - mxr_write(mdev, MXR_CFG, MXR_CFG_OUT_YUV444); + mxr_write(mdev, MXR_CFG, MXR_CFG_OUT_RGB888); /* 16 beat burst in DMA */ mxr_write_mask(mdev, MXR_STATUS, MXR_STATUS_16_BURST, @@ -376,6 +376,12 @@ void mxr_reg_set_mbus_fmt(struct mxr_device *mdev, spin_lock_irqsave(&mdev->reg_slock, flags); mxr_vsync_set_update(mdev, MXR_DISABLE); + /* selecting colorspace accepted by output */ + if (fmt->colorspace == V4L2_COLORSPACE_JPEG) + val |= MXR_CFG_OUT_YUV444; + else + val |= MXR_CFG_OUT_RGB888; + /* choosing between interlace and progressive mode */ if (fmt->field == V4L2_FIELD_INTERLACED) val |= MXR_CFG_SCAN_INTERLACE; @@ -394,7 +400,8 @@ void mxr_reg_set_mbus_fmt(struct mxr_device *mdev, else WARN(1, "unrecognized mbus height %u!\n", fmt->height); - mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_SCAN_MASK); + mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_SCAN_MASK | + MXR_CFG_OUT_MASK); val = (fmt->field == V4L2_FIELD_INTERLACED) ? ~0 : 0; vp_write_mask(mdev, VP_MODE, val, diff --git a/drivers/media/video/s5p-tv/regs-mixer.h b/drivers/media/video/s5p-tv/regs-mixer.h index 3c84426..158abb4 100644 --- a/drivers/media/video/s5p-tv/regs-mixer.h +++ b/drivers/media/video/s5p-tv/regs-mixer.h @@ -67,6 +67,7 @@ /* bits for MXR_CFG */ #define MXR_CFG_OUT_YUV444 (0 << 8) #define MXR_CFG_OUT_RGB888 (1 << 8) +#define MXR_CFG_OUT_MASK (1 << 8) #define MXR_CFG_DST_SDO (0 << 7) #define MXR_CFG_DST_HDMI (1 << 7) #define MXR_CFG_DST_MASK (1 << 7) diff --git a/drivers/media/video/s5p-tv/sdo_drv.c b/drivers/media/video/s5p-tv/sdo_drv.c index 4dddd6b..8cec67e 100644 --- a/drivers/media/video/s5p-tv/sdo_drv.c +++ b/drivers/media/video/s5p-tv/sdo_drv.c @@ -170,6 +170,7 @@ static int sdo_g_mbus_fmt(struct v4l2_subdev *sd, fmt->height = sdev->fmt->height; fmt->code = V4L2_MBUS_FMT_FIXED; fmt->field = V4L2_FIELD_INTERLACED; + fmt->colorspace = V4L2_COLORSPACE_JPEG; return 0; } -- cgit v0.10.2 From 0f910bf0008c54b33da5691278c8ee8e8700ac48 Mon Sep 17 00:00:00 2001 From: Michael Olbrich Date: Tue, 12 Jul 2011 09:46:44 -0300 Subject: [media] v4l: mem2mem: add wait_{prepare,finish} ops to m2m_testdev These are necessary to prevent dead-locks e.g. if one thread waits in dqbuf at one end and another tries to queue a buffer at the other end. Signed-off-by: Michael Olbrich Cc: Mauro Carvalho Chehab Cc: Pawel Osciak Acked-by: Pawel Osciak Signed-off-by: Marek Szyprowski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/mem2mem_testdev.c b/drivers/media/video/mem2mem_testdev.c index 0d0c0d5..9594b52 100644 --- a/drivers/media/video/mem2mem_testdev.c +++ b/drivers/media/video/mem2mem_testdev.c @@ -793,10 +793,24 @@ static void m2mtest_buf_queue(struct vb2_buffer *vb) v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); } +static void m2mtest_wait_prepare(struct vb2_queue *q) +{ + struct m2mtest_ctx *ctx = vb2_get_drv_priv(q); + m2mtest_unlock(ctx); +} + +static void m2mtest_wait_finish(struct vb2_queue *q) +{ + struct m2mtest_ctx *ctx = vb2_get_drv_priv(q); + m2mtest_lock(ctx); +} + static struct vb2_ops m2mtest_qops = { .queue_setup = m2mtest_queue_setup, .buf_prepare = m2mtest_buf_prepare, .buf_queue = m2mtest_buf_queue, + .wait_prepare = m2mtest_wait_prepare, + .wait_finish = m2mtest_wait_finish, }; static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) -- cgit v0.10.2 From 9e83b3e434f29d71f923035a6001870d185581ec Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 26 Sep 2011 16:49:01 -0300 Subject: Revert "[media] siano: apply debug flag to module level" This reverts commit ea3709435c7f2da8852c3d676874cd727253fc60. As reported by Stephen Rothwell: After merging the v4l-dvb tree, today's linux-next build (x86_64 allmodconfig) failed like this: ERROR: "sms_dbg" [drivers/media/dvb/siano/smsusb.ko] undefined! ERROR: "sms_dbg" [drivers/media/dvb/siano/smsdvb.ko] undefined! Caused by commit ea3709435c7f ("[media] siano: apply debug flag to module level"). Relevant config: CONFIG_SMS_SIANO_MDTV=m CONFIG_SMS_USB_DRV=m CONFIG_SMS_SDIO_DRV=m Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c index cf442dc..af121db 100644 --- a/drivers/media/dvb/siano/sms-cards.c +++ b/drivers/media/dvb/siano/sms-cards.c @@ -20,6 +20,10 @@ #include "sms-cards.h" #include "smsir.h" +static int sms_dbg; +module_param_named(cards_dbg, sms_dbg, int, 0644); +MODULE_PARM_DESC(cards_dbg, "set debug level (info=1, adv=2 (or-able))"); + static struct sms_board sms_boards[] = { [SMS_BOARD_UNKNOWN] = { .name = "Unknown board", diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c index c0acacc..7331e84 100644 --- a/drivers/media/dvb/siano/smscoreapi.c +++ b/drivers/media/dvb/siano/smscoreapi.c @@ -39,7 +39,7 @@ #include "smsir.h" #include "smsendian.h" -int sms_dbg; +static int sms_dbg; module_param_named(debug, sms_dbg, int, 0644); MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); diff --git a/drivers/media/dvb/siano/smscoreapi.h b/drivers/media/dvb/siano/smscoreapi.h index bd1cafc..c592ae0 100644 --- a/drivers/media/dvb/siano/smscoreapi.h +++ b/drivers/media/dvb/siano/smscoreapi.h @@ -751,7 +751,6 @@ int smscore_led_state(struct smscore_device_t *core, int led); /* ------------------------------------------------------------------------ */ -extern int sms_dbg; #define DBG_INFO 1 #define DBG_ADV 2 diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c index b1f4911..37c594f 100644 --- a/drivers/media/dvb/siano/smsdvb.c +++ b/drivers/media/dvb/siano/smsdvb.c @@ -60,6 +60,10 @@ struct smsdvb_client_t { static struct list_head g_smsdvb_clients; static struct mutex g_smsdvb_clientslock; +static int sms_dbg; +module_param_named(debug, sms_dbg, int, 0644); +MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); + /* Events that may come from DVB v3 adapter */ static void sms_board_dvb3_event(struct smsdvb_client_t *client, enum SMS_DVB3_EVENTS event) { diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c index f8dca55..0c8164a 100644 --- a/drivers/media/dvb/siano/smsusb.c +++ b/drivers/media/dvb/siano/smsusb.c @@ -29,6 +29,10 @@ along with this program. If not, see . #include "sms-cards.h" #include "smsendian.h" +static int sms_dbg; +module_param_named(debug, sms_dbg, int, 0644); +MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); + #define USB1_BUFFER_SIZE 0x1000 #define USB2_BUFFER_SIZE 0x4000 -- cgit v0.10.2 From 446b792c6bd87de4565ba200b75a708b4c575a06 Mon Sep 17 00:00:00 2001 From: Jonghun Han Date: Mon, 26 Sep 2011 01:14:04 -0300 Subject: [media] media: DocBook: Fix trivial typo in Sub-device Interface When satisfied with the try results, applications can set the active formats by setting the which argument to V4L2_SUBDEV_FORMAT_ACTIVE not V4L2_SUBDEV_FORMAT_TRY. Signed-off-by: Jonghun Han Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media/v4l/dev-subdev.xml b/Documentation/DocBook/media/v4l/dev-subdev.xml index 05c8fef..0916a73 100644 --- a/Documentation/DocBook/media/v4l/dev-subdev.xml +++ b/Documentation/DocBook/media/v4l/dev-subdev.xml @@ -266,7 +266,7 @@ When satisfied with the try results, applications can set the active formats by setting the which argument to - V4L2_SUBDEV_FORMAT_TRY. Active formats are changed + V4L2_SUBDEV_FORMAT_ACTIVE. Active formats are changed exactly as try formats by drivers. To avoid modifying the hardware state during format negotiation, applications should negotiate try formats first and then modify the active settings using the try formats returned during -- cgit v0.10.2 From 4c4364e022f8422e602edbb97a2d873dc0b6c769 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 29 Sep 2011 02:09:42 -0300 Subject: [media] mxl111sf: fix a couple precedence bugs Negate has higher precedence than bitwise AND. I2C_M_RD is 0x1 so the original code is equivelent to just checking if (!msg->flags). Signed-off-by: Dan Carpenter Cc: Steven Toth Cc: Michael Krufky Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-i2c.c b/drivers/media/dvb/dvb-usb/mxl111sf-i2c.c index a330987..2e8c288 100644 --- a/drivers/media/dvb/dvb-usb/mxl111sf-i2c.c +++ b/drivers/media/dvb/dvb-usb/mxl111sf-i2c.c @@ -453,7 +453,7 @@ static int mxl111sf_i2c_hw_xfer_msg(struct mxl111sf_state *state, mxl_i2c("addr: 0x%02x, read buff len: %d, write buff len: %d", msg->addr, (msg->flags & I2C_M_RD) ? msg->len : 0, - (!msg->flags & I2C_M_RD) ? msg->len : 0); + (!(msg->flags & I2C_M_RD)) ? msg->len : 0); for (index = 0; index < 26; index++) buf[index] = USB_END_I2C_CMD; @@ -489,7 +489,7 @@ static int mxl111sf_i2c_hw_xfer_msg(struct mxl111sf_state *state, ret = mxl111sf_i2c_send_data(state, 0, buf); /* write data on I2C bus */ - if ((!msg->flags & I2C_M_RD) && (msg->len > 0)) { + if (!(msg->flags & I2C_M_RD) && (msg->len > 0)) { mxl_i2c("%d\t%02x", msg->len, msg->buf[0]); /* control register on I2C interface to initialize I2C bus */ -- cgit v0.10.2 From 2f4cf2c3a971c4d5154def8ef9ce4811d702852d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 29 Sep 2011 02:10:06 -0300 Subject: [media] dib9000: release a lock on error This lock should be released as well on the error path. Signed-off-by: Dan Carpenter Cc: Patrick Boettcher Cc: Olivier Grenie Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/frontends/dib9000.c b/drivers/media/dvb/frontends/dib9000.c index e276b11..660f806 100644 --- a/drivers/media/dvb/frontends/dib9000.c +++ b/drivers/media/dvb/frontends/dib9000.c @@ -2169,6 +2169,7 @@ static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber) DibAcquireLock(&state->demod_lock); DibAcquireLock(&state->platform.risc.mem_mbx_lock); if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { + DibReleaseLock(&state->platform.risc.mem_mbx_lock); ret = -EIO; goto error; } -- cgit v0.10.2 From b728666ba5244505a80d1e395194e4b90386d504 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 3 Oct 2011 12:01:22 -0300 Subject: [media] saa7115: Fix standards detection There are several bugs at saa7115 standards detection: After the fix, the driver is returning the proper standards, as tested with 3 different broadcast sources: On an invalid channel (without any TV signal): [ 4394.931630] saa7115 15-0021: Status byte 2 (0x1f)=0xe0 [ 4394.931635] saa7115 15-0021: detected std mask = 00ffffff With a PAL/M signal: [ 4410.836855] saa7115 15-0021: Status byte 2 (0x1f)=0xb1 [ 4410.837727] saa7115 15-0021: Status byte 1 (0x1e)=0x82 [ 4410.837731] saa7115 15-0021: detected std mask = 00000900 With a NTSC/M signal: [ 4422.383893] saa7115 15-0021: Status byte 2 (0x1f)=0xb1 [ 4422.384768] saa7115 15-0021: Status byte 1 (0x1e)=0x81 [ 4422.384772] saa7115 15-0021: detected std mask = 0000b000 Tests were done with a WinTV PVR USB2 Model 29xx card. Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index cee98ea..86627a8 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -1344,35 +1344,52 @@ static int saa711x_g_vbi_data(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_dat static int saa711x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) { struct saa711x_state *state = to_state(sd); - int reg1e; + int reg1f, reg1e; - *std = V4L2_STD_ALL; - if (state->ident != V4L2_IDENT_SAA7115) { - int reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC); - - if (reg1f & 0x20) - *std = V4L2_STD_525_60; - else - *std = V4L2_STD_625_50; - - return 0; + reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC); + v4l2_dbg(1, debug, sd, "Status byte 2 (0x1f)=0x%02x\n", reg1f); + if (reg1f & 0x40) { + /* horizontal/vertical not locked */ + *std = V4L2_STD_ALL; + goto ret; } + if (reg1f & 0x20) + *std = V4L2_STD_525_60; + else + *std = V4L2_STD_625_50; + + if (state->ident != V4L2_IDENT_SAA7115) + goto ret; reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC); switch (reg1e & 0x03) { case 1: - *std = V4L2_STD_NTSC; + *std &= V4L2_STD_NTSC; break; case 2: - *std = V4L2_STD_PAL; + /* + * V4L2_STD_PAL just cover the european PAL standards. + * This is wrong, as the device could also be using an + * other PAL standard. + */ + *std &= V4L2_STD_PAL | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc | + V4L2_STD_PAL_M | V4L2_STD_PAL_60; break; case 3: - *std = V4L2_STD_SECAM; + *std &= V4L2_STD_SECAM; break; default: + /* Can't detect anything */ + *std = V4L2_STD_ALL; break; } + + v4l2_dbg(1, debug, sd, "Status byte 1 (0x1e)=0x%02x\n", reg1e); + +ret: + v4l2_dbg(1, debug, sd, "detected std mask = %08Lx\n", *std); + return 0; } -- cgit v0.10.2 From 7383a47395fd5c5ae564b754ca14f6ae25dedecd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 3 Oct 2011 12:22:28 -0300 Subject: [media] pvrusb2: implement VIDIOC_QUERYSTD Acked-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index e98d382..5a6f24d 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -2993,6 +2993,13 @@ static void pvr2_subdev_set_control(struct pvr2_hdw *hdw, int id, pvr2_subdev_set_control(hdw, id, #lab, (hdw)->lab##_val); \ } +int pvr2_hdw_get_detected_std(struct pvr2_hdw *hdw, v4l2_std_id *std) +{ + v4l2_device_call_all(&hdw->v4l2_dev, 0, + video, querystd, std); + return 0; +} + /* Execute whatever commands are required to update the state of all the sub-devices so that they match our current control values. */ static void pvr2_subdev_update(struct pvr2_hdw *hdw) diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h index d7753ae..6654658 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h @@ -214,6 +214,9 @@ struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *); int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw,struct v4l2_standard *std, unsigned int idx); +/* Get the detected video standard */ +int pvr2_hdw_get_detected_std(struct pvr2_hdw *hdw, v4l2_std_id *std); + /* Enable / disable retrieval of CPU firmware or prom contents. This must be enabled before pvr2_hdw_cpufw_get() will function. Note that doing this may prevent the device from running (and leaving this mode may diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index e27f8ab..0d029da 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -227,6 +227,13 @@ static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) break; } + case VIDIOC_QUERYSTD: + { + v4l2_std_id *std = arg; + ret = pvr2_hdw_get_detected_std(hdw, std); + break; + } + case VIDIOC_G_STD: { int val = 0; -- cgit v0.10.2 From 8715e6cbae2ec8b451920496a73786402a5d879d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 4 Oct 2011 09:32:23 -0300 Subject: [media] v4l2-ioctl: Fill the default value for VIDIOC_QUERYSTD According with the V4L2 API spec: "When detection is not possible or fails, the set must contain all standards supported by the current video input or output." The V4L2 core has the mask with all supported standards already. So, apply it. Driver and subdevs can then just remove standards from the mask, as they're able of detecting audio, video and frames frequency. Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index 21c49dc..24fd433 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -1109,6 +1109,14 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_querystd) break; + /* + * If nothing detected, it should return all supported + * Drivers just need to mask the std argument, in order + * to remove the standards that don't apply from the mask. + * This means that tuners, audio and video decoders can join + * their efforts to improve the standards detection + */ + *p = vfd->tvnorms; ret = ops->vidioc_querystd(file, fh, arg); if (!ret) dbgarg(cmd, "detected std=%08Lx\n", -- cgit v0.10.2 From e41567a61dff8f63ad7b56a325bd4d2350428999 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 4 Oct 2011 09:40:18 -0300 Subject: [media] saa7115: Trust that V4L2 core will fill the mask Instead of using V4L2_STD_ALL when no standard is detected, trust that the maximum allowed standards are already filled by the V4L2 core. It is better this way, as the bridge and/or the audio decoder may have some extra restrictions to some video standards. This also allow other devices like audio and tuners to contribute to standards detection, when they support such feature. Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index 86627a8..5cfdbc7 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -1346,17 +1346,23 @@ static int saa711x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) struct saa711x_state *state = to_state(sd); int reg1f, reg1e; + /* + * The V4L2 core already initializes std with all supported + * Standards. All driver needs to do is to mask it, to remove + * standards that don't apply from the mask + */ + reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC); v4l2_dbg(1, debug, sd, "Status byte 2 (0x1f)=0x%02x\n", reg1f); - if (reg1f & 0x40) { - /* horizontal/vertical not locked */ - *std = V4L2_STD_ALL; + + /* horizontal/vertical not locked */ + if (reg1f & 0x40) goto ret; - } + if (reg1f & 0x20) - *std = V4L2_STD_525_60; + *std &= V4L2_STD_525_60; else - *std = V4L2_STD_625_50; + *std &= V4L2_STD_625_50; if (state->ident != V4L2_IDENT_SAA7115) goto ret; @@ -1381,7 +1387,6 @@ static int saa711x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) break; default: /* Can't detect anything */ - *std = V4L2_STD_ALL; break; } -- cgit v0.10.2 From a5abdb6044f558bd5da24f122d7d622f887562c7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 4 Oct 2011 14:16:14 -0300 Subject: [media] pvrusb2: initialize standards mask before detecting standard Acked-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 0d029da..ce7ac45 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -230,6 +230,7 @@ static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_QUERYSTD: { v4l2_std_id *std = arg; + *std = V4L2_STD_ALL; ret = pvr2_hdw_get_detected_std(hdw, std); break; } -- cgit v0.10.2 From 8d6c0b216fd9a7f4b34aca6bd822756b9ef5690b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 4 Oct 2011 16:33:14 -0300 Subject: [media] videodev2: Reorganize standard macros and add a few more macros Reorganize the standards macro and add a few more, that will be used on msp3400 in order to allow it to detect the audio standard. Signed-off-by: Mauro Carvalho Chehab diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 9d14523..225560c 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -759,10 +759,10 @@ typedef __u64 v4l2_std_id; #define V4L2_STD_PAL_Nc ((v4l2_std_id)0x00000400) #define V4L2_STD_PAL_60 ((v4l2_std_id)0x00000800) -#define V4L2_STD_NTSC_M ((v4l2_std_id)0x00001000) -#define V4L2_STD_NTSC_M_JP ((v4l2_std_id)0x00002000) +#define V4L2_STD_NTSC_M ((v4l2_std_id)0x00001000) /* BTSC */ +#define V4L2_STD_NTSC_M_JP ((v4l2_std_id)0x00002000) /* EIA-J */ #define V4L2_STD_NTSC_443 ((v4l2_std_id)0x00004000) -#define V4L2_STD_NTSC_M_KR ((v4l2_std_id)0x00008000) +#define V4L2_STD_NTSC_M_KR ((v4l2_std_id)0x00008000) /* FM A2 */ #define V4L2_STD_SECAM_B ((v4l2_std_id)0x00010000) #define V4L2_STD_SECAM_D ((v4l2_std_id)0x00020000) @@ -786,47 +786,86 @@ typedef __u64 v4l2_std_id; v4l2-common.c should be fixed. */ -/* some merged standards */ -#define V4L2_STD_MN (V4L2_STD_PAL_M|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|V4L2_STD_NTSC) -#define V4L2_STD_B (V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_SECAM_B) -#define V4L2_STD_GH (V4L2_STD_PAL_G|V4L2_STD_PAL_H|V4L2_STD_SECAM_G|V4L2_STD_SECAM_H) -#define V4L2_STD_DK (V4L2_STD_PAL_DK|V4L2_STD_SECAM_DK) +/* + * Some macros to merge video standards in order to make live easier for the + * drivers and V4L2 applications + */ -/* some common needed stuff */ -#define V4L2_STD_PAL_BG (V4L2_STD_PAL_B |\ - V4L2_STD_PAL_B1 |\ - V4L2_STD_PAL_G) -#define V4L2_STD_PAL_DK (V4L2_STD_PAL_D |\ - V4L2_STD_PAL_D1 |\ - V4L2_STD_PAL_K) -#define V4L2_STD_PAL (V4L2_STD_PAL_BG |\ - V4L2_STD_PAL_DK |\ - V4L2_STD_PAL_H |\ - V4L2_STD_PAL_I) +/* + * "Common" NTSC/M - It should be noticed that V4L2_STD_NTSC_443 is + * Missing here. + */ #define V4L2_STD_NTSC (V4L2_STD_NTSC_M |\ V4L2_STD_NTSC_M_JP |\ V4L2_STD_NTSC_M_KR) +/* Secam macros */ #define V4L2_STD_SECAM_DK (V4L2_STD_SECAM_D |\ V4L2_STD_SECAM_K |\ V4L2_STD_SECAM_K1) +/* All Secam Standards */ #define V4L2_STD_SECAM (V4L2_STD_SECAM_B |\ V4L2_STD_SECAM_G |\ V4L2_STD_SECAM_H |\ V4L2_STD_SECAM_DK |\ V4L2_STD_SECAM_L |\ V4L2_STD_SECAM_LC) +/* PAL macros */ +#define V4L2_STD_PAL_BG (V4L2_STD_PAL_B |\ + V4L2_STD_PAL_B1 |\ + V4L2_STD_PAL_G) +#define V4L2_STD_PAL_DK (V4L2_STD_PAL_D |\ + V4L2_STD_PAL_D1 |\ + V4L2_STD_PAL_K) +/* + * "Common" PAL - This macro is there to be compatible with the old + * V4L1 concept of "PAL": /BGDKHI. + * Several PAL standards are mising here: /M, /N and /Nc + */ +#define V4L2_STD_PAL (V4L2_STD_PAL_BG |\ + V4L2_STD_PAL_DK |\ + V4L2_STD_PAL_H |\ + V4L2_STD_PAL_I) +/* Chroma "agnostic" standards */ +#define V4L2_STD_B (V4L2_STD_PAL_B |\ + V4L2_STD_PAL_B1 |\ + V4L2_STD_SECAM_B) +#define V4L2_STD_G (V4L2_STD_PAL_G |\ + V4L2_STD_SECAM_G) +#define V4L2_STD_H (V4L2_STD_PAL_H |\ + V4L2_STD_SECAM_H) +#define V4L2_STD_L (V4L2_STD_SECAM_L |\ + V4L2_STD_SECAM_LC) +#define V4L2_STD_GH (V4L2_STD_G |\ + V4L2_STD_H) +#define V4L2_STD_DK (V4L2_STD_PAL_DK |\ + V4L2_STD_SECAM_DK) +#define V4L2_STD_BG (V4L2_STD_B |\ + V4L2_STD_G) +#define V4L2_STD_MN (V4L2_STD_PAL_M |\ + V4L2_STD_PAL_N |\ + V4L2_STD_PAL_Nc |\ + V4L2_STD_NTSC) +/* Standards where MTS/BTSC stereo could be found */ +#define V4L2_STD_MTS (V4L2_STD_NTSC_M |\ + V4L2_STD_PAL_M |\ + V4L2_STD_PAL_N |\ + V4L2_STD_PAL_Nc) + +/* Standards for Countries with 60Hz Line frequency */ #define V4L2_STD_525_60 (V4L2_STD_PAL_M |\ V4L2_STD_PAL_60 |\ V4L2_STD_NTSC |\ V4L2_STD_NTSC_443) +/* Standards for Countries with 50Hz Line frequency */ #define V4L2_STD_625_50 (V4L2_STD_PAL |\ V4L2_STD_PAL_N |\ V4L2_STD_PAL_Nc |\ V4L2_STD_SECAM) + #define V4L2_STD_ATSC (V4L2_STD_ATSC_8_VSB |\ V4L2_STD_ATSC_16_VSB) - +/* Macros with none and all analog standards */ #define V4L2_STD_UNKNOWN 0 #define V4L2_STD_ALL (V4L2_STD_525_60 |\ V4L2_STD_625_50) -- cgit v0.10.2 From 5d1ed98683abafef595b8e3a237f845b82152606 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 4 Oct 2011 09:44:02 -0300 Subject: [media] msp3400: Add standards detection to the driver As msp3400 allows standards detection, add support for it. That efectivelly means that devices with msp3400 can now implement VIDIOC_QUERYSTD, and it will provide very good detection for the standard, specially if combined with a video decoder detection. Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index c43c81f..d0f5388 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -426,6 +426,20 @@ static int msp_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) return 0; } +static int msp_querystd(struct v4l2_subdev *sd, v4l2_std_id *id) +{ + struct msp_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + *id &= state->detected_std; + + v4l_dbg(2, msp_debug, client, + "detected standard: %s(0x%08Lx)\n", + msp_standard_std_name(state->std), state->detected_std); + + return 0; +} + static int msp_s_std(struct v4l2_subdev *sd, v4l2_std_id id) { struct msp_state *state = to_state(sd); @@ -616,6 +630,10 @@ static const struct v4l2_subdev_core_ops msp_core_ops = { .s_std = msp_s_std, }; +static const struct v4l2_subdev_video_ops msp_video_ops = { + .querystd = msp_querystd, +}; + static const struct v4l2_subdev_tuner_ops msp_tuner_ops = { .s_frequency = msp_s_frequency, .g_tuner = msp_g_tuner, @@ -630,6 +648,7 @@ static const struct v4l2_subdev_audio_ops msp_audio_ops = { static const struct v4l2_subdev_ops msp_ops = { .core = &msp_core_ops, + .video = &msp_video_ops, .tuner = &msp_tuner_ops, .audio = &msp_audio_ops, }; @@ -664,6 +683,7 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) v4l2_i2c_subdev_init(sd, client, &msp_ops); state->v4l2_std = V4L2_STD_NTSC; + state->detected_std = V4L2_STD_ALL; state->audmode = V4L2_TUNER_MODE_STEREO; state->input = -1; state->i2s_mode = 0; diff --git a/drivers/media/video/msp3400-driver.h b/drivers/media/video/msp3400-driver.h index 32a478e..831e8db 100644 --- a/drivers/media/video/msp3400-driver.h +++ b/drivers/media/video/msp3400-driver.h @@ -75,7 +75,7 @@ struct msp_state { int opmode; int std; int mode; - v4l2_std_id v4l2_std; + v4l2_std_id v4l2_std, detected_std; int nicam_on; int acb; int in_scart; diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c index 80387e2..f8b5171 100644 --- a/drivers/media/video/msp3400-kthreads.c +++ b/drivers/media/video/msp3400-kthreads.c @@ -37,29 +37,49 @@ static struct { int retval; int main, second; char *name; + v4l2_std_id std; } msp_stdlist[] = { - { 0x0000, 0, 0, "could not detect sound standard" }, - { 0x0001, 0, 0, "autodetect start" }, - { 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72), "4.5/4.72 M Dual FM-Stereo" }, - { 0x0003, MSP_CARRIER(5.5), MSP_CARRIER(5.7421875), "5.5/5.74 B/G Dual FM-Stereo" }, - { 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25 D/K1 Dual FM-Stereo" }, - { 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), "6.5/6.74 D/K2 Dual FM-Stereo" }, - { 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 D/K FM-Mono (HDEV3)" }, - { 0x0007, MSP_CARRIER(6.5), MSP_CARRIER(5.7421875), "6.5/5.74 D/K3 Dual FM-Stereo" }, - { 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85 B/G NICAM FM" }, - { 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 L NICAM AM" }, - { 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55 I NICAM FM" }, - { 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM" }, - { 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM (HDEV2)" }, - { 0x000d, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM (HDEV3)" }, - { 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Stereo" }, - { 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Mono + SAP" }, - { 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M EIA-J Japan Stereo" }, - { 0x0040, MSP_CARRIER(10.7), MSP_CARRIER(10.7), "10.7 FM-Stereo Radio" }, - { 0x0050, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 SAT-Mono" }, - { 0x0051, MSP_CARRIER(7.02), MSP_CARRIER(7.20), "7.02/7.20 SAT-Stereo" }, - { 0x0060, MSP_CARRIER(7.2), MSP_CARRIER(7.2), "7.2 SAT ADR" }, - { -1, 0, 0, NULL }, /* EOF */ + { 0x0000, 0, 0, "could not detect sound standard", V4L2_STD_ALL }, + { 0x0001, 0, 0, "autodetect start", V4L2_STD_ALL }, + { 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72), + "4.5/4.72 M Dual FM-Stereo", V4L2_STD_MN }, + { 0x0003, MSP_CARRIER(5.5), MSP_CARRIER(5.7421875), + "5.5/5.74 B/G Dual FM-Stereo", V4L2_STD_BG }, + { 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), + "6.5/6.25 D/K1 Dual FM-Stereo", V4L2_STD_DK }, + { 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), + "6.5/6.74 D/K2 Dual FM-Stereo", V4L2_STD_DK }, + { 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), + "6.5 D/K FM-Mono (HDEV3)", V4L2_STD_DK }, + { 0x0007, MSP_CARRIER(6.5), MSP_CARRIER(5.7421875), + "6.5/5.74 D/K3 Dual FM-Stereo", V4L2_STD_DK }, + { 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), + "5.5/5.85 B/G NICAM FM", V4L2_STD_BG }, + { 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), + "6.5/5.85 L NICAM AM", V4L2_STD_L }, + { 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), + "6.0/6.55 I NICAM FM", V4L2_STD_PAL_I }, + { 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), + "6.5/5.85 D/K NICAM FM", V4L2_STD_DK }, + { 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), + "6.5/5.85 D/K NICAM FM (HDEV2)", V4L2_STD_DK }, + { 0x000d, MSP_CARRIER(6.5), MSP_CARRIER(5.85), + "6.5/5.85 D/K NICAM FM (HDEV3)", V4L2_STD_DK }, + { 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), + "4.5 M BTSC-Stereo", V4L2_STD_MTS }, + { 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), + "4.5 M BTSC-Mono + SAP", V4L2_STD_MTS }, + { 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), + "4.5 M EIA-J Japan Stereo", V4L2_STD_NTSC_M_JP }, + { 0x0040, MSP_CARRIER(10.7), MSP_CARRIER(10.7), + "10.7 FM-Stereo Radio", V4L2_STD_ALL }, + { 0x0050, MSP_CARRIER(6.5), MSP_CARRIER(6.5), + "6.5 SAT-Mono", V4L2_STD_ALL }, + { 0x0051, MSP_CARRIER(7.02), MSP_CARRIER(7.20), + "7.02/7.20 SAT-Stereo", V4L2_STD_ALL }, + { 0x0060, MSP_CARRIER(7.2), MSP_CARRIER(7.2), + "7.2 SAT ADR", V4L2_STD_ALL }, + { -1, 0, 0, NULL, 0 }, /* EOF */ }; static struct msp3400c_init_data_dem { @@ -156,6 +176,16 @@ const char *msp_standard_std_name(int std) return "unknown"; } +static v4l2_std_id msp_standard_std(int std) +{ + int i; + + for (i = 0; msp_stdlist[i].name != NULL; i++) + if (msp_stdlist[i].retval == std) + return msp_stdlist[i].std; + return V4L2_STD_ALL; +} + static void msp_set_source(struct i2c_client *client, u16 src) { struct msp_state *state = to_state(i2c_get_clientdata(client)); @@ -479,6 +509,7 @@ int msp3400c_thread(void *data) int count, max1, max2, val1, val2, val, i; v4l_dbg(1, msp_debug, client, "msp3400 daemon started\n"); + state->detected_std = V4L2_STD_ALL; set_freezable(); for (;;) { v4l_dbg(2, msp_debug, client, "msp3400 thread: sleep\n"); @@ -579,6 +610,7 @@ restart: state->main = msp3400c_carrier_detect_main[max1].cdo; switch (max1) { case 1: /* 5.5 */ + state->detected_std = V4L2_STD_BG | V4L2_STD_PAL_H; if (max2 == 0) { /* B/G FM-stereo */ state->second = msp3400c_carrier_detect_55[max2].cdo; @@ -596,6 +628,7 @@ restart: break; case 2: /* 6.0 */ /* PAL I NICAM */ + state->detected_std = V4L2_STD_PAL_I; state->second = MSP_CARRIER(6.552); msp3400c_set_mode(client, MSP_MODE_FM_NICAM2); state->nicam_on = 1; @@ -607,22 +640,26 @@ restart: state->second = msp3400c_carrier_detect_65[max2].cdo; msp3400c_set_mode(client, MSP_MODE_FM_TERRA); state->watch_stereo = 1; + state->detected_std = V4L2_STD_DK; } else if (max2 == 0 && (state->v4l2_std & V4L2_STD_SECAM)) { /* L NICAM or AM-mono */ state->second = msp3400c_carrier_detect_65[max2].cdo; msp3400c_set_mode(client, MSP_MODE_AM_NICAM); state->watch_stereo = 1; + state->detected_std = V4L2_STD_L; } else if (max2 == 0 && state->has_nicam) { /* D/K NICAM */ state->second = msp3400c_carrier_detect_65[max2].cdo; msp3400c_set_mode(client, MSP_MODE_FM_NICAM1); state->nicam_on = 1; state->watch_stereo = 1; + state->detected_std = V4L2_STD_DK; } else { goto no_second; } break; case 0: /* 4.5 */ + state->detected_std = V4L2_STD_MN; default: no_second: state->second = msp3400c_carrier_detect_main[max1].cdo; @@ -662,6 +699,7 @@ int msp3410d_thread(void *data) int val, i, std, count; v4l_dbg(1, msp_debug, client, "msp3410 daemon started\n"); + state->detected_std = V4L2_STD_ALL; set_freezable(); for (;;) { v4l_dbg(2, msp_debug, client, "msp3410 thread: sleep\n"); @@ -743,6 +781,8 @@ restart: msp_stdlist[8].name : "unknown", val); state->std = val = 0x0009; msp_write_dem(client, 0x20, val); + } else { + state->detected_std = msp_standard_std(state->std); } /* set stereo */ @@ -957,6 +997,7 @@ int msp34xxg_thread(void *data) int val, i; v4l_dbg(1, msp_debug, client, "msp34xxg daemon started\n"); + state->detected_std = V4L2_STD_ALL; set_freezable(); for (;;) { v4l_dbg(2, msp_debug, client, "msp34xxg thread: sleep\n"); @@ -1013,6 +1054,7 @@ unmute: v4l_dbg(1, msp_debug, client, "detected standard: %s (0x%04x)\n", msp_standard_std_name(state->std), state->std); + state->detected_std = msp_standard_std(state->std); if (state->std == 9) { /* AM NICAM mode */ -- cgit v0.10.2 From d56ae6fbf33ddeb7ab2ffac896229ca473a7457f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 4 Oct 2011 09:53:00 -0300 Subject: [media] em28xx: Add VIDIOC_QUERYSTD support Allow subdevs to return the detected standards Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 61f35c8..62182e3 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -1156,6 +1156,21 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm) return 0; } +static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *norm) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + v4l2_device_call_all(&dev->v4l2_dev, 0, video, querystd, norm); + + return 0; +} + static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) { struct em28xx_fh *fh = priv; @@ -2354,6 +2369,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_qbuf = vidioc_qbuf, .vidioc_dqbuf = vidioc_dqbuf, .vidioc_g_std = vidioc_g_std, + .vidioc_querystd = vidioc_querystd, .vidioc_s_std = vidioc_s_std, .vidioc_g_parm = vidioc_g_parm, .vidioc_s_parm = vidioc_s_parm, -- cgit v0.10.2 From 86caf8113800cf4e4eedbeac222f3daa0fb146b5 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Fri, 30 Sep 2011 17:34:51 -0300 Subject: [media] drivers/media: fix dependencies in video mt9t001/mt9p031 Both mt9t001.c and mt9p031.c have two identical issues, those being that they will need module.h inclusion for the upcoming cleanup going on there, and that their dependencies don't limit selection of configs that will fail to compile as follows: The related config options are CONFIG_MEDIA_CONTROLLER and CONFIG_VIDEO_V4L2_SUBDEV_API. Looking at the code, it appears that the driver was never intended to work without these enabled, so add a dependency on CONFIG_VIDEO_V4L2_SUBDEV_API, which in turn already has a dependency on CONFIG_MEDIA_CONTROLLER. Reported-by: Randy Dunlap Signed-off-by: Paul Gortmaker Acked-by: Randy Dunlap Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index aed5b3d..b80bea2 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -469,14 +469,14 @@ config VIDEO_OV7670 config VIDEO_MT9P031 tristate "Aptina MT9P031 support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API ---help--- This is a Video4Linux2 sensor-level driver for the Aptina (Micron) mt9p031 5 Mpixel camera. config VIDEO_MT9T001 tristate "Aptina MT9T001 support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API ---help--- This is a Video4Linux2 sensor-level driver for the Aptina (Micron) mt0t001 3 Mpixel camera. diff --git a/drivers/media/video/mt9p031.c b/drivers/media/video/mt9p031.c index 5cfa39f..73c0689 100644 --- a/drivers/media/video/mt9p031.c +++ b/drivers/media/video/mt9p031.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include diff --git a/drivers/media/video/mt9t001.c b/drivers/media/video/mt9t001.c index cac1416..08074b8 100644 --- a/drivers/media/video/mt9t001.c +++ b/drivers/media/video/mt9t001.c @@ -13,6 +13,7 @@ */ #include +#include #include #include #include -- cgit v0.10.2 From 64933337e3cb61ca555969a35ab68b477db34ee2 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 30 Sep 2011 20:33:50 -0300 Subject: [media] tvp5150: Add video format registers configuration values The tvp5150 video decoder has two operation modes to configure the video standard used. If auto-switch mode is enable, the device can sense the signal and detect which video standard the device is operating. Also the device can be forced to use a user defined video standard. Each operation mode uses a different register and the bitmask values to represent each standard is different. So we add video standard constants for both autoswitch and no-autoswitch mode. Signed-off-by: Javier Martinez Canillas Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/tvp5150_reg.h b/drivers/media/video/tvp5150_reg.h index 4240043..25a9949 100644 --- a/drivers/media/video/tvp5150_reg.h +++ b/drivers/media/video/tvp5150_reg.h @@ -45,7 +45,22 @@ /* Reserved 1Fh-27h */ -#define TVP5150_VIDEO_STD 0x28 /* Video standard */ +#define VIDEO_STD_MASK (0x07 >> 1) +#define TVP5150_VIDEO_STD 0x28 /* Video standard */ +#define VIDEO_STD_AUTO_SWITCH_BIT 0x00 +#define VIDEO_STD_NTSC_MJ_BIT 0x02 +#define VIDEO_STD_PAL_BDGHIN_BIT 0x04 +#define VIDEO_STD_PAL_M_BIT 0x06 +#define VIDEO_STD_PAL_COMBINATION_N_BIT 0x08 +#define VIDEO_STD_NTSC_4_43_BIT 0x0a +#define VIDEO_STD_SECAM_BIT 0x0c + +#define VIDEO_STD_NTSC_MJ_BIT_AS 0x01 +#define VIDEO_STD_PAL_BDGHIN_BIT_AS 0x03 +#define VIDEO_STD_PAL_M_BIT_AS 0x05 +#define VIDEO_STD_PAL_COMBINATION_N_BIT_AS 0x07 +#define VIDEO_STD_NTSC_4_43_BIT_AS 0x09 +#define VIDEO_STD_SECAM_BIT_AS 0x0b /* Reserved 29h-2bh */ -- cgit v0.10.2 From e30528854797f057aa6ffb6dc9f890e923c467fd Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Sat, 1 Oct 2011 09:24:16 -0300 Subject: [media] it913x-fe changes to power up and down of tuner Currently the tuner is constantly powered causing these effects. 1. Remembering last tune channel causing corruptions of changing channel. 2. Causing corruption on other frontend. 3. Higher current in standby of demodulator with clock running. Power sequence now follows; Power Up Tuner on -> Frontend suspend off -> Tuner clk on Power Down Frontend suspend on -> Tuner clk off -> Tuner off Signed-off-by: Malcolm Priestley Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/frontends/it913x-fe-priv.h b/drivers/media/dvb/frontends/it913x-fe-priv.h index 40e1d9b..1c6fb4b 100644 --- a/drivers/media/dvb/frontends/it913x-fe-priv.h +++ b/drivers/media/dvb/frontends/it913x-fe-priv.h @@ -312,7 +312,15 @@ static struct it913xset it9137_set[] = { {PRO_LINK, GPIOH5_EN, {0x01}, 0x01}, {PRO_LINK, GPIOH5_ON, {0x01}, 0x01}, {PRO_LINK, GPIOH5_O, {0x00}, 0x01}, - {PRO_LINK, GPIOH5_O, {0x01}, 0x01},/* ?, but enable */ + {PRO_LINK, GPIOH5_O, {0x01}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ +}; + +static struct it913xset it9137_tuner_off[] = { + {PRO_DMOD, 0xfba8, {0x01}, 0x01}, /* Tuner Clock Off */ + {PRO_DMOD, 0xec40, {0x00}, 0x01}, /* Power Down Tuner */ + {PRO_DMOD, 0xec02, {0x3f, 0x1f, 0x3f, 0x3f}, 0x04}, + {PRO_DMOD, 0xec3f, {0x01}, 0x01}, {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ }; diff --git a/drivers/media/dvb/frontends/it913x-fe.c b/drivers/media/dvb/frontends/it913x-fe.c index 02839a8b7..d4bd24e 100644 --- a/drivers/media/dvb/frontends/it913x-fe.c +++ b/drivers/media/dvb/frontends/it913x-fe.c @@ -626,7 +626,7 @@ static int it913x_fe_suspend(struct it913x_fe_state *state) for (i = 0; i < 128; i++) { ret = it913x_read_reg(state, SUSPEND_FLAG, &b, 1); if (ret < 0) - return -EINVAL; + return -ENODEV; if (b == 0) break; @@ -634,18 +634,23 @@ static int it913x_fe_suspend(struct it913x_fe_state *state) ret |= it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x8); /* Turn LED off */ - ret = it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x0); + ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x0); - return 0; + ret |= it913x_fe_script_loader(state, it9137_tuner_off); + + return (ret < 0) ? -ENODEV : 0; } +/* Power sequence */ +/* Power Up Tuner on -> Frontend suspend off -> Tuner clk on */ +/* Power Down Frontend suspend on -> Tuner clk off -> Tuner off */ + static int it913x_fe_sleep(struct dvb_frontend *fe) { struct it913x_fe_state *state = fe->demodulator_priv; return it913x_fe_suspend(state); } - static u32 compute_div(u32 a, u32 b, u32 x) { u32 res = 0; @@ -738,11 +743,21 @@ static int it913x_fe_init(struct dvb_frontend *fe) { struct it913x_fe_state *state = fe->demodulator_priv; int ret = 0; + /* Power Up Tuner - common all versions */ + ret = it913x_write_reg(state, PRO_DMOD, 0xec40, 0x1); - it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x0); + ret |= it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x0); ret |= it913x_fe_script_loader(state, init_1); + switch (state->tuner_type) { + case IT9137: + ret |= it913x_write_reg(state, PRO_DMOD, 0xfba8, 0x0); + break; + default: + return -EINVAL; + } + return (ret < 0) ? -ENODEV : 0; } @@ -820,5 +835,5 @@ static struct dvb_frontend_ops it913x_fe_ofdm_ops = { MODULE_DESCRIPTION("it913x Frontend and it9137 tuner"); MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); -MODULE_VERSION("1.06"); +MODULE_VERSION("1.07"); MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 06bd801c23939952bc6e1cf65f0e8c0fff09d2d7 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 6 Oct 2011 02:41:06 -0300 Subject: [media] rc/ir-lirc-codec: cleanup __user tags The code here treated user pointers correctly, but the __user tags weren't used correctly so it caused Sparse warnings: Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index e5eeec4..ec2e67f 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -98,7 +98,7 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) return 0; } -static ssize_t ir_lirc_transmit_ir(struct file *file, const char *buf, +static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, size_t n, loff_t *ppos) { struct lirc_codec *lirc; @@ -140,10 +140,11 @@ out: } static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, - unsigned long __user arg) + unsigned long arg) { struct lirc_codec *lirc; struct rc_dev *dev; + u32 __user *argp = (u32 __user *)(arg); int ret = 0; __u32 val = 0, tmp; @@ -156,7 +157,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, return -EFAULT; if (_IOC_DIR(cmd) & _IOC_WRITE) { - ret = get_user(val, (__u32 *)arg); + ret = get_user(val, argp); if (ret) return ret; } @@ -265,7 +266,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, } if (_IOC_DIR(cmd) & _IOC_READ) - ret = put_user(val, (__u32 *)arg); + ret = put_user(val, argp); return ret; } -- cgit v0.10.2 From 39342dbb27323f174b286c9e19b9687d492b2d1a Mon Sep 17 00:00:00 2001 From: Lutz Sammer Date: Fri, 7 Oct 2011 16:11:37 -0300 Subject: [media] stb0899: Fix slow and not locking DVB-S transponder(s) In stb0899_status stb0899_check_data the first read of STB0899_VSTATUS could read old (from previous search) LOOP status bit and the search fails on a good frequency. With the patch more transponder could be locked and locks about 2* faster. Signed-off-by: Lutz Sammer Reviewed-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/frontends/stb0899_algo.c b/drivers/media/dvb/frontends/stb0899_algo.c index d70eee0..117a569 100644 --- a/drivers/media/dvb/frontends/stb0899_algo.c +++ b/drivers/media/dvb/frontends/stb0899_algo.c @@ -358,6 +358,9 @@ static enum stb0899_status stb0899_check_data(struct stb0899_state *state) else dataTime = 500; + /* clear previous failed END_LOOPVIT */ + stb0899_read_reg(state, STB0899_VSTATUS); + stb0899_write_reg(state, STB0899_DSTATUS2, 0x00); /* force search loop */ while (1) { /* WARNING! VIT LOCKED has to be tested before VIT_END_LOOOP */ -- cgit v0.10.2 From 873c07da6abd5519a7850caa90f226d3b15e3fba Mon Sep 17 00:00:00 2001 From: Renzo Dani Date: Sun, 9 Oct 2011 06:43:50 -0300 Subject: [media] update az6027 firmware URL Signed-off-by: Renzo Dani Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware index 996f578..e67be7a 100755 --- a/Documentation/dvb/get_dvb_firmware +++ b/Documentation/dvb/get_dvb_firmware @@ -576,19 +576,10 @@ sub ngene { } sub az6027{ - my $file = "AZ6027_Linux_Driver.tar.gz"; - my $url = "http://linux.terratec.de/files/$file"; my $firmware = "dvb-usb-az6027-03.fw"; + my $url = "http://linux.terratec.de/files/TERRATEC_S7/$firmware"; - wgetfile($file, $url); - - #untar - if( system("tar xzvf $file $firmware")){ - die "failed to untar firmware"; - } - if( system("rm $file")){ - die ("unable to remove unnecessary files"); - } + wgetfile($firmware, $url); $firmware; } -- cgit v0.10.2 From 9e44d63246a9c884900e56e2aa16fba94dee5f0c Mon Sep 17 00:00:00 2001 From: Mijhail Moreyra Date: Mon, 10 Oct 2011 11:09:52 -0300 Subject: [media] cx23885: Add ALSA support [stoth@kernellabs.com: add it to the makefile and fix snd_card binding] [liplianin@netup.ru: videobuf: Remove the videobuf_sg_dma_map/unmap functions] Signed-off-by: Mijhail Moreyra Signed-off-by: Steven Toth Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile index 185cc01..f81f279 100644 --- a/drivers/media/video/cx23885/Makefile +++ b/drivers/media/video/cx23885/Makefile @@ -2,7 +2,7 @@ cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o \ cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o \ cx23885-ioctl.o cx23885-ir.o cx23885-av.o cx23885-input.o \ cx23888-ir.o netup-init.o cimax2.o netup-eeprom.o \ - cx23885-f300.o + cx23885-f300.o cx23885-alsa.o obj-$(CONFIG_VIDEO_CX23885) += cx23885.o obj-$(CONFIG_MEDIA_ALTERA_CI) += altera-ci.o diff --git a/drivers/media/video/cx23885/cx23885-alsa.c b/drivers/media/video/cx23885/cx23885-alsa.c new file mode 100644 index 0000000..31a89b3 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-alsa.c @@ -0,0 +1,535 @@ +/* + * + * Support for CX23885 analog audio capture + * + * (c) 2008 Mijhail Moreyra + * Adapted from cx88-alsa.c + * (c) 2009 Steven Toth + * + * 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 of the License, 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 +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + + +#include "cx23885.h" +#include "cx23885-reg.h" + +#define AUDIO_SRAM_CHANNEL SRAM_CH07 + +#define dprintk(level, fmt, arg...) if (audio_debug >= level) \ + printk(KERN_INFO "%s/1: " fmt, chip->dev->name , ## arg) + +#define dprintk_core(level, fmt, arg...) if (audio_debug >= level) \ + printk(KERN_DEBUG "%s/1: " fmt, chip->dev->name , ## arg) + +/**************************************************************************** + Module global static vars + ****************************************************************************/ + +static unsigned int disable_analog_audio; +module_param(disable_analog_audio, int, 0644); +MODULE_PARM_DESC(disable_analog_audio, "disable analog audio ALSA driver"); + +static unsigned int audio_debug; +module_param(audio_debug, int, 0644); +MODULE_PARM_DESC(audio_debug, "enable debug messages [analog audio]"); + +/**************************************************************************** + Board specific funtions + ****************************************************************************/ + +/* Constants taken from cx88-reg.h */ +#define AUD_INT_DN_RISCI1 (1 << 0) +#define AUD_INT_UP_RISCI1 (1 << 1) +#define AUD_INT_RDS_DN_RISCI1 (1 << 2) +#define AUD_INT_DN_RISCI2 (1 << 4) /* yes, 3 is skipped */ +#define AUD_INT_UP_RISCI2 (1 << 5) +#define AUD_INT_RDS_DN_RISCI2 (1 << 6) +#define AUD_INT_DN_SYNC (1 << 12) +#define AUD_INT_UP_SYNC (1 << 13) +#define AUD_INT_RDS_DN_SYNC (1 << 14) +#define AUD_INT_OPC_ERR (1 << 16) +#define AUD_INT_BER_IRQ (1 << 20) +#define AUD_INT_MCHG_IRQ (1 << 21) +#define GP_COUNT_CONTROL_RESET 0x3 + +/* + * BOARD Specific: Sets audio DMA + */ + +static int cx23885_start_audio_dma(struct cx23885_audio_dev *chip) +{ + struct cx23885_audio_buffer *buf = chip->buf; + struct cx23885_dev *dev = chip->dev; + struct sram_channel *audio_ch = + &dev->sram_channels[AUDIO_SRAM_CHANNEL]; + + dprintk(1, "%s()\n", __func__); + + /* Make sure RISC/FIFO are off before changing FIFO/RISC settings */ + cx_clear(AUD_INT_DMA_CTL, 0x11); + + /* setup fifo + format - out channel */ + cx23885_sram_channel_setup(chip->dev, audio_ch, buf->bpl, + buf->risc.dma); + + /* sets bpl size */ + cx_write(AUD_INT_A_LNGTH, buf->bpl); + + /* This is required to get good audio (1 seems to be ok) */ + cx_write(AUD_INT_A_MODE, 1); + + /* reset counter */ + cx_write(AUD_INT_A_GPCNT_CTL, GP_COUNT_CONTROL_RESET); + atomic_set(&chip->count, 0); + + dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d periods, %d " + "byte buffer\n", buf->bpl, cx_read(audio_ch->cmds_start+12)>>1, + chip->num_periods, buf->bpl * chip->num_periods); + + /* Enables corresponding bits at AUD_INT_STAT */ + cx_write(AUDIO_INT_INT_MSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC | + AUD_INT_DN_RISCI1); + + /* Clean any pending interrupt bits already set */ + cx_write(AUDIO_INT_INT_STAT, ~0); + + /* enable audio irqs */ + cx_set(PCI_INT_MSK, chip->dev->pci_irqmask | PCI_MSK_AUD_INT); + + /* start dma */ + cx_set(DEV_CNTRL2, (1<<5)); /* Enables Risc Processor */ + cx_set(AUD_INT_DMA_CTL, 0x11); /* audio downstream FIFO and + RISC enable */ + if (audio_debug) + cx23885_sram_channel_dump(chip->dev, audio_ch); + + return 0; +} + +/* + * BOARD Specific: Resets audio DMA + */ +static int cx23885_stop_audio_dma(struct cx23885_audio_dev *chip) +{ + struct cx23885_dev *dev = chip->dev; + dprintk(1, "Stopping audio DMA\n"); + + /* stop dma */ + cx_clear(AUD_INT_DMA_CTL, 0x11); + + /* disable irqs */ + cx_clear(PCI_INT_MSK, PCI_MSK_AUD_INT); + cx_clear(AUDIO_INT_INT_MSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC | + AUD_INT_DN_RISCI1); + + if (audio_debug) + cx23885_sram_channel_dump(chip->dev, + &dev->sram_channels[AUDIO_SRAM_CHANNEL]); + + return 0; +} + +/* + * BOARD Specific: Handles audio IRQ + */ +int cx23885_audio_irq(struct cx23885_dev *dev, u32 status, u32 mask) +{ + struct cx23885_audio_dev *chip = dev->audio_dev; + + if (0 == (status & mask)) + return 0; + + cx_write(AUDIO_INT_INT_STAT, status); + + /* risc op code error */ + if (status & AUD_INT_OPC_ERR) { + printk(KERN_WARNING "%s/1: Audio risc op code error\n", + dev->name); + cx_clear(AUD_INT_DMA_CTL, 0x11); + cx23885_sram_channel_dump(dev, + &dev->sram_channels[AUDIO_SRAM_CHANNEL]); + } + if (status & AUD_INT_DN_SYNC) { + dprintk(1, "Downstream sync error\n"); + cx_write(AUD_INT_A_GPCNT_CTL, GP_COUNT_CONTROL_RESET); + return 1; + } + /* risc1 downstream */ + if (status & AUD_INT_DN_RISCI1) { + atomic_set(&chip->count, cx_read(AUD_INT_A_GPCNT)); + snd_pcm_period_elapsed(chip->substream); + } + /* FIXME: Any other status should deserve a special handling? */ + + return 1; +} + +static int dsp_buffer_free(struct cx23885_audio_dev *chip) +{ + BUG_ON(!chip->dma_size); + + dprintk(2, "Freeing buffer\n"); + videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc); + videobuf_dma_free(chip->dma_risc); + btcx_riscmem_free(chip->pci, &chip->buf->risc); + kfree(chip->buf); + + chip->dma_risc = NULL; + chip->dma_size = 0; + + return 0; +} + +/**************************************************************************** + ALSA PCM Interface + ****************************************************************************/ + +/* + * Digital hardware definition + */ +#define DEFAULT_FIFO_SIZE 4096 + +static struct snd_pcm_hardware snd_cx23885_digital_hw = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + /* Analog audio output will be full of clicks and pops if there + are not exactly four lines in the SRAM FIFO buffer. */ + .period_bytes_min = DEFAULT_FIFO_SIZE/4, + .period_bytes_max = DEFAULT_FIFO_SIZE/4, + .periods_min = 1, + .periods_max = 1024, + .buffer_bytes_max = (1024*1024), +}; + +/* + * audio pcm capture open callback + */ +static int snd_cx23885_pcm_open(struct snd_pcm_substream *substream) +{ + struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + int err; + + if (!chip) { + printk(KERN_ERR "BUG: cx23885 can't find device struct." + " Can't proceed with open\n"); + return -ENODEV; + } + + err = snd_pcm_hw_constraint_pow2(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) + goto _error; + + chip->substream = substream; + + runtime->hw = snd_cx23885_digital_hw; + + if (chip->dev->sram_channels[AUDIO_SRAM_CHANNEL].fifo_size != + DEFAULT_FIFO_SIZE) { + unsigned int bpl = chip->dev-> + sram_channels[AUDIO_SRAM_CHANNEL].fifo_size / 4; + bpl &= ~7; /* must be multiple of 8 */ + runtime->hw.period_bytes_min = bpl; + runtime->hw.period_bytes_max = bpl; + } + + return 0; +_error: + dprintk(1, "Error opening PCM!\n"); + return err; +} + +/* + * audio close callback + */ +static int snd_cx23885_close(struct snd_pcm_substream *substream) +{ + return 0; +} + +/* + * hw_params callback + */ +static int snd_cx23885_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream); + struct videobuf_dmabuf *dma; + + struct cx23885_audio_buffer *buf; + int ret; + + if (substream->runtime->dma_area) { + dsp_buffer_free(chip); + substream->runtime->dma_area = NULL; + } + + chip->period_size = params_period_bytes(hw_params); + chip->num_periods = params_periods(hw_params); + chip->dma_size = chip->period_size * params_periods(hw_params); + + BUG_ON(!chip->dma_size); + BUG_ON(chip->num_periods & (chip->num_periods-1)); + + buf = kzalloc(sizeof(*buf), GFP_KERNEL); + if (NULL == buf) + return -ENOMEM; + + buf->bpl = chip->period_size; + + dma = &buf->dma; + videobuf_dma_init(dma); + ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE, + (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT)); + if (ret < 0) + goto error; + + ret = videobuf_dma_map(&chip->pci->dev, dma); + if (ret < 0) + goto error; + + ret = cx23885_risc_databuffer(chip->pci, &buf->risc, dma->sglist, + chip->period_size, chip->num_periods, 1); + if (ret < 0) + goto error; + + /* Loop back to start of program */ + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ + + chip->buf = buf; + chip->dma_risc = dma; + + substream->runtime->dma_area = chip->dma_risc->vaddr; + substream->runtime->dma_bytes = chip->dma_size; + substream->runtime->dma_addr = 0; + + return 0; + +error: + kfree(buf); + return ret; +} + +/* + * hw free callback + */ +static int snd_cx23885_hw_free(struct snd_pcm_substream *substream) +{ + + struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream); + + if (substream->runtime->dma_area) { + dsp_buffer_free(chip); + substream->runtime->dma_area = NULL; + } + + return 0; +} + +/* + * prepare callback + */ +static int snd_cx23885_prepare(struct snd_pcm_substream *substream) +{ + return 0; +} + +/* + * trigger callback + */ +static int snd_cx23885_card_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream); + int err; + + /* Local interrupts are already disabled by ALSA */ + spin_lock(&chip->lock); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + err = cx23885_start_audio_dma(chip); + break; + case SNDRV_PCM_TRIGGER_STOP: + err = cx23885_stop_audio_dma(chip); + break; + default: + err = -EINVAL; + break; + } + + spin_unlock(&chip->lock); + + return err; +} + +/* + * pointer callback + */ +static snd_pcm_uframes_t snd_cx23885_pointer( + struct snd_pcm_substream *substream) +{ + struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + u16 count; + + count = atomic_read(&chip->count); + + return runtime->period_size * (count & (runtime->periods-1)); +} + +/* + * page callback (needed for mmap) + */ +static struct page *snd_cx23885_page(struct snd_pcm_substream *substream, + unsigned long offset) +{ + void *pageptr = substream->runtime->dma_area + offset; + return vmalloc_to_page(pageptr); +} + +/* + * operators + */ +static struct snd_pcm_ops snd_cx23885_pcm_ops = { + .open = snd_cx23885_pcm_open, + .close = snd_cx23885_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_cx23885_hw_params, + .hw_free = snd_cx23885_hw_free, + .prepare = snd_cx23885_prepare, + .trigger = snd_cx23885_card_trigger, + .pointer = snd_cx23885_pointer, + .page = snd_cx23885_page, +}; + +/* + * create a PCM device + */ +static int snd_cx23885_pcm(struct cx23885_audio_dev *chip, int device, + char *name) +{ + int err; + struct snd_pcm *pcm; + + err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm); + if (err < 0) + return err; + pcm->private_data = chip; + strcpy(pcm->name, name); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cx23885_pcm_ops); + + return 0; +} + +/**************************************************************************** + Basic Flow for Sound Devices + ****************************************************************************/ + +/* + * Alsa Constructor - Component probe + */ + +struct cx23885_audio_dev *cx23885_audio_initdev(struct cx23885_dev *dev) +{ + struct snd_card *card; + struct cx23885_audio_dev *chip; + int err; + + if (disable_analog_audio) + return NULL; + + if (dev->sram_channels[AUDIO_SRAM_CHANNEL].cmds_start == 0) { + printk(KERN_WARNING "%s(): Missing SRAM channel configuration " + "for analog TV Audio\n", __func__); + return NULL; + } + + err = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, + THIS_MODULE, sizeof(struct cx23885_audio_dev), &card); + if (err < 0) + goto error; + + chip = (struct cx23885_audio_dev *) card->private_data; + chip->dev = dev; + chip->pci = dev->pci; + chip->card = card; + spin_lock_init(&chip->lock); + + snd_card_set_dev(card, &dev->pci->dev); + + err = snd_cx23885_pcm(chip, 0, "CX23885 Digital"); + if (err < 0) + goto error; + + strcpy(card->driver, "CX23885"); + sprintf(card->shortname, "Conexant CX23885"); + sprintf(card->longname, "%s at %s", card->shortname, dev->name); + + err = snd_card_register(card); + if (err < 0) + goto error; + + dprintk(0, "registered ALSA audio device\n"); + + return chip; + +error: + snd_card_free(card); + printk(KERN_ERR "%s(): Failed to register analog " + "audio adapter\n", __func__); + + return NULL; +} + +/* + * ALSA destructor + */ +void cx23885_audio_finidev(struct cx23885_dev *dev) +{ + struct cx23885_audio_dev *chip = dev->audio_dev; + + snd_card_free(chip->card); +} diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index ee41a88..d8dfa40 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -156,11 +156,12 @@ static struct sram_channel cx23885_sram_channels[] = { }, [SRAM_CH07] = { .name = "ch7", - .cmds_start = 0x0, - .ctrl_start = 0x0, - .cdt = 0x0, - .fifo_start = 0x0, - .fifo_size = 0x0, + .name = "TV Audio", + .cmds_start = 0x10190, + .ctrl_start = 0x10480, + .cdt = 0x10a00, + .fifo_start = 0x7000, + .fifo_size = 0x1000, .ptr1_reg = DMA6_PTR1, .ptr2_reg = DMA6_PTR2, .cnt1_reg = DMA6_CNT1, @@ -1082,10 +1083,10 @@ static void cx23885_dev_unregister(struct cx23885_dev *dev) static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist, unsigned int offset, u32 sync_line, unsigned int bpl, unsigned int padding, - unsigned int lines) + unsigned int lines, unsigned int lpi) { struct scatterlist *sg; - unsigned int line, todo; + unsigned int line, todo, sol; /* sync instruction */ if (sync_line != NO_SYNC_LINE) @@ -1098,16 +1099,22 @@ static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist, offset -= sg_dma_len(sg); sg++; } + + if (lpi && line > 0 && !(line % lpi)) + sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC; + else + sol = RISC_SOL; + if (bpl <= sg_dma_len(sg)-offset) { /* fits into current chunk */ - *(rp++) = cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl); + *(rp++) = cpu_to_le32(RISC_WRITE|sol|RISC_EOL|bpl); *(rp++) = cpu_to_le32(sg_dma_address(sg)+offset); *(rp++) = cpu_to_le32(0); /* bits 63-32 */ offset += bpl; } else { /* scanline needs to be split */ todo = bpl; - *(rp++) = cpu_to_le32(RISC_WRITE|RISC_SOL| + *(rp++) = cpu_to_le32(RISC_WRITE|sol| (sg_dma_len(sg)-offset)); *(rp++) = cpu_to_le32(sg_dma_address(sg)+offset); *(rp++) = cpu_to_le32(0); /* bits 63-32 */ @@ -1164,10 +1171,10 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, rp = risc->cpu; if (UNSET != top_offset) rp = cx23885_risc_field(rp, sglist, top_offset, 0, - bpl, padding, lines); + bpl, padding, lines, 0); if (UNSET != bottom_offset) rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200, - bpl, padding, lines); + bpl, padding, lines, 0); /* save pointer to jmp instruction address */ risc->jmp = rp; @@ -1175,11 +1182,11 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, return 0; } -static int cx23885_risc_databuffer(struct pci_dev *pci, +int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, struct scatterlist *sglist, unsigned int bpl, - unsigned int lines) + unsigned int lines, unsigned int lpi) { u32 instructions; __le32 *rp; @@ -1199,7 +1206,8 @@ static int cx23885_risc_databuffer(struct pci_dev *pci, /* write risc instructions */ rp = risc->cpu; - rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines); + rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE, + bpl, 0, lines, lpi); /* save pointer to jmp instruction address */ risc->jmp = rp; @@ -1517,7 +1525,7 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, goto fail; cx23885_risc_databuffer(dev->pci, &buf->risc, videobuf_to_dma(&buf->vb)->sglist, - buf->vb.width, buf->vb.height); + buf->vb.width, buf->vb.height, 0); } buf->vb.state = VIDEOBUF_PREPARED; return 0; @@ -1741,15 +1749,19 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) struct cx23885_tsport *ts2 = &dev->ts2; u32 pci_status, pci_mask; u32 vida_status, vida_mask; + u32 audint_status, audint_mask; u32 ts1_status, ts1_mask; u32 ts2_status, ts2_mask; int vida_count = 0, ts1_count = 0, ts2_count = 0, handled = 0; + int audint_count = 0; bool subdev_handled; pci_status = cx_read(PCI_INT_STAT); pci_mask = cx23885_irq_get_mask(dev); vida_status = cx_read(VID_A_INT_STAT); vida_mask = cx_read(VID_A_INT_MSK); + audint_status = cx_read(AUDIO_INT_INT_STAT); + audint_mask = cx_read(AUDIO_INT_INT_MSK); ts1_status = cx_read(VID_B_INT_STAT); ts1_mask = cx_read(VID_B_INT_MSK); ts2_status = cx_read(VID_C_INT_STAT); @@ -1759,12 +1771,15 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) goto out; vida_count = cx_read(VID_A_GPCNT); + audint_count = cx_read(AUD_INT_A_GPCNT); ts1_count = cx_read(ts1->reg_gpcnt); ts2_count = cx_read(ts2->reg_gpcnt); dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n", pci_status, pci_mask); dprintk(7, "vida_status: 0x%08x vida_mask: 0x%08x count: 0x%x\n", vida_status, vida_mask, vida_count); + dprintk(7, "audint_status: 0x%08x audint_mask: 0x%08x count: 0x%x\n", + audint_status, audint_mask, audint_count); dprintk(7, "ts1_status: 0x%08x ts1_mask: 0x%08x count: 0x%x\n", ts1_status, ts1_mask, ts1_count); dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", @@ -1861,6 +1876,9 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) if (vida_status) handled += cx23885_video_irq(dev, vida_status); + if (audint_status) + handled += cx23885_audio_irq(dev, audint_status, audint_mask); + if (pci_status & PCI_MSK_IR) { subdev_handled = false; v4l2_subdev_call(dev->sd_ir, core, interrupt_service_routine, diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index d86bc0b..abeba7a 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -318,6 +318,34 @@ struct cx23885_kernel_ir { struct rc_dev *rc; }; +struct cx23885_audio_buffer { + unsigned int bpl; + struct btcx_riscmem risc; + struct videobuf_dmabuf dma; +}; + +struct cx23885_audio_dev { + struct cx23885_dev *dev; + + struct pci_dev *pci; + + struct snd_card *card; + + spinlock_t lock; + + atomic_t count; + + unsigned int dma_size; + unsigned int period_size; + unsigned int num_periods; + + struct videobuf_dmabuf *dma_risc; + + struct cx23885_audio_buffer *buf; + + struct snd_pcm_substream *substream; +}; + struct cx23885_dev { atomic_t refcount; struct v4l2_device v4l2_dev; @@ -400,6 +428,9 @@ struct cx23885_dev { atomic_t v4l_reader_count; struct cx23885_tvnorm encodernorm; + /* Analog raw audio */ + struct cx23885_audio_dev *audio_dev; + }; static inline struct cx23885_dev *to_cx23885(struct v4l2_device *v4l2_dev) @@ -563,6 +594,17 @@ extern void mc417_gpio_set(struct cx23885_dev *dev, u32 mask); extern void mc417_gpio_clear(struct cx23885_dev *dev, u32 mask); extern void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput); +/* ----------------------------------------------------------- */ +/* cx23885-alsa.c */ +extern struct cx23885_audio_dev *cx23885_audio_initdev(struct cx23885_dev *dev); +extern void cx23885_audio_finidev(struct cx23885_dev *dev); +extern int cx23885_audio_irq(struct cx23885_dev *dev, u32 status, u32 mask); +extern int cx23885_risc_databuffer(struct pci_dev *pci, + struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int bpl, + unsigned int lines, + unsigned int lpi); /* ----------------------------------------------------------- */ /* tv norms */ -- cgit v0.10.2 From 18d644767171a13214b01c7edc62105bdaddd66e Mon Sep 17 00:00:00 2001 From: Mijhail Moreyra Date: Mon, 10 Oct 2011 11:09:53 -0300 Subject: [media] cx23885: add definitions for HVR1500 to support audio Signed-off-by: Mijhail Moreyra Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 62fd25e..75d77c2d 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -153,7 +153,30 @@ struct cx23885_board cx23885_boards[] = { }, [CX23885_BOARD_HAUPPAUGE_HVR1500] = { .name = "Hauppauge WinTV-HVR1500", + .porta = CX23885_ANALOG_VIDEO, .portc = CX23885_MPEG_DVB, + .tuner_type = TUNER_XC2028, + .tuner_addr = 0x61, /* 0xc2 >> 1 */ + .input = {{ + .type = CX23885_VMUX_TELEVISION, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN5_CH2 | + CX25840_VIN2_CH1, + .gpio0 = 0, + }, { + .type = CX23885_VMUX_COMPOSITE1, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN4_CH2 | + CX25840_VIN6_CH1, + .gpio0 = 0, + }, { + .type = CX23885_VMUX_SVIDEO, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN4_CH2 | + CX25840_VIN8_CH1 | + CX25840_SVIDEO_ON, + .gpio0 = 0, + } }, }, [CX23885_BOARD_HAUPPAUGE_HVR1200] = { .name = "Hauppauge WinTV-HVR1200", @@ -1415,6 +1438,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1290: case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200: case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID: + case CX23885_BOARD_HAUPPAUGE_HVR1500: dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_bus[2].i2c_adap, "cx25840", 0x88 >> 1, NULL); -- cgit v0.10.2 From b12ab3f81c1ae129aae5ab0fe538ed0afd0cb7d1 Mon Sep 17 00:00:00 2001 From: Mijhail Moreyra Date: Mon, 10 Oct 2011 11:09:53 -0300 Subject: [media] cx23885: correct the contrast, saturation and hue controls Signed-off-by: Mijhail Moreyra Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 896bb32..0c463f9 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -171,7 +171,7 @@ static struct cx23885_ctrl cx23885_ctls[] = { .id = V4L2_CID_CONTRAST, .name = "Contrast", .minimum = 0, - .maximum = 0xff, + .maximum = 0x7f, .step = 1, .default_value = 0x3f, .type = V4L2_CTRL_TYPE_INTEGER, @@ -184,10 +184,10 @@ static struct cx23885_ctrl cx23885_ctls[] = { .v = { .id = V4L2_CID_HUE, .name = "Hue", - .minimum = 0, - .maximum = 0xff, + .minimum = -127, + .maximum = 128, .step = 1, - .default_value = 0x7f, + .default_value = 0x0, .type = V4L2_CTRL_TYPE_INTEGER, }, .off = 128, @@ -202,9 +202,9 @@ static struct cx23885_ctrl cx23885_ctls[] = { .id = V4L2_CID_SATURATION, .name = "Saturation", .minimum = 0, - .maximum = 0xff, + .maximum = 0x7f, .step = 1, - .default_value = 0x7f, + .default_value = 0x3f, .type = V4L2_CTRL_TYPE_INTEGER, }, .off = 0, -- cgit v0.10.2 From 97ce5670fcee40b37f75d227ed88dcc51af63140 Mon Sep 17 00:00:00 2001 From: Mijhail Moreyra Date: Mon, 10 Oct 2011 11:09:53 -0300 Subject: [media] cx23885: hooks the alsa changes into the video subsystem Signed-off-by: Mijhail Moreyra Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 0c463f9..acd6e0c 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -37,6 +37,8 @@ #include "cx23885-ioctl.h" #include "tuner-xc2028.h" +#include + MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards"); MODULE_AUTHOR("Steven Toth "); MODULE_LICENSE("GPL"); @@ -884,8 +886,9 @@ static int cx23885_get_control(struct cx23885_dev *dev, static int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl) { - dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)" - " (disabled - no action)\n", __func__); + dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)\n", __func__); + call_all(dev, core, s_ctrl, ctl); + return 0; } @@ -1220,11 +1223,9 @@ static int vidioc_g_tuner(struct file *file, void *priv, if (0 != t->index) return -EINVAL; + memset(t, 0, sizeof(*t)); strcpy(t->name, "Television"); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM; - t->rangehigh = 0xffffffffUL; - t->signal = 0xffff ; /* LOCKED */ + return 0; } @@ -1237,6 +1238,8 @@ static int vidioc_s_tuner(struct file *file, void *priv, return -EINVAL; if (0 != t->index) return -EINVAL; + /* Update the A/V core */ + return 0; } @@ -1438,6 +1441,9 @@ void cx23885_video_unregister(struct cx23885_dev *dev) btcx_riscmem_free(dev->pci, &dev->vidq.stopper); } + + if (dev->audio_dev) + cx23885_audio_finidev(dev); } int cx23885_video_register(struct cx23885_dev *dev) @@ -1504,7 +1510,6 @@ int cx23885_video_register(struct cx23885_dev *dev) } } - /* register v4l devices */ dev->video_dev = cx23885_vdev_init(dev, dev->pci, &cx23885_video_template, "video"); @@ -1517,6 +1522,10 @@ int cx23885_video_register(struct cx23885_dev *dev) } printk(KERN_INFO "%s/0: registered device %s [v4l2]\n", dev->name, video_device_node_name(dev->video_dev)); + + /* Register ALSA audio device */ + dev->audio_dev = cx23885_audio_initdev(dev); + /* initial device configuration */ mutex_lock(&dev->lock); cx23885_set_tvnorm(dev, dev->tvnorm); -- cgit v0.10.2 From d5492fb9ed3f3f25c56b25684072f0d234863b08 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Oct 2011 17:00:19 -0300 Subject: [media] cx23885: Don't use memset on vidioc_ callbacks vidioc_g_tuner should not do any memset for the parameters. Core already does that. In particular, V4L2 core now does some handling for the tuner type, and the tuner-core module relies on that. So, doing any memset there is a very bad idea. Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index acd6e0c..34854b0 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -1223,7 +1223,6 @@ static int vidioc_g_tuner(struct file *file, void *priv, if (0 != t->index) return -EINVAL; - memset(t, 0, sizeof(*t)); strcpy(t->name, "Television"); return 0; -- cgit v0.10.2 From 80f1e086e68f4e6ef066022d8b7f5ea0bd686220 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:53 -0300 Subject: [media] cx23885: convert call clients into subdevices Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 34854b0..747fdb3 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -1225,6 +1225,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, strcpy(t->name, "Television"); + call_all(dev, tuner, g_tuner, t); return 0; } @@ -1238,6 +1239,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, if (0 != t->index) return -EINVAL; /* Update the A/V core */ + call_all(dev, tuner, s_tuner, t); return 0; } -- cgit v0.10.2 From efa762f597cb6ec094a9e62acd4f1167b3199d34 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:53 -0300 Subject: [media] cx23885: minor function renaming to ensure uniformity Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-alsa.c b/drivers/media/video/cx23885/cx23885-alsa.c index 31a89b3..668776d 100644 --- a/drivers/media/video/cx23885/cx23885-alsa.c +++ b/drivers/media/video/cx23885/cx23885-alsa.c @@ -472,7 +472,7 @@ static int snd_cx23885_pcm(struct cx23885_audio_dev *chip, int device, * Alsa Constructor - Component probe */ -struct cx23885_audio_dev *cx23885_audio_initdev(struct cx23885_dev *dev) +struct cx23885_audio_dev *cx23885_audio_register(struct cx23885_dev *dev) { struct snd_card *card; struct cx23885_audio_dev *chip; @@ -527,7 +527,7 @@ error: /* * ALSA destructor */ -void cx23885_audio_finidev(struct cx23885_dev *dev) +void cx23885_audio_unregister(struct cx23885_dev *dev) { struct cx23885_audio_dev *chip = dev->audio_dev; diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 747fdb3..58855b2 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -1444,7 +1444,7 @@ void cx23885_video_unregister(struct cx23885_dev *dev) } if (dev->audio_dev) - cx23885_audio_finidev(dev); + cx23885_audio_unregister(dev); } int cx23885_video_register(struct cx23885_dev *dev) @@ -1525,7 +1525,7 @@ int cx23885_video_register(struct cx23885_dev *dev) dev->name, video_device_node_name(dev->video_dev)); /* Register ALSA audio device */ - dev->audio_dev = cx23885_audio_initdev(dev); + dev->audio_dev = cx23885_audio_register(dev); /* initial device configuration */ mutex_lock(&dev->lock); diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index abeba7a..892d971 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -596,8 +596,9 @@ extern void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput); /* ----------------------------------------------------------- */ /* cx23885-alsa.c */ -extern struct cx23885_audio_dev *cx23885_audio_initdev(struct cx23885_dev *dev); -extern void cx23885_audio_finidev(struct cx23885_dev *dev); +extern struct cx23885_audio_dev *cx23885_audio_register( + struct cx23885_dev *dev); +extern void cx23885_audio_unregister(struct cx23885_dev *dev); extern int cx23885_audio_irq(struct cx23885_dev *dev, u32 status, u32 mask); extern int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, -- cgit v0.10.2 From 3273961fe19116f0b94346bf3f82d23a956c3db4 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:53 -0300 Subject: [media] cx23885: setup the dma mapping for raw audio support Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index d8dfa40..a50b5cf 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -155,7 +155,6 @@ static struct sram_channel cx23885_sram_channels[] = { .cnt2_reg = DMA5_CNT2, }, [SRAM_CH07] = { - .name = "ch7", .name = "TV Audio", .cmds_start = 0x10190, .ctrl_start = 0x10480, -- cgit v0.10.2 From 6aa07d9e6329c93dfa5f6ff4fce8602f2a33b891 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:54 -0300 Subject: [media] cx23885: add two additional defines to simplify VBI register bitmap handling Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h index c87ac68..12b4d3a 100644 --- a/drivers/media/video/cx23885/cx23885-reg.h +++ b/drivers/media/video/cx23885/cx23885-reg.h @@ -271,7 +271,9 @@ Channel manager Data Structure entry = 20 DWORD #define VID_BC_MSK_OPC_ERR (1 << 16) #define VID_BC_MSK_SYNC (1 << 12) #define VID_BC_MSK_OF (1 << 8) +#define VID_BC_MSK_VBI_RISCI2 (1 << 5) #define VID_BC_MSK_RISCI2 (1 << 4) +#define VID_BC_MSK_VBI_RISCI1 (1 << 1) #define VID_BC_MSK_RISCI1 1 #define VID_C_INT_MSK 0x00040040 -- cgit v0.10.2 From b5f74050043f4782517cd9aa2b68c13ebf5cfa90 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:54 -0300 Subject: [media] cx23885: initial support for VBI with the cx23885 A handlful of coding style issue cleaned up in the following patches. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-alsa.c b/drivers/media/video/cx23885/cx23885-alsa.c index 668776d..7951692 100644 --- a/drivers/media/video/cx23885/cx23885-alsa.c +++ b/drivers/media/video/cx23885/cx23885-alsa.c @@ -46,10 +46,10 @@ #define AUDIO_SRAM_CHANNEL SRAM_CH07 #define dprintk(level, fmt, arg...) if (audio_debug >= level) \ - printk(KERN_INFO "%s/1: " fmt, chip->dev->name , ## arg) + printk(KERN_INFO "%s: " fmt, chip->dev->name , ## arg) #define dprintk_core(level, fmt, arg...) if (audio_debug >= level) \ - printk(KERN_DEBUG "%s/1: " fmt, chip->dev->name , ## arg) + printk(KERN_DEBUG "%s: " fmt, chip->dev->name , ## arg) /**************************************************************************** Module global static vars diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index a50b5cf..d42d225 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -54,7 +54,7 @@ MODULE_PARM_DESC(card, "card type"); #define dprintk(level, fmt, arg...)\ do { if (debug >= level)\ - printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ + printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg);\ } while (0) static unsigned int cx23885_devcount; diff --git a/drivers/media/video/cx23885/cx23885-vbi.c b/drivers/media/video/cx23885/cx23885-vbi.c index c0b6038..23ff098 100644 --- a/drivers/media/video/cx23885/cx23885-vbi.c +++ b/drivers/media/video/cx23885/cx23885-vbi.c @@ -62,30 +62,65 @@ int cx23885_vbi_fmt(struct file *file, void *priv, return 0; } +/* We're given the Video Interrupt status register. + * The cx23885_video_irq() func has already validated + * the potential error bits, we just need to + * deal with vbi payload and return indication if + * we actually processed any payload. + */ +int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status) +{ + u32 count; + int handled = 0; + + if (status & VID_BC_MSK_VBI_RISCI1) { + dprintk(1, "%s() VID_BC_MSK_VBI_RISCI1\n", __func__); + spin_lock(&dev->slock); + count = cx_read(VID_A_GPCNT); + cx23885_video_wakeup(dev, &dev->vbiq, count); + spin_unlock(&dev->slock); + handled++; + } + + if (status & VID_BC_MSK_VBI_RISCI2) { + dprintk(1, "%s() VID_BC_MSK_VBI_RISCI2\n", __func__); + dprintk(2, "stopper vbi\n"); + spin_lock(&dev->slock); + cx23885_restart_vbi_queue(dev, &dev->vbiq); + spin_unlock(&dev->slock); + handled++; + } + + return handled; +} + static int cx23885_start_vbi_dma(struct cx23885_dev *dev, struct cx23885_dmaqueue *q, struct cx23885_buffer *buf) { + dprintk(1, "%s()\n", __func__); + /* setup fifo + format */ cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02], buf->vb.width, buf->risc.dma); /* reset counter */ + cx_write(VID_A_GPCNT_CTL, 3); q->count = 1; - /* enable irqs */ + /* enable irq */ cx23885_irq_add_enable(dev, 0x01); cx_set(VID_A_INT_MSK, 0x000022); /* start dma */ cx_set(DEV_CNTRL2, (1<<5)); - cx_set(VID_A_DMA_CTL, 0x00000022); + cx_set(VID_A_DMA_CTL, 0x22); /* FIFO and RISC enable */ return 0; } -static int cx23885_restart_vbi_queue(struct cx23885_dev *dev, +int cx23885_restart_vbi_queue(struct cx23885_dev *dev, struct cx23885_dmaqueue *q) { struct cx23885_buffer *buf; @@ -115,6 +150,7 @@ void cx23885_vbi_timeout(unsigned long data) cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH02]); + /* Stop the VBI engine */ cx_clear(VID_A_DMA_CTL, 0x22); spin_lock_irqsave(&dev->slock, flags); diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 892d971..718afd8 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -564,6 +564,8 @@ extern void cx23885_free_buffer(struct videobuf_queue *q, extern int cx23885_video_register(struct cx23885_dev *dev); extern void cx23885_video_unregister(struct cx23885_dev *dev); extern int cx23885_video_irq(struct cx23885_dev *dev, u32 status); +extern void cx23885_video_wakeup(struct cx23885_dev *dev, + struct cx23885_dmaqueue *q, u32 count); /* ----------------------------------------------------------- */ /* cx23885-vbi.c */ @@ -571,6 +573,9 @@ extern int cx23885_vbi_fmt(struct file *file, void *priv, struct v4l2_format *f); extern void cx23885_vbi_timeout(unsigned long data); extern struct videobuf_queue_ops cx23885_vbi_qops; +extern int cx23885_restart_vbi_queue(struct cx23885_dev *dev, + struct cx23885_dmaqueue *q); +extern int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status); /* cx23885-i2c.c */ extern int cx23885_i2c_register(struct cx23885_i2c *bus); -- cgit v0.10.2 From 79776c89e0e52fce23d8c85f765a879ed20e760f Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:54 -0300 Subject: [media] cx23885: initialize VBI support in the core, add IRQ support, register vbi device Coding style and printk's are cleaned up in subsequent patches Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 58855b2..5496ca2 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -71,7 +71,7 @@ MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); #define dprintk(level, fmt, arg...)\ do { if (video_debug >= level)\ - printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ + printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg);\ } while (0) /* ------------------------------------------------------------------- */ @@ -260,8 +260,8 @@ static const u32 *ctrl_classes[] = { NULL }; -static void cx23885_video_wakeup(struct cx23885_dev *dev, - struct cx23885_dmaqueue *q, u32 count) +void cx23885_video_wakeup(struct cx23885_dev *dev, + struct cx23885_dmaqueue *q, u32 count) { struct cx23885_buffer *buf; int bc; @@ -759,6 +759,14 @@ static int video_open(struct file *file) sizeof(struct cx23885_buffer), fh, NULL); + videobuf_queue_sg_init(&fh->vbiq, &cx23885_vbi_qops, + &dev->pci->dev, &dev->slock, + V4L2_BUF_TYPE_VBI_CAPTURE, + V4L2_FIELD_SEQ_TB, + sizeof(struct cx23885_buffer), + fh, NULL); + + dprintk(1, "post videobuf_queue_init()\n"); return 0; @@ -1317,7 +1325,7 @@ static void cx23885_vid_timeout(unsigned long data) list_del(&buf->vb.queue); buf->vb.state = VIDEOBUF_ERROR; wake_up(&buf->vb.done); - printk(KERN_ERR "%s/0: [%p/%d] timeout - dma=0x%08lx\n", + printk(KERN_ERR "%s: [%p/%d] timeout - dma=0x%08lx\n", dev->name, buf, buf->vb.i, (unsigned long)buf->risc.dma); } @@ -1333,27 +1341,43 @@ int cx23885_video_irq(struct cx23885_dev *dev, u32 status) mask = cx_read(VID_A_INT_MSK); if (0 == (status & mask)) return handled; + cx_write(VID_A_INT_STAT, status); - dprintk(2, "%s() status = 0x%08x\n", __func__, status); /* risc op code error */ - if (status & (1 << 16)) { - printk(KERN_WARNING "%s/0: video risc op code error\n", + if ((status & VID_BC_MSK_OPC_ERR) || + (status & VID_BC_MSK_SYNC) || + (status & VID_BC_MSK_OF)) { + + if (status & VID_BC_MSK_OPC_ERR) + dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n", + VID_BC_MSK_OPC_ERR); + + if (status & VID_BC_MSK_SYNC) + dprintk(7, " (VID_BC_MSK_SYNC 0x%08x)\n", + VID_BC_MSK_SYNC); + + if (status & VID_BC_MSK_OF) + dprintk(7, " (VID_BC_MSK_OF 0x%08x)\n", + VID_BC_MSK_OF); + + printk(KERN_WARNING "%s: video risc op code error\n", dev->name); + cx_clear(VID_A_DMA_CTL, 0x11); cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]); + } - /* risc1 y */ - if (status & 0x01) { + /* Video */ + if (status & VID_BC_MSK_RISCI1) { spin_lock(&dev->slock); count = cx_read(VID_A_GPCNT); cx23885_video_wakeup(dev, &dev->vidq, count); spin_unlock(&dev->slock); handled++; } - /* risc2 y */ - if (status & 0x10) { + if (status & VID_BC_MSK_RISCI2) { dprintk(2, "stopper video\n"); spin_lock(&dev->slock); cx23885_restart_video_queue(dev, &dev->vidq); @@ -1361,6 +1385,9 @@ int cx23885_video_irq(struct cx23885_dev *dev, u32 status) handled++; } + /* Allow the VBI framework to process it's payload */ + handled += cx23885_vbi_irq(dev, status); + return handled; } @@ -1433,6 +1460,14 @@ void cx23885_video_unregister(struct cx23885_dev *dev) dprintk(1, "%s()\n", __func__); cx23885_irq_remove(dev, 0x01); + if (dev->vbi_dev) { + if (video_is_registered(dev->vbi_dev)) + video_unregister_device(dev->vbi_dev); + else + video_device_release(dev->vbi_dev); + dev->vbi_dev = NULL; + btcx_riscmem_free(dev->pci, &dev->vbiq.stopper); + } if (dev->video_dev) { if (video_is_registered(dev->video_dev)) video_unregister_device(dev->video_dev); @@ -1470,7 +1505,14 @@ int cx23885_video_register(struct cx23885_dev *dev) cx23885_risc_stopper(dev->pci, &dev->vidq.stopper, VID_A_DMA_CTL, 0x11, 0x00); - /* Don't enable VBI yet */ + /* init vbi dma queues */ + INIT_LIST_HEAD(&dev->vbiq.active); + INIT_LIST_HEAD(&dev->vbiq.queued); + dev->vbiq.timeout.function = cx23885_vbi_timeout; + dev->vbiq.timeout.data = (unsigned long)dev; + init_timer(&dev->vbiq.timeout); + cx23885_risc_stopper(dev->pci, &dev->vbiq.stopper, + VID_A_DMA_CTL, 0x22, 0x00); cx23885_irq_add_enable(dev, 0x01); @@ -1511,7 +1553,7 @@ int cx23885_video_register(struct cx23885_dev *dev) } } - /* register v4l devices */ + /* register Video device */ dev->video_dev = cx23885_vdev_init(dev, dev->pci, &cx23885_video_template, "video"); err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, -- cgit v0.10.2 From f88fb8e9385eaec2e7c0527ccc0d947fbbe4c5f9 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:54 -0300 Subject: [media] cx23885: minor printk cleanups and device registration Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 5496ca2..53d9f9d 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -1563,9 +1563,22 @@ int cx23885_video_register(struct cx23885_dev *dev) dev->name); goto fail_unreg; } - printk(KERN_INFO "%s/0: registered device %s [v4l2]\n", + printk(KERN_INFO "%s: registered device %s [v4l2]\n", dev->name, video_device_node_name(dev->video_dev)); + /* register VBI device */ + dev->vbi_dev = cx23885_vdev_init(dev, dev->pci, + &cx23885_vbi_template, "vbi"); + err = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, + vbi_nr[dev->nr]); + if (err < 0) { + printk(KERN_INFO "%s: can't register vbi device\n", + dev->name); + goto fail_unreg; + } + printk(KERN_INFO "%s: registered device %s\n", + dev->name, video_device_node_name(dev->vbi_dev)); + /* Register ALSA audio device */ dev->audio_dev = cx23885_audio_register(dev); -- cgit v0.10.2 From 99d389095f3270aaeb021370e01057910d3ef24d Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:54 -0300 Subject: [media] cx25840: enable raw cc processing only for the cx23885 hardware This change is probably good for other boards also, but the change has limited scope and is reasonably safe. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index b7ee2ae..8896999 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -702,6 +702,13 @@ static void cx231xx_initialize(struct i2c_client *client) /* start microcontroller */ cx25840_and_or(client, 0x803, ~0x10, 0x10); + + /* CC raw enable */ + cx25840_write(client, 0x404, 0x0b); + + /* CC on */ + cx25840_write(client, 0x42f, 0x66); + cx25840_write4(client, 0x474, 0x1e1e601a); } /* ----------------------------------------------------------------------- */ -- cgit v0.10.2 From 4f9c41439c495b4685393cf865418f7e6425fe60 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:54 -0300 Subject: [media] cx23885: vbi line window adjustments Coding style and printk's cleaned up in following patches. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-vbi.c b/drivers/media/video/cx23885/cx23885-vbi.c index 23ff098..1b3a01c 100644 --- a/drivers/media/video/cx23885/cx23885-vbi.c +++ b/drivers/media/video/cx23885/cx23885-vbi.c @@ -41,6 +41,12 @@ MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]"); /* ------------------------------------------------------------------ */ +#define VBI_LINE_LENGTH 1440 +#define NTSC_VBI_START_LINE 10 /* line 10 - 21 */ +#define NTSC_VBI_END_LINE 21 +#define NTSC_VBI_LINES (NTSC_VBI_END_LINE - NTSC_VBI_START_LINE + 1) + + int cx23885_vbi_fmt(struct file *file, void *priv, struct v4l2_format *f) { @@ -49,16 +55,21 @@ int cx23885_vbi_fmt(struct file *file, void *priv, if (dev->tvnorm & V4L2_STD_525_60) { /* ntsc */ + f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH; f->fmt.vbi.sampling_rate = 28636363; + f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; + f->fmt.vbi.offset = 64 * 4; f->fmt.vbi.start[0] = 10; - f->fmt.vbi.start[1] = 273; - + f->fmt.vbi.count[0] = 17; + f->fmt.vbi.start[1] = 272; + f->fmt.vbi.count[1] = 17; } else if (dev->tvnorm & V4L2_STD_625_50) { /* pal */ f->fmt.vbi.sampling_rate = 35468950; f->fmt.vbi.start[0] = 7 - 1; f->fmt.vbi.start[1] = 319 - 1; } + return 0; } @@ -106,6 +117,8 @@ static int cx23885_start_vbi_dma(struct cx23885_dev *dev, /* reset counter */ cx_write(VID_A_GPCNT_CTL, 3); + cx_write(VID_A_VBI_CTRL, 3); + cx_write(VBI_A_GPCNT_CTL, 3); q->count = 1; /* enable irq */ @@ -168,7 +181,7 @@ void cx23885_vbi_timeout(unsigned long data) } /* ------------------------------------------------------------------ */ -#define VBI_LINE_LENGTH 2048 +#define VBI_LINE_LENGTH 1440 #define VBI_LINE_COUNT 17 static int -- cgit v0.10.2 From 5ab27e6d31be4a794a44477b94aa56dd625eb0f2 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:54 -0300 Subject: [media] cx23885: add vbi buffer formatting, window changes and video core changes Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index d42d225..40e68b2 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1214,6 +1214,54 @@ int cx23885_risc_databuffer(struct pci_dev *pci, return 0; } +int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc, + struct scatterlist *sglist, unsigned int top_offset, + unsigned int bottom_offset, unsigned int bpl, + unsigned int padding, unsigned int lines) +{ + u32 instructions, fields; + __le32 *rp; + int rc; + + fields = 0; + if (UNSET != top_offset) + fields++; + if (UNSET != bottom_offset) + fields++; + + /* estimate risc mem: worst case is one write per page border + + one write per scan line + syncs + jump (all 2 dwords). Padding + can cause next bpl to start close to a page border. First DMA + region may be smaller than PAGE_SIZE */ + /* write and jump need and extra dword */ + instructions = fields * (1 + ((bpl + padding) * lines) + / PAGE_SIZE + lines); + instructions += 2; + rc = btcx_riscmem_alloc(pci, risc, instructions*12); + if (rc < 0) + return rc; + /* write risc instructions */ + rp = risc->cpu; + + /* Sync to line 6, so US CC line 21 will appear in line '12' + * in the userland vbi payload */ + if (UNSET != top_offset) + rp = cx23885_risc_field(rp, sglist, top_offset, 6, + bpl, padding, lines, 0); + + if (UNSET != bottom_offset) + rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x207, + bpl, padding, lines, 0); + + + + /* save pointer to jmp instruction address */ + risc->jmp = rp; + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); + return 0; +} + + int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, u32 reg, u32 mask, u32 value) { diff --git a/drivers/media/video/cx23885/cx23885-vbi.c b/drivers/media/video/cx23885/cx23885-vbi.c index 1b3a01c..10d8af8 100644 --- a/drivers/media/video/cx23885/cx23885-vbi.c +++ b/drivers/media/video/cx23885/cx23885-vbi.c @@ -56,12 +56,13 @@ int cx23885_vbi_fmt(struct file *file, void *priv, if (dev->tvnorm & V4L2_STD_525_60) { /* ntsc */ f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH; - f->fmt.vbi.sampling_rate = 28636363; + f->fmt.vbi.sampling_rate = 27000000; f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; - f->fmt.vbi.offset = 64 * 4; + f->fmt.vbi.offset = 0; + f->fmt.vbi.flags = 0; f->fmt.vbi.start[0] = 10; f->fmt.vbi.count[0] = 17; - f->fmt.vbi.start[1] = 272; + f->fmt.vbi.start[1] = 263 + 10 + 1; f->fmt.vbi.count[1] = 17; } else if (dev->tvnorm & V4L2_STD_625_50) { /* pal */ @@ -222,7 +223,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, rc = videobuf_iolock(q, &buf->vb, NULL); if (0 != rc) goto fail; - cx23885_risc_buffer(dev->pci, &buf->risc, + cx23885_risc_vbibuffer(dev->pci, &buf->risc, dma->sglist, 0, buf->vb.width * buf->vb.height, buf->vb.width, 0, diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 53d9f9d..cb9e05f 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -1070,7 +1070,8 @@ static int vidioc_streamon(struct file *file, void *priv, struct cx23885_dev *dev = fh->dev; dprintk(1, "%s()\n", __func__); - if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) + if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && + (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)) return -EINVAL; if (unlikely(i != fh->type)) return -EINVAL; @@ -1087,7 +1088,8 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) int err, res; dprintk(1, "%s()\n", __func__); - if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && + (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)) return -EINVAL; if (i != fh->type) return -EINVAL; diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 718afd8..670281a 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -509,6 +509,11 @@ extern int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, unsigned int top_offset, unsigned int bottom_offset, unsigned int bpl, unsigned int padding, unsigned int lines); +extern int cx23885_risc_vbibuffer(struct pci_dev *pci, + struct btcx_riscmem *risc, struct scatterlist *sglist, + unsigned int top_offset, unsigned int bottom_offset, + unsigned int bpl, unsigned int padding, unsigned int lines); + void cx23885_cancel_buffers(struct cx23885_tsport *port); extern int cx23885_restart_queue(struct cx23885_tsport *port, -- cgit v0.10.2 From af76e9f625b235f46d2a2002c4102f6f1249dcf4 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:54 -0300 Subject: [media] cx23885: Ensure the VBI pixel format is established correctly Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index cb9e05f..a182e82 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -78,7 +78,7 @@ MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); /* static data */ #define FORMAT_FLAGS_PACKED 0x01 - +#if 0 static struct cx23885_fmt formats[] = { { .name = "8 bpp, gray", @@ -132,6 +132,23 @@ static struct cx23885_fmt formats[] = { .flags = FORMAT_FLAGS_PACKED, }, }; +#else +static struct cx23885_fmt formats[] = { + { +#if 0 + .name = "4:2:2, packed, UYVY", + .fourcc = V4L2_PIX_FMT_UYVY, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + }, { +#endif + .name = "4:2:2, packed, YUYV", + .fourcc = V4L2_PIX_FMT_YUYV, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + } +}; +#endif static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc) { @@ -141,7 +158,12 @@ static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc) if (formats[i].fourcc == fourcc) return formats+i; - printk(KERN_ERR "%s(0x%08x) NOT FOUND\n", __func__, fourcc); + printk(KERN_ERR "%s(%c%c%c%c) NOT FOUND\n", __func__, + (fourcc & 0xff), + ((fourcc >> 8) & 0xff), + ((fourcc >> 16) & 0xff), + ((fourcc >> 24) & 0xff) + ); return NULL; } @@ -750,7 +772,7 @@ static int video_open(struct file *file) fh->type = type; fh->width = 320; fh->height = 240; - fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); + fh->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV); videobuf_queue_sg_init(&fh->vidq, &cx23885_video_qops, &dev->pci->dev, &dev->slock, -- cgit v0.10.2 From 24465b448546e10666ad6021be0615214a258cbc Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:54 -0300 Subject: [media] cx23885: ensure video is streaming before allowing vbi to stream Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index a182e82..44a63c4 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -1100,6 +1100,14 @@ static int vidioc_streamon(struct file *file, void *priv, if (unlikely(!res_get(dev, fh, get_resource(fh)))) return -EBUSY; + + /* Don't start VBI streaming unless vida streaming + * has already started. + */ + if ((fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) && + ((cx_read(VID_A_DMA_CTL) & 0x11) == 0)) + return -EINVAL; + return videobuf_streamon(get_queue(fh)); } -- cgit v0.10.2 From 68776b30fe2677e85fe19f4d5f8c8ed42a28d142 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:55 -0300 Subject: [media] cx23885: remove channel dump diagnostics when a vbi buffer times out Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-vbi.c b/drivers/media/video/cx23885/cx23885-vbi.c index 10d8af8..499bc45 100644 --- a/drivers/media/video/cx23885/cx23885-vbi.c +++ b/drivers/media/video/cx23885/cx23885-vbi.c @@ -162,8 +162,6 @@ void cx23885_vbi_timeout(unsigned long data) struct cx23885_buffer *buf; unsigned long flags; - cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH02]); - /* Stop the VBI engine */ cx_clear(VID_A_DMA_CTL, 0x22); -- cgit v0.10.2 From 1ca3553aa4db1d6795196a8602d33af0178eac06 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:55 -0300 Subject: [media] cx23885: Ensure VBI buffers timeout quickly - bugfix for vbi hangs during streaming Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-vbi.c b/drivers/media/video/cx23885/cx23885-vbi.c index 499bc45..a1154f0 100644 --- a/drivers/media/video/cx23885/cx23885-vbi.c +++ b/drivers/media/video/cx23885/cx23885-vbi.c @@ -151,7 +151,7 @@ int cx23885_restart_vbi_queue(struct cx23885_dev *dev, buf = list_entry(item, struct cx23885_buffer, vb.queue); buf->count = q->count++; } - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + mod_timer(&q->timeout, jiffies + (BUFFER_TIMEOUT / 30)); return 0; } @@ -255,7 +255,7 @@ vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) cx23885_start_vbi_dma(dev, q, buf); buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + mod_timer(&q->timeout, jiffies + (BUFFER_TIMEOUT / 30)); dprintk(2, "[%p/%d] vbi_queue - first active\n", buf, buf->vb.i); -- cgit v0.10.2 From d9368da71804053a6f84d170c63c6cb86c8318b2 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:55 -0300 Subject: [media] cx23885: Name an internal i2c part and declare a bitfield by name Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index 307ff54..0ff7a9e 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -287,6 +287,7 @@ static char *i2c_devs[128] = { [0x32 >> 1] = "cx24227", [0x88 >> 1] = "cx25837", [0x84 >> 1] = "tda8295", + [0x98 >> 1] = "flatiron", [0xa0 >> 1] = "eeprom", [0xc0 >> 1] = "tuner/mt2131/tda8275", [0xc2 >> 1] = "tuner/mt2131/tda8275/xc5000/xc3028", diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h index 12b4d3a..a99936e 100644 --- a/drivers/media/video/cx23885/cx23885-reg.h +++ b/drivers/media/video/cx23885/cx23885-reg.h @@ -203,6 +203,7 @@ Channel manager Data Structure entry = 20 DWORD #define SD2_BIAS_CTRL 0x0000000A #define AMP_BIAS_CTRL 0x0000000C #define CH_PWR_CTRL1 0x0000000E +#define FLD_CH_SEL (1 << 3) #define CH_PWR_CTRL2 0x0000000F #define DSM_STATUS1 0x00000010 #define DSM_STATUS2 0x00000011 -- cgit v0.10.2 From 2ccdd9a59b3a1ff3bd1be6390c4b1989a008e61c Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:55 -0300 Subject: [media] cx25840: Enable support for non-tuner LR1/LR2 audio inputs The change effects cx23885 boards only and preserves support for existing boards. Essentially, if we're using baseband audio into the cx23885 AV core then we have to patch registers. The cx23885 driver will call with either CX25840_AUDIO8 to signify tuner audio or AUDIO7 to signify baseband audio. If/When we become more comfortable with this change across a series of products then we may decide to relax the cx23885 only restriction. [liplianin@netup.ru: fix missing state declaration] Signed-off-by: Steven Toth Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c index 34b96c7..005f110 100644 --- a/drivers/media/video/cx25840/cx25840-audio.c +++ b/drivers/media/video/cx25840/cx25840-audio.c @@ -480,6 +480,7 @@ void cx25840_audio_set_path(struct i2c_client *client) static void set_volume(struct i2c_client *client, int volume) { + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); int vol; /* Convert the volume to msp3400 values (0-127) */ @@ -495,7 +496,14 @@ static void set_volume(struct i2c_client *client, int volume) } /* PATH1_VOLUME */ - cx25840_write(client, 0x8d4, 228 - (vol * 2)); + if (is_cx2388x(state)) { + /* for cx23885 volume doesn't work, + * the calculation always results in + * e4 regardless. + */ + cx25840_write(client, 0x8d4, volume); + } else + cx25840_write(client, 0x8d4, 228 - (vol * 2)); } static void set_balance(struct i2c_client *client, int balance) diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 8896999..0316e41 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -1074,6 +1074,17 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp cx25840_write(client, 0x919, 0x01); } + if (is_cx2388x(state) && (aud_input == CX25840_AUDIO7)) { + /* Configure audio from LR1 or LR2 input */ + cx25840_write4(client, 0x910, 0); + cx25840_write4(client, 0x8d0, 0x63073); + } else + if (is_cx2388x(state) && (aud_input == CX25840_AUDIO8)) { + /* Configure audio from tuner/sif input */ + cx25840_write4(client, 0x910, 0x12b000c9); + cx25840_write4(client, 0x8d0, 0x1f063870); + } + return 0; } -- cgit v0.10.2 From 8304be888c55b501b93907177e683db62d4000c0 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:56 -0300 Subject: [media] cx23885: Allow the audio mux config to be specified on a per input basis Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 670281a..2978e97 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -192,6 +192,7 @@ struct cx23885_buffer { struct cx23885_input { enum cx23885_itype type; unsigned int vmux; + unsigned int amux; u32 gpio0, gpio1, gpio2, gpio3; }; -- cgit v0.10.2 From 33cdeb35f559270d2c51ed641df69a9ac659bc22 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:55 -0300 Subject: [media] cx23885: Enable audio line in support from the back panel Add code to program the flatiron internal i2c ADC and pass the appropriate audio mux enums to the cx25840 driver. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 75d77c2d..969a9a3 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -106,12 +106,14 @@ struct cx23885_board cx23885_boards[] = { .vmux = CX25840_VIN7_CH3 | CX25840_VIN5_CH2 | CX25840_VIN2_CH1, + .amux = CX25840_AUDIO8, .gpio0 = 0, }, { .type = CX23885_VMUX_COMPOSITE1, .vmux = CX25840_VIN7_CH3 | CX25840_VIN4_CH2 | CX25840_VIN6_CH1, + .amux = CX25840_AUDIO7, .gpio0 = 0, }, { .type = CX23885_VMUX_SVIDEO, @@ -119,6 +121,7 @@ struct cx23885_board cx23885_boards[] = { CX25840_VIN4_CH2 | CX25840_VIN8_CH1 | CX25840_SVIDEO_ON, + .amux = CX25840_AUDIO7, .gpio0 = 0, } }, }, diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 44a63c4..adc8f78 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -417,6 +417,71 @@ static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh, mutex_unlock(&dev->lock); } +static int cx23885_flatiron_write(struct cx23885_dev *dev, u8 reg, u8 data) +{ + /* 8 bit registers, 8 bit values */ + u8 buf[] = { reg, data }; + + struct i2c_msg msg = { .addr = 0x98 >> 1, + .flags = 0, .buf = buf, .len = 2 }; + + return i2c_transfer(&dev->i2c_bus[2].i2c_adap, &msg, 1); +} + +static u8 cx23885_flatiron_read(struct cx23885_dev *dev, u8 reg) +{ + /* 8 bit registers, 8 bit values */ + int ret; + u8 b0[] = { reg }; + u8 b1[] = { 0 }; + + struct i2c_msg msg[] = { + { .addr = 0x98 >> 1, .flags = 0, .buf = b0, .len = 1 }, + { .addr = 0x98 >> 1, .flags = I2C_M_RD, .buf = b1, .len = 1 } + }; + + ret = i2c_transfer(&dev->i2c_bus[2].i2c_adap, &msg[0], 2); + if (ret != 2) + printk(KERN_ERR "%s() error\n", __func__); + + return b1[0]; +} + +static void cx23885_flatiron_dump(struct cx23885_dev *dev) +{ + int i; + dprintk(1, "Flatiron dump\n"); + for (i = 0; i < 0x24; i++) { + dprintk(1, "FI[%02x] = %02x\n", i, + cx23885_flatiron_read(dev, i)); + } +} + +static int cx23885_flatiron_mux(struct cx23885_dev *dev, int input) +{ + u8 val; + dprintk(1, "%s(input = %d)\n", __func__, input); + + if (input == 1) + val = cx23885_flatiron_read(dev, CH_PWR_CTRL1) & ~FLD_CH_SEL; + else if (input == 2) + val = cx23885_flatiron_read(dev, CH_PWR_CTRL1) | FLD_CH_SEL; + else + return -EINVAL; + + val |= 0x20; /* Enable clock to delta-sigma and dec filter */ + + cx23885_flatiron_write(dev, CH_PWR_CTRL1, val); + + /* Wake up */ + cx23885_flatiron_write(dev, CH_PWR_CTRL2, 0); + + if (video_debug) + cx23885_flatiron_dump(dev); + + return 0; +} + static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) { dprintk(1, "%s() video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n", @@ -437,6 +502,17 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) v4l2_subdev_call(dev->sd_cx25840, video, s_routing, INPUT(input)->vmux, 0, 0); + if (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1800) { + /* Configure audio routing */ + v4l2_subdev_call(dev->sd_cx25840, audio, s_routing, + INPUT(input)->amux, 0, 0); + + if (INPUT(input)->amux == CX25840_AUDIO7) + cx23885_flatiron_mux(dev, 1); + else if (INPUT(input)->amux == CX25840_AUDIO6) + cx23885_flatiron_mux(dev, 2); + } + return 0; } -- cgit v0.10.2 From 52422e3cb146ef643fc0dbe74fa80f1abbe5fc37 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:55 -0300 Subject: [media] cx25840: Ensure AUDIO6 and AUDIO7 trigger line-in baseband use Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 0316e41..cd99764 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -1074,7 +1074,8 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp cx25840_write(client, 0x919, 0x01); } - if (is_cx2388x(state) && (aud_input == CX25840_AUDIO7)) { + if (is_cx2388x(state) && ((aud_input == CX25840_AUDIO7) || + (aud_input == CX25840_AUDIO6))) { /* Configure audio from LR1 or LR2 input */ cx25840_write4(client, 0x910, 0); cx25840_write4(client, 0x8d0, 0x63073); -- cgit v0.10.2 From 2cb9ccd4612907c0a30de9be1c694672e0cd8933 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:55 -0300 Subject: [media] cx23885: Initial support for the MPX-885 mini-card Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 969a9a3..c3cf089 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -413,6 +413,31 @@ struct cx23885_board cx23885_boards[] = { .vmux = CX25840_COMPOSITE1, } }, }, + [CX23885_BOARD_MPX885] = { + .name = "MPX-885", + .porta = CX23885_ANALOG_VIDEO, + .input = {{ + .type = CX23885_VMUX_COMPOSITE1, + .vmux = CX25840_COMPOSITE1, + .amux = CX25840_AUDIO6, + .gpio0 = 0, + }, { + .type = CX23885_VMUX_COMPOSITE2, + .vmux = CX25840_COMPOSITE2, + .amux = CX25840_AUDIO6, + .gpio0 = 0, + }, { + .type = CX23885_VMUX_COMPOSITE3, + .vmux = CX25840_COMPOSITE3, + .amux = CX25840_AUDIO7, + .gpio0 = 0, + }, { + .type = CX23885_VMUX_COMPOSITE4, + .vmux = CX25840_COMPOSITE4, + .amux = CX25840_AUDIO7, + .gpio0 = 0, + } }, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -1442,6 +1467,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200: case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID: case CX23885_BOARD_HAUPPAUGE_HVR1500: + case CX23885_BOARD_MPX885: dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_bus[2].i2c_adap, "cx25840", 0x88 >> 1, NULL); diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index adc8f78..f13c40e 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -502,7 +502,8 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) v4l2_subdev_call(dev->sd_cx25840, video, s_routing, INPUT(input)->vmux, 0, 0); - if (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1800) { + if ((dev->board == CX23885_BOARD_HAUPPAUGE_HVR1800) || + (dev->board == CX23885_BOARD_MPX885)) { /* Configure audio routing */ v4l2_subdev_call(dev->sd_cx25840, audio, s_routing, INPUT(input)->amux, 0, 0); diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 2978e97..b205e32 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -86,6 +86,7 @@ #define CX23885_BOARD_GOTVIEW_X5_3D_HYBRID 29 #define CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF 30 #define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000 31 +#define CX23885_BOARD_MPX885 32 #define GPIO_0 0x00000001 #define GPIO_1 0x00000002 -- cgit v0.10.2 From e92bcf8d8abb654cb916f3e615697320bc6bf1e1 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:55 -0300 Subject: [media] cx23885: fixes related to maximum number of inputs and range checking Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index f13c40e..596b46e 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -1239,7 +1239,7 @@ static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) dprintk(1, "%s()\n", __func__); n = i->index; - if (n >= 4) + if (n >= MAX_CX23885_INPUT) return -EINVAL; if (0 == INPUT(n)->type) @@ -1279,11 +1279,14 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) dprintk(1, "%s(%d)\n", __func__, i); - if (i >= 4) { + if (i >= MAX_CX23885_INPUT) { dprintk(1, "%s() -EINVAL\n", __func__); return -EINVAL; } + if (INPUT(i)->type == 0) + return -EINVAL; + mutex_lock(&dev->lock); cx23885_video_mux(dev, i); mutex_unlock(&dev->lock); -- cgit v0.10.2 From fc1a889df78dea08e522310c9eb6110448dc61f0 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:56 -0300 Subject: [media] cx23885: add generic functions for dealing with audio input selection Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 596b46e..9726f2a 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -517,6 +517,22 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) return 0; } +static int cx23885_audio_mux(struct cx23885_dev *dev, unsigned int input) +{ + dprintk(1, "%s(input=%d)\n", __func__, input); + + if ((dev->board == CX23885_BOARD_HAUPPAUGE_HVR1800) || + (dev->board == CX23885_BOARD_MPX885)) { + + if (INPUT(input)->amux == CX25840_AUDIO7) + cx23885_flatiron_mux(dev, 1); + else if (INPUT(input)->amux == CX25840_AUDIO6) + cx23885_flatiron_mux(dev, 2); + } + + return 0; +} + /* ------------------------------------------------------------------ */ static int cx23885_set_scale(struct cx23885_dev *dev, unsigned int width, unsigned int height, enum v4l2_field field) @@ -1308,6 +1324,68 @@ static int vidioc_log_status(struct file *file, void *priv) return 0; } +static int cx23885_query_audinput(struct file *file, void *priv, + struct v4l2_audio *i) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + static const char *iname[] = { + [0] = "Baseband L/R 1", + [1] = "Baseband L/R 2", + }; + unsigned int n; + dprintk(1, "%s()\n", __func__); + + n = i->index; + if (n >= 2) + return -EINVAL; + + memset(i, 0, sizeof(*i)); + i->index = n; + strcpy(i->name, iname[n]); + i->capability = V4L2_AUDCAP_STEREO; + i->mode = V4L2_AUDMODE_AVL; + return 0; + +} + +static int vidioc_enum_audinput(struct file *file, void *priv, + struct v4l2_audio *i) +{ + return cx23885_query_audinput(file, priv, i); +} + +static int vidioc_g_audinput(struct file *file, void *priv, + struct v4l2_audio *i) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + + i->index = dev->audinput; + dprintk(1, "%s(input=%d)\n", __func__, i->index); + + return cx23885_query_audinput(file, priv, i); +} + +static int vidioc_s_audinput(struct file *file, void *priv, + struct v4l2_audio *i) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + + /* cx23885 offers 2 different audio inputs on the A/V core, LR1 and LR2. + * By default the driver has always used LR1 and we need support for + * switching. This isn't board specific, is part of the base silicon. + */ + if (i->index >= 2) + return -EINVAL; + + dprintk(1, "%s(%d)\n", __func__, i->index); + + mutex_lock(&dev->lock); + dev->audinput = i->index; + cx23885_audio_mux(dev, dev->audinput); + mutex_unlock(&dev->lock); + return 0; +} + static int vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *qctrl) { @@ -1548,6 +1626,9 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_g_register = cx23885_g_register, .vidioc_s_register = cx23885_s_register, #endif + .vidioc_enumaudio = vidioc_enum_audinput, + .vidioc_g_audio = vidioc_g_audinput, + .vidioc_s_audio = vidioc_s_audinput, }; static struct video_device cx23885_vbi_template; diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index b205e32..b49036f 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -392,6 +392,7 @@ struct cx23885_dev { /* Analog video */ u32 resources; unsigned int input; + unsigned int audinput; /* Selectable audio input */ u32 tvaudio; v4l2_std_id tvnorm; unsigned int tuner_type; -- cgit v0.10.2 From fa1e0fd3718417ad1e1058172fafd8cc2f480618 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:56 -0300 Subject: [media] cx23885: hook the audio selection functions into the main driver Ensure audio is established at driver start. Ensure the correct defaults are established for the audio path if the cards struct has nothing defined. Allow the caller to select one of the two baseband input paths. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 9726f2a..396fa4e 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -521,13 +521,22 @@ static int cx23885_audio_mux(struct cx23885_dev *dev, unsigned int input) { dprintk(1, "%s(input=%d)\n", __func__, input); - if ((dev->board == CX23885_BOARD_HAUPPAUGE_HVR1800) || - (dev->board == CX23885_BOARD_MPX885)) { - - if (INPUT(input)->amux == CX25840_AUDIO7) - cx23885_flatiron_mux(dev, 1); - else if (INPUT(input)->amux == CX25840_AUDIO6) - cx23885_flatiron_mux(dev, 2); + /* The baseband video core of the cx23885 has two audio inputs. + * LR1 and LR2. In almost every single case so far only HVR1xxx + * cards we've only ever supported LR1. Time to support LR2, + * which is available via the optional white breakout header on + * the board. + * We'll use a could of existing enums in the card struct to allow + * devs to specify which baseband input they need, or just default + * to what we've always used. + */ + if (INPUT(input)->amux == CX25840_AUDIO7) + cx23885_flatiron_mux(dev, 1); + else if (INPUT(input)->amux == CX25840_AUDIO6) + cx23885_flatiron_mux(dev, 2); + else { + /* Not specifically defined, assume the default. */ + cx23885_flatiron_mux(dev, 1); } return 0; @@ -1305,6 +1314,10 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) mutex_lock(&dev->lock); cx23885_video_mux(dev, i); + + /* By default establish the default audio input for the card also */ + /* Caller is free to use VIDIOC_S_AUDIO to override afterwards */ + cx23885_audio_mux(dev, i); mutex_unlock(&dev->lock); return 0; } @@ -1369,20 +1382,16 @@ static int vidioc_s_audinput(struct file *file, void *priv, struct v4l2_audio *i) { struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - /* cx23885 offers 2 different audio inputs on the A/V core, LR1 and LR2. - * By default the driver has always used LR1 and we need support for - * switching. This isn't board specific, is part of the base silicon. - */ if (i->index >= 2) return -EINVAL; dprintk(1, "%s(%d)\n", __func__, i->index); - mutex_lock(&dev->lock); dev->audinput = i->index; - cx23885_audio_mux(dev, dev->audinput); - mutex_unlock(&dev->lock); + + /* Skip the audio defaults from the cards struct, caller wants + * directly touch the audio mux hardware. */ + cx23885_flatiron_mux(dev, dev->audinput + 1); return 0; } @@ -1780,6 +1789,7 @@ int cx23885_video_register(struct cx23885_dev *dev) cx23885_set_tvnorm(dev, dev->tvnorm); init_controls(dev); cx23885_video_mux(dev, 0); + cx23885_audio_mux(dev, 0); mutex_unlock(&dev->lock); return 0; -- cgit v0.10.2 From 6c6f52fd6024b40297db32acb67f1fce6c6d1ae3 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:56 -0300 Subject: [media] cx23885: v4l2 api compliance, set the audioset field correctly Inform applications that multiple audio inputs are available on non-tv inputs. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 396fa4e..7291f64 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -1278,6 +1278,11 @@ static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) i->type = V4L2_INPUT_TYPE_TUNER; i->std = CX23885_NORMS; } + + /* Two selectable audio inputs for non-tv inputs */ + if (INPUT(n)->type != CX23885_VMUX_TELEVISION) + i->audioset = 0x3; + return 0; } -- cgit v0.10.2 From 84f42af66535a57875b72678126c4238142ad4be Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:56 -0300 Subject: [media] cx23885: Removed a spurious function cx23885_set_scale() Unused function removed. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 7291f64..65b1bd2 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -543,13 +543,6 @@ static int cx23885_audio_mux(struct cx23885_dev *dev, unsigned int input) } /* ------------------------------------------------------------------ */ -static int cx23885_set_scale(struct cx23885_dev *dev, unsigned int width, - unsigned int height, enum v4l2_field field) -{ - dprintk(1, "%s()\n", __func__); - return 0; -} - static int cx23885_start_video_dma(struct cx23885_dev *dev, struct cx23885_dmaqueue *q, struct cx23885_buffer *buf) @@ -559,7 +552,6 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev, /* setup fifo + format */ cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01], buf->bpl, buf->risc.dma); - cx23885_set_scale(dev, buf->vb.width, buf->vb.height, buf->vb.field); /* reset counter */ cx_write(VID_A_GPCNT_CTL, 3); -- cgit v0.10.2 From d44aa2d7fc9fba30cf81f25ba33f1caf73e8fbb8 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:56 -0300 Subject: [media] cx23885: Avoid stopping the risc engine during buffer timeout 1. Removed the verbose 'dump channel state to console', very noisy in weak signal conditions. 2. No need for the video buffer timeout to stop the risc engine here. Clearer and easier to maintain if start_video_dma() is the single place that this is done. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 65b1bd2..19900c6 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -1510,10 +1510,6 @@ static void cx23885_vid_timeout(unsigned long data) struct cx23885_buffer *buf; unsigned long flags; - cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]); - - cx_clear(VID_A_DMA_CTL, 0x11); - spin_lock_irqsave(&dev->slock, flags); while (!list_empty(&q->active)) { buf = list_entry(q->active.next, -- cgit v0.10.2 From 19696f09daeff897a672144be89a16b8df18c004 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:56 -0300 Subject: [media] cx23885: Avoid incorrect error handling and reporting Previous driver over-reported errors and stopped the video fifo (causing video to stop) if 1) A risc error occured 2) The risc processor detected that it has missing lines in the video frame 3) The risc fifo is about to overflow. The previous driver reported all three of these cases as risc errors when this is technically not correct. So, the function was cleaned up. 1. Ensure that risc opcode related errors are correctly shown as such, and not overly reported for non-risc-opcode cases. 2. Ensure that line sync and overflow errors are not reported as opcode errors. 3. Ensure that only the risc-op-code case can stop the fifo and dump channel / risc processor information. The net result is that if video becomes unstable, cable disconnect, this will not trigger a stop of the video firmware (due to missing lines errors). Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 19900c6..c91be47 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -1536,29 +1536,29 @@ int cx23885_video_irq(struct cx23885_dev *dev, u32 status) cx_write(VID_A_INT_STAT, status); - /* risc op code error */ + /* risc op code error, fifo overflow or line sync detection error */ if ((status & VID_BC_MSK_OPC_ERR) || (status & VID_BC_MSK_SYNC) || (status & VID_BC_MSK_OF)) { - if (status & VID_BC_MSK_OPC_ERR) + if (status & VID_BC_MSK_OPC_ERR) { dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n", VID_BC_MSK_OPC_ERR); + printk(KERN_WARNING "%s: video risc op code error\n", + dev->name); + cx23885_sram_channel_dump(dev, + &dev->sram_channels[SRAM_CH01]); + } if (status & VID_BC_MSK_SYNC) - dprintk(7, " (VID_BC_MSK_SYNC 0x%08x)\n", + dprintk(7, " (VID_BC_MSK_SYNC 0x%08x) " + "video lines miss-match\n", VID_BC_MSK_SYNC); if (status & VID_BC_MSK_OF) - dprintk(7, " (VID_BC_MSK_OF 0x%08x)\n", + dprintk(7, " (VID_BC_MSK_OF 0x%08x) fifo overflow\n", VID_BC_MSK_OF); - printk(KERN_WARNING "%s: video risc op code error\n", - dev->name); - - cx_clear(VID_A_DMA_CTL, 0x11); - cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]); - } /* Video */ -- cgit v0.10.2 From a461e0ad3d27b6342140566909a80db30d151a91 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 10 Oct 2011 11:09:56 -0300 Subject: [media] cx23885: Stop the risc video fifo before reconfiguring it Safety reasons. We shouldn't be trying to reconfigure a risc processor instruction queue unless it's stopped. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index c91be47..e730b92 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -549,6 +549,9 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev, { dprintk(1, "%s()\n", __func__); + /* Stop the dma/fifo before we tamper with it's risc programs */ + cx_clear(VID_A_DMA_CTL, 0x11); + /* setup fifo + format */ cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01], buf->bpl, buf->risc.dma); -- cgit v0.10.2 From 1c5c50685a04668a4a4431534bca804969fac3c6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 16 Oct 2011 13:52:43 -0200 Subject: [media] em28xx: implement VIDIOC_ENUM_FRAMESIZES Pidgin uses gstreamer (and libv4l) to work. Without implementing this ioctl, it won't detect properly the size range, and driver will fail. So, this patch is required, in order to use an em27xx webcam, like Silvercrest. The pigdin/gstreamer/libv4l needs to be fixed, as it shouldn't assume that all drivers will implement this optional ioctl, but, at least now, devices with em28xx have a better chance of working with pidgin. Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 62182e3..9b4557a 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -1802,6 +1802,45 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, return 0; } +static int vidioc_enum_framesizes(struct file *file, void *priv, + struct v4l2_frmsizeenum *fsize) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + struct em28xx_fmt *fmt; + unsigned int maxw = norm_maxw(dev); + unsigned int maxh = norm_maxh(dev); + + fmt = format_by_fourcc(fsize->pixel_format); + if (!fmt) { + em28xx_videodbg("Fourcc format (%08x) invalid.\n", + fsize->pixel_format); + return -EINVAL; + } + + if (dev->board.is_em2800) { + if (fsize->index > 1) + return -EINVAL; + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = maxw / (1 + fsize->index); + fsize->discrete.height = maxh / (1 + fsize->index); + return 0; + } + + if (fsize->index != 0) + return -EINVAL; + + /* Report a continuous range */ + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise.min_width = 48; + fsize->stepwise.min_height = 32; + fsize->stepwise.max_width = maxw; + fsize->stepwise.max_height = maxh; + fsize->stepwise.step_width = 1; + fsize->stepwise.step_height = 1; + return 0; +} + /* Sliced VBI ioctls */ static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv, struct v4l2_format *f) @@ -2356,10 +2395,10 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, .vidioc_s_fmt_vbi_cap = vidioc_s_fmt_vbi_cap, + .vidioc_enum_framesizes = vidioc_enum_framesizes, .vidioc_g_audio = vidioc_g_audio, .vidioc_s_audio = vidioc_s_audio, .vidioc_cropcap = vidioc_cropcap, - .vidioc_g_fmt_sliced_vbi_cap = vidioc_g_fmt_sliced_vbi_cap, .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap, .vidioc_s_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap, -- cgit v0.10.2 From 4c2625db6f172114bcc4fd9e62f3c030c5fb4e4c Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 3 Oct 2011 03:21:45 -0300 Subject: [media] media: vb2: fix incorrect return value This patch fixes incorrect return value. Errors should be returned as negative numbers. Reported-by: Tomasz Stanislawski Signed-off-by: Marek Szyprowski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 6687ac3..3f5c7a3 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -751,7 +751,7 @@ static int __qbuf_userptr(struct vb2_buffer *vb, struct v4l2_buffer *b) /* Check if the provided plane buffer is large enough */ if (planes[plane].length < q->plane_sizes[plane]) { - ret = EINVAL; + ret = -EINVAL; goto err; } -- cgit v0.10.2 From f1a84c9b0a962a940a1f8b9202d84842e54e8d7c Mon Sep 17 00:00:00 2001 From: Christian Gmeiner Date: Wed, 5 Oct 2011 17:48:43 -0300 Subject: [media] adv7175: Make use of media bus pixel codes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ADV7175A/ADV7176A can operate in either 8-bit or 16-bit YCrCb mode. * 8-Bit YCrCb Mode This default mode accepts multiplexed YCrCb inputs through the P7-P0 pixel inputs. The inputs follow the sequence Cb0, Y0 Cr0, Y1 Cb1, Y2, etc. The Y, Cb and Cr data are input on a rising clock edge. * 16-Bit YCrCb Mode This mode accepts Y inputs through the P7–P0 pixel inputs and multiplexed CrCb inputs through the P15–P8 pixel inputs. The data is loaded on every second rising edge of CLOCK. The inputs follow the sequence Cb0, Y0 Cr0, Y1 Cb1, Y2, etc. Signed-off-by: Christian Gmeiner Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c index d2327db..206078e 100644 --- a/drivers/media/video/adv7175.c +++ b/drivers/media/video/adv7175.c @@ -61,6 +61,11 @@ static inline struct adv7175 *to_adv7175(struct v4l2_subdev *sd) static char *inputs[] = { "pass_through", "play_back", "color_bar" }; +static enum v4l2_mbus_pixelcode adv7175_codes[] = { + V4L2_MBUS_FMT_UYVY8_2X8, + V4L2_MBUS_FMT_UYVY8_1X16, +}; + /* ----------------------------------------------------------------------- */ static inline int adv7175_write(struct v4l2_subdev *sd, u8 reg, u8 value) @@ -296,6 +301,60 @@ static int adv7175_s_routing(struct v4l2_subdev *sd, return 0; } +static int adv7175_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + if (index >= ARRAY_SIZE(adv7175_codes)) + return -EINVAL; + + *code = adv7175_codes[index]; + return 0; +} + +static int adv7175_g_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + u8 val = adv7175_read(sd, 0x7); + + if ((val & 0x40) == (1 << 6)) + mf->code = V4L2_MBUS_FMT_UYVY8_1X16; + else + mf->code = V4L2_MBUS_FMT_UYVY8_2X8; + + mf->colorspace = V4L2_COLORSPACE_SMPTE170M; + mf->width = 0; + mf->height = 0; + mf->field = V4L2_FIELD_ANY; + + return 0; +} + +static int adv7175_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + u8 val = adv7175_read(sd, 0x7); + int ret; + + switch (mf->code) { + case V4L2_MBUS_FMT_UYVY8_2X8: + val &= ~0x40; + break; + + case V4L2_MBUS_FMT_UYVY8_1X16: + val |= 0x40; + break; + + default: + v4l2_dbg(1, debug, sd, + "illegal v4l2_mbus_framefmt code: %d\n", mf->code); + return -EINVAL; + } + + ret = adv7175_write(sd, 0x7, val); + + return ret; +} + static int adv7175_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -324,6 +383,9 @@ static const struct v4l2_subdev_core_ops adv7175_core_ops = { static const struct v4l2_subdev_video_ops adv7175_video_ops = { .s_std_output = adv7175_s_std_output, .s_routing = adv7175_s_routing, + .s_mbus_fmt = adv7175_s_fmt, + .g_mbus_fmt = adv7175_g_fmt, + .enum_mbus_fmt = adv7175_enum_fmt, }; static const struct v4l2_subdev_ops adv7175_ops = { -- cgit v0.10.2 From bac2dacd5fb9ddad093d7a2dc5ab44e764874821 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Thu, 6 Oct 2011 05:15:22 -0300 Subject: [media] pctv452e: Remove bogus code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, usb_register calls two times with cloned structures, but for different driver names. Let's remove it. Signed-off-by: Igor M. Liplianin Acked-by: André Weidemann Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/pctv452e.c b/drivers/media/dvb/dvb-usb/pctv452e.c index 9a5c811..f9aec5c 100644 --- a/drivers/media/dvb/dvb-usb/pctv452e.c +++ b/drivers/media/dvb/dvb-usb/pctv452e.c @@ -1012,7 +1012,7 @@ static struct dvb_usb_device_properties tt_connect_s2_3600_properties = { .i2c_algo = &pctv452e_i2c_algo, - .generic_bulk_ctrl_endpoint = 1, /* allow generice rw function*/ + .generic_bulk_ctrl_endpoint = 1, /* allow generic rw function*/ .num_device_descs = 2, .devices = { @@ -1055,22 +1055,9 @@ static struct usb_driver pctv452e_usb_driver = { .id_table = pctv452e_usb_table, }; -static struct usb_driver tt_connects2_3600_usb_driver = { - .name = "dvb-usb-tt-connect-s2-3600-01.fw", - .probe = pctv452e_usb_probe, - .disconnect = pctv452e_usb_disconnect, - .id_table = pctv452e_usb_table, -}; - static int __init pctv452e_usb_init(void) { int ret = usb_register(&pctv452e_usb_driver); - - if (ret) { - err("%s: usb_register failed! Error %d", __FILE__, ret); - return ret; - } - ret = usb_register(&tt_connects2_3600_usb_driver); if (ret) err("%s: usb_register failed! Error %d", __FILE__, ret); @@ -1080,7 +1067,6 @@ static int __init pctv452e_usb_init(void) static void __exit pctv452e_usb_exit(void) { usb_deregister(&pctv452e_usb_driver); - usb_deregister(&tt_connects2_3600_usb_driver); } module_init(pctv452e_usb_init); -- cgit v0.10.2