Commit 271002ca authored by Dmitry Torokhov's avatar Dmitry Torokhov

Input: xilinx_ps2 - allocate serio port separately

'struct serio' is a refcounted data structure with lifetime rules different
from 'struct xps2data'. It is quite likely that serio_unregister_port() will
try to free memory allocated by the port and that is why it should be
allocated separately.

Also switch to using platform_get/set_drvdata instead of dev_get/set_drvdata
because we are dealing with platform device.
Reported-by: default avatarTobias Klauser <tklauser@distanz.ch>
Signed-off-by: default avatarDmitry Torokhov <dtor@mail.ru>
parent 131c713f
...@@ -73,7 +73,8 @@ struct xps2data { ...@@ -73,7 +73,8 @@ struct xps2data {
spinlock_t lock; spinlock_t lock;
void __iomem *base_address; /* virt. address of control registers */ void __iomem *base_address; /* virt. address of control registers */
unsigned int flags; unsigned int flags;
struct serio serio; /* serio */ struct serio *serio; /* serio */
struct device *dev;
}; };
/************************************/ /************************************/
...@@ -119,7 +120,7 @@ static irqreturn_t xps2_interrupt(int irq, void *dev_id) ...@@ -119,7 +120,7 @@ static irqreturn_t xps2_interrupt(int irq, void *dev_id)
/* Check which interrupt is active */ /* Check which interrupt is active */
if (intr_sr & XPS2_IPIXR_RX_OVF) if (intr_sr & XPS2_IPIXR_RX_OVF)
dev_warn(drvdata->serio.dev.parent, "receive overrun error\n"); dev_warn(drvdata->dev, "receive overrun error\n");
if (intr_sr & XPS2_IPIXR_RX_ERR) if (intr_sr & XPS2_IPIXR_RX_ERR)
drvdata->flags |= SERIO_PARITY; drvdata->flags |= SERIO_PARITY;
...@@ -132,10 +133,10 @@ static irqreturn_t xps2_interrupt(int irq, void *dev_id) ...@@ -132,10 +133,10 @@ static irqreturn_t xps2_interrupt(int irq, void *dev_id)
/* Error, if a byte is not received */ /* Error, if a byte is not received */
if (status) { if (status) {
dev_err(drvdata->serio.dev.parent, dev_err(drvdata->dev,
"wrong rcvd byte count (%d)\n", status); "wrong rcvd byte count (%d)\n", status);
} else { } else {
serio_interrupt(&drvdata->serio, c, drvdata->flags); serio_interrupt(drvdata->serio, c, drvdata->flags);
drvdata->flags = 0; drvdata->flags = 0;
} }
} }
...@@ -193,7 +194,7 @@ static int sxps2_open(struct serio *pserio) ...@@ -193,7 +194,7 @@ static int sxps2_open(struct serio *pserio)
error = request_irq(drvdata->irq, &xps2_interrupt, 0, error = request_irq(drvdata->irq, &xps2_interrupt, 0,
DRIVER_NAME, drvdata); DRIVER_NAME, drvdata);
if (error) { if (error) {
dev_err(drvdata->serio.dev.parent, dev_err(drvdata->dev,
"Couldn't allocate interrupt %d\n", drvdata->irq); "Couldn't allocate interrupt %d\n", drvdata->irq);
return error; return error;
} }
...@@ -259,15 +260,16 @@ static int __devinit xps2_of_probe(struct platform_device *ofdev) ...@@ -259,15 +260,16 @@ static int __devinit xps2_of_probe(struct platform_device *ofdev)
} }
drvdata = kzalloc(sizeof(struct xps2data), GFP_KERNEL); drvdata = kzalloc(sizeof(struct xps2data), GFP_KERNEL);
if (!drvdata) { serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
dev_err(dev, "Couldn't allocate device private record\n"); if (!drvdata || !serio) {
return -ENOMEM; error = -ENOMEM;
goto failed1;
} }
dev_set_drvdata(dev, drvdata);
spin_lock_init(&drvdata->lock); spin_lock_init(&drvdata->lock);
drvdata->irq = r_irq.start; drvdata->irq = r_irq.start;
drvdata->serio = serio;
drvdata->dev = dev;
phys_addr = r_mem.start; phys_addr = r_mem.start;
remap_size = resource_size(&r_mem); remap_size = resource_size(&r_mem);
...@@ -298,7 +300,6 @@ static int __devinit xps2_of_probe(struct platform_device *ofdev) ...@@ -298,7 +300,6 @@ static int __devinit xps2_of_probe(struct platform_device *ofdev)
(unsigned long long)phys_addr, drvdata->base_address, (unsigned long long)phys_addr, drvdata->base_address,
drvdata->irq); drvdata->irq);
serio = &drvdata->serio;
serio->id.type = SERIO_8042; serio->id.type = SERIO_8042;
serio->write = sxps2_write; serio->write = sxps2_write;
serio->open = sxps2_open; serio->open = sxps2_open;
...@@ -312,13 +313,14 @@ static int __devinit xps2_of_probe(struct platform_device *ofdev) ...@@ -312,13 +313,14 @@ static int __devinit xps2_of_probe(struct platform_device *ofdev)
serio_register_port(serio); serio_register_port(serio);
platform_set_drvdata(ofdev, drvdata);
return 0; /* success */ return 0; /* success */
failed2: failed2:
release_mem_region(phys_addr, remap_size); release_mem_region(phys_addr, remap_size);
failed1: failed1:
kfree(serio);
kfree(drvdata); kfree(drvdata);
dev_set_drvdata(dev, NULL);
return error; return error;
} }
...@@ -333,22 +335,21 @@ static int __devinit xps2_of_probe(struct platform_device *ofdev) ...@@ -333,22 +335,21 @@ static int __devinit xps2_of_probe(struct platform_device *ofdev)
*/ */
static int __devexit xps2_of_remove(struct platform_device *of_dev) static int __devexit xps2_of_remove(struct platform_device *of_dev)
{ {
struct device *dev = &of_dev->dev; struct xps2data *drvdata = platform_get_drvdata(of_dev);
struct xps2data *drvdata = dev_get_drvdata(dev);
struct resource r_mem; /* IO mem resources */ struct resource r_mem; /* IO mem resources */
serio_unregister_port(&drvdata->serio); serio_unregister_port(drvdata->serio);
iounmap(drvdata->base_address); iounmap(drvdata->base_address);
/* Get iospace of the device */ /* Get iospace of the device */
if (of_address_to_resource(of_dev->dev.of_node, 0, &r_mem)) if (of_address_to_resource(of_dev->dev.of_node, 0, &r_mem))
dev_err(dev, "invalid address\n"); dev_err(drvdata->dev, "invalid address\n");
else else
release_mem_region(r_mem.start, resource_size(&r_mem)); release_mem_region(r_mem.start, resource_size(&r_mem));
kfree(drvdata); kfree(drvdata);
dev_set_drvdata(dev, NULL); platform_set_drvdata(of_dev, NULL);
return 0; return 0;
} }
......
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