diff options
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/scx200_gpio.c | 53 |
1 files changed, 41 insertions, 12 deletions
diff --git a/drivers/char/scx200_gpio.c b/drivers/char/scx200_gpio.c index dd051ea6755e..507a5bf567cb 100644 --- a/drivers/char/scx200_gpio.c +++ b/drivers/char/scx200_gpio.c | |||
@@ -14,6 +14,9 @@ | |||
14 | #include <asm/uaccess.h> | 14 | #include <asm/uaccess.h> |
15 | #include <asm/io.h> | 15 | #include <asm/io.h> |
16 | 16 | ||
17 | #include <linux/types.h> | ||
18 | #include <linux/cdev.h> | ||
19 | |||
17 | #include <linux/scx200_gpio.h> | 20 | #include <linux/scx200_gpio.h> |
18 | 21 | ||
19 | #define NAME "scx200_gpio" | 22 | #define NAME "scx200_gpio" |
@@ -26,6 +29,8 @@ static int major = 0; /* default to dynamic major */ | |||
26 | module_param(major, int, 0); | 29 | module_param(major, int, 0); |
27 | MODULE_PARM_DESC(major, "Major device number"); | 30 | MODULE_PARM_DESC(major, "Major device number"); |
28 | 31 | ||
32 | extern void scx200_gpio_dump(unsigned index); | ||
33 | |||
29 | static ssize_t scx200_gpio_write(struct file *file, const char __user *data, | 34 | static ssize_t scx200_gpio_write(struct file *file, const char __user *data, |
30 | size_t len, loff_t *ppos) | 35 | size_t len, loff_t *ppos) |
31 | { | 36 | { |
@@ -108,33 +113,57 @@ static struct file_operations scx200_gpio_fops = { | |||
108 | .release = scx200_gpio_release, | 113 | .release = scx200_gpio_release, |
109 | }; | 114 | }; |
110 | 115 | ||
116 | struct cdev *scx200_devices; | ||
117 | int num_devs = 32; | ||
118 | |||
111 | static int __init scx200_gpio_init(void) | 119 | static int __init scx200_gpio_init(void) |
112 | { | 120 | { |
113 | int r; | 121 | int rc, i; |
122 | dev_t dev = MKDEV(major, 0); | ||
114 | 123 | ||
115 | printk(KERN_DEBUG NAME ": NatSemi SCx200 GPIO Driver\n"); | 124 | printk(KERN_DEBUG NAME ": NatSemi SCx200 GPIO Driver\n"); |
116 | 125 | ||
117 | if (!scx200_gpio_present()) { | 126 | if (!scx200_gpio_present()) { |
118 | printk(KERN_ERR NAME ": no SCx200 gpio pins available\n"); | 127 | printk(KERN_ERR NAME ": no SCx200 gpio present\n"); |
119 | return -ENODEV; | 128 | return -ENODEV; |
120 | } | 129 | } |
121 | 130 | if (major) | |
122 | r = register_chrdev(major, NAME, &scx200_gpio_fops); | 131 | rc = register_chrdev_region(dev, num_devs, "scx200_gpio"); |
123 | if (r < 0) { | 132 | else { |
124 | printk(KERN_ERR NAME ": unable to register character device\n"); | 133 | rc = alloc_chrdev_region(&dev, 0, num_devs, "scx200_gpio"); |
125 | return r; | 134 | major = MAJOR(dev); |
126 | } | 135 | } |
127 | if (!major) { | 136 | if (rc < 0) { |
128 | major = r; | 137 | printk(KERN_ERR NAME ": SCx200 chrdev_region: %d\n", rc); |
129 | printk(KERN_DEBUG NAME ": got dynamic major %d\n", major); | 138 | return rc; |
139 | } | ||
140 | scx200_devices = kzalloc(num_devs * sizeof(struct cdev), GFP_KERNEL); | ||
141 | if (!scx200_devices) { | ||
142 | rc = -ENOMEM; | ||
143 | goto fail_malloc; | ||
144 | } | ||
145 | for (i = 0; i < num_devs; i++) { | ||
146 | struct cdev *cdev = &scx200_devices[i]; | ||
147 | cdev_init(cdev, &scx200_gpio_fops); | ||
148 | cdev->owner = THIS_MODULE; | ||
149 | cdev->ops = &scx200_gpio_fops; | ||
150 | rc = cdev_add(cdev, MKDEV(major, i), 1); | ||
151 | /* Fail gracefully if need be */ | ||
152 | if (rc) | ||
153 | printk(KERN_ERR NAME "Error %d on minor %d", rc, i); | ||
130 | } | 154 | } |
131 | 155 | ||
132 | return 0; | 156 | return 0; /* succeed */ |
157 | |||
158 | fail_malloc: | ||
159 | unregister_chrdev_region(dev, num_devs); | ||
160 | return rc; | ||
133 | } | 161 | } |
134 | 162 | ||
135 | static void __exit scx200_gpio_cleanup(void) | 163 | static void __exit scx200_gpio_cleanup(void) |
136 | { | 164 | { |
137 | unregister_chrdev(major, NAME); | 165 | kfree(scx200_devices); |
166 | unregister_chrdev_region(MKDEV(major, 0), num_devs); | ||
138 | } | 167 | } |
139 | 168 | ||
140 | module_init(scx200_gpio_init); | 169 | module_init(scx200_gpio_init); |