Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1176860
  • 博文数量: 573
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 66
  • 用 户 组: 普通用户
  • 注册时间: 2016-06-28 16:21
文章分类

全部博文(573)

文章存档

2018年(3)

2016年(48)

2015年(522)

分类: LINUX

2015-12-07 14:45:51

makefile文件

点击(此处)折叠或打开

  1. # File: Makefile
  2. # wangxiancai

  3. MODEXT = ko
  4. INSTALLDIR=/home/wangxc/linux/rootfs/nfs_2.6.13/wxc/driver/chardriver/ko
  5. # INSTALLDIR=/home/wangxc/linux/rootfs/nfs_2.6.30/wxc/driver/chardriver/ko
  6. CROSS=/home/wangxc/linux/toolchain/crosstools_3.4.1_softfloat/arm-linux/gcc-3.4.1-glibc-2.3.3/bin/arm-linux-
  7. # CROSS=/home/wangxc/linux/toolchain/crosstools_4.4.3_softfloat/bin/arm-linux-
  8. KERNELDIR=/home/wangxc/linux/kernel/kernel-2.6.13
  9. # KERNELDIR=/home/wangxc/linux/kernel/kerner-2.6.30

  10. CC= $(CROSS)gcc
  11. LD= $(CROSS)ld

  12. #############################################################################
  13. # Compiler Flags
  14. #############################################################################
  15. EXTRA_CFLAGS += -I$(KERNELDIR)/include
  16. #############################################################################
  17. # Make Targets
  18. #############################################################################
  19. obj-m := proc_mymsg.o mydriver_myprintk.o
  20. default:
  21.     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
  22. # Otherwise we were called directly from the command line; invoke the kernel build system.

  23. install: default
  24.     rm -rf $(INSTALLDIR)/proc_mymsg.$(MODEXT)
  25.     cp -rf $(PWD)/proc_mymsg.$(MODEXT) $(INSTALLDIR)
  26.     rm -rf $(INSTALLDIR)/mydriver_myprintk.$(MODEXT)
  27.     cp -rf $(PWD)/mydriver_myprintk.$(MODEXT) $(INSTALLDIR)

  28. dis:
  29.     $(CROSS)objdump -D proc_mymsg.ko > proc_mymsg.dis
  30.     $(CROSS)objdump -D mydriver_myprintk.ko > mydriver_myprintk.dis    

  31. clean:
  32.     rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.bak modules.order Module.symvers
proc_mymsg.c文件

点击(此处)折叠或打开

  1. /*目的:printk()非常多时,一屏难以显示,怎么办?使用proc虚拟文件系统来实现。
  2. * 让其他驱动程序,可以使用myprintk()函数,并且把日志保存在一个我们自己指定的文件中。
  3. * 自己的驱动使用自己的打印函数,让自己打印的日志和内核打印的日志 分别存放。
  4. 仿照printk函数,自己建立一个mylog_buf,自己建立一个/proc/mymsg 文件,写一个驱动程序myprintk()
  5. 参考文件 : \kernel-2.6.13\fs\proc\proc_misc.c
  6. */

  7. #include <linux/module.h>
  8. #include <linux/kernel.h>
  9. #include <linux/fs.h>
  10. #include <linux/init.h>
  11. #include <linux/delay.h>
  12. #include <asm/irq.h>
  13. #include <linux/device.h>
  14. #include <asm-arm/arch/regs-gpio.h>
  15. #include <asm/arch/hardware.h>
  16. #include <linux/miscdevice.h>
  17. #include <linux/slab.h>
  18. #include <linux/ioport.h>
  19. #include <linux/fcntl.h>
  20. #include <linux/fs.h>
  21. #include <asm/io.h>
  22. #include <asm/uaccess.h>
  23. #include <asm/system.h>
  24. #include <linux/device.h>
  25. #include <asm/arch/regs-gpio.h>
  26. #include <asm/hardware.h>

  27. #include <linux/proc_fs.h>

  28. #define MYLOG_BUF_LEN 1024 /*环形缓冲区的长度*/
  29. static char mylog_buf[MYLOG_BUF_LEN]; /*定义一个环形缓冲区,最后会留一个空间放\0*/
  30. static char tmp_buf[MYLOG_BUF_LEN]; /*myprintk函数中要使用的一个临时变量*/
  31. static int mylog_r = 0;        /*环形缓冲区读指针,每读取一个,则表示缓冲区少了一个数据,则读指针也要后移一位,读指针总是指向下一个要读取的位置,肯定是数据位的第1个位置。后移到缓冲区尾时,则跳到缓冲区最开始的位置重新开始*/
  32. static int mylog_w = 0;        /*环形缓冲区写指针,每写入一个,则表示缓冲区多了一个数据,则写指针也要后移一位,写指针总是指向下一个要写入的位置,肯定是空位置的第1个位置。后移到缓冲区尾时,则跳到缓冲区最开始的位置重新开始*/

  33. /*为了可以多次cat,做的一个小的技术性的修改,用另外一个变量 mylog_r_for_read 来表示 读取位置,
  34. 不使用mylog_r变量。在open()函数里面,让 mylog_r_for_read 的初始值 为
  35. */
  36. static int mylog_r_for_read = 0;

  37. struct proc_dir_entry * myentry;
  38. static DECLARE_WAIT_QUEUE_HEAD(mymsg_waitq); /*申明一个等待队列头*/



  39. /*函数功能 : 判断缓冲区是否是空的
  40. *函数返回值 : 返回1 : 缓冲区空
  41. * 返回0 : 缓冲区非空
  42. */
  43. static int is_mylog_empty(void)
  44. {
  45.     /*如果读指针==写指针,则表示环形缓冲区是空的,则函数返回1*/
  46.     return (mylog_r == mylog_w);
  47. }

  48. /*函数功能 : 同is_mylog_empty()函数
  49. */
  50. static int is_mylog_empty_for_read(void)
  51. {
  52.     return (mylog_r_for_read == mylog_w);
  53. }

  54. /*函数功能 : 判断缓冲区是否是满的
  55. *函数返回值 : 返回1 : 缓冲区满
  56. * 返回0 : 缓冲区非满
  57. */
  58. static int is_mylog_full(void)
  59. {
  60.     /*如果写指针的下一个位置是读指针,则表示环形缓冲区是满的,则函数返回1*/
  61.     return ((mylog_w + 1)% MYLOG_BUF_LEN == mylog_r);
  62. }

  63. /*函数功能 : 向缓冲区里面写入1个字节的数据
  64. */
  65. static void mylog_putc(char c)
  66. {
  67.     if(is_mylog_full()) //满了
  68.     {
  69.         /* 丢弃一个数据 : 向后移动(即向右边移动指针)一下读指针,这样,相当于丢弃了一个老的数据,腾出一个空位置出来,以便可以写进去新的数据。
  70.         * 即当环形缓冲区已经写满了,还要继续写入的话,会覆盖掉原来的数据,继续写入。
  71.         */
  72.         mylog_r = (mylog_r + 1) % MYLOG_BUF_LEN;
  73.         
  74.         /*读取指针 mylog_r 后移了,另外一个读取指针mylog_r_for_read的位置,可能在 mylog_r 指向的位置,也可能在其后面一点,
  75.         *所以,另外一个读取指针mylog_r_for_read的位置,可能也要后移,才对。
  76.         *特例 : mylog_getc_for_read()之后,mylog_r_for_read 的位置后移了,如果这时myprintk继续使用,
  77.         * 出来很多日志,写满了缓冲区,使得 mylog_r 指向的位置后移超过了 mylog_r_for_read,
  78.         * 此时,再 mylog_getc_for_read(),则不会使用后来新覆盖的数据。
  79.         */
  80.         if((mylog_r_for_read + 1) % MYLOG_BUF_LEN == mylog_r) /*一旦 mylog_r 向后移的位置 超过了 mylog_r_for_read 的位置,则 mylog_r_for_read 也要跟着后移了。*/
  81.         {
  82.                 mylog_r_for_read = mylog_r; /*mylog_r_for_read 后移到 读取指针 mylog_r 相同的位置*/
  83.         }
  84.     }
  85.     //还没有满
  86.     mylog_buf[mylog_w] = c; //写指针指向的位置,填充1个字符
  87.     mylog_w = (mylog_w + 1) % MYLOG_BUF_LEN; //写指针后移1个位置

  88.     /* 唤醒等待数据的进程 */
  89.     wake_up_interruptible(&mymsg_waitq); /* 唤醒休眠的进程 */    
  90. }

  91. /*函数功能 : 从缓冲区里面读取1个字节的数据
  92. *函数参数 : 输出参数,保存读取的值
  93. *返回值 : 0 : 读取不到数据
  94. * 1 : 成功读取到1个字节的数据
  95. */
  96. static int mylog_getc(char *p)
  97. {
  98.     if(is_mylog_empty()) //空的
  99.     {
  100.             return 0;
  101.     }
  102.     //有数据
  103.     *p = mylog_buf[mylog_r]; //从读指针指向的位置读取1个字节
  104.     mylog_r = (mylog_r + 1) % MYLOG_BUF_LEN; //读指针后移1个位置
  105.     return 1;
  106. }

  107. /*函数功能 : 同mylog_getc()函数,不使用 读写位置指针:mylog_r
  108. *函数参数 : 输出参数,保存读取的值
  109. *返回值 : 0 : 读取不到数据
  110. * 1 : 成功读取到1个字节的数据
  111. */
  112. static int mylog_getc_for_read(char *p)
  113. {
  114.     if(is_mylog_empty_for_read())
  115.     {
  116.         return 0;
  117.     }
  118.     //有数据
  119.     *p = mylog_buf[mylog_r_for_read]; /*用另外一个变量,不使用以前的位置指针 mylog_r*/
  120.     mylog_r_for_read = (mylog_r_for_read + 1) % MYLOG_BUF_LEN;
  121.     return 1;
  122. }

  123. /*自己创造的一个printk函数*/
  124. int myprintk(const char *fmt, ...)
  125. {
  126.     va_list args;
  127.     int i;
  128.     int j;

  129.     va_start(args, fmt);
  130.     i = vsnprintf(tmp_buf, INT_MAX, fmt, args);
  131.     va_end(args);
  132.     //临时缓冲区中,已经有数据了,可以填充到环形缓冲区中了。
  133.     for (j = 0; j < i; j++)
  134.     {
  135.         mylog_putc(tmp_buf[j]); //写到环形缓冲区中
  136.     }
  137.         
  138.     return i;
  139. }

  140. /*函数功能 : 把mylog_buf的数据copy_to_user拷贝到用户空间
  141. *注意 : 下面的驱动程序,在 cat 执行之后,肯定会先 mymsg_open(),再 mymsg_read()
  142. * 其中 mylog_getc()函数,会将读指针 mylog_r 后移,再次cat的时候,mylog_r 已经后移了。
  143. * 这样就不是我们想要的效果,我们想要每次cat,都可以读出全部内容,如何修改???
  144. *思路 : 每次 mymsg_read() 前,mylog_r必须在起点位置。
  145. */
  146. static ssize_t mymsg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
  147. {
  148.     int error = 0;
  149.     int i = 0;
  150.     char c;

  151.     /* 如果以非阻塞方式读取+缓冲区是空,则报错返回。*/
  152.     /*if((file->f_flags & O_NONBLOCK) && is_mylog_empty())*/
  153.     if((file->f_flags & O_NONBLOCK) && is_mylog_empty_for_read()) /*为了可以多次使用cat函数*/
  154.     {
  155.             return -EAGAIN;
  156.     }

  157.     /*以阻塞方式读取
  158.     睡眠等待,直到缓冲区非空。即如果缓冲区是空,则本进程休眠*/
  159.     /*error = wait_event_interruptible(mymsg_waitq, !is_mylog_empty());*/
  160.     error = wait_event_interruptible(mymsg_waitq, !is_mylog_empty_for_read()); /*为了可以多次使用cat函数*/

  161.     /* 缓冲区非空 或者 本进程被唤醒,则copy_to_user */
  162.     /* while(!error && (mylog_getc(&c)) && i < count) */
  163.     while(!error && (mylog_getc_for_read(&c)) && i < count) /*为了可以多次使用cat函数*/
  164.     {
  165.             error = __put_user(c, buf);
  166.             buf++;
  167.             i++;
  168.     }
  169.     
  170.     if(!error) //如果没有错误,则error赋i值,再返回。
  171.     {
  172.             error = i;
  173.     }

  174.     return error;
  175. }

  176. /*open函数*/
  177. static int mymsg_open(struct inode *inode, struct file *file)
  178. {
  179.     /*cat执行一次,则open执行一次,让mylog_r_for_read指向 当前 读取位置 mylog_r
  180.     *目的 : 保持原来的值不变,用另外一个变量去表示读取位置。
  181.     * 这样,无论执行多少次cat,读取位置都会保存不变。
  182.     */
  183.     mylog_r_for_read = mylog_r;
  184.     return 0;
  185. }

  186. struct file_operations proc_mymsg_operations = {

  187.     .read        = mymsg_read,
  188.     .open        = mymsg_open,
  189. };

  190. static int __init mymsg_init(void)
  191. {
  192.     /*create_proc_entry函数功能 : 在虚拟文件系统/proc目录下面,生成一个文件 mymsg
  193.     *参数 : mymsg : 目录名称
  194.     * S_IRUSR : 文件权限,只读
  195.     * proc_root : 父目录
  196.     */
  197.     myentry = create_proc_entry("mymsg", S_IRUSR, &proc_root);
  198.     if(myentry)
  199.     {
  200.             /*注意 : 以后读写myentry条目指向的文件的时候,会调用到这里给出的操作函数。*/
  201.             myentry->proc_fops = &proc_mymsg_operations;
  202.     }
  203.     
  204.     return 0;
  205. }

  206. static void __exit mymsg_exit(void)
  207. {
  208.     remove_proc_entry("mymsg", &proc_root);

  209.     return;
  210. }

  211. module_init(mymsg_init);
  212. module_exit(mymsg_exit);

  213. /*EXPORT_SYMBOL()功能 : 导出myprintk函数,以便其他驱动程序可以使用。*/
  214. EXPORT_SYMBOL(myprintk);

  215. MODULE_AUTHOR("wangxiancai");
  216. MODULE_DESCRIPTION("DEVICE : key");
  217. MODULE_LICENSE("GPL");


  218. /*
  219. *注意 : 本驱动程序提供的myprintk()函数,测试的驱动程序在: nfs_2.6.13\wxc\driver\chardriver\example\mydriver_myprintk.c
  220. * 测试的应用程序在: nfs_2.6.13\wxc\app\example\mydrivertest_myprintk.c
  221. *测试步骤 :
  222. * 1,直接插入我们自己使用myprintk函数的驱动模块 : insmod mydriver_myprintk.ko
  223. * 会报错如下 : mydriver_myprintk: Unknown symbol myprintk
  224. * insmod: cannot insert `mydriver_myprintk.ko': Unknown symbol in module (-1): No such file or directory
  225. *                2,所以需要我们先插入生成myprintk函数的驱动模块 :
  226. *                        # insmod proc_mymsg.ko
  227. * 3, insmod mydriver_myprintk.ko
  228. *                        # cat /proc/mymsg //可以看见myprintk打印的日志已经保存在这个文件里面了。
  229. *                        DEVICE:mydriver_init
  230. *                        DEVICE:register mydriver Major = [253]
  231. *                        DEVICE:initialized
  232. * mknod /dev/mydriver_myprintk c 253 0
  233. * 4,应用程序 :
  234. *                        # ./mydrivertest_myprintk
  235. *                        APP:open fd=[3]
  236. *                        APP:0000000000000000000000000000000
  237. *                        APP:readbuf = [zhangqiuping], ret=[12]
  238. *                        APP:1111111111111111111111111111111
  239. *                        APP:writebuf = [wangxiancai], ret=[11]
  240. *                        APP:2222222222222222222222222222222
  241. *                        
  242. *                        # cat /proc/mymsg //可以看见myprintk新打印的日志已经保存在这个文件里面了。
  243. *                        DEVICE:mydriver_open
  244. *                        DEVICE:mydriver_read
  245. *                        DEVICE:buf=[],count=[12],*f_pos=[0]
  246. *                        DEVICE:mydriver_read:copy_to_user:ret=[0]
  247. *                        DEVICE:readbuf=[zhangqiuping],buf=[zhangqiuping],count=[12],*f_pos=[0]
  248. *                        DEVICE:mydriver_write
  249. *                        DEVICE:buf=[wangxiancai],count=[11],*f_pos=[0]
  250. *                        DEVICE:mydriver_write:copy_from_user:ret=[0], writebuf=[wangxiancai]
  251. *                        DEVICE:buf =[wangxiancai],count=[11],*f_pos=[0]
  252. *                        DEVICE:mydriver_release
  253. *
  254. * 注意 : cat一次,就会read一次全部的文件,文件位置指针会指向文件尾部,如果没有新数据加入到文件,则再次cat时,什么也看不见。
  255. * 5, 解决cat的问题后,再测试。cat可以多次执行。
  256. */
mydriver_myprintk.c文件

点击(此处)折叠或打开

  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/fs.h>
  4. #include <linux/init.h>
  5. #include <linux/delay.h>
  6. #include <asm/irq.h>
  7. #include <linux/device.h>

  8. #include <asm-arm/arch/regs-gpio.h>
  9. #include <asm/arch/hardware.h>

  10. #include <linux/miscdevice.h>
  11. #include <linux/slab.h>
  12. #include <linux/ioport.h>
  13. #include <linux/fcntl.h>
  14. #include <linux/fs.h>

  15. #include <asm/io.h>
  16. #include <asm/uaccess.h>
  17. #include <asm/system.h>

  18. #include <linux/device.h>

  19. #define DEVICE_NAME    "mydriver_myprintk"
  20. static int MYDRIVER_Major = 0;

  21. static char readbuf[1024] = "zhangqiuping";
  22. static char writebuf[1024] ="";

  23. static struct class * mydriver_class;
  24. static struct class_device    * mydriver_class_dev;

  25. /*申明一个外部定义的函数,申明之后,本程序就可以使用了。
  26. *要想使用myprintk函数需要先插入生成myprintk()函数的驱动模块 # insmod proc_mymsg.ko
  27. *再插入本驱动程序的模块,才可以正常使用myprintk()函数。
  28. */
  29. extern int myprintk(const char *fmt, ...);

  30. static int mydriver_open(struct inode *inode, struct file *file)
  31. {
  32.     myprintk("DEVICE:mydriver_open Called!\n");
  33.     return 0;
  34. }

  35. static int mydriver_release(struct inode *inode, struct file *file)
  36. {
  37.     myprintk("DEVICE:mydriver_release Called!\n");
  38.     return 0;
  39. }

  40. /*
  41. count : 应用程序传来的read的第3个参数。
  42. */
  43. static int mydriver_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
  44. {
  45.     int ret = -1;
  46.     
  47.     myprintk("DEVICE:mydriver_read Called!\n");
  48.     myprintk("DEVICE:buf=[%s],count=[%ld],*f_pos=[%ld]\n", buf, (long)count, (long)(*f_pos));
  49.     
  50.     if(count < 1024)
  51.     {
  52.         /*
  53.         put_user("zhangqiuping", buf);
  54.         */
  55.         ret=copy_to_user(buf, readbuf, count);
  56.         myprintk("DEVICE:mydriver_read:copy_to_user:ret=[%d]\n", ret);
  57.         myprintk("DEVICE:readbuf=[%s],buf=[%s],count=[%ld],*f_pos=[%ld]\n",readbuf, buf, (long)count, (long)(*f_pos));
  58.         if(ret == 0) /*正常返回*/
  59.         {
  60.             return count;
  61.         }
  62.         else /*错误返回*/
  63.         {
  64.             myprintk("copy_to_user faile!\n");
  65.             return -EFAULT;
  66.         }
  67.     }
  68.     else
  69.     {
  70.         myprintk("buffer should less than 1024\n");
  71.         return -EFAULT;
  72.     }
  73. }

  74. static int mydriver_write(struct file *file, const char __user *buf, size_t count, loff_t *f_pos)
  75. {
  76.     int ret;
  77.     
  78.     myprintk("DEVICE:mydriver_write Called!\n");
  79.     myprintk("DEVICE:buf=[%s],count=[%ld],*f_pos=[%ld]\n", buf, (long)count, (long)(*f_pos));
  80.     
  81.     if(count < 1024)
  82.     {
  83.         ret = copy_from_user(writebuf, buf, count);
  84.         myprintk("DEVICE:mydriver_write:copy_from_user:ret=[%d], writebuf=[%s]\n", ret, writebuf);
  85.         myprintk("DEVICE:buf =[%s],count=[%ld],*f_pos=[%ld]\n", buf, (long)count, (long)(*f_pos));
  86.         if(ret == 0) /*正常返回*/
  87.         {
  88.             return count;
  89.         }
  90.         else /*错误返回*/
  91.         {
  92.             myprintk("copy_from_user faile\n");
  93.             return -EFAULT;
  94.         }
  95.     }
  96.     else
  97.     {
  98.         myprintk("buffer should less than 1024\n");
  99.         return -EFAULT;
  100.     }
  101. }

  102. static int mydriver_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
  103. {
  104.     myprintk("DEVICE:mydriver_ioctl Called!\n");
  105.     myprintk("DEVICE:cmd=[%d], arg=[%ld]\n", cmd, arg);
  106.     
  107.     return 0;
  108. }

  109. /*
  110. static : 表示只在本文件中使用
  111. */
  112. static struct file_operations mydriver_fops =
  113. {
  114.     .owner = THIS_MODULE, /*固定写这个*/
  115.     .open = mydriver_open,
  116.     .release = mydriver_release,
  117.     .read = mydriver_read,
  118.     .write = mydriver_write,
  119.     .ioctl = mydriver_ioctl,
  120. };

  121. /*
  122. __init __exit其实不要,也是可以运行的
  123. 这里加上的目的是:
  124. 当编译进内核时;
  125. __init : 在初始化完成之后,丢弃该函数,并收回内存,无__init标示是,标示不收回内存。
  126. __exit : 忽略“清理收尾”的函数,即忽略mydriver_exit()函数所占的空间,因为既然编译进内核了,就不可能再卸载了,就不需要这个函数了。

  127. 当编译成模块时,__init __exit : 用不用都一样,
  128. */
  129. static int __init mydriver_init(void)
  130. {
  131.     myprintk("DEVICE:mydriver_init\n");
  132.     /*
  133.     老方法注册:
  134.     int register_chrdev(unsigned int major, const char * name, struct file_operations * fops);
  135.     register_chrdev函数功能:注册一个字符设备,并向内核添加一个设备了。
  136.     只是在内核数组中,把mydriver_fops结构 填充进去。还不会生成文件系统的信息,也不会生成设备节点。
  137.     第1个参数:主设备号,0:表示让内核自动分配一个设备号。也可以程序员自己指定:第1个参数指定为非0的数,比如233。
  138.     第2个参数:要生成的设备的名称。
  139.     第3个参数:文件操作的结构体。
  140.     返回值:第1个参数是0,就返回主设备号。第1个参数是253,注册成功返回0,注册失败返回非0。
  141.     */
  142.     MYDRIVER_Major = register_chrdev(0, DEVICE_NAME, &mydriver_fops);
  143.     if (MYDRIVER_Major < 0)
  144.     {
  145.         myprintk(DEVICE_NAME " can't register major number\n");
  146.         return MYDRIVER_Major;
  147.     }
  148.     myprintk("DEVICE:register mydriver OK! Major = [%d]\n", MYDRIVER_Major);

  149.     /*注册一个类,使mdev可以在"/dev/"目录下面建立设备节点
  150.     静态编译进内核的,才可以依赖mdev来建立设备节点,
  151.     编译成模块的,还是必须得使用,insmod,mknod,rmmod
  152.     */
  153.     mydriver_class = class_create(THIS_MODULE, DEVICE_NAME);
  154.     if(IS_ERR(mydriver_class))
  155.     {
  156.         myprintk("DEVICE:class_create err!\n");
  157.         return -1;
  158.     }
  159.     //创建一个设备节点,节点名为DEVICE_NAME
  160.     //device_create(mydriver_class, NULL, MKDEV(MYDRIVER_Major, 0), NULL, DEVICE_NAME);
  161.     mydriver_class_dev = class_device_create(mydriver_class, MKDEV(MYDRIVER_Major, 0), NULL, DEVICE_NAME); // dev/mydriver

  162.     myprintk("DEVICE:initialized\n");
  163.     return 0;
  164. }

  165. static void __exit mydriver_exit(void)
  166. {
  167.     myprintk("DEVICE:mydriver_exit####################\n");
  168.     
  169.   /*unregister_chrdev函数功能:
  170.   老方法注销:将注册的字符设备撤销
  171.   unregister_chrdev(unsigned int major, const char * name);
  172.   */
  173.     unregister_chrdev(MYDRIVER_Major, DEVICE_NAME);
  174.     class_device_destroy(mydriver_class, MKDEV(MYDRIVER_Major, 0));
  175.     class_destroy(mydriver_class);
  176. }

  177. module_init(mydriver_init);
  178. module_exit(mydriver_exit);

  179. MODULE_AUTHOR("wangxiancai");    
  180. MODULE_DESCRIPTION("DEVICE:mydriver");
  181. MODULE_LICENSE("GPL");


  182. /*
  183. 源码分析:

  184. 内核使用read,write函数来和用户传输数据:
  185. 因为,用户空间和内核空间,不能使用memcpy这样的拷贝,而是使用内核提供的接口来进行,如下2个函数,是内核提供的接口:
  186. #include <asm/uaccess.h>
  187. unsigned long copy_to_user(void __usr * to, const void * from, unsigned long count); //数据:内核空间->用户空间

  188. ungigned long copy_from_user(void * to, const void * __user from, unsigned long count);//数据:用户空间->内核空间

  189. */

应用程序:

点击(此处)折叠或打开

  1. CROSS=/home/wangxc/linux/toolchain/crosstools_3.4.1_softfloat/arm-linux/gcc-3.4.1-glibc-2.3.3/bin/arm-linux-gcc
  2. all: myprintk regeditor
  3. myprintk:myprintk.c
  4.     $(CROSS) -o myprintk myprintk.c
  5. clean:
  6.     @rm -vf myprintk.o myprintk 
myprintk.c文件

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <fcntl.h>
  6. #include <sys/ioctl.h>

  7. int main(int argc, char **argv)
  8. {
  9.     int fd = -1;
  10.     int ret = -1;
  11.     char readbuf[1024];
  12.     char writebuf[1024];

  13.     fd = open("/dev/mydriver_myprintk", O_RDWR|O_TRUNC);
  14.     if (fd < 0)
  15.     {
  16.         perror("APP:open err!");
  17.         exit(1);
  18.     }
  19.     printf("APP:open fd=[%d]\n", fd);
  20.     
  21.     printf("APP:0000000000000000000000000000000\n");
  22.     
  23.     memset(readbuf, 0, sizeof(readbuf));
  24.     ret=read(fd, readbuf, 12);
  25.     if(ret<0)
  26.     {
  27.         perror("APP:read err!");
  28.         exit(1);
  29.     }
  30.     printf("APP:readbuf = [%s], ret=[%d]\n", readbuf, ret);
  31.     
  32.     printf("APP:1111111111111111111111111111111\n");
  33.     
  34.     memset(writebuf, 0, sizeof(writebuf));
  35.     strcpy(writebuf, "wangxiancai");
  36.     ret=write(fd, writebuf, 11); /*返回值还有问题*/
  37.     printf("APP:writebuf = [%s], ret=[%d]\n", writebuf, ret);
  38.     if(ret<0)
  39.     {
  40.         perror("APP:write err!");
  41.         exit(1);
  42.     }
  43.     
  44.     printf("APP:2222222222222222222222222222222\n");
  45.     
  46.     close(fd);
  47.     
  48.     return 0;
  49. }



阅读(970) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~