1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
| /************************************************************************* Late Lee from http://www.latelee.org 简单的字符型设备驱动 从应用层获取一数据,再复制到应用层(在前面添加字符串)。 注册设备号及设备号的几个宏,均系ldd3例子scull。
何处释放data更好?看ldd3,似乎exit中更好。 2011-04-29 & 2011-05-06 *************************************************************************/
#include <linux/module.h> #include <linux/kernel.h> /**< printk() */ #include <linux/init.h>
#include <linux/cdev.h> /**< cdev_* */ #include <linux/fs.h> #include <asm/uaccess.h> /**< copy_*_user */
#include <linux/types.h> /**< size_t */ #include <linux/errno.h> /**< error codes */ #include <linux/string.h>
#ifdef DEBUG /* define it in Makefile or somewhere */ /* KERN_INFO */ #define debug(fmt, ...) printk(KERN_DEBUG fmt, ##__VA_ARGS__) #else #define debug(fmt, ...) #endif
#define DEV_NAME "foo"
//#define HAVE_MAJOR #ifdef HAVE_MAJOR #define DEVICE_MAJOR 248 #else /* auto alloc */ #define DEVICE_MAJOR 0 #endif /* HAVE_MAJOR */
#define FOO_NR_DEVS 1
struct cdev foo_cdev; int foo_major = DEVICE_MAJOR; int foo_minor = 0; int foo_nr_devs = FOO_NR_DEVS; dev_t devno; char *data;
static int foo_open(struct inode *inode, struct file *filp) { debug("in %s()/n", __func__); return 0; }
static int foo_release(struct inode *inode, struct file *filp) { debug("in %s()/n", __func__); //kfree(data); //data = NULL; return 0; }
static ssize_t foo_read(struct file *filp, char *buf, size_t count, loff_t *f_ops) { int len; char *tmp; if (count < 0) return -EINVAL; tmp = (char *)kmalloc(sizeof(char) * (count+1), GFP_KERNEL); // ?? here sprintf(tmp, "The voice from hell: %s", data); len = strlen(tmp); if (len < count) count = len; if ( copy_to_user(buf, tmp, count) ) return -EFAULT; debug("in %s() tmp: %s/n", __func__, tmp); debug("in %s() buf: %s/n", __func__, buf); debug("in %s() data: %s/n", __func__, data); kfree(tmp); return count; }
static ssize_t foo_write(struct file *filp, const char *buf, size_t count, loff_t *f_ops) { if (count < 0) return -EINVAL; data = (char *)kmalloc(sizeof(char) * (count+1), GFP_KERNEL); if (data == NULL) return -ENOMEM; if (copy_from_user(data, buf, count+1)) return -EFAULT; debug("in %s() buff: %s/n", __func__, buf); debug("in %s() data: %s/n", __func__, data); return count; }
static int foo_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { switch (cmd) { default: return -EINVAL; } return 0; }
static struct file_operations foo_fops = { .owner = THIS_MODULE, .open = foo_open, .release = foo_release, .read = foo_read, .write = foo_write, .ioctl = foo_ioctl, };
static int __init foo_init(void) { int ret = -1;
cdev_init(&foo_cdev, &foo_fops); foo_cdev.owner = THIS_MODULE; /* register to who? */ if (foo_major) { devno = MKDEV(foo_major, foo_minor); ret = register_chrdev_region(devno, foo_nr_devs, DEV_NAME); } else { ret = alloc_chrdev_region(&devno, foo_minor, foo_nr_devs, DEV_NAME); /* get devno */ foo_major = MAJOR(devno); /* get major */ } if (ret < 0) { debug(" %s can't get major %d/n", DEV_NAME, foo_major); return -EINVAL; } ret = cdev_add(&foo_cdev, devno, 1); if (ret < 0) { debug(" %s cdev_add failure!/n", DEV_NAME); return -EINVAL; } debug("%s init ok!/n", DEV_NAME); return 0; }
static void __exit foo_exit(void) { if (data != NULL) kfree(data); unregister_chrdev_region(devno, 1); cdev_del(&foo_cdev); debug("%s exit ok!/n", DEV_NAME); }
module_init(foo_init); module_exit(foo_exit); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Chiangchin Li");
|