diff options
Diffstat (limited to 'drivers/char/scx200_gpio.c')
-rw-r--r-- | drivers/char/scx200_gpio.c | 72 |
1 files changed, 29 insertions, 43 deletions
diff --git a/drivers/char/scx200_gpio.c b/drivers/char/scx200_gpio.c index 425c58719db6..b956c7babd18 100644 --- a/drivers/char/scx200_gpio.c +++ b/drivers/char/scx200_gpio.c | |||
@@ -5,7 +5,6 @@ | |||
5 | 5 | ||
6 | Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> */ | 6 | Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> */ |
7 | 7 | ||
8 | #include <linux/config.h> | ||
9 | #include <linux/device.h> | 8 | #include <linux/device.h> |
10 | #include <linux/fs.h> | 9 | #include <linux/fs.h> |
11 | #include <linux/module.h> | 10 | #include <linux/module.h> |
@@ -22,37 +21,37 @@ | |||
22 | #include <linux/scx200_gpio.h> | 21 | #include <linux/scx200_gpio.h> |
23 | #include <linux/nsc_gpio.h> | 22 | #include <linux/nsc_gpio.h> |
24 | 23 | ||
25 | #define NAME "scx200_gpio" | 24 | #define DRVNAME "scx200_gpio" |
26 | #define DEVNAME NAME | ||
27 | 25 | ||
28 | static struct platform_device *pdev; | 26 | static struct platform_device *pdev; |
29 | 27 | ||
30 | MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>"); | 28 | MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>"); |
31 | MODULE_DESCRIPTION("NatSemi SCx200 GPIO Pin Driver"); | 29 | MODULE_DESCRIPTION("NatSemi/AMD SCx200 GPIO Pin Driver"); |
32 | MODULE_LICENSE("GPL"); | 30 | MODULE_LICENSE("GPL"); |
33 | 31 | ||
34 | static int major = 0; /* default to dynamic major */ | 32 | static int major = 0; /* default to dynamic major */ |
35 | module_param(major, int, 0); | 33 | module_param(major, int, 0); |
36 | MODULE_PARM_DESC(major, "Major device number"); | 34 | MODULE_PARM_DESC(major, "Major device number"); |
37 | 35 | ||
38 | struct nsc_gpio_ops scx200_access = { | 36 | #define MAX_PINS 32 /* 64 later, when known ok */ |
37 | |||
38 | struct nsc_gpio_ops scx200_gpio_ops = { | ||
39 | .owner = THIS_MODULE, | 39 | .owner = THIS_MODULE, |
40 | .gpio_config = scx200_gpio_configure, | 40 | .gpio_config = scx200_gpio_configure, |
41 | .gpio_dump = nsc_gpio_dump, | 41 | .gpio_dump = nsc_gpio_dump, |
42 | .gpio_get = scx200_gpio_get, | 42 | .gpio_get = scx200_gpio_get, |
43 | .gpio_set = scx200_gpio_set, | 43 | .gpio_set = scx200_gpio_set, |
44 | .gpio_set_high = scx200_gpio_set_high, | ||
45 | .gpio_set_low = scx200_gpio_set_low, | ||
46 | .gpio_change = scx200_gpio_change, | 44 | .gpio_change = scx200_gpio_change, |
47 | .gpio_current = scx200_gpio_current | 45 | .gpio_current = scx200_gpio_current |
48 | }; | 46 | }; |
47 | EXPORT_SYMBOL(scx200_gpio_ops); | ||
49 | 48 | ||
50 | static int scx200_gpio_open(struct inode *inode, struct file *file) | 49 | static int scx200_gpio_open(struct inode *inode, struct file *file) |
51 | { | 50 | { |
52 | unsigned m = iminor(inode); | 51 | unsigned m = iminor(inode); |
53 | file->private_data = &scx200_access; | 52 | file->private_data = &scx200_gpio_ops; |
54 | 53 | ||
55 | if (m > 63) | 54 | if (m >= MAX_PINS) |
56 | return -EINVAL; | 55 | return -EINVAL; |
57 | return nonseekable_open(inode, file); | 56 | return nonseekable_open(inode, file); |
58 | } | 57 | } |
@@ -62,8 +61,7 @@ static int scx200_gpio_release(struct inode *inode, struct file *file) | |||
62 | return 0; | 61 | return 0; |
63 | } | 62 | } |
64 | 63 | ||
65 | 64 | static const struct file_operations scx200_gpio_fileops = { | |
66 | static const struct file_operations scx200_gpio_fops = { | ||
67 | .owner = THIS_MODULE, | 65 | .owner = THIS_MODULE, |
68 | .write = nsc_gpio_write, | 66 | .write = nsc_gpio_write, |
69 | .read = nsc_gpio_read, | 67 | .read = nsc_gpio_read, |
@@ -71,21 +69,20 @@ static const struct file_operations scx200_gpio_fops = { | |||
71 | .release = scx200_gpio_release, | 69 | .release = scx200_gpio_release, |
72 | }; | 70 | }; |
73 | 71 | ||
74 | struct cdev *scx200_devices; | 72 | struct cdev scx200_gpio_cdev; /* use 1 cdev for all pins */ |
75 | static int num_pins = 32; | ||
76 | 73 | ||
77 | static int __init scx200_gpio_init(void) | 74 | static int __init scx200_gpio_init(void) |
78 | { | 75 | { |
79 | int rc, i; | 76 | int rc; |
80 | dev_t dev = MKDEV(major, 0); | 77 | dev_t devid; |
81 | 78 | ||
82 | if (!scx200_gpio_present()) { | 79 | if (!scx200_gpio_present()) { |
83 | printk(KERN_ERR NAME ": no SCx200 gpio present\n"); | 80 | printk(KERN_ERR DRVNAME ": no SCx200 gpio present\n"); |
84 | return -ENODEV; | 81 | return -ENODEV; |
85 | } | 82 | } |
86 | 83 | ||
87 | /* support dev_dbg() with pdev->dev */ | 84 | /* support dev_dbg() with pdev->dev */ |
88 | pdev = platform_device_alloc(DEVNAME, 0); | 85 | pdev = platform_device_alloc(DRVNAME, 0); |
89 | if (!pdev) | 86 | if (!pdev) |
90 | return -ENOMEM; | 87 | return -ENOMEM; |
91 | 88 | ||
@@ -94,37 +91,25 @@ static int __init scx200_gpio_init(void) | |||
94 | goto undo_malloc; | 91 | goto undo_malloc; |
95 | 92 | ||
96 | /* nsc_gpio uses dev_dbg(), so needs this */ | 93 | /* nsc_gpio uses dev_dbg(), so needs this */ |
97 | scx200_access.dev = &pdev->dev; | 94 | scx200_gpio_ops.dev = &pdev->dev; |
98 | 95 | ||
99 | if (major) | 96 | if (major) { |
100 | rc = register_chrdev_region(dev, num_pins, "scx200_gpio"); | 97 | devid = MKDEV(major, 0); |
101 | else { | 98 | rc = register_chrdev_region(devid, MAX_PINS, "scx200_gpio"); |
102 | rc = alloc_chrdev_region(&dev, 0, num_pins, "scx200_gpio"); | 99 | } else { |
103 | major = MAJOR(dev); | 100 | rc = alloc_chrdev_region(&devid, 0, MAX_PINS, "scx200_gpio"); |
101 | major = MAJOR(devid); | ||
104 | } | 102 | } |
105 | if (rc < 0) { | 103 | if (rc < 0) { |
106 | dev_err(&pdev->dev, "SCx200 chrdev_region err: %d\n", rc); | 104 | dev_err(&pdev->dev, "SCx200 chrdev_region err: %d\n", rc); |
107 | goto undo_platform_device_add; | 105 | goto undo_platform_device_add; |
108 | } | 106 | } |
109 | scx200_devices = kzalloc(num_pins * sizeof(struct cdev), GFP_KERNEL); | 107 | |
110 | if (!scx200_devices) { | 108 | cdev_init(&scx200_gpio_cdev, &scx200_gpio_fileops); |
111 | rc = -ENOMEM; | 109 | cdev_add(&scx200_gpio_cdev, devid, MAX_PINS); |
112 | goto undo_chrdev_region; | ||
113 | } | ||
114 | for (i = 0; i < num_pins; i++) { | ||
115 | struct cdev *cdev = &scx200_devices[i]; | ||
116 | cdev_init(cdev, &scx200_gpio_fops); | ||
117 | cdev->owner = THIS_MODULE; | ||
118 | rc = cdev_add(cdev, MKDEV(major, i), 1); | ||
119 | /* tolerate 'minor' errors */ | ||
120 | if (rc) | ||
121 | dev_err(&pdev->dev, "Error %d on minor %d", rc, i); | ||
122 | } | ||
123 | 110 | ||
124 | return 0; /* succeed */ | 111 | return 0; /* succeed */ |
125 | 112 | ||
126 | undo_chrdev_region: | ||
127 | unregister_chrdev_region(dev, num_pins); | ||
128 | undo_platform_device_add: | 113 | undo_platform_device_add: |
129 | platform_device_del(pdev); | 114 | platform_device_del(pdev); |
130 | undo_malloc: | 115 | undo_malloc: |
@@ -135,10 +120,11 @@ undo_malloc: | |||
135 | 120 | ||
136 | static void __exit scx200_gpio_cleanup(void) | 121 | static void __exit scx200_gpio_cleanup(void) |
137 | { | 122 | { |
138 | kfree(scx200_devices); | 123 | cdev_del(&scx200_gpio_cdev); |
139 | unregister_chrdev_region(MKDEV(major, 0), num_pins); | 124 | /* cdev_put(&scx200_gpio_cdev); */ |
125 | |||
126 | unregister_chrdev_region(MKDEV(major, 0), MAX_PINS); | ||
140 | platform_device_unregister(pdev); | 127 | platform_device_unregister(pdev); |
141 | /* kfree(pdev); */ | ||
142 | } | 128 | } |
143 | 129 | ||
144 | module_init(scx200_gpio_init); | 130 | module_init(scx200_gpio_init); |