aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKristian Høgsberg <krh@redhat.com>2007-03-07 12:12:44 -0500
committerStefan Richter <stefanr@s5r6.in-berlin.de>2007-03-09 16:03:09 -0500
commita3aca3dabbcf00f2088d472f27755c29acaa992e (patch)
treec6b23c1d51a7eab5bee4137d344264974ddfc432
parent344bbc4de14e70d03f09bff04bb7d161b8a0d28c (diff)
firewire: Switch cdev code over to use register_chrdev and keep a list of devices.
The old mechanism kept a struct cdev for each fw device, but fops->release would reference this struct after the device got freed in some cases. Signed-off-by: Kristian Høgsberg <krh@redhat.com> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
-rw-r--r--drivers/firewire/fw-device-cdev.c5
-rw-r--r--drivers/firewire/fw-device.c56
-rw-r--r--drivers/firewire/fw-device.h5
-rw-r--r--drivers/firewire/fw-transaction.c7
4 files changed, 51 insertions, 22 deletions
diff --git a/drivers/firewire/fw-device-cdev.c b/drivers/firewire/fw-device-cdev.c
index d9f3bb2be1c2..54ef27b2adb5 100644
--- a/drivers/firewire/fw-device-cdev.c
+++ b/drivers/firewire/fw-device-cdev.c
@@ -28,6 +28,7 @@
28#include <linux/poll.h> 28#include <linux/poll.h>
29#include <linux/delay.h> 29#include <linux/delay.h>
30#include <linux/mm.h> 30#include <linux/mm.h>
31#include <linux/idr.h>
31#include <linux/compat.h> 32#include <linux/compat.h>
32#include <asm/uaccess.h> 33#include <asm/uaccess.h>
33#include "fw-transaction.h" 34#include "fw-transaction.h"
@@ -103,7 +104,9 @@ static int fw_device_op_open(struct inode *inode, struct file *file)
103 struct client *client; 104 struct client *client;
104 unsigned long flags; 105 unsigned long flags;
105 106
106 device = container_of(inode->i_cdev, struct fw_device, cdev); 107 device = fw_device_from_devt(inode->i_rdev);
108 if (device == NULL)
109 return -ENODEV;
107 110
108 client = kzalloc(sizeof *client, GFP_KERNEL); 111 client = kzalloc(sizeof *client, GFP_KERNEL);
109 if (client == NULL) 112 if (client == NULL)
diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c
index ccc05e511a4f..b24090ae9c70 100644
--- a/drivers/firewire/fw-device.c
+++ b/drivers/firewire/fw-device.c
@@ -25,6 +25,7 @@
25#include <linux/kthread.h> 25#include <linux/kthread.h>
26#include <linux/device.h> 26#include <linux/device.h>
27#include <linux/delay.h> 27#include <linux/delay.h>
28#include <linux/idr.h>
28#include "fw-transaction.h" 29#include "fw-transaction.h"
29#include "fw-topology.h" 30#include "fw-topology.h"
30#include "fw-device.h" 31#include "fw-device.h"
@@ -407,14 +408,31 @@ static int shutdown_unit(struct device *device, void *data)
407 return 0; 408 return 0;
408} 409}
409 410
411static DEFINE_IDR(fw_device_idr);
412int fw_cdev_major;
413
414struct fw_device *fw_device_from_devt(dev_t devt)
415{
416 struct fw_device *device;
417
418 down_read(&fw_bus_type.subsys.rwsem);
419 device = idr_find(&fw_device_idr, MINOR(devt));
420 up_read(&fw_bus_type.subsys.rwsem);
421
422 return device;
423}
424
410static void fw_device_shutdown(struct work_struct *work) 425static void fw_device_shutdown(struct work_struct *work)
411{ 426{
412 struct fw_device *device = 427 struct fw_device *device =
413 container_of(work, struct fw_device, work.work); 428 container_of(work, struct fw_device, work.work);
429 int minor = MINOR(device->device.devt);
430
431 down_write(&fw_bus_type.subsys.rwsem);
432 idr_remove(&fw_device_idr, minor);
433 up_write(&fw_bus_type.subsys.rwsem);
414 434
415 device_remove_file(&device->device, &config_rom_attribute); 435 device_remove_file(&device->device, &config_rom_attribute);
416 cdev_del(&device->cdev);
417 unregister_chrdev_region(device->device.devt, 1);
418 device_for_each_child(&device->device, NULL, shutdown_unit); 436 device_for_each_child(&device->device, NULL, shutdown_unit);
419 device_unregister(&device->device); 437 device_unregister(&device->device);
420} 438}
@@ -434,9 +452,9 @@ static void fw_device_shutdown(struct work_struct *work)
434 452
435static void fw_device_init(struct work_struct *work) 453static void fw_device_init(struct work_struct *work)
436{ 454{
437 static atomic_t serial = ATOMIC_INIT(-1);
438 struct fw_device *device = 455 struct fw_device *device =
439 container_of(work, struct fw_device, work.work); 456 container_of(work, struct fw_device, work.work);
457 int minor, err;
440 458
441 /* All failure paths here set node->data to NULL, so that we 459 /* All failure paths here set node->data to NULL, so that we
442 * don't try to do device_for_each_child() on a kfree()'d 460 * don't try to do device_for_each_child() on a kfree()'d
@@ -456,28 +474,24 @@ static void fw_device_init(struct work_struct *work)
456 return; 474 return;
457 } 475 }
458 476
477 err = -ENOMEM;
478 down_write(&fw_bus_type.subsys.rwsem);
479 if (idr_pre_get(&fw_device_idr, GFP_KERNEL))
480 err = idr_get_new(&fw_device_idr, device, &minor);
481 up_write(&fw_bus_type.subsys.rwsem);
482 if (err < 0)
483 goto error;
484
459 device->device.bus = &fw_bus_type; 485 device->device.bus = &fw_bus_type;
460 device->device.release = fw_device_release; 486 device->device.release = fw_device_release;
461 device->device.parent = device->card->device; 487 device->device.parent = device->card->device;
488 device->device.devt = MKDEV(fw_cdev_major, minor);
462 snprintf(device->device.bus_id, sizeof device->device.bus_id, 489 snprintf(device->device.bus_id, sizeof device->device.bus_id,
463 "fw%d", atomic_inc_return(&serial)); 490 "fw%d", minor);
464
465 if (alloc_chrdev_region(&device->device.devt, 0, 1, "fw")) {
466 fw_error("Failed to register char device region.\n");
467 goto error;
468 }
469
470 cdev_init(&device->cdev, &fw_device_ops);
471 device->cdev.owner = THIS_MODULE;
472 kobject_set_name(&device->cdev.kobj, device->device.bus_id);
473 if (cdev_add(&device->cdev, device->device.devt, 1)) {
474 fw_error("Failed to register char device.\n");
475 goto error;
476 }
477 491
478 if (device_add(&device->device)) { 492 if (device_add(&device->device)) {
479 fw_error("Failed to add device.\n"); 493 fw_error("Failed to add device.\n");
480 goto error; 494 goto error_with_cdev;
481 } 495 }
482 496
483 if (device_create_file(&device->device, &config_rom_attribute) < 0) { 497 if (device_create_file(&device->device, &config_rom_attribute) < 0) {
@@ -513,9 +527,11 @@ static void fw_device_init(struct work_struct *work)
513 527
514 error_with_device: 528 error_with_device:
515 device_del(&device->device); 529 device_del(&device->device);
530 error_with_cdev:
531 down_write(&fw_bus_type.subsys.rwsem);
532 idr_remove(&fw_device_idr, minor);
533 up_write(&fw_bus_type.subsys.rwsem);
516 error: 534 error:
517 cdev_del(&device->cdev);
518 unregister_chrdev_region(device->device.devt, 1);
519 put_device(&device->device); 535 put_device(&device->device);
520} 536}
521 537
diff --git a/drivers/firewire/fw-device.h b/drivers/firewire/fw-device.h
index 4f731c2b121c..1a3655bea335 100644
--- a/drivers/firewire/fw-device.h
+++ b/drivers/firewire/fw-device.h
@@ -39,7 +39,7 @@ struct fw_device {
39 int generation; 39 int generation;
40 struct fw_card *card; 40 struct fw_card *card;
41 struct device device; 41 struct device device;
42 struct cdev cdev; 42 struct list_head link;
43 struct list_head client_list; 43 struct list_head client_list;
44 __be32 *config_rom; 44 __be32 *config_rom;
45 size_t config_rom_length; 45 size_t config_rom_length;
@@ -59,6 +59,9 @@ int fw_device_enable_phys_dma(struct fw_device *device);
59 59
60void fw_device_cdev_update(struct fw_device *device); 60void fw_device_cdev_update(struct fw_device *device);
61 61
62struct fw_device *fw_device_from_devt(dev_t devt);
63extern int fw_cdev_major;
64
62struct fw_unit { 65struct fw_unit {
63 struct device device; 66 struct device device;
64 u32 *directory; 67 u32 *directory;
diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c
index 8e2b94557390..3052698c13a6 100644
--- a/drivers/firewire/fw-transaction.c
+++ b/drivers/firewire/fw-transaction.c
@@ -761,6 +761,12 @@ static int __init fw_core_init(void)
761 if (retval < 0) 761 if (retval < 0)
762 return retval; 762 return retval;
763 763
764 fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops);
765 if (fw_cdev_major < 0) {
766 bus_unregister(&fw_bus_type);
767 return fw_cdev_major;
768 }
769
764 /* Add the vendor textual descriptor. */ 770 /* Add the vendor textual descriptor. */
765 retval = fw_core_add_descriptor(&vendor_id_descriptor); 771 retval = fw_core_add_descriptor(&vendor_id_descriptor);
766 BUG_ON(retval < 0); 772 BUG_ON(retval < 0);
@@ -772,6 +778,7 @@ static int __init fw_core_init(void)
772 778
773static void __exit fw_core_cleanup(void) 779static void __exit fw_core_cleanup(void)
774{ 780{
781 unregister_chrdev(fw_cdev_major, "firewire");
775 bus_unregister(&fw_bus_type); 782 bus_unregister(&fw_bus_type);
776} 783}
777 784