diff options
Diffstat (limited to 'litmus/ftdev.c')
-rw-r--r-- | litmus/ftdev.c | 144 |
1 files changed, 112 insertions, 32 deletions
diff --git a/litmus/ftdev.c b/litmus/ftdev.c index 51dafaebf8a6..4a4b2e3e56c2 100644 --- a/litmus/ftdev.c +++ b/litmus/ftdev.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include <linux/cdev.h> | 4 | #include <linux/cdev.h> |
5 | #include <asm/uaccess.h> | 5 | #include <asm/uaccess.h> |
6 | #include <linux/module.h> | 6 | #include <linux/module.h> |
7 | #include <linux/device.h> | ||
7 | 8 | ||
8 | #include <litmus/litmus.h> | 9 | #include <litmus/litmus.h> |
9 | #include <litmus/feather_trace.h> | 10 | #include <litmus/feather_trace.h> |
@@ -309,52 +310,131 @@ struct file_operations ftdev_fops = { | |||
309 | .read = ftdev_read, | 310 | .read = ftdev_read, |
310 | }; | 311 | }; |
311 | 312 | ||
312 | 313 | int ftdev_init( struct ftdev* ftdev, struct module* owner, | |
313 | void ftdev_init(struct ftdev* ftdev, struct module* owner) | 314 | const int minor_cnt, const char* name) |
314 | { | 315 | { |
315 | int i; | 316 | int i, err; |
317 | |||
318 | BUG_ON(minor_cnt < 1); | ||
319 | |||
316 | cdev_init(&ftdev->cdev, &ftdev_fops); | 320 | cdev_init(&ftdev->cdev, &ftdev_fops); |
321 | ftdev->name = name; | ||
322 | ftdev->minor_cnt = minor_cnt; | ||
317 | ftdev->cdev.owner = owner; | 323 | ftdev->cdev.owner = owner; |
318 | ftdev->cdev.ops = &ftdev_fops; | 324 | ftdev->cdev.ops = &ftdev_fops; |
319 | ftdev->minor_cnt = 0; | 325 | ftdev->alloc = NULL; |
320 | for (i = 0; i < MAX_FTDEV_MINORS; i++) { | 326 | ftdev->free = NULL; |
327 | ftdev->can_open = NULL; | ||
328 | |||
329 | ftdev->minor = kcalloc(ftdev->minor_cnt, sizeof(*ftdev->minor), | ||
330 | GFP_KERNEL); | ||
331 | if (!ftdev->minor) { | ||
332 | printk(KERN_WARNING "ftdev(%s): Could not allocate memory\n", | ||
333 | ftdev->name); | ||
334 | err = -ENOMEM; | ||
335 | goto err_out; | ||
336 | } | ||
337 | |||
338 | for (i = 0; i < ftdev->minor_cnt; i++) { | ||
321 | mutex_init(&ftdev->minor[i].lock); | 339 | mutex_init(&ftdev->minor[i].lock); |
322 | ftdev->minor[i].readers = 0; | 340 | ftdev->minor[i].readers = 0; |
323 | ftdev->minor[i].buf = NULL; | 341 | ftdev->minor[i].buf = NULL; |
324 | ftdev->minor[i].events = NULL; | 342 | ftdev->minor[i].events = NULL; |
325 | } | 343 | } |
326 | ftdev->alloc = NULL; | 344 | |
327 | ftdev->free = NULL; | 345 | ftdev->class = class_create(owner, ftdev->name); |
328 | ftdev->can_open = NULL; | 346 | if (IS_ERR(ftdev->class)) { |
347 | err = PTR_ERR(ftdev->class); | ||
348 | printk(KERN_WARNING "ftdev(%s): " | ||
349 | "Could not create device class.\n", ftdev->name); | ||
350 | goto err_dealloc; | ||
351 | } | ||
352 | |||
353 | return 0; | ||
354 | |||
355 | err_dealloc: | ||
356 | kfree(ftdev->minor); | ||
357 | err_out: | ||
358 | return err; | ||
329 | } | 359 | } |
330 | 360 | ||
331 | int register_ftdev(struct ftdev* ftdev, const char* name, int major) | 361 | /* |
362 | * Destroy minor devices up to, but not including, up_to. | ||
363 | */ | ||
364 | static void ftdev_device_destroy(struct ftdev* ftdev, unsigned int up_to) | ||
332 | { | 365 | { |
333 | dev_t trace_dev; | 366 | dev_t minor_cntr; |
334 | int error = 0; | 367 | |
335 | 368 | if (up_to < 1) | |
336 | if(major) { | 369 | up_to = (ftdev->minor_cnt < 1) ? 0 : ftdev->minor_cnt; |
337 | trace_dev = MKDEV(major, 0); | 370 | |
338 | error = register_chrdev_region(trace_dev, ftdev->minor_cnt, | 371 | for (minor_cntr = 0; minor_cntr < up_to; ++minor_cntr) |
339 | name); | 372 | device_destroy(ftdev->class, MKDEV(ftdev->major, minor_cntr)); |
340 | } else { | 373 | } |
341 | error = alloc_chrdev_region(&trace_dev, 0, ftdev->minor_cnt, | 374 | |
342 | name); | 375 | void ftdev_exit(struct ftdev* ftdev) |
343 | major = MAJOR(trace_dev); | 376 | { |
344 | } | 377 | printk("ftdev(%s): Exiting\n", ftdev->name); |
345 | if (error) | 378 | ftdev_device_destroy(ftdev, -1); |
346 | { | 379 | cdev_del(&ftdev->cdev); |
380 | unregister_chrdev_region(MKDEV(ftdev->major, 0), ftdev->minor_cnt); | ||
381 | class_destroy(ftdev->class); | ||
382 | kfree(ftdev->minor); | ||
383 | } | ||
384 | |||
385 | int register_ftdev(struct ftdev* ftdev) | ||
386 | { | ||
387 | struct device **device; | ||
388 | dev_t trace_dev_tmp, minor_cntr; | ||
389 | int err; | ||
390 | |||
391 | err = alloc_chrdev_region(&trace_dev_tmp, 0, ftdev->minor_cnt, | ||
392 | ftdev->name); | ||
393 | if (err) { | ||
347 | printk(KERN_WARNING "ftdev(%s): " | 394 | printk(KERN_WARNING "ftdev(%s): " |
348 | "Could not register major/minor number %d/%u\n", | 395 | "Could not allocate char. device region (%d minors)\n", |
349 | name, major, ftdev->minor_cnt); | 396 | ftdev->name, ftdev->minor_cnt); |
350 | return error; | 397 | goto err_out; |
351 | } | 398 | } |
352 | error = cdev_add(&ftdev->cdev, trace_dev, ftdev->minor_cnt); | 399 | |
353 | if (error) { | 400 | ftdev->major = MAJOR(trace_dev_tmp); |
401 | |||
402 | err = cdev_add(&ftdev->cdev, trace_dev_tmp, ftdev->minor_cnt); | ||
403 | if (err) { | ||
354 | printk(KERN_WARNING "ftdev(%s): " | 404 | printk(KERN_WARNING "ftdev(%s): " |
355 | "Could not add cdev for major/minor = %d/%u.\n", | 405 | "Could not add cdev for major %u with %u minor(s).\n", |
356 | name, major, ftdev->minor_cnt); | 406 | ftdev->name, ftdev->major, ftdev->minor_cnt); |
357 | return error; | 407 | goto err_unregister; |
358 | } | 408 | } |
359 | return error; | 409 | |
410 | /* create the minor device(s) */ | ||
411 | for (minor_cntr = 0; minor_cntr < ftdev->minor_cnt; ++minor_cntr) | ||
412 | { | ||
413 | trace_dev_tmp = MKDEV(ftdev->major, minor_cntr); | ||
414 | device = &ftdev->minor[minor_cntr].device; | ||
415 | |||
416 | *device = device_create(ftdev->class, NULL, trace_dev_tmp, NULL, | ||
417 | "litmus/%s%d", ftdev->name, minor_cntr); | ||
418 | if (IS_ERR(*device)) { | ||
419 | err = PTR_ERR(*device); | ||
420 | printk(KERN_WARNING "ftdev(%s): " | ||
421 | "Could not create device major/minor number " | ||
422 | "%u/%u\n", ftdev->name, ftdev->major, | ||
423 | minor_cntr); | ||
424 | printk(KERN_WARNING "ftdev(%s): " | ||
425 | "will attempt deletion of allocated devices.\n", | ||
426 | ftdev->name); | ||
427 | goto err_minors; | ||
428 | } | ||
429 | } | ||
430 | |||
431 | return 0; | ||
432 | |||
433 | err_minors: | ||
434 | ftdev_device_destroy(ftdev, minor_cntr); | ||
435 | cdev_del(&ftdev->cdev); | ||
436 | err_unregister: | ||
437 | unregister_chrdev_region(MKDEV(ftdev->major, 0), ftdev->minor_cnt); | ||
438 | err_out: | ||
439 | return err; | ||
360 | } | 440 | } |