免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5778 | 回复: 8
打印 上一主题 下一主题

如何编写LINUX设备驱动程序 [复制链接]

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
1 [报告]
发表于 2008-08-07 10:18 |显示全部楼层
原帖由 yyykkk1229 于 2008-8-7 16:37 发表
非常感谢楼上的回答,虽然说自己还是很模糊
慢慢琢磨吧,哎...现在思路有些乱


给lz提几点建议:
1、内核源码版本最好和系统版本要一致;
2、不要什么头文件都一骨碌弄进去,哪个函数需要哪个头文件,搞清楚了再说;
3、调用的函数有什么作用,参数的意义,都搞明确;
4、Makefile的写法,应该明确一些。

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
2 [报告]
发表于 2008-08-07 11:32 |显示全部楼层
/*  hello-1.c - The simplest kernel module.
*/
#include <linux/module.h>  /* Needed by all modules */
#include <linux/kernel.h>  /* Needed for KERN_ALERT */


int init_module(void)
{
   printk("<1>Hello world 1.\n");
       
   // A non 0 return means init_module failed; module can't be loaded.
   return 0;
}


void cleanup_module(void)
{
  printk(KERN_ALERT "Goodbye world 1.\n");
}  

把这个在2.4下面实现一下吧。

makefile:
TARGET  := hello-1
WARN    := -W -Wall -Wstrict-prototypes -Wmissing-prototypes
INCLUDE := -isystem /lib/modules/`uname -r`/build/include
CFLAGS  := -O2 -DMODULE -D__KERNEL__ ${WARN} ${INCLUDE}
CC      := gcc-3.0
       
${TARGET}.o: ${TARGET}.c

.PHONY: clean

clean:
    rm -rf {TARGET}.o

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
3 [报告]
发表于 2008-08-07 12:11 |显示全部楼层

回复 #6 yyykkk1229 的帖子

你试试这个,虚拟的一个设备,/dev/hello

  1. /*  chardev.c: Creates a read-only char device that says how many times
  2. *  you've read from the dev file
  3. */
  4.        
  5.         #if defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)
  6.            #include <linux/modversions.h>
  7.            #define MODVERSIONS
  8.         #endif
  9.         #include <linux/kernel.h>
  10.         #include <linux/module.h>
  11.         #include <linux/fs.h>
  12.         #include <asm/uaccess.h>  /* for put_user */
  13.        
  14.         /*  Prototypes - this would normally go in a .h file
  15.          */
  16.         int init_module(void);
  17.         void cleanup_module(void);
  18.         static int device_open(struct inode *, struct file *);
  19.         static int device_release(struct inode *, struct file *);
  20.         static ssize_t device_read(struct file *, char *, size_t, loff_t *);
  21.         static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
  22.        
  23.         #define SUCCESS 0
  24.         #define DEVICE_NAME "chardev" /* Dev name as it appears in /proc/devices   */
  25.         #define BUF_LEN 80            /* Max length of the message from the device */
  26.        
  27.        
  28.         /* Global variables are declared as static, so are global within the file. */
  29.        
  30.         static int Major;            /* Major number assigned to our device driver */
  31.         static int Device_Open = 0;  /* Is device open?  Used to prevent multiple  */
  32.                                         access to the device                       */
  33.         static char msg[BUF_LEN];    /* The msg the device will give when asked    */
  34.         static char *msg_Ptr;
  35.        
  36.         static struct file_operations fops = {
  37.           .read = device_read,
  38.           .write = device_write,
  39.           .open = device_open,
  40.           .release = device_release
  41.         };
  42.        
  43.        
  44.         /*                   Functions
  45.          */
  46.        
  47.         int init_module(void)
  48.         {
  49.            Major = register_chrdev(0, DEVICE_NAME, &fops);
  50.        
  51.            if (Major < 0) {
  52.              printk ("Registering the character device failed with %d\n", Major);
  53.              return Major;
  54.            }
  55.        
  56.            printk("<1>I was assigned major number %d.  To talk to\n", Major);
  57.            printk("<1>the driver, create a dev file with\n");
  58.                  printk("'mknod /dev/hello c %d 0'.\n", Major);
  59.            printk("<1>Try various minor numbers.  Try to cat and echo to\n");
  60.                  printk("the device file.\n");
  61.            printk("<1>Remove the device file and module when done.\n");
  62.        
  63.            return 0;
  64.         }
  65.        
  66.        
  67.         void cleanup_module(void)
  68.         {
  69.            /* Unregister the device */
  70.            int ret = unregister_chrdev(Major, DEVICE_NAME);
  71.            if (ret < 0) printk("Error in unregister_chrdev: %d\n", ret);
  72.         }  
  73.        
  74.        
  75.         /*                   Methods
  76.          */
  77.        
  78.         /* Called when a process tries to open the device file, like
  79.          * "cat /dev/mycharfile"
  80.          */
  81.         static int device_open(struct inode *inode, struct file *file)
  82.         {
  83.            static int counter = 0;
  84.            if (Device_Open) return -EBUSY;
  85.            Device_Open++;
  86.            sprintf(msg,"I already told you %d times Hello world!\n", counter++");
  87.            msg_Ptr = msg;
  88.            MOD_INC_USE_COUNT;
  89.        
  90.           return SUCCESS;
  91.         }
  92.        
  93.        
  94.         /* Called when a process closes the device file.
  95.          */
  96.         static int device_release(struct inode *inode, struct file *file)
  97.         {
  98.            Device_Open --;     /* We're now ready for our next caller */
  99.        
  100.            /* Decrement the usage count, or else once you opened the file, you'll
  101.                     never get get rid of the module. */
  102.            MOD_DEC_USE_COUNT;
  103.        
  104.            return 0;
  105.         }
  106.        
  107.        
  108.         /* Called when a process, which already opened the dev file, attempts to
  109.            read from it.
  110.         */
  111.         static ssize_t device_read(struct file *filp,
  112.            char *buffer,    /* The buffer to fill with data */
  113.            size_t length,   /* The length of the buffer     */
  114.            loff_t *offset)  /* Our offset in the file       */
  115.         {
  116.            /* Number of bytes actually written to the buffer */
  117.            int bytes_read = 0;
  118.        
  119.            /* If we're at the end of the message, return 0 signifying end of file */
  120.            if (*msg_Ptr == 0) return 0;
  121.        
  122.            /* Actually put the data into the buffer */
  123.            while (length && *msg_Ptr)  {
  124.        
  125.                 /* The buffer is in the user data segment, not the kernel segment;
  126.                  * assignment won't work.  We have to use put_user which copies data from
  127.                  * the kernel data segment to the user data segment. */
  128.               put_user(*(msg_Ptr++), buffer++);
  129.        
  130.               length--;
  131.               bytes_read++;
  132.            }
  133.        
  134.            /* Most read functions return the number of bytes put into the buffer */
  135.            return bytes_read;
  136.         }
  137.        
  138.        
  139.         /*  Called when a process writes to dev file: echo "hi" > /dev/hello */
  140.         static ssize_t device_write(struct file *filp,
  141.            const char *buff,
  142.                  size_t len,
  143.                  loff_t *off)
  144.         {
  145.            printk ("<1>Sorry, this operation isn't supported.\n");
  146.            return -EINVAL;
  147.         }
复制代码

makefile 我就不说了,自己编译,试一下。

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
4 [报告]
发表于 2008-08-07 14:13 |显示全部楼层
原帖由 yyykkk1229 于 2008-8-7 13:50 发表
感谢,可是还是同样的错误,说出现fops时出错,跟我刚才的问题一样,我刚才设置那个文件是用的是test_fops
Major = register_chrdev(0, DEVICE_NAME, &fops);
这句话的DEVICE_NAME应该如何设置呀


DEVICE_NAME前面不是有宏定义吗?你可不可以把你的makefile贴出来看看?

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
5 [报告]
发表于 2008-08-07 14:15 |显示全部楼层
还有一个问题,我刚才给你hello-1那个简单的模块,在你的系统下能成功编译加载么?

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
6 [报告]
发表于 2008-08-07 14:41 |显示全部楼层

回复 #11 yyykkk1229 的帖子

应该不是,你编译一下那个hello-1试一下,看能不能成功。

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
7 [报告]
发表于 2008-08-07 14:52 |显示全部楼层

回复 #11 yyykkk1229 的帖子

老大,你怎么没有加#include <linux/kernel.h>阿?

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
8 [报告]
发表于 2008-08-07 15:13 |显示全部楼层
错误1:没有找到这个文件asm/uaccess.h
错误2:Using kernel header in userland!  你的编译有问题,makefile可能写得不对,在用户空间引用内核头文件,这本身就可能造成错误。其它地方,可能是兼容性造成的错误。

[ 本帖最后由 dreamice 于 2008-8-7 15:23 编辑 ]

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
9 [报告]
发表于 2008-08-08 11:25 |显示全部楼层

回复 #19 yyykkk1229 的帖子

继续加油,大家一起交流学习
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP