曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 5486|回复: 1
打印 上一主题 下一主题

次设备号文件处理实例

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
跳转到指定楼层
楼主
发表于 2009-9-25 02:39:17 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
驱动程序代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/fcntl.h>

#include <asm/uaccess.h>
#include <asm/io.h>

#define MINOR_DEV_NAME    "minordev"
#define MINOR_DEV_MAJOR    240
#define MINOR_WRITE_ADDR 0x378
#define MINOR_READ_ADDR  0x379

int minor0_open (struct inode *inode, struct file *filp)
{
    printk ("call minor0_open\n");
    return 0;
}

ssize_t minor0_write (struct file *filp, const char *buf, size_t count, loff_t *f_pos)
{
    unsigned char status;
    int    loop;

    for (loop = 0; loop < count; loop++) {
        get_user (status, (char *)&buf[loop]);
        outb (status, MINOR_WRITE_ADDR);
    }
   
    return count;
}

int minor0_release (struct inode *inode, struct file *filp)
{
    printk ("call minor0_release\n");
    return 0;
}

int minor1_open (struct inode *inode, struct file *filp)
{
    printk ("call minor1_open\n");
    return 0;
}

ssize_t minor1_read (struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
    unsigned char status;
    int    loop;

    for (loop = 0; loop < count; loop++) {
        status = inb (MINOR_READ_ADDR);
        put_user (status, (char *)&buf[loop]);
    }

    return count;
}

int minor1_release (struct inode *inode, struct file *filp)
{
    printk ("call minor1_release\n");
    return 0;
}

struct file_operations minor0_fops = {
    .owner = THIS_MODULE,
    .write = minor0_write,
    .open = minor0_open,
    .release = minor0_release,
};

struct file_operations minor1_fops = {
    .owner = THIS_MODULE,
    .read = minor1_read,
    .open = minor1_open,
    .release = minor1_release,
};

int minor_open (struct inode *inode, struct file *filp)
{
    printk ("call minor_open\n");
   
    switch (MINOR (inode->i_rdev)) {
        case 1:
           filp->f_op = &minor0_fops;
           break;
       
        case 2:
           filp->f_op = &minor1_fops;
           break;
       
        default :
            return -ENXIO;
    }
    if (filp->f_op && filp->f_op->open)
        return filp->f_op->open (inode, filp);

    return 0;
}

struct file_operations minor_fops = {
        .owner = THIS_MODULE,
        .open = minor_open,
};

int minor_init (void)
{
    int result;
   
    result = register_chrdev (MINOR_DEV_MAJOR, MINOR_DEV_NAME, &minor_fops);
   
    if (result < 0)
        return result;

    return 0;
}

void minor_exit (void)
{
    unregister_chrdev (MINOR_DEV_MAJOR, MINOR_DEV_NAME);
}

module_init (minor_init);
module_exit (minor_exit);

MODULE_LICENSE ("Dual BSD/GPL");

Makefile 文件
obj-m := minor_dev.o

KDIR := /lib/modules/$(shell uname -r)/build

PWD := $(shell pwd)

default:
    $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules

clean:
    rm -rf *.ko
    rm -rf *.mod.*
    rm -rf .*.cmd
    rm -rf *.o

测试应用程序
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>

#define READ_DEVICE_FILENAME "/dev/minor_read"
#define WRITE_DEVICE_FILENAME "/dev/minor_write"

int main()
{
    int read_dev;
    int write_dev;

    char buff [128];
    int loop;

    read_dev = open (READ_DEVICE_FILENAME, O_RDWR | O_NDELAY);
    if (read_dev < 0) {
        printf (READ_DEVICE_FILENAME "open error\n");
        close (read_dev);
        exit (1);
    }

    write_dev = open (WRITE_DEVICE_FILENAME, O_RDWR | O_NDELAY);
    if (write_dev < 0) {
        printf (WRITE_DEVICE_FILENAME "open error\n");
        close (write_dev);
        exit (1);
    }

    printf ("wait... input\n");
   
    while (1) {
        if (read (read_dev, buff, 1) == 1) {
            printf ("read data [%02X]\n", buff[0] & 0xFF);
            if (!(buff[0] & 0x10)) break;
        }
    }

    printf ("input ok ... \n");

    printf ("led flashing ... \n");
   
    for (loop = 0; loop < 5; loop++) {
        buff[0] = 0xFF;
        write (write_dev, buff, 1);
        sleep (1);
        buff[0] = 0x00;
        write (write_dev, buff, 1);
        sleep (1);
    }
   
    close (read_dev);
    close (write_dev);

    return 0;
}

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
沙发
 楼主| 发表于 2009-9-25 03:02:57 | 只看该作者

说明

上面的驱动程序,需要创建两个设备文件
mknod /dev/minor_write c 240 1
mknod /dev/minor_read c 240 2

make 后加载内核模块
insmod minor_dev.ko

确认已经注册模块使用 lsmod 命令
beyes@linux-beyes:~/Drivers/my/major_and_minor> lsmod
Module                  Size  Used by
minor_dev               2504  0
... ...

或通过查看 /proc/kallsyms 虚拟文件确认注册模块
beyes@linux-beyes:~/Drivers/my/major_and_minor> cat /proc/kallsyms | grep minor_dev
00000000 a minor_dev.c    [minor_dev]
fb0ac1fc ? __mod_license129    [minor_dev]
00000000 a minor_dev.mod.c    [minor_dev]
fb0ac214 ? __mod_srcversion34    [minor_dev]
fb0ac238 ? __module_depends    [minor_dev]
fb0ac280 ? ____versions    [minor_dev]
fb0ac244 ? __mod_vermagic5    [minor_dev]
fa2fd890 d __this_module    [minor_dev]
c0194915 u unregister_chrdev    [minor_dev]
fa2fd061 t cleanup_module    [minor_dev]
fa2fd81c d minor_fops    [minor_dev]
fa2fd126 t minor0_open    [minor_dev]
fa2fd070 t init_module    [minor_dev]
c0194a75 u register_chrdev    [minor_dev]
fa2fd092 t minor_open    [minor_dev]
c0230680 u __put_user_1    [minor_dev]
fa2fd100 t minor1_open    [minor_dev]
c03491ae u printk    [minor_dev]
fa2fd113 t minor0_release    [minor_dev]
fa2fd7a8 d minor1_fops    [minor_dev]
fa2fd070 t minor_init    [minor_dev]
fa2fd734 d minor0_fops    [minor_dev]
c02305c0 u __get_user_1    [minor_dev]
fa2fd029 t minor1_read    [minor_dev]
fa2fd000 t minor0_write    [minor_dev]
fa2fd061 t minor_exit    [minor_dev]
fa2fd0ed t minor1_release    [minor_dev]

/proc/ksyms 文件是在 ( 2.4 内核中为 /proc/ksyms ) /proc 目录下的虚拟文件之一,包含当前内核中包含的symbol ,即全局变量和函数名称。通过 grep 命令可以虑出注册的模块名称,如果没有显式任何执行结果,那么表名模块未能正确注册。


在打印口的 13 脚和 25 脚分别引出两条引线;LED 灯接到 2 脚 和 18 脚上 (2 脚接 LED 的长脚 <+>, 18 脚接 LED 的短脚 <->) 。当运行应用测试程序时,如果两条引线互相碰触然后 LED 就会每隔 1 秒闪烁一次。

当驱动程序运行时,最先调用的是 minor_init() 函数 。minor_init() 函数注册 MINOR_DEV_MAJOR (240)为主设备号的 file_operations 类型结构体 minor_fops 。在 minor_fops 结构体中,仅定义了 minor_open() 函数,这是应用程序打开设备文件后最先运行的形态。那么当 minor_open() 函数执行时,它通过 MINOR( inode->i_rdev) 函数获取了次设备号信息,然后就可以执行相应于这个次设备号的 open() 函数。比如获得的次设备号为 1 ,那么执行的 open 函数为 minor0_open() .

关于次设备号的处理:http://www.groad.net/bbs/read.php?tid=1014#2153
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2025-5-3 13:06 , Processed in 0.064079 second(s), 21 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

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