函数原型:
int ioctl(int fd, unsigned long cmd, ...);
功能:
1.利用此函数可以向硬件设备发送控制命令(有种write感觉)
2.利用此函数还可以跟硬件进行数据的交互(又有读又有写的感觉)
参数:
fd:设备文件描述符
cmd:给硬件设备发送的控制命令
命令由驱动工程师自行定义,命令的值尽量大点,建议10以内的数字不要用
例如:
#define LED_ON (0x100001) //开灯命令
#define LED_OFF (0x100002) //关灯命令
...:如果应用程序要和硬件进行读或者写操作,第三个参数只需传递用户缓冲区的首地址即可
类似read/write的第二个参数void *buf
将来驱动程序利用copy_from_user/copy_to_user可以对用户缓冲区进行读或者写数据操作
返回值:成功返回0,失败返回-1
参考代码:
//1.传递2个参数
ioctl(fd, LED_ON); //仅仅发送开灯命令
//2.传递3个参数
int index = 2;
ioctl(fd, LED_ON, &index); //不仅仅发送开灯命令,还要把灯的编号传递给驱动程序
//第三个参数就是用户缓冲区index的首地址,将来驱动拿到这个地址
可以访问index
struct file_operations {
long (*unlocked_ioctl)(strut file *file, unsigned int cmd, unsigned long buf);
};
接口功能:
1.根据用户发送来的命令操作硬件
2.如果应用ioctl传递三个参数,表示应用想利用ioctl实现和硬件的数据交互
参数:
file:文件指针,跟应用ioctl的第一个参数fd是亲戚关系
cmd:其值就是应用ioctl发送来的命令例如:cmd=LED_ON/LED_OFF
将来底层驱动解析cmd命令,各种判断呗
buf:如果应用ioctl传递三个参数,那么此buf保存的就是应用程序ioctl的第三个参数&index
(指针的三大用法:通过有类型指针访问,通过无类型指针访问,通过unsigned long类型访问)
底层驱动将来对buf进行访问时,记得数据类型要转换,同样利用copy_to_user
和copy_from_user进行内存的拷贝,不能直接访问,太危险
例如:
int kindex;
kindex = *(int *)buf; //理论上可以,但是很危险
copy_from_user(&kindex, (int *)buf, 4);//拷贝用户数据到内核
copy_to_user((int *)buf, &kindex, 4); //拷贝内核数据到用户
上位机执行:
mkdir /opt/drivers/day03/5.0 -p
cd /opt/drivers/day03/5.0
vim led_test.c
unsigned long类型的buf需要强转为int类型指针
(指针的三大用法:通过有类型指针访问,通过无类型指针访问,通过unsigned long类型访问)
vim Makefile
make
arm-cortex_a9-linux-gnueabi-gcc -o led_test led_test.c
cp led_test led_drv.ko /opt/rootfs/home/drivers/
下位机测试
cd /home/drivers
insmod led_drv.ko
cat /proc/device 查看申请的主设备号
mknod /dev/myled c 244 0
./led_test on 1 //观察打印的灯的状态
./led_test off 1
./led_test on 2
./led_test off 2
insmod安装驱动时设备文件自动创建好
rmmod卸载驱动时设备文件自动删除
驱动程序只需调用以下四个函数最终完成设备文件的自动创建和自动删除
struct class *cls; //定义设备类指针(类似长树枝嫩芽)
//创建设备类对象(类似长树枝,此树枝叫tarena1)
//THIS_MODULE:内核常量
//"tarena1":树枝名,对象名
//结果是:将来在/sys/class/tarena1目录(生成)
cls = class_create(THIS_MODULE, "tarena1");
//在tarena1设备类下自动创建设备文件/dev/myled,设备号是dev
//类似长苹果
//此函数内部会帮你解析/proc/sys/kernel/hotplug文件,找到/sbin/mdev
//然后把设备号dev和设备文件名myled给/sbin/mdev,mdev自动帮你创建
//创建设备文件的原材料:设备号dev和设备文件名myled将来会放在/sys/class/tarena1目录下
device_create(cls, NULL, dev, NULL, "myled");
//自动删除设备文件,类似摘苹果
device_destroy(cls, dev);
//自动删除设备类对象,类似砍树枝
class_destroy(cls);
案例:给day03/5.0驱动代码添加设备文件自动创建功能
参考代码:day03/6.0
上位机执行:
cp /opt/drivers/day03/5.0 /opt/drivers/day03/6.0 -fr
cd /opt/drivers/day03/6.0
vim led_drv.c
make
cp led_drv.ko /opt/rootfs/home/drivers
下位机测试:
重启下位机,然后执行:
echo 8 > /proc/sys/kernel/printk
cd /home/drivers
ls /dev/myled //刚开始确实没有设备文件
insmod led_drv.ko //此时设备文件自动创建好
ls /dev/myled -l
./led_test on 1
./led_test off 1
...
rmmod led_drv //此时自动删除设备文件
ls -l /dev/myled