【驱动学习】ioctl 函数

static int globalmem_ioctl(struct inode* inodep, struct file* filep,
                            unsigned int cmd, unsigned long arg)
{
    switch (cmd)
    {
        case MEM_CLEAR:
            /* 清除全局内存 */
            memset(dev->mem, 0, GLOBALMEM_SIZE);
            printk(KERN_INFO "globalmem is set to zero\n");
            break;
        default:
            return -EINVAL;//其他不支持的命令
            break;
    }
    return 0;

}

如果设备 A、 B 都支持 0x0、 0x1、 0x2 这样的命令,假设用户本身希望给 A 发 0x1 命令,可是不经意间发给了 B,这个时候 B 因为支持该命令,它就会执行该命令。因此, Linux 内核推荐采用一套统一的 ioctl()命令生成方式。

2. ioctl()命令

Linux 系统建议以如图 6.2 所示的方式定义 ioctl()的命令码。

设备类型 序列号 方向 数据尺寸
8bit 8bit 2bit 13/14bit

图 6.2 ioctl()命令码的组成

命令码的设备类型字段为一个“幻数”,可以是 0~0xff 之间的值,内核中的 ioctl-number.txt 给出了一些推荐的和已经被使用的“幻数”,新设备驱动定义“幻数”的时候要避免与其冲突。
命令码的序列号也是 8 位宽。命令码的方向字段为 2 位,该字段表示数据传送的方向,可能的值是_IOC_NONE(无数据传输)、_IOC_READ(读)、_IOC_WRITE(写)和_IOC_READ|_IOC_WRITE(双向)。数据传送的方向是从应用程序的角度来看的。
命令码的数据长度字段表示涉及的用户数据的大小,这个成员的宽度依赖于体系结构,通常是 13 位或者 14 位。
内核还定义了_IO()、 _IOR()、 _IOW()和_IOWR()这 4 个宏来辅助生成命令,这 4 个宏的通用定义如代
码清单 6.16 所示。

#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)
#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr), (_IOC_TYPECHECK(size)))
/*_IO、 _IOR 等使用的_IOC 宏*/
#define _IOC(dir,type,nr,size) \
    (((dir) << _IOC_DIRSHIFT) | \
    ((type) << _IOC_TYPESHIFT) | \
    ((nr) << _IOC_NRSHIFT) | \
    ((size) << _IOC_SIZESHIFT))

由此可见,这几个宏的作用是根据传入的 type(设备类型字段)、 nr(序列号字段)和 size(数据长度字段)和宏名隐含的方向字段移位组合生成命令码。
由于 globalmem 的 MEM_CLEAR 命令不涉及数据传输,因此它可以定义如下:

#define GLOBALMEM_MAGIC …
#define MEM_CLEAR _IO(GLOBALMEM_MAGIC,0)

猜你喜欢

转载自blog.csdn.net/u012335044/article/details/79989720
今日推荐