diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2007-07-28 01:31:46 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-07-30 03:27:33 -0400 |
commit | c7f439b99efbea74c70a5531f92566db5a6731f2 (patch) | |
tree | 7053ceffa23d54670862e14d0bc2eec9d5d42427 /drivers/video/p9100.c | |
parent | a0afaa6ab12cf696d170c22a8fdfd88c3e33555c (diff) |
[VIDEO]: Fix OOPS in all SBUS framebuffer drivers.
All of these drivers use a silly:
struct all_info {
struct fb_info info;
struct foo_par par;
};
struct all_info *all = kzalloc(sizeof(*all), GFP_KERNEL);
all->info.par = &all->par;
etc. etc. code sequence, basically replicating the provided
framebuffer_alloc()/framebuffer_release(), and doing it badly.
Not only is this massive code duplication, it also caused a
bug in that we weren't setting the fb_info->device pointer
which results in an OOPS when fb_is_primary_device() runs.
Fix all of this by using framebuffer_{alloc,release}() and
passing in "&of_device->dev" as the device pointer.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/video/p9100.c')
-rw-r--r-- | drivers/video/p9100.c | 138 |
1 files changed, 63 insertions, 75 deletions
diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c index 637b78bb4bf7..58496061142d 100644 --- a/drivers/video/p9100.c +++ b/drivers/video/p9100.c | |||
@@ -255,107 +255,95 @@ static void p9100_init_fix(struct fb_info *info, int linebytes, struct device_no | |||
255 | info->fix.accel = FB_ACCEL_SUN_CGTHREE; | 255 | info->fix.accel = FB_ACCEL_SUN_CGTHREE; |
256 | } | 256 | } |
257 | 257 | ||
258 | struct all_info { | 258 | static int __devinit p9100_probe(struct of_device *op, const struct of_device_id *match) |
259 | struct fb_info info; | ||
260 | struct p9100_par par; | ||
261 | }; | ||
262 | |||
263 | static int __devinit p9100_init_one(struct of_device *op) | ||
264 | { | 259 | { |
265 | struct device_node *dp = op->node; | 260 | struct device_node *dp = op->node; |
266 | struct all_info *all; | 261 | struct fb_info *info; |
262 | struct p9100_par *par; | ||
267 | int linebytes, err; | 263 | int linebytes, err; |
268 | 264 | ||
269 | all = kzalloc(sizeof(*all), GFP_KERNEL); | 265 | info = framebuffer_alloc(sizeof(struct p9100_par), &op->dev); |
270 | if (!all) | 266 | |
271 | return -ENOMEM; | 267 | err = -ENOMEM; |
268 | if (!info) | ||
269 | goto out_err; | ||
270 | par = info->par; | ||
272 | 271 | ||
273 | spin_lock_init(&all->par.lock); | 272 | spin_lock_init(&par->lock); |
274 | 273 | ||
275 | /* This is the framebuffer and the only resource apps can mmap. */ | 274 | /* This is the framebuffer and the only resource apps can mmap. */ |
276 | all->par.physbase = op->resource[2].start; | 275 | par->physbase = op->resource[2].start; |
277 | all->par.which_io = op->resource[2].flags & IORESOURCE_BITS; | 276 | par->which_io = op->resource[2].flags & IORESOURCE_BITS; |
278 | |||
279 | sbusfb_fill_var(&all->info.var, dp->node, 8); | ||
280 | all->info.var.red.length = 8; | ||
281 | all->info.var.green.length = 8; | ||
282 | all->info.var.blue.length = 8; | ||
283 | |||
284 | linebytes = of_getintprop_default(dp, "linebytes", | ||
285 | all->info.var.xres); | ||
286 | all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); | ||
287 | |||
288 | all->par.regs = of_ioremap(&op->resource[0], 0, | ||
289 | sizeof(struct p9100_regs), "p9100 regs"); | ||
290 | if (!all->par.regs) { | ||
291 | kfree(all); | ||
292 | return -ENOMEM; | ||
293 | } | ||
294 | 277 | ||
295 | all->info.flags = FBINFO_DEFAULT; | 278 | sbusfb_fill_var(&info->var, dp->node, 8); |
296 | all->info.fbops = &p9100_ops; | 279 | info->var.red.length = 8; |
297 | all->info.screen_base = of_ioremap(&op->resource[2], 0, | 280 | info->var.green.length = 8; |
298 | all->par.fbsize, "p9100 ram"); | 281 | info->var.blue.length = 8; |
299 | if (!all->info.screen_base) { | ||
300 | of_iounmap(&op->resource[0], | ||
301 | all->par.regs, sizeof(struct p9100_regs)); | ||
302 | kfree(all); | ||
303 | return -ENOMEM; | ||
304 | } | ||
305 | all->info.par = &all->par; | ||
306 | 282 | ||
307 | p9100_blank(0, &all->info); | 283 | linebytes = of_getintprop_default(dp, "linebytes", info->var.xres); |
284 | par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); | ||
308 | 285 | ||
309 | if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { | 286 | par->regs = of_ioremap(&op->resource[0], 0, |
310 | of_iounmap(&op->resource[0], | 287 | sizeof(struct p9100_regs), "p9100 regs"); |
311 | all->par.regs, sizeof(struct p9100_regs)); | 288 | if (!par->regs) |
312 | of_iounmap(&op->resource[2], | 289 | goto out_release_fb; |
313 | all->info.screen_base, all->par.fbsize); | ||
314 | kfree(all); | ||
315 | return -ENOMEM; | ||
316 | } | ||
317 | 290 | ||
318 | p9100_init_fix(&all->info, linebytes, dp); | 291 | info->flags = FBINFO_DEFAULT; |
319 | 292 | info->fbops = &p9100_ops; | |
320 | err = register_framebuffer(&all->info); | 293 | info->screen_base = of_ioremap(&op->resource[2], 0, |
321 | if (err < 0) { | 294 | par->fbsize, "p9100 ram"); |
322 | fb_dealloc_cmap(&all->info.cmap); | 295 | if (!info->screen_base) |
323 | of_iounmap(&op->resource[0], | 296 | goto out_unmap_regs; |
324 | all->par.regs, sizeof(struct p9100_regs)); | 297 | |
325 | of_iounmap(&op->resource[2], | 298 | p9100_blank(0, info); |
326 | all->info.screen_base, all->par.fbsize); | 299 | |
327 | kfree(all); | 300 | if (fb_alloc_cmap(&info->cmap, 256, 0)) |
328 | return err; | 301 | goto out_unmap_screen; |
329 | } | ||
330 | fb_set_cmap(&all->info.cmap, &all->info); | ||
331 | 302 | ||
332 | dev_set_drvdata(&op->dev, all); | 303 | p9100_init_fix(info, linebytes, dp); |
304 | |||
305 | err = register_framebuffer(info); | ||
306 | if (err < 0) | ||
307 | goto out_dealloc_cmap; | ||
308 | |||
309 | fb_set_cmap(&info->cmap, info); | ||
310 | |||
311 | dev_set_drvdata(&op->dev, info); | ||
333 | 312 | ||
334 | printk("%s: p9100 at %lx:%lx\n", | 313 | printk("%s: p9100 at %lx:%lx\n", |
335 | dp->full_name, | 314 | dp->full_name, |
336 | all->par.which_io, all->par.physbase); | 315 | par->which_io, par->physbase); |
337 | 316 | ||
338 | return 0; | 317 | return 0; |
339 | } | ||
340 | 318 | ||
341 | static int __devinit p9100_probe(struct of_device *dev, const struct of_device_id *match) | 319 | out_dealloc_cmap: |
342 | { | 320 | fb_dealloc_cmap(&info->cmap); |
343 | struct of_device *op = to_of_device(&dev->dev); | 321 | |
322 | out_unmap_screen: | ||
323 | of_iounmap(&op->resource[2], info->screen_base, par->fbsize); | ||
324 | |||
325 | out_unmap_regs: | ||
326 | of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs)); | ||
327 | |||
328 | out_release_fb: | ||
329 | framebuffer_release(info); | ||
344 | 330 | ||
345 | return p9100_init_one(op); | 331 | out_err: |
332 | return err; | ||
346 | } | 333 | } |
347 | 334 | ||
348 | static int __devexit p9100_remove(struct of_device *op) | 335 | static int __devexit p9100_remove(struct of_device *op) |
349 | { | 336 | { |
350 | struct all_info *all = dev_get_drvdata(&op->dev); | 337 | struct fb_info *info = dev_get_drvdata(&op->dev); |
338 | struct p9100_par *par = info->par; | ||
351 | 339 | ||
352 | unregister_framebuffer(&all->info); | 340 | unregister_framebuffer(info); |
353 | fb_dealloc_cmap(&all->info.cmap); | 341 | fb_dealloc_cmap(&info->cmap); |
354 | 342 | ||
355 | of_iounmap(&op->resource[0], all->par.regs, sizeof(struct p9100_regs)); | 343 | of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs)); |
356 | of_iounmap(&op->resource[2], all->info.screen_base, all->par.fbsize); | 344 | of_iounmap(&op->resource[2], info->screen_base, par->fbsize); |
357 | 345 | ||
358 | kfree(all); | 346 | framebuffer_release(info); |
359 | 347 | ||
360 | dev_set_drvdata(&op->dev, NULL); | 348 | dev_set_drvdata(&op->dev, NULL); |
361 | 349 | ||