information on code.
/* * file: gkos_char_device.c * * Desc: A simple device that * echos a message when read, * write method not implemented * * This was made on top of * LDD and LKMPG examples * */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/cdev.h> #include <asm/uaccess.h> #define DEVICE_NAME "gkos_char_device" /* * Prototypes */ int init_module(void); void cleanup_module(void); static int dev_open(struct inode *inode, struct file *); static int dev_release(struct inode *inode, struct file *); static ssize_t dev_read(struct file *fp, char *buf, size_t len, loff_t *off); static ssize_t dev_write(struct file *, const char *buf, size_t len, loff_t *off); static int dev_init(void); /* * Our variables, @use_counter * will block concurrenty opens. * @buffer is the message and * @buffer_len the lenght of @buffer (duh) */ static char use_counter = 0; static char buffer[] = "Hello character device world\n"; static int buffer_len = sizeof(buffer); static dev_t dev; static struct cdev *cdevp; static struct file_operations fops = { .owner = THIS_MODULE, .read = dev_read, .write = dev_write, .open = dev_open, .release = dev_release }; /* * Any device specific initialization * goes here. Its called at bottom of init_module() */ static int dev_init(void) { return 0; } /* * Called when device is opened */ static int dev_open(struct inode *inode, struct file *fp) { if (use_counter) return -EBUSY; use_counter++; try_module_get(THIS_MODULE); return 0; } /* * Called when device is released. The device is * released when there is no process using it. */ static int dev_release(struct inode *inode, struct file *fp) { use_counter--; module_put(THIS_MODULE); return 0; } /* * @off controls * the "walk" through our buffer, is whith @off * that we say to user where is stoped. * @len is how much bytes to read. I almost ignore it. * I just check if is greater than 0. * * Called when device is read. * This method will read one, and only one byte per call, * If @off is longer than my buffer size or len is not * greater than 0 it returns 0, otherwise I copy one byte * to user buffer and returns the bytes readed, so 1. */ static ssize_t dev_read(struct file *fp, char *buf, size_t len, loff_t *off) { if (*off >= buffer_len || len <= 0) return 0; if (copy_to_user(buf, &buffer[*off], 1u)) return -EFAULT; (*off)++; return 1; } /* * Not implemented at all */ static ssize_t dev_write(struct file *fp, const char *buf, size_t len, loff_t *off) { return -ENOSYS; } /* * Called when module is load */ int init_module(void) { int error; /* Alloc a device region */ error = alloc_chrdev_region(&dev, 1, 1, DEVICE_NAME); if (error) goto error_out; /* Registring */ cdevp = cdev_alloc(); if (!cdevp) return -ENOMEM; /* Init it! */ cdev_init(cdevp, &fops); /* Tell the kernel "hey, I'm exist" */ error = cdev_add(cdevp, dev, 1); if (error < 0) goto error_out; printk(KERN_INFO DEVICE_NAME " registred with major %d\n", MAJOR(dev)); printk(KERN_INFO DEVICE_NAME " do: `mknod /dev/%s c %d %d' to create " "the device file\n", DEVICE_NAME, MAJOR(dev), MINOR(dev)); /* Device initialization isn't needed yet */ if (dev_init()) goto error_out; return 0; error_out: return -EFAULT; } void cleanup_module(void) { cdev_del(cdevp); } MODULE_LICENSE("GPL");Makefile:
obj-m += gkos_char_device.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: rm *.ko *.o *.mod.c *.mod.oBuilding and Running: