linux设备驱动程序的编写 -电脑资料

电脑资料 时间:2019-01-01 我要投稿
【www.unjs.com - 电脑资料】

   

    先介绍下我的环境,用的ubuntu发行版,kernel版本是3.8.0,《Linux设备驱动程序》一书是针对2.6.0的kernel,在这个例子中会看到一些差异,

linux设备驱动程序的编写

。这个例子要实现的目标是,编译装载该module后,通过udev动态的生成设备节点star0,读取设备节点cat /dev/star0可以打印出星号,星号的数量可以由模块参数动态的指定。以下为源代码:

    star.h

    #ifndef STAR_H_H_H

    #define STAR_H_H_H

    #define AUTHOR "Tao Yang"

    #define DESCRIPTION "A CHAR DEVICE DIRVERS SAMPLE USING UDEV"

    #define VERSION "0.1"

    #endif

    star.c

    //module_init module_exit

    #include

    #include

    //module_param

    #include

    //printk container_of

    #include

    //dev_t MAJOR MINOR MKDEV

    #include

    //file_operations file register/unregister_chrdev_region alloc_chrdev_region register/unregister_chrdev(old)

    #include

    //cdev cdev_init/add/del

    #include

    //copy_from_user copy_to_user

    #include

    #include

    #include "star.h"

    //define device number

    #define STAR_MAJOR 0

    #define STAR_MINOR 0

    #define STAR_DEVS 1

    #define DEVICE_NAME "star0"

    #define CLASS_NAME "star"

    static int howmany=5;

    module_param(howmany,int,S_IRUGO);

    //module info

    MODULE_AUTHOR(AUTHOR);

    MODULE_DESCRIPTION(DESCRIPTION);

    MODULE_VERSION(VERSION);

    MODULE_LICENSE("GPL");

    //device variables

    static struct class* star_class=NULL;

    static struct device* star_sysdevice=NULL;

    int star_major=STAR_MAJOR;

    int star_minor=STAR_MINOR;

    int star_nr_devs=STAR_DEVS;

    //device struct

    static struct star_dev {

    char *data;

    struct cdev cdev;

    };

    static struct star_dev star_device;

    static ssize_t star_read(struct file * filp,char * buf,size_t count,loff_t *ppos)

    {

    int i;

    char star_str[10000];

    struct star_dev *dev=filp->private_data;

    for (i=0;i

    star_str[i]='*';

    }

    star_str[howmany]='\n';

    int len=strlen(star_str);

    if(count

    return -EINVAL;

    if(*ppos!=0)

    return 0;

    if(copy_to_user(buf,star_str,len))

    return -EINVAL;

    *ppos=len;

    return len;

    }

    int star_open(struct inode *inode,struct file *filp)

    {

    struct star_dev *dev;

    dev=container_of(inode->i_cdev,struct star_dev,cdev);

    filp->private_data=dev;

    //......

    return 0;

    }

    //file operations

    static const struct file_operations star_fops = {

    .owner = THIS_MODULE,

    .read = star_read,

    .open = star_open,

    };

    static void star_setup_cdev(struct star_dev *dev,int index)

    {

    int err,devno=MKDEV(star_major,star_minor+index);

    printk(KERN_ALERT "setup cdev...\n");

    cdev_init(&dev->cdev,&star_fops);

    dev->cdev.owner=THIS_MODULE;

    dev->cdev.ops=&star_fops;

    err=cdev_add(&dev->cdev,devno,1);

    if(err)

    printk(KERN_ALERT "Error %d adding star%d",err,index);

    }

    static int __init star_init(void)

    {

    int ret;

    dev_t dev;

    printk(KERN_ALERT "hello tom!\n");

    if(star_major){

    dev=MKDEV(star_major,star_minor);

    ret=register_chrdev_region(dev,star_nr_devs,DEVICE_NAME);

    printk(KERN_ALERT "static!\n");

    }else{

    ret=alloc_chrdev_region(&dev,star_minor,star_nr_devs,DEVICE_NAME);

    star_major=MAJOR(dev);

    printk(KERN_ALERT "dynamic!\n");

    printk(KERN_ALERT "Device Major is %d!\n",star_major);

    }

    if(ret<0){

    printk(KERN_ALERT "star:can't get major %d\n",star_major);

    return ret;

    }

    printk(KERN_ALERT "set up cdev!");

    star_setup_cdev(&star_device,0);

    star_class=class_create(THIS_MODULE,CLASS_NAME);

    if(IS_ERR(star_class)){

    printk(KERN_ALERT "failed to register device class '%s'\n",CLASS_NAME);

    }

    //with a class ,the easiest way to instantiate a device is to call device_create()

    star_sysdevice=device_create(star_class,NULL,MKDEV(star_major,0),NULL,DEVICE_NAME);

    return 0;

    }

    static void __exit star_exit(void)

    {

    device_destroy(star_class,MKDEV(star_major,star_minor));

    class_unregister(star_class);

    class_destroy(star_class);

    cdev_del(&star_device.cdev);

    printk(KERN_ALERT "goodbye...\n");

    }

    module_init(star_init);

    module_exit(star_exit);

    Makefile

    ifneq ($(KERNELRELEASE),)

    obj-m:=star.o

    else

    KERNELDIR ?= /lib/modules/$(shell uname -r)/build

    PWD :=$(shell pwd)

    default:

    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

    endif

    编译源代码:

    root@ubuntu:~/embedded_linux/ldd3/practice# make

    make -C /lib/modules/3.8.0-29-generic/build M=/home/tom/embedded_linux/ldd3/practice modules

    make[1]: Entering directory `/usr/src/linux-headers-3.8.0-29-generic'

    CC [M] /home/tom/embedded_linux/ldd3/practice/star.o

    /home/tom/embedded_linux/ldd3/practice/star.c:58:1: warning: useless storage class specifier in empty declaration [enabled by default]

    /home/tom/embedded_linux/ldd3/practice/star.c: In function ‘star_read’:

    /home/tom/embedded_linux/ldd3/practice/star.c:72:5: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]

    /home/tom/embedded_linux/ldd3/practice/star.c:66:22: warning: unused variable ‘dev’ [-Wunused-variable]

    /home/tom/embedded_linux/ldd3/practice/star.c:81:1: warning: the frame. size of 10032 bytes is larger than 1024 bytes [-Wframe-larger-than=]

    Building modules, stage 2.

    MODPOST 1 modules

    CC /home/tom/embedded_linux/ldd3/practice/star.mod.o

    LD [M] /home/tom/embedded_linux/ldd3/practice/star.ko

    make[1]: Leaving directory `/usr/src/linux-headers-3.8.0-29-generic'

    root@ubuntu:~/embedded_linux/ldd3/practice#

    安装驱动模块:

    root@ubuntu:~/embedded_linux/ldd3/practice# insmod star.ko

    root@ubuntu:~/embedded_linux/ldd3/practice# dmesg -c

    [ 3946.696548] hello tom!

    [ 3946.699892] dynamic!

    [ 3946.699894] Device Major is 249!

    [ 3946.699895] set up cdev!

最新文章