diff options
-rw-r--r-- | char.c | 38 | ||||
-rw-r--r-- | pci.h | 5 |
2 files changed, 29 insertions, 14 deletions
@@ -37,33 +37,41 @@ int new_doomdev(struct pci_dev *dev) { int err = 0; int minor; - dev_t devt; - struct cdev *doom_cdev; - struct device *doomdev; struct doom_data *doom_data; + dev_t devt; + if (next_minor >= DOOMDEV_COUNT) { return -ENOMEM; } - doom_cdev = cdev_alloc(); - if (doom_cdev == NULL) { + doom_data = kmalloc(sizeof(*doom_data), GFP_KERNEL); + if (doom_data == NULL) { + err = -ENOMEM; + goto error_kmalloc; + } + + doom_data->cdev = cdev_alloc(); + if (doom_data->cdev == NULL) { return -ENOMEM; } + cdev_init(doom_data->cdev, &doomdev_fops); + ORFAIL(cdev_add(doom_data->cdev, first, 1), error_add); - doom_cdev->ops = &doomdev_fops; - ORFAIL(cdev_add(doom_cdev, first, 1), error_add); minor = next_minor++; - doom_data = kmalloc(sizeof(*doom_data), GFP_KERNEL); - doom_data->minor = minor; - pci_set_drvdata(dev, doom_data); devt = MKDEV(major, minor); ORFAIL_PTR(device_create(doom_class, NULL, devt, NULL, "doom%d", minor), - doomdev, error_create); + doom_data->device, error_create); + + pci_set_drvdata(dev, doom_data); + + return 0; error_create: - cdev_del(doom_cdev); + cdev_del(doom_data->cdev); error_add: + kfree(doom_data); +error_kmalloc: return err; } @@ -71,7 +79,8 @@ void destroy_doomdev(struct pci_dev *dev) { struct doom_data *data; data = pci_get_drvdata(dev); - device_destroy(doom_class, MKDEV(major, data->minor)); + device_destroy(doom_class, data->device->devt); + cdev_del(data->cdev); kfree(data); } @@ -87,6 +96,8 @@ int char_init(void) goto error_create; } + return 0; + error_create: unregister_chrdev_region(first, DOOMDEV_COUNT); error_region: @@ -97,4 +108,5 @@ void char_cleanup(void) { unregister_chrdev_region(first, DOOMDEV_COUNT); class_unregister(doom_class); + class_destroy(doom_class); } @@ -1,8 +1,11 @@ #ifndef PCI_H #define PCI_H +#include <linux/device.h> + struct doom_data { - int minor; + struct cdev *cdev; + struct device *device; }; int pci_init(void); |