相关知识点
udev创建设备节点的原理
linux操作系统中ioctl函数的使用
linux内核有意将设备的功能控制和数据的读写分成不同的函数完成,比如串口驱动,将串口的波特率、数据位宽等信息通过ioctl来实现,串口的数据收发通过read/write来实现
ioctl函数的功能码
上面的方向指的是从内核到用户还是从用户到内核,以用户作为第一人称
如果想要得到上面的表述某种功能的命名码,需要通过一些宏定义实现
#define _IOC(dir,type,nr,size) \
(((dir) << _IOC_DIRSHIFT) | \
((type) << _IOC_TYPESHIFT) | \
((nr) << _IOC_NRSHIFT) | \
((size) << _IOC_SIZESHIFT))
dir<<30|size<<16|type<<8|nr<<0
#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)
#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size))
#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size))
#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))
//如果想要得到一个具有某种特定含义的功能码只需要_IO\_IOW\_IOR\_IOWR就可以得到
ex:以灯的开和关为例
#define LED_ON _IOW('a',1,int)
LED_ON 01 00000000000100 01100001 00000001
#define LED_OFF _IOW('a',0,int)
LED_OFF 01 00000000000100 01100001 00000000
相关API
自动创建设备节点相关API
# include <linux/device.h>
1. 向上提交目录
struct class * class_create ( struct module * owner, const char * name)
功能:向上提交目录
参数:
owner: THIS_MODULE/ 和编译器相关的宏,这个宏是struct module 类型,这个结构体
里面指定了入口和出口
name: 目录名
返回值:成功返回目录结构体指针,失败返回指向错误码的指针(void * )( - error)
关于错误码的解释:
IS_ERR ( ) :根据地址区间的位置判断错误,IS_ERR判断目录所在的地址区间是否在最顶层的4 K空间(预留空间)中,如果在就表示创建错误
static inline long __must_check IS_ERR ( const void * ptr)
{
return IS_ERR_VALUE ( ( unsigned long ) ptr) ;
}
IS_ERR_VALUE ( x) unlikely ( ( x) (
2. 向上提交设备节点
struct device * device_create ( struct class * class, struct device * parent,
dev_t devt, void * drvdata, const char * fmt, . . . )
功能:提交节点信息
参数:
class: class_create创建产生的句柄
parent: NULL
devt: 设备号
MKDEV ( major, minor) ;
MAJOR ( dev)
MINOR ( dev)
drvdata:NULL
fmt:节点名
3. 销毁节点
void device_destroy ( struct class * class, dev_t devt)
功能:销毁设备节点
参数:
class: class_create创建的句柄
devt: 设备号
4. 销毁目录
void class_destroy ( struct class * cls)
功能:销毁目录
参数:目录指针(句柄)
ioctl的相关API
系统调用函数:
# include <sys/ioctl.h>
int ioctl ( int fd, unsigned long request, . . . ) ;
功能:通过功能码实现设备的控制
参数:
fd: 设备文件的文件描述符
request: 功能码
. . . : 可以写参数,也可以不写,写参数的时候写地址
返回值:成功返回0 ,失败返回错误码
An ioctl ( ) request has encoded in it whether the argument is an in parameter or out
parameter, and the size of the argument argp in bytes.
struct file_operations {
long ( * unlocked_ioctl) ( struct file * , unsigned int cmd, unsigned long arg) ;
} ;
代码实现
tim.c文件
# include <linux/init.h>
# include <linux/module.h>
# include <linux/fs.h>
# include <linux/io.h>
# include <linux/ioctl.h>
# include <linux/device.h>
# include <linux/uaccess.h>
# include "myled.h"
# define CNAME "mytim"
int major;
char kbuf[ 128 ] = {
} ;
gpio_t * vir_tim1;
gpio_t * vir_tim4;
unsigned int * vir_rcc;
struct class * cls;
struct device * dev;
int mycdev_open ( struct inode * inode, struct file * file)
{
printk ( "%s:%s:%d\n" , __FILE__ , __func__ , __LINE__ ) ;
return 0 ;
}
ssize_t mycdev_read ( struct file * file, char __user * ubuf, size_t size, loff_t * loff)
{
int ret;
if ( size> sizeof ( kbuf) )
size= sizeof ( kbuf) ;
ret= copy_to_user ( ubuf, kbuf, size) ;
if ( ret)
{
printk ( "数据从内核向用户拷贝失败\n" ) ;
return - EIO;
}
return size;
}
ssize_t mycdev_write ( struct file * file, const char __user * ubuf, size_t size,