summaryrefslogtreecommitdiff
path: root/drivers/media/usb/em28xx
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/usb/em28xx')
-rw-r--r--drivers/media/usb/em28xx/em28xx-camera.c4
-rw-r--r--drivers/media/usb/em28xx/em28xx-cards.c3
-rw-r--r--drivers/media/usb/em28xx/em28xx-dvb.c40
-rw-r--r--drivers/media/usb/em28xx/em28xx-i2c.c6
-rw-r--r--drivers/media/usb/em28xx/em28xx-input.c106
-rw-r--r--drivers/media/usb/em28xx/em28xx-video.c116
-rw-r--r--drivers/media/usb/em28xx/em28xx.h8
7 files changed, 136 insertions, 147 deletions
diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
index 12d4c0326e31..6d2ea9afd57b 100644
--- a/drivers/media/usb/em28xx/em28xx-camera.c
+++ b/drivers/media/usb/em28xx/em28xx-camera.c
@@ -366,7 +366,7 @@ int em28xx_init_camera(struct em28xx *dev)
v4l2->sensor_xtal = 4300000;
pdata.xtal = v4l2->sensor_xtal;
if (NULL ==
- v4l2_i2c_new_subdev_board(&dev->v4l2->v4l2_dev, adap,
+ v4l2_i2c_new_subdev_board(&v4l2->v4l2_dev, adap,
&mt9v011_info, NULL)) {
ret = -ENODEV;
break;
@@ -423,7 +423,7 @@ int em28xx_init_camera(struct em28xx *dev)
v4l2->sensor_yres = 480;
subdev =
- v4l2_i2c_new_subdev_board(&dev->v4l2->v4l2_dev, adap,
+ v4l2_i2c_new_subdev_board(&v4l2->v4l2_dev, adap,
&ov2640_info, NULL);
if (NULL == subdev) {
ret = -ENODEV;
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 15ad47045553..a7e24848f6c8 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -2280,6 +2280,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2820_BOARD_UNKNOWN },
{ USB_DEVICE(0xeb1a, 0x2875),
.driver_info = EM2820_BOARD_UNKNOWN },
+ { USB_DEVICE(0xeb1a, 0x2885), /* MSI Digivox Trio */
+ .driver_info = EM2884_BOARD_TERRATEC_H5 },
{ USB_DEVICE(0xeb1a, 0xe300),
.driver_info = EM2861_BOARD_KWORLD_PVRTV_300U },
{ USB_DEVICE(0xeb1a, 0xe303),
@@ -3522,7 +3524,6 @@ static struct usb_driver em28xx_usb_driver = {
.disconnect = em28xx_usb_disconnect,
.suspend = em28xx_usb_suspend,
.resume = em28xx_usb_resume,
- .reset_resume = em28xx_usb_resume,
.id_table = em28xx_id_table,
};
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index a121ed9561fd..3a3e243edf89 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -1213,9 +1213,17 @@ static int em28xx_dvb_init(struct em28xx *dev)
dvb->fe[0] = dvb_attach(lgdt3305_attach,
&em2870_lgdt3304_dev,
&dev->i2c_adap[dev->def_i2c_bus]);
- if (dvb->fe[0] != NULL)
- dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
- &dev->i2c_adap[dev->def_i2c_bus], &kworld_a340_config);
+ if (!dvb->fe[0]) {
+ result = -EINVAL;
+ goto out_free;
+ }
+ if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ &kworld_a340_config)) {
+ dvb_frontend_detach(dvb->fe[0]);
+ result = -EINVAL;
+ goto out_free;
+ }
break;
case EM28174_BOARD_PCTV_290E:
/* set default GPIO0 for LNA, used if GPIOLIB is undefined */
@@ -1545,6 +1553,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
dvb->i2c_client_demod = client;
/* attach tuner */
+ memset(&si2157_config, 0, sizeof(si2157_config));
si2157_config.fe = dvb->fe[0];
memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, "si2157", I2C_NAME_SIZE);
@@ -1645,10 +1654,14 @@ static int em28xx_dvb_fini(struct em28xx *dev)
if (dev->disconnected) {
/* We cannot tell the device to sleep
* once it has been unplugged. */
- if (dvb->fe[0])
+ if (dvb->fe[0]) {
prevent_sleep(&dvb->fe[0]->ops);
- if (dvb->fe[1])
+ dvb->fe[0]->exit = DVB_FE_DEVICE_REMOVED;
+ }
+ if (dvb->fe[1]) {
prevent_sleep(&dvb->fe[1]->ops);
+ dvb->fe[1]->exit = DVB_FE_DEVICE_REMOVED;
+ }
}
/* remove I2C tuner */
@@ -1712,7 +1725,6 @@ static int em28xx_dvb_resume(struct em28xx *dev)
em28xx_info("Resuming DVB extension");
if (dev->dvb) {
struct em28xx_dvb *dvb = dev->dvb;
- struct i2c_client *client = dvb->i2c_client_tuner;
if (dvb->fe[0]) {
ret = dvb_frontend_resume(dvb->fe[0]);
@@ -1723,22 +1735,6 @@ static int em28xx_dvb_resume(struct em28xx *dev)
ret = dvb_frontend_resume(dvb->fe[1]);
em28xx_info("fe1 resume %d", ret);
}
- /* remove I2C tuner */
- if (client) {
- module_put(client->dev.driver->owner);
- i2c_unregister_device(client);
- }
-
- /* remove I2C demod */
- client = dvb->i2c_client_demod;
- if (client) {
- module_put(client->dev.driver->owner);
- i2c_unregister_device(client);
- }
-
- em28xx_unregister_dvb(dvb);
- kfree(dvb);
- dev->dvb = NULL;
}
return 0;
diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
index b58d4ebf6419..1048c1a23fb6 100644
--- a/drivers/media/usb/em28xx/em28xx-i2c.c
+++ b/drivers/media/usb/em28xx/em28xx-i2c.c
@@ -501,6 +501,12 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
int addr, rc, i;
u8 reg;
+ /* prevent i2c xfer attempts after device is disconnected
+ some fe's try to do i2c writes/reads from their release
+ interfaces when called in disconnect path */
+ if (dev->disconnected)
+ return -ENODEV;
+
rc = rt_mutex_trylock(&dev->i2c_bus_lock);
if (rc < 0)
return rc;
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index 56ef49df4f8d..ed843bd221ea 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -27,6 +27,7 @@
#include <linux/interrupt.h>
#include <linux/usb.h>
#include <linux/slab.h>
+#include <linux/bitrev.h>
#include "em28xx.h"
@@ -53,6 +54,7 @@ struct em28xx_ir_poll_result {
unsigned int toggle_bit:1;
unsigned int read_count:7;
+ enum rc_type protocol;
u32 scancode;
};
@@ -72,7 +74,7 @@ struct em28xx_IR {
/* i2c slave address of external device (if used) */
u16 i2c_dev_addr;
- int (*get_key_i2c)(struct i2c_client *, u32 *);
+ int (*get_key_i2c)(struct i2c_client *ir, enum rc_type *protocol, u32 *scancode);
int (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *);
};
@@ -80,7 +82,8 @@ struct em28xx_IR {
I2C IR based get keycodes - should be used with ir-kbd-i2c
**********************************************************/
-static int em28xx_get_key_terratec(struct i2c_client *i2c_dev, u32 *ir_key)
+static int em28xx_get_key_terratec(struct i2c_client *i2c_dev,
+ enum rc_type *protocol, u32 *scancode)
{
unsigned char b;
@@ -98,14 +101,15 @@ static int em28xx_get_key_terratec(struct i2c_client *i2c_dev, u32 *ir_key)
/* keep old data */
return 1;
- *ir_key = b;
+ *protocol = RC_TYPE_UNKNOWN;
+ *scancode = b;
return 1;
}
-static int em28xx_get_key_em_haup(struct i2c_client *i2c_dev, u32 *ir_key)
+static int em28xx_get_key_em_haup(struct i2c_client *i2c_dev,
+ enum rc_type *protocol, u32 *scancode)
{
unsigned char buf[2];
- u16 code;
int size;
/* poll IR chip */
@@ -127,26 +131,13 @@ static int em28xx_get_key_em_haup(struct i2c_client *i2c_dev, u32 *ir_key)
* So, the code translation is not complete. Yet, it is enough to
* work with the provided RC5 IR.
*/
- code =
- ((buf[0] & 0x01) ? 0x0020 : 0) | /* 0010 0000 */
- ((buf[0] & 0x02) ? 0x0010 : 0) | /* 0001 0000 */
- ((buf[0] & 0x04) ? 0x0008 : 0) | /* 0000 1000 */
- ((buf[0] & 0x08) ? 0x0004 : 0) | /* 0000 0100 */
- ((buf[0] & 0x10) ? 0x0002 : 0) | /* 0000 0010 */
- ((buf[0] & 0x20) ? 0x0001 : 0) | /* 0000 0001 */
- ((buf[1] & 0x08) ? 0x1000 : 0) | /* 0001 0000 */
- ((buf[1] & 0x10) ? 0x0800 : 0) | /* 0000 1000 */
- ((buf[1] & 0x20) ? 0x0400 : 0) | /* 0000 0100 */
- ((buf[1] & 0x40) ? 0x0200 : 0) | /* 0000 0010 */
- ((buf[1] & 0x80) ? 0x0100 : 0); /* 0000 0001 */
-
- /* return key */
- *ir_key = code;
+ *protocol = RC_TYPE_RC5;
+ *scancode = (bitrev8(buf[1]) & 0x1f) << 8 | bitrev8(buf[0]) >> 2;
return 1;
}
static int em28xx_get_key_pinnacle_usb_grey(struct i2c_client *i2c_dev,
- u32 *ir_key)
+ enum rc_type *protocol, u32 *scancode)
{
unsigned char buf[3];
@@ -158,13 +149,13 @@ static int em28xx_get_key_pinnacle_usb_grey(struct i2c_client *i2c_dev,
if (buf[0] != 0x00)
return 0;
- *ir_key = buf[2]&0x3f;
-
+ *protocol = RC_TYPE_UNKNOWN;
+ *scancode = buf[2] & 0x3f;
return 1;
}
static int em28xx_get_key_winfast_usbii_deluxe(struct i2c_client *i2c_dev,
- u32 *ir_key)
+ enum rc_type *protocol, u32 *scancode)
{
unsigned char subaddr, keydetect, key;
@@ -184,7 +175,8 @@ static int em28xx_get_key_winfast_usbii_deluxe(struct i2c_client *i2c_dev,
if (key == 0x00)
return 0;
- *ir_key = key;
+ *protocol = RC_TYPE_UNKNOWN;
+ *scancode = key;
return 1;
}
@@ -215,7 +207,22 @@ static int default_polling_getkey(struct em28xx_IR *ir,
poll_result->read_count = (msg[0] & 0x7f);
/* Remote Control Address/Data (Regs 0x46/0x47) */
- poll_result->scancode = msg[1] << 8 | msg[2];
+ switch (ir->rc_type) {
+ case RC_BIT_RC5:
+ poll_result->protocol = RC_TYPE_RC5;
+ poll_result->scancode = RC_SCANCODE_RC5(msg[1], msg[2]);
+ break;
+
+ case RC_BIT_NEC:
+ poll_result->protocol = RC_TYPE_NEC;
+ poll_result->scancode = RC_SCANCODE_NEC(msg[1], msg[2]);
+ break;
+
+ default:
+ poll_result->protocol = RC_TYPE_UNKNOWN;
+ poll_result->scancode = msg[1] << 8 | msg[2];
+ break;
+ }
return 0;
}
@@ -247,25 +254,32 @@ static int em2874_polling_getkey(struct em28xx_IR *ir,
*/
switch (ir->rc_type) {
case RC_BIT_RC5:
- poll_result->scancode = msg[1] << 8 | msg[2];
+ poll_result->protocol = RC_TYPE_RC5;
+ poll_result->scancode = RC_SCANCODE_RC5(msg[1], msg[2]);
break;
+
case RC_BIT_NEC:
+ poll_result->protocol = RC_TYPE_RC5;
+ poll_result->scancode = msg[1] << 8 | msg[2];
if ((msg[3] ^ msg[4]) != 0xff) /* 32 bits NEC */
- poll_result->scancode = (msg[1] << 24) |
- (msg[2] << 16) |
- (msg[3] << 8) |
- msg[4];
+ poll_result->scancode = RC_SCANCODE_NEC32((msg[1] << 24) |
+ (msg[2] << 16) |
+ (msg[3] << 8) |
+ (msg[4]));
else if ((msg[1] ^ msg[2]) != 0xff) /* 24 bits NEC */
- poll_result->scancode = (msg[1] << 16) |
- (msg[2] << 8) |
- msg[3];
+ poll_result->scancode = RC_SCANCODE_NECX(msg[1] << 8 |
+ msg[2], msg[3]);
else /* Normal NEC */
- poll_result->scancode = msg[1] << 8 | msg[3];
+ poll_result->scancode = RC_SCANCODE_NEC(msg[1], msg[3]);
break;
+
case RC_BIT_RC6_0:
- poll_result->scancode = msg[1] << 8 | msg[2];
+ poll_result->protocol = RC_TYPE_RC6_0;
+ poll_result->scancode = RC_SCANCODE_RC6_0(msg[1], msg[2]);
break;
+
default:
+ poll_result->protocol = RC_TYPE_UNKNOWN;
poll_result->scancode = (msg[1] << 24) | (msg[2] << 16) |
(msg[3] << 8) | msg[4];
break;
@@ -281,22 +295,24 @@ static int em2874_polling_getkey(struct em28xx_IR *ir,
static int em28xx_i2c_ir_handle_key(struct em28xx_IR *ir)
{
struct em28xx *dev = ir->dev;
- static u32 ir_key;
+ static u32 scancode;
+ enum rc_type protocol;
int rc;
struct i2c_client client;
client.adapter = &ir->dev->i2c_adap[dev->def_i2c_bus];
client.addr = ir->i2c_dev_addr;
- rc = ir->get_key_i2c(&client, &ir_key);
+ rc = ir->get_key_i2c(&client, &protocol, &scancode);
if (rc < 0) {
dprintk("ir->get_key_i2c() failed: %d\n", rc);
return rc;
}
if (rc) {
- dprintk("%s: keycode = 0x%04x\n", __func__, ir_key);
- rc_keydown(ir->rc, ir_key, 0);
+ dprintk("%s: proto = 0x%04x, scancode = 0x%04x\n",
+ __func__, protocol, scancode);
+ rc_keydown(ir->rc, protocol, scancode, 0);
}
return 0;
}
@@ -319,10 +335,12 @@ static void em28xx_ir_handle_key(struct em28xx_IR *ir)
poll_result.scancode);
if (ir->full_code)
rc_keydown(ir->rc,
+ poll_result.protocol,
poll_result.scancode,
poll_result.toggle_bit);
else
rc_keydown(ir->rc,
+ RC_TYPE_UNKNOWN,
poll_result.scancode & 0xff,
poll_result.toggle_bit);
@@ -727,7 +745,7 @@ static int em28xx_ir_init(struct em28xx *dev)
case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
rc->map_name = RC_MAP_HAUPPAUGE;
ir->get_key_i2c = em28xx_get_key_em_haup;
- rc_set_allowed_protocols(rc, RC_BIT_RC5);
+ rc->allowed_protocols = RC_BIT_RC5;
break;
case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE:
rc->map_name = RC_MAP_WINFAST_USBII_DELUXE;
@@ -743,7 +761,7 @@ static int em28xx_ir_init(struct em28xx *dev)
switch (dev->chip_id) {
case CHIP_ID_EM2860:
case CHIP_ID_EM2883:
- rc_set_allowed_protocols(rc, RC_BIT_RC5 | RC_BIT_NEC);
+ rc->allowed_protocols = RC_BIT_RC5 | RC_BIT_NEC;
ir->get_key = default_polling_getkey;
break;
case CHIP_ID_EM2884:
@@ -751,8 +769,8 @@ static int em28xx_ir_init(struct em28xx *dev)
case CHIP_ID_EM28174:
case CHIP_ID_EM28178:
ir->get_key = em2874_polling_getkey;
- rc_set_allowed_protocols(rc, RC_BIT_RC5 | RC_BIT_NEC |
- RC_BIT_RC6_0);
+ rc->allowed_protocols = RC_BIT_RC5 | RC_BIT_NEC |
+ RC_BIT_RC6_0;
break;
default:
err = -ENODEV;
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index f6b49c98e2c9..90dec2955f1c 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1227,8 +1227,7 @@ static void scale_to_size(struct em28xx *dev,
static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
f->fmt.pix.width = v4l2->width;
@@ -1261,8 +1260,7 @@ static struct em28xx_fmt *format_by_fourcc(unsigned int fourcc)
static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
unsigned int width = f->fmt.pix.width;
unsigned int height = f->fmt.pix.height;
@@ -1355,8 +1353,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
*norm = dev->v4l2->norm;
@@ -1365,8 +1362,7 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *norm)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, video, querystd, norm);
@@ -1375,8 +1371,7 @@ static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *norm)
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
struct v4l2_format f;
@@ -1408,8 +1403,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
static int vidioc_g_parm(struct file *file, void *priv,
struct v4l2_streamparm *p)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
int rc = 0;
@@ -1427,8 +1421,7 @@ static int vidioc_g_parm(struct file *file, void *priv,
static int vidioc_s_parm(struct file *file, void *priv,
struct v4l2_streamparm *p)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
p->parm.capture.readbuffers = EM28XX_MIN_BUF;
return v4l2_device_call_until_err(&dev->v4l2->v4l2_dev,
@@ -1450,8 +1443,7 @@ static const char *iname[] = {
static int vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *i)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
unsigned int n;
n = i->index;
@@ -1479,8 +1471,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
*i = dev->ctl_input;
@@ -1489,8 +1480,7 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
if (i >= MAX_EM28XX_INPUT)
return -EINVAL;
@@ -1503,8 +1493,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
switch (a->index) {
case EM28XX_AMUX_VIDEO:
@@ -1543,8 +1532,7 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *a)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
if (a->index >= MAX_EM28XX_INPUT)
return -EINVAL;
@@ -1563,8 +1551,7 @@ static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio
static int vidioc_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *t)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
if (0 != t->index)
return -EINVAL;
@@ -1578,8 +1565,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
static int vidioc_s_tuner(struct file *file, void *priv,
const struct v4l2_tuner *t)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
if (0 != t->index)
return -EINVAL;
@@ -1591,8 +1577,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
static int vidioc_g_frequency(struct file *file, void *priv,
struct v4l2_frequency *f)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
if (0 != f->tuner)
@@ -1606,8 +1591,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
const struct v4l2_frequency *f)
{
struct v4l2_frequency new_freq = *f;
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
if (0 != f->tuner)
@@ -1624,8 +1608,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
static int vidioc_g_chip_info(struct file *file, void *priv,
struct v4l2_dbg_chip_info *chip)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
if (chip->match.addr > 1)
return -EINVAL;
@@ -1652,8 +1635,7 @@ static int em28xx_reg_len(int reg)
static int vidioc_g_register(struct file *file, void *priv,
struct v4l2_dbg_register *reg)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
int ret;
if (reg->match.addr > 1)
@@ -1693,8 +1675,7 @@ static int vidioc_g_register(struct file *file, void *priv,
static int vidioc_s_register(struct file *file, void *priv,
const struct v4l2_dbg_register *reg)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
__le16 buf;
if (reg->match.addr > 1)
@@ -1715,8 +1696,7 @@ static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
struct video_device *vdev = video_devdata(file);
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
@@ -1761,8 +1741,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
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 *dev = video_drvdata(file);
struct em28xx_fmt *fmt;
unsigned int maxw = norm_maxw(dev);
unsigned int maxh = norm_maxh(dev);
@@ -1806,8 +1785,7 @@ static int vidioc_enum_framesizes(struct file *file, void *priv,
static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
struct v4l2_format *format)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
format->fmt.vbi.samples_per_line = v4l2->vbi_width;
@@ -1840,7 +1818,7 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
static int radio_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *t)
{
- struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
+ struct em28xx *dev = video_drvdata(file);
if (unlikely(t->index > 0))
return -EINVAL;
@@ -1855,7 +1833,7 @@ static int radio_g_tuner(struct file *file, void *priv,
static int radio_s_tuner(struct file *file, void *priv,
const struct v4l2_tuner *t)
{
- struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
+ struct em28xx *dev = video_drvdata(file);
if (0 != t->index)
return -EINVAL;
@@ -1890,7 +1868,7 @@ static int em28xx_v4l2_open(struct file *filp)
struct em28xx *dev = video_drvdata(filp);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
enum v4l2_buf_type fh_type = 0;
- struct em28xx_fh *fh;
+ int ret;
switch (vdev->vfl_type) {
case VFL_TYPE_GRABBER:
@@ -1905,24 +1883,23 @@ static int em28xx_v4l2_open(struct file *filp)
return -EINVAL;
}
- em28xx_videodbg("open dev=%s type=%s users=%d\n",
- video_device_node_name(vdev), v4l2_type_names[fh_type],
- v4l2->users);
+ em28xx_videodbg("open dev=%s type=%s\n",
+ video_device_node_name(vdev), v4l2_type_names[fh_type]);
if (mutex_lock_interruptible(&dev->lock))
return -ERESTARTSYS;
- fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
- if (!fh) {
- em28xx_errdev("em28xx-video.c: Out of memory?!\n");
+
+ ret = v4l2_fh_open(filp);
+ if (ret) {
+ em28xx_errdev("%s: v4l2_fh_open() returned error %d\n",
+ __func__, ret);
mutex_unlock(&dev->lock);
- return -ENOMEM;
+ return ret;
}
- v4l2_fh_init(&fh->fh, vdev);
- fh->dev = dev;
- fh->type = fh_type;
- filp->private_data = fh;
- if (v4l2->users == 0) {
+ if (v4l2_fh_is_singular_file(filp)) {
+ em28xx_videodbg("first opened filehandle, initializing device\n");
+
em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
if (vdev->vfl_type != VFL_TYPE_RADIO)
@@ -1933,6 +1910,8 @@ static int em28xx_v4l2_open(struct file *filp)
* of some i2c devices
*/
em28xx_wake_i2c(dev);
+ } else {
+ em28xx_videodbg("further filehandles are already opened\n");
}
if (vdev->vfl_type == VFL_TYPE_RADIO) {
@@ -1942,10 +1921,8 @@ static int em28xx_v4l2_open(struct file *filp)
kref_get(&dev->ref);
kref_get(&v4l2->ref);
- v4l2->users++;
mutex_unlock(&dev->lock);
- v4l2_fh_add(&fh->fh);
return 0;
}
@@ -2046,17 +2023,15 @@ static int em28xx_v4l2_resume(struct em28xx *dev)
*/
static int em28xx_v4l2_close(struct file *filp)
{
- struct em28xx_fh *fh = filp->private_data;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(filp);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
int errCode;
- em28xx_videodbg("users=%d\n", v4l2->users);
-
- vb2_fop_release(filp);
mutex_lock(&dev->lock);
- if (v4l2->users == 1) {
+ if (v4l2_fh_is_singular_file(filp)) {
+ em28xx_videodbg("last opened filehandle, shutting down device\n");
+
/* No sense to try to write to the device */
if (dev->disconnected)
goto exit;
@@ -2075,10 +2050,12 @@ static int em28xx_v4l2_close(struct file *filp)
em28xx_errdev("cannot change alternate number to "
"0 (error=%i)\n", errCode);
}
+ } else {
+ em28xx_videodbg("further opened filehandles left\n");
}
exit:
- v4l2->users--;
+ vb2_fop_release(filp);
kref_put(&v4l2->ref, em28xx_free_v4l2);
mutex_unlock(&dev->lock);
kref_put(&dev->ref, em28xx_free_device);
@@ -2208,7 +2185,6 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
vfd->v4l2_dev = &dev->v4l2->v4l2_dev;
vfd->debug = video_debug;
vfd->lock = &dev->lock;
- set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
if (dev->board.is_webcam)
vfd->tvnorms = 0;
@@ -2552,7 +2528,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
v4l2->vbi_dev->queue->lock = &v4l2->vb_vbi_queue_lock;
/* disable inapplicable ioctls */
- v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_PARM);
+ v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_PARM);
if (dev->tuner_type == TUNER_ABSENT) {
v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_G_TUNER);
v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_TUNER);
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index b4c837d77e5d..84ef8efdb148 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -524,7 +524,6 @@ struct em28xx_v4l2 {
int sensor_yres;
int sensor_xtal;
- int users; /* user count for exclusive use */
int streaming_users; /* number of actively streaming users */
u32 frequency; /* selected tuner frequency */
@@ -576,13 +575,6 @@ struct em28xx_audio {
struct em28xx;
-struct em28xx_fh {
- struct v4l2_fh fh;
- struct em28xx *dev;
-
- enum v4l2_buf_type type;
-};
-
enum em28xx_i2c_algo_type {
EM28XX_I2C_ALGO_EM28XX = 0,
EM28XX_I2C_ALGO_EM2800,