Commit de3796e7 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6

* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (46 commits)
  [media] rc: call input_sync after scancode reports
  [media] imon: allow either proto on unknown 0xffdc
  [media] imon: auto-config ffdc 7e device
  [media] saa7134: fix raw IR timeout value
  [media] rc: fix ghost keypresses with certain hw
  [media] [staging] lirc_serial: allocate irq at init time
  [media] lirc_zilog: fix spinning rx thread
  [media] keymaps: fix table for pinnacle pctv hd devices
  [media] ite-cir: 8709 needs to use pnp resource 2
  [media] V4L: mx1-camera: fix uninitialized variable
  [media] omap_vout: Added check in reqbuf & mmap for buf_size allocation
  [media] OMAP_VOUT: Change hardcoded device node number to -1
  [media] OMAP_VOUTLIB: Fix wrong resizer calculation
  [media] uvcvideo: Disable the queue when failing to start
  [media] uvcvideo: Remove buffers from the queues when freeing
  [media] uvcvideo: Ignore entities for terminals with no supported format
  [media] v4l: Don't access media entity after is has been destroyed
  [media] media: omap3isp: fix a potential NULL deref
  [media] media: vb2: fix allocation failure check
  [media] media: vb2: reset queued_count value during queue reinitialization
  ...

Fix up trivial conflict in MAINTAINERS as per Mauro
parents bcb65a79 98c32bcd
...@@ -6733,6 +6733,7 @@ F: fs/fat/ ...@@ -6733,6 +6733,7 @@ F: fs/fat/
VIDEOBUF2 FRAMEWORK VIDEOBUF2 FRAMEWORK
M: Pawel Osciak <pawel@osciak.com> M: Pawel Osciak <pawel@osciak.com>
M: Marek Szyprowski <m.szyprowski@samsung.com> M: Marek Szyprowski <m.szyprowski@samsung.com>
M: Kyungmin Park <kyungmin.park@samsung.com>
L: linux-media@vger.kernel.org L: linux-media@vger.kernel.org
S: Maintained S: Maintained
F: drivers/media/video/videobuf2-* F: drivers/media/video/videobuf2-*
......
...@@ -597,12 +597,17 @@ static void __devexit fintek_remove(struct pnp_dev *pdev) ...@@ -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) static int fintek_suspend(struct pnp_dev *pdev, pm_message_t state)
{ {
struct fintek_dev *fintek = pnp_get_drvdata(pdev); struct fintek_dev *fintek = pnp_get_drvdata(pdev);
unsigned long flags;
fit_dbg("%s called", __func__); fit_dbg("%s called", __func__);
spin_lock_irqsave(&fintek->fintek_lock, flags);
/* disable all CIR interrupts */ /* disable all CIR interrupts */
fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS); fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS);
spin_unlock_irqrestore(&fintek->fintek_lock, flags);
fintek_config_mode_enable(fintek); fintek_config_mode_enable(fintek);
/* disable cir logical dev */ /* disable cir logical dev */
......
...@@ -307,6 +307,14 @@ static const struct { ...@@ -307,6 +307,14 @@ static const struct {
/* 0xffdc iMON MCE VFD */ /* 0xffdc iMON MCE VFD */
{ 0x00010000ffffffeell, KEY_VOLUMEUP }, { 0x00010000ffffffeell, KEY_VOLUMEUP },
{ 0x01000000ffffffeell, KEY_VOLUMEDOWN }, { 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 */ /* iMON Knob values */
{ 0x000100ffffffffeell, KEY_VOLUMEUP }, { 0x000100ffffffffeell, KEY_VOLUMEUP },
{ 0x010000ffffffffeell, KEY_VOLUMEDOWN }, { 0x010000ffffffffeell, KEY_VOLUMEDOWN },
...@@ -1582,16 +1590,16 @@ static void imon_incoming_packet(struct imon_context *ictx, ...@@ -1582,16 +1590,16 @@ static void imon_incoming_packet(struct imon_context *ictx,
/* Only panel type events left to process now */ /* Only panel type events left to process now */
spin_lock_irqsave(&ictx->kc_lock, flags); spin_lock_irqsave(&ictx->kc_lock, flags);
do_gettimeofday(&t);
/* KEY_MUTE repeats from knob need to be suppressed */ /* KEY_MUTE repeats from knob need to be suppressed */
if (ictx->kc == KEY_MUTE && ictx->kc == ictx->last_keycode) { if (ictx->kc == KEY_MUTE && ictx->kc == ictx->last_keycode) {
do_gettimeofday(&t);
msec = tv2int(&t, &prev_time); msec = tv2int(&t, &prev_time);
prev_time = t;
if (msec < ictx->idev->rep[REP_DELAY]) { if (msec < ictx->idev->rep[REP_DELAY]) {
spin_unlock_irqrestore(&ictx->kc_lock, flags); spin_unlock_irqrestore(&ictx->kc_lock, flags);
return; return;
} }
} }
prev_time = t;
kc = ictx->kc; kc = ictx->kc;
spin_unlock_irqrestore(&ictx->kc_lock, flags); spin_unlock_irqrestore(&ictx->kc_lock, flags);
...@@ -1603,7 +1611,9 @@ static void imon_incoming_packet(struct imon_context *ictx, ...@@ -1603,7 +1611,9 @@ static void imon_incoming_packet(struct imon_context *ictx,
input_report_key(ictx->idev, kc, 0); input_report_key(ictx->idev, kc, 0);
input_sync(ictx->idev); input_sync(ictx->idev);
spin_lock_irqsave(&ictx->kc_lock, flags);
ictx->last_keycode = kc; ictx->last_keycode = kc;
spin_unlock_irqrestore(&ictx->kc_lock, flags);
return; return;
...@@ -1740,6 +1750,8 @@ static void imon_get_ffdc_type(struct imon_context *ictx) ...@@ -1740,6 +1750,8 @@ static void imon_get_ffdc_type(struct imon_context *ictx)
detected_display_type = IMON_DISPLAY_TYPE_VFD; detected_display_type = IMON_DISPLAY_TYPE_VFD;
break; break;
/* iMON VFD, MCE IR */ /* iMON VFD, MCE IR */
case 0x46:
case 0x7e:
case 0x9e: case 0x9e:
dev_info(ictx->dev, "0xffdc iMON VFD, MCE IR"); dev_info(ictx->dev, "0xffdc iMON VFD, MCE IR");
detected_display_type = IMON_DISPLAY_TYPE_VFD; detected_display_type = IMON_DISPLAY_TYPE_VFD;
...@@ -1755,6 +1767,9 @@ static void imon_get_ffdc_type(struct imon_context *ictx) ...@@ -1755,6 +1767,9 @@ static void imon_get_ffdc_type(struct imon_context *ictx)
dev_info(ictx->dev, "Unknown 0xffdc device, " dev_info(ictx->dev, "Unknown 0xffdc device, "
"defaulting to VFD and iMON IR"); "defaulting to VFD and iMON IR");
detected_display_type = IMON_DISPLAY_TYPE_VFD; 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; break;
} }
......
...@@ -114,18 +114,20 @@ int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type) ...@@ -114,18 +114,20 @@ int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type)
s64 delta; /* ns */ s64 delta; /* ns */
DEFINE_IR_RAW_EVENT(ev); DEFINE_IR_RAW_EVENT(ev);
int rc = 0; int rc = 0;
int delay;
if (!dev->raw) if (!dev->raw)
return -EINVAL; return -EINVAL;
now = ktime_get(); now = ktime_get();
delta = ktime_to_ns(ktime_sub(now, dev->raw->last_event)); 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 /* Check for a long duration since last event or if we're
* being called for the first time, note that delta can't * being called for the first time, note that delta can't
* possibly be negative. * possibly be negative.
*/ */
if (delta > IR_MAX_DURATION || !dev->raw->last_type) if (delta > delay || !dev->raw->last_type)
type |= IR_START_EVENT; type |= IR_START_EVENT;
else else
ev.duration = delta; ev.duration = delta;
......
...@@ -1347,6 +1347,7 @@ static const struct ite_dev_params ite_dev_descs[] = { ...@@ -1347,6 +1347,7 @@ static const struct ite_dev_params ite_dev_descs[] = {
{ /* 0: ITE8704 */ { /* 0: ITE8704 */
.model = "ITE8704 CIR transceiver", .model = "ITE8704 CIR transceiver",
.io_region_size = IT87_IOREG_LENGTH, .io_region_size = IT87_IOREG_LENGTH,
.io_rsrc_no = 0,
.hw_tx_capable = true, .hw_tx_capable = true,
.sample_period = (u32) (1000000000ULL / 115200), .sample_period = (u32) (1000000000ULL / 115200),
.tx_carrier_freq = 38000, .tx_carrier_freq = 38000,
...@@ -1371,6 +1372,7 @@ static const struct ite_dev_params ite_dev_descs[] = { ...@@ -1371,6 +1372,7 @@ static const struct ite_dev_params ite_dev_descs[] = {
{ /* 1: ITE8713 */ { /* 1: ITE8713 */
.model = "ITE8713 CIR transceiver", .model = "ITE8713 CIR transceiver",
.io_region_size = IT87_IOREG_LENGTH, .io_region_size = IT87_IOREG_LENGTH,
.io_rsrc_no = 0,
.hw_tx_capable = true, .hw_tx_capable = true,
.sample_period = (u32) (1000000000ULL / 115200), .sample_period = (u32) (1000000000ULL / 115200),
.tx_carrier_freq = 38000, .tx_carrier_freq = 38000,
...@@ -1395,6 +1397,7 @@ static const struct ite_dev_params ite_dev_descs[] = { ...@@ -1395,6 +1397,7 @@ static const struct ite_dev_params ite_dev_descs[] = {
{ /* 2: ITE8708 */ { /* 2: ITE8708 */
.model = "ITE8708 CIR transceiver", .model = "ITE8708 CIR transceiver",
.io_region_size = IT8708_IOREG_LENGTH, .io_region_size = IT8708_IOREG_LENGTH,
.io_rsrc_no = 0,
.hw_tx_capable = true, .hw_tx_capable = true,
.sample_period = (u32) (1000000000ULL / 115200), .sample_period = (u32) (1000000000ULL / 115200),
.tx_carrier_freq = 38000, .tx_carrier_freq = 38000,
...@@ -1420,6 +1423,7 @@ static const struct ite_dev_params ite_dev_descs[] = { ...@@ -1420,6 +1423,7 @@ static const struct ite_dev_params ite_dev_descs[] = {
{ /* 3: ITE8709 */ { /* 3: ITE8709 */
.model = "ITE8709 CIR transceiver", .model = "ITE8709 CIR transceiver",
.io_region_size = IT8709_IOREG_LENGTH, .io_region_size = IT8709_IOREG_LENGTH,
.io_rsrc_no = 2,
.hw_tx_capable = true, .hw_tx_capable = true,
.sample_period = (u32) (1000000000ULL / 115200), .sample_period = (u32) (1000000000ULL / 115200),
.tx_carrier_freq = 38000, .tx_carrier_freq = 38000,
...@@ -1461,6 +1465,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id ...@@ -1461,6 +1465,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
struct rc_dev *rdev = NULL; struct rc_dev *rdev = NULL;
int ret = -ENOMEM; int ret = -ENOMEM;
int model_no; int model_no;
int io_rsrc_no;
ite_dbg("%s called", __func__); ite_dbg("%s called", __func__);
...@@ -1490,10 +1495,11 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id ...@@ -1490,10 +1495,11 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
/* get the description for the device */ /* get the description for the device */
dev_desc = &ite_dev_descs[model_no]; dev_desc = &ite_dev_descs[model_no];
io_rsrc_no = dev_desc->io_rsrc_no;
/* validate pnp resources */ /* validate pnp resources */
if (!pnp_port_valid(pdev, 0) || if (!pnp_port_valid(pdev, io_rsrc_no) ||
pnp_port_len(pdev, 0) != dev_desc->io_region_size) { pnp_port_len(pdev, io_rsrc_no) != dev_desc->io_region_size) {
dev_err(&pdev->dev, "IR PNP Port not valid!\n"); dev_err(&pdev->dev, "IR PNP Port not valid!\n");
goto failure; goto failure;
} }
...@@ -1504,7 +1510,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id ...@@ -1504,7 +1510,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
} }
/* store resource values */ /* 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); itdev->cir_irq = pnp_irq(pdev, 0);
/* initialize spinlocks */ /* initialize spinlocks */
......
...@@ -57,6 +57,9 @@ struct ite_dev_params { ...@@ -57,6 +57,9 @@ struct ite_dev_params {
/* size of the I/O region */ /* size of the I/O region */
int io_region_size; int io_region_size;
/* IR pnp I/O resource number */
int io_rsrc_no;
/* true if the hardware supports transmission */ /* true if the hardware supports transmission */
bool hw_tx_capable; bool hw_tx_capable;
......
...@@ -15,43 +15,39 @@ ...@@ -15,43 +15,39 @@
/* Pinnacle PCTV HD 800i mini remote */ /* Pinnacle PCTV HD 800i mini remote */
static struct rc_map_table pinnacle_pctv_hd[] = { static struct rc_map_table pinnacle_pctv_hd[] = {
/* Key codes for the tiny Pinnacle remote*/
{ 0x0f, KEY_1 }, { 0x0700, KEY_MUTE },
{ 0x15, KEY_2 }, { 0x0701, KEY_MENU }, /* Pinnacle logo */
{ 0x10, KEY_3 }, { 0x0739, KEY_POWER },
{ 0x18, KEY_4 }, { 0x0703, KEY_VOLUMEUP },
{ 0x1b, KEY_5 }, { 0x0709, KEY_VOLUMEDOWN },
{ 0x1e, KEY_6 }, { 0x0706, KEY_CHANNELUP },
{ 0x11, KEY_7 }, { 0x070c, KEY_CHANNELDOWN },
{ 0x21, KEY_8 }, { 0x070f, KEY_1 },
{ 0x12, KEY_9 }, { 0x0715, KEY_2 },
{ 0x27, KEY_0 }, { 0x0710, KEY_3 },
{ 0x0718, KEY_4 },
{ 0x24, KEY_ZOOM }, { 0x071b, KEY_5 },
{ 0x2a, KEY_SUBTITLE }, { 0x071e, KEY_6 },
{ 0x0711, KEY_7 },
{ 0x00, KEY_MUTE }, { 0x0721, KEY_8 },
{ 0x01, KEY_ENTER }, /* Pinnacle Logo */ { 0x0712, KEY_9 },
{ 0x39, KEY_POWER }, { 0x0727, KEY_0 },
{ 0x0724, KEY_ZOOM }, /* 'Square' key */
{ 0x03, KEY_VOLUMEUP }, { 0x072a, KEY_SUBTITLE }, /* 'T' key */
{ 0x09, KEY_VOLUMEDOWN }, { 0x072d, KEY_REWIND },
{ 0x06, KEY_CHANNELUP }, { 0x0730, KEY_PLAYPAUSE },
{ 0x0c, KEY_CHANNELDOWN }, { 0x0733, KEY_FASTFORWARD },
{ 0x0736, KEY_RECORD },
{ 0x2d, KEY_REWIND }, { 0x073c, KEY_STOP },
{ 0x30, KEY_PLAYPAUSE }, { 0x073f, KEY_HELP }, /* '?' key */
{ 0x33, KEY_FASTFORWARD },
{ 0x3c, KEY_STOP },
{ 0x36, KEY_RECORD },
{ 0x3f, KEY_EPG }, /* Labeled "?" */
}; };
static struct rc_map_list pinnacle_pctv_hd_map = { static struct rc_map_list pinnacle_pctv_hd_map = {
.map = { .map = {
.scan = pinnacle_pctv_hd, .scan = pinnacle_pctv_hd,
.size = ARRAY_SIZE(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, .name = RC_MAP_PINNACLE_PCTV_HD,
} }
}; };
......
...@@ -55,6 +55,8 @@ struct irctl { ...@@ -55,6 +55,8 @@ struct irctl {
struct lirc_buffer *buf; struct lirc_buffer *buf;
unsigned int chunk_size; unsigned int chunk_size;
struct cdev *cdev;
struct task_struct *task; struct task_struct *task;
long jiffies_to_wait; long jiffies_to_wait;
}; };
...@@ -62,7 +64,6 @@ struct irctl { ...@@ -62,7 +64,6 @@ struct irctl {
static DEFINE_MUTEX(lirc_dev_lock); static DEFINE_MUTEX(lirc_dev_lock);
static struct irctl *irctls[MAX_IRCTL_DEVICES]; static struct irctl *irctls[MAX_IRCTL_DEVICES];
static struct cdev cdevs[MAX_IRCTL_DEVICES];
/* Only used for sysfs but defined to void otherwise */ /* Only used for sysfs but defined to void otherwise */
static struct class *lirc_class; static struct class *lirc_class;
...@@ -167,9 +168,13 @@ static struct file_operations lirc_dev_fops = { ...@@ -167,9 +168,13 @@ static struct file_operations lirc_dev_fops = {
static int lirc_cdev_add(struct irctl *ir) static int lirc_cdev_add(struct irctl *ir)
{ {
int retval; int retval = -ENOMEM;
struct lirc_driver *d = &ir->d; 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) { if (d->fops) {
cdev_init(cdev, d->fops); cdev_init(cdev, d->fops);
...@@ -180,12 +185,20 @@ static int lirc_cdev_add(struct irctl *ir) ...@@ -180,12 +185,20 @@ static int lirc_cdev_add(struct irctl *ir)
} }
retval = kobject_set_name(&cdev->kobj, "lirc%d", d->minor); retval = kobject_set_name(&cdev->kobj, "lirc%d", d->minor);
if (retval) if (retval)
return retval; goto err_out;
retval = cdev_add(cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1); retval = cdev_add(cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1);
if (retval) if (retval) {
kobject_put(&cdev->kobj); kobject_put(&cdev->kobj);
goto err_out;
}
ir->cdev = cdev;
return 0;
err_out:
kfree(cdev);
return retval; return retval;
} }
...@@ -214,7 +227,7 @@ int lirc_register_driver(struct lirc_driver *d) ...@@ -214,7 +227,7 @@ int lirc_register_driver(struct lirc_driver *d)
if (MAX_IRCTL_DEVICES <= d->minor) { if (MAX_IRCTL_DEVICES <= d->minor) {
dev_err(d->dev, "lirc_dev: lirc_register_driver: " dev_err(d->dev, "lirc_dev: lirc_register_driver: "
"\"minor\" must be between 0 and %d (%d)!\n", "\"minor\" must be between 0 and %d (%d)!\n",
MAX_IRCTL_DEVICES-1, d->minor); MAX_IRCTL_DEVICES - 1, d->minor);
err = -EBADRQC; err = -EBADRQC;
goto out; goto out;
} }
...@@ -369,7 +382,7 @@ int lirc_unregister_driver(int minor) ...@@ -369,7 +382,7 @@ int lirc_unregister_driver(int minor)
if (minor < 0 || minor >= MAX_IRCTL_DEVICES) { if (minor < 0 || minor >= MAX_IRCTL_DEVICES) {
printk(KERN_ERR "lirc_dev: %s: minor (%d) must be between " 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; return -EBADRQC;
} }
...@@ -380,7 +393,7 @@ int lirc_unregister_driver(int minor) ...@@ -380,7 +393,7 @@ int lirc_unregister_driver(int minor)
return -ENOENT; return -ENOENT;
} }
cdev = &cdevs[minor]; cdev = ir->cdev;
mutex_lock(&lirc_dev_lock); mutex_lock(&lirc_dev_lock);
...@@ -410,6 +423,7 @@ int lirc_unregister_driver(int minor) ...@@ -410,6 +423,7 @@ int lirc_unregister_driver(int minor)
} else { } else {
lirc_irctl_cleanup(ir); lirc_irctl_cleanup(ir);
cdev_del(cdev); cdev_del(cdev);
kfree(cdev);
kfree(ir); kfree(ir);
irctls[minor] = NULL; irctls[minor] = NULL;
} }
...@@ -453,7 +467,7 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file) ...@@ -453,7 +467,7 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file)
goto error; goto error;
} }
cdev = &cdevs[iminor(inode)]; cdev = ir->cdev;
if (try_module_get(cdev->owner)) { if (try_module_get(cdev->owner)) {
ir->open++; ir->open++;
retval = ir->d.set_use_inc(ir->d.data); retval = ir->d.set_use_inc(ir->d.data);
...@@ -484,13 +498,15 @@ EXPORT_SYMBOL(lirc_dev_fop_open); ...@@ -484,13 +498,15 @@ EXPORT_SYMBOL(lirc_dev_fop_open);
int lirc_dev_fop_close(struct inode *inode, struct file *file) int lirc_dev_fop_close(struct inode *inode, struct file *file)
{ {
struct irctl *ir = irctls[iminor(inode)]; struct irctl *ir = irctls[iminor(inode)];
struct cdev *cdev = &cdevs[iminor(inode)]; struct cdev *cdev;
if (!ir) { if (!ir) {
printk(KERN_ERR "%s: called with invalid irctl\n", __func__); printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
return -EINVAL; return -EINVAL;
} }
cdev = ir->cdev;
dev_dbg(ir->d.dev, LOGHEAD "close called\n", ir->d.name, ir->d.minor); dev_dbg(ir->d.dev, LOGHEAD "close called\n", ir->d.name, ir->d.minor);
WARN_ON(mutex_lock_killable(&lirc_dev_lock)); WARN_ON(mutex_lock_killable(&lirc_dev_lock));
...@@ -503,6 +519,7 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file) ...@@ -503,6 +519,7 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file)
lirc_irctl_cleanup(ir); lirc_irctl_cleanup(ir);
cdev_del(cdev); cdev_del(cdev);
irctls[ir->d.minor] = NULL; irctls[ir->d.minor] = NULL;
kfree(cdev);
kfree(ir); kfree(ir);
} }
......
...@@ -108,6 +108,12 @@ static int debug = 1; ...@@ -108,6 +108,12 @@ static int debug = 1;
static int debug; static int debug;
#endif #endif
#define mce_dbg(dev, fmt, ...) \
do { \
if (debug) \
dev_info(dev, fmt, ## __VA_ARGS__); \
} while (0)
/* general constants */ /* general constants */
#define SEND_FLAG_IN_PROGRESS 1 #define SEND_FLAG_IN_PROGRESS 1
#define SEND_FLAG_COMPLETE 2 #define SEND_FLAG_COMPLETE 2
...@@ -246,6 +252,9 @@ static struct usb_device_id mceusb_dev_table[] = { ...@@ -246,6 +252,9 @@ static struct usb_device_id mceusb_dev_table[] = {
.driver_info = MCE_GEN2_TX_INV }, .driver_info = MCE_GEN2_TX_INV },
/* SMK eHome Infrared Transceiver */ /* SMK eHome Infrared Transceiver */
{ USB_DEVICE(VENDOR_SMK, 0x0338) }, { 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 */ /* Tatung eHome Infrared Transceiver */
{ USB_DEVICE(VENDOR_TATUNG, 0x9150) }, { USB_DEVICE(VENDOR_TATUNG, 0x9150) },
/* Shuttle eHome Infrared Transceiver */ /* Shuttle eHome Infrared Transceiver */
...@@ -606,12 +615,15 @@ static void mce_async_callback(struct urb *urb, struct pt_regs *regs) ...@@ -606,12 +615,15 @@ static void mce_async_callback(struct urb *urb, struct pt_regs *regs)
if (ir) { if (ir) {
len = urb->actual_length; 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); urb->status, len);
mceusb_dev_printdata(ir, urb->transfer_buffer, 0, len, true); 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 */ /* 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, ...@@ -655,17 +667,17 @@ static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data,
return; 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->transfer_buffer_length = size;
async_urb->dev = ir->usbdev; async_urb->dev = ir->usbdev;
res = usb_submit_urb(async_urb, GFP_ATOMIC); res = usb_submit_urb(async_urb, GFP_ATOMIC);
if (res) { if (res) {
dev_dbg(dev, "receive request FAILED! (res=%d)\n", res); mce_dbg(dev, "receive request FAILED! (res=%d)\n", res);
return; 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) 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) ...@@ -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); 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) */ /* Send data out the IR blaster port(s) */
...@@ -794,7 +806,7 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier) ...@@ -794,7 +806,7 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier)
ir->carrier = carrier; ir->carrier = carrier;
cmdbuf[2] = MCE_CMD_SIG_END; cmdbuf[2] = MCE_CMD_SIG_END;
cmdbuf[3] = MCE_IRDATA_TRAILER; cmdbuf[3] = MCE_IRDATA_TRAILER;
dev_dbg(ir->dev, "%s: disabling carrier " mce_dbg(ir->dev, "%s: disabling carrier "
"modulation\n", __func__); "modulation\n", __func__);
mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
return carrier; return carrier;
...@@ -806,7 +818,7 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier) ...@@ -806,7 +818,7 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier)
ir->carrier = carrier; ir->carrier = carrier;
cmdbuf[2] = prescaler; cmdbuf[2] = prescaler;
cmdbuf[3] = divisor; cmdbuf[3] = divisor;
dev_dbg(ir->dev, "%s: requesting %u HZ " mce_dbg(ir->dev, "%s: requesting %u HZ "
"carrier\n", __func__, carrier); "carrier\n", __func__, carrier);
/* Transmit new carrier to mce device */ /* Transmit new carrier to mce device */
...@@ -879,7 +891,7 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) ...@@ -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) rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK)
* US_TO_NS(MCE_TIME_UNIT); * 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.pulse ? "pulse" : "space",
rawir.duration); rawir.duration);
...@@ -911,7 +923,7 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) ...@@ -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) if (ir->parser_state != CMD_HEADER && !ir->rem)
ir->parser_state = CMD_HEADER; 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); ir_raw_event_handle(ir->rc);
} }
...@@ -933,7 +945,7 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs) ...@@ -933,7 +945,7 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs)
if (ir->send_flags == RECV_FLAG_IN_PROGRESS) { if (ir->send_flags == RECV_FLAG_IN_PROGRESS) {
ir->send_flags = SEND_FLAG_COMPLETE; 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); buf_len);
} }
...@@ -951,7 +963,7 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs) ...@@ -951,7 +963,7 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs)
case -EPIPE: case -EPIPE:
default: default:
dev_dbg(ir->dev, "Error: urb status = %d\n", urb->status); mce_dbg(ir->dev, "Error: urb status = %d\n", urb->status);
break; break;
} }
...@@ -961,7 +973,6 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs) ...@@ -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) static void mceusb_gen1_init(struct mceusb_dev *ir)
{ {
int ret; int ret;
int maxp = ir->len_in;
struct device *dev = ir->dev; struct device *dev = ir->dev;
char *data; char *data;
...@@ -978,8 +989,8 @@ static void mceusb_gen1_init(struct mceusb_dev *ir) ...@@ -978,8 +989,8 @@ static void mceusb_gen1_init(struct mceusb_dev *ir)
ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
USB_REQ_SET_ADDRESS, USB_TYPE_VENDOR, 0, 0, USB_REQ_SET_ADDRESS, USB_TYPE_VENDOR, 0, 0,
data, USB_CTRL_MSG_SZ, HZ * 3); data, USB_CTRL_MSG_SZ, HZ * 3);
dev_dbg(dev, "%s - ret = %d\n", __func__, ret); mce_dbg(dev, "%s - ret = %d\n", __func__, ret);
dev_dbg(dev, "%s - data[0] = %d, data[1] = %d\n", mce_dbg(dev, "%s - data[0] = %d, data[1] = %d\n",
__func__, data[0], data[1]); __func__, data[0], data[1]);
/* set feature: bit rate 38400 bps */ /* set feature: bit rate 38400 bps */
...@@ -987,71 +998,56 @@ static void mceusb_gen1_init(struct mceusb_dev *ir) ...@@ -987,71 +998,56 @@ static void mceusb_gen1_init(struct mceusb_dev *ir)
USB_REQ_SET_FEATURE, USB_TYPE_VENDOR, USB_REQ_SET_FEATURE, USB_TYPE_VENDOR,
0xc04e, 0x0000, NULL, 0, HZ * 3); 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 */ /* bRequest 4: set char length to 8 bits */
ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
4, USB_TYPE_VENDOR, 4, USB_TYPE_VENDOR,
0x0808, 0x0000, NULL, 0, HZ * 3); 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 */ /* bRequest 2: set handshaking to use DTR/DSR */
ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
2, USB_TYPE_VENDOR, 2, USB_TYPE_VENDOR,
0x0000, 0x0100, NULL, 0, HZ * 3); 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 */ /* device reset */
mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET)); mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET));
mce_sync_in(ir, NULL, maxp);
/* get hw/sw revision? */ /* get hw/sw revision? */
mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION)); mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION));
mce_sync_in(ir, NULL, maxp);
kfree(data); kfree(data);
}; };
static void mceusb_gen2_init(struct mceusb_dev *ir) static void mceusb_gen2_init(struct mceusb_dev *ir)
{ {
int maxp = ir->len_in;
/* device reset */ /* device reset */
mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET)); mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET));
mce_sync_in(ir, NULL, maxp);
/* get hw/sw revision? */ /* get hw/sw revision? */
mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION)); mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION));
mce_sync_in(ir, NULL, maxp);
/* unknown what the next two actually return... */ /* unknown what the next two actually return... */
mce_async_out(ir, GET_UNKNOWN, sizeof(GET_UNKNOWN)); 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_async_out(ir, GET_UNKNOWN2, sizeof(GET_UNKNOWN2));
mce_sync_in(ir, NULL, maxp);
} }
static void mceusb_get_parameters(struct mceusb_dev *ir) static void mceusb_get_parameters(struct mceusb_dev *ir)
{ {
int maxp = ir->len_in;
/* get the carrier and frequency */ /* get the carrier and frequency */
mce_async_out(ir, GET_CARRIER_FREQ, sizeof(GET_CARRIER_FREQ)); 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 */ /* get the transmitter bitmask */
mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK)); mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK));
mce_sync_in(ir, NULL, maxp);
}
/* get receiver timeout value */ /* get receiver timeout value */
mce_async_out(ir, GET_RX_TIMEOUT, sizeof(GET_RX_TIMEOUT)); mce_async_out(ir, GET_RX_TIMEOUT, sizeof(GET_RX_TIMEOUT));
mce_sync_in(ir, NULL, maxp);
/* get receiver sensor setting */ /* get receiver sensor setting */
mce_async_out(ir, GET_RX_SENSOR, sizeof(GET_RX_SENSOR)); 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) 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, ...@@ -1122,7 +1118,7 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
bool tx_mask_normal; bool tx_mask_normal;
int ir_intfnum; int ir_intfnum;
dev_dbg(&intf->dev, "%s called\n", __func__); mce_dbg(&intf->dev, "%s called\n", __func__);
idesc = intf->cur_altsetting; idesc = intf->cur_altsetting;
...@@ -1150,7 +1146,7 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf, ...@@ -1150,7 +1146,7 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
ep_in = ep; ep_in = ep;
ep_in->bmAttributes = USB_ENDPOINT_XFER_INT; ep_in->bmAttributes = USB_ENDPOINT_XFER_INT;
ep_in->bInterval = 1; ep_in->bInterval = 1;
dev_dbg(&intf->dev, "acceptable inbound endpoint " mce_dbg(&intf->dev, "acceptable inbound endpoint "
"found\n"); "found\n");
} }
...@@ -1165,12 +1161,12 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf, ...@@ -1165,12 +1161,12 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
ep_out = ep; ep_out = ep;
ep_out->bmAttributes = USB_ENDPOINT_XFER_INT; ep_out->bmAttributes = USB_ENDPOINT_XFER_INT;
ep_out->bInterval = 1; ep_out->bInterval = 1;
dev_dbg(&intf->dev, "acceptable outbound endpoint " mce_dbg(&intf->dev, "acceptable outbound endpoint "
"found\n"); "found\n");
} }
} }
if (ep_in == NULL) { 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; return -ENODEV;
} }
...@@ -1215,16 +1211,16 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf, ...@@ -1215,16 +1211,16 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
if (!ir->rc) if (!ir->rc)
goto rc_dev_fail; 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 */ /* wire up inbound data handler */
usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in, usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in,
maxp, (usb_complete_t) mceusb_dev_recv, ir, ep_in->bInterval); maxp, (usb_complete_t) mceusb_dev_recv, ir, ep_in->bInterval);
ir->urb_in->transfer_dma = ir->dma_in; ir->urb_in->transfer_dma = ir->dma_in;
ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 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 */ /* initialize device */
if (ir->flags.microsoft_gen1) if (ir->flags.microsoft_gen1)
mceusb_gen1_init(ir); mceusb_gen1_init(ir);
......
...@@ -991,7 +991,6 @@ static int nvt_open(struct rc_dev *dev) ...@@ -991,7 +991,6 @@ static int nvt_open(struct rc_dev *dev)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&nvt->nvt_lock, flags); spin_lock_irqsave(&nvt->nvt_lock, flags);
nvt->in_use = true;
nvt_enable_cir(nvt); nvt_enable_cir(nvt);
spin_unlock_irqrestore(&nvt->nvt_lock, flags); spin_unlock_irqrestore(&nvt->nvt_lock, flags);
...@@ -1004,7 +1003,6 @@ static void nvt_close(struct rc_dev *dev) ...@@ -1004,7 +1003,6 @@ static void nvt_close(struct rc_dev *dev)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&nvt->nvt_lock, flags); spin_lock_irqsave(&nvt->nvt_lock, flags);
nvt->in_use = false;
nvt_disable_cir(nvt); nvt_disable_cir(nvt);
spin_unlock_irqrestore(&nvt->nvt_lock, flags); spin_unlock_irqrestore(&nvt->nvt_lock, flags);
} }
......
...@@ -70,7 +70,6 @@ struct nvt_dev { ...@@ -70,7 +70,6 @@ struct nvt_dev {
struct ir_raw_event rawir; struct ir_raw_event rawir;
spinlock_t nvt_lock; spinlock_t nvt_lock;
bool in_use;
/* for rx */ /* for rx */
u8 buf[RX_BUF_LEN]; u8 buf[RX_BUF_LEN];
......
...@@ -522,17 +522,19 @@ EXPORT_SYMBOL_GPL(rc_g_keycode_from_table); ...@@ -522,17 +522,19 @@ EXPORT_SYMBOL_GPL(rc_g_keycode_from_table);
/** /**
* ir_do_keyup() - internal function to signal the release of a keypress * ir_do_keyup() - internal function to signal the release of a keypress
* @dev: the struct rc_dev descriptor of the device * @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 * This function is used internally to release a keypress, it must be
* called with keylock held. * 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) if (!dev->keypressed)
return; return;
IR_dprintk(1, "keyup key 0x%04x\n", dev->last_keycode); IR_dprintk(1, "keyup key 0x%04x\n", dev->last_keycode);
input_report_key(dev->input_dev, dev->last_keycode, 0); input_report_key(dev->input_dev, dev->last_keycode, 0);
if (sync)
input_sync(dev->input_dev); input_sync(dev->input_dev);
dev->keypressed = false; dev->keypressed = false;
} }
...@@ -549,7 +551,7 @@ void rc_keyup(struct rc_dev *dev) ...@@ -549,7 +551,7 @@ void rc_keyup(struct rc_dev *dev)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&dev->keylock, flags); spin_lock_irqsave(&dev->keylock, flags);
ir_do_keyup(dev); ir_do_keyup(dev, true);
spin_unlock_irqrestore(&dev->keylock, flags); spin_unlock_irqrestore(&dev->keylock, flags);
} }
EXPORT_SYMBOL_GPL(rc_keyup); EXPORT_SYMBOL_GPL(rc_keyup);
...@@ -578,7 +580,7 @@ static void ir_timer_keyup(unsigned long cookie) ...@@ -578,7 +580,7 @@ static void ir_timer_keyup(unsigned long cookie)
*/ */
spin_lock_irqsave(&dev->keylock, flags); spin_lock_irqsave(&dev->keylock, flags);
if (time_is_before_eq_jiffies(dev->keyup_jiffies)) if (time_is_before_eq_jiffies(dev->keyup_jiffies))
ir_do_keyup(dev); ir_do_keyup(dev, true);
spin_unlock_irqrestore(&dev->keylock, flags); spin_unlock_irqrestore(&dev->keylock, flags);
} }
...@@ -597,6 +599,7 @@ void rc_repeat(struct rc_dev *dev) ...@@ -597,6 +599,7 @@ void rc_repeat(struct rc_dev *dev)
spin_lock_irqsave(&dev->keylock, flags); spin_lock_irqsave(&dev->keylock, flags);
input_event(dev->input_dev, EV_MSC, MSC_SCAN, dev->last_scancode); input_event(dev->input_dev, EV_MSC, MSC_SCAN, dev->last_scancode);
input_sync(dev->input_dev);
if (!dev->keypressed) if (!dev->keypressed)
goto out; goto out;
...@@ -622,29 +625,28 @@ EXPORT_SYMBOL_GPL(rc_repeat); ...@@ -622,29 +625,28 @@ EXPORT_SYMBOL_GPL(rc_repeat);
static void ir_do_keydown(struct rc_dev *dev, int scancode, static void ir_do_keydown(struct rc_dev *dev, int scancode,
u32 keycode, u8 toggle) u32 keycode, u8 toggle)
{ {
input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode); bool new_event = !dev->keypressed ||
dev->last_scancode != scancode ||
dev->last_toggle != toggle;
/* Repeat event? */ if (new_event && dev->keypressed)
if (dev->keypressed && ir_do_keyup(dev, false);
dev->last_scancode == scancode &&
dev->last_toggle == toggle)
return;
/* Release old keypress */ input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode);
ir_do_keyup(dev);
if (new_event && keycode != KEY_RESERVED) {
/* Register a keypress */
dev->keypressed = true;
dev->last_scancode = scancode; dev->last_scancode = scancode;
dev->last_toggle = toggle; dev->last_toggle = toggle;
dev->last_keycode = keycode; dev->last_keycode = keycode;
if (keycode == KEY_RESERVED) IR_dprintk(1, "%s: key down event, "
return; "key 0x%04x, scancode 0x%04x\n",
/* 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); dev->input_name, keycode, scancode);
input_report_key(dev->input_dev, dev->last_keycode, 1); input_report_key(dev->input_dev, keycode, 1);
}
input_sync(dev->input_dev); input_sync(dev->input_dev);
} }
......
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
* Header for M-5MOLS 8M Pixel camera sensor with ISP * Header for M-5MOLS 8M Pixel camera sensor with ISP
* *
* Copyright (C) 2011 Samsung Electronics Co., Ltd. * 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. * 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 * 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 * it under the terms of the GNU General Public License as published by
...@@ -106,23 +106,23 @@ struct m5mols_capture { ...@@ -106,23 +106,23 @@ struct m5mols_capture {
* The each value according to each scenemode is recommended in the documents. * The each value according to each scenemode is recommended in the documents.
*/ */
struct m5mols_scenemode { struct m5mols_scenemode {
u32 metering; u8 metering;
u32 ev_bias; u8 ev_bias;
u32 wb_mode; u8 wb_mode;
u32 wb_preset; u8 wb_preset;
u32 chroma_en; u8 chroma_en;
u32 chroma_lvl; u8 chroma_lvl;
u32 edge_en; u8 edge_en;
u32 edge_lvl; u8 edge_lvl;
u32 af_range; u8 af_range;
u32 fd_mode; u8 fd_mode;
u32 mcc; u8 mcc;
u32 light; u8 light;
u32 flash; u8 flash;
u32 tone; u8 tone;
u32 iso; u8 iso;
u32 capt_mode; u8 capt_mode;
u32 wdr; u8 wdr;
}; };
/** /**
...@@ -154,7 +154,6 @@ struct m5mols_version { ...@@ -154,7 +154,6 @@ struct m5mols_version {
u8 str[VERSION_STRING_SIZE]; u8 str[VERSION_STRING_SIZE];
u8 af; u8 af;
}; };
#define VERSION_SIZE sizeof(struct m5mols_version)
/** /**
* struct m5mols_info - M-5MOLS driver data structure * struct m5mols_info - M-5MOLS driver data structure
...@@ -216,9 +215,9 @@ struct m5mols_info { ...@@ -216,9 +215,9 @@ struct m5mols_info {
bool lock_ae; bool lock_ae;
bool lock_awb; bool lock_awb;
u8 resolution; u8 resolution;
u32 interrupt; u8 interrupt;
u32 mode; u8 mode;
u32 mode_save; u8 mode_save;
int (*set_power)(struct device *dev, int on); int (*set_power)(struct device *dev, int on);
}; };
...@@ -256,9 +255,11 @@ struct m5mols_info { ...@@ -256,9 +255,11 @@ struct m5mols_info {
* +-------+---+----------+-----+------+------+------+------+ * +-------+---+----------+-----+------+------+------+------+
* - d[0..3]: according to size1 * - 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_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 * Mode operation of the M-5MOLS
...@@ -280,12 +281,12 @@ int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 value); ...@@ -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: * The available executing order between each modes are as follows:
* PARAMETER <---> MONITOR <---> CAPTURE * 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_sync_controls(struct m5mols_info *info);
int m5mols_start_capture(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_lock_3a(struct m5mols_info *info, bool lock);
int m5mols_set_ctrl(struct v4l2_ctrl *ctrl); int m5mols_set_ctrl(struct v4l2_ctrl *ctrl);
......
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
* The Capture code for Fujitsu M-5MOLS ISP * The Capture code for Fujitsu M-5MOLS ISP
* *
* Copyright (C) 2011 Samsung Electronics Co., Ltd. * 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. * 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 * 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 * 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, ...@@ -58,9 +58,9 @@ static int m5mols_read_rational(struct v4l2_subdev *sd, u32 addr_num,
{ {
u32 num, den; u32 num, den;
int ret = m5mols_read(sd, addr_num, &num); int ret = m5mols_read_u32(sd, addr_num, &num);
if (!ret) if (!ret)
ret = m5mols_read(sd, addr_den, &den); ret = m5mols_read_u32(sd, addr_den, &den);
if (ret) if (ret)
return ret; return ret;
*val = den == 0 ? 0 : num / den; *val = den == 0 ? 0 : num / den;
...@@ -99,20 +99,20 @@ static int m5mols_capture_info(struct m5mols_info *info) ...@@ -99,20 +99,20 @@ static int m5mols_capture_info(struct m5mols_info *info)
if (ret) if (ret)
return 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) if (!ret)
ret = m5mols_read(sd, EXIF_INFO_FLASH, (u32 *)&exif->flash); ret = m5mols_read_u16(sd, EXIF_INFO_FLASH, &exif->flash);
if (!ret) if (!ret)
ret = m5mols_read(sd, EXIF_INFO_SDR, (u32 *)&exif->sdr); ret = m5mols_read_u16(sd, EXIF_INFO_SDR, &exif->sdr);
if (!ret) if (!ret)
ret = m5mols_read(sd, EXIF_INFO_QVAL, (u32 *)&exif->qval); ret = m5mols_read_u16(sd, EXIF_INFO_QVAL, &exif->qval);
if (ret) if (ret)
return ret; return ret;
if (!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) 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) if (!ret)
info->cap.total = info->cap.main + info->cap.thumb; info->cap.total = info->cap.main + info->cap.thumb;
...@@ -122,7 +122,7 @@ static int m5mols_capture_info(struct m5mols_info *info) ...@@ -122,7 +122,7 @@ static int m5mols_capture_info(struct m5mols_info *info)
int m5mols_start_capture(struct m5mols_info *info) int m5mols_start_capture(struct m5mols_info *info)
{ {
struct v4l2_subdev *sd = &info->sd; struct v4l2_subdev *sd = &info->sd;
u32 resolution = info->resolution; u8 resolution = info->resolution;
int timeout; int timeout;
int ret; int ret;
......
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
* Controls for M-5MOLS 8M Pixel camera sensor with ISP * Controls for M-5MOLS 8M Pixel camera sensor with ISP
* *
* Copyright (C) 2011 Samsung Electronics Co., Ltd. * 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. * 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 * 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 * it under the terms of the GNU General Public License as published by
...@@ -130,7 +130,7 @@ static struct m5mols_scenemode m5mols_default_scenemode[] = { ...@@ -130,7 +130,7 @@ static struct m5mols_scenemode m5mols_default_scenemode[] = {
* *
* WARNING: The execution order is important. Do not change the order. * 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 v4l2_subdev *sd = &info->sd;
struct m5mols_scenemode scenemode = m5mols_default_scenemode[mode]; struct m5mols_scenemode scenemode = m5mols_default_scenemode[mode];
......
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
* Driver for M-5MOLS 8M Pixel camera sensor with ISP * Driver for M-5MOLS 8M Pixel camera sensor with ISP
* *
* Copyright (C) 2011 Samsung Electronics Co., Ltd. * 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. * 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 * 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 * 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) ...@@ -133,13 +133,13 @@ static u32 m5mols_swap_byte(u8 *data, u8 length)
/** /**
* m5mols_read - I2C read function * m5mols_read - I2C read function
* @reg: combination of size, category and command for the I2C packet * @reg: combination of size, category and command for the I2C packet
* @size: desired size of I2C packet
* @val: read value * @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); struct i2c_client *client = v4l2_get_subdevdata(sd);
u8 rbuf[M5MOLS_I2C_MAX_SIZE + 1]; u8 rbuf[M5MOLS_I2C_MAX_SIZE + 1];
u8 size = I2C_SIZE(reg);
u8 category = I2C_CATEGORY(reg); u8 category = I2C_CATEGORY(reg);
u8 cmd = I2C_COMMAND(reg); u8 cmd = I2C_COMMAND(reg);
struct i2c_msg msg[2]; struct i2c_msg msg[2];
...@@ -149,11 +149,6 @@ int m5mols_read(struct v4l2_subdev *sd, u32 reg, u32 *val) ...@@ -149,11 +149,6 @@ int m5mols_read(struct v4l2_subdev *sd, u32 reg, u32 *val)
if (!client->adapter) if (!client->adapter)
return -ENODEV; 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].addr = client->addr;
msg[0].flags = 0; msg[0].flags = 0;
msg[0].len = 5; msg[0].len = 5;
...@@ -184,6 +179,52 @@ int m5mols_read(struct v4l2_subdev *sd, u32 reg, u32 *val) ...@@ -184,6 +179,52 @@ int m5mols_read(struct v4l2_subdev *sd, u32 reg, u32 *val)
return 0; 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 * m5mols_write - I2C command write function
* @reg: combination of size, category and command for the I2C packet * @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) ...@@ -231,13 +272,14 @@ int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val)
return 0; 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; int ret;
for (i = 0; i < M5MOLS_I2C_CHECK_RETRY; i++) { 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) if (ret < 0)
return ret; return ret;
if ((busy & mask) == mask) if ((busy & mask) == mask)
...@@ -252,14 +294,14 @@ int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 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 * Before writing desired interrupt value the INT_FACTOR register should
* be read to clear pending interrupts. * 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); struct m5mols_info *info = to_m5mols(sd);
u32 mask = is_available_af(info) ? REG_INT_AF : 0; u8 mask = is_available_af(info) ? REG_INT_AF : 0;
u32 dummy; u8 dummy;
int ret; int ret;
ret = m5mols_read(sd, SYSTEM_INT_FACTOR, &dummy); ret = m5mols_read_u8(sd, SYSTEM_INT_FACTOR, &dummy);
if (!ret) if (!ret)
ret = m5mols_write(sd, SYSTEM_INT_ENABLE, reg & ~mask); ret = m5mols_write(sd, SYSTEM_INT_ENABLE, reg & ~mask);
return ret; return ret;
...@@ -271,7 +313,7 @@ int m5mols_enable_interrupt(struct v4l2_subdev *sd, u32 reg) ...@@ -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 * It always accompanies a little delay changing the M-5MOLS mode, so it is
* needed checking current busy status to guarantee right mode. * 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); int ret = m5mols_write(sd, SYSTEM_SYSMODE, mode);
...@@ -286,16 +328,16 @@ static int m5mols_reg_mode(struct v4l2_subdev *sd, u32 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 * can be guaranteed only when the sensor is operating in mode which which
* a command belongs to. * 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; struct v4l2_subdev *sd = &info->sd;
int ret = -EINVAL; int ret = -EINVAL;
u32 reg; u8 reg;
if (mode < REG_PARAMETER && mode > REG_CAPTURE) if (mode < REG_PARAMETER && mode > REG_CAPTURE)
return ret; return ret;
ret = m5mols_read(sd, SYSTEM_SYSMODE, &reg); ret = m5mols_read_u8(sd, SYSTEM_SYSMODE, &reg);
if ((!ret && reg == mode) || ret) if ((!ret && reg == mode) || ret)
return ret; return ret;
...@@ -344,41 +386,37 @@ int m5mols_mode(struct m5mols_info *info, u32 mode) ...@@ -344,41 +386,37 @@ int m5mols_mode(struct m5mols_info *info, u32 mode)
static int m5mols_get_version(struct v4l2_subdev *sd) static int m5mols_get_version(struct v4l2_subdev *sd)
{ {
struct m5mols_info *info = to_m5mols(sd); struct m5mols_info *info = to_m5mols(sd);
union { struct m5mols_version *ver = &info->ver;
struct m5mols_version ver; u8 *str = ver->str;
u8 bytes[VERSION_SIZE]; int i;
} version;
u32 *value;
u8 cmd = CAT0_VER_CUSTOMER;
int ret; int ret;
do { ret = m5mols_read_u8(sd, SYSTEM_VER_CUSTOMER, &ver->customer);
value = (u32 *)&version.bytes[cmd]; if (!ret)
ret = m5mols_read(sd, SYSTEM_CMD(cmd), value); ret = m5mols_read_u8(sd, SYSTEM_VER_PROJECT, &ver->project);
if (ret) if (!ret)
return ret; ret = m5mols_read_u16(sd, SYSTEM_VER_FIRMWARE, &ver->fw);
} while (cmd++ != CAT0_VER_AWB); if (!ret)
ret = m5mols_read_u16(sd, SYSTEM_VER_HARDWARE, &ver->hw);
do { if (!ret)
value = (u32 *)&version.bytes[cmd]; ret = m5mols_read_u16(sd, SYSTEM_VER_PARAMETER, &ver->param);
ret = m5mols_read(sd, SYSTEM_VER_STRING, value); 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) if (ret)
return ret; return ret;
if (cmd >= VERSION_SIZE - 1)
return -EINVAL;
} while (version.bytes[cmd++]);
value = (u32 *)&version.bytes[cmd]; for (i = 0; i < VERSION_STRING_SIZE; i++) {
ret = m5mols_read(sd, AF_VERSION, value); ret = m5mols_read_u8(sd, SYSTEM_VER_STRING, &str[i]);
if (ret) if (ret)
return ret; return ret;
}
/* store version information swapped for being readable */ ver->fw = be16_to_cpu(ver->fw);
info->ver = version.ver; ver->hw = be16_to_cpu(ver->hw);
info->ver.fw = be16_to_cpu(info->ver.fw); ver->param = be16_to_cpu(ver->param);
info->ver.hw = be16_to_cpu(info->ver.hw); ver->awb = be16_to_cpu(ver->awb);
info->ver.param = be16_to_cpu(info->ver.param);
info->ver.awb = be16_to_cpu(info->ver.awb);
v4l2_info(sd, "Manufacturer\t[%s]\n", v4l2_info(sd, "Manufacturer\t[%s]\n",
is_manufacturer(info, REG_SAMSUNG_ELECTRO) ? is_manufacturer(info, REG_SAMSUNG_ELECTRO) ?
...@@ -722,7 +760,7 @@ static int m5mols_init_controls(struct m5mols_info *info) ...@@ -722,7 +760,7 @@ static int m5mols_init_controls(struct m5mols_info *info)
int ret; int ret;
/* Determine value's range & step of controls for various FW version */ /* 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) if (!ret)
step_zoom = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1; step_zoom = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1;
if (ret) if (ret)
...@@ -842,18 +880,18 @@ static void m5mols_irq_work(struct work_struct *work) ...@@ -842,18 +880,18 @@ static void m5mols_irq_work(struct work_struct *work)
struct m5mols_info *info = struct m5mols_info *info =
container_of(work, struct m5mols_info, work_irq); container_of(work, struct m5mols_info, work_irq);
struct v4l2_subdev *sd = &info->sd; struct v4l2_subdev *sd = &info->sd;
u32 reg; u8 reg;
int ret; int ret;
if (!is_powered(info) || if (!is_powered(info) ||
m5mols_read(sd, SYSTEM_INT_FACTOR, &info->interrupt)) m5mols_read_u8(sd, SYSTEM_INT_FACTOR, &info->interrupt))
return; return;
switch (info->interrupt & REG_INT_MASK) { switch (info->interrupt & REG_INT_MASK) {
case REG_INT_AF: case REG_INT_AF:
if (!is_available_af(info)) if (!is_available_af(info))
break; break;
ret = m5mols_read(sd, AF_STATUS, &reg); ret = m5mols_read_u8(sd, AF_STATUS, &reg);
v4l2_dbg(2, m5mols_debug, sd, "AF %s\n", v4l2_dbg(2, m5mols_debug, sd, "AF %s\n",
reg == REG_AF_FAIL ? "Failed" : reg == REG_AF_FAIL ? "Failed" :
reg == REG_AF_SUCCESS ? "Success" : reg == REG_AF_SUCCESS ? "Success" :
......
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
* Register map for M-5MOLS 8M Pixel camera sensor with ISP * Register map for M-5MOLS 8M Pixel camera sensor with ISP
* *
* Copyright (C) 2011 Samsung Electronics Co., Ltd. * 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. * 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 * 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 * it under the terms of the GNU General Public License as published by
...@@ -56,13 +56,24 @@ ...@@ -56,13 +56,24 @@
* more specific contents, see definition if file m5mols.h. * more specific contents, see definition if file m5mols.h.
*/ */
#define CAT0_VER_CUSTOMER 0x00 /* customer version */ #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_VER_STRING 0x0a /* string including M-5MOLS */
#define CAT0_SYSMODE 0x0b /* SYSTEM mode register */ #define CAT0_SYSMODE 0x0b /* SYSTEM mode register */
#define CAT0_STATUS 0x0c /* SYSTEM mode status register */ #define CAT0_STATUS 0x0c /* SYSTEM mode status register */
#define CAT0_INT_FACTOR 0x10 /* interrupt pending register */ #define CAT0_INT_FACTOR 0x10 /* interrupt pending register */
#define CAT0_INT_ENABLE 0x11 /* interrupt enable 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 SYSTEM_SYSMODE I2C_REG(CAT_SYSTEM, CAT0_SYSMODE, 1)
#define REG_SYSINIT 0x00 /* SYSTEM mode */ #define REG_SYSINIT 0x00 /* SYSTEM mode */
#define REG_PARAMETER 0x01 /* PARAMETER mode */ #define REG_PARAMETER 0x01 /* PARAMETER mode */
...@@ -382,8 +393,8 @@ ...@@ -382,8 +393,8 @@
#define REG_CAP_START_MAIN 0x01 #define REG_CAP_START_MAIN 0x01
#define REG_CAP_START_THUMB 0x03 #define REG_CAP_START_THUMB 0x03
#define CAPC_IMAGE_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_IMAGE_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, 1) #define CAPC_THUMB_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_THUMB_SIZE, 4)
/* /*
* Category F - Flash * Category F - Flash
......
...@@ -444,12 +444,9 @@ static int mx1_camera_add_device(struct soc_camera_device *icd) ...@@ -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 soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct mx1_camera_dev *pcdev = ici->priv; struct mx1_camera_dev *pcdev = ici->priv;
int ret;
if (pcdev->icd) { if (pcdev->icd)
ret = -EBUSY; return -EBUSY;
goto ebusy;
}
dev_info(icd->dev.parent, "MX1 Camera driver attached to camera %d\n", dev_info(icd->dev.parent, "MX1 Camera driver attached to camera %d\n",
icd->devnum); icd->devnum);
...@@ -458,8 +455,7 @@ static int mx1_camera_add_device(struct soc_camera_device *icd) ...@@ -458,8 +455,7 @@ static int mx1_camera_add_device(struct soc_camera_device *icd)
pcdev->icd = icd; pcdev->icd = icd;
ebusy: return 0;
return ret;
} }
static void mx1_camera_remove_device(struct soc_camera_device *icd) static void mx1_camera_remove_device(struct soc_camera_device *icd)
......
...@@ -982,6 +982,14 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count, ...@@ -982,6 +982,14 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
startindex = (vout->vid == OMAP_VIDEO1) ? startindex = (vout->vid == OMAP_VIDEO1) ?
video1_numbuffers : video2_numbuffers; 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++) { for (i = startindex; i < *count; i++) {
vout->buffer_size = *size; vout->buffer_size = *size;
...@@ -1228,6 +1236,14 @@ static int omap_vout_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -1228,6 +1236,14 @@ static int omap_vout_mmap(struct file *file, struct vm_area_struct *vma)
(vma->vm_pgoff << PAGE_SHIFT)); (vma->vm_pgoff << PAGE_SHIFT));
return -EINVAL; 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; q->bufs[i]->baddr = vma->vm_start;
vma->vm_flags |= VM_RESERVED; vma->vm_flags |= VM_RESERVED;
...@@ -2391,7 +2407,7 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev) ...@@ -2391,7 +2407,7 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev)
/* Register the Video device with V4L2 /* Register the Video device with V4L2
*/ */
vfd = vout->vfd; 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 " dev_err(&pdev->dev, ": Could not register "
"Video for Linux device\n"); "Video for Linux device\n");
vfd->minor = -1; vfd->minor = -1;
......
...@@ -193,7 +193,7 @@ int omap_vout_new_crop(struct v4l2_pix_format *pix, ...@@ -193,7 +193,7 @@ int omap_vout_new_crop(struct v4l2_pix_format *pix,
return -EINVAL; return -EINVAL;
if (cpu_is_omap24xx()) { 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 /* If we're resizing vertically, we can't support a
* crop width wider than 768 pixels. * crop width wider than 768 pixels.
*/ */
...@@ -202,7 +202,7 @@ int omap_vout_new_crop(struct v4l2_pix_format *pix, ...@@ -202,7 +202,7 @@ int omap_vout_new_crop(struct v4l2_pix_format *pix,
} }
} }
/* vertical resizing */ /* vertical resizing */
vresize = (1024 * crop->height) / win->w.height; vresize = (1024 * try_crop.height) / win->w.height;
if (cpu_is_omap24xx() && (vresize > 2048)) if (cpu_is_omap24xx() && (vresize > 2048))
vresize = 2048; vresize = 2048;
else if (cpu_is_omap34xx() && (vresize > 4096)) else if (cpu_is_omap34xx() && (vresize > 4096))
...@@ -221,7 +221,7 @@ int omap_vout_new_crop(struct v4l2_pix_format *pix, ...@@ -221,7 +221,7 @@ int omap_vout_new_crop(struct v4l2_pix_format *pix,
try_crop.height = 2; try_crop.height = 2;
} }
/* horizontal resizing */ /* horizontal resizing */
hresize = (1024 * crop->width) / win->w.width; hresize = (1024 * try_crop.width) / win->w.width;
if (cpu_is_omap24xx() && (hresize > 2048)) if (cpu_is_omap24xx() && (hresize > 2048))
hresize = 2048; hresize = 2048;
else if (cpu_is_omap34xx() && (hresize > 4096)) else if (cpu_is_omap34xx() && (hresize > 4096))
......
...@@ -1748,7 +1748,7 @@ static int isp_register_entities(struct isp_device *isp) ...@@ -1748,7 +1748,7 @@ static int isp_register_entities(struct isp_device *isp)
goto done; goto done;
/* Register external entities */ /* Register external entities */
for (subdevs = pdata->subdevs; subdevs->subdevs; ++subdevs) { for (subdevs = pdata->subdevs; subdevs && subdevs->subdevs; ++subdevs) {
struct v4l2_subdev *sensor; struct v4l2_subdev *sensor;
struct media_entity *input; struct media_entity *input;
unsigned int flags; unsigned int flags;
......
...@@ -1414,7 +1414,7 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) ...@@ -1414,7 +1414,7 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
{ {
ARG_DEF(struct pwc_probe, probe) 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; ARGR(probe).type = pdev->type;
ARG_OUT(probe) ARG_OUT(probe)
break; break;
......
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
Oh yes, convention: to disctinguish between all the various pointers to Oh yes, convention: to disctinguish between all the various pointers to
device-structures, I use these names for the pointer variables: device-structures, I use these names for the pointer variables:
udev: struct usb_device * udev: struct usb_device *
vdev: struct video_device * vdev: struct video_device (member of pwc_dev)
pdev: struct pwc_devive * pdev: struct pwc_devive *
*/ */
...@@ -152,6 +152,7 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf, ...@@ -152,6 +152,7 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos); size_t count, loff_t *ppos);
static unsigned int pwc_video_poll(struct file *file, poll_table *wait); 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 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 = { static const struct v4l2_file_operations pwc_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
...@@ -164,41 +165,11 @@ static const struct v4l2_file_operations pwc_fops = { ...@@ -164,41 +165,11 @@ static const struct v4l2_file_operations pwc_fops = {
}; };
static struct video_device pwc_template = { static struct video_device pwc_template = {
.name = "Philips Webcam", /* Filled in later */ .name = "Philips Webcam", /* Filled in later */
.release = video_device_release, .release = pwc_video_release,
.fops = &pwc_fops, .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 */ /* Private functions */
...@@ -1016,16 +987,15 @@ static ssize_t show_snapshot_button_status(struct device *class_dev, ...@@ -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, static DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status,
NULL); 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; int rc;
rc = device_create_file(&vdev->dev, &dev_attr_button); rc = device_create_file(&pdev->vdev.dev, &dev_attr_button);
if (rc) if (rc)
goto err; goto err;
if (pdev->features & FEATURE_MOTOR_PANTILT) { 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) if (rc)
goto err_button; goto err_button;
} }
...@@ -1033,19 +1003,17 @@ static int pwc_create_sysfs_files(struct video_device *vdev) ...@@ -1033,19 +1003,17 @@ static int pwc_create_sysfs_files(struct video_device *vdev)
return 0; return 0;
err_button: err_button:
device_remove_file(&vdev->dev, &dev_attr_button); device_remove_file(&pdev->vdev.dev, &dev_attr_button);
err: err:
PWC_ERROR("Could not create sysfs files.\n"); PWC_ERROR("Could not create sysfs files.\n");
return rc; 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) if (pdev->features & FEATURE_MOTOR_PANTILT)
device_remove_file(&vdev->dev, &dev_attr_pan_tilt); device_remove_file(&pdev->vdev.dev, &dev_attr_pan_tilt);
device_remove_file(&vdev->dev, &dev_attr_button); device_remove_file(&pdev->vdev.dev, &dev_attr_button);
} }
#ifdef CONFIG_USB_PWC_DEBUG #ifdef CONFIG_USB_PWC_DEBUG
...@@ -1106,7 +1074,7 @@ static int pwc_video_open(struct file *file) ...@@ -1106,7 +1074,7 @@ static int pwc_video_open(struct file *file)
if (ret >= 0) if (ret >= 0)
{ {
PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n", 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); pwc_sensor_type_to_string(i), i);
} }
} }
...@@ -1180,16 +1148,15 @@ static int pwc_video_open(struct file *file) ...@@ -1180,16 +1148,15 @@ static int pwc_video_open(struct file *file)
return 0; return 0;
} }
static void pwc_video_release(struct video_device *vfd)
static void pwc_cleanup(struct pwc_device *pdev)
{ {
pwc_remove_sysfs_files(pdev->vdev); struct pwc_device *pdev = container_of(vfd, struct pwc_device, vdev);
video_unregister_device(pdev->vdev); int hint;
#ifdef CONFIG_USB_PWC_INPUT_EVDEV /* search device_hint[] table if we occupy a slot, by any chance */
if (pdev->button_dev) for (hint = 0; hint < MAX_DEV_HINTS; hint++)
input_unregister_device(pdev->button_dev); if (device_hint[hint].pdev == pdev)
#endif device_hint[hint].pdev = NULL;
kfree(pdev); kfree(pdev);
} }
...@@ -1199,7 +1166,7 @@ static int pwc_video_close(struct file *file) ...@@ -1199,7 +1166,7 @@ static int pwc_video_close(struct file *file)
{ {
struct video_device *vdev = file->private_data; struct video_device *vdev = file->private_data;
struct pwc_device *pdev; struct pwc_device *pdev;
int i, hint; int i;
PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev); PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);
...@@ -1234,12 +1201,6 @@ static int pwc_video_close(struct file *file) ...@@ -1234,12 +1201,6 @@ static int pwc_video_close(struct file *file)
} }
pdev->vopen--; pdev->vopen--;
PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", 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; return 0;
...@@ -1715,19 +1676,12 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -1715,19 +1676,12 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
init_waitqueue_head(&pdev->frameq); init_waitqueue_head(&pdev->frameq);
pdev->vcompression = pwc_preferred_compression; pdev->vcompression = pwc_preferred_compression;
/* Allocate video_device structure */ /* Init video_device structure */
pdev->vdev = video_device_alloc(); memcpy(&pdev->vdev, &pwc_template, sizeof(pwc_template));
if (!pdev->vdev) { pdev->vdev.parent = &intf->dev;
PWC_ERROR("Err, cannot allocate video_device struture. Failing probe."); pdev->vdev.lock = &pdev->modlock;
rc = -ENOMEM; strcpy(pdev->vdev.name, name);
goto err_free_mem; video_set_drvdata(&pdev->vdev, pdev);
}
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);
pdev->release = le16_to_cpu(udev->descriptor.bcdDevice); pdev->release = le16_to_cpu(udev->descriptor.bcdDevice);
PWC_DEBUG_PROBE("Release: %04x\n", pdev->release); 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 ...@@ -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 */ /* occupy slot */
if (hint < MAX_DEV_HINTS) if (hint < MAX_DEV_HINTS)
device_hint[hint].pdev = pdev; device_hint[hint].pdev = pdev;
...@@ -1759,16 +1711,16 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -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_set_leds(pdev, 0, 0);
pwc_camera_power(pdev, 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) { if (rc < 0) {
PWC_ERROR("Failed to register as video device (%d).\n", rc); 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) if (rc)
goto err_video_unreg; 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 #ifdef CONFIG_USB_PWC_INPUT_EVDEV
/* register webcam snapshot button input device */ /* register webcam snapshot button input device */
...@@ -1776,7 +1728,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -1776,7 +1728,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
if (!pdev->button_dev) { if (!pdev->button_dev) {
PWC_ERROR("Err, insufficient memory for webcam snapshot button device."); PWC_ERROR("Err, insufficient memory for webcam snapshot button device.");
rc = -ENOMEM; rc = -ENOMEM;
pwc_remove_sysfs_files(pdev->vdev); pwc_remove_sysfs_files(pdev);
goto err_video_unreg; goto err_video_unreg;
} }
...@@ -1794,7 +1746,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -1794,7 +1746,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
if (rc) { if (rc) {
input_free_device(pdev->button_dev); input_free_device(pdev->button_dev);
pdev->button_dev = NULL; pdev->button_dev = NULL;
pwc_remove_sysfs_files(pdev->vdev); pwc_remove_sysfs_files(pdev);
goto err_video_unreg; goto err_video_unreg;
} }
#endif #endif
...@@ -1804,10 +1756,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -1804,10 +1756,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
err_video_unreg: err_video_unreg:
if (hint < MAX_DEV_HINTS) if (hint < MAX_DEV_HINTS)
device_hint[hint].pdev = NULL; device_hint[hint].pdev = NULL;
video_unregister_device(pdev->vdev); 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);
err_free_mem: err_free_mem:
kfree(pdev); kfree(pdev);
return rc; return rc;
...@@ -1816,10 +1765,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -1816,10 +1765,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
/* The user yanked out the cable... */ /* The user yanked out the cable... */
static void usb_pwc_disconnect(struct usb_interface *intf) static void usb_pwc_disconnect(struct usb_interface *intf)
{ {
struct pwc_device *pdev; struct pwc_device *pdev = usb_get_intfdata(intf);
int hint;
pdev = usb_get_intfdata (intf);
mutex_lock(&pdev->modlock); mutex_lock(&pdev->modlock);
usb_set_intfdata (intf, NULL); usb_set_intfdata (intf, NULL);
if (pdev == NULL) { if (pdev == NULL) {
...@@ -1836,30 +1783,25 @@ static void usb_pwc_disconnect(struct usb_interface *intf) ...@@ -1836,30 +1783,25 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
} }
/* We got unplugged; this is signalled by an EPIPE error code */ /* 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 */ /* Alert waiting processes */
wake_up_interruptible(&pdev->frameq); 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: /* No need to keep the urbs around after disconnection */
/* search device_hint[] table if we occupy a slot, by any chance */ pwc_isoc_cleanup(pdev);
for (hint = 0; hint < MAX_DEV_HINTS; hint++)
if (device_hint[hint].pdev == pdev)
device_hint[hint].pdev = NULL;
}
disconnect_out:
mutex_unlock(&pdev->modlock); 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
} }
......
...@@ -162,9 +162,9 @@ struct pwc_imgbuf ...@@ -162,9 +162,9 @@ struct pwc_imgbuf
struct pwc_device 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; struct usb_device *udev;
int type; /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */ int type; /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */
......
/* /*
* 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> * Author: Sylwester Nawrocki, <s.nawrocki@samsung.com>
* *
* This program is free software; you can redistribute it and/or modify * 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) ...@@ -262,12 +262,7 @@ static unsigned int get_plane_size(struct fimc_frame *fr, unsigned int plane)
{ {
if (!fr || plane >= fr->fmt->memplanes) if (!fr || plane >= fr->fmt->memplanes)
return 0; 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; return fr->f_width * fr->f_height * fr->fmt->depth[plane] / 8;
} }
static int queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, 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, ...@@ -283,24 +278,14 @@ static int queue_setup(struct vb2_queue *vq, unsigned int *num_buffers,
*num_planes = fmt->memplanes; *num_planes = fmt->memplanes;
dbg("%s, buffer count=%d, plane count=%d",
__func__, *num_buffers, *num_planes);
for (i = 0; i < fmt->memplanes; i++) { for (i = 0; i < fmt->memplanes; i++) {
sizes[i] = get_plane_size(&ctx->d_frame, 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; allocators[i] = ctx->fimc_dev->alloc_ctx;
} }
return 0; return 0;
} }
static int buffer_init(struct vb2_buffer *vb)
{
/* TODO: */
return 0;
}
static int buffer_prepare(struct vb2_buffer *vb) static int buffer_prepare(struct vb2_buffer *vb)
{ {
struct vb2_queue *vq = vb->vb2_queue; struct vb2_queue *vq = vb->vb2_queue;
...@@ -380,7 +365,6 @@ static struct vb2_ops fimc_capture_qops = { ...@@ -380,7 +365,6 @@ static struct vb2_ops fimc_capture_qops = {
.queue_setup = queue_setup, .queue_setup = queue_setup,
.buf_prepare = buffer_prepare, .buf_prepare = buffer_prepare,
.buf_queue = buffer_queue, .buf_queue = buffer_queue,
.buf_init = buffer_init,
.wait_prepare = fimc_unlock, .wait_prepare = fimc_unlock,
.wait_finish = fimc_lock, .wait_finish = fimc_lock,
.start_streaming = start_streaming, .start_streaming = start_streaming,
...@@ -903,6 +887,7 @@ int fimc_register_capture_device(struct fimc_dev *fimc) ...@@ -903,6 +887,7 @@ int fimc_register_capture_device(struct fimc_dev *fimc)
err_v4l2_reg: err_v4l2_reg:
v4l2_device_unregister(v4l2_dev); v4l2_device_unregister(v4l2_dev);
err_info: err_info:
kfree(ctx);
dev_err(&fimc->pdev->dev, "failed to install\n"); dev_err(&fimc->pdev->dev, "failed to install\n");
return ret; return ret;
} }
......
/* /*
* S5P camera interface (video postprocessor) driver * Samsung S5P/EXYNOS4 SoC series camera interface (video postprocessor) driver
* *
* Copyright (c) 2010 Samsung Electronics Co., Ltd * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd.
* * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.com>
* Sylwester Nawrocki, <s.nawrocki@samsung.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published * it under the terms of the GNU General Public License as published
...@@ -42,7 +41,6 @@ static struct fimc_fmt fimc_formats[] = { ...@@ -42,7 +41,6 @@ static struct fimc_fmt fimc_formats[] = {
.color = S5P_FIMC_RGB565, .color = S5P_FIMC_RGB565,
.memplanes = 1, .memplanes = 1,
.colplanes = 1, .colplanes = 1,
.mbus_code = V4L2_MBUS_FMT_RGB565_2X8_BE,
.flags = FMT_FLAGS_M2M, .flags = FMT_FLAGS_M2M,
}, { }, {
.name = "BGR666", .name = "BGR666",
...@@ -232,11 +230,7 @@ static int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift) ...@@ -232,11 +230,7 @@ static int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift)
return 0; return 0;
} }
} }
*shift = 0, *ratio = 1; *shift = 0, *ratio = 1;
dbg("s: %d, t: %d, shift: %d, ratio: %d",
src, tar, *shift, *ratio);
return 0; return 0;
} }
...@@ -268,10 +262,8 @@ int fimc_set_scaler_info(struct fimc_ctx *ctx) ...@@ -268,10 +262,8 @@ int fimc_set_scaler_info(struct fimc_ctx *ctx)
err("invalid source size: %d x %d", sx, sy); err("invalid source size: %d x %d", sx, sy);
return -EINVAL; return -EINVAL;
} }
sc->real_width = sx; sc->real_width = sx;
sc->real_height = sy; 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); ret = fimc_get_scaler_factor(sx, tx, &sc->pre_hratio, &sc->hfactor);
if (ret) if (ret)
...@@ -711,22 +703,18 @@ static int fimc_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, ...@@ -711,22 +703,18 @@ static int fimc_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers,
f = ctx_get_frame(ctx, vq->type); f = ctx_get_frame(ctx, vq->type);
if (IS_ERR(f)) if (IS_ERR(f))
return PTR_ERR(f); return PTR_ERR(f);
/* /*
* Return number of non-contigous planes (plane buffers) * Return number of non-contigous planes (plane buffers)
* depending on the configured color format. * depending on the configured color format.
*/ */
if (f->fmt) if (!f->fmt)
*num_planes = f->fmt->memplanes; return -EINVAL;
*num_planes = f->fmt->memplanes;
for (i = 0; i < f->fmt->memplanes; i++) { 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; allocators[i] = ctx->fimc_dev->alloc_ctx;
} }
if (*num_buffers == 0)
*num_buffers = 1;
return 0; return 0;
} }
...@@ -852,7 +840,7 @@ struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask) ...@@ -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) { for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) {
fmt = &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)) (fmt->flags & mask))
break; break;
} }
......
/* /*
* Copyright (c) 2010 Samsung Electronics * Copyright (C) 2010 - 2011 Samsung Electronics Co., Ltd.
*
* Sylwester Nawrocki, <s.nawrocki@samsung.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
...@@ -135,9 +133,10 @@ enum fimc_color_fmt { ...@@ -135,9 +133,10 @@ enum fimc_color_fmt {
* @name: format description * @name: format description
* @fourcc: the fourcc code for this format, 0 if not applicable * @fourcc: the fourcc code for this format, 0 if not applicable
* @color: the corresponding fimc_color_fmt * @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 * @memplanes: number of physically non-contiguous data planes
* @colplanes: number of physically 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 { struct fimc_fmt {
enum v4l2_mbus_pixelcode mbus_code; enum v4l2_mbus_pixelcode mbus_code;
...@@ -171,7 +170,7 @@ struct fimc_dma_offset { ...@@ -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 * @type: effect type
* @pat_cb: cr value when type is "arbitrary" * @pat_cb: cr value when type is "arbitrary"
* @pat_cr: cr value when type is "arbitrary" * @pat_cr: cr value when type is "arbitrary"
...@@ -184,7 +183,6 @@ struct fimc_effect { ...@@ -184,7 +183,6 @@ struct fimc_effect {
/** /**
* struct fimc_scaler - the configuration data for FIMC inetrnal scaler * struct fimc_scaler - the configuration data for FIMC inetrnal scaler
*
* @scaleup_h: flag indicating scaling up horizontally * @scaleup_h: flag indicating scaling up horizontally
* @scaleup_v: flag indicating scaling up vertically * @scaleup_v: flag indicating scaling up vertically
* @copy_mode: flag indicating transparent DMA transfer (no scaling * @copy_mode: flag indicating transparent DMA transfer (no scaling
...@@ -220,7 +218,6 @@ struct fimc_scaler { ...@@ -220,7 +218,6 @@ struct fimc_scaler {
/** /**
* struct fimc_addr - the FIMC physical address set for DMA * struct fimc_addr - the FIMC physical address set for DMA
*
* @y: luminance plane physical address * @y: luminance plane physical address
* @cb: Cb plane physical address * @cb: Cb plane physical address
* @cr: Cr plane physical address * @cr: Cr plane physical address
...@@ -234,6 +231,7 @@ struct fimc_addr { ...@@ -234,6 +231,7 @@ struct fimc_addr {
/** /**
* struct fimc_vid_buffer - the driver's video buffer * struct fimc_vid_buffer - the driver's video buffer
* @vb: v4l videobuf buffer * @vb: v4l videobuf buffer
* @list: linked list structure for buffer queue
* @paddr: precalculated physical address set * @paddr: precalculated physical address set
* @index: buffer index for the output DMA engine * @index: buffer index for the output DMA engine
*/ */
...@@ -254,11 +252,10 @@ struct fimc_vid_buffer { ...@@ -254,11 +252,10 @@ struct fimc_vid_buffer {
* @offs_v: image vertical pixel offset * @offs_v: image vertical pixel offset
* @width: image pixel width * @width: image pixel width
* @height: image pixel weight * @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) * @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 * @dma_offset: DMA offset in bytes
* @fmt: fimc color format pointer
*/ */
struct fimc_frame { struct fimc_frame {
u32 f_width; u32 f_width;
...@@ -390,21 +387,22 @@ struct fimc_ctx; ...@@ -390,21 +387,22 @@ struct fimc_ctx;
/** /**
* struct fimc_dev - abstraction for FIMC entity * struct fimc_dev - abstraction for FIMC entity
*
* @slock: the spinlock protecting this data structure * @slock: the spinlock protecting this data structure
* @lock: the mutex protecting this data structure * @lock: the mutex protecting this data structure
* @pdev: pointer to the FIMC platform device * @pdev: pointer to the FIMC platform device
* @pdata: pointer to the device platform data * @pdata: pointer to the device platform data
* @variant: the IP variant information
* @id: FIMC device index (0..FIMC_MAX_DEVS) * @id: FIMC device index (0..FIMC_MAX_DEVS)
* @num_clocks: the number of clocks managed by this device instance * @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: the mapped hardware registers
* @regs_res: the resource claimed for IO registers * @regs_res: the resource claimed for IO registers
* @irq: interrupt number of the FIMC subdevice * @irq: FIMC interrupt number
* @irq_queue: * @irq_queue: interrupt handler waitqueue
* @m2m: memory-to-memory V4L2 device information * @m2m: memory-to-memory V4L2 device information
* @vid_cap: camera capture device information * @vid_cap: camera capture device information
* @state: flags used to synchronize m2m and capture mode operation * @state: flags used to synchronize m2m and capture mode operation
* @alloc_ctx: videobuf2 memory allocator context
*/ */
struct fimc_dev { struct fimc_dev {
spinlock_t slock; spinlock_t slock;
...@@ -427,8 +425,7 @@ struct fimc_dev { ...@@ -427,8 +425,7 @@ struct fimc_dev {
/** /**
* fimc_ctx - the device context data * fimc_ctx - the device context data
* * @slock: spinlock protecting this data structure
* @lock: mutex protecting this data structure
* @s_frame: source frame properties * @s_frame: source frame properties
* @d_frame: destination frame properties * @d_frame: destination frame properties
* @out_order_1p: output 1-plane YCBCR order * @out_order_1p: output 1-plane YCBCR order
......
...@@ -963,7 +963,7 @@ static int saa7134_raw_decode_irq(struct saa7134_dev *dev) ...@@ -963,7 +963,7 @@ static int saa7134_raw_decode_irq(struct saa7134_dev *dev)
* to work with other protocols. * to work with other protocols.
*/ */
if (!ir->active) { if (!ir->active) {
timeout = jiffies + jiffies_to_msecs(15); timeout = jiffies + msecs_to_jiffies(15);
mod_timer(&ir->timer, timeout); mod_timer(&ir->timer, timeout);
ir->active = true; ir->active = true;
} }
......
...@@ -27,14 +27,20 @@ static int uvc_mc_register_entity(struct uvc_video_chain *chain, ...@@ -27,14 +27,20 @@ static int uvc_mc_register_entity(struct uvc_video_chain *chain,
struct uvc_entity *entity) struct uvc_entity *entity)
{ {
const u32 flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE; const u32 flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE;
struct uvc_entity *remote; struct media_entity *sink;
unsigned int i; unsigned int i;
u8 remote_pad; int ret;
int ret = 0;
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) { for (i = 0; i < entity->num_pads; ++i) {
struct media_entity *source; struct media_entity *source;
struct media_entity *sink; struct uvc_entity *remote;
u8 remote_pad;
if (!(entity->pads[i].flags & MEDIA_PAD_FL_SINK)) if (!(entity->pads[i].flags & MEDIA_PAD_FL_SINK))
continue; continue;
...@@ -43,10 +49,11 @@ static int uvc_mc_register_entity(struct uvc_video_chain *chain, ...@@ -43,10 +49,11 @@ static int uvc_mc_register_entity(struct uvc_video_chain *chain,
if (remote == NULL) if (remote == NULL)
return -EINVAL; return -EINVAL;
source = (UVC_ENTITY_TYPE(remote) == UVC_TT_STREAMING) source = (UVC_ENTITY_TYPE(remote) != UVC_TT_STREAMING)
? &remote->vdev->entity : &remote->subdev.entity; ? (remote->vdev ? &remote->vdev->entity : NULL)
sink = (UVC_ENTITY_TYPE(entity) == UVC_TT_STREAMING) : &remote->subdev.entity;
? &entity->vdev->entity : &entity->subdev.entity; if (source == NULL)
continue;
remote_pad = remote->num_pads - 1; remote_pad = remote->num_pads - 1;
ret = media_entity_create_link(source, remote_pad, ret = media_entity_create_link(source, remote_pad,
...@@ -55,11 +62,10 @@ static int uvc_mc_register_entity(struct uvc_video_chain *chain, ...@@ -55,11 +62,10 @@ static int uvc_mc_register_entity(struct uvc_video_chain *chain,
return ret; return ret;
} }
if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING) if (UVC_ENTITY_TYPE(entity) == UVC_TT_STREAMING)
ret = v4l2_device_register_subdev(&chain->dev->vdev, return 0;
&entity->subdev);
return ret; return v4l2_device_register_subdev(&chain->dev->vdev, &entity->subdev);
} }
static struct v4l2_subdev_ops uvc_subdev_ops = { static struct v4l2_subdev_ops uvc_subdev_ops = {
...@@ -84,9 +90,11 @@ static int uvc_mc_init_entity(struct uvc_entity *entity) ...@@ -84,9 +90,11 @@ static int uvc_mc_init_entity(struct uvc_entity *entity)
ret = media_entity_init(&entity->subdev.entity, ret = media_entity_init(&entity->subdev.entity,
entity->num_pads, entity->pads, 0); entity->num_pads, entity->pads, 0);
} else } else if (entity->vdev != NULL) {
ret = media_entity_init(&entity->vdev->entity, ret = media_entity_init(&entity->vdev->entity,
entity->num_pads, entity->pads, 0); entity->num_pads, entity->pads, 0);
} else
ret = 0;
return ret; return ret;
} }
......
...@@ -104,6 +104,8 @@ static int __uvc_free_buffers(struct uvc_video_queue *queue) ...@@ -104,6 +104,8 @@ static int __uvc_free_buffers(struct uvc_video_queue *queue)
} }
if (queue->count) { if (queue->count) {
uvc_queue_cancel(queue, 0);
INIT_LIST_HEAD(&queue->mainqueue);
vfree(queue->mem); vfree(queue->mem);
queue->count = 0; queue->count = 0;
} }
......
...@@ -1255,8 +1255,10 @@ int uvc_video_enable(struct uvc_streaming *stream, int enable) ...@@ -1255,8 +1255,10 @@ int uvc_video_enable(struct uvc_streaming *stream, int enable)
/* Commit the streaming parameters. */ /* Commit the streaming parameters. */
ret = uvc_commit_video(stream, &stream->ctrl); ret = uvc_commit_video(stream, &stream->ctrl);
if (ret < 0) if (ret < 0) {
uvc_queue_enable(&stream->queue, 0);
return ret; return ret;
}
return uvc_init_video(stream, GFP_KERNEL); return uvc_init_video(stream, GFP_KERNEL);
} }
......
...@@ -167,6 +167,12 @@ static void v4l2_device_release(struct device *cd) ...@@ -167,6 +167,12 @@ static void v4l2_device_release(struct device *cd)
mutex_unlock(&videodev_lock); 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 /* Release video_device and perform other
cleanups as needed. */ cleanups as needed. */
vdev->release(vdev); vdev->release(vdev);
...@@ -389,9 +395,6 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm) ...@@ -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) static int v4l2_open(struct inode *inode, struct file *filp)
{ {
struct video_device *vdev; struct video_device *vdev;
#if defined(CONFIG_MEDIA_CONTROLLER)
struct media_entity *entity = NULL;
#endif
int ret = 0; int ret = 0;
/* Check if the video device is available */ /* Check if the video device is available */
...@@ -405,17 +408,6 @@ static int v4l2_open(struct inode *inode, struct file *filp) ...@@ -405,17 +408,6 @@ static int v4l2_open(struct inode *inode, struct file *filp)
/* and increase the device refcount */ /* and increase the device refcount */
video_get(vdev); video_get(vdev);
mutex_unlock(&videodev_lock); 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->fops->open) {
if (vdev->lock && mutex_lock_interruptible(vdev->lock)) { if (vdev->lock && mutex_lock_interruptible(vdev->lock)) {
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
...@@ -431,14 +423,8 @@ static int v4l2_open(struct inode *inode, struct file *filp) ...@@ -431,14 +423,8 @@ static int v4l2_open(struct inode *inode, struct file *filp)
err: err:
/* decrease the refcount in case of an error */ /* decrease the refcount in case of an error */
if (ret) { 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
video_put(vdev); video_put(vdev);
}
return ret; return ret;
} }
...@@ -455,11 +441,6 @@ static int v4l2_release(struct inode *inode, struct file *filp) ...@@ -455,11 +441,6 @@ static int v4l2_release(struct inode *inode, struct file *filp)
if (vdev->lock) if (vdev->lock)
mutex_unlock(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() /* decrease the refcount unconditionally since the release()
return value is ignored. */ return value is ignored. */
video_put(vdev); video_put(vdev);
...@@ -754,12 +735,6 @@ void video_unregister_device(struct video_device *vdev) ...@@ -754,12 +735,6 @@ void video_unregister_device(struct video_device *vdev)
if (!vdev || !video_is_registered(vdev)) if (!vdev || !video_is_registered(vdev))
return; 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); mutex_lock(&videodev_lock);
/* This must be in a critical section to prevent a race with v4l2_open. /* 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. * Once this bit has been cleared video_get may never be called again.
......
...@@ -492,13 +492,6 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) ...@@ -492,13 +492,6 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
return -EINVAL; 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) { if (req->count == 0 || q->num_buffers != 0 || q->memory != req->memory) {
/* /*
* We already have buffers allocated, so first check if they * 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) ...@@ -539,9 +532,9 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
/* Finally, allocate buffers and video memory */ /* Finally, allocate buffers and video memory */
ret = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes, ret = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes,
plane_sizes); plane_sizes);
if (ret < 0) { if (ret == 0) {
dprintk(1, "Memory allocation failed with error: %d\n", ret); dprintk(1, "Memory allocation failed\n");
return ret; return -ENOMEM;
} }
/* /*
...@@ -1196,6 +1189,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q) ...@@ -1196,6 +1189,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
* has not already dequeued before initiating cancel. * has not already dequeued before initiating cancel.
*/ */
INIT_LIST_HEAD(&q->done_list); INIT_LIST_HEAD(&q->done_list);
atomic_set(&q->queued_count, 0);
wake_up_all(&q->done_wq); wake_up_all(&q->done_wq);
/* /*
......
...@@ -62,7 +62,7 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size) ...@@ -62,7 +62,7 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size)
goto fail_pages_array_alloc; goto fail_pages_array_alloc;
for (i = 0; i < buf->sg_desc.num_pages; ++i) { 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]) if (NULL == buf->pages[i])
goto fail_pages_alloc; goto fail_pages_alloc;
sg_set_page(&buf->sg_desc.sglist[i], sg_set_page(&buf->sg_desc.sglist[i],
......
...@@ -672,8 +672,6 @@ static void imon_incoming_packet(struct imon_context *context, ...@@ -672,8 +672,6 @@ static void imon_incoming_packet(struct imon_context *context,
static void usb_rx_callback(struct urb *urb) static void usb_rx_callback(struct urb *urb)
{ {
struct imon_context *context; struct imon_context *context;
unsigned char *buf;
int len;
int intfnum = 0; int intfnum = 0;
if (!urb) if (!urb)
...@@ -683,9 +681,6 @@ static void usb_rx_callback(struct urb *urb) ...@@ -683,9 +681,6 @@ static void usb_rx_callback(struct urb *urb)
if (!context) if (!context)
return; return;
buf = urb->transfer_buffer;
len = urb->actual_length;
switch (urb->status) { switch (urb->status) {
case -ENOENT: /* usbcore unlink successful! */ case -ENOENT: /* usbcore unlink successful! */
return; return;
...@@ -728,7 +723,6 @@ static int imon_probe(struct usb_interface *interface, ...@@ -728,7 +723,6 @@ static int imon_probe(struct usb_interface *interface,
int ir_ep_found = 0; int ir_ep_found = 0;
int alloc_status = 0; int alloc_status = 0;
int vfd_proto_6p = 0; int vfd_proto_6p = 0;
int code_length;
struct imon_context *context = NULL; struct imon_context *context = NULL;
int i; int i;
u16 vendor, product; u16 vendor, product;
...@@ -749,8 +743,6 @@ static int imon_probe(struct usb_interface *interface, ...@@ -749,8 +743,6 @@ static int imon_probe(struct usb_interface *interface,
else else
context->display = 1; context->display = 1;
code_length = BUF_CHUNK_SIZE * 8;
usbdev = usb_get_dev(interface_to_usbdev(interface)); usbdev = usb_get_dev(interface_to_usbdev(interface));
iface_desc = interface->cur_altsetting; iface_desc = interface->cur_altsetting;
num_endpts = iface_desc->desc.bNumEndpoints; num_endpts = iface_desc->desc.bNumEndpoints;
...@@ -856,7 +848,7 @@ static int imon_probe(struct usb_interface *interface, ...@@ -856,7 +848,7 @@ static int imon_probe(struct usb_interface *interface,
strcpy(driver->name, MOD_NAME); strcpy(driver->name, MOD_NAME);
driver->minor = -1; driver->minor = -1;
driver->code_length = sizeof(int) * 8; driver->code_length = BUF_CHUNK_SIZE * 8;
driver->sample_rate = 0; driver->sample_rate = 0;
driver->features = LIRC_CAN_REC_MODE2; driver->features = LIRC_CAN_REC_MODE2;
driver->data = context; driver->data = context;
......
...@@ -838,7 +838,23 @@ static int hardware_init_port(void) ...@@ -838,7 +838,23 @@ static int hardware_init_port(void)
static int init_port(void) static int init_port(void)
{ {
int i, nlow, nhigh; int i, nlow, nhigh, result;
result = request_irq(irq, irq_handler,
IRQF_DISABLED | (share_irq ? IRQF_SHARED : 0),
LIRC_DRIVER_NAME, (void *)&hardware);
switch (result) {
case -EBUSY:
printk(KERN_ERR LIRC_DRIVER_NAME ": IRQ %d busy\n", irq);
return -EBUSY;
case -EINVAL:
printk(KERN_ERR LIRC_DRIVER_NAME
": Bad irq number or handler\n");
return -EINVAL;
default:
break;
};
/* Reserve io region. */ /* Reserve io region. */
/* /*
...@@ -893,34 +909,17 @@ static int init_port(void) ...@@ -893,34 +909,17 @@ static int init_port(void)
printk(KERN_INFO LIRC_DRIVER_NAME ": Manually using active " printk(KERN_INFO LIRC_DRIVER_NAME ": Manually using active "
"%s receiver\n", sense ? "low" : "high"); "%s receiver\n", sense ? "low" : "high");
dprintk("Interrupt %d, port %04x obtained\n", irq, io);
return 0; return 0;
} }
static int set_use_inc(void *data) static int set_use_inc(void *data)
{ {
int result;
unsigned long flags; unsigned long flags;
/* initialize timestamp */ /* initialize timestamp */
do_gettimeofday(&lasttv); do_gettimeofday(&lasttv);
result = request_irq(irq, irq_handler,
IRQF_DISABLED | (share_irq ? IRQF_SHARED : 0),
LIRC_DRIVER_NAME, (void *)&hardware);
switch (result) {
case -EBUSY:
printk(KERN_ERR LIRC_DRIVER_NAME ": IRQ %d busy\n", irq);
return -EBUSY;
case -EINVAL:
printk(KERN_ERR LIRC_DRIVER_NAME
": Bad irq number or handler\n");
return -EINVAL;
default:
dprintk("Interrupt %d, port %04x obtained\n", irq, io);
break;
}
spin_lock_irqsave(&hardware[type].lock, flags); spin_lock_irqsave(&hardware[type].lock, flags);
/* Set DLAB 0. */ /* Set DLAB 0. */
...@@ -945,10 +944,6 @@ static void set_use_dec(void *data) ...@@ -945,10 +944,6 @@ static void set_use_dec(void *data)
soutp(UART_IER, sinp(UART_IER) & soutp(UART_IER, sinp(UART_IER) &
(~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI)));
spin_unlock_irqrestore(&hardware[type].lock, flags); spin_unlock_irqrestore(&hardware[type].lock, flags);
free_irq(irq, (void *)&hardware);
dprintk("freed IRQ %d\n", irq);
} }
static ssize_t lirc_write(struct file *file, const char *buf, static ssize_t lirc_write(struct file *file, const char *buf,
...@@ -1256,6 +1251,9 @@ static int __init lirc_serial_init_module(void) ...@@ -1256,6 +1251,9 @@ static int __init lirc_serial_init_module(void)
static void __exit lirc_serial_exit_module(void) static void __exit lirc_serial_exit_module(void)
{ {
lirc_serial_exit(); lirc_serial_exit();
free_irq(irq, (void *)&hardware);
if (iommap != 0) if (iommap != 0)
release_mem_region(iommap, 8 << ioshift); release_mem_region(iommap, 8 << ioshift);
else else
......
...@@ -739,23 +739,16 @@ static void send_space(unsigned long len) ...@@ -739,23 +739,16 @@ static void send_space(unsigned long len)
static void send_pulse(unsigned long len) static void send_pulse(unsigned long len)
{ {
long bytes_out = len / TIME_CONST; long bytes_out = len / TIME_CONST;
long time_left;
time_left = (long)len - (long)bytes_out * (long)TIME_CONST; if (bytes_out == 0)
if (bytes_out == 0) {
bytes_out++; bytes_out++;
time_left = 0;
}
while (bytes_out--) { while (bytes_out--) {
outb(PULSE, io + UART_TX); outb(PULSE, io + UART_TX);
/* FIXME treba seriozne cakanie z char/serial.c */ /* FIXME treba seriozne cakanie z char/serial.c */
while (!(inb(io + UART_LSR) & UART_LSR_THRE)) while (!(inb(io + UART_LSR) & UART_LSR_THRE))
; ;
} }
#if 0
if (time_left > 0)
safe_udelay(time_left);
#endif
} }
#endif #endif
......
...@@ -475,14 +475,14 @@ static int lirc_thread(void *arg) ...@@ -475,14 +475,14 @@ static int lirc_thread(void *arg)
dprintk("poll thread started\n"); dprintk("poll thread started\n");
while (!kthread_should_stop()) { while (!kthread_should_stop()) {
set_current_state(TASK_INTERRUPTIBLE);
/* if device not opened, we can sleep half a second */ /* if device not opened, we can sleep half a second */
if (atomic_read(&ir->open_count) == 0) { if (atomic_read(&ir->open_count) == 0) {
schedule_timeout(HZ/2); schedule_timeout(HZ/2);
continue; continue;
} }
set_current_state(TASK_INTERRUPTIBLE);
/* /*
* This is ~113*2 + 24 + jitter (2*repeat gap + code length). * This is ~113*2 + 24 + jitter (2*repeat gap + code length).
* We use this interval as the chip resets every time you poll * We use this interval as the chip resets every time you poll
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#ifndef _LINUX_LIRC_DEV_H #ifndef _LINUX_LIRC_DEV_H
#define _LINUX_LIRC_DEV_H #define _LINUX_LIRC_DEV_H
#define MAX_IRCTL_DEVICES 4 #define MAX_IRCTL_DEVICES 8
#define BUFLEN 16 #define BUFLEN 16
#define mod(n, div) ((n) % (div)) #define mod(n, div) ((n) % (div))
......
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
* Driver header for M-5MOLS 8M Pixel camera sensor with ISP * Driver header for M-5MOLS 8M Pixel camera sensor with ISP
* *
* Copyright (C) 2011 Samsung Electronics Co., Ltd. * 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. * 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 * 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 * it under the terms of the GNU General Public License as published by
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment