六狼论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

新浪微博账号登陆

只需一步,快速开始

搜索
查看: 38|回复: 0

Linux驱动开发入门(二)

[复制链接]

升级  31.33%

90

主题

90

主题

90

主题

举人

Rank: 3Rank: 3

积分
294
 楼主| 发表于 2013-1-26 12:29:18 | 显示全部楼层 |阅读模式
本文制作一个char设备。撰写chardev.c如下:

/* * http://linux.die.net/lkmpg/x569.html *//* *  chardev.c: Creates a read-only char device that says how many times *  you've read from the dev file */#include <linux/kernel.h>#include <linux/module.h>#include <linux/fs.h>#include <asm/uaccess.h>        /* for put_user *//*   *  Prototypes - this would normally go in a .h file */int init_module(void);void cleanup_module(void);static int device_open(struct inode *, struct file *);static int device_release(struct inode *, struct file *);static ssize_t device_read(struct file *, char *, size_t, loff_t *);static ssize_t device_write(struct file *, const char *, size_t, loff_t *);#define SUCCESS 0#define DEVICE_NAME "chardev"   /* Dev name as it appears in /proc/devices   */#define BUF_LEN 80              /* Max length of the message from the device *//*  * Global variables are declared as static, so are global within the file.  */static int Major;               /* Major number assigned to our device driver */static int Device_Open = 0;     /* Is device open?                                   * Used to prevent multiple access to device */static char msg[BUF_LEN];       /* The msg the device will give when asked */static char *msg_Ptr;static struct file_operations fops = {        .read = device_read,        .write = device_write,        .open = device_open,        .release = device_release};/* * This function is called when the module is loaded */int init_module(void){        Major = register_chrdev(0, DEVICE_NAME, &fops);        if (Major < 0) {          printk(KERN_ALERT "Registering char device failed with %d\n", Major);          return Major;        }        printk(KERN_INFO "I was assigned major number %d. To talk to\n", Major);        printk(KERN_INFO "the driver, create a dev file with\n");        printk(KERN_INFO "'mknod /dev/%s c %d 0'.\n", DEVICE_NAME, Major);        printk(KERN_INFO "Try various minor numbers. Try to cat and echo to\n");        printk(KERN_INFO "the device file.\n");        printk(KERN_INFO "Remove the device file and module when done.\n");        return SUCCESS;}/* * This function is called when the module is unloaded */void cleanup_module(void){        /*          * Unregister the device          */        unregister_chrdev(Major, DEVICE_NAME);}/* * Methods *//*  * Called when a process tries to open the device file, like * "cat /dev/mycharfile" */static int device_open(struct inode *inode, struct file *file){        static int counter = 0;        if (Device_Open)                return -EBUSY;        Device_Open++;        sprintf(msg, "I already told you %d times Hello world!\n", counter++);        msg_Ptr = msg;        try_module_get(THIS_MODULE);        return SUCCESS;}/*  * Called when a process closes the device file. */static int device_release(struct inode *inode, struct file *file){        Device_Open--;          /* We're now ready for our next caller */        /*          * Decrement the usage count, or else once you opened the file, you'll         * never get get rid of the module.          */        module_put(THIS_MODULE);        return 0;}/*  * Called when a process, which already opened the dev file, attempts to * read from it. */static ssize_t device_read(struct file *filp,   /* see include/linux/fs.h   */                           char *buffer,        /* buffer to fill with data */                           size_t length,       /* length of the buffer     */                           loff_t * offset){        /*         * Number of bytes actually written to the buffer          */        int bytes_read = 0;        /*         * If we're at the end of the message,          * return 0 signifying end of file          */        if (*msg_Ptr == 0)                return 0;        /*          * Actually put the data into the buffer          */        while (length && *msg_Ptr) {                /*                  * The buffer is in the user data segment, not the kernel                  * segment so "*" assignment won't work.  We have to use                  * put_user which copies data from the kernel data segment to                 * the user data segment.                  */                put_user(*(msg_Ptr++), buffer++);                length--;                bytes_read++;        }        /*          * Most read functions return the number of bytes put into the buffer         */        return bytes_read;}/*   * Called when a process writes to dev file: echo "hi" > /dev/hello  */static ssize_tdevice_write(struct file *filp, const char *buff, size_t len, loff_t * off){        printk(KERN_ALERT "Sorry, this operation isn't supported.\n");        return -EINVAL;}

然后撰写Makefile:

# Comment/uncomment the following line to disable/enable debugging#DEBUG = y# Add your debugging flag (or not) to CFLAGSifeq ($(DEBUG),y)  DEBFLAGS = -O -g # "-O" is needed to expand inlineselse  DEBFLAGS = -O2endifEXTRA_CFLAGS += $(DEBFLAGS) #-I$(LDDINCDIR)ifneq ($(KERNELRELEASE),)# call from kernel build systemobj-m   := chardev.oelseKERNELDIR ?= /lib/modules/$(shell uname -r)/buildPWD       := $(shell pwd)default:        $(MAKE) -C $(KERNELDIR) M=$(PWD) modules #LDDINCDIR=$(PWD)/../include modulesendifclean:        rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versionsdepend .depend dep:        $(CC) $(CFLAGS) -M *.c > .dependifeq (.depend,$(wildcard .depend))include .dependendif

接下来是生成目标文件:



然后是安装驱动,并查看内核的日志输出:



看到驱动已经成功加载了,此时查看设备列表:



可以看到最后一行,设备已经加载了。此时使用mknod在dev中安装这个chardev设备:



此时已经可以使用这个设备了:



测试完成后,删除设备并卸载驱动:

您需要登录后才可以回帖 登录 | 立即注册 新浪微博账号登陆

本版积分规则

快速回复 返回顶部 返回列表