diff options
Diffstat (limited to 'drivers/char/bsr.c')
-rw-r--r-- | drivers/char/bsr.c | 84 |
1 files changed, 55 insertions, 29 deletions
diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c index 456f54db73e2..977dfb1096a0 100644 --- a/drivers/char/bsr.c +++ b/drivers/char/bsr.c | |||
@@ -60,6 +60,8 @@ struct bsr_dev { | |||
60 | unsigned bsr_num; /* bsr id number for its type */ | 60 | unsigned bsr_num; /* bsr id number for its type */ |
61 | int bsr_minor; | 61 | int bsr_minor; |
62 | 62 | ||
63 | struct list_head bsr_list; | ||
64 | |||
63 | dev_t bsr_dev; | 65 | dev_t bsr_dev; |
64 | struct cdev bsr_cdev; | 66 | struct cdev bsr_cdev; |
65 | struct device *bsr_device; | 67 | struct device *bsr_device; |
@@ -67,8 +69,8 @@ struct bsr_dev { | |||
67 | 69 | ||
68 | }; | 70 | }; |
69 | 71 | ||
70 | static unsigned num_bsr_devs; | 72 | static unsigned total_bsr_devs; |
71 | static struct bsr_dev *bsr_devs; | 73 | static struct list_head bsr_devs = LIST_HEAD_INIT(bsr_devs); |
72 | static struct class *bsr_class; | 74 | static struct class *bsr_class; |
73 | static int bsr_major; | 75 | static int bsr_major; |
74 | 76 | ||
@@ -146,24 +148,25 @@ const static struct file_operations bsr_fops = { | |||
146 | 148 | ||
147 | static void bsr_cleanup_devs(void) | 149 | static void bsr_cleanup_devs(void) |
148 | { | 150 | { |
149 | int i; | 151 | struct bsr_dev *cur, *n; |
150 | for (i=0 ; i < num_bsr_devs; i++) { | 152 | |
151 | struct bsr_dev *cur = bsr_devs + i; | 153 | list_for_each_entry_safe(cur, n, &bsr_devs, bsr_list) { |
152 | if (cur->bsr_device) { | 154 | if (cur->bsr_device) { |
153 | cdev_del(&cur->bsr_cdev); | 155 | cdev_del(&cur->bsr_cdev); |
154 | device_del(cur->bsr_device); | 156 | device_del(cur->bsr_device); |
155 | } | 157 | } |
158 | list_del(&cur->bsr_list); | ||
159 | kfree(cur); | ||
156 | } | 160 | } |
157 | |||
158 | kfree(bsr_devs); | ||
159 | } | 161 | } |
160 | 162 | ||
161 | static int bsr_create_devs(struct device_node *bn) | 163 | static int bsr_add_node(struct device_node *bn) |
162 | { | 164 | { |
163 | int bsr_stride_len, bsr_bytes_len; | 165 | int bsr_stride_len, bsr_bytes_len, num_bsr_devs; |
164 | const u32 *bsr_stride; | 166 | const u32 *bsr_stride; |
165 | const u32 *bsr_bytes; | 167 | const u32 *bsr_bytes; |
166 | unsigned i; | 168 | unsigned i; |
169 | int ret = -ENODEV; | ||
167 | 170 | ||
168 | bsr_stride = of_get_property(bn, "ibm,lock-stride", &bsr_stride_len); | 171 | bsr_stride = of_get_property(bn, "ibm,lock-stride", &bsr_stride_len); |
169 | bsr_bytes = of_get_property(bn, "ibm,#lock-bytes", &bsr_bytes_len); | 172 | bsr_bytes = of_get_property(bn, "ibm,#lock-bytes", &bsr_bytes_len); |
@@ -171,35 +174,36 @@ static int bsr_create_devs(struct device_node *bn) | |||
171 | if (!bsr_stride || !bsr_bytes || | 174 | if (!bsr_stride || !bsr_bytes || |
172 | (bsr_stride_len != bsr_bytes_len)) { | 175 | (bsr_stride_len != bsr_bytes_len)) { |
173 | printk(KERN_ERR "bsr of-node has missing/incorrect property\n"); | 176 | printk(KERN_ERR "bsr of-node has missing/incorrect property\n"); |
174 | return -ENODEV; | 177 | return ret; |
175 | } | 178 | } |
176 | 179 | ||
177 | num_bsr_devs = bsr_bytes_len / sizeof(u32); | 180 | num_bsr_devs = bsr_bytes_len / sizeof(u32); |
178 | 181 | ||
179 | /* only a warning, its informational since we'll fail and exit */ | ||
180 | WARN_ON(num_bsr_devs > BSR_MAX_DEVS); | ||
181 | |||
182 | bsr_devs = kzalloc(sizeof(struct bsr_dev) * num_bsr_devs, GFP_KERNEL); | ||
183 | if (!bsr_devs) | ||
184 | return -ENOMEM; | ||
185 | |||
186 | for (i = 0 ; i < num_bsr_devs; i++) { | 182 | for (i = 0 ; i < num_bsr_devs; i++) { |
187 | struct bsr_dev *cur = bsr_devs + i; | 183 | struct bsr_dev *cur = kzalloc(sizeof(struct bsr_dev), |
184 | GFP_KERNEL); | ||
188 | struct resource res; | 185 | struct resource res; |
189 | int result; | 186 | int result; |
190 | 187 | ||
188 | if (!cur) { | ||
189 | printk(KERN_ERR "Unable to alloc bsr dev\n"); | ||
190 | ret = -ENOMEM; | ||
191 | goto out_err; | ||
192 | } | ||
193 | |||
191 | result = of_address_to_resource(bn, i, &res); | 194 | result = of_address_to_resource(bn, i, &res); |
192 | if (result < 0) { | 195 | if (result < 0) { |
193 | printk(KERN_ERR "bsr of-node has invalid reg property\n"); | 196 | printk(KERN_ERR "bsr of-node has invalid reg property, skipping\n"); |
194 | goto out_err; | 197 | kfree(cur); |
198 | continue; | ||
195 | } | 199 | } |
196 | 200 | ||
197 | cur->bsr_minor = i; | 201 | cur->bsr_minor = i + total_bsr_devs; |
198 | cur->bsr_addr = res.start; | 202 | cur->bsr_addr = res.start; |
199 | cur->bsr_len = res.end - res.start + 1; | 203 | cur->bsr_len = res.end - res.start + 1; |
200 | cur->bsr_bytes = bsr_bytes[i]; | 204 | cur->bsr_bytes = bsr_bytes[i]; |
201 | cur->bsr_stride = bsr_stride[i]; | 205 | cur->bsr_stride = bsr_stride[i]; |
202 | cur->bsr_dev = MKDEV(bsr_major, i); | 206 | cur->bsr_dev = MKDEV(bsr_major, i + total_bsr_devs); |
203 | 207 | ||
204 | switch(cur->bsr_bytes) { | 208 | switch(cur->bsr_bytes) { |
205 | case 8: | 209 | case 8: |
@@ -220,14 +224,15 @@ static int bsr_create_devs(struct device_node *bn) | |||
220 | } | 224 | } |
221 | 225 | ||
222 | cur->bsr_num = bsr_types[cur->bsr_type]; | 226 | cur->bsr_num = bsr_types[cur->bsr_type]; |
223 | bsr_types[cur->bsr_type] = cur->bsr_num + 1; | ||
224 | snprintf(cur->bsr_name, 32, "bsr%d_%d", | 227 | snprintf(cur->bsr_name, 32, "bsr%d_%d", |
225 | cur->bsr_bytes, cur->bsr_num); | 228 | cur->bsr_bytes, cur->bsr_num); |
226 | 229 | ||
227 | cdev_init(&cur->bsr_cdev, &bsr_fops); | 230 | cdev_init(&cur->bsr_cdev, &bsr_fops); |
228 | result = cdev_add(&cur->bsr_cdev, cur->bsr_dev, 1); | 231 | result = cdev_add(&cur->bsr_cdev, cur->bsr_dev, 1); |
229 | if (result) | 232 | if (result) { |
233 | kfree(cur); | ||
230 | goto out_err; | 234 | goto out_err; |
235 | } | ||
231 | 236 | ||
232 | cur->bsr_device = device_create(bsr_class, NULL, cur->bsr_dev, | 237 | cur->bsr_device = device_create(bsr_class, NULL, cur->bsr_dev, |
233 | cur, cur->bsr_name); | 238 | cur, cur->bsr_name); |
@@ -235,16 +240,37 @@ static int bsr_create_devs(struct device_node *bn) | |||
235 | printk(KERN_ERR "device_create failed for %s\n", | 240 | printk(KERN_ERR "device_create failed for %s\n", |
236 | cur->bsr_name); | 241 | cur->bsr_name); |
237 | cdev_del(&cur->bsr_cdev); | 242 | cdev_del(&cur->bsr_cdev); |
243 | kfree(cur); | ||
238 | goto out_err; | 244 | goto out_err; |
239 | } | 245 | } |
246 | |||
247 | bsr_types[cur->bsr_type] = cur->bsr_num + 1; | ||
248 | list_add_tail(&cur->bsr_list, &bsr_devs); | ||
240 | } | 249 | } |
241 | 250 | ||
251 | total_bsr_devs += num_bsr_devs; | ||
252 | |||
242 | return 0; | 253 | return 0; |
243 | 254 | ||
244 | out_err: | 255 | out_err: |
245 | 256 | ||
246 | bsr_cleanup_devs(); | 257 | bsr_cleanup_devs(); |
247 | return -ENODEV; | 258 | return ret; |
259 | } | ||
260 | |||
261 | static int bsr_create_devs(struct device_node *bn) | ||
262 | { | ||
263 | int ret; | ||
264 | |||
265 | while (bn) { | ||
266 | ret = bsr_add_node(bn); | ||
267 | if (ret) { | ||
268 | of_node_put(bn); | ||
269 | return ret; | ||
270 | } | ||
271 | bn = of_find_compatible_node(bn, NULL, "ibm,bsr"); | ||
272 | } | ||
273 | return 0; | ||
248 | } | 274 | } |
249 | 275 | ||
250 | static int __init bsr_init(void) | 276 | static int __init bsr_init(void) |
@@ -254,7 +280,7 @@ static int __init bsr_init(void) | |||
254 | int ret = -ENODEV; | 280 | int ret = -ENODEV; |
255 | int result; | 281 | int result; |
256 | 282 | ||
257 | np = of_find_compatible_node(NULL, "ibm,bsr", "ibm,bsr"); | 283 | np = of_find_compatible_node(NULL, NULL, "ibm,bsr"); |
258 | if (!np) | 284 | if (!np) |
259 | goto out_err; | 285 | goto out_err; |
260 | 286 | ||
@@ -272,10 +298,10 @@ static int __init bsr_init(void) | |||
272 | goto out_err_2; | 298 | goto out_err_2; |
273 | } | 299 | } |
274 | 300 | ||
275 | if ((ret = bsr_create_devs(np)) < 0) | 301 | if ((ret = bsr_create_devs(np)) < 0) { |
302 | np = NULL; | ||
276 | goto out_err_3; | 303 | goto out_err_3; |
277 | 304 | } | |
278 | of_node_put(np); | ||
279 | 305 | ||
280 | return 0; | 306 | return 0; |
281 | 307 | ||