编写驱动文件和test.c,实现使用test.c访问驱动并控制数码管显示的数据
设备树节点的编写
&spi4{
pinctrl-names = "default", "sleep";
pinctrl-0 = <&spi4_pins_b>;
pinctrl-1 = <&spi4_sleep_pins_b>;
cs-gpios = <&gpioe 11 0>;//代表片选线
status = "okay";
m74hc595@0 {//0表示是SPI总线上的第0个设备
compatible = "hqyj,m74hc595";
reg = <0>;
spi-max-frequency = <10000000>;//SPI总线速率
//59MHZ
};
};
驱动文件
#include <linux/init.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/ioctl.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#define CNAME "myspi"
unsigned int major;
struct class *cls;//句柄
struct device *dev;
struct spi_device *myspi=NULL;
long ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
char buf[2]={};
buf[0]=cmd;
if(cmd == 0x5)
buf[0]=0x2;
buf[1]=arg;
spi_write(myspi,buf,sizeof(buf));
return 0;
}
//操作方法结构体的初始化
struct file_operations fops=
{
.unlocked_ioctl=ioctl,
};
int m74hc595_probe(struct spi_device *spi)
{
myspi=spi;
//动态注册字符设备驱动
major=register_chrdev(0,CNAME,&fops);
if(major<0)
{
printk("字符设备驱动注册失败\n");
return major;
}
printk("字符设备驱动注册成功major=%d\n",major);
//向上提交节点目录
cls=class_create(THIS_MODULE,"LED");
if(IS_ERR(cls))
{
printk("向上提交目录失败\n");
return PTR_ERR(cls);
}
printk("向上提交目录成功\n");
//创建设备节点文件
dev=device_create(cls,NULL,MKDEV(major,0),NULL,"myspi");
if(IS_ERR(dev))
{
printk("创建节点失败\n");
return PTR_ERR(dev);
}
printk("创建节点成功\n");
//初始化队列头
//init_waitqueue_head(&wq_head);
printk("%s:%d\n",__FILE__,__LINE__);
return 0;
}
int m74hc595_remove(struct spi_device *spi)
{
//销毁节点
device_destroy(cls,MKDEV(major,0));
//销毁目录
class_destroy(cls);
//注销字符设备驱动
unregister_chrdev(major,CNAME);
printk("%s:%d\n",__FILE__,__LINE__);
return 0;
}
//设备树匹配表
struct of_device_id of_table[]={
{.compatible="hqyj,m74hc595"},
{},
};
MODULE_DEVICE_TABLE(of,of_table);
//定义SPI对象并初始化
struct spi_driver m74hc595={
.probe=m74hc595_probe,
.remove=m74hc595_remove,
.driver={
.name="m74hc595",
.of_match_table=of_table,
},
};
module_spi_driver(m74hc595);
MODULE_LICENSE("GPL");
test.c——测试文件
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <unistd.h>
/*管脚顺序由h到a
*0011 1111 0x3F 0
*0000 0110 0x06 1
*0101 1011 0x5B 2
*0100 1111 0x4F 3
*0110 0110 0x66 4
*0110 1101 0x6D 5
*0111 1101 0x7D 6
*0000 0111 0x07 7
*0111 1111 0x7F 8
*0110 1111 0x6F 9
* */
int main(int argc,char const *argv[])
{
long led[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
int which[]={0x1,0x5,0x4,0x8};
int fd,number,val;
fd=open("/dev/myspi",O_RDWR);
if(fd<0)
{
printf("打开文件失败\n");
exit(-1);
}
printf("打开文件成功\n");
while(1)
{
printf("请输入想要改变的数码管(1~4) 5:关闭所有的数码管并退出程序\n");
scanf("%d",&val);
if(val==5)
{
for(int i=0; i<4; i++)
{
ioctl(fd,which[i],0);
}
printf("程序即将退出\n");
break;
}else if(val<=4 && val>=1 )
{
printf("请输入第%d个数码管的数字(0~9)\n",val);
scanf("%d",&number);
ioctl(fd,which[val-1],led[number]);
}else
{
printf("输入有误,请重新输入\n");
}
}
close(fd);
return 0;
}
实验现象