驱动如何操作寄存器
rgb_led灯的寄存器是物理地址,在linux内核启动之后,
在使用地址的时候,操作的全是虚拟地址。需要将物理地址
转化为虚拟地址。在驱动代码中操作的虚拟地址就相当于
操作实际的物理地址。
物理地址<------>虚拟地址
void * ioremap(phys_addr_t offset, unsigned long size)
功能:将物理地址映射成虚拟地址
参数:
@offset :要映射的物理地址
@size :大小(字节)
返回值:成功返回虚拟地址,失败返回NULL;
void iounmap(void *addr)
功能:取消映射
参数:
@addr :虚拟地址
返回值:无
RGB_led
red :gpioa28
GPIOXOUT :控制高低电平的 0xC001A000
GPIOxOUTENB:输入输出模式 0xC001A004
GPIOxALTFN1:function寄存器 0xC001A024
green:gpioe13
0xC001e000
blue :gpiob12
0xC001b000
指针类型加1是加的他的类型大小
驱动控制灯
- #include
- #include
- #include
- #include
- #include
- #include
- int major=0;
- #define CNAME "hello"
- char kbuf[128]={0};
- int dev=0;
- #define RED_BASE 0XC001A000
- #define BLUE_BASE 0XC001B000
- #define GREEN_BASE 0XC001E000
- unsigned int *red_base=NULL;
- unsigned int *blue_base=NULL;
- unsigned int *green_base=NULL;
-
-
-
- ssize_t mycdev_read (struct file *file, char __user *user, size_t size, loff_t * loff)
- {
- //printk("this is read");
- if(size>128){
- size=128;
- }
- dev=copy_to_user(user,kbuf,size);
- if(dev)
- {
- printk("copy to user errer");
- return dev;
- }
- return 0;
- }
- ssize_t mycdev_write (struct file *file, const char __user *user, size_t size, loff_t *loff)
- {
- //printk("this is write");
- if(size>128){
- size=128;
- }
- dev=copy_from_user(kbuf,user,size);
- return 0;
- }
- int mycdev_open (struct inode *inode, struct file *file)
- {
- printk("this is open");
- return 0;
- }
- int mycdev_release (struct inode *inode, struct file *file)
- {
- printk("this is close");
- return 0;
- }
-
- const struct file_operations fops={
- .open=mycdev_open,
- .read=mycdev_read,
- .write=mycdev_write,
- .release=mycdev_release,
- };
-
- static int __init hello_init(void)//入口
- {
- major=register_chrdev(major,CNAME,&fops);
- if(major<0)
- {
- printk("register chrdev error");
- }
- red_base=ioremap(RED_BASE,36);
- if(red_base==NULL)
- {
- printk("red ioremap error\n");
- return -ENOMEM;
- }
- blue_base=ioremap(BLUE_BASE,36);
- if(blue_base==NULL)
- {
- printk("blue ioremap error\n");
- return -ENOMEM;
- }
- green_base=ioremap(GREEN_BASE,36);
- if(green_base==NULL)
- {
- printk("green ioremap error\n");
- return -ENOMEM;
- }
-
- *red_base &=~(1<<28);
- *(red_base+1) |=1<<28;
- *(red_base+9) |=3<<24;
-
-
- return 0;
- }
- static void __exit hello_exit(void)//出口
- {
- iounmap(green_base);
- iounmap(blue_base);
- iounmap(red_base);
- unregister_chrdev(major,CNAME);
- }
- module_init(hello_init);//告诉内核驱动的入口
- module_exit(hello_exit);//告诉内核驱动的出口
- MODULE_LICENSE("GPL");
驱动层(只有部分程序)
- #define RED_ON *red_base |= 1<<28
- #define RED_OF *red_base &= ~(1<<28)
- ssize_t mycdev_write (struct file *file, const char __user *user, size_t size, loff_t *loff)
- {
- //printk("this is write");
- if(size>128){
- size=128;
- }
- dev=copy_from_user(kbuf,user,size);
- if(kbuf[0]==1)
- {
- RED_ON;
- }
- else{
- RED_OF;
- }
- return 0;
- }
1.写宏定义灯的基地址

2.虚拟地址声明

3.去注册驱动下做地址映射

物理地址 长度一个占四个 四九三十六


其他灯同理去映射虚拟地址
偏移地址
int四字节 +1等于+4

#include
取消地址


vi MAKEFILE
打开开发板,关闭内核的
再make
放到nfs里


进行应用:
内核层:



应用层

make一下
vi test.c






vi MAKEFILE





打开nfs





#include
自动创建设备节点:
struct class *cls;
cls = class_create(owner, name) /void class_destroy(struct class *cls)
功能:向用户空间提交目录信息
参数:
@owner :THIS_MODULE
@name :目录名字
返回值:成功返回struct class *指针
失败返回错误码指针 int (-5)
if(IS_ERR(cls)){
}
struct device *device_create(struct class *class, struct device *parent,
dev_t devt, void *drvdata, const char *fmt, ...)
/void device_destroy(struct class *class, dev_t devt)
功能:向用户空间提交文件信息
参数:
@class :目录名字(向用户空间提交目录信息时产生的返回值)
@parent:NULL
@devt :设备号 MKDEV(major,0)
@drvdata :NULL
@fmt :文件的名字
返回值:成功返回struct device *指针
失败返回错误码指针 int (-5)
- struct class*cls;
- struct device *dev;
- //自动创建设备节点
- cls = class_create(THIS_MODULE,CNAME);
- if(IS_ERR(cls)){
- printk("class create error\n");
- return PTR_ERR(cls);
- }
- dev = device_create(cls,NULL,MKDEV(major,0),NULL
- ,CNAME);
- if(IS_ERR(dev)){
- printk("device create error\n");
- return PTR_ERR(dev);
- }
- //出口-》这里写了卸载时注销的函数
- static void __exit hello_exit(void)//出口
- {
- device_destroy(devc,MKDEV(major,1));//注销内容
- class_destroy(cls);//注销目录
- iounmap(green_base);
- iounmap(blue_base);
- iounmap(red_base);
- unregister_chrdev(major,CNAME);
- }
注意:MKDEV(major,0)为一个宏用于配置主设备号和次设备号
写在入口
声明:

在入口处

改为







make

自动创建设备节点建立在dev里
用户:
#include
int ioctl(int fd, int request, ...);
(让点灯的代码变得简洁)
参数:
@fd : 打开文件产生的文件描述符
@request: 请求码(读写|第三个参数传递的字节的个数),
:在sys/ioctl.h中有这个请求码的定义方式。
@... :可写、可不写,如果要写,写一个内存的地址
内核:
long (*unlocked_ioctl) (struct file *, unsigned int,unsigned long)
作用:此函数指针原型位于struct file_operations结构体当中,配合应用层ioctl函数实现指令传递的功能


vi test.c









