aboutsummaryrefslogtreecommitdiffstats
path: root/litmus/ftdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'litmus/ftdev.c')
-rw-r--r--litmus/ftdev.c144
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 313int ftdev_init( struct ftdev* ftdev, struct module* owner,
313void 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
355err_dealloc:
356 kfree(ftdev->minor);
357err_out:
358 return err;
329} 359}
330 360
331int register_ftdev(struct ftdev* ftdev, const char* name, int major) 361/*
362 * Destroy minor devices up to, but not including, up_to.
363 */
364static 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); 375void 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
385int 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
433err_minors:
434 ftdev_device_destroy(ftdev, minor_cntr);
435 cdev_del(&ftdev->cdev);
436err_unregister:
437 unregister_chrdev_region(MKDEV(ftdev->major, 0), ftdev->minor_cnt);
438err_out:
439 return err;
360} 440}