diff options
Diffstat (limited to 'drivers/media/usb')
45 files changed, 957 insertions, 209 deletions
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 70e187971590..62b45062b1e6 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -133,7 +133,7 @@ static void au0828_irq_callback(struct urb *urb) au0828_isocdbg("au0828_irq_callback called: status kill\n"); return; default: /* unknown error */ - au0828_isocdbg("urb completition error %d.\n", urb->status); + au0828_isocdbg("urb completion error %d.\n", urb->status); break; } diff --git a/drivers/media/usb/cx231xx/Kconfig b/drivers/media/usb/cx231xx/Kconfig index 0f13192634c7..9e5b3e7c3ef5 100644 --- a/drivers/media/usb/cx231xx/Kconfig +++ b/drivers/media/usb/cx231xx/Kconfig @@ -15,7 +15,7 @@ config VIDEO_CX231XX config VIDEO_CX231XX_RC bool "Conexant cx231xx Remote Controller additional support" - depends on RC_CORE + depends on RC_CORE=y || RC_CORE=VIDEO_CX231XX depends on VIDEO_CX231XX default y ---help--- diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c index c4a84fb930b6..32ee7b3f21c9 100644 --- a/drivers/media/usb/cx231xx/cx231xx-audio.c +++ b/drivers/media/usb/cx231xx/cx231xx-audio.c @@ -112,7 +112,7 @@ static void cx231xx_audio_isocirq(struct urb *urb) case -ESHUTDOWN: return; default: /* error */ - dev_dbg(dev->dev, "urb completition error %d.\n", + dev_dbg(dev->dev, "urb completion error %d.\n", urb->status); break; } @@ -126,6 +126,7 @@ static void cx231xx_audio_isocirq(struct urb *urb) stride = runtime->frame_bits >> 3; for (i = 0; i < urb->number_of_packets; i++) { + unsigned long flags; int length = urb->iso_frame_desc[i].actual_length / stride; cp = (unsigned char *)urb->transfer_buffer + @@ -148,7 +149,7 @@ static void cx231xx_audio_isocirq(struct urb *urb) length * stride); } - snd_pcm_stream_lock(substream); + snd_pcm_stream_lock_irqsave(substream, flags); dev->adev.hwptr_done_capture += length; if (dev->adev.hwptr_done_capture >= @@ -163,7 +164,7 @@ static void cx231xx_audio_isocirq(struct urb *urb) runtime->period_size; period_elapsed = 1; } - snd_pcm_stream_unlock(substream); + snd_pcm_stream_unlock_irqrestore(substream, flags); } if (period_elapsed) snd_pcm_period_elapsed(substream); @@ -202,7 +203,7 @@ static void cx231xx_audio_bulkirq(struct urb *urb) case -ESHUTDOWN: return; default: /* error */ - dev_dbg(dev->dev, "urb completition error %d.\n", + dev_dbg(dev->dev, "urb completion error %d.\n", urb->status); break; } @@ -216,6 +217,7 @@ static void cx231xx_audio_bulkirq(struct urb *urb) stride = runtime->frame_bits >> 3; if (1) { + unsigned long flags; int length = urb->actual_length / stride; cp = (unsigned char *)urb->transfer_buffer; @@ -234,7 +236,7 @@ static void cx231xx_audio_bulkirq(struct urb *urb) length * stride); } - snd_pcm_stream_lock(substream); + snd_pcm_stream_lock_irqsave(substream, flags); dev->adev.hwptr_done_capture += length; if (dev->adev.hwptr_done_capture >= @@ -249,7 +251,7 @@ static void cx231xx_audio_bulkirq(struct urb *urb) runtime->period_size; period_elapsed = 1; } - snd_pcm_stream_unlock(substream); + snd_pcm_stream_unlock_irqrestore(substream, flags); } if (period_elapsed) snd_pcm_period_elapsed(substream); diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c index 53d846dea3d2..493c2dca6244 100644 --- a/drivers/media/usb/cx231xx/cx231xx-core.c +++ b/drivers/media/usb/cx231xx/cx231xx-core.c @@ -799,6 +799,7 @@ static void cx231xx_isoc_irq_callback(struct urb *urb) struct cx231xx_video_mode *vmode = container_of(dma_q, struct cx231xx_video_mode, vidq); struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode); + unsigned long flags; int i; switch (urb->status) { @@ -815,9 +816,9 @@ static void cx231xx_isoc_irq_callback(struct urb *urb) } /* Copy data from URB */ - spin_lock(&dev->video_mode.slock); + spin_lock_irqsave(&dev->video_mode.slock, flags); dev->video_mode.isoc_ctl.isoc_copy(dev, urb); - spin_unlock(&dev->video_mode.slock); + spin_unlock_irqrestore(&dev->video_mode.slock, flags); /* Reset urb buffers */ for (i = 0; i < urb->number_of_packets; i++) { @@ -844,6 +845,7 @@ static void cx231xx_bulk_irq_callback(struct urb *urb) struct cx231xx_video_mode *vmode = container_of(dma_q, struct cx231xx_video_mode, vidq); struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode); + unsigned long flags; switch (urb->status) { case 0: /* success */ @@ -862,9 +864,9 @@ static void cx231xx_bulk_irq_callback(struct urb *urb) } /* Copy data from URB */ - spin_lock(&dev->video_mode.slock); + spin_lock_irqsave(&dev->video_mode.slock, flags); dev->video_mode.bulk_ctl.bulk_copy(dev, urb); - spin_unlock(&dev->video_mode.slock); + spin_unlock_irqrestore(&dev->video_mode.slock, flags); /* Reset urb buffers */ urb->status = usb_submit_urb(urb, GFP_ATOMIC); diff --git a/drivers/media/usb/cx231xx/cx231xx-i2c.c b/drivers/media/usb/cx231xx/cx231xx-i2c.c index 6e1bef2a45bb..15a91169e749 100644 --- a/drivers/media/usb/cx231xx/cx231xx-i2c.c +++ b/drivers/media/usb/cx231xx/cx231xx-i2c.c @@ -376,8 +376,6 @@ static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap, struct cx231xx *dev = bus->dev; int addr, rc, i, byte; - if (num <= 0) - return 0; mutex_lock(&dev->i2c_lock); for (i = 0; i < num; i++) { diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c index b621cf1aa96b..10b2eb7338ad 100644 --- a/drivers/media/usb/cx231xx/cx231xx-vbi.c +++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c @@ -305,6 +305,7 @@ static void cx231xx_irq_vbi_callback(struct urb *urb) struct cx231xx_video_mode *vmode = container_of(dma_q, struct cx231xx_video_mode, vidq); struct cx231xx *dev = container_of(vmode, struct cx231xx, vbi_mode); + unsigned long flags; switch (urb->status) { case 0: /* success */ @@ -316,14 +317,14 @@ static void cx231xx_irq_vbi_callback(struct urb *urb) return; default: /* error */ dev_err(dev->dev, - "urb completition error %d.\n", urb->status); + "urb completion error %d.\n", urb->status); break; } /* Copy data from URB */ - spin_lock(&dev->vbi_mode.slock); + spin_lock_irqsave(&dev->vbi_mode.slock, flags); dev->vbi_mode.bulk_ctl.bulk_copy(dev, urb); - spin_unlock(&dev->vbi_mode.slock); + spin_unlock_irqrestore(&dev->vbi_mode.slock, flags); /* Reset status */ urb->status = 0; diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig index 082b8d67244b..df4412245a8a 100644 --- a/drivers/media/usb/dvb-usb-v2/Kconfig +++ b/drivers/media/usb/dvb-usb-v2/Kconfig @@ -96,10 +96,13 @@ config DVB_USB_GL861 tristate "Genesys Logic GL861 USB2.0 support" depends on DVB_USB_V2 select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TC90522 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT + select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0 - receiver with USB ID 0db0:5581. + receiver with USB ID 0db0:5581, Friio White ISDB-T receiver + with USB ID 0x7a69:0001. config DVB_USB_LME2510 tristate "LME DM04/QQBOX DVB-S USB2.0 support" diff --git a/drivers/media/usb/dvb-usb-v2/gl861.c b/drivers/media/usb/dvb-usb-v2/gl861.c index 9d154fdae45b..3338b21d8b25 100644 --- a/drivers/media/usb/dvb-usb-v2/gl861.c +++ b/drivers/media/usb/dvb-usb-v2/gl861.c @@ -6,10 +6,14 @@ * * see Documentation/media/dvb-drivers/dvb-usb.rst for more information */ +#include <linux/string.h> + #include "gl861.h" #include "zl10353.h" #include "qt1010.h" +#include "tc90522.h" +#include "dvb-pll.h" DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); @@ -26,10 +30,14 @@ static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr, if (wo) { req = GL861_REQ_I2C_WRITE; type = GL861_WRITE; + buf = kmemdup(wbuf, wlen, GFP_KERNEL); } else { /* rw */ req = GL861_REQ_I2C_READ; type = GL861_READ; + buf = kmalloc(rlen, GFP_KERNEL); } + if (!buf) + return -ENOMEM; switch (wlen) { case 1: @@ -42,24 +50,19 @@ static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr, default: dev_err(&d->udev->dev, "%s: wlen=%d, aborting\n", KBUILD_MODNAME, wlen); + kfree(buf); return -EINVAL; } - buf = NULL; - if (rlen > 0) { - buf = kmalloc(rlen, GFP_KERNEL); - if (!buf) - return -ENOMEM; - } + usleep_range(1000, 2000); /* avoid I2C errors */ ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), req, type, value, index, buf, rlen, 2000); - if (rlen > 0) { - if (ret > 0) - memcpy(rbuf, buf, rlen); - kfree(buf); - } + if (!wo && ret > 0) + memcpy(rbuf, buf, rlen); + + kfree(buf); return ret; } @@ -162,11 +165,478 @@ static struct dvb_usb_device_properties gl861_props = { } }; + +/* + * For Friio + */ + +struct friio_priv { + struct i2c_adapter *demod_sub_i2c; + struct i2c_client *i2c_client_demod; + struct i2c_client *i2c_client_tuner; + struct i2c_adapter tuner_adap; +}; + +struct friio_config { + struct i2c_board_info demod_info; + struct tc90522_config demod_cfg; + + struct i2c_board_info tuner_info; + struct dvb_pll_config tuner_cfg; +}; + +static const struct friio_config friio_config = { + .demod_info = { I2C_BOARD_INFO(TC90522_I2C_DEV_TER, 0x18), }, + .tuner_info = { I2C_BOARD_INFO("tua6034_friio", 0x60), }, +}; + +/* For another type of I2C: + * message sent by a USB control-read/write transaction with data stage. + * Used in init/config of Friio. + */ +static int +gl861_i2c_write_ex(struct dvb_usb_device *d, u8 addr, u8 *wbuf, u16 wlen) +{ + u8 *buf; + int ret; + + buf = kmalloc(wlen, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + memcpy(buf, wbuf, wlen); + ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), + GL861_REQ_I2C_RAW, GL861_WRITE, + addr << (8 + 1), 0x0100, buf, wlen, 2000); + kfree(buf); + return ret; +} + +static int +gl861_i2c_read_ex(struct dvb_usb_device *d, u8 addr, u8 *rbuf, u16 rlen) +{ + u8 *buf; + int ret; + + buf = kmalloc(rlen, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), + GL861_REQ_I2C_READ, GL861_READ, + addr << (8 + 1), 0x0100, buf, rlen, 2000); + if (ret > 0 && rlen > 0) + memcpy(buf, rbuf, rlen); + kfree(buf); + return ret; +} + +/* For I2C transactions to the tuner of Friio (dvb_pll). + * + * Friio uses irregular USB encapsulation for tuner i2c transactions: + * write transacions are encapsulated with a different USB 'request' value. + * + * Although all transactions are sent via the demod(tc90522) + * and the demod provides an i2c adapter for them, it cannot be used in Friio + * since it assumes using the same parent adapter with the demod, + * which does not use the request value and uses same one for both read/write. + * So we define a dedicated i2c adapter here. + */ + +static int +friio_i2c_tuner_read(struct dvb_usb_device *d, struct i2c_msg *msg) +{ + struct friio_priv *priv; + u8 addr; + + priv = d_to_priv(d); + addr = priv->i2c_client_demod->addr; + return gl861_i2c_read_ex(d, addr, msg->buf, msg->len); +} + +static int +friio_i2c_tuner_write(struct dvb_usb_device *d, struct i2c_msg *msg) +{ + u8 *buf; + int ret; + struct friio_priv *priv; + + priv = d_to_priv(d); + + if (msg->len < 1) + return -EINVAL; + + buf = kmalloc(msg->len + 1, GFP_KERNEL); + if (!buf) + return -ENOMEM; + buf[0] = msg->addr << 1; + memcpy(buf + 1, msg->buf, msg->len); + + ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), + GL861_REQ_I2C_RAW, GL861_WRITE, + priv->i2c_client_demod->addr << (8 + 1), + 0xFE, buf, msg->len + 1, 2000); + kfree(buf); + return ret; +} + +static int friio_tuner_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i; + + if (num > 2) + return -EINVAL; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + int ret; + + if (msg[i].flags & I2C_M_RD) + ret = friio_i2c_tuner_read(d, &msg[i]); + else + ret = friio_i2c_tuner_write(d, &msg[i]); + + if (ret < 0) + break; + + usleep_range(1000, 2000); /* avoid I2C errors */ + } + + mutex_unlock(&d->i2c_mutex); + return i; +} + +static struct i2c_algorithm friio_tuner_i2c_algo = { + .master_xfer = friio_tuner_i2c_xfer, + .functionality = gl861_i2c_func, +}; + +/* GPIO control in Friio */ + +#define FRIIO_CTL_LNB (1 << 0) +#define FRIIO_CTL_STROBE (1 << 1) +#define FRIIO_CTL_CLK (1 << 2) +#define FRIIO_CTL_LED (1 << 3) + +#define FRIIO_LED_RUNNING 0x6400ff64 +#define FRIIO_LED_STOPPED 0x96ff00ff + +/* control PIC16F676 attached to Friio */ +static int friio_ext_ctl(struct dvb_usb_device *d, + u32 sat_color, int power_on) +{ + int i, ret; + struct i2c_msg msg; + u8 *buf; + u32 mask; + u8 power = (power_on) ? FRIIO_CTL_LNB : 0; + + buf = kmalloc(2, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + msg.addr = 0x00; + msg.flags = 0; + msg.len = 2; + msg.buf = buf; + buf[0] = 0x00; + + /* send 2bit header (&B10) */ + buf[1] = power | FRIIO_CTL_LED | FRIIO_CTL_STROBE; + ret = i2c_transfer(&d->i2c_adap, &msg, 1); + buf[1] |= FRIIO_CTL_CLK; + ret += i2c_transfer(&d->i2c_adap, &msg, 1); + + buf[1] = power | FRIIO_CTL_STROBE; + ret += i2c_transfer(&d->i2c_adap, &msg, 1); + buf[1] |= FRIIO_CTL_CLK; + ret += i2c_transfer(&d->i2c_adap, &msg, 1); + + /* send 32bit(satur, R, G, B) data in serial */ + mask = 1 << 31; + for (i = 0; i < 32; i++) { + buf[1] = power | FRIIO_CTL_STROBE; + if (sat_color & mask) + buf[1] |= FRIIO_CTL_LED; + ret += i2c_transfer(&d->i2c_adap, &msg, 1); + buf[1] |= FRIIO_CTL_CLK; + ret += i2c_transfer(&d->i2c_adap, &msg, 1); + mask >>= 1; + } + + /* set the strobe off */ + buf[1] = power; + ret += i2c_transfer(&d->i2c_adap, &msg, 1); + buf[1] |= FRIIO_CTL_CLK; + ret += i2c_transfer(&d->i2c_adap, &msg, 1); + + kfree(buf); + return (ret == 70) ? 0 : -EREMOTEIO; +} + +/* init/config of gl861 for Friio */ +/* NOTE: + * This function cannot be moved to friio_init()/dvb_usbv2_init(), + * because the init defined here must be done before any activities like I2C, + * but friio_init() is called by dvb-usbv2 after {_frontend, _tuner}_attach(), + * where I2C communication is used. + * Thus this function is set to be called from _power_ctl(). + * + * Since it will be called on the early init stage + * where the i2c adapter is not initialized yet, + * we cannot use i2c_transfer() here. + */ +static int friio_reset(struct dvb_usb_device *d) +{ + int i, ret; + u8 wbuf[2], rbuf[2]; + + static const u8 friio_init_cmds[][2] = { + {0x33, 0x08}, {0x37, 0x40}, {0x3a, 0x1f}, {0x3b, 0xff}, + {0x3c, 0x1f}, {0x3d, 0xff}, {0x38, 0x00}, {0x35, 0x00}, + {0x39, 0x00}, {0x36, 0x00}, + }; + + ret = usb_set_interface(d->udev, 0, 0); + if (ret < 0) + return ret; + + wbuf[0] = 0x11; + wbuf[1] = 0x02; + ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0); + if (ret < 0) + return ret; + usleep_range(2000, 3000); + + wbuf[0] = 0x11; + wbuf[1] = 0x00; + ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0); + if (ret < 0) + return ret; + + /* + * Check if the dev is really a Friio White, since it might be + * another device, Friio Black, with the same VID/PID. + */ + + usleep_range(1000, 2000); + wbuf[0] = 0x03; + wbuf[1] = 0x80; + ret = gl861_i2c_write_ex(d, 0x09, wbuf, 2); + if (ret < 0) + return ret; + + usleep_range(2000, 3000); + ret = gl861_i2c_read_ex(d, 0x09, rbuf, 2); + if (ret < 0) + return ret; + if (rbuf[0] != 0xff || rbuf[1] != 0xff) + return -ENODEV; + + + usleep_range(1000, 2000); + ret = gl861_i2c_write_ex(d, 0x48, wbuf, 2); + if (ret < 0) + return ret; + + usleep_range(2000, 3000); + ret = gl861_i2c_read_ex(d, 0x48, rbuf, 2); + if (ret < 0) + return ret; + if (rbuf[0] != 0xff || rbuf[1] != 0xff) + return -ENODEV; + + wbuf[0] = 0x30; + wbuf[1] = 0x04; + ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0); + if (ret < 0) + return ret; + + wbuf[0] = 0x00; + wbuf[1] = 0x01; + ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0); + if (ret < 0) + return ret; + + wbuf[0] = 0x06; + wbuf[1] = 0x0f; + ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0); + if (ret < 0) + return ret; + + for (i = 0; i < ARRAY_SIZE(friio_init_cmds); i++) { + ret = gl861_i2c_msg(d, 0x00, (u8 *)friio_init_cmds[i], 2, + NULL, 0); + if (ret < 0) + return ret; + } + return 0; +} + +/* + * DVB callbacks for Friio + */ + +static int friio_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + return onoff ? friio_reset(d) : 0; +} + +static int friio_frontend_attach(struct dvb_usb_adapter *adap) +{ + const struct i2c_board_info *info; + struct dvb_usb_device *d; + struct tc90522_config cfg; + struct i2c_client *cl; + struct friio_priv *priv; + + info = &friio_config.demod_info; + d = adap_to_d(adap); + cl = dvb_module_probe("tc90522", info->type, + &d->i2c_adap, info->addr, &cfg); + if (!cl) + return -ENODEV; + adap->fe[0] = cfg.fe; + + /* ignore cfg.tuner_i2c and create new one */ + priv = adap_to_priv(adap); + priv->i2c_client_demod = cl; + priv->tuner_adap.algo = &friio_tuner_i2c_algo; + priv->tuner_adap.dev.parent = &d->udev->dev; + strlcpy(priv->tuner_adap.name, d->name, sizeof(priv->tuner_adap.name)); + strlcat(priv->tuner_adap.name, "-tuner", sizeof(priv->tuner_adap.name)); + priv->demod_sub_i2c = &priv->tuner_adap; + i2c_set_adapdata(&priv->tuner_adap, d); + + return i2c_add_adapter(&priv->tuner_adap); +} + +static int friio_frontend_detach(struct dvb_usb_adapter *adap) +{ + struct friio_priv *priv; + + priv = adap_to_priv(adap); + i2c_del_adapter(&priv->tuner_adap); + dvb_module_release(priv->i2c_client_demod); + return 0; +} + +static int friio_tuner_attach(struct dvb_usb_adapter *adap) +{ + const struct i2c_board_info *info; + struct dvb_pll_config cfg; + struct i2c_client *cl; + struct friio_priv *priv; + + priv = adap_to_priv(adap); + info = &friio_config.tuner_info; + cfg = friio_config.tuner_cfg; + cfg.fe = adap->fe[0]; + + cl = dvb_module_probe("dvb_pll", info->type, + priv->demod_sub_i2c, info->addr, &cfg); + if (!cl) + return -ENODEV; + priv->i2c_client_tuner = cl; + return 0; +} + +static int friio_tuner_detach(struct dvb_usb_adapter *adap) +{ + struct friio_priv *priv; + + priv = adap_to_priv(adap); + dvb_module_release(priv->i2c_client_tuner); + return 0; +} + +static int friio_init(struct dvb_usb_device *d) +{ + int i; + int ret; + struct friio_priv *priv; + + static const u8 demod_init[][2] = { + {0x01, 0x40}, {0x04, 0x38}, {0x05, 0x40}, {0x07, 0x40}, + {0x0f, 0x4f}, {0x11, 0x21}, {0x12, 0x0b}, {0x13, 0x2f}, + {0x14, 0x31}, {0x16, 0x02}, {0x21, 0xc4}, {0x22, 0x20}, + {0x2c, 0x79}, {0x2d, 0x34}, {0x2f, 0x00}, {0x30, 0x28}, + {0x31, 0x31}, {0x32, 0xdf}, {0x38, 0x01}, {0x39, 0x78}, + {0x3b, 0x33}, {0x3c, 0x33}, {0x48, 0x90}, {0x51, 0x68}, + {0x5e, 0x38}, {0x71, 0x00}, {0x72, 0x08}, {0x77, 0x00}, + {0xc0, 0x21}, {0xc1, 0x10}, {0xe4, 0x1a}, {0xea, 0x1f}, + {0x77, 0x00}, {0x71, 0x00}, {0x71, 0x00}, {0x76, 0x0c}, + }; + + /* power on LNA? */ + ret = friio_ext_ctl(d, FRIIO_LED_STOPPED, true); + if (ret < 0) + return ret; + msleep(20); + + /* init/config demod */ + priv = d_to_priv(d); + for (i = 0; i < ARRAY_SIZE(demod_init); i++) { + int ret; + + ret = i2c_master_send(priv->i2c_client_demod, demod_init[i], 2); + if (ret < 0) + return ret; + } + msleep(100); + return 0; +} + +static void friio_exit(struct dvb_usb_device *d) +{ + friio_ext_ctl(d, FRIIO_LED_STOPPED, false); +} + +static int friio_streaming_ctrl(struct dvb_frontend *fe, int onoff) +{ + u32 led_color; + + led_color = onoff ? FRIIO_LED_RUNNING : FRIIO_LED_STOPPED; + return friio_ext_ctl(fe_to_d(fe), led_color, true); +} + + +static struct dvb_usb_device_properties friio_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + + .size_of_priv = sizeof(struct friio_priv), + + .i2c_algo = &gl861_i2c_algo, + .power_ctrl = friio_power_ctrl, + .frontend_attach = friio_frontend_attach, + .frontend_detach = friio_frontend_detach, + .tuner_attach = friio_tuner_attach, + .tuner_detach = friio_tuner_detach, + .init = friio_init, + .exit = friio_exit, + .streaming_ctrl = friio_streaming_ctrl, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_BULK(0x01, 8, 16384), + } + } +}; + static const struct usb_device_id gl861_id_table[] = { { DVB_USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801, &gl861_props, "MSI Mega Sky 55801 DVB-T USB2.0", NULL) }, { DVB_USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU, &gl861_props, "A-LINK DTU DVB-T USB2.0", NULL) }, + { DVB_USB_DEVICE(USB_VID_774, USB_PID_FRIIO_WHITE, + &friio_props, "774 Friio White ISDB-T USB2.0", NULL) }, { } }; MODULE_DEVICE_TABLE(usb, gl861_id_table); diff --git a/drivers/media/usb/dvb-usb-v2/gl861.h b/drivers/media/usb/dvb-usb-v2/gl861.h index b651b857e034..02c00e10748a 100644 --- a/drivers/media/usb/dvb-usb-v2/gl861.h +++ b/drivers/media/usb/dvb-usb-v2/gl861.h @@ -9,5 +9,6 @@ #define GL861_REQ_I2C_WRITE 0x01 #define GL861_REQ_I2C_READ 0x02 +#define GL861_REQ_I2C_RAW 0x03 #endif diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c index 221cf46b4140..9f74453799a2 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c @@ -554,9 +554,9 @@ static const struct dvb_frontend_ops mxl111sf_demod_ops = { .delsys = { SYS_DVBT }, .info = { .name = "MaxLinear MxL111SF DVB-T demodulator", - .frequency_min = 177000000, - .frequency_max = 858000000, - .frequency_stepsize = 166666, + .frequency_min_hz = 177 * MHz, + .frequency_max_hz = 858 * MHz, + .frequency_stepsize_hz = 166666, .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c index 240d736bf1bb..92b3b9221a21 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c @@ -465,9 +465,9 @@ static const struct dvb_tuner_ops mxl111sf_tuner_tuner_ops = { .info = { .name = "MaxLinear MxL111SF", #if 0 - .frequency_min = , - .frequency_max = , - .frequency_step = , + .frequency_min_hz = , + .frequency_max_hz = , + .frequency_step_hz = , #endif }, #if 0 diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index c76e78f9638a..a970224a94bd 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -1732,7 +1732,7 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d) goto exit; ret = rtl28xxu_rd_reg(d, IR_RX_BC, &buf[0]); - if (ret) + if (ret || buf[0] > sizeof(buf)) goto err; len = buf[0]; diff --git a/drivers/media/usb/dvb-usb-v2/usb_urb.c b/drivers/media/usb/dvb-usb-v2/usb_urb.c index b0499f95ec45..024c751eb165 100644 --- a/drivers/media/usb/dvb-usb-v2/usb_urb.c +++ b/drivers/media/usb/dvb-usb-v2/usb_urb.c @@ -40,7 +40,7 @@ static void usb_urb_complete(struct urb *urb) return; default: /* error */ dev_dbg_ratelimited(&stream->udev->dev, - "%s: urb completition failed=%d\n", + "%s: urb completion failed=%d\n", __func__, urb->status); break; } @@ -69,7 +69,7 @@ static void usb_urb_complete(struct urb *urb) break; default: dev_err(&stream->udev->dev, - "%s: unknown endpoint type in completition handler\n", + "%s: unknown endpoint type in completion handler\n", KBUILD_MODNAME); return; } diff --git a/drivers/media/usb/dvb-usb/Kconfig b/drivers/media/usb/dvb-usb/Kconfig index b8a1c62a0682..513df955eaa3 100644 --- a/drivers/media/usb/dvb-usb/Kconfig +++ b/drivers/media/usb/dvb-usb/Kconfig @@ -312,12 +312,6 @@ config DVB_USB_DTV5100 help Say Y here to support the AME DTV-5100 USB2.0 DVB-T receiver. -config DVB_USB_FRIIO - tristate "Friio ISDB-T USB2.0 Receiver support" - depends on DVB_USB - help - Say Y here to support the Japanese DTV receiver Friio. - config DVB_USB_AZ6027 tristate "Azurewave DVB-S/S2 USB2.0 AZ6027 support" depends on DVB_USB diff --git a/drivers/media/usb/dvb-usb/Makefile b/drivers/media/usb/dvb-usb/Makefile index 9ad2618408ef..407d90ca8be0 100644 --- a/drivers/media/usb/dvb-usb/Makefile +++ b/drivers/media/usb/dvb-usb/Makefile @@ -71,9 +71,6 @@ obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o dvb-usb-cinergyT2-objs := cinergyT2-core.o cinergyT2-fe.o obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o -dvb-usb-friio-objs := friio.o friio-fe.o -obj-$(CONFIG_DVB_USB_FRIIO) += dvb-usb-friio.o - dvb-usb-az6027-objs := az6027.o obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o diff --git a/drivers/media/usb/dvb-usb/af9005-fe.c b/drivers/media/usb/dvb-usb/af9005-fe.c index 7fbbc954da16..09cc3a21af65 100644 --- a/drivers/media/usb/dvb-usb/af9005-fe.c +++ b/drivers/media/usb/dvb-usb/af9005-fe.c @@ -1455,9 +1455,9 @@ static const struct dvb_frontend_ops af9005_fe_ops = { .delsys = { SYS_DVBT }, .info = { .name = "AF9005 USB DVB-T", - .frequency_min = 44250000, - .frequency_max = 867250000, - .frequency_stepsize = 250000, + .frequency_min_hz = 44250 * kHz, + .frequency_max_hz = 867250 * kHz, + .frequency_stepsize_hz = 250 * kHz, .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | diff --git a/drivers/media/usb/dvb-usb/cinergyT2-fe.c b/drivers/media/usb/dvb-usb/cinergyT2-fe.c index 5a2f81311fb7..df71df7ed524 100644 --- a/drivers/media/usb/dvb-usb/cinergyT2-fe.c +++ b/drivers/media/usb/dvb-usb/cinergyT2-fe.c @@ -295,9 +295,9 @@ static const struct dvb_frontend_ops cinergyt2_fe_ops = { .delsys = { SYS_DVBT }, .info = { .name = DRIVER_NAME, - .frequency_min = 174000000, - .frequency_max = 862000000, - .frequency_stepsize = 166667, + .frequency_min_hz = 174 * MHz, + .frequency_max_hz = 862 * MHz, + .frequency_stepsize_hz = 166667, .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index c53a969bc6be..091389fdf89e 100644 --- a/drivers/media/usb/dvb-usb/dib0700_devices.c +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c @@ -1745,6 +1745,7 @@ static int dib809x_tuner_attach(struct dvb_usb_adapter *adap) if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &dib809x_dib0090_config) == NULL) return -ENODEV; } else { + /* FIXME: check if it is fe_adap[1] */ if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &dib809x_dib0090_config) == NULL) return -ENODEV; } diff --git a/drivers/media/usb/dvb-usb/dtt200u-fe.c b/drivers/media/usb/dvb-usb/dtt200u-fe.c index 7e75aae34fb8..1ca3a51b2ae3 100644 --- a/drivers/media/usb/dvb-usb/dtt200u-fe.c +++ b/drivers/media/usb/dvb-usb/dtt200u-fe.c @@ -230,9 +230,9 @@ static const struct dvb_frontend_ops dtt200u_fe_ops = { .delsys = { SYS_DVBT }, .info = { .name = "WideView USB DVB-T", - .frequency_min = 44250000, - .frequency_max = 867250000, - .frequency_stepsize = 250000, + .frequency_min_hz = 44250 * kHz, + .frequency_max_hz = 867250 * kHz, + .frequency_stepsize_hz = 250 * kHz, .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c index 0d4fdd34a710..9ce8b4d79d1f 100644 --- a/drivers/media/usb/dvb-usb/dw2102.c +++ b/drivers/media/usb/dvb-usb/dw2102.c @@ -2101,14 +2101,12 @@ static struct dvb_usb_device_properties s6x0_properties = { } }; -static struct dvb_usb_device_properties *p1100; static const struct dvb_usb_device_description d1100 = { "Prof 1100 USB ", {&dw2102_table[PROF_1100], NULL}, {NULL}, }; -static struct dvb_usb_device_properties *s660; static const struct dvb_usb_device_description d660 = { "TeVii S660 USB", {&dw2102_table[TEVII_S660], NULL}, @@ -2127,14 +2125,12 @@ static const struct dvb_usb_device_description d480_2 = { {NULL}, }; -static struct dvb_usb_device_properties *p7500; static const struct dvb_usb_device_description d7500 = { "Prof 7500 USB DVB-S2", {&dw2102_table[PROF_7500], NULL}, {NULL}, }; -static struct dvb_usb_device_properties *s421; static const struct dvb_usb_device_description d421 = { "TeVii S421 PCI", {&dw2102_table[TEVII_S421], NULL}, @@ -2334,6 +2330,11 @@ static int dw2102_probe(struct usb_interface *intf, const struct usb_device_id *id) { int retval = -ENOMEM; + struct dvb_usb_device_properties *p1100; + struct dvb_usb_device_properties *s660; + struct dvb_usb_device_properties *p7500; + struct dvb_usb_device_properties *s421; + p1100 = kmemdup(&s6x0_properties, sizeof(struct dvb_usb_device_properties), GFP_KERNEL); if (!p1100) @@ -2402,8 +2403,16 @@ static int dw2102_probe(struct usb_interface *intf, 0 == dvb_usb_device_init(intf, &t220_properties, THIS_MODULE, NULL, adapter_nr) || 0 == dvb_usb_device_init(intf, &tt_s2_4600_properties, - THIS_MODULE, NULL, adapter_nr)) + THIS_MODULE, NULL, adapter_nr)) { + + /* clean up copied properties */ + kfree(s421); + kfree(p7500); + kfree(s660); + kfree(p1100); + return 0; + } retval = -ENODEV; kfree(s421); diff --git a/drivers/media/usb/dvb-usb/friio-fe.c b/drivers/media/usb/dvb-usb/friio-fe.c index 932f262452eb..e6bd0ed8d789 100644 --- a/drivers/media/usb/dvb-usb/friio-fe.c +++ b/drivers/media/usb/dvb-usb/friio-fe.c @@ -133,10 +133,10 @@ static int jdvbt90502_pll_set_freq(struct jdvbt90502_state *state, u32 freq) u32 f; deb_fe("%s: freq=%d, step=%d\n", __func__, freq, - state->frontend.ops.info.frequency_stepsize); + state->frontend.ops.info.frequency_stepsize_hz); /* freq -> oscilator frequency conversion. */ /* freq: 473,000,000 + n*6,000,000 [+ 142857 (center freq. shift)] */ - f = freq / state->frontend.ops.info.frequency_stepsize; + f = freq / state->frontend.ops.info.frequency_stepsize_hz; /* add 399[1/7 MHZ] = 57MHz for the IF */ f += 399; /* add center frequency shift if necessary */ @@ -413,10 +413,9 @@ static const struct dvb_frontend_ops jdvbt90502_ops = { .delsys = { SYS_ISDBT }, .info = { .name = "Comtech JDVBT90502 ISDB-T", - .frequency_min = 473000000, /* UHF 13ch, center */ - .frequency_max = 767142857, /* UHF 62ch, center */ - .frequency_stepsize = JDVBT90502_PLL_CLK / JDVBT90502_PLL_DIVIDER, - .frequency_tolerance = 0, + .frequency_min_hz = 473000000, /* UHF 13ch, center */ + .frequency_max_hz = 767142857, /* UHF 62ch, center */ + .frequency_stepsize_hz = JDVBT90502_PLL_CLK / JDVBT90502_PLL_DIVIDER, /* NOTE: this driver ignores all parameters but frequency. */ .caps = FE_CAN_INVERSION_AUTO | diff --git a/drivers/media/usb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c index 51b026fa6bfb..22554d9abd43 100644 --- a/drivers/media/usb/dvb-usb/m920x.c +++ b/drivers/media/usb/dvb-usb/m920x.c @@ -255,9 +255,6 @@ static int m920x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int nu int i, j; int ret = 0; - if (!num) - return -EINVAL; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) return -EAGAIN; diff --git a/drivers/media/usb/dvb-usb/usb-urb.c b/drivers/media/usb/dvb-usb/usb-urb.c index 5e05963f4220..9771f0954c69 100644 --- a/drivers/media/usb/dvb-usb/usb-urb.c +++ b/drivers/media/usb/dvb-usb/usb-urb.c @@ -33,7 +33,7 @@ static void usb_urb_complete(struct urb *urb) case -ESHUTDOWN: return; default: /* error */ - deb_ts("urb completition error %d.\n", urb->status); + deb_ts("urb completion error %d.\n", urb->status); break; } @@ -57,7 +57,7 @@ static void usb_urb_complete(struct urb *urb) stream->complete(stream, b, urb->actual_length); break; default: - err("unknown endpoint type in completition handler."); + err("unknown endpoint type in completion handler."); return; } usb_submit_urb(urb,GFP_ATOMIC); diff --git a/drivers/media/usb/dvb-usb/vp702x-fe.c b/drivers/media/usb/dvb-usb/vp702x-fe.c index ae48146e005c..9eb811452f2e 100644 --- a/drivers/media/usb/dvb-usb/vp702x-fe.c +++ b/drivers/media/usb/dvb-usb/vp702x-fe.c @@ -349,10 +349,9 @@ static const struct dvb_frontend_ops vp702x_fe_ops = { .delsys = { SYS_DVBS }, .info = { .name = "Twinhan DST-like frontend (VP7021/VP7020) DVB-S", - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 1000, /* kHz for QPSK frontends */ - .frequency_tolerance = 0, + .frequency_min_hz = 950 * MHz, + .frequency_max_hz = 2150 * MHz, + .frequency_stepsize_hz = 1 * MHz, .symbol_rate_min = 1000000, .symbol_rate_max = 45000000, .symbol_rate_tolerance = 500, /* ppm */ diff --git a/drivers/media/usb/dvb-usb/vp7045-fe.c b/drivers/media/usb/dvb-usb/vp7045-fe.c index f86040173b8d..1173ae29885b 100644 --- a/drivers/media/usb/dvb-usb/vp7045-fe.c +++ b/drivers/media/usb/dvb-usb/vp7045-fe.c @@ -162,9 +162,9 @@ static const struct dvb_frontend_ops vp7045_fe_ops = { .delsys = { SYS_DVBT }, .info = { .name = "Twinhan VP7045/46 USB DVB-T", - .frequency_min = 44250000, - .frequency_max = 867250000, - .frequency_stepsize = 1000, + .frequency_min_hz = 44250 * kHz, + .frequency_max_hz = 867250 * kHz, + .frequency_stepsize_hz = 1 * kHz, .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 6c8438311d3b..71c829f31d3b 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -543,7 +543,7 @@ static const struct em28xx_reg_seq hauppauge_dualhd_dvb[] = { {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xdf, 0xff, 100}, /* demod 2 reset */ {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 100}, - {EM2874_R5F_TS_ENABLE, 0x44, 0xff, 50}, + {EM2874_R5F_TS_ENABLE, 0x00, 0xff, 50}, /* disable TS filters */ {EM2874_R5D_TS1_PKT_SIZE, 0x05, 0xff, 50}, {EM2874_R5E_TS2_PKT_SIZE, 0x05, 0xff, 50}, {-1, -1, -1, -1}, @@ -2688,8 +2688,6 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM28178_BOARD_PCTV_292E }, { USB_DEVICE(0x2040, 0x8268), /* Hauppauge Retail WinTV-soloHD Bulk */ .driver_info = EM28178_BOARD_PCTV_292E }, - { USB_DEVICE(0x2040, 0x8268), /* Hauppauge WinTV-soloHD alt. PID */ - .driver_info = EM28178_BOARD_PCTV_292E }, { USB_DEVICE(0x0413, 0x6f07), .driver_info = EM2861_BOARD_LEADTEK_VC100 }, { USB_DEVICE(0xeb1a, 0x8179), @@ -2854,13 +2852,13 @@ static void em28xx_pre_card_setup(struct em28xx *dev) em28xx_write_reg(dev, EM2880_R04_GPO, 0x01); usleep_range(10000, 11000); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfd); - mdelay(70); + msleep(70); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfc); - mdelay(70); + msleep(70); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xdc); - mdelay(70); + msleep(70); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfc); - mdelay(70); + msleep(70); break; case EM2870_BOARD_TERRATEC_XS_MT2060: /* @@ -2868,11 +2866,11 @@ static void em28xx_pre_card_setup(struct em28xx *dev) * demod work */ em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe); - mdelay(70); + msleep(70); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xde); - mdelay(70); + msleep(70); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe); - mdelay(70); + msleep(70); break; case EM2870_BOARD_PINNACLE_PCTV_DVB: /* @@ -2880,11 +2878,11 @@ static void em28xx_pre_card_setup(struct em28xx *dev) * DVB-T demod work */ em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe); - mdelay(70); + msleep(70); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xde); - mdelay(70); + msleep(70); em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe); - mdelay(70); + msleep(70); break; case EM2820_BOARD_GADMEI_UTV310: case EM2820_BOARD_MSI_VOX_USB_2: @@ -3376,7 +3374,9 @@ void em28xx_free_device(struct kref *ref) if (!dev->disconnected) em28xx_release_resources(dev); - kfree(dev->alt_max_pkt_size_isoc); + if (dev->ts == PRIMARY_TS) + kfree(dev->alt_max_pkt_size_isoc); + kfree(dev); } EXPORT_SYMBOL_GPL(em28xx_free_device); @@ -3861,6 +3861,17 @@ static int em28xx_usb_probe(struct usb_interface *intf, dev->has_video = false; } + if (dev->board.has_dual_ts && + (dev->tuner_type != TUNER_ABSENT || INPUT(0)->type)) { + /* + * The logic with sets alternate is not ready for dual-tuners + * which analog modes. + */ + dev_err(&intf->dev, + "We currently don't support analog TV or stream capture on dual tuners.\n"); + has_video = false; + } + /* Select USB transfer types to use */ if (has_video) { if (!dev->analog_ep_isoc || (try_bulk && dev->analog_ep_bulk)) diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index f70845e7d8c6..5657f8710ca6 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -655,12 +655,12 @@ int em28xx_capture_start(struct em28xx *dev, int start) rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE, start ? EM2874_TS1_CAPTURE_ENABLE : 0x00, - EM2874_TS1_CAPTURE_ENABLE); + EM2874_TS1_CAPTURE_ENABLE | EM2874_TS1_FILTER_ENABLE | EM2874_TS1_NULL_DISCARD); else rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE, start ? EM2874_TS2_CAPTURE_ENABLE : 0x00, - EM2874_TS2_CAPTURE_ENABLE); + EM2874_TS2_CAPTURE_ENABLE | EM2874_TS2_FILTER_ENABLE | EM2874_TS2_NULL_DISCARD); } else { /* FIXME: which is the best order? */ /* video registers are sampled by VREF */ @@ -1053,7 +1053,7 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode, /* submit urbs and enables IRQ */ for (i = 0; i < usb_bufs->num_bufs; i++) { - rc = usb_submit_urb(usb_bufs->urb[i], GFP_ATOMIC); + rc = usb_submit_urb(usb_bufs->urb[i], GFP_KERNEL); if (rc) { dev_err(&dev->intf->dev, "submit of urb %i failed (error=%i)\n", i, rc); diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index b778d8a1983e..a73faf12f7e4 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -218,7 +218,9 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb) dvb_alt = dev->dvb_alt_isoc; } - usb_set_interface(udev, dev->ifnum, dvb_alt); + if (!dev->board.has_dual_ts) + usb_set_interface(udev, dev->ifnum, dvb_alt); + rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); if (rc < 0) return rc; diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 6458682bc6e2..e19d6342e0d0 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -559,10 +559,6 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, dev->cur_i2c_bus = bus; } - if (num <= 0) { - rt_mutex_unlock(&dev->i2c_bus_lock); - return 0; - } for (i = 0; i < num; i++) { addr = msgs[i].addr << 1; if (!msgs[i].len) { diff --git a/drivers/media/usb/go7007/go7007-driver.c b/drivers/media/usb/go7007/go7007-driver.c index 05b1126f263e..62aeebcdd7f7 100644 --- a/drivers/media/usb/go7007/go7007-driver.c +++ b/drivers/media/usb/go7007/go7007-driver.c @@ -448,13 +448,14 @@ static struct go7007_buffer *frame_boundary(struct go7007 *go, struct go7007_buf { u32 *bytesused; struct go7007_buffer *vb_tmp = NULL; + unsigned long flags; if (vb == NULL) { - spin_lock(&go->spinlock); + spin_lock_irqsave(&go->spinlock, flags); if (!list_empty(&go->vidq_active)) vb = go->active_buf = list_first_entry(&go->vidq_active, struct go7007_buffer, list); - spin_unlock(&go->spinlock); + spin_unlock_irqrestore(&go->spinlock, flags); go->next_seq++; return vb; } @@ -468,7 +469,7 @@ static struct go7007_buffer *frame_boundary(struct go7007 *go, struct go7007_buf vb->vb.vb2_buf.timestamp = ktime_get_ns(); vb_tmp = vb; - spin_lock(&go->spinlock); + spin_lock_irqsave(&go->spinlock, flags); list_del(&vb->list); if (list_empty(&go->vidq_active)) vb = NULL; @@ -476,7 +477,7 @@ static struct go7007_buffer *frame_boundary(struct go7007 *go, struct go7007_buf vb = list_first_entry(&go->vidq_active, struct go7007_buffer, list); go->active_buf = vb; - spin_unlock(&go->spinlock); + spin_unlock_irqrestore(&go->spinlock, flags); vb2_buffer_done(&vb_tmp->vb.vb2_buf, VB2_BUF_STATE_DONE); return vb; } diff --git a/drivers/media/usb/go7007/snd-go7007.c b/drivers/media/usb/go7007/snd-go7007.c index f84a2130f033..137fc253b122 100644 --- a/drivers/media/usb/go7007/snd-go7007.c +++ b/drivers/media/usb/go7007/snd-go7007.c @@ -75,13 +75,14 @@ static void parse_audio_stream_data(struct go7007 *go, u8 *buf, int length) struct go7007_snd *gosnd = go->snd_context; struct snd_pcm_runtime *runtime = gosnd->substream->runtime; int frames = bytes_to_frames(runtime, length); + unsigned long flags; - spin_lock(&gosnd->lock); + spin_lock_irqsave(&gosnd->lock, flags); gosnd->hw_ptr += frames; if (gosnd->hw_ptr >= runtime->buffer_size) gosnd->hw_ptr -= runtime->buffer_size; gosnd->avail += frames; - spin_unlock(&gosnd->lock); + spin_unlock_irqrestore(&gosnd->lock, flags); if (gosnd->w_idx + length > runtime->dma_bytes) { int cpy = runtime->dma_bytes - gosnd->w_idx; @@ -92,13 +93,13 @@ static void parse_audio_stream_data(struct go7007 *go, u8 *buf, int length) } memcpy(runtime->dma_area + gosnd->w_idx, buf, length); gosnd->w_idx += length; - spin_lock(&gosnd->lock); + spin_lock_irqsave(&gosnd->lock, flags); if (gosnd->avail < runtime->period_size) { - spin_unlock(&gosnd->lock); + spin_unlock_irqrestore(&gosnd->lock, flags); return; } gosnd->avail -= runtime->period_size; - spin_unlock(&gosnd->lock); + spin_unlock_irqrestore(&gosnd->lock, flags); if (gosnd->capturing) snd_pcm_period_elapsed(gosnd->substream); } diff --git a/drivers/media/usb/gspca/kinect.c b/drivers/media/usb/gspca/kinect.c index 0cfdf8a1e19d..f993f6280c56 100644 --- a/drivers/media/usb/gspca/kinect.c +++ b/drivers/media/usb/gspca/kinect.c @@ -163,7 +163,7 @@ static int send_cmd(struct gspca_dev *gspca_dev, uint16_t cmd, void *cmdbuf, actual_len = kinect_read(udev, ibuf, 0x200); } while (actual_len == 0); gspca_dbg(gspca_dev, D_USBO, "Control reply: %d\n", actual_len); - if (actual_len < sizeof(*rhdr)) { + if (actual_len < (int)sizeof(*rhdr)) { pr_err("send_cmd: Input control transfer failed (%d)\n", actual_len); return actual_len < 0 ? actual_len : -EREMOTEIO; diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c index 6d692fb3e8dd..34085a0b15a1 100644 --- a/drivers/media/usb/hackrf/hackrf.c +++ b/drivers/media/usb/hackrf/hackrf.c @@ -597,7 +597,7 @@ static int hackrf_submit_urbs(struct hackrf_dev *dev) for (i = 0; i < dev->urbs_initialized; i++) { dev_dbg(dev->dev, "submit urb=%d\n", i); - ret = usb_submit_urb(dev->urb_list[i], GFP_ATOMIC); + ret = usb_submit_urb(dev->urb_list[i], GFP_KERNEL); if (ret) { dev_err(dev->dev, "Could not submit URB no. %d - get them all back\n", i); @@ -636,7 +636,7 @@ static int hackrf_alloc_stream_bufs(struct hackrf_dev *dev) for (dev->buf_num = 0; dev->buf_num < MAX_BULK_BUFS; dev->buf_num++) { dev->buf_list[dev->buf_num] = usb_alloc_coherent(dev->udev, - BULK_BUFFER_SIZE, GFP_ATOMIC, + BULK_BUFFER_SIZE, GFP_KERNEL, &dev->dma_addr[dev->buf_num]); if (!dev->buf_list[dev->buf_num]) { dev_dbg(dev->dev, "alloc buf=%d failed\n", @@ -689,7 +689,7 @@ static int hackrf_alloc_urbs(struct hackrf_dev *dev, bool rcv) /* allocate the URBs */ for (i = 0; i < MAX_BULK_BUFS; i++) { dev_dbg(dev->dev, "alloc urb=%d\n", i); - dev->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); + dev->urb_list[i] = usb_alloc_urb(0, GFP_KERNEL); if (!dev->urb_list[i]) { for (j = 0; j < i; j++) usb_free_urb(dev->urb_list[j]); diff --git a/drivers/media/usb/hdpvr/hdpvr-i2c.c b/drivers/media/usb/hdpvr/hdpvr-i2c.c index c71ddefd2e58..5a3cb614a211 100644 --- a/drivers/media/usb/hdpvr/hdpvr-i2c.c +++ b/drivers/media/usb/hdpvr/hdpvr-i2c.c @@ -117,9 +117,6 @@ static int hdpvr_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs, struct hdpvr_device *dev = i2c_get_adapdata(i2c_adapter); int retval = 0, addr; - if (num <= 0) - return 0; - mutex_lock(&dev->i2c_mutex); addr = msgs[0].addr << 1; diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index 77b759a0bcd9..504e413edcd2 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -802,6 +802,7 @@ int stk1160_vb2_setup(struct stk1160 *dev) q->buf_struct_size = sizeof(struct stk1160_buffer); q->ops = &stk1160_video_qops; q->mem_ops = &vb2_vmalloc_memops; + q->lock = &dev->vb_queue_lock; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; rc = vb2_queue_init(q); @@ -827,7 +828,6 @@ int stk1160_video_register(struct stk1160 *dev) * It will be used to protect *only* v4l2 ioctls. */ dev->vdev.lock = &dev->v4l_lock; - dev->vdev.queue->lock = &dev->vb_queue_lock; /* This will be used to set video_device parent */ dev->vdev.v4l2_dev = &dev->v4l2_dev; diff --git a/drivers/media/usb/tm6000/tm6000-dvb.c b/drivers/media/usb/tm6000/tm6000-dvb.c index c811fc6cf48a..3a4e545c6037 100644 --- a/drivers/media/usb/tm6000/tm6000-dvb.c +++ b/drivers/media/usb/tm6000/tm6000-dvb.c @@ -266,6 +266,11 @@ static int register_dvb(struct tm6000_core *dev) ret = dvb_register_adapter(&dvb->adapter, "Trident TVMaster 6000 DVB-T", THIS_MODULE, &dev->udev->dev, adapter_nr); + if (ret < 0) { + pr_err("tm6000: couldn't register the adapter!\n"); + goto err; + } + dvb->adapter.priv = dev; if (dvb->frontend) { diff --git a/drivers/media/usb/tm6000/tm6000-i2c.c b/drivers/media/usb/tm6000/tm6000-i2c.c index 659b63febf85..ccd1adf862b1 100644 --- a/drivers/media/usb/tm6000/tm6000-i2c.c +++ b/drivers/media/usb/tm6000/tm6000-i2c.c @@ -145,8 +145,6 @@ static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap, 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:", diff --git a/drivers/media/usb/ttusb-dec/ttusbdecfe.c b/drivers/media/usb/ttusb-dec/ttusbdecfe.c index 6ea05d909024..278bf6c5855b 100644 --- a/drivers/media/usb/ttusb-dec/ttusbdecfe.c +++ b/drivers/media/usb/ttusb-dec/ttusbdecfe.c @@ -247,9 +247,9 @@ static const struct dvb_frontend_ops ttusbdecfe_dvbt_ops = { .delsys = { SYS_DVBT }, .info = { .name = "TechnoTrend/Hauppauge DEC2000-t Frontend", - .frequency_min = 51000000, - .frequency_max = 858000000, - .frequency_stepsize = 62500, + .frequency_min_hz = 51 * MHz, + .frequency_max_hz = 858 * MHz, + .frequency_stepsize_hz = 62500, .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | @@ -270,9 +270,9 @@ static const struct dvb_frontend_ops ttusbdecfe_dvbs_ops = { .delsys = { SYS_DVBS }, .info = { .name = "TechnoTrend/Hauppauge DEC3000-s Frontend", - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 125, + .frequency_min_hz = 950 * MHz, + .frequency_max_hz = 2150 * MHz, + .frequency_stepsize_hz = 125 * kHz, .symbol_rate_min = 1000000, /* guessed */ .symbol_rate_max = 45000000, /* guessed */ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | diff --git a/drivers/media/usb/usbtv/usbtv-audio.c b/drivers/media/usb/usbtv/usbtv-audio.c index 2c2ca77fa01f..4ce38246ed64 100644 --- a/drivers/media/usb/usbtv/usbtv-audio.c +++ b/drivers/media/usb/usbtv/usbtv-audio.c @@ -126,6 +126,7 @@ static void usbtv_audio_urb_received(struct urb *urb) struct snd_pcm_runtime *runtime = substream->runtime; size_t i, frame_bytes, chunk_length, buffer_pos, period_pos; int period_elapsed; + unsigned long flags; void *urb_current; switch (urb->status) { @@ -179,12 +180,12 @@ static void usbtv_audio_urb_received(struct urb *urb) } } - snd_pcm_stream_lock(substream); + snd_pcm_stream_lock_irqsave(substream, flags); chip->snd_buffer_pos = buffer_pos; chip->snd_period_pos = period_pos; - snd_pcm_stream_unlock(substream); + snd_pcm_stream_unlock_irqrestore(substream, flags); if (period_elapsed) snd_pcm_period_elapsed(substream); diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index a36b4fb949fa..c2ad102bd693 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -20,6 +20,7 @@ #include <linux/videodev2.h> #include <linux/vmalloc.h> #include <linux/wait.h> +#include <linux/workqueue.h> #include <linux/atomic.h> #include <media/v4l2-ctrls.h> @@ -971,12 +972,30 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain, return 0; } +static s32 __uvc_ctrl_get_value(struct uvc_control_mapping *mapping, + const u8 *data) +{ + s32 value = mapping->get(mapping, UVC_GET_CUR, data); + + if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) { + struct uvc_menu_info *menu = mapping->menu_info; + unsigned int i; + + for (i = 0; i < mapping->menu_count; ++i, ++menu) { + if (menu->value == value) { + value = i; + break; + } + } + } + + return value; +} + static int __uvc_ctrl_get(struct uvc_video_chain *chain, struct uvc_control *ctrl, struct uvc_control_mapping *mapping, s32 *value) { - struct uvc_menu_info *menu; - unsigned int i; int ret; if ((ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) == 0) @@ -993,18 +1012,8 @@ static int __uvc_ctrl_get(struct uvc_video_chain *chain, ctrl->loaded = 1; } - *value = mapping->get(mapping, UVC_GET_CUR, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); - - if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) { - menu = mapping->menu_info; - for (i = 0; i < mapping->menu_count; ++i, ++menu) { - if (menu->value == *value) { - *value = i; - break; - } - } - } + *value = __uvc_ctrl_get_value(mapping, + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); return 0; } @@ -1125,7 +1134,7 @@ done: } /* - * Mapping V4L2 controls to UVC controls can be straighforward if done well. + * Mapping V4L2 controls to UVC controls can be straightforward if done well. * Most of the UVC controls exist in V4L2, and can be mapped directly. Some * must be grouped (for instance the Red Balance, Blue Balance and Do White * Balance V4L2 controls use the White Balance Component UVC control) or @@ -1216,53 +1225,135 @@ static void uvc_ctrl_fill_event(struct uvc_video_chain *chain, ev->u.ctrl.default_value = v4l2_ctrl.default_value; } -static void uvc_ctrl_send_event(struct uvc_fh *handle, - struct uvc_control *ctrl, struct uvc_control_mapping *mapping, - s32 value, u32 changes) +/* + * Send control change events to all subscribers for the @ctrl control. By + * default the subscriber that generated the event, as identified by @handle, + * is not notified unless it has set the V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK flag. + * @handle can be NULL for asynchronous events related to auto-update controls, + * in which case all subscribers are notified. + */ +static void uvc_ctrl_send_event(struct uvc_video_chain *chain, + struct uvc_fh *handle, struct uvc_control *ctrl, + struct uvc_control_mapping *mapping, s32 value, u32 changes) { + struct v4l2_fh *originator = handle ? &handle->vfh : NULL; struct v4l2_subscribed_event *sev; struct v4l2_event ev; if (list_empty(&mapping->ev_subs)) return; - uvc_ctrl_fill_event(handle->chain, &ev, ctrl, mapping, value, changes); + uvc_ctrl_fill_event(chain, &ev, ctrl, mapping, value, changes); list_for_each_entry(sev, &mapping->ev_subs, node) { - if (sev->fh && (sev->fh != &handle->vfh || + if (sev->fh != originator || (sev->flags & V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK) || - (changes & V4L2_EVENT_CTRL_CH_FLAGS))) + (changes & V4L2_EVENT_CTRL_CH_FLAGS)) v4l2_event_queue_fh(sev->fh, &ev); } } -static void uvc_ctrl_send_slave_event(struct uvc_fh *handle, - struct uvc_control *master, u32 slave_id, - const struct v4l2_ext_control *xctrls, unsigned int xctrls_count) +/* + * Send control change events for the slave of the @master control identified + * by the V4L2 ID @slave_id. The @handle identifies the event subscriber that + * generated the event and may be NULL for auto-update events. + */ +static void uvc_ctrl_send_slave_event(struct uvc_video_chain *chain, + struct uvc_fh *handle, struct uvc_control *master, u32 slave_id) { struct uvc_control_mapping *mapping = NULL; struct uvc_control *ctrl = NULL; u32 changes = V4L2_EVENT_CTRL_CH_FLAGS; - unsigned int i; s32 val = 0; - /* - * We can skip sending an event for the slave if the slave - * is being modified in the same transaction. - */ - for (i = 0; i < xctrls_count; i++) { - if (xctrls[i].id == slave_id) - return; - } - __uvc_find_control(master->entity, slave_id, &mapping, &ctrl, 0); if (ctrl == NULL) return; - if (__uvc_ctrl_get(handle->chain, ctrl, mapping, &val) == 0) + if (__uvc_ctrl_get(chain, ctrl, mapping, &val) == 0) changes |= V4L2_EVENT_CTRL_CH_VALUE; - uvc_ctrl_send_event(handle, ctrl, mapping, val, changes); + uvc_ctrl_send_event(chain, handle, ctrl, mapping, val, changes); +} + +static void uvc_ctrl_status_event_work(struct work_struct *work) +{ + struct uvc_device *dev = container_of(work, struct uvc_device, + async_ctrl.work); + struct uvc_ctrl_work *w = &dev->async_ctrl; + struct uvc_video_chain *chain = w->chain; + struct uvc_control_mapping *mapping; + struct uvc_control *ctrl = w->ctrl; + struct uvc_fh *handle; + unsigned int i; + int ret; + + mutex_lock(&chain->ctrl_mutex); + + handle = ctrl->handle; + ctrl->handle = NULL; + + list_for_each_entry(mapping, &ctrl->info.mappings, list) { + s32 value = __uvc_ctrl_get_value(mapping, w->data); + + /* + * handle may be NULL here if the device sends auto-update + * events without a prior related control set from userspace. + */ + for (i = 0; i < ARRAY_SIZE(mapping->slave_ids); ++i) { + if (!mapping->slave_ids[i]) + break; + + uvc_ctrl_send_slave_event(chain, handle, ctrl, + mapping->slave_ids[i]); + } + + uvc_ctrl_send_event(chain, handle, ctrl, mapping, value, + V4L2_EVENT_CTRL_CH_VALUE); + } + + mutex_unlock(&chain->ctrl_mutex); + + /* Resubmit the URB. */ + w->urb->interval = dev->int_ep->desc.bInterval; + ret = usb_submit_urb(w->urb, GFP_KERNEL); + if (ret < 0) + uvc_printk(KERN_ERR, "Failed to resubmit status URB (%d).\n", + ret); +} + +bool uvc_ctrl_status_event(struct urb *urb, struct uvc_video_chain *chain, + struct uvc_control *ctrl, const u8 *data) +{ + struct uvc_device *dev = chain->dev; + struct uvc_ctrl_work *w = &dev->async_ctrl; + + if (list_empty(&ctrl->info.mappings)) { + ctrl->handle = NULL; + return false; + } + + w->data = data; + w->urb = urb; + w->chain = chain; + w->ctrl = ctrl; + + schedule_work(&w->work); + + return true; +} + +static bool uvc_ctrl_xctrls_has_control(const struct v4l2_ext_control *xctrls, + unsigned int xctrls_count, u32 id) +{ + unsigned int i; + + for (i = 0; i < xctrls_count; ++i) { + if (xctrls[i].id == id) + return true; + } + + return false; } static void uvc_ctrl_send_events(struct uvc_fh *handle, @@ -1277,29 +1368,39 @@ static void uvc_ctrl_send_events(struct uvc_fh *handle, for (i = 0; i < xctrls_count; ++i) { ctrl = uvc_find_control(handle->chain, xctrls[i].id, &mapping); + if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS) + /* Notification will be sent from an Interrupt event. */ + continue; + for (j = 0; j < ARRAY_SIZE(mapping->slave_ids); ++j) { - if (!mapping->slave_ids[j]) + u32 slave_id = mapping->slave_ids[j]; + + if (!slave_id) break; - uvc_ctrl_send_slave_event(handle, ctrl, - mapping->slave_ids[j], - xctrls, xctrls_count); + + /* + * We can skip sending an event for the slave if the + * slave is being modified in the same transaction. + */ + if (uvc_ctrl_xctrls_has_control(xctrls, xctrls_count, + slave_id)) + continue; + + uvc_ctrl_send_slave_event(handle->chain, handle, ctrl, + slave_id); } /* * If the master is being modified in the same transaction * flags may change too. */ - if (mapping->master_id) { - for (j = 0; j < xctrls_count; j++) { - if (xctrls[j].id == mapping->master_id) { - changes |= V4L2_EVENT_CTRL_CH_FLAGS; - break; - } - } - } + if (mapping->master_id && + uvc_ctrl_xctrls_has_control(xctrls, xctrls_count, + mapping->master_id)) + changes |= V4L2_EVENT_CTRL_CH_FLAGS; - uvc_ctrl_send_event(handle, ctrl, mapping, xctrls[i].value, - changes); + uvc_ctrl_send_event(handle->chain, handle, ctrl, mapping, + xctrls[i].value, changes); } } @@ -1472,9 +1573,10 @@ int uvc_ctrl_get(struct uvc_video_chain *chain, return __uvc_ctrl_get(chain, ctrl, mapping, &xctrl->value); } -int uvc_ctrl_set(struct uvc_video_chain *chain, +int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl) { + struct uvc_video_chain *chain = handle->chain; struct uvc_control *ctrl; struct uvc_control_mapping *mapping; s32 value; @@ -1581,6 +1683,9 @@ int uvc_ctrl_set(struct uvc_video_chain *chain, mapping->set(mapping, value, uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); + if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS) + ctrl->handle = handle; + ctrl->dirty = 1; ctrl->modified = 1; return 0; @@ -1612,7 +1717,9 @@ static int uvc_ctrl_get_flags(struct uvc_device *dev, | (data[0] & UVC_CONTROL_CAP_SET ? UVC_CTRL_FLAG_SET_CUR : 0) | (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ? - UVC_CTRL_FLAG_AUTO_UPDATE : 0); + UVC_CTRL_FLAG_AUTO_UPDATE : 0) + | (data[0] & UVC_CONTROL_CAP_ASYNCHRONOUS ? + UVC_CTRL_FLAG_ASYNCHRONOUS : 0); kfree(data); return ret; @@ -2173,6 +2280,8 @@ int uvc_ctrl_init_device(struct uvc_device *dev) struct uvc_entity *entity; unsigned int i; + INIT_WORK(&dev->async_ctrl.work, uvc_ctrl_status_event_work); + /* Walk the entities list and instantiate controls */ list_for_each_entry(entity, &dev->entities, list) { struct uvc_control *ctrl; @@ -2241,6 +2350,8 @@ void uvc_ctrl_cleanup_device(struct uvc_device *dev) struct uvc_entity *entity; unsigned int i; + cancel_work_sync(&dev->async_ctrl.work); + /* Free controls and control mappings for all entities. */ list_for_each_entry(entity, &dev->entities, list) { for (i = 0; i < entity->ncontrols; ++i) { diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 8e138201330f..d46dc432456c 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -100,6 +100,11 @@ static struct uvc_format_desc uvc_fmts[] = { .fcc = V4L2_PIX_FMT_GREY, }, { + .name = "IR 8-bit (L8_IR)", + .guid = UVC_GUID_FORMAT_KSMEDIA_L8_IR, + .fcc = V4L2_PIX_FMT_GREY, + }, + { .name = "Greyscale 10-bit (Y10 )", .guid = UVC_GUID_FORMAT_Y10, .fcc = V4L2_PIX_FMT_Y10, diff --git a/drivers/media/usb/uvc/uvc_status.c b/drivers/media/usb/uvc/uvc_status.c index 7b710410584a..0722dc684378 100644 --- a/drivers/media/usb/uvc/uvc_status.c +++ b/drivers/media/usb/uvc/uvc_status.c @@ -78,7 +78,24 @@ static void uvc_input_report_key(struct uvc_device *dev, unsigned int code, /* -------------------------------------------------------------------------- * Status interrupt endpoint */ -static void uvc_event_streaming(struct uvc_device *dev, u8 *data, int len) +struct uvc_streaming_status { + u8 bStatusType; + u8 bOriginator; + u8 bEvent; + u8 bValue[]; +} __packed; + +struct uvc_control_status { + u8 bStatusType; + u8 bOriginator; + u8 bEvent; + u8 bSelector; + u8 bAttribute; + u8 bValue[]; +} __packed; + +static void uvc_event_streaming(struct uvc_device *dev, + struct uvc_streaming_status *status, int len) { if (len < 3) { uvc_trace(UVC_TRACE_STATUS, "Invalid streaming status event " @@ -86,31 +103,97 @@ static void uvc_event_streaming(struct uvc_device *dev, u8 *data, int len) return; } - if (data[2] == 0) { + if (status->bEvent == 0) { if (len < 4) return; uvc_trace(UVC_TRACE_STATUS, "Button (intf %u) %s len %d\n", - data[1], data[3] ? "pressed" : "released", len); - uvc_input_report_key(dev, KEY_CAMERA, data[3]); + status->bOriginator, + status->bValue[0] ? "pressed" : "released", len); + uvc_input_report_key(dev, KEY_CAMERA, status->bValue[0]); } else { uvc_trace(UVC_TRACE_STATUS, "Stream %u error event %02x len %d.\n", - data[1], data[2], len); + status->bOriginator, status->bEvent, len); } } -static void uvc_event_control(struct uvc_device *dev, u8 *data, int len) +#define UVC_CTRL_VALUE_CHANGE 0 +#define UVC_CTRL_INFO_CHANGE 1 +#define UVC_CTRL_FAILURE_CHANGE 2 +#define UVC_CTRL_MIN_CHANGE 3 +#define UVC_CTRL_MAX_CHANGE 4 + +static struct uvc_control *uvc_event_entity_find_ctrl(struct uvc_entity *entity, + u8 selector) { - char *attrs[3] = { "value", "info", "failure" }; + struct uvc_control *ctrl; + unsigned int i; + + for (i = 0, ctrl = entity->controls; i < entity->ncontrols; i++, ctrl++) + if (ctrl->info.selector == selector) + return ctrl; + + return NULL; +} - if (len < 6 || data[2] != 0 || data[4] > 2) { +static struct uvc_control *uvc_event_find_ctrl(struct uvc_device *dev, + const struct uvc_control_status *status, + struct uvc_video_chain **chain) +{ + list_for_each_entry((*chain), &dev->chains, list) { + struct uvc_entity *entity; + struct uvc_control *ctrl; + + list_for_each_entry(entity, &(*chain)->entities, chain) { + if (entity->id != status->bOriginator) + continue; + + ctrl = uvc_event_entity_find_ctrl(entity, + status->bSelector); + if (ctrl) + return ctrl; + } + } + + return NULL; +} + +static bool uvc_event_control(struct urb *urb, + const struct uvc_control_status *status, int len) +{ + static const char *attrs[] = { "value", "info", "failure", "min", "max" }; + struct uvc_device *dev = urb->context; + struct uvc_video_chain *chain; + struct uvc_control *ctrl; + + if (len < 6 || status->bEvent != 0 || + status->bAttribute >= ARRAY_SIZE(attrs)) { uvc_trace(UVC_TRACE_STATUS, "Invalid control status event " "received.\n"); - return; + return false; } uvc_trace(UVC_TRACE_STATUS, "Control %u/%u %s change len %d.\n", - data[1], data[3], attrs[data[4]], len); + status->bOriginator, status->bSelector, + attrs[status->bAttribute], len); + + /* Find the control. */ + ctrl = uvc_event_find_ctrl(dev, status, &chain); + if (!ctrl) + return false; + + switch (status->bAttribute) { + case UVC_CTRL_VALUE_CHANGE: + return uvc_ctrl_status_event(urb, chain, ctrl, status->bValue); + + case UVC_CTRL_INFO_CHANGE: + case UVC_CTRL_FAILURE_CHANGE: + case UVC_CTRL_MIN_CHANGE: + case UVC_CTRL_MAX_CHANGE: + break; + } + + return false; } static void uvc_status_complete(struct urb *urb) @@ -138,13 +221,23 @@ static void uvc_status_complete(struct urb *urb) len = urb->actual_length; if (len > 0) { switch (dev->status[0] & 0x0f) { - case UVC_STATUS_TYPE_CONTROL: - uvc_event_control(dev, dev->status, len); + case UVC_STATUS_TYPE_CONTROL: { + struct uvc_control_status *status = + (struct uvc_control_status *)dev->status; + + if (uvc_event_control(urb, status, len)) + /* The URB will be resubmitted in work context. */ + return; break; + } - case UVC_STATUS_TYPE_STREAMING: - uvc_event_streaming(dev, dev->status, len); + case UVC_STATUS_TYPE_STREAMING: { + struct uvc_streaming_status *status = + (struct uvc_streaming_status *)dev->status; + + uvc_event_streaming(dev, status, len); break; + } default: uvc_trace(UVC_TRACE_STATUS, "Unknown status event " diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index bd32914259ae..18a7384b50ee 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -994,7 +994,7 @@ static int uvc_ioctl_s_ctrl(struct file *file, void *fh, if (ret < 0) return ret; - ret = uvc_ctrl_set(chain, &xctrl); + ret = uvc_ctrl_set(handle, &xctrl); if (ret < 0) { uvc_ctrl_rollback(handle); return ret; @@ -1069,7 +1069,7 @@ static int uvc_ioctl_s_try_ext_ctrls(struct uvc_fh *handle, return ret; for (i = 0; i < ctrls->count; ++ctrl, ++i) { - ret = uvc_ctrl_set(chain, ctrl); + ret = uvc_ctrl_set(handle, ctrl); if (ret < 0) { uvc_ctrl_rollback(handle); ctrls->error_idx = commit ? ctrls->count : i; diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index a88b2e51a666..86a99f461fd8 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -73,17 +73,57 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit, u8 intfnum, u8 cs, void *data, u16 size) { int ret; + u8 error; + u8 tmp; ret = __uvc_query_ctrl(dev, query, unit, intfnum, cs, data, size, UVC_CTRL_CONTROL_TIMEOUT); - if (ret != size) { - uvc_printk(KERN_ERR, "Failed to query (%s) UVC control %u on " - "unit %u: %d (exp. %u).\n", uvc_query_name(query), cs, - unit, ret, size); - return -EIO; + if (likely(ret == size)) + return 0; + + uvc_printk(KERN_ERR, + "Failed to query (%s) UVC control %u on unit %u: %d (exp. %u).\n", + uvc_query_name(query), cs, unit, ret, size); + + if (ret != -EPIPE) + return ret; + + tmp = *(u8 *)data; + + ret = __uvc_query_ctrl(dev, UVC_GET_CUR, 0, intfnum, + UVC_VC_REQUEST_ERROR_CODE_CONTROL, data, 1, + UVC_CTRL_CONTROL_TIMEOUT); + + error = *(u8 *)data; + *(u8 *)data = tmp; + + if (ret != 1) + return ret < 0 ? ret : -EPIPE; + + uvc_trace(UVC_TRACE_CONTROL, "Control error %u\n", error); + + switch (error) { + case 0: + /* Cannot happen - we received a STALL */ + return -EPIPE; + case 1: /* Not ready */ + return -EBUSY; + case 2: /* Wrong state */ + return -EILSEQ; + case 3: /* Power */ + return -EREMOTE; + case 4: /* Out of range */ + return -ERANGE; + case 5: /* Invalid unit */ + case 6: /* Invalid control */ + case 7: /* Invalid Request */ + case 8: /* Invalid value within range */ + return -EINVAL; + default: /* reserved or unknown */ + break; } - return 0; + return -EPIPE; } static void uvc_fixup_video_ctrl(struct uvc_streaming *stream, @@ -1232,6 +1272,8 @@ static void uvc_video_validate_buffer(const struct uvc_streaming *stream, static void uvc_video_next_buffers(struct uvc_streaming *stream, struct uvc_buffer **video_buf, struct uvc_buffer **meta_buf) { + uvc_video_validate_buffer(stream, *video_buf); + if (*meta_buf) { struct vb2_v4l2_buffer *vb2_meta = &(*meta_buf)->buf; const struct vb2_v4l2_buffer *vb2_video = &(*video_buf)->buf; @@ -1270,10 +1312,8 @@ static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream, do { ret = uvc_video_decode_start(stream, buf, mem, urb->iso_frame_desc[i].actual_length); - if (ret == -EAGAIN) { - uvc_video_validate_buffer(stream, buf); + if (ret == -EAGAIN) uvc_video_next_buffers(stream, &buf, &meta_buf); - } } while (ret == -EAGAIN); if (ret < 0) @@ -1289,10 +1329,8 @@ static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream, uvc_video_decode_end(stream, buf, mem, urb->iso_frame_desc[i].actual_length); - if (buf->state == UVC_BUF_STATE_READY) { - uvc_video_validate_buffer(stream, buf); + if (buf->state == UVC_BUF_STATE_READY) uvc_video_next_buffers(stream, &buf, &meta_buf); - } } } diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index be5cf179228b..e5f5d84f1d1d 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -12,6 +12,7 @@ #include <linux/usb/video.h> #include <linux/uvcvideo.h> #include <linux/videodev2.h> +#include <linux/workqueue.h> #include <media/media-device.h> #include <media/v4l2-device.h> #include <media/v4l2-event.h> @@ -157,6 +158,9 @@ #define UVC_GUID_FORMAT_D3DFMT_L8 \ {0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, \ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_KSMEDIA_L8_IR \ + {0x32, 0x00, 0x00, 0x00, 0x02, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} /* ------------------------------------------------------------------------ @@ -256,6 +260,8 @@ struct uvc_control { initialized:1; u8 *uvc_data; + + struct uvc_fh *handle; /* File handle that last changed the control. */ }; struct uvc_format_desc { @@ -600,6 +606,14 @@ struct uvc_device { u8 *status; struct input_dev *input; char input_phys[64]; + + struct uvc_ctrl_work { + struct work_struct work; + struct urb *urb; + struct uvc_video_chain *chain; + struct uvc_control *ctrl; + const void *data; + } async_ctrl; }; enum uvc_handle_state { @@ -753,6 +767,8 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain, int uvc_ctrl_init_device(struct uvc_device *dev); void uvc_ctrl_cleanup_device(struct uvc_device *dev); int uvc_ctrl_restore_values(struct uvc_device *dev); +bool uvc_ctrl_status_event(struct urb *urb, struct uvc_video_chain *chain, + struct uvc_control *ctrl, const u8 *data); int uvc_ctrl_begin(struct uvc_video_chain *chain); int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback, @@ -770,7 +786,7 @@ static inline int uvc_ctrl_rollback(struct uvc_fh *handle) } int uvc_ctrl_get(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl); -int uvc_ctrl_set(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl); +int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl); int uvc_xu_ctrl_query(struct uvc_video_chain *chain, struct uvc_xu_control_query *xqry); |