Chinaunix首页 | 论坛 | 博客
  • 博客访问: 7688036
  • 博文数量: 961
  • 博客积分: 15795
  • 博客等级: 上将
  • 技术积分: 16612
  • 用 户 组: 普通用户
  • 注册时间: 2010-08-07 14:23
文章分类

全部博文(961)

文章存档

2016年(1)

2015年(61)

2014年(41)

2013年(51)

2012年(235)

2011年(391)

2010年(181)

分类: 嵌入式

2011-02-25 10:13:42

  1. /* 文件名:kpad.c */
  2. /* 说明:kpad 字符设备驱动例程 */

  3. #include <linux/module.h> /* 模块编程 */
  4. #include <linux/fs.h> /* 设备号、文件操作接口 */
  5. #include <linux/cdev.h> /* 字符设备编程接口 */
  6. #include <linux/uaccess.h> /* 访问用户态内存接口 */

  7. MODULE_LICENSE("GPL"); /* 版权声明 */

  8. #define BUF_SIZE 256 /* 内核缓冲区的大小 */

  9. /* 以下类型表示 kpad 设备 */
  10. struct kpad_dev {
  11.     struct cdev cdev; /* 内嵌一个字符设备作为代表向内核注册 */
  12.     char *buf; /* 保存内核缓冲区的首地址 */
  13.     int len; /* 保存内核缓冲区的长度 */
  14.     dev_t dev; /* 保存对应的设备号 */
  15. };

  16. /* 打开操作 */
  17. static int kpad_open(struct inode *inode, struct file *file)
  18. {
  19.     /* 由 inode 对应的字符设备指针得到 kpad 设备的地址 */
  20.     struct kpad_dev *dev = container_of(inode->i_cdev, struct kpad_dev, cdev);
  21.     pr_debug("kpad_open: be called!\n");
  22.     /* 将 kpad 设备的地址保存在打开的文件中 */
  23.     file->private_data = dev;
  24.     /* 返回 0 表示打开成功 */
  25.     return 0;
  26. }

  27. /* 关闭操作 */
  28. static int kpad_release(struct inode *inode, struct file *file)
  29. {
  30.     pr_debug("kpad_release: be called!\n");
  31.     /* 无操作,返回 0 表示成功 */
  32.     return 0;
  33. }

  34. /* 读操作 */
  35. static ssize_t kpad_read(struct file *file, char __user *buf,
  36.         size_t count, loff_t *pos)
  37. {
  38.     /* 从 file 中得到对应的 kpad 设备 */
  39.     struct kpad_dev *dev = (struct kpad_dev *)file->private_data;
  40.     pr_debug("kpad_read: pos = %d, count = %d.\n", (int)*pos, count);
  41.     /* 参数合法性检查 */
  42.     if (count < 0) return -EINVAL; /* 非法参数 */
  43.     if (count == 0) return 0; /* 直接返回 0 */
  44.     /* 控制读取的长度,不能超过当前读写位置到内核缓冲区末尾的长度 */
  45.     if (*pos+count > dev->len) count = dev->len-*pos;
  46.     if (count == 0) return 0; /* 无数据可读,返回 0 */
  47.     /* 从内核缓冲区复制数据到 buf 指向的用户态内存 */
  48.     if (copy_to_user(buf, dev->buf+*pos, count) > 0) {
  49.         pr_debug("kpad_read: copy_to_user() FAILED!\n");
  50.         return -EFAULT;
  51.     }
  52.     /* 修改文件的读写位置 */
  53.     *pos += count;
  54.     /* 返回读到的字节数 */
  55.     return count;
  56. }

  57. /* 写操作 */
  58. static ssize_t kpad_write(struct file *file, const char __user *buf,
  59.         size_t count, loff_t *pos)
  60. {
  61.     /* 从 file 中得到对应的 kpad 设备 */
  62.     struct kpad_dev *dev = (struct kpad_dev *)file->private_data;
  63.     pr_debug("kpad_write: pos = %d, count = %d.\n", (int)*pos, count);
  64.     /* 参数合法性检查 */
  65.     if (count < 0) return -EINVAL; /* 非法参数 */
  66.     if (count == 0) return 0; /* 直接返回 0 */
  67.     /* 控制写入的长度,不能超过当前读写位置到内核缓冲区末尾的长度 */
  68.     if (*pos+count > dev->len) count = dev->len-*pos;
  69.     if (count == 0) return -ENOSPC; /* 无空间可写,返回错误:设备无空间 */
  70.     /* 从 buf 指向的用户态内存复制数据到内核缓冲区 */
  71.     if (copy_from_user(dev->buf+*pos, buf, count) > 0) {
  72.         pr_debug("kpad_write: copy_from_user() FAILED!\n");
  73.         return -EFAULT;
  74.     }
  75.     /* 修改文件的读写位置 */
  76.     *pos += count;
  77.     /* 返回写入的字节数 */
  78.     return count;
  79. }

  80. /* 定位操作 */
  81. static loff_t kpad_llseek(struct file *file, loff_t offset, int whence)
  82. {
  83.     /* 从 file 中得到对应的 kpad 设备 */
  84.     struct kpad_dev *dev = (struct kpad_dev *)file->private_data;
  85.     loff_t pos; /* 用于暂存新的读写位置 */
  86.     pr_debug("kpad_llseek: f_pos = %d.\n", (int)file->f_pos);
  87.     switch (whence) { /* 根据 whence 参数采用不同的操作 */
  88.     case SEEK_SET: /* 相对于文件开始 */
  89.         pos = offset;
  90.         break;
  91.     case SEEK_CUR: /* 相对于当前位置 */
  92.         pos = file->f_pos+offset;
  93.         break;
  94.     case SEEK_END: /* 相对于文件结尾 */
  95.         pos = dev->len+offset;
  96.         break;
  97.     default:
  98.         return -EINVAL;
  99.     }
  100.     /* 新的读写位置应在合理范围之内 */
  101.     if (pos < 0 || pos > dev->len) return -EINVAL;
  102.     file->f_pos = pos; /* 修改文件的读写位置 */
  103.     return pos; /* 返回新的读写位置 */
  104. }

  105. /* 设备的文件操作,全局变量 */
  106. static struct file_operations kpad_fops = {
  107.     .owner = THIS_MODULE, /* 所属模块 */
  108.     .open = kpad_open, /* 打开操作 */
  109.     .release = kpad_release, /* 关闭操作 */
  110.     .read = kpad_read, /* 读操作 */
  111.     .write = kpad_write, /* 写操作 */
  112.     .llseek = kpad_llseek, /* 定位操作 */
  113. };

  114. /* 全局变量,表示一个 kpad 设备 */
  115. static struct kpad_dev kpad;

  116. /* 模块的初始化函数 */
  117. static __init int kpad_init(void)
  118. {
  119.     int err; /* 用于保存错误码 */
  120.     pr_debug("kpad_init: be called!\n");
  121.     /* 分配设备号 */
  122.     if ((err = alloc_chrdev_region(&kpad.dev, 0, 1, "kpad")) < 0) {
  123.         pr_debug("kpad_init: alloc_chrdev_region() ERR = %d!\n", -err);
  124.         goto alloc_chrdev_region_fail;
  125.     }
  126.     pr_debug("kpad_init: dev = (%d, %d).\n", MAJOR(kpad.dev), MINOR(kpad.dev));
  127.     /* 分配内核缓冲区 */
  128.     if ((kpad.buf = kmalloc(BUF_SIZE, GFP_KERNEL)) == NULL) {
  129.         pr_debug("kpad_init: kmalloc() ERR!\n");
  130.         err = -ENOMEM; /* 此错误号表示内存不足 */
  131.         goto kmalloc_kpad_buf_fail;
  132.     }
  133.     /* 保存缓冲区的长度 */
  134.     kpad.len = BUF_SIZE;
  135.     /* 初始化字符设备 */
  136.     cdev_init(&kpad.cdev, &kpad_fops);
  137.     kpad.cdev.owner = kpad_fops.owner;
  138.     /* 注册字符设备 */
  139.     if ((err = cdev_add(&kpad.cdev, kpad.dev, 1)) < 0) {
  140.         pr_debug("kpad_init: cdev_add() ERR = %d!\n", -err);
  141.         goto cdev_add_fail;
  142.     }
  143.     return 0; /* 返回 0 表示初始化成功 */
  144. /* 以下为出错处理,各个清理操作按初始化时的倒序排列,出错时跳转到相应的位置,
  145.  * 这是驱动编程中常用的做法 */
  146. cdev_add_fail:
  147.     kfree(kpad.buf); /* 释放所分配的内存 */
  148. kmalloc_kpad_buf_fail:
  149.     unregister_chrdev_region(kpad.dev, 1); /* 注销所注册的设备号 */
  150. alloc_chrdev_region_fail:
  151.     return err;
  152. }
  153. module_init(kpad_init); /* 指定 kpad_init 为模块的初始化函数 */

  154. /* 模块的退出函数 */
  155. static __exit void kpad_exit(void)
  156. {
  157.     pr_debug("kpad_exit: be called!\n");
  158.     /* 模块退出时进行清理,按初始化时的倒序操作 */
  159.     cdev_del(&kpad.cdev); /* 注销字符设备 */
  160.     kfree(kpad.buf); /* 释放所分配的内存 */
  161.     unregister_chrdev_region(kpad.dev, 1); /* 注销所注册的设备号 */
  162. }
  163. module_exit(kpad_exit); /* 指定 kpad_exit 为模块的退出函数 */
  1. # 文件名:Makefile
  2. # 说明:kpad 例程 Makefile

  3. # 模块名
  4. MOD_NAME := kpad

  5. # 模块源码(不能出现与模块名相同的文件名)
  6. SRCS := \

  7. EXTRA_CFLAGS = -DDEBUG

  8. OBJS := $(SRCS:.c=.o)

  9. ifeq ($(KERNELRELEASE),)

  10.   KERNELDIR ?= /lib/modules/$(shell uname -r)/build
  11.   PWD := $(shell pwd)

  12. default:
  13.     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

  14. clean:
  15.     -rm -f $(MOD_NAME).ko
  16.     -rm -f $(MOD_NAME).o
  17.     -rm -f $(OBJS)
  18.     -rm -rf .tmp_versions
  19.     -rm -f .*.cmd
  20.     -rm -f *.mod.c
  21.     -rm -f *.mod.o
  22.     -rm -f Module.symvers
  23.     -rm -f modules.order

  24. else

  25.   $(MOD_NAME)-objs := $(OBJS)
  26.   obj-m := $(MOD_NAME).o

  27. endif
阅读(1439) | 评论(0) | 转发(4) |
0

上一篇:图像运动检测程序

下一篇:内核模块例程

给主人留下些什么吧!~~