简单的字符设备驱动模型

字符设备是指在I/O传输过程中以字符为单位进行传输的设备,这种设备没有缓存,例如键盘,打印机等。

#include< linux/module.h>
#include< linux/sche.h>
#include< linux/kernel.h>
#include< linux/init.h>

static loff_t test_llseek(struct file *filp, loff_t off, int whence);
/*
 *linux 使用 llseek来改变驱动程序的llseek() 的值来修改设备(文件)的读写位置
 *实质上是改变filp->f_pos的值
 *它有三个参数
 * 第一个是file指针,file结构是设备驱动程序最重要的一个数据结构(注意file!= FILE)
 * file代表一个“打开的文件”,它由内核在open()时创建且在close()前作为参数传递给操作
 *  在设备上的函数,以下是具体构成
    struct file{
        struct list_head f_list;
        struct dentry * f_dentry;
        struct vfsmount * f_vfsmnt;
        struct file_operations * f_op;
        atomic_t f_count;
        unsigned int f_flags;
        mode_t f_mode;
        loff_t f_pos;
        unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;
        int f_error;

        unsigned long f_version;

        void * private_data;

        struct kiobuf * f_iobuf;
        long f_iobuf_lock;
    };
    其中有几个常用成员:
    1.f_mode
        文件模式由 FMODE_READ && FMODE_WRITE 标识,驱动程序的ioctl()方法可能查看这个域,
        read()和write()在调用前已经检查,所以无需检查权限。
    2.f_ops
        当前读写位置,loff_t 是long long (64位整数)。如果定义了llseek()方法,就应该更新
        f_pos
    3.f_inode
        打开文件对应的i节点(节点是内核中的一个概念,至于到底是啥我也不知道),inode指针
        是内核传递给所有文件操作的第一个参数,所以驱动程序一般不需要访问file这个字段。
    4.f_op
        与文件对应的操作,内核在open()对这个指针赋值,以后需要分派操作时就读这些数据。
 * 第二个参数loff_t 为要移动的偏移量
 * 第三个参数wence 为偏移方式,0为从文件头移动, 1为从文件当前位置移动, 2为从文件尾移动
 */
static ssize_t test_read(struct file *filp, char *buf, size_t count, loff_t f_pos);
/*
 *如果数据全部传输完成,则返回值为count
 *如果数据部分传输完成, 则返回值为小于count的数,这种情况下一般会重新读数据
 *如果已经到文件尾, 则返回值为0
 *如果发生错误则返回负值
 */
static ssize_t test_write(struct file *filp, char *buf, size_t count, loff_t f_pos);
/*
 *如果数据全部传输完成,则返回值为count
 *如果数据部分传输完成, 则返回值为小于count的数,这种情况下一般会重新写数据
 *如果已经到文件尾, 则返回值为0
 *如果发生错误则返回负值
 */

static int test_open(struct inode *inode, struct file *filp);
/*
 *在linux使用设备前会调用驱动程序的这个方法
 *open()方法最重要的是调用 MOD_INC_USE_COUNT,这个宏用来增加驱动程序使用计数器,避免在不正确
 * 的卸载驱动程序
 *inode作用是打开文件对应的i节点,主要作用是获取设备号
 *filp代表一个打开的文件(设备)
 */
static int test_release(struct inode *inode, struct file *filp);
/*
*/
static int test_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long param);
/*
*/

int test_init(void);
int test_cleanup(void);

#define MAJOR_DEV 125
#define DEVICE_NAME "my_simpledev"

module_init(test_init);
module_init(test_clenup);

static struct file_operations test_fops = 
{
    .owner = THIS_MODULE,
    .llseek = test_llseek,
    .read = test_read,
    .write = test_write,
    .open = test_open,
    .release = test_release,
    .ioctl = test_ioctl,
};

static loff_t test_llseek(struct file * filp, loff_t off, int whence)
{
    printk("llseek called\n");
    return 0;
}

static ssize_t test_read(struct file * filp, char * buf, size_t count, loff_t f_pos)
{
    printk("read called\n");
    return 0;
}

static ssize_t test_write(struct file * filp, char * buf, size_t count, loff_t f_pos)
{
    printk("write called\n");
    return 0;
}

static ssize_t test_open(struct inode *inode, struct file * filp)
{
    printk("open called\n");
    MOD_INC_USE_COUNT;
    return 0;
}

static int test_release(struct inode *inode, struct file * filp)
{
    printk("release called\n");
    MOD_DEC_USE_COUNT;
    return 0;
}

static int test_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long param)
{
    printk("ioctl called\n");
    return 0;
}

int test_init(void)
{
    int result = 0;

    result = register_chrdev(MAJOR_NR, DEVICE_NAME, &test_fops)
    if(result < 0)
    {
        printk(KERN_ERR_DEVICE_NAME ":Unable to get major %d\n", MAJOR_NR);
        return result;
    }
    printk(KERN_ERR_DEVICE_NAME ": init OK \n");
    return 0;
}

void test_cleanup(void)
{
    unregister_chrdev(MAJOR_NR, DEVICE_NAME);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值