您的位置 首页 设计

驱动之路-硬件访问及稠浊设备LED驱动

驱动之路-硬件访问及混杂设备LED驱动-一些CPU制造厂在它们的芯片中使用单一的地址空间,而一些则为外设保留独立的地址空间,以便和内存区间分开来,这段独立与内存地址空间的地址空间就叫I/O端口。在/proc/ioport中可以看到。嵌入式处理器大部分不支持I/O端口。

一、重要知识点

1.I/O端口和I/O内存

寄存器和惯例内存的差异:寄存器和RAM首要不同在于寄存器有边沿作用,读取某个地址时或许导致该地址的内容产生变化,比如说许多设备的中止状况寄存器只需一读取,便主动清0。所以硬件寄存器不能直接拜访,而要经过I/O端口和I/O内存两种方法拜访。

在硬件层,I/O内存区域和I/O端口区域没有概念上的差异:它们都是经过向地址总线和操控总线产生电平信号进行拜访,再经过数据总线读写数据。

a.I/O端口:

一些CPU制作厂在它们的芯片中运用单一的地址空间,而一些则为外设保存独立的地址空间,以便和内存区间分开来,这段独立与内存地址空间的地址空间就叫I/O端口。在/proc/ioport中能够看到。嵌入式处理器大部分不支撑I/O端口。

拜访I/O端口有两步:1.请求I/O端口2.读写I/O端口

请求I/O端口:

structresource *request_region(unsigned long first, unsigned long n, const char *name)

请求从first开端的n个端口。参数name为设备称号。假如分配成功则回来非NULL值。

开释I/O端口:

voidrelease_region(unsigned long start, unsigned long n)

读写I/O端口:

读写一个字节

unsignedinb(unsigned port)

voidoutb(usigned char byte, unsigned port)

读写二个字节

unsignedinb(unsigned port)

voidoutb(usigned short byte, unsigned port)

读写四个字节

unsignedinb(unsigned port)

voidoutb(usigned long byte, unsigned port)

b.I/O内存

经过将外设寄存器映射到内存空间来进行拜访叫做I/O内存,嵌入式大多只支撑这种操作。

拜访I/O内存有三步:1.请求I/O内存区域2.映射I/O内存区域3.读写I/O内存

请求I/O内存区域

structresource *request_mem_region(unsigned long start, unsigned long len, char *name)

请求拜访从start(I/O物理地址)开端的len长度的I/O内存区域,如成功则回来非NULL值。在/proc/iomem中可能够检查到现已被请求的I/O内存区域。在后面的我写的驱动程序中并没用运用请求这一步,是由于我运用的GPIO内存区域现已被请求,假如在请求会导致失利。可是这样做法是不安全的做法,由于同一I/O内存区域域被多个模块运用。

开释I/O内存区域

voidrelease_mem_region(unsigned long start, unsigned long len)

映射I/O内存区域

void*ioremap(unsigned long phy_addr, unsigned long size)

映射从物理地址phy_addr开端的size长度的的地址空间。回来能够拜访I/O内存地址。由ioreamp回来的地址不应该直接引证,有必要经过下面一些列的读写函数完结。

读写操作I/O内存

读1、2、4个字节:

unsignedint read8(void *addr);

unsignedint read16(void *addr)

unsignedint read32(void *addr)

写读1、2、4个字节:

voidiowrite8(u8 value, void *addr)

voidiowrite16(u8 value, void *addr)

voidiowrite32(u8 value, void *addr)

2.稠浊设备驱动

Linux体系中,存在一类字符设备,他们同享一个主设备号(10),但此设备号不同,咱们称这类设备为稠浊设备(miscdeivce),检查/proc/device中能够看到一个名为misc的主设备号为10。一切的稠浊设备构成一个链表,对设备拜访时内存依据次设备号找到对应的miscdevice设备。

Linux内核运用structmiscdeivce来描绘一个稠浊设备

structmiscdevice{
         int minor;

conststruct file_opreations *fops;

structlist_head list;

structdevice *parent;

structdevice *this_device;     

}

运用时只需填写minor次设备号,*name设备名,*fops文件操作函数集即可。

Linux内核运用misc_register函数注册一个稠浊设备。注册成功后,linux内核为主动为该设备创立设备文件。

intmisc_register(struct miscdevice *misc)

二、驱动代码

1.驱动代码一

这段LED驱动代码选用手动I/O内存映射的方法拜访。没有运用请求内存区域函数,这样使不安全的。直接拜访I/O内存地址而不是经过读写函数拜访也是不安全。一起驱动代码包括硬件相关代码也是移植性欠好的。写这段代码是为了协助了解I/O内存映射的进程。

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

volaTIle unsigned int long *gpb_con = NULL;  

volaTIle unsigned int long *gpb_data = NULL;  

staTIc int leds_ioctl(struct inode *inode, struct file *file,  

unsigned int cmd, unsigned long arg)  

{  

if((cmd>1) |(arg>3))  

return-EINVAL;  

switch(cmd)  

{  

case 0:  

*gpb_data&= ~(1<

break;  

case 1:  

*gpb_data|= (1<

break;  

default:  

return-EINVAL;  

}  

return 0;  

}  

staTIc const struct file_operations leds_fops = {  

.owner = THIS_MODULE,  

.ioctl = leds_ioctl,  

};  

static struct miscdevice misc = {  

.minor =MISC_DYNAMIC_MINOR,  

.name =”my_leds”,  

.fops =&leds_fops,  

};  

static int __init leds_init(void)  

{  

int ret;  

//注册稠浊设备  

ret =misc_register(&misc);  

//映射I/O内存  

gpb_con = (volatileunsigned long *)ioremap(0x56000010, 16); //0x56000010为GPIOB操控寄存器的物理地址  

gpb_data = gpb_con+1;  

//装备LED对应的GPIOB 5、6、7、8口为输出并初始化为1,LED灭  

*gpb_con |=(1<<5*2)|(1<<6*2)|(1<<7*2)|(1<<8*2);  

*gpb_data |=(1<<5) | (1<<6) | (1<<7) | (1<<8);  

printk(“ledsinit.\n”);  

return ret;  

}  

static void leds_exit(void)  

{  

misc_deregister(&misc);          

printk(“leds_exit\n”);  

}  

module_init(leds_init);  

module_exit(leds_exit);  

MODULE_AUTHOR(“Y-Kee”);  

MODULE_LICENSE(“GPL”);  

#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include volatile unsigned int long *gpb_con = NULL;volatile unsigned int long *gpb_data = NULL;static int leds_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg){if((cmd>1) |(arg>3))return-EINVAL;switch(cmd){case 0:*gpb_data&= ~(1<

2.驱动代码二:

选用内核界说好的GPIO接口(S3C2410_GPB5和S3C2410_GPB5_OUTP)和GPIO操作函数(s3c2410_gpio_setpin和s3c2410_gpio_cfgpin)。可移植性好,也是正确的做法。内核的GPIO操作函数也是经过一些的运算将GPIO接口换算成虚拟内存地址然后进行拜访的。

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

#include   

static unsigned long led_table[] =   {  

S3C2410_GPB5,  

S3C2410_GPB6,  

S3C2410_GPB7,  

S3C2410_GPB8,  

};  

static unsigned long led_cfg_table[] =    {  

S3C2410_GPB5_OUTP,  

S3C2410_GPB6_OUTP,  

S3C2410_GPB7_OUTP,  

S3C2410_GPB8_OUTP,  

};  

static int leds_ioctl(struct inode *inode, struct file *file,  

unsigned int cmd, unsigned long arg)  

{  

if((cmd>1) |(arg>3))  

return-EINVAL;  

switch(cmd)  

{  

case 0:  

s3c2410_gpio_setpin(led_table[arg],0);  

break;  

case 1:  

s3c2410_gpio_setpin(led_table[arg],1);  

break;  

default:  

return-EINVAL;  

}  

return 0;  

}  

static const struct file_operations leds_fops = {  

.owner = THIS_MODULE,  

.ioctl = leds_ioctl,  

};  

static struct miscdevice misc = {  

.minor =MISC_DYNAMIC_MINOR,  

.name =”my_leds”,  

.fops =&leds_fops,  

};  

static int __init leds_init(void)  

{  

int ret, i;  

//注册稠浊设备  

ret =misc_register(&misc);  

//装备LED对应的GPIOB 5、6、7、8口为输出并初始化为1,LED灭  

for(i=0; i<4; i++)  

{  

s3c2410_gpio_cfgpin(led_table[i],led_cfg_table[i]);  

s3c2410_gpio_setpin(led_table[i],1);  

}  

printk(“ledsinit.\n”);  

return ret;  

}  

static void leds_exit(void)  

{  

misc_deregister(&misc);  

printk(“leds_exit\n”);  

}  

module_init(leds_init);  

module_exit(leds_exit);  

MODULE_AUTHOR(“Y-Kee”);  

MODULE_LICENSE(“GPL”);  

#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static unsigned long led_table[] = {S3C2410_GPB5,S3C2410_GPB6,S3C2410_GPB7,S3C2410_GPB8,};static unsigned long led_cfg_table[] = {S3C2410_GPB5_OUTP,S3C2410_GPB6_OUTP,S3C2410_GPB7_OUTP,S3C2410_GPB8_OUTP,};static int leds_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg){if((cmd>1) |(arg>3))return-EINVAL;switch(cmd){case 0:s3c2410_gpio_setpin(led_table[arg],0);break;case 1:s3c2410_gpio_setpin(led_table[arg],1);break;default:return-EINVAL;}return 0;}static const struct file_operations leds_fops = {.owner = THIS_MODULE,.ioctl = leds_ioctl,};static struct miscdevice misc = {.minor =MISC_DYNAMIC_MINOR,.name =”my_leds”,.fops =&leds_fops,};static int __init leds_init(void){int ret, i;//注册稠浊设备ret =misc_register(&misc);//装备LED对应的GPIOB 5、6、7、8口为输出并初始化为1,LED灭for(i=0; i<4; i++){s3c2410_gpio_cfgpin(led_table[i],led_cfg_table[i]);s3c2410_gpio_setpin(led_table[i],1);}printk("ledsinit.\n");return ret;}static void leds_exit(void){misc_deregister(&misc);printk("leds_exit\n");}module_init(leds_init);module_exit(leds_exit);MODULE_AUTHOR("Y-Kee");MODULE_LICENSE("GPL");  

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/ziliao/sheji/88715.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部