diff options
Diffstat (limited to 'drivers/media/usb/em28xx')
-rw-r--r-- | drivers/media/usb/em28xx/em28xx-camera.c | 4 | ||||
-rw-r--r-- | drivers/media/usb/em28xx/em28xx-cards.c | 3 | ||||
-rw-r--r-- | drivers/media/usb/em28xx/em28xx-dvb.c | 40 | ||||
-rw-r--r-- | drivers/media/usb/em28xx/em28xx-i2c.c | 6 | ||||
-rw-r--r-- | drivers/media/usb/em28xx/em28xx-input.c | 106 | ||||
-rw-r--r-- | drivers/media/usb/em28xx/em28xx-video.c | 116 | ||||
-rw-r--r-- | drivers/media/usb/em28xx/em28xx.h | 8 |
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, |