diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2012-03-25 20:23:19 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2012-04-03 12:57:11 -0400 |
commit | 271002ca7956e5ef140c02af1bd8e93063924ec6 (patch) | |
tree | 23672b4bdbdcb3d651f6a7ec9e0c652287fc6d09 /drivers/input | |
parent | 131c713fd96e251fcb18f4d2d05f263aa41bb11f (diff) |
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: Tobias Klauser <tklauser@distanz.ch>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/serio/xilinx_ps2.c | 35 |
1 files changed, 18 insertions, 17 deletions
diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c index d96d4c2a76a9..1e983bec7d86 100644 --- a/drivers/input/serio/xilinx_ps2.c +++ b/drivers/input/serio/xilinx_ps2.c | |||
@@ -73,7 +73,8 @@ struct xps2data { | |||
73 | spinlock_t lock; | 73 | spinlock_t lock; |
74 | void __iomem *base_address; /* virt. address of control registers */ | 74 | void __iomem *base_address; /* virt. address of control registers */ |
75 | unsigned int flags; | 75 | unsigned int flags; |
76 | struct serio serio; /* serio */ | 76 | struct serio *serio; /* serio */ |
77 | struct device *dev; | ||
77 | }; | 78 | }; |
78 | 79 | ||
79 | /************************************/ | 80 | /************************************/ |
@@ -119,7 +120,7 @@ static irqreturn_t xps2_interrupt(int irq, void *dev_id) | |||
119 | 120 | ||
120 | /* Check which interrupt is active */ | 121 | /* Check which interrupt is active */ |
121 | if (intr_sr & XPS2_IPIXR_RX_OVF) | 122 | if (intr_sr & XPS2_IPIXR_RX_OVF) |
122 | dev_warn(drvdata->serio.dev.parent, "receive overrun error\n"); | 123 | dev_warn(drvdata->dev, "receive overrun error\n"); |
123 | 124 | ||
124 | if (intr_sr & XPS2_IPIXR_RX_ERR) | 125 | if (intr_sr & XPS2_IPIXR_RX_ERR) |
125 | drvdata->flags |= SERIO_PARITY; | 126 | drvdata->flags |= SERIO_PARITY; |
@@ -132,10 +133,10 @@ static irqreturn_t xps2_interrupt(int irq, void *dev_id) | |||
132 | 133 | ||
133 | /* Error, if a byte is not received */ | 134 | /* Error, if a byte is not received */ |
134 | if (status) { | 135 | if (status) { |
135 | dev_err(drvdata->serio.dev.parent, | 136 | dev_err(drvdata->dev, |
136 | "wrong rcvd byte count (%d)\n", status); | 137 | "wrong rcvd byte count (%d)\n", status); |
137 | } else { | 138 | } else { |
138 | serio_interrupt(&drvdata->serio, c, drvdata->flags); | 139 | serio_interrupt(drvdata->serio, c, drvdata->flags); |
139 | drvdata->flags = 0; | 140 | drvdata->flags = 0; |
140 | } | 141 | } |
141 | } | 142 | } |
@@ -193,7 +194,7 @@ static int sxps2_open(struct serio *pserio) | |||
193 | error = request_irq(drvdata->irq, &xps2_interrupt, 0, | 194 | error = request_irq(drvdata->irq, &xps2_interrupt, 0, |
194 | DRIVER_NAME, drvdata); | 195 | DRIVER_NAME, drvdata); |
195 | if (error) { | 196 | if (error) { |
196 | dev_err(drvdata->serio.dev.parent, | 197 | dev_err(drvdata->dev, |
197 | "Couldn't allocate interrupt %d\n", drvdata->irq); | 198 | "Couldn't allocate interrupt %d\n", drvdata->irq); |
198 | return error; | 199 | return error; |
199 | } | 200 | } |
@@ -259,15 +260,16 @@ static int __devinit xps2_of_probe(struct platform_device *ofdev) | |||
259 | } | 260 | } |
260 | 261 | ||
261 | drvdata = kzalloc(sizeof(struct xps2data), GFP_KERNEL); | 262 | drvdata = kzalloc(sizeof(struct xps2data), GFP_KERNEL); |
262 | if (!drvdata) { | 263 | serio = kzalloc(sizeof(struct serio), GFP_KERNEL); |
263 | dev_err(dev, "Couldn't allocate device private record\n"); | 264 | if (!drvdata || !serio) { |
264 | return -ENOMEM; | 265 | error = -ENOMEM; |
266 | goto failed1; | ||
265 | } | 267 | } |
266 | 268 | ||
267 | dev_set_drvdata(dev, drvdata); | ||
268 | |||
269 | spin_lock_init(&drvdata->lock); | 269 | spin_lock_init(&drvdata->lock); |
270 | drvdata->irq = r_irq.start; | 270 | drvdata->irq = r_irq.start; |
271 | drvdata->serio = serio; | ||
272 | drvdata->dev = dev; | ||
271 | 273 | ||
272 | phys_addr = r_mem.start; | 274 | phys_addr = r_mem.start; |
273 | remap_size = resource_size(&r_mem); | 275 | remap_size = resource_size(&r_mem); |
@@ -298,7 +300,6 @@ static int __devinit xps2_of_probe(struct platform_device *ofdev) | |||
298 | (unsigned long long)phys_addr, drvdata->base_address, | 300 | (unsigned long long)phys_addr, drvdata->base_address, |
299 | drvdata->irq); | 301 | drvdata->irq); |
300 | 302 | ||
301 | serio = &drvdata->serio; | ||
302 | serio->id.type = SERIO_8042; | 303 | serio->id.type = SERIO_8042; |
303 | serio->write = sxps2_write; | 304 | serio->write = sxps2_write; |
304 | serio->open = sxps2_open; | 305 | serio->open = sxps2_open; |
@@ -312,13 +313,14 @@ static int __devinit xps2_of_probe(struct platform_device *ofdev) | |||
312 | 313 | ||
313 | serio_register_port(serio); | 314 | serio_register_port(serio); |
314 | 315 | ||
316 | platform_set_drvdata(ofdev, drvdata); | ||
315 | return 0; /* success */ | 317 | return 0; /* success */ |
316 | 318 | ||
317 | failed2: | 319 | failed2: |
318 | release_mem_region(phys_addr, remap_size); | 320 | release_mem_region(phys_addr, remap_size); |
319 | failed1: | 321 | failed1: |
322 | kfree(serio); | ||
320 | kfree(drvdata); | 323 | kfree(drvdata); |
321 | dev_set_drvdata(dev, NULL); | ||
322 | 324 | ||
323 | return error; | 325 | return error; |
324 | } | 326 | } |
@@ -333,22 +335,21 @@ failed1: | |||
333 | */ | 335 | */ |
334 | static int __devexit xps2_of_remove(struct platform_device *of_dev) | 336 | static int __devexit xps2_of_remove(struct platform_device *of_dev) |
335 | { | 337 | { |
336 | struct device *dev = &of_dev->dev; | 338 | struct xps2data *drvdata = platform_get_drvdata(of_dev); |
337 | struct xps2data *drvdata = dev_get_drvdata(dev); | ||
338 | struct resource r_mem; /* IO mem resources */ | 339 | struct resource r_mem; /* IO mem resources */ |
339 | 340 | ||
340 | serio_unregister_port(&drvdata->serio); | 341 | serio_unregister_port(drvdata->serio); |
341 | iounmap(drvdata->base_address); | 342 | iounmap(drvdata->base_address); |
342 | 343 | ||
343 | /* Get iospace of the device */ | 344 | /* Get iospace of the device */ |
344 | if (of_address_to_resource(of_dev->dev.of_node, 0, &r_mem)) | 345 | if (of_address_to_resource(of_dev->dev.of_node, 0, &r_mem)) |
345 | dev_err(dev, "invalid address\n"); | 346 | dev_err(drvdata->dev, "invalid address\n"); |
346 | else | 347 | else |
347 | release_mem_region(r_mem.start, resource_size(&r_mem)); | 348 | release_mem_region(r_mem.start, resource_size(&r_mem)); |
348 | 349 | ||
349 | kfree(drvdata); | 350 | kfree(drvdata); |
350 | 351 | ||
351 | dev_set_drvdata(dev, NULL); | 352 | platform_set_drvdata(of_dev, NULL); |
352 | 353 | ||
353 | return 0; | 354 | return 0; |
354 | } | 355 | } |