Commit 9fa35204 authored by Matthijs Kooijman's avatar Matthijs Kooijman Committed by Mauro Carvalho Chehab

[media] rc: Call rc_register_device before irq setup

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 <jarod@redhat.com>
Cc: Maxim Levitsky <maximlevitsky@gmail.com>
Cc: David Härdeman <david@hardeman.nu>
Signed-off-by: default avatarMatthijs Kooijman <matthijs@stdin.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent d62b6818
...@@ -1075,10 +1075,14 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) ...@@ -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_capable(&pnp_dev->dev, true);
device_set_wakeup_enable(&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 */ /* claim the resources */
error = -EBUSY; error = -EBUSY;
if (!request_region(dev->hw_io, ENE_IO_SIZE, ENE_DRIVER_NAME)) { 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); 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) ...@@ -1087,17 +1091,13 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
goto exit_release_hw_io; 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"); pr_notice("driver has been successfully loaded\n");
return 0; return 0;
exit_free_irq:
free_irq(dev->irq, dev);
exit_release_hw_io: exit_release_hw_io:
release_region(dev->hw_io, ENE_IO_SIZE); release_region(dev->hw_io, ENE_IO_SIZE);
exit_unregister_device:
rc_unregister_device(rdev);
exit_free_dev_rdev: exit_free_dev_rdev:
rc_free_device(rdev); rc_free_device(rdev);
kfree(dev); kfree(dev);
......
...@@ -1591,28 +1591,28 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id ...@@ -1591,28 +1591,28 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
rdev->driver_name = ITE_DRIVER_NAME; rdev->driver_name = ITE_DRIVER_NAME;
rdev->map_name = RC_MAP_RC6_MCE; rdev->map_name = RC_MAP_RC6_MCE;
ret = rc_register_device(rdev);
if (ret)
goto exit_free_dev_rdev;
ret = -EBUSY; ret = -EBUSY;
/* now claim resources */ /* now claim resources */
if (!request_region(itdev->cir_addr, if (!request_region(itdev->cir_addr,
dev_desc->io_region_size, ITE_DRIVER_NAME)) 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, if (request_irq(itdev->cir_irq, ite_cir_isr, IRQF_SHARED,
ITE_DRIVER_NAME, (void *)itdev)) ITE_DRIVER_NAME, (void *)itdev))
goto exit_release_cir_addr; 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"); ite_pr(KERN_NOTICE, "driver has been successfully loaded\n");
return 0; return 0;
exit_free_irq:
free_irq(itdev->cir_irq, itdev);
exit_release_cir_addr: exit_release_cir_addr:
release_region(itdev->cir_addr, itdev->params.io_region_size); release_region(itdev->cir_addr, itdev->params.io_region_size);
exit_unregister_device:
rc_unregister_device(rdev);
exit_free_dev_rdev: exit_free_dev_rdev:
rc_free_device(rdev); rc_free_device(rdev);
kfree(itdev); kfree(itdev);
......
...@@ -1067,11 +1067,15 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) ...@@ -1067,11 +1067,15 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
#endif #endif
nvt->rdev = rdev; nvt->rdev = rdev;
ret = rc_register_device(rdev);
if (ret)
goto exit_free_dev_rdev;
ret = -EBUSY; ret = -EBUSY;
/* now claim resources */ /* now claim resources */
if (!request_region(nvt->cir_addr, if (!request_region(nvt->cir_addr,
CIR_IOREG_LENGTH, NVT_DRIVER_NAME)) 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, if (request_irq(nvt->cir_irq, nvt_cir_isr, IRQF_SHARED,
NVT_DRIVER_NAME, (void *)nvt)) NVT_DRIVER_NAME, (void *)nvt))
...@@ -1085,10 +1089,6 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) ...@@ -1085,10 +1089,6 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
NVT_DRIVER_NAME, (void *)nvt)) NVT_DRIVER_NAME, (void *)nvt))
goto exit_release_cir_wake_addr; goto exit_release_cir_wake_addr;
ret = rc_register_device(rdev);
if (ret)
goto exit_free_wake_irq;
device_init_wakeup(&pdev->dev, true); device_init_wakeup(&pdev->dev, true);
nvt_pr(KERN_NOTICE, "driver has been successfully loaded\n"); 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) ...@@ -1099,14 +1099,14 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
return 0; return 0;
exit_free_wake_irq:
free_irq(nvt->cir_wake_irq, nvt);
exit_release_cir_wake_addr: exit_release_cir_wake_addr:
release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH); release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH);
exit_free_irq: exit_free_irq:
free_irq(nvt->cir_irq, nvt); free_irq(nvt->cir_irq, nvt);
exit_release_cir_addr: exit_release_cir_addr:
release_region(nvt->cir_addr, CIR_IOREG_LENGTH); release_region(nvt->cir_addr, CIR_IOREG_LENGTH);
exit_unregister_device:
rc_unregister_device(rdev);
exit_free_dev_rdev: exit_free_dev_rdev:
rc_free_device(rdev); rc_free_device(rdev);
kfree(nvt); kfree(nvt);
......
...@@ -1093,11 +1093,15 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id) ...@@ -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->rx_resolution = US_TO_NS(2);
data->dev->allowed_protos = RC_BIT_ALL; 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)) { if (!request_region(data->wbase, WAKEUP_IOMEM_LEN, DRVNAME)) {
dev_err(dev, "Region 0x%lx-0x%lx already in use!\n", dev_err(dev, "Region 0x%lx-0x%lx already in use!\n",
data->wbase, data->wbase + WAKEUP_IOMEM_LEN - 1); data->wbase, data->wbase + WAKEUP_IOMEM_LEN - 1);
err = -EBUSY; err = -EBUSY;
goto exit_free_rc; goto exit_unregister_device;
} }
if (!request_region(data->ebase, EHFUNC_IOMEM_LEN, DRVNAME)) { 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) ...@@ -1122,24 +1126,20 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
goto exit_release_sbase; goto exit_release_sbase;
} }
err = rc_register_device(data->dev);
if (err)
goto exit_free_irq;
device_init_wakeup(&device->dev, 1); device_init_wakeup(&device->dev, 1);
wbcir_init_hw(data); wbcir_init_hw(data);
return 0; return 0;
exit_free_irq:
free_irq(data->irq, device);
exit_release_sbase: exit_release_sbase:
release_region(data->sbase, SP_IOMEM_LEN); release_region(data->sbase, SP_IOMEM_LEN);
exit_release_ebase: exit_release_ebase:
release_region(data->ebase, EHFUNC_IOMEM_LEN); release_region(data->ebase, EHFUNC_IOMEM_LEN);
exit_release_wbase: exit_release_wbase:
release_region(data->wbase, WAKEUP_IOMEM_LEN); release_region(data->wbase, WAKEUP_IOMEM_LEN);
exit_unregister_device:
rc_unregister_device(data->dev);
exit_free_rc: exit_free_rc:
rc_free_device(data->dev); rc_free_device(data->dev);
exit_unregister_led: exit_unregister_led:
......
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