aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/char/scx200_gpio.c53
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 */
26module_param(major, int, 0); 29module_param(major, int, 0);
27MODULE_PARM_DESC(major, "Major device number"); 30MODULE_PARM_DESC(major, "Major device number");
28 31
32extern void scx200_gpio_dump(unsigned index);
33
29static ssize_t scx200_gpio_write(struct file *file, const char __user *data, 34static 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
116struct cdev *scx200_devices;
117int num_devs = 32;
118
111static int __init scx200_gpio_init(void) 119static 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
158fail_malloc:
159 unregister_chrdev_region(dev, num_devs);
160 return rc;
133} 161}
134 162
135static void __exit scx200_gpio_cleanup(void) 163static 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
140module_init(scx200_gpio_init); 169module_init(scx200_gpio_init);