From e5d85b9ac3133f67460ea5b2d4e33e0473d6eb4b Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Tue, 25 Nov 2008 10:57:30 -0300 Subject: [media] rc: Fix double free in gpio_ir_recv_probe() At the 'err_request_irq' label, rc_unregister_device(rcdev) frees its argument. So when we fall through to the 'err_gpio_request' label further down and call rc_free_device(rcdev) then that's a double free. Fix that by moving 'rcdev = NULL' from after the call to rc_free_device() to after rc_unregister_device(). That fixes the problem since rc_free_device() just does nothing if passed NULL and there's no further use of 'rcdev' after the call to rc_free_device() so it's not needed there. Signed-off-by: Jesper Juhl Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/gpio-ir-recv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index ba1a1eb..32db5f5 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -129,12 +129,12 @@ static int __devinit gpio_ir_recv_probe(struct platform_device *pdev) err_request_irq: platform_set_drvdata(pdev, NULL); rc_unregister_device(rcdev); + rcdev = NULL; err_register_rc_device: err_gpio_direction_input: gpio_free(pdata->gpio_nr); err_gpio_request: rc_free_device(rcdev); - rcdev = NULL; err_allocate_device: kfree(gpio_dev); return rc; -- cgit v1.1 From bbe2a1d32f40c01ca1a7e7795e20ca06f87ffc9b Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Tue, 25 Nov 2008 10:57:54 -0300 Subject: [media] rc: Fix double free in gpio_ir_recv_remove() Since rc_unregister_device() frees its argument there's no need to subsequently call rc_free_device() on the same variable - in fact it's a double free bug. Easily fixed by just removing the rc_free_device() call. Signed-off-by: Jesper Juhl Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/gpio-ir-recv.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index 32db5f5..03e3cf6 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -148,7 +148,6 @@ static int __devexit gpio_ir_recv_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); rc_unregister_device(gpio_dev->rcdev); gpio_free(gpio_dev->gpio_nr); - rc_free_device(gpio_dev->rcdev); kfree(gpio_dev); return 0; } -- cgit v1.1 From 70ef69915b1fba4ad85aebe530caf156a144c2e5 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Fri, 2 Nov 2012 09:13:54 -0300 Subject: [media] rc: Make probe cleanup goto labels more verbose Before, labels were simply numbered. Now, the labels are named after the cleanup action they'll perform (first), based on how the winbond-cir driver does it. This makes the code a bit more clear and makes changes in the ordering of labels easier to review. This change is applied only to the rc drivers that do significant cleanup in their probe functions: ati-remote, ene-ir, fintek-cir, gpio-ir-recv, ite-cir, nuvoton-cir. This commit should not change any code, it just renames goto labels. [mchehab@redhat.com: removed changes at gpio-ir-recv.c, due to merge conflicts] Signed-off-by: Matthijs Kooijman Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ati_remote.c | 27 ++++++++++++++++----------- drivers/media/rc/ene_ir.c | 20 ++++++++++---------- drivers/media/rc/fintek-cir.c | 20 ++++++++++---------- drivers/media/rc/ite-cir.c | 18 +++++++++--------- drivers/media/rc/nuvoton-cir.c | 30 +++++++++++++++--------------- 5 files changed, 60 insertions(+), 55 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index 2d6fb26..4d6a63f 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c @@ -872,11 +872,11 @@ static int ati_remote_probe(struct usb_interface *interface, ati_remote = kzalloc(sizeof (struct ati_remote), GFP_KERNEL); rc_dev = rc_allocate_device(); if (!ati_remote || !rc_dev) - goto fail1; + goto exit_free_dev_rdev; /* Allocate URB buffers, URBs */ if (ati_remote_alloc_buffers(udev, ati_remote)) - goto fail2; + goto exit_free_buffers; ati_remote->endpoint_in = endpoint_in; ati_remote->endpoint_out = endpoint_out; @@ -924,12 +924,12 @@ static int ati_remote_probe(struct usb_interface *interface, /* Device Hardware Initialization - fills in ati_remote->idev from udev. */ err = ati_remote_initialize(ati_remote); if (err) - goto fail3; + goto exit_kill_urbs; /* Set up and register rc device */ err = rc_register_device(ati_remote->rdev); if (err) - goto fail3; + goto exit_kill_urbs; /* use our delay for rc_dev */ ati_remote->rdev->input_dev->rep[REP_DELAY] = repeat_delay; @@ -939,7 +939,7 @@ static int ati_remote_probe(struct usb_interface *interface, input_dev = input_allocate_device(); if (!input_dev) { err = -ENOMEM; - goto fail4; + goto exit_unregister_device; } ati_remote->idev = input_dev; @@ -947,19 +947,24 @@ static int ati_remote_probe(struct usb_interface *interface, err = input_register_device(input_dev); if (err) - goto fail5; + goto exit_free_input_device; } usb_set_intfdata(interface, ati_remote); return 0; - fail5: input_free_device(input_dev); - fail4: rc_unregister_device(rc_dev); + exit_free_input_device: + input_free_device(input_dev); + exit_unregister_device: + rc_unregister_device(rc_dev); rc_dev = NULL; - fail3: usb_kill_urb(ati_remote->irq_urb); + exit_kill_urbs: + usb_kill_urb(ati_remote->irq_urb); usb_kill_urb(ati_remote->out_urb); - fail2: ati_remote_free_buffers(ati_remote); - fail1: rc_free_device(rc_dev); + exit_free_buffers: + ati_remote_free_buffers(ati_remote); + exit_free_dev_rdev: + rc_free_device(rc_dev); kfree(ati_remote); return err; } diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index 22231dd..f7fdfea 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -1003,7 +1003,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL); rdev = rc_allocate_device(); if (!dev || !rdev) - goto failure; + goto exit_free_dev_rdev; /* validate resources */ error = -ENODEV; @@ -1014,10 +1014,10 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) if (!pnp_port_valid(pnp_dev, 0) || pnp_port_len(pnp_dev, 0) < ENE_IO_SIZE) - goto failure; + goto exit_free_dev_rdev; if (!pnp_irq_valid(pnp_dev, 0)) - goto failure; + goto exit_free_dev_rdev; spin_lock_init(&dev->hw_lock); @@ -1033,7 +1033,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) /* detect hardware version and features */ error = ene_hw_detect(dev); if (error) - goto failure; + goto exit_free_dev_rdev; if (!dev->hw_learning_and_tx_capable && txsim) { dev->hw_learning_and_tx_capable = true; @@ -1078,27 +1078,27 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) /* claim the resources */ error = -EBUSY; if (!request_region(dev->hw_io, ENE_IO_SIZE, ENE_DRIVER_NAME)) { - goto failure; + goto exit_free_dev_rdev; } dev->irq = pnp_irq(pnp_dev, 0); if (request_irq(dev->irq, ene_isr, IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev)) { - goto failure2; + goto exit_release_hw_io; } error = rc_register_device(rdev); if (error < 0) - goto failure3; + goto exit_free_irq; pr_notice("driver has been successfully loaded\n"); return 0; -failure3: +exit_free_irq: free_irq(dev->irq, dev); -failure2: +exit_release_hw_io: release_region(dev->hw_io, ENE_IO_SIZE); -failure: +exit_free_dev_rdev: rc_free_device(rdev); kfree(dev); return error; diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c index 936c3f7..3d5e57c 100644 --- a/drivers/media/rc/fintek-cir.c +++ b/drivers/media/rc/fintek-cir.c @@ -500,18 +500,18 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id /* input device for IR remote (and tx) */ rdev = rc_allocate_device(); if (!rdev) - goto failure; + goto exit_free_dev_rdev; ret = -ENODEV; /* validate pnp resources */ if (!pnp_port_valid(pdev, 0)) { dev_err(&pdev->dev, "IR PNP Port not valid!\n"); - goto failure; + goto exit_free_dev_rdev; } if (!pnp_irq_valid(pdev, 0)) { dev_err(&pdev->dev, "IR PNP IRQ not valid!\n"); - goto failure; + goto exit_free_dev_rdev; } fintek->cir_addr = pnp_port_start(pdev, 0); @@ -528,7 +528,7 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id ret = fintek_hw_detect(fintek); if (ret) - goto failure; + goto exit_free_dev_rdev; /* Initialize CIR & CIR Wake Logical Devices */ fintek_config_mode_enable(fintek); @@ -561,15 +561,15 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id /* now claim resources */ if (!request_region(fintek->cir_addr, fintek->cir_port_len, FINTEK_DRIVER_NAME)) - goto failure; + goto exit_free_dev_rdev; if (request_irq(fintek->cir_irq, fintek_cir_isr, IRQF_SHARED, FINTEK_DRIVER_NAME, (void *)fintek)) - goto failure2; + goto exit_free_cir_addr; ret = rc_register_device(rdev); if (ret) - goto failure3; + goto exit_free_irq; device_init_wakeup(&pdev->dev, true); fintek->rdev = rdev; @@ -579,11 +579,11 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id return 0; -failure3: +exit_free_irq: free_irq(fintek->cir_irq, fintek); -failure2: +exit_free_cir_addr: release_region(fintek->cir_addr, fintek->cir_port_len); -failure: +exit_free_dev_rdev: rc_free_device(rdev); kfree(fintek); diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index 5e5a7f2..8e0e661 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -1472,7 +1472,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id /* input device for IR remote (and tx) */ rdev = rc_allocate_device(); if (!rdev) - goto failure; + goto exit_free_dev_rdev; itdev->rdev = rdev; ret = -ENODEV; @@ -1498,12 +1498,12 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id if (!pnp_port_valid(pdev, io_rsrc_no) || pnp_port_len(pdev, io_rsrc_no) != dev_desc->io_region_size) { dev_err(&pdev->dev, "IR PNP Port not valid!\n"); - goto failure; + goto exit_free_dev_rdev; } if (!pnp_irq_valid(pdev, 0)) { dev_err(&pdev->dev, "PNP IRQ not valid!\n"); - goto failure; + goto exit_free_dev_rdev; } /* store resource values */ @@ -1595,25 +1595,25 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id /* now claim resources */ if (!request_region(itdev->cir_addr, dev_desc->io_region_size, ITE_DRIVER_NAME)) - goto failure; + goto exit_free_dev_rdev; if (request_irq(itdev->cir_irq, ite_cir_isr, IRQF_SHARED, ITE_DRIVER_NAME, (void *)itdev)) - goto failure2; + goto exit_release_cir_addr; ret = rc_register_device(rdev); if (ret) - goto failure3; + goto exit_free_irq; ite_pr(KERN_NOTICE, "driver has been successfully loaded\n"); return 0; -failure3: +exit_free_irq: free_irq(itdev->cir_irq, itdev); -failure2: +exit_release_cir_addr: release_region(itdev->cir_addr, itdev->params.io_region_size); -failure: +exit_free_dev_rdev: rc_free_device(rdev); kfree(itdev); diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index e4ea89a..3477e23 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -986,25 +986,25 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) /* input device for IR remote (and tx) */ rdev = rc_allocate_device(); if (!rdev) - goto failure; + goto exit_free_dev_rdev; ret = -ENODEV; /* validate pnp resources */ if (!pnp_port_valid(pdev, 0) || pnp_port_len(pdev, 0) < CIR_IOREG_LENGTH) { dev_err(&pdev->dev, "IR PNP Port not valid!\n"); - goto failure; + goto exit_free_dev_rdev; } if (!pnp_irq_valid(pdev, 0)) { dev_err(&pdev->dev, "PNP IRQ not valid!\n"); - goto failure; + goto exit_free_dev_rdev; } if (!pnp_port_valid(pdev, 1) || pnp_port_len(pdev, 1) < CIR_IOREG_LENGTH) { dev_err(&pdev->dev, "Wake PNP Port not valid!\n"); - goto failure; + goto exit_free_dev_rdev; } nvt->cir_addr = pnp_port_start(pdev, 0); @@ -1027,7 +1027,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) ret = nvt_hw_detect(nvt); if (ret) - goto failure; + goto exit_free_dev_rdev; /* Initialize CIR & CIR Wake Logical Devices */ nvt_efm_enable(nvt); @@ -1070,23 +1070,23 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) /* now claim resources */ if (!request_region(nvt->cir_addr, CIR_IOREG_LENGTH, NVT_DRIVER_NAME)) - goto failure; + goto exit_free_dev_rdev; if (request_irq(nvt->cir_irq, nvt_cir_isr, IRQF_SHARED, NVT_DRIVER_NAME, (void *)nvt)) - goto failure2; + goto exit_release_cir_addr; if (!request_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH, NVT_DRIVER_NAME)) - goto failure3; + goto exit_free_irq; if (request_irq(nvt->cir_wake_irq, nvt_cir_wake_isr, IRQF_SHARED, NVT_DRIVER_NAME, (void *)nvt)) - goto failure4; + goto exit_release_cir_wake_addr; ret = rc_register_device(rdev); if (ret) - goto failure5; + goto exit_free_wake_irq; device_init_wakeup(&pdev->dev, true); nvt->rdev = rdev; @@ -1098,15 +1098,15 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) return 0; -failure5: +exit_free_wake_irq: free_irq(nvt->cir_wake_irq, nvt); -failure4: +exit_release_cir_wake_addr: release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH); -failure3: +exit_free_irq: free_irq(nvt->cir_irq, nvt); -failure2: +exit_release_cir_addr: release_region(nvt->cir_addr, CIR_IOREG_LENGTH); -failure: +exit_free_dev_rdev: rc_free_device(rdev); kfree(nvt); -- cgit v1.1 From d62b6818477704683d00c680335eff5833bd3906 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Fri, 2 Nov 2012 09:13:55 -0300 Subject: [media] rc: Set rdev before irq setup This fixes a problem in fintek-cir and nuvoton-cir where the irq handler would trigger during module load before the rdev member was set, causing a NULL pointer crash. It seems this crash is very reproducible (just bombard the receiver with IR signals during module load), probably because when request_irq is called, any pending intterupt is handled immediately, before request_irq returns and rdev can be set. This same crash was supposed to be fixed by commit 9ef449c6b31bb6a8e6dedc24de475a3b8c79be20 ("[media] rc: Postpone ISR registration"), but the crash was still observed on the nuvoton-cir driver. This commit was tested on nuvoton-cir only. Cc: Jarod Wilson Signed-off-by: Matthijs Kooijman Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/fintek-cir.c | 4 +++- drivers/media/rc/nuvoton-cir.c | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c index 3d5e57c..5eefe65 100644 --- a/drivers/media/rc/fintek-cir.c +++ b/drivers/media/rc/fintek-cir.c @@ -557,6 +557,8 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id /* rx resolution is hardwired to 50us atm, 1, 25, 100 also possible */ rdev->rx_resolution = US_TO_NS(CIR_SAMPLE_PERIOD); + fintek->rdev = rdev; + ret = -EBUSY; /* now claim resources */ if (!request_region(fintek->cir_addr, @@ -572,7 +574,7 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id goto exit_free_irq; device_init_wakeup(&pdev->dev, true); - fintek->rdev = rdev; + fit_pr(KERN_NOTICE, "driver has been successfully loaded\n"); if (debug) cir_dump_regs(fintek); diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index 3477e23..c6441e6 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -1065,6 +1065,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) /* tx bits */ rdev->tx_resolution = XYZ; #endif + nvt->rdev = rdev; ret = -EBUSY; /* now claim resources */ @@ -1089,7 +1090,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) goto exit_free_wake_irq; device_init_wakeup(&pdev->dev, true); - nvt->rdev = rdev; + nvt_pr(KERN_NOTICE, "driver has been successfully loaded\n"); if (debug) { cir_dump_regs(nvt); -- cgit v1.1 From 9fa35204dd19eb0e96ee870b7128a8f5da51dbfa Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Fri, 2 Nov 2012 09:13:56 -0300 Subject: [media] rc: Call rc_register_device before irq setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should fix a potential race condition, when the irq handler triggers while rc_register_device is still setting up the rdev->raw device. This crash has not been observed in practice, but there should be a very small window where it could occur. Since ir_raw_event_store_with_filter checks if rdev->raw is not NULL before using it, this bug is not triggered if the request_irq triggers a pending irq directly (since rdev->raw will still be NULL then). This commit was tested on nuvoton-cir only. Cc: Jarod Wilson Cc: Maxim Levitsky Cc: David Härdeman Signed-off-by: Matthijs Kooijman Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ene_ir.c | 14 +++++++------- drivers/media/rc/ite-cir.c | 14 +++++++------- drivers/media/rc/nuvoton-cir.c | 14 +++++++------- drivers/media/rc/winbond-cir.c | 14 +++++++------- 4 files changed, 28 insertions(+), 28 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index f7fdfea..e601166 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -1075,10 +1075,14 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) device_set_wakeup_capable(&pnp_dev->dev, true); device_set_wakeup_enable(&pnp_dev->dev, true); + error = rc_register_device(rdev); + if (error < 0) + goto exit_free_dev_rdev; + /* claim the resources */ error = -EBUSY; if (!request_region(dev->hw_io, ENE_IO_SIZE, ENE_DRIVER_NAME)) { - goto exit_free_dev_rdev; + goto exit_unregister_device; } dev->irq = pnp_irq(pnp_dev, 0); @@ -1087,17 +1091,13 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) goto exit_release_hw_io; } - error = rc_register_device(rdev); - if (error < 0) - goto exit_free_irq; - pr_notice("driver has been successfully loaded\n"); return 0; -exit_free_irq: - free_irq(dev->irq, dev); exit_release_hw_io: release_region(dev->hw_io, ENE_IO_SIZE); +exit_unregister_device: + rc_unregister_device(rdev); exit_free_dev_rdev: rc_free_device(rdev); kfree(dev); diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index 8e0e661..e810846 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -1591,28 +1591,28 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id rdev->driver_name = ITE_DRIVER_NAME; rdev->map_name = RC_MAP_RC6_MCE; + ret = rc_register_device(rdev); + if (ret) + goto exit_free_dev_rdev; + ret = -EBUSY; /* now claim resources */ if (!request_region(itdev->cir_addr, dev_desc->io_region_size, ITE_DRIVER_NAME)) - goto exit_free_dev_rdev; + goto exit_unregister_device; if (request_irq(itdev->cir_irq, ite_cir_isr, IRQF_SHARED, ITE_DRIVER_NAME, (void *)itdev)) goto exit_release_cir_addr; - ret = rc_register_device(rdev); - if (ret) - goto exit_free_irq; - ite_pr(KERN_NOTICE, "driver has been successfully loaded\n"); return 0; -exit_free_irq: - free_irq(itdev->cir_irq, itdev); exit_release_cir_addr: release_region(itdev->cir_addr, itdev->params.io_region_size); +exit_unregister_device: + rc_unregister_device(rdev); exit_free_dev_rdev: rc_free_device(rdev); kfree(itdev); diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index c6441e6..6cf43cc 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -1067,11 +1067,15 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) #endif nvt->rdev = rdev; + ret = rc_register_device(rdev); + if (ret) + goto exit_free_dev_rdev; + ret = -EBUSY; /* now claim resources */ if (!request_region(nvt->cir_addr, CIR_IOREG_LENGTH, NVT_DRIVER_NAME)) - goto exit_free_dev_rdev; + goto exit_unregister_device; if (request_irq(nvt->cir_irq, nvt_cir_isr, IRQF_SHARED, NVT_DRIVER_NAME, (void *)nvt)) @@ -1085,10 +1089,6 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) NVT_DRIVER_NAME, (void *)nvt)) goto exit_release_cir_wake_addr; - ret = rc_register_device(rdev); - if (ret) - goto exit_free_wake_irq; - device_init_wakeup(&pdev->dev, true); nvt_pr(KERN_NOTICE, "driver has been successfully loaded\n"); @@ -1099,14 +1099,14 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) return 0; -exit_free_wake_irq: - free_irq(nvt->cir_wake_irq, nvt); exit_release_cir_wake_addr: release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH); exit_free_irq: free_irq(nvt->cir_irq, nvt); exit_release_cir_addr: release_region(nvt->cir_addr, CIR_IOREG_LENGTH); +exit_unregister_device: + rc_unregister_device(rdev); exit_free_dev_rdev: rc_free_device(rdev); kfree(nvt); diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index 7f3c476..553d1cd 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c @@ -1093,11 +1093,15 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id) data->dev->rx_resolution = US_TO_NS(2); data->dev->allowed_protos = RC_BIT_ALL; + err = rc_register_device(data->dev); + if (err) + goto exit_free_rc; + if (!request_region(data->wbase, WAKEUP_IOMEM_LEN, DRVNAME)) { dev_err(dev, "Region 0x%lx-0x%lx already in use!\n", data->wbase, data->wbase + WAKEUP_IOMEM_LEN - 1); err = -EBUSY; - goto exit_free_rc; + goto exit_unregister_device; } if (!request_region(data->ebase, EHFUNC_IOMEM_LEN, DRVNAME)) { @@ -1122,24 +1126,20 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id) goto exit_release_sbase; } - err = rc_register_device(data->dev); - if (err) - goto exit_free_irq; - device_init_wakeup(&device->dev, 1); wbcir_init_hw(data); return 0; -exit_free_irq: - free_irq(data->irq, device); exit_release_sbase: release_region(data->sbase, SP_IOMEM_LEN); exit_release_ebase: release_region(data->ebase, EHFUNC_IOMEM_LEN); exit_release_wbase: release_region(data->wbase, WAKEUP_IOMEM_LEN); +exit_unregister_device: + rc_unregister_device(data->dev); exit_free_rc: rc_free_device(data->dev); exit_unregister_led: -- cgit v1.1 From 36cb26a4a67cdc186a2a5ec5e49063ea635969ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20Jes=C3=BAs=20Delaiti?= Date: Thu, 8 Nov 2012 16:14:50 -0300 Subject: [media] rc/keymaps: add RC keytable for MyGica X8507 Add RC-5 remote keytable definition for MyGica X8507. [mchehab@redhat.com: fixed whitespacing - it seems that Alfredo's emailer mangled it] Signed-off-by: Alfredo J. Delaiti Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/keymaps/Makefile | 1 + .../media/rc/keymaps/rc-total-media-in-hand-02.c | 86 ++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 drivers/media/rc/keymaps/rc-total-media-in-hand-02.c (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index ab84d66..7786619 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -88,6 +88,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-tevii-nec.o \ rc-tivo.o \ rc-total-media-in-hand.o \ + rc-total-media-in-hand-02.o \ rc-trekstor.o \ rc-tt-1500.o \ rc-twinhan1027.o \ diff --git a/drivers/media/rc/keymaps/rc-total-media-in-hand-02.c b/drivers/media/rc/keymaps/rc-total-media-in-hand-02.c new file mode 100644 index 0000000..47270f7 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-total-media-in-hand-02.c @@ -0,0 +1,86 @@ +/* + * Total Media In Hand_02 remote controller keytable for Mygica X8507 + * + * Copyright (C) 2012 Alfredo J. Delaiti + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include + + +static struct rc_map_table total_media_in_hand_02[] = { + { 0x0000, KEY_0 }, + { 0x0001, KEY_1 }, + { 0x0002, KEY_2 }, + { 0x0003, KEY_3 }, + { 0x0004, KEY_4 }, + { 0x0005, KEY_5 }, + { 0x0006, KEY_6 }, + { 0x0007, KEY_7 }, + { 0x0008, KEY_8 }, + { 0x0009, KEY_9 }, + { 0x000a, KEY_MUTE }, + { 0x000b, KEY_STOP }, /* Stop */ + { 0x000c, KEY_POWER2 }, /* Turn on/off application */ + { 0x000d, KEY_OK }, /* OK */ + { 0x000e, KEY_CAMERA }, /* Snapshot */ + { 0x000f, KEY_ZOOM }, /* Full Screen/Restore */ + { 0x0010, KEY_RIGHT }, /* Right arrow */ + { 0x0011, KEY_LEFT }, /* Left arrow */ + { 0x0012, KEY_CHANNELUP }, + { 0x0013, KEY_CHANNELDOWN }, + { 0x0014, KEY_SHUFFLE }, + { 0x0016, KEY_PAUSE }, + { 0x0017, KEY_PLAY }, /* Play */ + { 0x001e, KEY_TIME }, /* Time Shift */ + { 0x001f, KEY_RECORD }, + { 0x0020, KEY_UP }, + { 0x0021, KEY_DOWN }, + { 0x0025, KEY_POWER }, /* Turn off computer */ + { 0x0026, KEY_REWIND }, /* FR << */ + { 0x0027, KEY_FASTFORWARD }, /* FF >> */ + { 0x0029, KEY_ESC }, + { 0x002b, KEY_VOLUMEUP }, + { 0x002c, KEY_VOLUMEDOWN }, + { 0x002d, KEY_CHANNEL }, /* CH Surfing */ + { 0x0038, KEY_VIDEO }, /* TV/AV/S-Video/YPbPr */ +}; + +static struct rc_map_list total_media_in_hand_02_map = { + .map = { + .scan = total_media_in_hand_02, + .size = ARRAY_SIZE(total_media_in_hand_02), + .rc_type = RC_TYPE_RC5, + .name = RC_MAP_TOTAL_MEDIA_IN_HAND_02, + } +}; + +static int __init init_rc_map_total_media_in_hand_02(void) +{ + return rc_map_register(&total_media_in_hand_02_map); +} + +static void __exit exit_rc_map_total_media_in_hand_02(void) +{ + rc_map_unregister(&total_media_in_hand_02_map); +} + +module_init(init_rc_map_total_media_in_hand_02) +module_exit(exit_rc_map_total_media_in_hand_02) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR(" Alfredo J. Delaiti "); -- cgit v1.1 From 30ebc5e44d057a1619ad63fe32c8c1670c37c4b8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 27 Nov 2012 13:35:09 -0300 Subject: [media] rc: unlock on error in show_protocols() We recently introduced a new return -ENODEV in this function but we need to unlock before returning. [mchehab@redhat.com: found two patches with the same fix. Merged SOB's/acks into one patch] Acked-by: Herton R. Krzesinski Signed-off-by: Dan Carpenter Cc: stable@vger.kernel.org Signed-off-by: Douglas Bagnall Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 601d1ac1..d593bc6 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -789,8 +789,10 @@ static ssize_t show_protocols(struct device *device, } else if (dev->raw) { enabled = dev->raw->enabled_protocols; allowed = ir_raw_get_allowed_protocols(); - } else + } else { + mutex_unlock(&dev->lock); return -ENODEV; + } IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n", (long long)allowed, -- cgit v1.1 From afe5624b142279c6072ce1872811e309ad7e94be Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 27 Nov 2012 13:35:30 -0300 Subject: [media] rc: unlock on error in store_protocols() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This error path is missing the unlock. [mchehab@redhat.com: Merged two equal patches into one] Signed-off-by: Sasha Levin Acked-by: David Härdeman Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index d593bc6..759a40a 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -892,7 +892,8 @@ static ssize_t store_protocols(struct device *device, if (i == ARRAY_SIZE(proto_names)) { IR_dprintk(1, "Unknown protocol: '%s'\n", tmp); - return -EINVAL; + ret = -EINVAL; + goto out; } count++; -- cgit v1.1 From a4bb6f353e287f51a52a347670fd60938a566c25 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Fri, 14 Dec 2012 07:02:48 -0300 Subject: [media] media/rc: fix oops on unloading module rc-core During modiles initialization rc-core schedules work which calls request_module() several times to load ir-*-decoder modules, but it does not wait or cancel this work on module unloading. rc-core should use request_module_nowait() instead, because it anyway cannot load modules synchronously or cancel/wait pending work on unloading, because this leads to deadlock on modules_mutex between several "modprobe" processes. Signed-off-by: Konstantin Khlebnikov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-raw.c | 17 +---------------- drivers/media/rc/rc-core-priv.h | 16 ++++++++-------- 2 files changed, 9 insertions(+), 24 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c index 97dc8d1..17c94be 100644 --- a/drivers/media/rc/ir-raw.c +++ b/drivers/media/rc/ir-raw.c @@ -31,11 +31,6 @@ static DEFINE_MUTEX(ir_raw_handler_lock); static LIST_HEAD(ir_raw_handler_list); static u64 available_protocols; -#ifdef MODULE -/* Used to load the decoders */ -static struct work_struct wq_load; -#endif - static int ir_raw_event_thread(void *data) { struct ir_raw_event ev; @@ -347,8 +342,7 @@ void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler) } EXPORT_SYMBOL(ir_raw_handler_unregister); -#ifdef MODULE -static void init_decoders(struct work_struct *work) +void ir_raw_init(void) { /* Load the decoder modules */ @@ -365,12 +359,3 @@ static void init_decoders(struct work_struct *work) it is needed to change the CONFIG_MODULE test at rc-core.h */ } -#endif - -void ir_raw_init(void) -{ -#ifdef MODULE - INIT_WORK(&wq_load, init_decoders); - schedule_work(&wq_load); -#endif -} diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index 96f0a8b..5d87287 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -165,56 +165,56 @@ void ir_raw_init(void); /* from ir-nec-decoder.c */ #ifdef CONFIG_IR_NEC_DECODER_MODULE -#define load_nec_decode() request_module("ir-nec-decoder") +#define load_nec_decode() request_module_nowait("ir-nec-decoder") #else static inline void load_nec_decode(void) { } #endif /* from ir-rc5-decoder.c */ #ifdef CONFIG_IR_RC5_DECODER_MODULE -#define load_rc5_decode() request_module("ir-rc5-decoder") +#define load_rc5_decode() request_module_nowait("ir-rc5-decoder") #else static inline void load_rc5_decode(void) { } #endif /* from ir-rc6-decoder.c */ #ifdef CONFIG_IR_RC6_DECODER_MODULE -#define load_rc6_decode() request_module("ir-rc6-decoder") +#define load_rc6_decode() request_module_nowait("ir-rc6-decoder") #else static inline void load_rc6_decode(void) { } #endif /* from ir-jvc-decoder.c */ #ifdef CONFIG_IR_JVC_DECODER_MODULE -#define load_jvc_decode() request_module("ir-jvc-decoder") +#define load_jvc_decode() request_module_nowait("ir-jvc-decoder") #else static inline void load_jvc_decode(void) { } #endif /* from ir-sony-decoder.c */ #ifdef CONFIG_IR_SONY_DECODER_MODULE -#define load_sony_decode() request_module("ir-sony-decoder") +#define load_sony_decode() request_module_nowait("ir-sony-decoder") #else static inline void load_sony_decode(void) { } #endif /* from ir-sanyo-decoder.c */ #ifdef CONFIG_IR_SANYO_DECODER_MODULE -#define load_sanyo_decode() request_module("ir-sanyo-decoder") +#define load_sanyo_decode() request_module_nowait("ir-sanyo-decoder") #else static inline void load_sanyo_decode(void) { } #endif /* from ir-mce_kbd-decoder.c */ #ifdef CONFIG_IR_MCE_KBD_DECODER_MODULE -#define load_mce_kbd_decode() request_module("ir-mce_kbd-decoder") +#define load_mce_kbd_decode() request_module_nowait("ir-mce_kbd-decoder") #else static inline void load_mce_kbd_decode(void) { } #endif /* from ir-lirc-codec.c */ #ifdef CONFIG_IR_LIRC_CODEC_MODULE -#define load_lirc_codec() request_module("ir-lirc-codec") +#define load_lirc_codec() request_module_nowait("ir-lirc-codec") #else static inline void load_lirc_codec(void) { } #endif -- cgit v1.1 From 24dec5dabfcc1d424d7bc86d393d31f57ebcc975 Mon Sep 17 00:00:00 2001 From: Alexandre Lissy Date: Sun, 2 Sep 2012 15:35:20 -0300 Subject: [media] imon: fix Knob event interpretation issues on ARM Events for the iMon Knob pad where not correctly interpreted on ARM, resulting in buggy mouse movements (cursor going straight out of the screen), key pad only generating KEY_RIGHT and KEY_DOWN events. A reproducer is: int main(int argc, char ** argv) { char rel_x = 0x00; printf("rel_x:%d @%s:%d\n", rel_x, __FILE__, __LINE__); rel_x = 0x0f; printf("rel_x:%d @%s:%d\n", rel_x, __FILE__, __LINE__); rel_x |= ~0x0f; printf("rel_x:%d @%s:%d\n", rel_x, __FILE__, __LINE__); return 0; } (running on x86 or amd64) $ ./test rel_x:0 @test.c:6 rel_x:15 @test.c:7 rel_x:-1 @test.c:8 (running on armv6) rel_x:0 @test.c:6 rel_x:15 @test.c:7 rel_x:255 @test.c:8 Forcing the rel_x and rel_y variables as signed char fixes the issue. Reference: http://www.arm.linux.org.uk/docs/faqs/signedchar.php Signed-off-by: Alexandre Lissy Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 78d109b..dec203b 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -1221,7 +1221,7 @@ static u32 imon_panel_key_lookup(u64 code) static bool imon_mouse_event(struct imon_context *ictx, unsigned char *buf, int len) { - char rel_x = 0x00, rel_y = 0x00; + signed char rel_x = 0x00, rel_y = 0x00; u8 right_shift = 1; bool mouse_input = true; int dir = 0; @@ -1297,7 +1297,7 @@ static void imon_touch_event(struct imon_context *ictx, unsigned char *buf) static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) { int dir = 0; - char rel_x = 0x00, rel_y = 0x00; + signed char rel_x = 0x00, rel_y = 0x00; u16 timeout, threshold; u32 scancode = KEY_RESERVED; unsigned long flags; -- cgit v1.1 From 6f2627c29f6619ebdbc6de8934b33c23b73be8e6 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sun, 6 Jan 2013 13:19:43 -0300 Subject: [media] winbond-cir: only enable higher sample resolution if needed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A sample resolution of 2us generates more than 300 interrupts per key and this resolution is not needed unless carrier reports are enabled. Revert to a resolution of 10us unless carrier reports are needed. This generates up to a fifth of the interrupts. Signed-off-by: Sean Young Acked-by: David Härdeman Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/winbond-cir.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index 8542485..535a18d 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c @@ -154,6 +154,8 @@ #define WBCIR_CNTR_R 0x02 /* Invert TX */ #define WBCIR_IRTX_INV 0x04 +/* Receiver oversampling */ +#define WBCIR_RX_T_OV 0x40 /* Valid banks for the SP3 UART */ enum wbcir_bank { @@ -394,7 +396,8 @@ wbcir_irq_rx(struct wbcir_data *data, struct pnp_dev *device) if (data->rxstate == WBCIR_RXSTATE_ERROR) continue; - duration = ((irdata & 0x7F) + 1) * 2; + duration = ((irdata & 0x7F) + 1) * + (data->carrier_report_enabled ? 2 : 10); rawir.pulse = irdata & 0x80 ? false : true; rawir.duration = US_TO_NS(duration); @@ -550,6 +553,17 @@ wbcir_set_carrier_report(struct rc_dev *dev, int enable) wbcir_set_bits(data->ebase + WBCIR_REG_ECEIR_CCTL, WBCIR_CNTR_EN, WBCIR_CNTR_EN | WBCIR_CNTR_R); + /* Set a higher sampling resolution if carrier reports are enabled */ + wbcir_select_bank(data, WBCIR_BANK_2); + data->dev->rx_resolution = US_TO_NS(enable ? 2 : 10); + outb(enable ? 0x03 : 0x0f, data->sbase + WBCIR_REG_SP3_BGDL); + outb(0x00, data->sbase + WBCIR_REG_SP3_BGDH); + + /* Enable oversampling if carrier reports are enabled */ + wbcir_select_bank(data, WBCIR_BANK_7); + wbcir_set_bits(data->sbase + WBCIR_REG_SP3_RCCFG, + enable ? WBCIR_RX_T_OV : 0, WBCIR_RX_T_OV); + data->carrier_report_enabled = enable; spin_unlock_irqrestore(&data->spinlock, flags); @@ -931,8 +945,8 @@ wbcir_init_hw(struct wbcir_data *data) /* prescaler 1.0, tx/rx fifo lvl 16 */ outb(0x30, data->sbase + WBCIR_REG_SP3_EXCR2); - /* Set baud divisor to sample every 2 ns */ - outb(0x03, data->sbase + WBCIR_REG_SP3_BGDL); + /* Set baud divisor to sample every 10 us */ + outb(0x0f, data->sbase + WBCIR_REG_SP3_BGDL); outb(0x00, data->sbase + WBCIR_REG_SP3_BGDH); /* Set CEIR mode */ @@ -941,12 +955,9 @@ wbcir_init_hw(struct wbcir_data *data) inb(data->sbase + WBCIR_REG_SP3_LSR); /* Clear LSR */ inb(data->sbase + WBCIR_REG_SP3_MSR); /* Clear MSR */ - /* - * Disable RX demod, enable run-length enc/dec, set freq span and - * enable over-sampling - */ + /* Disable RX demod, enable run-length enc/dec, set freq span */ wbcir_select_bank(data, WBCIR_BANK_7); - outb(0xd0, data->sbase + WBCIR_REG_SP3_RCCFG); + outb(0x90, data->sbase + WBCIR_REG_SP3_RCCFG); /* Disable timer */ wbcir_select_bank(data, WBCIR_BANK_4); -- cgit v1.1 From d0aab6564d12add07572141ceb34c60046e93ac3 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sun, 6 Jan 2013 13:19:44 -0300 Subject: [media] iguanair: ensure transmission mask is initialized Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/iguanair.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c index b99b096..b8b3e37 100644 --- a/drivers/media/rc/iguanair.c +++ b/drivers/media/rc/iguanair.c @@ -512,6 +512,7 @@ static int iguanair_probe(struct usb_interface *intf, rc->rx_resolution = RX_RESOLUTION; iguanair_set_tx_carrier(rc, 38000); + iguanair_set_tx_mask(rc, 0); ret = rc_register_device(rc); if (ret < 0) { -- cgit v1.1 From c6a3ea570e5d0ca20069cce5d537c845128b70f4 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 14 Jan 2013 05:51:44 -0300 Subject: [media] iguanair: intermittent initialization failure On cold boot the device does not initialize until the first packet is received, and that packet is not processed. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/iguanair.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c index b8b3e37..a4ab2e6 100644 --- a/drivers/media/rc/iguanair.c +++ b/drivers/media/rc/iguanair.c @@ -58,6 +58,7 @@ struct iguanair { char phys[64]; }; +#define CMD_NOP 0x00 #define CMD_GET_VERSION 0x01 #define CMD_GET_BUFSIZE 0x11 #define CMD_GET_FEATURES 0x10 @@ -196,6 +197,10 @@ static void iguanair_irq_out(struct urb *urb) if (urb->status) dev_dbg(ir->dev, "Error: out urb status = %d\n", urb->status); + + /* if we sent an nop packet, do not expect a response */ + if (urb->status == 0 && ir->packet->header.cmd == CMD_NOP) + complete(&ir->completion); } static int iguanair_send(struct iguanair *ir, unsigned size) @@ -219,10 +224,17 @@ static int iguanair_get_features(struct iguanair *ir) { int rc; + /* + * On cold boot, the iguanair initializes on the first packet + * received but does not process that packet. Send an empty + * packet. + */ ir->packet->header.start = 0; ir->packet->header.direction = DIR_OUT; - ir->packet->header.cmd = CMD_GET_VERSION; + ir->packet->header.cmd = CMD_NOP; + iguanair_send(ir, sizeof(ir->packet->header)); + ir->packet->header.cmd = CMD_GET_VERSION; rc = iguanair_send(ir, sizeof(ir->packet->header)); if (rc) { dev_info(ir->dev, "failed to get version\n"); @@ -255,19 +267,14 @@ static int iguanair_get_features(struct iguanair *ir) ir->packet->header.cmd = CMD_GET_FEATURES; rc = iguanair_send(ir, sizeof(ir->packet->header)); - if (rc) { + if (rc) dev_info(ir->dev, "failed to get features\n"); - goto out; - } - out: return rc; } static int iguanair_receiver(struct iguanair *ir, bool enable) { - int rc; - ir->packet->header.start = 0; ir->packet->header.direction = DIR_OUT; ir->packet->header.cmd = enable ? CMD_RECEIVER_ON : CMD_RECEIVER_OFF; @@ -275,9 +282,7 @@ static int iguanair_receiver(struct iguanair *ir, bool enable) if (enable) ir_raw_event_reset(ir->rc); - rc = iguanair_send(ir, sizeof(ir->packet->header)); - - return rc; + return iguanair_send(ir, sizeof(ir->packet->header)); } /* -- cgit v1.1 From d2008b56cfd6fa76ac6990d9c12a045ce5026c85 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Tue, 29 Jan 2013 08:19:27 -0300 Subject: [media] ttusbir: do not set led twice on resume led_classdev_resume already sets the led. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ttusbir.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c index 78be8a9..f9226b8 100644 --- a/drivers/media/rc/ttusbir.c +++ b/drivers/media/rc/ttusbir.c @@ -408,9 +408,8 @@ static int ttusbir_resume(struct usb_interface *intf) struct ttusbir *tt = usb_get_intfdata(intf); int i, rc; - led_classdev_resume(&tt->led); tt->is_led_on = true; - ttusbir_set_led(tt); + led_classdev_resume(&tt->led); for (i = 0; i < NUM_URBS; i++) { rc = usb_submit_urb(tt->urb[i], GFP_KERNEL); -- cgit v1.1 From 1e801adc7a70c2f67214b2617088a41f4bebe55e Mon Sep 17 00:00:00 2001 From: Sean Young Date: Tue, 29 Jan 2013 08:19:28 -0300 Subject: [media] ttusbir: add missing endian conversion spotted by sparse. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ttusbir.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c index f9226b8..cf0d47f 100644 --- a/drivers/media/rc/ttusbir.c +++ b/drivers/media/rc/ttusbir.c @@ -213,19 +213,20 @@ static int ttusbir_probe(struct usb_interface *intf, /* find the correct alt setting */ for (i = 0; i < intf->num_altsetting && altsetting == -1; i++) { - int bulk_out_endp = -1, iso_in_endp = -1; + int max_packet, bulk_out_endp = -1, iso_in_endp = -1; idesc = &intf->altsetting[i].desc; for (j = 0; j < idesc->bNumEndpoints; j++) { desc = &intf->altsetting[i].endpoint[j].desc; + max_packet = le16_to_cpu(desc->wMaxPacketSize); if (usb_endpoint_dir_in(desc) && usb_endpoint_xfer_isoc(desc) && - desc->wMaxPacketSize == 0x10) + max_packet == 0x10) iso_in_endp = j; else if (usb_endpoint_dir_out(desc) && usb_endpoint_xfer_bulk(desc) && - desc->wMaxPacketSize == 0x20) + max_packet == 0x20) bulk_out_endp = j; if (bulk_out_endp != -1 && iso_in_endp != -1) { -- cgit v1.1 From 8dfef674e6c954f9b6476c1b252b385c48c9ee26 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Tue, 29 Jan 2013 08:19:29 -0300 Subject: [media] mceusb: make transmit work on the Philips IR transceiver The GET_REVISION command puts the device in an unresponsive state, although it continues to report any IR activity. Note that GET_REVISION command is not documented, nor is any possible response to it parsed. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 9afb933..14fea35 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -291,7 +291,8 @@ static struct usb_device_id mceusb_dev_table[] = { /* Philips/Spinel plus IR transceiver for ASUS */ { USB_DEVICE(VENDOR_PHILIPS, 0x2088) }, /* Philips IR transceiver (Dell branded) */ - { USB_DEVICE(VENDOR_PHILIPS, 0x2093) }, + { USB_DEVICE(VENDOR_PHILIPS, 0x2093), + .driver_info = MCE_GEN2_TX_INV }, /* Realtek MCE IR Receiver and card reader */ { USB_DEVICE(VENDOR_REALTEK, 0x0161), .driver_info = MULTIFUNCTION }, @@ -1121,16 +1122,13 @@ static void mceusb_gen1_init(struct mceusb_dev *ir) mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION)); kfree(data); -}; +} static void mceusb_gen2_init(struct mceusb_dev *ir) { /* device resume */ mce_async_out(ir, DEVICE_RESUME, sizeof(DEVICE_RESUME)); - /* get hw/sw revision? */ - mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION)); - /* get wake version (protocol, key, address) */ mce_async_out(ir, GET_WAKEVERSION, sizeof(GET_WAKEVERSION)); -- cgit v1.1 From db8ee1064c97879bff614d653158dff1894d2e37 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Tue, 29 Jan 2013 08:19:30 -0300 Subject: [media] mceusb: make transmit work on HP transceiver This transceiver expects the set IR TX ports and IR data as seperate packets, like the Windows driver does. Remove unnecessary kzalloc. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 14fea35..bdd1ed8 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -62,7 +62,6 @@ #define MCE_PACKET_SIZE 4 /* Normal length of packet (without header) */ #define MCE_IRDATA_HEADER 0x84 /* Actual header format is 0x80 + num_bytes */ #define MCE_IRDATA_TRAILER 0x80 /* End of IR data */ -#define MCE_TX_HEADER_LENGTH 3 /* # of bytes in the initializing tx header */ #define MCE_MAX_CHANNELS 2 /* Two transmitters, hardware dependent? */ #define MCE_DEFAULT_TX_MASK 0x03 /* Vals: TX1=0x01, TX2=0x02, ALL=0x03 */ #define MCE_PULSE_BIT 0x80 /* Pulse bit, MSB set == PULSE else SPACE */ @@ -366,7 +365,8 @@ static struct usb_device_id mceusb_dev_table[] = { /* Formosa Industrial Computing */ { USB_DEVICE(VENDOR_FORMOSA, 0xe042) }, /* Fintek eHome Infrared Transceiver (HP branded) */ - { USB_DEVICE(VENDOR_FINTEK, 0x5168) }, + { USB_DEVICE(VENDOR_FINTEK, 0x5168), + .driver_info = MCE_GEN2_TX_INV }, /* Fintek eHome Infrared Transceiver */ { USB_DEVICE(VENDOR_FINTEK, 0x0602) }, /* Fintek eHome Infrared Transceiver (in the AOpen MP45) */ @@ -789,19 +789,19 @@ static void mce_flush_rx_buffer(struct mceusb_dev *ir, int size) static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count) { struct mceusb_dev *ir = dev->priv; - int i, ret = 0; + int i, length, ret = 0; int cmdcount = 0; - unsigned char *cmdbuf; /* MCE command buffer */ - - cmdbuf = kzalloc(sizeof(unsigned) * MCE_CMDBUF_SIZE, GFP_KERNEL); - if (!cmdbuf) - return -ENOMEM; + unsigned char cmdbuf[MCE_CMDBUF_SIZE]; /* MCE tx init header */ cmdbuf[cmdcount++] = MCE_CMD_PORT_IR; cmdbuf[cmdcount++] = MCE_CMD_SETIRTXPORTS; cmdbuf[cmdcount++] = ir->tx_mask; + /* Send the set TX ports command */ + mce_async_out(ir, cmdbuf, cmdcount); + cmdcount = 0; + /* Generate mce packet data */ for (i = 0; (i < count) && (cmdcount < MCE_CMDBUF_SIZE); i++) { txbuf[i] = txbuf[i] / MCE_TIME_UNIT; @@ -810,8 +810,7 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count) /* Insert mce packet header every 4th entry */ if ((cmdcount < MCE_CMDBUF_SIZE) && - (cmdcount - MCE_TX_HEADER_LENGTH) % - MCE_CODE_LENGTH == 0) + (cmdcount % MCE_CODE_LENGTH) == 0) cmdbuf[cmdcount++] = MCE_IRDATA_HEADER; /* Insert mce packet data */ @@ -830,9 +829,8 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count) } /* Fix packet length in last header */ - cmdbuf[cmdcount - (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH] = - MCE_COMMAND_IRDATA + (cmdcount - MCE_TX_HEADER_LENGTH) % - MCE_CODE_LENGTH - 1; + length = cmdcount % MCE_CODE_LENGTH; + cmdbuf[cmdcount - length] -= MCE_CODE_LENGTH - length; /* Check if we have room for the empty packet at the end */ if (cmdcount >= MCE_CMDBUF_SIZE) { @@ -847,7 +845,6 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count) mce_async_out(ir, cmdbuf, cmdcount); out: - kfree(cmdbuf); return ret ? ret : count; } -- cgit v1.1 From 06eae25f162e2a0d9e60f0ad3ec3d14c738fbe68 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Tue, 29 Jan 2013 08:19:31 -0300 Subject: [media] redrat3: fix transmit return value and overrun If more than 127 different lengths are transmitted then the driver causes an overrun on sample_lens. Try to send as much as possible and return the amount sent. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/redrat3.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 1800326..1b37fe2 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -195,9 +195,6 @@ struct redrat3_dev { dma_addr_t dma_in; dma_addr_t dma_out; - /* locks this structure */ - struct mutex lock; - /* rx signal timeout timer */ struct timer_list rx_timeout; u32 hw_timeout; @@ -922,8 +919,7 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf, return -EAGAIN; } - if (count > (RR3_DRIVER_MAXLENS * 2)) - return -EINVAL; + count = min_t(unsigned, count, RR3_MAX_SIG_SIZE - RR3_TX_TRAILER_LEN); /* rr3 will disable rc detector on transmit */ rr3->det_enabled = false; @@ -936,24 +932,22 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf, } for (i = 0; i < count; i++) { + cur_sample_len = redrat3_us_to_len(txbuf[i]); for (lencheck = 0; lencheck < curlencheck; lencheck++) { - cur_sample_len = redrat3_us_to_len(txbuf[i]); if (sample_lens[lencheck] == cur_sample_len) break; } if (lencheck == curlencheck) { - cur_sample_len = redrat3_us_to_len(txbuf[i]); rr3_dbg(dev, "txbuf[%d]=%u, pos %d, enc %u\n", i, txbuf[i], curlencheck, cur_sample_len); - if (curlencheck < 255) { + if (curlencheck < RR3_DRIVER_MAXLENS) { /* now convert the value to a proper * rr3 value.. */ sample_lens[curlencheck] = cur_sample_len; curlencheck++; } else { - dev_err(dev, "signal too long\n"); - ret = -EINVAL; - goto out; + count = i - 1; + break; } } } @@ -1087,6 +1081,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3) rc->tx_ir = redrat3_transmit_ir; rc->s_tx_carrier = redrat3_set_tx_carrier; rc->driver_name = DRIVER_NAME; + rc->rx_resolution = US_TO_NS(2); rc->map_name = RC_MAP_HAUPPAUGE; ret = rc_register_device(rc); @@ -1202,7 +1197,6 @@ static int redrat3_dev_probe(struct usb_interface *intf, rr3->bulk_out_buf, ep_out->wMaxPacketSize, (usb_complete_t)redrat3_write_bulk_callback, rr3); - mutex_init(&rr3->lock); rr3->udev = udev; redrat3_reset(rr3); -- cgit v1.1 From b940a2219c9d59171339cc4510462154934fcb49 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 12 Feb 2013 08:22:08 -0300 Subject: [media] mceusb: move check earlier to make smatch happy Smatch complains that "cmdbuf[cmdcount - length]" might go past the end of the array. It's an easy warning to silence by moving the limit check earlier. Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index bdd1ed8..5b5b6e6 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -828,16 +828,16 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count) (txbuf[i] -= MCE_MAX_PULSE_LENGTH)); } - /* Fix packet length in last header */ - length = cmdcount % MCE_CODE_LENGTH; - cmdbuf[cmdcount - length] -= MCE_CODE_LENGTH - length; - /* Check if we have room for the empty packet at the end */ if (cmdcount >= MCE_CMDBUF_SIZE) { ret = -EINVAL; goto out; } + /* Fix packet length in last header */ + length = cmdcount % MCE_CODE_LENGTH; + cmdbuf[cmdcount - length] -= MCE_CODE_LENGTH - length; + /* All mce commands end with an empty packet (0x80) */ cmdbuf[cmdcount++] = MCE_IRDATA_TRAILER; -- cgit v1.1 From 2fd7f398d32a0d490d28de75b613263502918e51 Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Fri, 8 Feb 2013 18:47:30 -0300 Subject: [media] media: rc: gpio-ir-recv: add support for device tree parsing This patch adds device tree parsing for gpio_ir_recv platform_data and the mandatory binding documentation. It basically follows what we already have for e.g. gpio_keys. All required device tree properties are OS independent but an optional property allows linux specific support for rc maps. Signed-off-by: Sebastian Hesselbarth Reviewed-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/gpio-ir-recv.c | 52 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'drivers/media/rc') diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index 382f362..8b82ae9 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,45 @@ struct gpio_rc_dev { bool active_low; }; +#ifdef CONFIG_OF +/* + * Translate OpenFirmware node properties into platform_data + */ +static int gpio_ir_recv_get_devtree_pdata(struct device *dev, + struct gpio_ir_recv_platform_data *pdata) +{ + struct device_node *np = dev->of_node; + enum of_gpio_flags flags; + int gpio; + + gpio = of_get_gpio_flags(np, 0, &flags); + if (gpio < 0) { + if (gpio != -EPROBE_DEFER) + dev_err(dev, "Failed to get gpio flags (%d)\n", gpio); + return gpio; + } + + pdata->gpio_nr = gpio; + pdata->active_low = (flags & OF_GPIO_ACTIVE_LOW); + /* probe() takes care of map_name == NULL or allowed_protos == 0 */ + pdata->map_name = of_get_property(np, "linux,rc-map-name", NULL); + pdata->allowed_protos = 0; + + return 0; +} + +static struct of_device_id gpio_ir_recv_of_match[] = { + { .compatible = "gpio-ir-receiver", }, + { }, +}; +MODULE_DEVICE_TABLE(of, gpio_ir_recv_of_match); + +#else /* !CONFIG_OF */ + +#define gpio_ir_recv_get_devtree_pdata(dev, pdata) (-ENOSYS) + +#endif + static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id) { struct gpio_rc_dev *gpio_dev = dev_id; @@ -66,6 +106,17 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) pdev->dev.platform_data; int rc; + if (pdev->dev.of_node) { + struct gpio_ir_recv_platform_data *dtpdata = + devm_kzalloc(&pdev->dev, sizeof(*dtpdata), GFP_KERNEL); + if (!dtpdata) + return -ENOMEM; + rc = gpio_ir_recv_get_devtree_pdata(&pdev->dev, dtpdata); + if (rc) + return rc; + pdata = dtpdata; + } + if (!pdata) return -EINVAL; @@ -191,6 +242,7 @@ static struct platform_driver gpio_ir_recv_driver = { .driver = { .name = GPIO_IR_DRIVER_NAME, .owner = THIS_MODULE, + .of_match_table = of_match_ptr(gpio_ir_recv_of_match), #ifdef CONFIG_PM .pm = &gpio_ir_recv_pm_ops, #endif -- cgit v1.1