diff options
Diffstat (limited to 'drivers/media')
40 files changed, 586 insertions, 583 deletions
diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c index 8fa539dde1b..7f7079b12f2 100644 --- a/drivers/media/rc/fintek-cir.c +++ b/drivers/media/rc/fintek-cir.c @@ -597,12 +597,17 @@ static void __devexit fintek_remove(struct pnp_dev *pdev) static int fintek_suspend(struct pnp_dev *pdev, pm_message_t state) { struct fintek_dev *fintek = pnp_get_drvdata(pdev); + unsigned long flags; fit_dbg("%s called", __func__); + spin_lock_irqsave(&fintek->fintek_lock, flags); + /* disable all CIR interrupts */ fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS); + spin_unlock_irqrestore(&fintek->fintek_lock, flags); + fintek_config_mode_enable(fintek); /* disable cir logical dev */ diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 3f3c7071626..6bc35eeb653 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -307,6 +307,14 @@ static const struct { /* 0xffdc iMON MCE VFD */ { 0x00010000ffffffeell, KEY_VOLUMEUP }, { 0x01000000ffffffeell, KEY_VOLUMEDOWN }, + { 0x00000001ffffffeell, KEY_MUTE }, + { 0x0000000fffffffeell, KEY_MEDIA }, + { 0x00000012ffffffeell, KEY_UP }, + { 0x00000013ffffffeell, KEY_DOWN }, + { 0x00000014ffffffeell, KEY_LEFT }, + { 0x00000015ffffffeell, KEY_RIGHT }, + { 0x00000016ffffffeell, KEY_ENTER }, + { 0x00000017ffffffeell, KEY_ESC }, /* iMON Knob values */ { 0x000100ffffffffeell, KEY_VOLUMEUP }, { 0x010000ffffffffeell, KEY_VOLUMEDOWN }, @@ -1582,16 +1590,16 @@ static void imon_incoming_packet(struct imon_context *ictx, /* Only panel type events left to process now */ spin_lock_irqsave(&ictx->kc_lock, flags); + do_gettimeofday(&t); /* KEY_MUTE repeats from knob need to be suppressed */ if (ictx->kc == KEY_MUTE && ictx->kc == ictx->last_keycode) { - do_gettimeofday(&t); msec = tv2int(&t, &prev_time); - prev_time = t; if (msec < ictx->idev->rep[REP_DELAY]) { spin_unlock_irqrestore(&ictx->kc_lock, flags); return; } } + prev_time = t; kc = ictx->kc; spin_unlock_irqrestore(&ictx->kc_lock, flags); @@ -1603,7 +1611,9 @@ static void imon_incoming_packet(struct imon_context *ictx, input_report_key(ictx->idev, kc, 0); input_sync(ictx->idev); + spin_lock_irqsave(&ictx->kc_lock, flags); ictx->last_keycode = kc; + spin_unlock_irqrestore(&ictx->kc_lock, flags); return; @@ -1740,6 +1750,8 @@ static void imon_get_ffdc_type(struct imon_context *ictx) detected_display_type = IMON_DISPLAY_TYPE_VFD; break; /* iMON VFD, MCE IR */ + case 0x46: + case 0x7e: case 0x9e: dev_info(ictx->dev, "0xffdc iMON VFD, MCE IR"); detected_display_type = IMON_DISPLAY_TYPE_VFD; @@ -1755,6 +1767,9 @@ static void imon_get_ffdc_type(struct imon_context *ictx) dev_info(ictx->dev, "Unknown 0xffdc device, " "defaulting to VFD and iMON IR"); detected_display_type = IMON_DISPLAY_TYPE_VFD; + /* We don't know which one it is, allow user to set the + * RC6 one from userspace if OTHER wasn't correct. */ + allowed_protos |= RC_TYPE_RC6; break; } diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c index 11c19d8d0ee..423ed45d6c5 100644 --- a/drivers/media/rc/ir-raw.c +++ b/drivers/media/rc/ir-raw.c @@ -114,18 +114,20 @@ int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type) s64 delta; /* ns */ DEFINE_IR_RAW_EVENT(ev); int rc = 0; + int delay; if (!dev->raw) return -EINVAL; now = ktime_get(); delta = ktime_to_ns(ktime_sub(now, dev->raw->last_event)); + delay = MS_TO_NS(dev->input_dev->rep[REP_DELAY]); /* Check for a long duration since last event or if we're * being called for the first time, note that delta can't * possibly be negative. */ - if (delta > IR_MAX_DURATION || !dev->raw->last_type) + if (delta > delay || !dev->raw->last_type) type |= IR_START_EVENT; else ev.duration = delta; diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index e716b931cf7..ecd3d028076 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -1347,6 +1347,7 @@ static const struct ite_dev_params ite_dev_descs[] = { { /* 0: ITE8704 */ .model = "ITE8704 CIR transceiver", .io_region_size = IT87_IOREG_LENGTH, + .io_rsrc_no = 0, .hw_tx_capable = true, .sample_period = (u32) (1000000000ULL / 115200), .tx_carrier_freq = 38000, @@ -1371,6 +1372,7 @@ static const struct ite_dev_params ite_dev_descs[] = { { /* 1: ITE8713 */ .model = "ITE8713 CIR transceiver", .io_region_size = IT87_IOREG_LENGTH, + .io_rsrc_no = 0, .hw_tx_capable = true, .sample_period = (u32) (1000000000ULL / 115200), .tx_carrier_freq = 38000, @@ -1395,6 +1397,7 @@ static const struct ite_dev_params ite_dev_descs[] = { { /* 2: ITE8708 */ .model = "ITE8708 CIR transceiver", .io_region_size = IT8708_IOREG_LENGTH, + .io_rsrc_no = 0, .hw_tx_capable = true, .sample_period = (u32) (1000000000ULL / 115200), .tx_carrier_freq = 38000, @@ -1420,6 +1423,7 @@ static const struct ite_dev_params ite_dev_descs[] = { { /* 3: ITE8709 */ .model = "ITE8709 CIR transceiver", .io_region_size = IT8709_IOREG_LENGTH, + .io_rsrc_no = 2, .hw_tx_capable = true, .sample_period = (u32) (1000000000ULL / 115200), .tx_carrier_freq = 38000, @@ -1461,6 +1465,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id struct rc_dev *rdev = NULL; int ret = -ENOMEM; int model_no; + int io_rsrc_no; ite_dbg("%s called", __func__); @@ -1490,10 +1495,11 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id /* get the description for the device */ dev_desc = &ite_dev_descs[model_no]; + io_rsrc_no = dev_desc->io_rsrc_no; /* validate pnp resources */ - if (!pnp_port_valid(pdev, 0) || - pnp_port_len(pdev, 0) != dev_desc->io_region_size) { + if (!pnp_port_valid(pdev, io_rsrc_no) || + pnp_port_len(pdev, io_rsrc_no) != dev_desc->io_region_size) { dev_err(&pdev->dev, "IR PNP Port not valid!\n"); goto failure; } @@ -1504,7 +1510,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id } /* store resource values */ - itdev->cir_addr = pnp_port_start(pdev, 0); + itdev->cir_addr = pnp_port_start(pdev, io_rsrc_no); itdev->cir_irq = pnp_irq(pdev, 0); /* initialize spinlocks */ diff --git a/drivers/media/rc/ite-cir.h b/drivers/media/rc/ite-cir.h index 16a19f5fd71..aa899a0b975 100644 --- a/drivers/media/rc/ite-cir.h +++ b/drivers/media/rc/ite-cir.h @@ -57,6 +57,9 @@ struct ite_dev_params { /* size of the I/O region */ int io_region_size; + /* IR pnp I/O resource number */ + int io_rsrc_no; + /* true if the hardware supports transmission */ bool hw_tx_capable; diff --git a/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c index bb10ffe086b..8d558ae6345 100644 --- a/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c +++ b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c @@ -15,43 +15,39 @@ /* Pinnacle PCTV HD 800i mini remote */ static struct rc_map_table pinnacle_pctv_hd[] = { - - { 0x0f, KEY_1 }, - { 0x15, KEY_2 }, - { 0x10, KEY_3 }, - { 0x18, KEY_4 }, - { 0x1b, KEY_5 }, - { 0x1e, KEY_6 }, - { 0x11, KEY_7 }, - { 0x21, KEY_8 }, - { 0x12, KEY_9 }, - { 0x27, KEY_0 }, - - { 0x24, KEY_ZOOM }, - { 0x2a, KEY_SUBTITLE }, - - { 0x00, KEY_MUTE }, - { 0x01, KEY_ENTER }, /* Pinnacle Logo */ - { 0x39, KEY_POWER }, - - { 0x03, KEY_VOLUMEUP }, - { 0x09, KEY_VOLUMEDOWN }, - { 0x06, KEY_CHANNELUP }, - { 0x0c, KEY_CHANNELDOWN }, - - { 0x2d, KEY_REWIND }, - { 0x30, KEY_PLAYPAUSE }, - { 0x33, KEY_FASTFORWARD }, - { 0x3c, KEY_STOP }, - { 0x36, KEY_RECORD }, - { 0x3f, KEY_EPG }, /* Labeled "?" */ + /* Key codes for the tiny Pinnacle remote*/ + { 0x0700, KEY_MUTE }, + { 0x0701, KEY_MENU }, /* Pinnacle logo */ + { 0x0739, KEY_POWER }, + { 0x0703, KEY_VOLUMEUP }, + { 0x0709, KEY_VOLUMEDOWN }, + { 0x0706, KEY_CHANNELUP }, + { 0x070c, KEY_CHANNELDOWN }, + { 0x070f, KEY_1 }, + { 0x0715, KEY_2 }, + { 0x0710, KEY_3 }, + { 0x0718, KEY_4 }, + { 0x071b, KEY_5 }, + { 0x071e, KEY_6 }, + { 0x0711, KEY_7 }, + { 0x0721, KEY_8 }, + { 0x0712, KEY_9 }, + { 0x0727, KEY_0 }, + { 0x0724, KEY_ZOOM }, /* 'Square' key */ + { 0x072a, KEY_SUBTITLE }, /* 'T' key */ + { 0x072d, KEY_REWIND }, + { 0x0730, KEY_PLAYPAUSE }, + { 0x0733, KEY_FASTFORWARD }, + { 0x0736, KEY_RECORD }, + { 0x073c, KEY_STOP }, + { 0x073f, KEY_HELP }, /* '?' key */ }; static struct rc_map_list pinnacle_pctv_hd_map = { .map = { .scan = pinnacle_pctv_hd, .size = ARRAY_SIZE(pinnacle_pctv_hd), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .rc_type = RC_TYPE_RC5, .name = RC_MAP_PINNACLE_PCTV_HD, } }; diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index fd237ab120b..27997a9ceb0 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -55,6 +55,8 @@ struct irctl { struct lirc_buffer *buf; unsigned int chunk_size; + struct cdev *cdev; + struct task_struct *task; long jiffies_to_wait; }; @@ -62,7 +64,6 @@ struct irctl { static DEFINE_MUTEX(lirc_dev_lock); static struct irctl *irctls[MAX_IRCTL_DEVICES]; -static struct cdev cdevs[MAX_IRCTL_DEVICES]; /* Only used for sysfs but defined to void otherwise */ static struct class *lirc_class; @@ -167,9 +168,13 @@ static struct file_operations lirc_dev_fops = { static int lirc_cdev_add(struct irctl *ir) { - int retval; + int retval = -ENOMEM; struct lirc_driver *d = &ir->d; - struct cdev *cdev = &cdevs[d->minor]; + struct cdev *cdev; + + cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); + if (!cdev) + goto err_out; if (d->fops) { cdev_init(cdev, d->fops); @@ -180,12 +185,20 @@ static int lirc_cdev_add(struct irctl *ir) } retval = kobject_set_name(&cdev->kobj, "lirc%d", d->minor); if (retval) - return retval; + goto err_out; retval = cdev_add(cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1); - if (retval) + if (retval) { kobject_put(&cdev->kobj); + goto err_out; + } + + ir->cdev = cdev; + + return 0; +err_out: + kfree(cdev); return retval; } @@ -214,7 +227,7 @@ int lirc_register_driver(struct lirc_driver *d) if (MAX_IRCTL_DEVICES <= d->minor) { dev_err(d->dev, "lirc_dev: lirc_register_driver: " "\"minor\" must be between 0 and %d (%d)!\n", - MAX_IRCTL_DEVICES-1, d->minor); + MAX_IRCTL_DEVICES - 1, d->minor); err = -EBADRQC; goto out; } @@ -369,7 +382,7 @@ int lirc_unregister_driver(int minor) if (minor < 0 || minor >= MAX_IRCTL_DEVICES) { printk(KERN_ERR "lirc_dev: %s: minor (%d) must be between " - "0 and %d!\n", __func__, minor, MAX_IRCTL_DEVICES-1); + "0 and %d!\n", __func__, minor, MAX_IRCTL_DEVICES - 1); return -EBADRQC; } @@ -380,7 +393,7 @@ int lirc_unregister_driver(int minor) return -ENOENT; } - cdev = &cdevs[minor]; + cdev = ir->cdev; mutex_lock(&lirc_dev_lock); @@ -410,6 +423,7 @@ int lirc_unregister_driver(int minor) } else { lirc_irctl_cleanup(ir); cdev_del(cdev); + kfree(cdev); kfree(ir); irctls[minor] = NULL; } @@ -453,7 +467,7 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file) goto error; } - cdev = &cdevs[iminor(inode)]; + cdev = ir->cdev; if (try_module_get(cdev->owner)) { ir->open++; retval = ir->d.set_use_inc(ir->d.data); @@ -484,13 +498,15 @@ EXPORT_SYMBOL(lirc_dev_fop_open); int lirc_dev_fop_close(struct inode *inode, struct file *file) { struct irctl *ir = irctls[iminor(inode)]; - struct cdev *cdev = &cdevs[iminor(inode)]; + struct cdev *cdev; if (!ir) { printk(KERN_ERR "%s: called with invalid irctl\n", __func__); return -EINVAL; } + cdev = ir->cdev; + dev_dbg(ir->d.dev, LOGHEAD "close called\n", ir->d.name, ir->d.minor); WARN_ON(mutex_lock_killable(&lirc_dev_lock)); @@ -503,6 +519,7 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file) lirc_irctl_cleanup(ir); cdev_del(cdev); irctls[ir->d.minor] = NULL; + kfree(cdev); kfree(ir); } diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index ad927fcaa02..06dfe0957b5 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -108,6 +108,12 @@ static int debug = 1; static int debug; #endif +#define mce_dbg(dev, fmt, ...) \ + do { \ + if (debug) \ + dev_info(dev, fmt, ## __VA_ARGS__); \ + } while (0) + /* general constants */ #define SEND_FLAG_IN_PROGRESS 1 #define SEND_FLAG_COMPLETE 2 @@ -246,6 +252,9 @@ static struct usb_device_id mceusb_dev_table[] = { .driver_info = MCE_GEN2_TX_INV }, /* SMK eHome Infrared Transceiver */ { USB_DEVICE(VENDOR_SMK, 0x0338) }, + /* SMK/I-O Data GV-MC7/RCKIT Receiver */ + { USB_DEVICE(VENDOR_SMK, 0x0353), + .driver_info = MCE_GEN2_NO_TX }, /* Tatung eHome Infrared Transceiver */ { USB_DEVICE(VENDOR_TATUNG, 0x9150) }, /* Shuttle eHome Infrared Transceiver */ @@ -606,12 +615,15 @@ static void mce_async_callback(struct urb *urb, struct pt_regs *regs) if (ir) { len = urb->actual_length; - dev_dbg(ir->dev, "callback called (status=%d len=%d)\n", + mce_dbg(ir->dev, "callback called (status=%d len=%d)\n", urb->status, len); mceusb_dev_printdata(ir, urb->transfer_buffer, 0, len, true); } + /* the transfer buffer and urb were allocated in mce_request_packet */ + kfree(urb->transfer_buffer); + usb_free_urb(urb); } /* request incoming or send outgoing usb packet - used to initialize remote */ @@ -655,17 +667,17 @@ static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data, return; } - dev_dbg(dev, "receive request called (size=%#x)\n", size); + mce_dbg(dev, "receive request called (size=%#x)\n", size); async_urb->transfer_buffer_length = size; async_urb->dev = ir->usbdev; res = usb_submit_urb(async_urb, GFP_ATOMIC); if (res) { - dev_dbg(dev, "receive request FAILED! (res=%d)\n", res); + mce_dbg(dev, "receive request FAILED! (res=%d)\n", res); return; } - dev_dbg(dev, "receive request complete (res=%d)\n", res); + mce_dbg(dev, "receive request complete (res=%d)\n", res); } static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size) @@ -673,9 +685,9 @@ static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size) mce_request_packet(ir, data, size, MCEUSB_TX); } -static void mce_sync_in(struct mceusb_dev *ir, unsigned char *data, int size) +static void mce_flush_rx_buffer(struct mceusb_dev *ir, int size) { - mce_request_packet(ir, data, size, MCEUSB_RX); + mce_request_packet(ir, NULL, size, MCEUSB_RX); } /* Send data out the IR blaster port(s) */ @@ -794,7 +806,7 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier) ir->carrier = carrier; cmdbuf[2] = MCE_CMD_SIG_END; cmdbuf[3] = MCE_IRDATA_TRAILER; - dev_dbg(ir->dev, "%s: disabling carrier " + mce_dbg(ir->dev, "%s: disabling carrier " "modulation\n", __func__); mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); return carrier; @@ -806,7 +818,7 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier) ir->carrier = carrier; cmdbuf[2] = prescaler; cmdbuf[3] = divisor; - dev_dbg(ir->dev, "%s: requesting %u HZ " + mce_dbg(ir->dev, "%s: requesting %u HZ " "carrier\n", __func__, carrier); /* Transmit new carrier to mce device */ @@ -879,7 +891,7 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK) * US_TO_NS(MCE_TIME_UNIT); - dev_dbg(ir->dev, "Storing %s with duration %d\n", + mce_dbg(ir->dev, "Storing %s with duration %d\n", rawir.pulse ? "pulse" : "space", rawir.duration); @@ -911,7 +923,7 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) if (ir->parser_state != CMD_HEADER && !ir->rem) ir->parser_state = CMD_HEADER; } - dev_dbg(ir->dev, "processed IR data, calling ir_raw_event_handle\n"); + mce_dbg(ir->dev, "processed IR data, calling ir_raw_event_handle\n"); ir_raw_event_handle(ir->rc); } @@ -933,7 +945,7 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs) if (ir->send_flags == RECV_FLAG_IN_PROGRESS) { ir->send_flags = SEND_FLAG_COMPLETE; - dev_dbg(ir->dev, "setup answer received %d bytes\n", + mce_dbg(ir->dev, "setup answer received %d bytes\n", buf_len); } @@ -951,7 +963,7 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs) case -EPIPE: default: - dev_dbg(ir->dev, "Error: urb status = %d\n", urb->status); + mce_dbg(ir->dev, "Error: urb status = %d\n", urb->status); break; } @@ -961,7 +973,6 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs) static void mceusb_gen1_init(struct mceusb_dev *ir) { int ret; - int maxp = ir->len_in; struct device *dev = ir->dev; char *data; @@ -978,8 +989,8 @@ static void mceusb_gen1_init(struct mceusb_dev *ir) ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), USB_REQ_SET_ADDRESS, USB_TYPE_VENDOR, 0, 0, data, USB_CTRL_MSG_SZ, HZ * 3); - dev_dbg(dev, "%s - ret = %d\n", __func__, ret); - dev_dbg(dev, "%s - data[0] = %d, data[1] = %d\n", + mce_dbg(dev, "%s - ret = %d\n", __func__, ret); + mce_dbg(dev, "%s - data[0] = %d, data[1] = %d\n", __func__, data[0], data[1]); /* set feature: bit rate 38400 bps */ @@ -987,71 +998,56 @@ static void mceusb_gen1_init(struct mceusb_dev *ir) USB_REQ_SET_FEATURE, USB_TYPE_VENDOR, 0xc04e, 0x0000, NULL, 0, HZ * 3); - dev_dbg(dev, "%s - ret = %d\n", __func__, ret); + mce_dbg(dev, "%s - ret = %d\n", __func__, ret); /* bRequest 4: set char length to 8 bits */ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), 4, USB_TYPE_VENDOR, 0x0808, 0x0000, NULL, 0, HZ * 3); - dev_dbg(dev, "%s - retB = %d\n", __func__, ret); + mce_dbg(dev, "%s - retB = %d\n", __func__, ret); /* bRequest 2: set handshaking to use DTR/DSR */ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), 2, USB_TYPE_VENDOR, 0x0000, 0x0100, NULL, 0, HZ * 3); - dev_dbg(dev, "%s - retC = %d\n", __func__, ret); + mce_dbg(dev, "%s - retC = %d\n", __func__, ret); /* device reset */ mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET)); - mce_sync_in(ir, NULL, maxp); /* get hw/sw revision? */ mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION)); - mce_sync_in(ir, NULL, maxp); kfree(data); }; static void mceusb_gen2_init(struct mceusb_dev *ir) { - int maxp = ir->len_in; - /* device reset */ mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET)); - mce_sync_in(ir, NULL, maxp); /* get hw/sw revision? */ mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION)); - mce_sync_in(ir, NULL, maxp); /* unknown what the next two actually return... */ mce_async_out(ir, GET_UNKNOWN, sizeof(GET_UNKNOWN)); - mce_sync_in(ir, NULL, maxp); mce_async_out(ir, GET_UNKNOWN2, sizeof(GET_UNKNOWN2)); - mce_sync_in(ir, NULL, maxp); } static void mceusb_get_parameters(struct mceusb_dev *ir) { - int maxp = ir->len_in; - /* get the carrier and frequency */ mce_async_out(ir, GET_CARRIER_FREQ, sizeof(GET_CARRIER_FREQ)); - mce_sync_in(ir, NULL, maxp); - if (!ir->flags.no_tx) { + if (!ir->flags.no_tx) /* get the transmitter bitmask */ mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK)); - mce_sync_in(ir, NULL, maxp); - } /* get receiver timeout value */ mce_async_out(ir, GET_RX_TIMEOUT, sizeof(GET_RX_TIMEOUT)); - mce_sync_in(ir, NULL, maxp); /* get receiver sensor setting */ mce_async_out(ir, GET_RX_SENSOR, sizeof(GET_RX_SENSOR)); - mce_sync_in(ir, NULL, maxp); } static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) @@ -1122,7 +1118,7 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf, bool tx_mask_normal; int ir_intfnum; - dev_dbg(&intf->dev, "%s called\n", __func__); + mce_dbg(&intf->dev, "%s called\n", __func__); idesc = intf->cur_altsetting; @@ -1150,7 +1146,7 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf, ep_in = ep; ep_in->bmAttributes = USB_ENDPOINT_XFER_INT; ep_in->bInterval = 1; - dev_dbg(&intf->dev, "acceptable inbound endpoint " + mce_dbg(&intf->dev, "acceptable inbound endpoint " "found\n"); } @@ -1165,12 +1161,12 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf, ep_out = ep; ep_out->bmAttributes = USB_ENDPOINT_XFER_INT; ep_out->bInterval = 1; - dev_dbg(&intf->dev, "acceptable outbound endpoint " + mce_dbg(&intf->dev, "acceptable outbound endpoint " "found\n"); } } if (ep_in == NULL) { - dev_dbg(&intf->dev, "inbound and/or endpoint not found\n"); + mce_dbg(&intf->dev, "inbound and/or endpoint not found\n"); return -ENODEV; } @@ -1215,16 +1211,16 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf, if (!ir->rc) goto rc_dev_fail; - /* flush buffers on the device */ - mce_sync_in(ir, NULL, maxp); - mce_sync_in(ir, NULL, maxp); - /* wire up inbound data handler */ usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in, maxp, (usb_complete_t) mceusb_dev_recv, ir, ep_in->bInterval); ir->urb_in->transfer_dma = ir->dma_in; ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + /* flush buffers on the device */ + mce_dbg(&intf->dev, "Flushing receive buffers\n"); + mce_flush_rx_buffer(ir, maxp); + /* initialize device */ if (ir->flags.microsoft_gen1) mceusb_gen1_init(ir); diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index bf3060ea610..565f24c20d7 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -991,7 +991,6 @@ static int nvt_open(struct rc_dev *dev) unsigned long flags; spin_lock_irqsave(&nvt->nvt_lock, flags); - nvt->in_use = true; nvt_enable_cir(nvt); spin_unlock_irqrestore(&nvt->nvt_lock, flags); @@ -1004,7 +1003,6 @@ static void nvt_close(struct rc_dev *dev) unsigned long flags; spin_lock_irqsave(&nvt->nvt_lock, flags); - nvt->in_use = false; nvt_disable_cir(nvt); spin_unlock_irqrestore(&nvt->nvt_lock, flags); } diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h index 379795d61ea..1241fc89a36 100644 --- a/drivers/media/rc/nuvoton-cir.h +++ b/drivers/media/rc/nuvoton-cir.h @@ -70,7 +70,6 @@ struct nvt_dev { struct ir_raw_event rawir; spinlock_t nvt_lock; - bool in_use; /* for rx */ u8 buf[RX_BUF_LEN]; diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index f57cd5677ac..3186ac7c2c1 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -522,18 +522,20 @@ EXPORT_SYMBOL_GPL(rc_g_keycode_from_table); /** * ir_do_keyup() - internal function to signal the release of a keypress * @dev: the struct rc_dev descriptor of the device + * @sync: whether or not to call input_sync * * This function is used internally to release a keypress, it must be * called with keylock held. */ -static void ir_do_keyup(struct rc_dev *dev) +static void ir_do_keyup(struct rc_dev *dev, bool sync) { if (!dev->keypressed) return; IR_dprintk(1, "keyup key 0x%04x\n", dev->last_keycode); input_report_key(dev->input_dev, dev->last_keycode, 0); - input_sync(dev->input_dev); + if (sync) + input_sync(dev->input_dev); dev->keypressed = false; } @@ -549,7 +551,7 @@ void rc_keyup(struct rc_dev *dev) unsigned long flags; spin_lock_irqsave(&dev->keylock, flags); - ir_do_keyup(dev); + ir_do_keyup(dev, true); spin_unlock_irqrestore(&dev->keylock, flags); } EXPORT_SYMBOL_GPL(rc_keyup); @@ -578,7 +580,7 @@ static void ir_timer_keyup(unsigned long cookie) */ spin_lock_irqsave(&dev->keylock, flags); if (time_is_before_eq_jiffies(dev->keyup_jiffies)) - ir_do_keyup(dev); + ir_do_keyup(dev, true); spin_unlock_irqrestore(&dev->keylock, flags); } @@ -597,6 +599,7 @@ void rc_repeat(struct rc_dev *dev) spin_lock_irqsave(&dev->keylock, flags); input_event(dev->input_dev, EV_MSC, MSC_SCAN, dev->last_scancode); + input_sync(dev->input_dev); if (!dev->keypressed) goto out; @@ -622,29 +625,28 @@ EXPORT_SYMBOL_GPL(rc_repeat); static void ir_do_keydown(struct rc_dev *dev, int scancode, u32 keycode, u8 toggle) { - input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode); - - /* Repeat event? */ - if (dev->keypressed && - dev->last_scancode == scancode && - dev->last_toggle == toggle) - return; + bool new_event = !dev->keypressed || + dev->last_scancode != scancode || + dev->last_toggle != toggle; - /* Release old keypress */ - ir_do_keyup(dev); + if (new_event && dev->keypressed) + ir_do_keyup(dev, false); - dev->last_scancode = scancode; - dev->last_toggle = toggle; - dev->last_keycode = keycode; + input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode); - if (keycode == KEY_RESERVED) - return; + if (new_event && keycode != KEY_RESERVED) { + /* Register a keypress */ + dev->keypressed = true; + dev->last_scancode = scancode; + dev->last_toggle = toggle; + dev->last_keycode = keycode; + + IR_dprintk(1, "%s: key down event, " + "key 0x%04x, scancode 0x%04x\n", + dev->input_name, keycode, scancode); + input_report_key(dev->input_dev, keycode, 1); + } - /* Register a keypress */ - dev->keypressed = true; - IR_dprintk(1, "%s: key down event, key 0x%04x, scancode 0x%04x\n", - dev->input_name, keycode, scancode); - input_report_key(dev->input_dev, dev->last_keycode, 1); input_sync(dev->input_dev); } diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index a97cf2750bd..834a48394bc 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -3474,7 +3474,7 @@ static int radio_s_tuner(struct file *file, void *priv, if (0 != t->index) return -EINVAL; - bttv_call_all(btv, tuner, g_tuner, t); + bttv_call_all(btv, tuner, s_tuner, t); return 0; } diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index 1933d4d11bf..e80134f52ef 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c @@ -695,14 +695,10 @@ static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) cx18_call_all(cx, tuner, g_tuner, vt); - if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { + if (vt->type == V4L2_TUNER_RADIO) strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name)); - vt->type = V4L2_TUNER_RADIO; - } else { + else strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name)); - vt->type = V4L2_TUNER_ANALOG_TV; - } - return 0; } diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index f9e347dae73..120c7d8e089 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1184,14 +1184,10 @@ static int ivtv_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) ivtv_call_all(itv, tuner, g_tuner, vt); - if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { + if (vt->type == V4L2_TUNER_RADIO) strlcpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name)); - vt->type = V4L2_TUNER_RADIO; - } else { + else strlcpy(vt->name, "ivtv TV Tuner", sizeof(vt->name)); - vt->type = V4L2_TUNER_ANALOG_TV; - } - return 0; } diff --git a/drivers/media/video/m5mols/m5mols.h b/drivers/media/video/m5mols/m5mols.h index 10b55c85448..89d09a8914f 100644 --- a/drivers/media/video/m5mols/m5mols.h +++ b/drivers/media/video/m5mols/m5mols.h @@ -2,10 +2,10 @@ * Header for M-5MOLS 8M Pixel camera sensor with ISP * * Copyright (C) 2011 Samsung Electronics Co., Ltd. - * Author: HeungJun Kim, riverful.kim@samsung.com + * Author: HeungJun Kim <riverful.kim@samsung.com> * * Copyright (C) 2009 Samsung Electronics Co., Ltd. - * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com + * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -106,23 +106,23 @@ struct m5mols_capture { * The each value according to each scenemode is recommended in the documents. */ struct m5mols_scenemode { - u32 metering; - u32 ev_bias; - u32 wb_mode; - u32 wb_preset; - u32 chroma_en; - u32 chroma_lvl; - u32 edge_en; - u32 edge_lvl; - u32 af_range; - u32 fd_mode; - u32 mcc; - u32 light; - u32 flash; - u32 tone; - u32 iso; - u32 capt_mode; - u32 wdr; + u8 metering; + u8 ev_bias; + u8 wb_mode; + u8 wb_preset; + u8 chroma_en; + u8 chroma_lvl; + u8 edge_en; + u8 edge_lvl; + u8 af_range; + u8 fd_mode; + u8 mcc; + u8 light; + u8 flash; + u8 tone; + u8 iso; + u8 capt_mode; + u8 wdr; }; /** @@ -154,7 +154,6 @@ struct m5mols_version { u8 str[VERSION_STRING_SIZE]; u8 af; }; -#define VERSION_SIZE sizeof(struct m5mols_version) /** * struct m5mols_info - M-5MOLS driver data structure @@ -216,9 +215,9 @@ struct m5mols_info { bool lock_ae; bool lock_awb; u8 resolution; - u32 interrupt; - u32 mode; - u32 mode_save; + u8 interrupt; + u8 mode; + u8 mode_save; int (*set_power)(struct device *dev, int on); }; @@ -256,9 +255,11 @@ struct m5mols_info { * +-------+---+----------+-----+------+------+------+------+ * - d[0..3]: according to size1 */ -int m5mols_read(struct v4l2_subdev *sd, u32 reg_comb, u32 *val); +int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg_comb, u8 *val); +int m5mols_read_u16(struct v4l2_subdev *sd, u32 reg_comb, u16 *val); +int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg_comb, u32 *val); int m5mols_write(struct v4l2_subdev *sd, u32 reg_comb, u32 val); -int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 value); +int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u8 value); /* * Mode operation of the M-5MOLS @@ -280,12 +281,12 @@ int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 value); * The available executing order between each modes are as follows: * PARAMETER <---> MONITOR <---> CAPTURE */ -int m5mols_mode(struct m5mols_info *info, u32 mode); +int m5mols_mode(struct m5mols_info *info, u8 mode); -int m5mols_enable_interrupt(struct v4l2_subdev *sd, u32 reg); +int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg); int m5mols_sync_controls(struct m5mols_info *info); int m5mols_start_capture(struct m5mols_info *info); -int m5mols_do_scenemode(struct m5mols_info *info, u32 mode); +int m5mols_do_scenemode(struct m5mols_info *info, u8 mode); int m5mols_lock_3a(struct m5mols_info *info, bool lock); int m5mols_set_ctrl(struct v4l2_ctrl *ctrl); diff --git a/drivers/media/video/m5mols/m5mols_capture.c b/drivers/media/video/m5mols/m5mols_capture.c index d71a3903b60..d9471928369 100644 --- a/drivers/media/video/m5mols/m5mols_capture.c +++ b/drivers/media/video/m5mols/m5mols_capture.c @@ -2,10 +2,10 @@ * The Capture code for Fujitsu M-5MOLS ISP * * Copyright (C) 2011 Samsung Electronics Co., Ltd. - * Author: HeungJun Kim, riverful.kim@samsung.com + * Author: HeungJun Kim <riverful.kim@samsung.com> * * Copyright (C) 2009 Samsung Electronics Co., Ltd. - * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com + * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -58,9 +58,9 @@ static int m5mols_read_rational(struct v4l2_subdev *sd, u32 addr_num, { u32 num, den; - int ret = m5mols_read(sd, addr_num, &num); + int ret = m5mols_read_u32(sd, addr_num, &num); if (!ret) - ret = m5mols_read(sd, addr_den, &den); + ret = m5mols_read_u32(sd, addr_den, &den); if (ret) return ret; *val = den == 0 ? 0 : num / den; @@ -99,20 +99,20 @@ static int m5mols_capture_info(struct m5mols_info *info) if (ret) return ret; - ret = m5mols_read(sd, EXIF_INFO_ISO, (u32 *)&exif->iso_speed); + ret = m5mols_read_u16(sd, EXIF_INFO_ISO, &exif->iso_speed); if (!ret) - ret = m5mols_read(sd, EXIF_INFO_FLASH, (u32 *)&exif->flash); + ret = m5mols_read_u16(sd, EXIF_INFO_FLASH, &exif->flash); if (!ret) - ret = m5mols_read(sd, EXIF_INFO_SDR, (u32 *)&exif->sdr); + ret = m5mols_read_u16(sd, EXIF_INFO_SDR, &exif->sdr); if (!ret) - ret = m5mols_read(sd, EXIF_INFO_QVAL, (u32 *)&exif->qval); + ret = m5mols_read_u16(sd, EXIF_INFO_QVAL, &exif->qval); if (ret) return ret; if (!ret) - ret = m5mols_read(sd, CAPC_IMAGE_SIZE, &info->cap.main); + ret = m5mols_read_u32(sd, CAPC_IMAGE_SIZE, &info->cap.main); if (!ret) - ret = m5mols_read(sd, CAPC_THUMB_SIZE, &info->cap.thumb); + ret = m5mols_read_u32(sd, CAPC_THUMB_SIZE, &info->cap.thumb); if (!ret) info->cap.total = info->cap.main + info->cap.thumb; @@ -122,7 +122,7 @@ static int m5mols_capture_info(struct m5mols_info *info) int m5mols_start_capture(struct m5mols_info *info) { struct v4l2_subdev *sd = &info->sd; - u32 resolution = info->resolution; + u8 resolution = info->resolution; int timeout; int ret; diff --git a/drivers/media/video/m5mols/m5mols_controls.c b/drivers/media/video/m5mols/m5mols_controls.c index 817c16fec36..d135d20d09c 100644 --- a/drivers/media/video/m5mols/m5mols_controls.c +++ b/drivers/media/video/m5mols/m5mols_controls.c @@ -2,10 +2,10 @@ * Controls for M-5MOLS 8M Pixel camera sensor with ISP * * Copyright (C) 2011 Samsung Electronics Co., Ltd. - * Author: HeungJun Kim, riverful.kim@samsung.com + * Author: HeungJun Kim <riverful.kim@samsung.com> * * Copyright (C) 2009 Samsung Electronics Co., Ltd. - * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com + * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -130,7 +130,7 @@ static struct m5mols_scenemode m5mols_default_scenemode[] = { * * WARNING: The execution order is important. Do not change the order. */ -int m5mols_do_scenemode(struct m5mols_info *info, u32 mode) +int m5mols_do_scenemode(struct m5mols_info *info, u8 mode) { struct v4l2_subdev *sd = &info->sd; struct m5mols_scenemode scenemode = m5mols_default_scenemode[mode]; diff --git a/drivers/media/video/m5mols/m5mols_core.c b/drivers/media/video/m5mols/m5mols_core.c index 76eac26e84a..43c68f51c5c 100644 --- a/drivers/media/video/m5mols/m5mols_core.c +++ b/drivers/media/video/m5mols/m5mols_core.c @@ -2,10 +2,10 @@ * Driver for M-5MOLS 8M Pixel camera sensor with ISP * * Copyright (C) 2011 Samsung Electronics Co., Ltd. - * Author: HeungJun Kim, riverful.kim@samsung.com + * Author: HeungJun Kim <riverful.kim@samsung.com> * * Copyright (C) 2009 Samsung Electronics Co., Ltd. - * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com + * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -133,13 +133,13 @@ static u32 m5mols_swap_byte(u8 *data, u8 length) /** * m5mols_read - I2C read function * @reg: combination of size, category and command for the I2C packet + * @size: desired size of I2C packet * @val: read value */ -int m5mols_read(struct v4l2_subdev *sd, u32 reg, u32 *val) +static int m5mols_read(struct v4l2_subdev *sd, u32 size, u32 reg, u32 *val) { struct i2c_client *client = v4l2_get_subdevdata(sd); u8 rbuf[M5MOLS_I2C_MAX_SIZE + 1]; - u8 size = I2C_SIZE(reg); u8 category = I2C_CATEGORY(reg); u8 cmd = I2C_COMMAND(reg); struct i2c_msg msg[2]; @@ -149,11 +149,6 @@ int m5mols_read(struct v4l2_subdev *sd, u32 reg, u32 *val) if (!client->adapter) return -ENODEV; - if (size != 1 && size != 2 && size != 4) { - v4l2_err(sd, "Wrong data size\n"); - return -EINVAL; - } - msg[0].addr = client->addr; msg[0].flags = 0; msg[0].len = 5; @@ -184,6 +179,52 @@ int m5mols_read(struct v4l2_subdev *sd, u32 reg, u32 *val) return 0; } +int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg, u8 *val) +{ + u32 val_32; + int ret; + + if (I2C_SIZE(reg) != 1) { + v4l2_err(sd, "Wrong data size\n"); + return -EINVAL; + } + + ret = m5mols_read(sd, I2C_SIZE(reg), reg, &val_32); + if (ret) + return ret; + + *val = (u8)val_32; + return ret; +} + +int m5mols_read_u16(struct v4l2_subdev *sd, u32 reg, u16 *val) +{ + u32 val_32; + int ret; + + if (I2C_SIZE(reg) != 2) { + v4l2_err(sd, "Wrong data size\n"); + return -EINVAL; + } + + ret = m5mols_read(sd, I2C_SIZE(reg), reg, &val_32); + if (ret) + return ret; + + *val = (u16)val_32; + return ret; +} + +int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg, u32 *val) +{ + if (I2C_SIZE(reg) != 4) { + v4l2_err(sd, "Wrong data size\n"); + return -EINVAL; + } + + return m5mols_read(sd, I2C_SIZE(reg), reg, val); +} + /** * m5mols_write - I2C command write function * @reg: combination of size, category and command for the I2C packet @@ -231,13 +272,14 @@ int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val) return 0; } -int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 mask) +int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u8 mask) { - u32 busy, i; + u8 busy; + int i; int ret; for (i = 0; i < M5MOLS_I2C_CHECK_RETRY; i++) { - ret = m5mols_read(sd, I2C_REG(category, cmd, 1), &busy); + ret = m5mols_read_u8(sd, I2C_REG(category, cmd, 1), &busy); if (ret < 0) return ret; if ((busy & mask) == mask) @@ -252,14 +294,14 @@ int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 mask) * Before writing desired interrupt value the INT_FACTOR register should * be read to clear pending interrupts. */ -int m5mols_enable_interrupt(struct v4l2_subdev *sd, u32 reg) +int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg) { struct m5mols_info *info = to_m5mols(sd); - u32 mask = is_available_af(info) ? REG_INT_AF : 0; - u32 dummy; + u8 mask = is_available_af(info) ? REG_INT_AF : 0; + u8 dummy; int ret; - ret = m5mols_read(sd, SYSTEM_INT_FACTOR, &dummy); + ret = m5mols_read_u8(sd, SYSTEM_INT_FACTOR, &dummy); if (!ret) ret = m5mols_write(sd, SYSTEM_INT_ENABLE, reg & ~mask); return ret; @@ -271,7 +313,7 @@ int m5mols_enable_interrupt(struct v4l2_subdev *sd, u32 reg) * It always accompanies a little delay changing the M-5MOLS mode, so it is * needed checking current busy status to guarantee right mode. */ -static int m5mols_reg_mode(struct v4l2_subdev *sd, u32 mode) +static int m5mols_reg_mode(struct v4l2_subdev *sd, u8 mode) { int ret = m5mols_write(sd, SYSTEM_SYSMODE, mode); @@ -286,16 +328,16 @@ static int m5mols_reg_mode(struct v4l2_subdev *sd, u32 mode) * can be guaranteed only when the sensor is operating in mode which which * a command belongs to. */ -int m5mols_mode(struct m5mols_info *info, u32 mode) +int m5mols_mode(struct m5mols_info *info, u8 mode) { struct v4l2_subdev *sd = &info->sd; int ret = -EINVAL; - u32 reg; + u8 reg; if (mode < REG_PARAMETER && mode > REG_CAPTURE) return ret; - ret = m5mols_read(sd, SYSTEM_SYSMODE, ®); + ret = m5mols_read_u8(sd, SYSTEM_SYSMODE, ®); if ((!ret && reg == mode) || ret) return ret; @@ -344,41 +386,37 @@ int m5mols_mode(struct m5mols_info *info, u32 mode) static int m5mols_get_version(struct v4l2_subdev *sd) { struct m5mols_info *info = to_m5mols(sd); - union { - struct m5mols_version ver; - u8 bytes[VERSION_SIZE]; - } version; - u32 *value; - u8 cmd = CAT0_VER_CUSTOMER; + struct m5mols_version *ver = &info->ver; + u8 *str = ver->str; + int i; int ret; - do { - value = (u32 *)&version.bytes[cmd]; - ret = m5mols_read(sd, SYSTEM_CMD(cmd), value); - if (ret) - return ret; - } while (cmd++ != CAT0_VER_AWB); + ret = m5mols_read_u8(sd, SYSTEM_VER_CUSTOMER, &ver->customer); + if (!ret) + ret = m5mols_read_u8(sd, SYSTEM_VER_PROJECT, &ver->project); + if (!ret) + ret = m5mols_read_u16(sd, SYSTEM_VER_FIRMWARE, &ver->fw); + if (!ret) + ret = m5mols_read_u16(sd, SYSTEM_VER_HARDWARE, &ver->hw); + if (!ret) + ret = m5mols_read_u16(sd, SYSTEM_VER_PARAMETER, &ver->param); + if (!ret) + ret = m5mols_read_u16(sd, SYSTEM_VER_AWB, &ver->awb); + if (!ret) + ret = m5mols_read_u8(sd, AF_VERSION, &ver->af); + if (ret) + return ret; - do { - value = (u32 *)&version.bytes[cmd]; - ret = m5mols_read(sd, SYSTEM_VER_STRING, value); + for (i = 0; i < VERSION_STRING_SIZE; i++) { + ret = m5mols_read_u8(sd, SYSTEM_VER_STRING, &str[i]); if (ret) return ret; - if (cmd >= VERSION_SIZE - 1) - return -EINVAL; - } while (version.bytes[cmd++]); - - value = (u32 *)&version.bytes[cmd]; - ret = m5mols_read(sd, AF_VERSION, value); - if (ret) - return ret; + } - /* store version information swapped for being readable */ - info->ver = version.ver; - info->ver.fw = be16_to_cpu(info->ver.fw); - info->ver.hw = be16_to_cpu(info->ver.hw); - info->ver.param = be16_to_cpu(info->ver.param); - info->ver.awb = be16_to_cpu(info->ver.awb); + ver->fw = be16_to_cpu(ver->fw); + ver->hw = be16_to_cpu(ver->hw); + ver->param = be16_to_cpu(ver->param); + ver->awb = be16_to_cpu(ver->awb); v4l2_info(sd, "Manufacturer\t[%s]\n", is_manufacturer(info, REG_SAMSUNG_ELECTRO) ? @@ -722,7 +760,7 @@ static int m5mols_init_controls(struct m5mols_info *info) int ret; /* Determine value's range & step of controls for various FW version */ - ret = m5mols_read(sd, AE_MAX_GAIN_MON, (u32 *)&max_exposure); + ret = m5mols_read_u16(sd, AE_MAX_GAIN_MON, &max_exposure); if (!ret) step_zoom = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1; if (ret) @@ -842,18 +880,18 @@ static void m5mols_irq_work(struct work_struct *work) struct m5mols_info *info = container_of(work, struct m5mols_info, work_irq); struct v4l2_subdev *sd = &info->sd; - u32 reg; + u8 reg; int ret; if (!is_powered(info) || - m5mols_read(sd, SYSTEM_INT_FACTOR, &info->interrupt)) + m5mols_read_u8(sd, SYSTEM_INT_FACTOR, &info->interrupt)) return; switch (info->interrupt & REG_INT_MASK) { case REG_INT_AF: if (!is_available_af(info)) break; - ret = m5mols_read(sd, AF_STATUS, ®); + ret = m5mols_read_u8(sd, AF_STATUS, ®); v4l2_dbg(2, m5mols_debug, sd, "AF %s\n", reg == REG_AF_FAIL ? "Failed" : reg == REG_AF_SUCCESS ? "Success" : diff --git a/drivers/media/video/m5mols/m5mols_reg.h b/drivers/media/video/m5mols/m5mols_reg.h index b83e36fc6ac..c755bd6edfe 100644 --- a/drivers/media/video/m5mols/m5mols_reg.h +++ b/drivers/media/video/m5mols/m5mols_reg.h @@ -2,10 +2,10 @@ * Register map for M-5MOLS 8M Pixel camera sensor with ISP * * Copyright (C) 2011 Samsung Electronics Co., Ltd. - * Author: HeungJun Kim, riverful.kim@samsung.com + * Author: HeungJun Kim <riverful.kim@samsung.com> * * Copyright (C) 2009 Samsung Electronics Co., Ltd. - * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com + * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -56,13 +56,24 @@ * more specific contents, see definition if file m5mols.h. */ #define CAT0_VER_CUSTOMER 0x00 /* customer version */ -#define CAT0_VER_AWB 0x09 /* Auto WB version */ +#define CAT0_VER_PROJECT 0x01 /* project version */ +#define CAT0_VER_FIRMWARE 0x02 /* Firmware version */ +#define CAT0_VER_HARDWARE 0x04 /* Hardware version */ +#define CAT0_VER_PARAMETER 0x06 /* Parameter version */ +#define CAT0_VER_AWB 0x08 /* Auto WB version */ #define CAT0_VER_STRING 0x0a /* string including M-5MOLS */ #define CAT0_SYSMODE 0x0b /* SYSTEM mode register */ #define CAT0_STATUS 0x0c /* SYSTEM mode status register */ #define CAT0_INT_FACTOR 0x10 /* interrupt pending register */ #define CAT0_INT_ENABLE 0x11 /* interrupt enable register */ +#define SYSTEM_VER_CUSTOMER I2C_REG(CAT_SYSTEM, CAT0_VER_CUSTOMER, 1) +#define SYSTEM_VER_PROJECT I2C_REG(CAT_SYSTEM, CAT0_VER_PROJECT, 1) +#define SYSTEM_VER_FIRMWARE I2C_REG(CAT_SYSTEM, CAT0_VER_FIRMWARE, 2) +#define SYSTEM_VER_HARDWARE I2C_REG(CAT_SYSTEM, CAT0_VER_HARDWARE, 2) +#define SYSTEM_VER_PARAMETER I2C_REG(CAT_SYSTEM, CAT0_VER_PARAMETER, 2) +#define SYSTEM_VER_AWB I2C_REG(CAT_SYSTEM, CAT0_VER_AWB, 2) + #define SYSTEM_SYSMODE I2C_REG(CAT_SYSTEM, CAT0_SYSMODE, 1) #define REG_SYSINIT 0x00 /* SYSTEM mode */ #define REG_PARAMETER 0x01 /* PARAMETER mode */ @@ -382,8 +393,8 @@ #define REG_CAP_START_MAIN 0x01 #define REG_CAP_START_THUMB 0x03 -#define CAPC_IMAGE_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_IMAGE_SIZE, 1) -#define CAPC_THUMB_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_THUMB_SIZE, 1) +#define CAPC_IMAGE_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_IMAGE_SIZE, 4) +#define CAPC_THUMB_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_THUMB_SIZE, 4) /* * Category F - Flash diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index de5d481b032..c43c81f5f97 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -480,12 +480,14 @@ static int msp_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) struct msp_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); - if (state->radio) + if (vt->type != V4L2_TUNER_ANALOG_TV) return 0; - if (state->opmode == OPMODE_AUTOSELECT) - msp_detect_stereo(client); - vt->audmode = state->audmode; - vt->rxsubchans = state->rxsubchans; + if (!state->radio) { + if (state->opmode == OPMODE_AUTOSELECT) + msp_detect_stereo(client); + vt->rxsubchans = state->rxsubchans; + } + vt->audmode = state->audmode; vt->capability |= V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; return 0; diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c index bc0c23a1009..63f8a0cc33d 100644 --- a/drivers/media/video/mx1_camera.c +++ b/drivers/media/video/mx1_camera.c @@ -444,12 +444,9 @@ static int mx1_camera_add_device(struct soc_camera_device *icd) { struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct mx1_camera_dev *pcdev = ici->priv; - int ret; - if (pcdev->icd) { - ret = -EBUSY; - goto ebusy; - } + if (pcdev->icd) + return -EBUSY; dev_info(icd->dev.parent, "MX1 Camera driver attached to camera %d\n", icd->devnum); @@ -458,8 +455,7 @@ static int mx1_camera_add_device(struct soc_camera_device *icd) pcdev->icd = icd; -ebusy: - return ret; + return 0; } static void mx1_camera_remove_device(struct soc_camera_device *icd) diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c index 4ada9be1d43..4d07c584440 100644 --- a/drivers/media/video/omap/omap_vout.c +++ b/drivers/media/video/omap/omap_vout.c @@ -982,6 +982,14 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count, startindex = (vout->vid == OMAP_VIDEO1) ? video1_numbuffers : video2_numbuffers; + /* Check the size of the buffer */ + if (*size > vout->buffer_size) { + v4l2_err(&vout->vid_dev->v4l2_dev, + "buffer allocation mismatch [%u] [%u]\n", + *size, vout->buffer_size); + return -ENOMEM; + } + for (i = startindex; i < *count; i++) { vout->buffer_size = *size; @@ -1228,6 +1236,14 @@ static int omap_vout_mmap(struct file *file, struct vm_area_struct *vma) (vma->vm_pgoff << PAGE_SHIFT)); return -EINVAL; } + /* Check the size of the buffer */ + if (size > vout->buffer_size) { + v4l2_err(&vout->vid_dev->v4l2_dev, + "insufficient memory [%lu] [%u]\n", + size, vout->buffer_size); + return -ENOMEM; + } + q->bufs[i]->baddr = vma->vm_start; vma->vm_flags |= VM_RESERVED; @@ -2391,7 +2407,7 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev) /* Register the Video device with V4L2 */ vfd = vout->vfd; - if (video_register_device(vfd, VFL_TYPE_GRABBER, k + 1) < 0) { + if (video_register_device(vfd, VFL_TYPE_GRABBER, -1) < 0) { dev_err(&pdev->dev, ": Could not register " "Video for Linux device\n"); vfd->minor = -1; diff --git a/drivers/media/video/omap/omap_voutlib.c b/drivers/media/video/omap/omap_voutlib.c index 2aa6a76c5e5..8ae74817a11 100644 --- a/drivers/media/video/omap/omap_voutlib.c +++ b/drivers/media/video/omap/omap_voutlib.c @@ -193,7 +193,7 @@ int omap_vout_new_crop(struct v4l2_pix_format *pix, return -EINVAL; if (cpu_is_omap24xx()) { - if (crop->height != win->w.height) { + if (try_crop.height != win->w.height) { /* If we're resizing vertically, we can't support a * crop width wider than 768 pixels. */ @@ -202,7 +202,7 @@ int omap_vout_new_crop(struct v4l2_pix_format *pix, } } /* vertical resizing */ - vresize = (1024 * crop->height) / win->w.height; + vresize = (1024 * try_crop.height) / win->w.height; if (cpu_is_omap24xx() && (vresize > 2048)) vresize = 2048; else if (cpu_is_omap34xx() && (vresize > 4096)) @@ -221,7 +221,7 @@ int omap_vout_new_crop(struct v4l2_pix_format *pix, try_crop.height = 2; } /* horizontal resizing */ - hresize = (1024 * crop->width) / win->w.width; + hresize = (1024 * try_crop.width) / win->w.width; if (cpu_is_omap24xx() && (hresize > 2048)) hresize = 2048; else if (cpu_is_omap34xx() && (hresize > 4096)) diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c index c9fd04ee70a..94b6ed89e19 100644 --- a/drivers/media/video/omap3isp/isp.c +++ b/drivers/media/video/omap3isp/isp.c @@ -1748,7 +1748,7 @@ static int isp_register_entities(struct isp_device *isp) goto done; /* Register external entities */ - for (subdevs = pdata->subdevs; subdevs->subdevs; ++subdevs) { + for (subdevs = pdata->subdevs; subdevs && subdevs->subdevs; ++subdevs) { struct v4l2_subdev *sensor; struct media_entity *input; unsigned int flags; diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 9d0dd08f57f..e98d3821279 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -3046,6 +3046,8 @@ static void pvr2_subdev_update(struct pvr2_hdw *hdw) if (hdw->input_dirty || hdw->audiomode_dirty || hdw->force_dirty) { struct v4l2_tuner vt; memset(&vt, 0, sizeof(vt)); + vt.type = (hdw->input_val == PVR2_CVAL_INPUT_RADIO) ? + V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; vt.audmode = hdw->audiomode_val; v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, s_tuner, &vt); } @@ -5171,6 +5173,8 @@ void pvr2_hdw_status_poll(struct pvr2_hdw *hdw) { struct v4l2_tuner *vtp = &hdw->tuner_signal_info; memset(vtp, 0, sizeof(*vtp)); + vtp->type = (hdw->input_val == PVR2_CVAL_INPUT_RADIO) ? + V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; hdw->tuner_signal_stale = 0; /* Note: There apparently is no replacement for VIDIOC_CROPCAP using v4l2-subdev - therefore we can't support that AT ALL right diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c index 1593f8deb81..760b4de13ad 100644 --- a/drivers/media/video/pwc/pwc-ctrl.c +++ b/drivers/media/video/pwc/pwc-ctrl.c @@ -1414,7 +1414,7 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) { ARG_DEF(struct pwc_probe, probe) - strcpy(ARGR(probe).name, pdev->vdev->name); + strcpy(ARGR(probe).name, pdev->vdev.name); ARGR(probe).type = pdev->type; ARG_OUT(probe) break; diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 356cd42b593..b0bde5a87c8 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -40,7 +40,7 @@ Oh yes, convention: to disctinguish between all the various pointers to device-structures, I use these names for the pointer variables: udev: struct usb_device * - vdev: struct video_device * + vdev: struct video_device (member of pwc_dev) pdev: struct pwc_devive * */ @@ -152,6 +152,7 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf, size_t count, loff_t *ppos); static unsigned int pwc_video_poll(struct file *file, poll_table *wait); static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma); +static void pwc_video_release(struct video_device *vfd); static const struct v4l2_file_operations pwc_fops = { .owner = THIS_MODULE, @@ -164,42 +165,12 @@ static const struct v4l2_file_operations pwc_fops = { }; static struct video_device pwc_template = { .name = "Philips Webcam", /* Filled in later */ - .release = video_device_release, + .release = pwc_video_release, .fops = &pwc_fops, + .ioctl_ops = &pwc_ioctl_ops, }; /***************************************************************************/ - -/* Okay, this is some magic that I worked out and the reasoning behind it... - - The biggest problem with any USB device is of course: "what to do - when the user unplugs the device while it is in use by an application?" - We have several options: - 1) Curse them with the 7 plagues when they do (requires divine intervention) - 2) Tell them not to (won't work: they'll do it anyway) - 3) Oops the kernel (this will have a negative effect on a user's uptime) - 4) Do something sensible. - - Of course, we go for option 4. - - It happens that this device will be linked to two times, once from - usb_device and once from the video_device in their respective 'private' - pointers. This is done when the device is probed() and all initialization - succeeded. The pwc_device struct links back to both structures. - - When a device is unplugged while in use it will be removed from the - list of known USB devices; I also de-register it as a V4L device, but - unfortunately I can't free the memory since the struct is still in use - by the file descriptor. This free-ing is then deferend until the first - opportunity. Crude, but it works. - - A small 'advantage' is that if a user unplugs the cam and plugs it back - in, it should get assigned the same video device minor, but unfortunately - it's non-trivial to re-link the cam back to the video device... (that - would surely be magic! :)) -*/ - -/***************************************************************************/ /* Private functions */ /* Here we want the physical address of the memory. @@ -1016,16 +987,15 @@ static ssize_t show_snapshot_button_status(struct device *class_dev, static DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status, NULL); -static int pwc_create_sysfs_files(struct video_device *vdev) +static int pwc_create_sysfs_files(struct pwc_device *pdev) { - struct pwc_device *pdev = video_get_drvdata(vdev); int rc; - rc = device_create_file(&vdev->dev, &dev_attr_button); + rc = device_create_file(&pdev->vdev.dev, &dev_attr_button); if (rc) goto err; if (pdev->features & FEATURE_MOTOR_PANTILT) { - rc = device_create_file(&vdev->dev, &dev_attr_pan_tilt); + rc = device_create_file(&pdev->vdev.dev, &dev_attr_pan_tilt); if (rc) goto err_button; } @@ -1033,19 +1003,17 @@ static int pwc_create_sysfs_files(struct video_device *vdev) return 0; err_button: - device_remove_file(&vdev->dev, &dev_attr_button); + device_remove_file(&pdev->vdev.dev, &dev_attr_button); err: PWC_ERROR("Could not create sysfs files.\n"); return rc; } -static void pwc_remove_sysfs_files(struct video_device *vdev) +static void pwc_remove_sysfs_files(struct pwc_device *pdev) { - struct pwc_device *pdev = video_get_drvdata(vdev); - if (pdev->features & FEATURE_MOTOR_PANTILT) - device_remove_file(&vdev->dev, &dev_attr_pan_tilt); - device_remove_file(&vdev->dev, &dev_attr_button); + device_remove_file(&pdev->vdev.dev, &dev_attr_pan_tilt); + device_remove_file(&pdev->vdev.dev, &dev_attr_button); } #ifdef CONFIG_USB_PWC_DEBUG @@ -1106,7 +1074,7 @@ static int pwc_video_open(struct file *file) if (ret >= 0) { PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n", - pdev->vdev->name, + pdev->vdev.name, pwc_sensor_type_to_string(i), i); } } @@ -1180,16 +1148,15 @@ static int pwc_video_open(struct file *file) return 0; } - -static void pwc_cleanup(struct pwc_device *pdev) +static void pwc_video_release(struct video_device *vfd) { - pwc_remove_sysfs_files(pdev->vdev); - video_unregister_device(pdev->vdev); + struct pwc_device *pdev = container_of(vfd, struct pwc_device, vdev); + int hint; -#ifdef CONFIG_USB_PWC_INPUT_EVDEV - if (pdev->button_dev) - input_unregister_device(pdev->button_dev); -#endif + /* search device_hint[] table if we occupy a slot, by any chance */ + for (hint = 0; hint < MAX_DEV_HINTS; hint++) + if (device_hint[hint].pdev == pdev) + device_hint[hint].pdev = NULL; kfree(pdev); } @@ -1199,7 +1166,7 @@ static int pwc_video_close(struct file *file) { struct video_device *vdev = file->private_data; struct pwc_device *pdev; - int i, hint; + int i; PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev); @@ -1234,12 +1201,6 @@ static int pwc_video_close(struct file *file) } pdev->vopen--; PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen); - } else { - pwc_cleanup(pdev); - /* search device_hint[] table if we occupy a slot, by any chance */ - for (hint = 0; hint < MAX_DEV_HINTS; hint++) - if (device_hint[hint].pdev == pdev) - device_hint[hint].pdev = NULL; } return 0; @@ -1715,19 +1676,12 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id init_waitqueue_head(&pdev->frameq); pdev->vcompression = pwc_preferred_compression; - /* Allocate video_device structure */ - pdev->vdev = video_device_alloc(); - if (!pdev->vdev) { - PWC_ERROR("Err, cannot allocate video_device struture. Failing probe."); - rc = -ENOMEM; - goto err_free_mem; - } - memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template)); - pdev->vdev->parent = &intf->dev; - pdev->vdev->lock = &pdev->modlock; - pdev->vdev->ioctl_ops = &pwc_ioctl_ops; - strcpy(pdev->vdev->name, name); - video_set_drvdata(pdev->vdev, pdev); + /* Init video_device structure */ + memcpy(&pdev->vdev, &pwc_template, sizeof(pwc_template)); + pdev->vdev.parent = &intf->dev; + pdev->vdev.lock = &pdev->modlock; + strcpy(pdev->vdev.name, name); + video_set_drvdata(&pdev->vdev, pdev); pdev->release = le16_to_cpu(udev->descriptor.bcdDevice); PWC_DEBUG_PROBE("Release: %04x\n", pdev->release); @@ -1746,8 +1700,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id } } - pdev->vdev->release = video_device_release; - /* occupy slot */ if (hint < MAX_DEV_HINTS) device_hint[hint].pdev = pdev; @@ -1759,16 +1711,16 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id pwc_set_leds(pdev, 0, 0); pwc_camera_power(pdev, 0); - rc = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr); + rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, video_nr); if (rc < 0) { PWC_ERROR("Failed to register as video device (%d).\n", rc); - goto err_video_release; + goto err_free_mem; } - rc = pwc_create_sysfs_files(pdev->vdev); + rc = pwc_create_sysfs_files(pdev); if (rc) goto err_video_unreg; - PWC_INFO("Registered as %s.\n", video_device_node_name(pdev->vdev)); + PWC_INFO("Registered as %s.\n", video_device_node_name(&pdev->vdev)); #ifdef CONFIG_USB_PWC_INPUT_EVDEV /* register webcam snapshot button input device */ @@ -1776,7 +1728,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id if (!pdev->button_dev) { PWC_ERROR("Err, insufficient memory for webcam snapshot button device."); rc = -ENOMEM; - pwc_remove_sysfs_files(pdev->vdev); + pwc_remove_sysfs_files(pdev); goto err_video_unreg; } @@ -1794,7 +1746,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id if (rc) { input_free_device(pdev->button_dev); pdev->button_dev = NULL; - pwc_remove_sysfs_files(pdev->vdev); + pwc_remove_sysfs_files(pdev); goto err_video_unreg; } #endif @@ -1804,10 +1756,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id err_video_unreg: if (hint < MAX_DEV_HINTS) device_hint[hint].pdev = NULL; - video_unregister_device(pdev->vdev); - pdev->vdev = NULL; /* So we don't try to release it below */ -err_video_release: - video_device_release(pdev->vdev); + video_unregister_device(&pdev->vdev); err_free_mem: kfree(pdev); return rc; @@ -1816,10 +1765,8 @@ err_free_mem: /* The user yanked out the cable... */ static void usb_pwc_disconnect(struct usb_interface *intf) { - struct pwc_device *pdev; - int hint; + struct pwc_device *pdev = usb_get_intfdata(intf); - pdev = usb_get_intfdata (intf); mutex_lock(&pdev->modlock); usb_set_intfdata (intf, NULL); if (pdev == NULL) { @@ -1836,30 +1783,25 @@ static void usb_pwc_disconnect(struct usb_interface *intf) } /* We got unplugged; this is signalled by an EPIPE error code */ - if (pdev->vopen) { - PWC_INFO("Disconnected while webcam is in use!\n"); - pdev->error_status = EPIPE; - } + pdev->error_status = EPIPE; + pdev->unplugged = 1; /* Alert waiting processes */ wake_up_interruptible(&pdev->frameq); - /* Wait until device is closed */ - if (pdev->vopen) { - pdev->unplugged = 1; - pwc_iso_stop(pdev); - } else { - /* Device is closed, so we can safely unregister it */ - PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n"); -disconnect_out: - /* search device_hint[] table if we occupy a slot, by any chance */ - for (hint = 0; hint < MAX_DEV_HINTS; hint++) - if (device_hint[hint].pdev == pdev) - device_hint[hint].pdev = NULL; - } + /* No need to keep the urbs around after disconnection */ + pwc_isoc_cleanup(pdev); +disconnect_out: mutex_unlock(&pdev->modlock); - pwc_cleanup(pdev); + + pwc_remove_sysfs_files(pdev); + video_unregister_device(&pdev->vdev); + +#ifdef CONFIG_USB_PWC_INPUT_EVDEV + if (pdev->button_dev) + input_unregister_device(pdev->button_dev); +#endif } diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h index e947766337d..083f8b15df7 100644 --- a/drivers/media/video/pwc/pwc.h +++ b/drivers/media/video/pwc/pwc.h @@ -162,9 +162,9 @@ struct pwc_imgbuf struct pwc_device { - struct video_device *vdev; + struct video_device vdev; - /* Pointer to our usb_device */ + /* Pointer to our usb_device, may be NULL after unplug */ struct usb_device *udev; int type; /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */ diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index d142b40ea64..81b4a826ee5 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -1,7 +1,7 @@ /* - * Samsung S5P SoC series camera interface (camera capture) driver + * Samsung S5P/EXYNOS4 SoC series camera interface (camera capture) driver * - * Copyright (c) 2010 Samsung Electronics Co., Ltd + * Copyright (C) 2010 - 2011 Samsung Electronics Co., Ltd. * Author: Sylwester Nawrocki, <s.nawrocki@samsung.com> * * This program is free software; you can redistribute it and/or modify @@ -262,12 +262,7 @@ static unsigned int get_plane_size(struct fimc_frame *fr, unsigned int plane) { if (!fr || plane >= fr->fmt->memplanes) return 0; - - dbg("%s: w: %d. h: %d. depth[%d]: %d", - __func__, fr->width, fr->height, plane, fr->fmt->depth[plane]); - return fr->f_width * fr->f_height * fr->fmt->depth[plane] / 8; - } static int queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, @@ -283,24 +278,14 @@ static int queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, *num_planes = fmt->memplanes; - dbg("%s, buffer count=%d, plane count=%d", - __func__, *num_buffers, *num_planes); - for (i = 0; i < fmt->memplanes; i++) { sizes[i] = get_plane_size(&ctx->d_frame, i); - dbg("plane: %u, plane_size: %lu", i, sizes[i]); allocators[i] = ctx->fimc_dev->alloc_ctx; } return 0; } -static int buffer_init(struct vb2_buffer *vb) -{ - /* TODO: */ - return 0; -} - static int buffer_prepare(struct vb2_buffer *vb) { struct vb2_queue *vq = vb->vb2_queue; @@ -380,7 +365,6 @@ static struct vb2_ops fimc_capture_qops = { .queue_setup = queue_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, - .buf_init = buffer_init, .wait_prepare = fimc_unlock, .wait_finish = fimc_lock, .start_streaming = start_streaming, @@ -903,6 +887,7 @@ err_vd_reg: err_v4l2_reg: v4l2_device_unregister(v4l2_dev); err_info: + kfree(ctx); dev_err(&fimc->pdev->dev, "failed to install\n"); return ret; } diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index dc91a8511af..bdf19ada917 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -1,9 +1,8 @@ /* - * S5P camera interface (video postprocessor) driver + * Samsung S5P/EXYNOS4 SoC series camera interface (video postprocessor) driver * - * Copyright (c) 2010 Samsung Electronics Co., Ltd - * - * Sylwester Nawrocki, <s.nawrocki@samsung.com> + * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd. + * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published @@ -42,7 +41,6 @@ static struct fimc_fmt fimc_formats[] = { .color = S5P_FIMC_RGB565, .memplanes = 1, .colplanes = 1, - .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_BE, .flags = FMT_FLAGS_M2M, }, { .name = "BGR666", @@ -232,11 +230,7 @@ static int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift) return 0; } } - *shift = 0, *ratio = 1; - - dbg("s: %d, t: %d, shift: %d, ratio: %d", - src, tar, *shift, *ratio); return 0; } @@ -268,10 +262,8 @@ int fimc_set_scaler_info(struct fimc_ctx *ctx) err("invalid source size: %d x %d", sx, sy); return -EINVAL; } - sc->real_width = sx; sc->real_height = sy; - dbg("sx= %d, sy= %d, tx= %d, ty= %d", sx, sy, tx, ty); ret = fimc_get_scaler_factor(sx, tx, &sc->pre_hratio, &sc->hfactor); if (ret) @@ -711,22 +703,18 @@ static int fimc_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, f = ctx_get_frame(ctx, vq->type); if (IS_ERR(f)) return PTR_ERR(f); - /* * Return number of non-contigous planes (plane buffers) * depending on the configured color format. */ - if (f->fmt) - *num_planes = f->fmt->memplanes; + if (!f->fmt) + return -EINVAL; + *num_planes = f->fmt->memplanes; for (i = 0; i < f->fmt->memplanes; i++) { - sizes[i] = (f->width * f->height * f->fmt->depth[i]) >> 3; + sizes[i] = (f->f_width * f->f_height * f->fmt->depth[i]) / 8; allocators[i] = ctx->fimc_dev->alloc_ctx; } - - if (*num_buffers == 0) - *num_buffers = 1; - return 0; } @@ -852,7 +840,7 @@ struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask) for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) { fmt = &fimc_formats[i]; - if (fmt->fourcc == f->fmt.pix.pixelformat && + if (fmt->fourcc == f->fmt.pix_mp.pixelformat && (fmt->flags & mask)) break; } diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 3beb1e5320c..1f70772daaf 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -1,7 +1,5 @@ /* - * Copyright (c) 2010 Samsung Electronics - * - * Sylwester Nawrocki, <s.nawrocki@samsung.com> + * Copyright (C) 2010 - 2011 Samsung Electronics Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -135,9 +133,10 @@ enum fimc_color_fmt { * @name: format description * @fourcc: the fourcc code for this format, 0 if not applicable * @color: the corresponding fimc_color_fmt - * @depth: per plane driver's private 'number of bits per pixel' * @memplanes: number of physically non-contiguous data planes * @colplanes: number of physically contiguous data planes + * @depth: per plane driver's private 'number of bits per pixel' + * @flags: flags indicating which operation mode format applies to */ struct fimc_fmt { enum v4l2_mbus_pixelcode mbus_code; @@ -171,7 +170,7 @@ struct fimc_dma_offset { }; /** - * struct fimc_effect - the configuration data for the "Arbitrary" image effect + * struct fimc_effect - color effect information * @type: effect type * @pat_cb: cr value when type is "arbitrary" * @pat_cr: cr value when type is "arbitrary" @@ -184,7 +183,6 @@ struct fimc_effect { /** * struct fimc_scaler - the configuration data for FIMC inetrnal scaler - * * @scaleup_h: flag indicating scaling up horizontally * @scaleup_v: flag indicating scaling up vertically * @copy_mode: flag indicating transparent DMA transfer (no scaling @@ -220,7 +218,6 @@ struct fimc_scaler { /** * struct fimc_addr - the FIMC physical address set for DMA - * * @y: luminance plane physical address * @cb: Cb plane physical address * @cr: Cr plane physical address @@ -234,6 +231,7 @@ struct fimc_addr { /** * struct fimc_vid_buffer - the driver's video buffer * @vb: v4l videobuf buffer + * @list: linked list structure for buffer queue * @paddr: precalculated physical address set * @index: buffer index for the output DMA engine */ @@ -254,11 +252,10 @@ struct fimc_vid_buffer { * @offs_v: image vertical pixel offset * @width: image pixel width * @height: image pixel weight - * @paddr: image frame buffer physical addresses - * @buf_cnt: number of buffers depending on a color format * @payload: image size in bytes (w x h x bpp) - * @color: color format + * @paddr: image frame buffer physical addresses * @dma_offset: DMA offset in bytes + * @fmt: fimc color format pointer */ struct fimc_frame { u32 f_width; @@ -390,21 +387,22 @@ struct fimc_ctx; /** * struct fimc_dev - abstraction for FIMC entity - * * @slock: the spinlock protecting this data structure * @lock: the mutex protecting this data structure * @pdev: pointer to the FIMC platform device * @pdata: pointer to the device platform data + * @variant: the IP variant information * @id: FIMC device index (0..FIMC_MAX_DEVS) * @num_clocks: the number of clocks managed by this device instance - * @clock[]: the clocks required for FIMC operation + * @clock: clocks required for FIMC operation * @regs: the mapped hardware registers * @regs_res: the resource claimed for IO registers - * @irq: interrupt number of the FIMC subdevice - * @irq_queue: + * @irq: FIMC interrupt number + * @irq_queue: interrupt handler waitqueue * @m2m: memory-to-memory V4L2 device information * @vid_cap: camera capture device information * @state: flags used to synchronize m2m and capture mode operation + * @alloc_ctx: videobuf2 memory allocator context */ struct fimc_dev { spinlock_t slock; @@ -427,8 +425,7 @@ struct fimc_dev { /** * fimc_ctx - the device context data - * - * @lock: mutex protecting this data structure + * @slock: spinlock protecting this data structure * @s_frame: source frame properties * @d_frame: destination frame properties * @out_order_1p: output 1-plane YCBCR order diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index ff6c0e97563..d4ee24bf692 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -963,7 +963,7 @@ static int saa7134_raw_decode_irq(struct saa7134_dev *dev) * to work with other protocols. */ if (!ir->active) { - timeout = jiffies + jiffies_to_msecs(15); + timeout = jiffies + msecs_to_jiffies(15); mod_timer(&ir->timer, timeout); ir->active = true; } diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 9363ed91a4c..cfa9f7efe93 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -724,19 +724,15 @@ static inline int check_mode(struct tuner *t, enum v4l2_tuner_type mode) } /** - * set_mode_freq - Switch tuner to other mode. - * @client: struct i2c_client pointer + * set_mode - Switch tuner to other mode. * @t: a pointer to the module's internal struct_tuner * @mode: enum v4l2_type (radio or TV) - * @freq: frequency to set (0 means to use the previous one) * * If tuner doesn't support the needed mode (radio or TV), prints a * debug message and returns -EINVAL, changing its state to standby. - * Otherwise, changes the state and sets frequency to the last value, if - * the tuner can sleep or if it supports both Radio and TV. + * Otherwise, changes the mode and returns 0. */ -static int set_mode_freq(struct i2c_client *client, struct tuner *t, - enum v4l2_tuner_type mode, unsigned int freq) +static int set_mode(struct tuner *t, enum v4l2_tuner_type mode) { struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; @@ -752,17 +748,27 @@ static int set_mode_freq(struct i2c_client *client, struct tuner *t, t->mode = mode; tuner_dbg("Changing to mode %d\n", mode); } + return 0; +} + +/** + * set_freq - Set the tuner to the desired frequency. + * @t: a pointer to the module's internal struct_tuner + * @freq: frequency to set (0 means to use the current frequency) + */ +static void set_freq(struct tuner *t, unsigned int freq) +{ + struct i2c_client *client = v4l2_get_subdevdata(&t->sd); + if (t->mode == V4L2_TUNER_RADIO) { - if (freq) - t->radio_freq = freq; - set_radio_freq(client, t->radio_freq); + if (!freq) + freq = t->radio_freq; + set_radio_freq(client, freq); } else { - if (freq) - t->tv_freq = freq; - set_tv_freq(client, t->tv_freq); + if (!freq) + freq = t->tv_freq; + set_tv_freq(client, freq); } - - return 0; } /* @@ -817,7 +823,8 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) /** * tuner_fixup_std - force a given video standard variant * - * @t: tuner internal struct + * @t: tuner internal struct + * @std: TV standard * * A few devices or drivers have problem to detect some standard variations. * On other operational systems, the drivers generally have a per-country @@ -827,57 +834,39 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) * to distinguish all video standard variations, a modprobe parameter can * be used to force a video standard match. */ -static int tuner_fixup_std(struct tuner *t) +static v4l2_std_id tuner_fixup_std(struct tuner *t, v4l2_std_id std) { - if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) { + if (pal[0] != '-' && (std & V4L2_STD_PAL) == V4L2_STD_PAL) { switch (pal[0]) { case '6': - tuner_dbg("insmod fixup: PAL => PAL-60\n"); - t->std = V4L2_STD_PAL_60; - break; + return V4L2_STD_PAL_60; case 'b': case 'B': case 'g': case 'G': - tuner_dbg("insmod fixup: PAL => PAL-BG\n"); - t->std = V4L2_STD_PAL_BG; - break; + return V4L2_STD_PAL_BG; case 'i': case 'I': - tuner_dbg("insmod fixup: PAL => PAL-I\n"); - t->std = V4L2_STD_PAL_I; - break; + return V4L2_STD_PAL_I; case 'd': case 'D': case 'k': case 'K': - tuner_dbg("insmod fixup: PAL => PAL-DK\n"); - t->std = V4L2_STD_PAL_DK; - break; + return V4L2_STD_PAL_DK; case 'M': case 'm': - tuner_dbg("insmod fixup: PAL => PAL-M\n"); - t->std = V4L2_STD_PAL_M; - break; + return V4L2_STD_PAL_M; case 'N': case 'n': - if (pal[1] == 'c' || pal[1] == 'C') { - tuner_dbg("insmod fixup: PAL => PAL-Nc\n"); - t->std = V4L2_STD_PAL_Nc; - } else { - tuner_dbg("insmod fixup: PAL => PAL-N\n"); - t->std = V4L2_STD_PAL_N; - } - break; - case '-': - /* default parameter, do nothing */ - break; + if (pal[1] == 'c' || pal[1] == 'C') + return V4L2_STD_PAL_Nc; + return V4L2_STD_PAL_N; default: tuner_warn("pal= argument not recognised\n"); break; } } - if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) { + if (secam[0] != '-' && (std & V4L2_STD_SECAM) == V4L2_STD_SECAM) { switch (secam[0]) { case 'b': case 'B': @@ -885,63 +874,42 @@ static int tuner_fixup_std(struct tuner *t) case 'G': case 'h': case 'H': - tuner_dbg("insmod fixup: SECAM => SECAM-BGH\n"); - t->std = V4L2_STD_SECAM_B | - V4L2_STD_SECAM_G | - V4L2_STD_SECAM_H; - break; + return V4L2_STD_SECAM_B | + V4L2_STD_SECAM_G | + V4L2_STD_SECAM_H; case 'd': case 'D': case 'k': case 'K': - tuner_dbg("insmod fixup: SECAM => SECAM-DK\n"); - t->std = V4L2_STD_SECAM_DK; - break; + return V4L2_STD_SECAM_DK; case 'l': case 'L': - if ((secam[1] == 'C') || (secam[1] == 'c')) { - tuner_dbg("insmod fixup: SECAM => SECAM-L'\n"); - t->std = V4L2_STD_SECAM_LC; - } else { - tuner_dbg("insmod fixup: SECAM => SECAM-L\n"); - t->std = V4L2_STD_SECAM_L; - } - break; - case '-': - /* default parameter, do nothing */ - break; + if ((secam[1] == 'C') || (secam[1] == 'c')) + return V4L2_STD_SECAM_LC; + return V4L2_STD_SECAM_L; default: tuner_warn("secam= argument not recognised\n"); break; } } - if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) { + if (ntsc[0] != '-' && (std & V4L2_STD_NTSC) == V4L2_STD_NTSC) { switch (ntsc[0]) { case 'm': case 'M': - tuner_dbg("insmod fixup: NTSC => NTSC-M\n"); - t->std = V4L2_STD_NTSC_M; - break; + return V4L2_STD_NTSC_M; case 'j': case 'J': - tuner_dbg("insmod fixup: NTSC => NTSC_M_JP\n"); - t->std = V4L2_STD_NTSC_M_JP; - break; + return V4L2_STD_NTSC_M_JP; case 'k': case 'K': - tuner_dbg("insmod fixup: NTSC => NTSC_M_KR\n"); - t->std = V4L2_STD_NTSC_M_KR; - break; - case '-': - /* default parameter, do nothing */ - break; + return V4L2_STD_NTSC_M_KR; default: tuner_info("ntsc= argument not recognised\n"); break; } } - return 0; + return std; } /* @@ -1058,10 +1026,9 @@ static void tuner_status(struct dvb_frontend *fe) static int tuner_s_radio(struct v4l2_subdev *sd) { struct tuner *t = to_tuner(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - if (set_mode_freq(client, t, V4L2_TUNER_RADIO, 0) == -EINVAL) - return 0; + if (set_mode(t, V4L2_TUNER_RADIO) == 0) + set_freq(t, 0); return 0; } @@ -1072,16 +1039,20 @@ static int tuner_s_radio(struct v4l2_subdev *sd) /** * tuner_s_power - controls the power state of the tuner * @sd: pointer to struct v4l2_subdev - * @on: a zero value puts the tuner to sleep + * @on: a zero value puts the tuner to sleep, non-zero wakes it up */ static int tuner_s_power(struct v4l2_subdev *sd, int on) { struct tuner *t = to_tuner(sd); struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - /* FIXME: Why this function don't wake the tuner if on != 0 ? */ - if (on) + if (on) { + if (t->standby && set_mode(t, t->mode) == 0) { + tuner_dbg("Waking up tuner\n"); + set_freq(t, 0); + } return 0; + } tuner_dbg("Putting tuner to sleep\n"); t->standby = true; @@ -1093,28 +1064,36 @@ static int tuner_s_power(struct v4l2_subdev *sd, int on) static int tuner_s_std(struct v4l2_subdev *sd, v4l2_std_id std) { struct tuner *t = to_tuner(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - if (set_mode_freq(client, t, V4L2_TUNER_ANALOG_TV, 0) == -EINVAL) + if (set_mode(t, V4L2_TUNER_ANALOG_TV)) return 0; - t->std = std; - tuner_fixup_std(t); - + t->std = tuner_fixup_std(t, std); + if (t->std != std) + tuner_dbg("Fixup standard %llx to %llx\n", std, t->std); + set_freq(t, 0); return 0; } static int tuner_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) { struct tuner *t = to_tuner(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (set_mode_freq(client, t, f->type, f->frequency) == -EINVAL) - return 0; + if (set_mode(t, f->type) == 0) + set_freq(t, f->frequency); return 0; } +/** + * tuner_g_frequency - Get the tuned frequency for the tuner + * @sd: pointer to struct v4l2_subdev + * @f: pointer to struct v4l2_frequency + * + * At return, the structure f will be filled with tuner frequency + * if the tuner matches the f->type. + * Note: f->type should be initialized before calling it. + * This is done by either video_ioctl2 or by the bridge driver. + */ static int tuner_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) { struct tuner *t = to_tuner(sd); @@ -1122,8 +1101,7 @@ static int tuner_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) if (check_mode(t, f->type) == -EINVAL) return 0; - f->type = t->mode; - if (fe_tuner_ops->get_frequency && !t->standby) { + if (f->type == t->mode && fe_tuner_ops->get_frequency && !t->standby) { u32 abs_freq; fe_tuner_ops->get_frequency(&t->fe, &abs_freq); @@ -1131,12 +1109,22 @@ static int tuner_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) DIV_ROUND_CLOSEST(abs_freq * 2, 125) : DIV_ROUND_CLOSEST(abs_freq, 62500); } else { - f->frequency = (V4L2_TUNER_RADIO == t->mode) ? + f->frequency = (V4L2_TUNER_RADIO == f->type) ? t->radio_freq : t->tv_freq; } return 0; } +/** + * tuner_g_tuner - Fill in tuner information + * @sd: pointer to struct v4l2_subdev + * @vt: pointer to struct v4l2_tuner + * + * At return, the structure vt will be filled with tuner information + * if the tuner matches vt->type. + * Note: vt->type should be initialized before calling it. + * This is done by either video_ioctl2 or by the bridge driver. + */ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) { struct tuner *t = to_tuner(sd); @@ -1145,48 +1133,58 @@ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) if (check_mode(t, vt->type) == -EINVAL) return 0; - vt->type = t->mode; - if (analog_ops->get_afc) + if (vt->type == t->mode && analog_ops->get_afc) vt->afc = analog_ops->get_afc(&t->fe); - if (t->mode == V4L2_TUNER_ANALOG_TV) + if (vt->type == V4L2_TUNER_ANALOG_TV) vt->capability |= V4L2_TUNER_CAP_NORM; - if (t->mode != V4L2_TUNER_RADIO) { + if (vt->type != V4L2_TUNER_RADIO) { vt->rangelow = tv_range[0] * 16; vt->rangehigh = tv_range[1] * 16; return 0; } /* radio mode */ - vt->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - if (fe_tuner_ops->get_status) { - u32 tuner_status; - - fe_tuner_ops->get_status(&t->fe, &tuner_status); - vt->rxsubchans = - (tuner_status & TUNER_STATUS_STEREO) ? - V4L2_TUNER_SUB_STEREO : - V4L2_TUNER_SUB_MONO; + if (vt->type == t->mode) { + vt->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + if (fe_tuner_ops->get_status) { + u32 tuner_status; + + fe_tuner_ops->get_status(&t->fe, &tuner_status); + vt->rxsubchans = + (tuner_status & TUNER_STATUS_STEREO) ? + V4L2_TUNER_SUB_STEREO : + V4L2_TUNER_SUB_MONO; + } + if (analog_ops->has_signal) + vt->signal = analog_ops->has_signal(&t->fe); + vt->audmode = t->audmode; } - if (analog_ops->has_signal) - vt->signal = analog_ops->has_signal(&t->fe); vt->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; - vt->audmode = t->audmode; vt->rangelow = radio_range[0] * 16000; vt->rangehigh = radio_range[1] * 16000; return 0; } +/** + * tuner_s_tuner - Set the tuner's audio mode + * @sd: pointer to struct v4l2_subdev + * @vt: pointer to struct v4l2_tuner + * + * Sets the audio mode if the tuner matches vt->type. + * Note: vt->type should be initialized before calling it. + * This is done by either video_ioctl2 or by the bridge driver. + */ static int tuner_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) { struct tuner *t = to_tuner(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - if (set_mode_freq(client, t, vt->type, 0) == -EINVAL) + if (set_mode(t, vt->type)) return 0; if (t->mode == V4L2_TUNER_RADIO) t->audmode = vt->audmode; + set_freq(t, 0); return 0; } @@ -1221,7 +1219,8 @@ static int tuner_resume(struct i2c_client *c) tuner_dbg("resume\n"); if (!t->standby) - set_mode_freq(c, t, t->type, 0); + if (set_mode(t, t->mode) == 0) + set_freq(t, 0); return 0; } diff --git a/drivers/media/video/uvc/uvc_entity.c b/drivers/media/video/uvc/uvc_entity.c index c3ab0c813be..48fea373c25 100644 --- a/drivers/media/video/uvc/uvc_entity.c +++ b/drivers/media/video/uvc/uvc_entity.c @@ -27,14 +27,20 @@ static int uvc_mc_register_entity(struct uvc_video_chain *chain, struct uvc_entity *entity) { const u32 flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE; - struct uvc_entity *remote; + struct media_entity *sink; unsigned int i; - u8 remote_pad; - int ret = 0; + int ret; + + sink = (UVC_ENTITY_TYPE(entity) == UVC_TT_STREAMING) + ? (entity->vdev ? &entity->vdev->entity : NULL) + : &entity->subdev.entity; + if (sink == NULL) + return 0; for (i = 0; i < entity->num_pads; ++i) { struct media_entity *source; - struct media_entity *sink; + struct uvc_entity *remote; + u8 remote_pad; if (!(entity->pads[i].flags & MEDIA_PAD_FL_SINK)) continue; @@ -43,10 +49,11 @@ static int uvc_mc_register_entity(struct uvc_video_chain *chain, if (remote == NULL) return -EINVAL; - source = (UVC_ENTITY_TYPE(remote) == UVC_TT_STREAMING) - ? &remote->vdev->entity : &remote->subdev.entity; - sink = (UVC_ENTITY_TYPE(entity) == UVC_TT_STREAMING) - ? &entity->vdev->entity : &entity->subdev.entity; + source = (UVC_ENTITY_TYPE(remote) != UVC_TT_STREAMING) + ? (remote->vdev ? &remote->vdev->entity : NULL) + : &remote->subdev.entity; + if (source == NULL) + continue; remote_pad = remote->num_pads - 1; ret = media_entity_create_link(source, remote_pad, @@ -55,11 +62,10 @@ static int uvc_mc_register_entity(struct uvc_video_chain *chain, return ret; } - if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING) - ret = v4l2_device_register_subdev(&chain->dev->vdev, - &entity->subdev); + if (UVC_ENTITY_TYPE(entity) == UVC_TT_STREAMING) + return 0; - return ret; + return v4l2_device_register_subdev(&chain->dev->vdev, &entity->subdev); } static struct v4l2_subdev_ops uvc_subdev_ops = { @@ -84,9 +90,11 @@ static int uvc_mc_init_entity(struct uvc_entity *entity) ret = media_entity_init(&entity->subdev.entity, entity->num_pads, entity->pads, 0); - } else + } else if (entity->vdev != NULL) { ret = media_entity_init(&entity->vdev->entity, entity->num_pads, entity->pads, 0); + } else + ret = 0; return ret; } diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c index 109a06384a8..f90ce9fce53 100644 --- a/drivers/media/video/uvc/uvc_queue.c +++ b/drivers/media/video/uvc/uvc_queue.c @@ -104,6 +104,8 @@ static int __uvc_free_buffers(struct uvc_video_queue *queue) } if (queue->count) { + uvc_queue_cancel(queue, 0); + INIT_LIST_HEAD(&queue->mainqueue); vfree(queue->mem); queue->count = 0; } diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index fc766b9f24c..49994793cc7 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c @@ -1255,8 +1255,10 @@ int uvc_video_enable(struct uvc_streaming *stream, int enable) /* Commit the streaming parameters. */ ret = uvc_commit_video(stream, &stream->ctrl); - if (ret < 0) + if (ret < 0) { + uvc_queue_enable(&stream->queue, 0); return ret; + } return uvc_init_video(stream, GFP_KERNEL); } diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 19d5ae29378..06f14008b34 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -167,6 +167,12 @@ static void v4l2_device_release(struct device *cd) mutex_unlock(&videodev_lock); +#if defined(CONFIG_MEDIA_CONTROLLER) + if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && + vdev->vfl_type != VFL_TYPE_SUBDEV) + media_device_unregister_entity(&vdev->entity); +#endif + /* Release video_device and perform other cleanups as needed. */ vdev->release(vdev); @@ -389,9 +395,6 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm) static int v4l2_open(struct inode *inode, struct file *filp) { struct video_device *vdev; -#if defined(CONFIG_MEDIA_CONTROLLER) - struct media_entity *entity = NULL; -#endif int ret = 0; /* Check if the video device is available */ @@ -405,17 +408,6 @@ static int v4l2_open(struct inode *inode, struct file *filp) /* and increase the device refcount */ video_get(vdev); mutex_unlock(&videodev_lock); -#if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && - vdev->vfl_type != VFL_TYPE_SUBDEV) { - entity = media_entity_get(&vdev->entity); - if (!entity) { - ret = -EBUSY; - video_put(vdev); - return ret; - } - } -#endif if (vdev->fops->open) { if (vdev->lock && mutex_lock_interruptible(vdev->lock)) { ret = -ERESTARTSYS; @@ -431,14 +423,8 @@ static int v4l2_open(struct inode *inode, struct file *filp) err: /* decrease the refcount in case of an error */ - if (ret) { -#if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && - vdev->vfl_type != VFL_TYPE_SUBDEV) - media_entity_put(entity); -#endif + if (ret) video_put(vdev); - } return ret; } @@ -455,11 +441,6 @@ static int v4l2_release(struct inode *inode, struct file *filp) if (vdev->lock) mutex_unlock(vdev->lock); } -#if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && - vdev->vfl_type != VFL_TYPE_SUBDEV) - media_entity_put(&vdev->entity); -#endif /* decrease the refcount unconditionally since the release() return value is ignored. */ video_put(vdev); @@ -754,12 +735,6 @@ void video_unregister_device(struct video_device *vdev) if (!vdev || !video_is_registered(vdev)) return; -#if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && - vdev->vfl_type != VFL_TYPE_SUBDEV) - media_device_unregister_entity(&vdev->entity); -#endif - mutex_lock(&videodev_lock); /* This must be in a critical section to prevent a race with v4l2_open. * Once this bit has been cleared video_get may never be called again. diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index 506edcc2dde..69e8c6ffcc4 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -1822,6 +1822,8 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_g_tuner) break; + p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ? + V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; ret = ops->vidioc_g_tuner(file, fh, p); if (!ret) dbgarg(cmd, "index=%d, name=%s, type=%d, " @@ -1840,6 +1842,8 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_s_tuner) break; + p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ? + V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; dbgarg(cmd, "index=%d, name=%s, type=%d, " "capability=0x%x, rangelow=%d, " "rangehigh=%d, signal=%d, afc=%d, " @@ -1858,6 +1862,8 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_g_frequency) break; + p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ? + V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; ret = ops->vidioc_g_frequency(file, fh, p); if (!ret) dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n", @@ -1940,13 +1946,19 @@ static long __video_do_ioctl(struct file *file, case VIDIOC_S_HW_FREQ_SEEK: { struct v4l2_hw_freq_seek *p = arg; + enum v4l2_tuner_type type; if (!ops->vidioc_s_hw_freq_seek) break; + type = (vfd->vfl_type == VFL_TYPE_RADIO) ? + V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; dbgarg(cmd, - "tuner=%d, type=%d, seek_upward=%d, wrap_around=%d\n", - p->tuner, p->type, p->seek_upward, p->wrap_around); - ret = ops->vidioc_s_hw_freq_seek(file, fh, p); + "tuner=%u, type=%u, seek_upward=%u, wrap_around=%u, spacing=%u\n", + p->tuner, p->type, p->seek_upward, p->wrap_around, p->spacing); + if (p->type != type) + ret = -EINVAL; + else + ret = ops->vidioc_s_hw_freq_seek(file, fh, p); break; } case VIDIOC_ENUM_FRAMESIZES: diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 6ba1461d51e..3015e600094 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -492,13 +492,6 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) return -EINVAL; } - /* - * If the same number of buffers and memory access method is requested - * then return immediately. - */ - if (q->memory == req->memory && req->count == q->num_buffers) - return 0; - if (req->count == 0 || q->num_buffers != 0 || q->memory != req->memory) { /* * We already have buffers allocated, so first check if they @@ -539,9 +532,9 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) /* Finally, allocate buffers and video memory */ ret = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes, plane_sizes); - if (ret < 0) { - dprintk(1, "Memory allocation failed with error: %d\n", ret); - return ret; + if (ret == 0) { + dprintk(1, "Memory allocation failed\n"); + return -ENOMEM; } /* @@ -1196,6 +1189,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q) * has not already dequeued before initiating cancel. */ INIT_LIST_HEAD(&q->done_list); + atomic_set(&q->queued_count, 0); wake_up_all(&q->done_wq); /* diff --git a/drivers/media/video/videobuf2-dma-sg.c b/drivers/media/video/videobuf2-dma-sg.c index b2d9485aac7..10a20d9509d 100644 --- a/drivers/media/video/videobuf2-dma-sg.c +++ b/drivers/media/video/videobuf2-dma-sg.c @@ -62,7 +62,7 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size) goto fail_pages_array_alloc; for (i = 0; i < buf->sg_desc.num_pages; ++i) { - buf->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); + buf->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN); if (NULL == buf->pages[i]) goto fail_pages_alloc; sg_set_page(&buf->sg_desc.sglist[i], |