diff options
| -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 | <|||
