aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/usb/em28xx/em28xx-cards.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/usb/em28xx/em28xx-cards.c')
-rw-r--r--drivers/media/usb/em28xx/em28xx-cards.c168
1 files changed, 147 insertions, 21 deletions
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 4d97a76cc3b..15ad4704555 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -66,7 +66,7 @@ MODULE_PARM_DESC(usb_xfer_mode,
/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS - 1 */
-DECLARE_BITMAP(em28xx_devused, EM28XX_MAXBOARDS);
+static DECLARE_BITMAP(em28xx_devused, EM28XX_MAXBOARDS);
struct em28xx_hash_table {
unsigned long hash;
@@ -189,6 +189,14 @@ static struct em28xx_reg_seq kworld_a340_digital[] = {
{ -1, -1, -1, -1},
};
+static struct em28xx_reg_seq kworld_ub435q_v3_digital[] = {
+ {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xfe, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xbe, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xfe, 0xff, 100},
+ { -1, -1, -1, -1},
+};
+
/* Pinnacle Hybrid Pro eb1a:2881 */
static struct em28xx_reg_seq pinnacle_hybrid_pro_analog[] = {
{EM2820_R08_GPIO_CTRL, 0xfd, ~EM_GPIO_4, 10},
@@ -214,6 +222,17 @@ static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_digital[] = {
{ -1, -1, -1, -1},
};
+/* PCTV HD Mini (80e) GPIOs
+ 0-5: not used
+ 6: demod reset, active low
+ 7: LED on, active high */
+static struct em28xx_reg_seq em2874_pctv_80e_digital[] = {
+ {EM28XX_R06_I2C_CLK, 0x45, 0xff, 10}, /*400 KHz*/
+ {EM2874_R80_GPIO_P0_CTRL, 0x00, 0xff, 100},/*Demod reset*/
+ {EM2874_R80_GPIO_P0_CTRL, 0x40, 0xff, 10},
+ { -1, -1, -1, -1},
+};
+
/* eb1a:2868 Reddo DVB-C USB TV Box
GPIO4 - CU1216L NIM
Other GPIOs seems to be don't care. */
@@ -448,6 +467,18 @@ static struct em28xx_reg_seq speedlink_vad_laplace_reg_seq[] = {
{ -1, -1, -1, -1},
};
+static struct em28xx_reg_seq pctv_292e[] = {
+ {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0},
+ {0x0d, 0xff, 0xff, 950},
+ {EM2874_R80_GPIO_P0_CTRL, 0xbd, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xfd, 0xff, 410},
+ {EM2874_R80_GPIO_P0_CTRL, 0x7d, 0xff, 300},
+ {EM2874_R80_GPIO_P0_CTRL, 0x7c, 0xff, 60},
+ {0x0d, 0x42, 0xff, 50},
+ {EM2874_R5F_TS_ENABLE, 0x85, 0xff, 0},
+ {-1, -1, -1, -1},
+};
+
/*
* Button definitions
*/
@@ -497,6 +528,27 @@ static struct em28xx_led speedlink_vad_laplace_leds[] = {
{-1, 0, 0, 0},
};
+static struct em28xx_led kworld_ub435q_v3_leds[] = {
+ {
+ .role = EM28XX_LED_DIGITAL_CAPTURING,
+ .gpio_reg = EM2874_R80_GPIO_P0_CTRL,
+ .gpio_mask = 0x80,
+ .inverted = 1,
+ },
+ {-1, 0, 0, 0},
+};
+
+static struct em28xx_led pctv_80e_leds[] = {
+ {
+ .role = EM28XX_LED_DIGITAL_CAPTURING,
+ .gpio_reg = EM2874_R80_GPIO_P0_CTRL,
+ .gpio_mask = 0x80,
+ .inverted = 0,
+ },
+ {-1, 0, 0, 0},
+};
+
+
/*
* Board definitions
*/
@@ -2128,6 +2180,29 @@ struct em28xx_board em28xx_boards[] = {
.tuner_gpio = default_tuner_gpio,
.def_i2c_bus = 1,
},
+ /*
+ * 1b80:e34c KWorld USB ATSC TV Stick UB435-Q V3
+ * Empia EM2874B + LG DT3305 + NXP TDA18271HDC2
+ */
+ [EM2874_BOARD_KWORLD_UB435Q_V3] = {
+ .name = "KWorld USB ATSC TV Stick UB435-Q V3",
+ .tuner_type = TUNER_ABSENT,
+ .has_dvb = 1,
+ .tuner_gpio = kworld_ub435q_v3_digital,
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_100_KHZ,
+ .leds = kworld_ub435q_v3_leds,
+ },
+ [EM2874_BOARD_PCTV_HD_MINI_80E] = {
+ .name = "Pinnacle PCTV HD Mini",
+ .tuner_type = TUNER_ABSENT,
+ .has_dvb = 1,
+ .dvb_gpio = em2874_pctv_80e_digital,
+ .decoder = EM28XX_NODECODER,
+ .ir_codes = RC_MAP_PINNACLE_PCTV_HD,
+ .leds = pctv_80e_leds,
+ },
/* 1ae7:9003/9004 SpeedLink Vicious And Devine Laplace webcam
* Empia EM2765 + OmniVision OV2640 */
[EM2765_BOARD_SPEEDLINK_VAD_LAPLACE] = {
@@ -2157,6 +2232,17 @@ struct em28xx_board em28xx_boards[] = {
.has_dvb = 1,
.ir_codes = RC_MAP_PINNACLE_PCTV_HD,
},
+ /* 2013:025f PCTV tripleStick (292e).
+ * Empia EM28178, Silicon Labs Si2168, Silicon Labs Si2157 */
+ [EM28178_BOARD_PCTV_292E] = {
+ .name = "PCTV tripleStick (292e)",
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ,
+ .tuner_type = TUNER_ABSENT,
+ .tuner_gpio = pctv_292e,
+ .has_dvb = 1,
+ .ir_codes = RC_MAP_PINNACLE_PCTV_HD,
+ },
};
EXPORT_SYMBOL_GPL(em28xx_boards);
@@ -2290,6 +2376,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2882_BOARD_PINNACLE_HYBRID_PRO_330E },
{ USB_DEVICE(0x2304, 0x0227),
.driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO },
+ { USB_DEVICE(0x2304, 0x023f),
+ .driver_info = EM2874_BOARD_PCTV_HD_MINI_80E },
{ USB_DEVICE(0x0413, 0x6023),
.driver_info = EM2800_BOARD_LEADTEK_WINFAST_USBII },
{ USB_DEVICE(0x093b, 0xa003),
@@ -2304,6 +2392,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2870_BOARD_KWORLD_A340 },
{ USB_DEVICE(0x1b80, 0xe346),
.driver_info = EM2874_BOARD_KWORLD_UB435Q_V2 },
+ { USB_DEVICE(0x1b80, 0xe34c),
+ .driver_info = EM2874_BOARD_KWORLD_UB435Q_V3 },
{ USB_DEVICE(0x2013, 0x024f),
.driver_info = EM28174_BOARD_PCTV_290E },
{ USB_DEVICE(0x2013, 0x024c),
@@ -2330,6 +2420,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2765_BOARD_SPEEDLINK_VAD_LAPLACE },
{ USB_DEVICE(0x2013, 0x0258),
.driver_info = EM28178_BOARD_PCTV_461E },
+ { USB_DEVICE(0x2013, 0x025f),
+ .driver_info = EM28178_BOARD_PCTV_292E },
{ },
};
MODULE_DEVICE_TABLE(usb, em28xx_id_table);
@@ -2615,8 +2707,6 @@ static void em28xx_card_setup(struct em28xx *dev)
if (dev->board.is_webcam) {
if (em28xx_detect_sensor(dev) < 0)
dev->board.is_webcam = 0;
- else
- dev->progressive = 1;
}
switch (dev->model) {
@@ -2651,11 +2741,6 @@ static void em28xx_card_setup(struct em28xx *dev)
dev->board.name, dev->model);
dev->tuner_type = em28xx_boards[dev->model].tuner_type;
- if (em28xx_boards[dev->model].tuner_addr)
- dev->tuner_addr = em28xx_boards[dev->model].tuner_addr;
-
- if (em28xx_boards[dev->model].tda9887_conf)
- dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf;
/* request some modules */
switch (dev->model) {
@@ -2872,7 +2957,7 @@ static void flush_request_modules(struct em28xx *dev)
* unregisters the v4l2,i2c and usb devices
* called when the device gets disconnected or at module unload
*/
-void em28xx_release_resources(struct em28xx *dev)
+static void em28xx_release_resources(struct em28xx *dev)
{
/*FIXME: I2C IR should be disconnected */
@@ -2889,7 +2974,27 @@ void em28xx_release_resources(struct em28xx *dev)
mutex_unlock(&dev->lock);
};
-EXPORT_SYMBOL_GPL(em28xx_release_resources);
+
+/**
+ * em28xx_free_device() - Free em28xx device
+ *
+ * @ref: struct kref for em28xx device
+ *
+ * This is called when all extensions and em28xx core unregisters a device
+ */
+void em28xx_free_device(struct kref *ref)
+{
+ struct em28xx *dev = kref_to_dev(ref);
+
+ em28xx_info("Freeing device\n");
+
+ if (!dev->disconnected)
+ em28xx_release_resources(dev);
+
+ kfree(dev->alt_max_pkt_size_isoc);
+ kfree(dev);
+}
+EXPORT_SYMBOL_GPL(em28xx_free_device);
/*
* em28xx_init_dev()
@@ -2904,8 +3009,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
const char *chip_name = default_chip_name;
dev->udev = udev;
- mutex_init(&dev->vb_queue_lock);
- mutex_init(&dev->vb_vbi_queue_lock);
mutex_init(&dev->ctrl_urb_lock);
spin_lock_init(&dev->slock);
@@ -3329,19 +3432,20 @@ static int em28xx_usb_probe(struct usb_interface *interface,
/* Select USB transfer types to use */
if (has_video) {
- if (!dev->analog_ep_isoc || (try_bulk && dev->analog_ep_bulk))
- dev->analog_xfer_bulk = 1;
+ if (!dev->analog_ep_isoc || (try_bulk && dev->analog_ep_bulk))
+ dev->analog_xfer_bulk = 1;
em28xx_info("analog set to %s mode.\n",
dev->analog_xfer_bulk ? "bulk" : "isoc");
}
if (has_dvb) {
- if (!dev->dvb_ep_isoc || (try_bulk && dev->dvb_ep_bulk))
- dev->dvb_xfer_bulk = 1;
-
+ if (!dev->dvb_ep_isoc || (try_bulk && dev->dvb_ep_bulk))
+ dev->dvb_xfer_bulk = 1;
em28xx_info("dvb set to %s mode.\n",
dev->dvb_xfer_bulk ? "bulk" : "isoc");
}
+ kref_init(&dev->ref);
+
request_modules(dev);
/* Should be the last thing to do, to avoid newer udev's to
@@ -3386,17 +3490,39 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
em28xx_close_extension(dev);
em28xx_release_resources(dev);
+ kref_put(&dev->ref, em28xx_free_device);
+}
- if (!dev->users) {
- kfree(dev->alt_max_pkt_size_isoc);
- kfree(dev);
- }
+static int em28xx_usb_suspend(struct usb_interface *interface,
+ pm_message_t message)
+{
+ struct em28xx *dev;
+
+ dev = usb_get_intfdata(interface);
+ if (!dev)
+ return 0;
+ em28xx_suspend_extension(dev);
+ return 0;
+}
+
+static int em28xx_usb_resume(struct usb_interface *interface)
+{
+ struct em28xx *dev;
+
+ dev = usb_get_intfdata(interface);
+ if (!dev)
+ return 0;
+ em28xx_resume_extension(dev);
+ return 0;
}
static struct usb_driver em28xx_usb_driver = {
.name = "em28xx",
.probe = em28xx_usb_probe,
.disconnect = em28xx_usb_disconnect,
+ .suspend = em28xx_usb_suspend,
+ .resume = em28xx_usb_resume,
+ .reset_resume = em28xx_usb_resume,
.id_table = em28xx_id_table,
};