etisserant@391: #include etisserant@391: #include etisserant@391: #include etisserant@391: #include etisserant@391: #include etisserant@391: etisserant@391: #include "TestMasterSlave.h" etisserant@391: #include "console/console.h" etisserant@391: etisserant@391: #define minor 0 etisserant@391: etisserant@391: MODULE_LICENSE("GPL"); etisserant@391: etisserant@391: static dev_t canftest_dev; etisserant@391: static struct cdev *canftest_cdev; etisserant@391: static struct task_struct *thread_start_p, *thread_stop_p; etisserant@391: static DECLARE_MUTEX (canftest_mutex); etisserant@391: static int canftest_stopped = 1; etisserant@391: greg@467: int thread_start (void* data); greg@467: int thread_stop (void* data); greg@467: etisserant@391: // handler processing write() requests from user-space etisserant@391: ssize_t canftest_write(struct file *filp, const char __user *buf, size_t count, etisserant@391: loff_t *f_pos) etisserant@391: { etisserant@391: int cmd; etisserant@391: etisserant@391: // get integer from user-space etisserant@391: if (get_user (cmd, buf)) etisserant@391: return -EFAULT; etisserant@391: etisserant@391: // process integer as command etisserant@391: switch (cmd) { etisserant@391: case CMD_START: greg@467: if (!canftest_stopped) break; greg@467: thread_start_p = kthread_create (thread_start, NULL, "canftest_start"); greg@467: greg@467: if (PTR_ERR(thread_start_p) == -ENOMEM) { greg@467: printk(KERN_WARNING "canftest: error creating start thread\n"); greg@467: return -ENOMEM; greg@467: } greg@467: etisserant@391: wake_up_process (thread_start_p); etisserant@391: break; greg@467: etisserant@391: case CMD_STOP: etisserant@391: if (canftest_stopped) break; greg@467: thread_stop_p = kthread_create (thread_stop, NULL, "canftest_stop"); greg@467: greg@467: if (PTR_ERR(thread_stop_p) == -ENOMEM) { greg@467: printk(KERN_WARNING "canftest: error creating stop thread\n"); greg@467: return -ENOMEM; greg@467: } greg@467: etisserant@391: wake_up_process (thread_stop_p); etisserant@391: break; greg@467: etisserant@391: // ignore new line character etisserant@391: case 10: etisserant@391: break; greg@467: etisserant@391: default: etisserant@391: printk("canftest: bad command %d\n", cmd); etisserant@391: break; etisserant@391: } etisserant@391: etisserant@391: return count; etisserant@391: } etisserant@391: etisserant@391: // register write() handler etisserant@391: static struct file_operations canftest_fops = { etisserant@391: .owner = THIS_MODULE, etisserant@391: .write = canftest_write, etisserant@391: }; etisserant@391: etisserant@391: // start TestMasterSlave example etisserant@391: int thread_start (void* data) etisserant@391: { etisserant@391: int ret=0; etisserant@391: etisserant@391: down_interruptible (&canftest_mutex); etisserant@391: etisserant@391: ret=TestMasterSlave_start(); etisserant@391: etisserant@391: // if started etisserant@391: if (ret == 0) { etisserant@391: canftest_stopped = 0; etisserant@391: etisserant@391: // increment module usage count etisserant@391: try_module_get(THIS_MODULE); etisserant@391: } etisserant@391: etisserant@391: up (&canftest_mutex); etisserant@391: etisserant@391: return ret; etisserant@391: } etisserant@391: etisserant@391: // finish TestMasterSlave example etisserant@391: int thread_stop (void* data) etisserant@391: { etisserant@391: down_interruptible (&canftest_mutex); etisserant@391: etisserant@391: TestMasterSlave_stop(); etisserant@391: canftest_stopped = 1; etisserant@391: etisserant@391: // decrement usage count etisserant@391: module_put(THIS_MODULE); etisserant@391: etisserant@391: up (&canftest_mutex); etisserant@391: etisserant@391: return 0; etisserant@391: } etisserant@391: etisserant@391: int init_module(void) etisserant@391: { etisserant@391: int ret, major; etisserant@391: etisserant@391: // get major device number dynamically etisserant@391: ret = alloc_chrdev_region(&canftest_dev, minor, 1, DEVICE_NAME); etisserant@391: major = MAJOR(canftest_dev); etisserant@391: if (ret < 0) { etisserant@391: printk(KERN_WARNING "canftest: can't get major %d\n", major); etisserant@391: return ret; etisserant@391: } etisserant@391: etisserant@391: canftest_cdev = cdev_alloc( ); etisserant@391: canftest_cdev->owner = THIS_MODULE; etisserant@391: canftest_cdev->ops = &canftest_fops; etisserant@391: etisserant@391: // register new character device etisserant@391: ret = cdev_add (canftest_cdev, canftest_dev, 1); etisserant@391: if (ret) { etisserant@391: printk(KERN_WARNING "canftest: error %d adding char device\n", ret); etisserant@391: return ret; etisserant@391: } etisserant@391: etisserant@391: return 0; etisserant@391: } etisserant@391: etisserant@391: void cleanup_module(void) etisserant@391: { etisserant@391: // unregister major device number and character device etisserant@391: unregister_chrdev_region(canftest_dev, 1); etisserant@391: cdev_del(canftest_cdev); etisserant@391: }