linux驱动学习笔记LED
led代码总结

Led灯总结1、module_param_call//函数源码#define module_param_call(name, set, get, arg, perm) \ staticconststruct kernel_param_ops __param_ops_##name = \{ .flags = 0, (void *)set, (void *)get }; \ __module_param_call(MODULE_PARAM_PREFIX, \name, &__param_ops_##name, arg, \(perm) + sizeof(__check_old_set_param(set))*0, -1, 0)调用module_param_call会填充kernel_param中最重要的就是kernel_param_ops结构体,此结构体会被填充,此结构体包含了set函数指针和get函数指针重要的函数指针。
struct kernel_param{constchar*name;conststruct kernel_param_ops*ops;u16perm;s16level;union{void*arg;conststruct kparam_string*str;conststruct kparam_array*arr;};};struct kernel_param_ops{/* How the ops should behave */unsignedintflags;/* Returns 0, or -errno. arg is in kp->arg. */int(*set)(constchar*val,conststruct kernel_param*kp);/* Returns length written or -errno. Buffer is 4k (ie. be short!) */int(*get)(char*buffer,conststruct kernel_param*kp);/* Optional function to free kp->arg when module unloaded. */void(*free)(void*arg);};在__module_param_call函数中,通过__attribute__(__section(“__param”))将数据放入__param字段中,即初始化kernel_param结构体。
Linux设备驱动模型与sysfs---platform总线设备驱动

Linux在2.6版本引入了设备驱动模型,设备驱动模型负责统一实现和维护一些特性,诸如:热插拔、对象生命周期、用户空间和驱动空间的交互等基础设施1.设备驱动模型基本概念设备驱动模型主要包含:类(class)、总线(bus)、设备(device)、驱动(driver),它们的本质都是内核中的几种数据结构的“实例”∙类的本质是class结构体类型,各种不同的类其实就是class的各种实例∙总线的本质是bus_type结构体类型,各种不同的总线其实就是bus_type的各种实例∙设备的本质是device结构体类型,各种不同的设备其实就是device的各种实例∙驱动的本质是device_driver结构体类型,各种不同的驱动其实就是device_driver的各种实例2.sysfs基本概念sysfs其实就是/sys目录,其主要作用就是:展示设备驱动模型中各组件的层次关系,并将各组件的本体——内核中的数据结构以文件形式呈现,方便用户层查看及操作3./sys目录结构与设备驱动模型∙/sys目录结构很好的展示了驱动设备模型,如图:∙注意:同一个设备可能在/sys中存在多个设备文件,比如一颗led的设备文件可能在/sys/bus/platform/devices/led1,同时还有一个在/sys/class/leds/led1。
虽然他们都是同一颗led的设备文件,但是他们的来源、机制、原理都是不同的,不能混为一谈4.各组件的特性与联系∙kobject:设备驱动模型各实例的最基本单元,提供一些公用型服务如:提供该实例在sysfs中的操作方法(show和store);提供在sysfs中以文件形式存在的属性,其实就是应用接口;提供各个实例的层次架构,让sysfs中弄出目录结构。
设备驱动模型中每个实例内部都会包含一个kobject∙总线、设备、驱动,这三者有着密切的联系。
在内核中,设备和驱动是分开注册的,注册设备的时候,并不需要驱动已经存在,而驱动被注册的时候,也不需要对应的设备已经被注册。
基于Linux的LED点阵应用程序设计

030 ) 6 00 料 学 院 ,河 北 石家 庄 0 04 ;4唐 山市 气 象 局 科 技服 务 中心 ,河 北 唐 山 503 .
’
.
卟 戋 卟 奖 。
卟 ‘
奖
装
明 Байду номын сангаас
驱动程序作为可加载的模块 ,由系统管理员动态加载,使之
成为核心的一部分。 编写驱动程序的主要工作就是编 写子 函
数,并填充 feop r to s各个域 。 i e ai n l
.
此应用程序 是在 L D 驱动加载之后使用 ,否则无法正 E 常运行 。本设计首先将 L D 点阵驱动起来 ,通过编写测试 E
,
(. ax e ooo i l ueuT n sa 6 3 0 C ia2C l g f c nmis n n ae n, h i ha g i a nvr 1 n i t rlgc ra, aghn0 4 0 , hn ; .ol e E o o c d Qi M e aB e o a Ma gme tS ia u e oU i - jz n T d e sy S iah ag0 04 , hn; .ol e f a r l c n e n n ier g S iah agTea nvri , h i h ag i, h i un 50 3 C i 3 lg M t i i c d gn ei , h i u idoU ie t S ia un t jz a C e o eaS e a E n jz n sy j z 0 0 3 C i ; . tooo i l cec dT cn lg et , aghnMeerl i l ueu T n sa 3 0 , hn) 50 , hn 4 4 a Meerl c i e eh o yC ne T n sa tooo c ra , agh 0 00 C ia g aS n a n o r g aB n 6
uboot 传统led驱动写法

uboot 传统led驱动写法
传统的U-Boot LED驱动通常是通过对硬件寄存器的直接操作来实现的。
在U-Boot中,LED驱动通常包括以下几个方面的内容:
1. 硬件初始化,在U-Boot启动过程中,需要对与LED相关的硬件进行初始化,包括设置相应的寄存器、引脚复用等操作。
2. LED控制接口,U-Boot通常会提供一些API或者函数接口,用于控制LED的开关、亮度和闪烁等操作。
这些接口通常会直接操作硬件寄存器来实现对LED的控制。
3. 设备树配置,在一些新的U-Boot版本中,设备树已经成为了描述硬件信息的标准方式。
因此,针对一些新的硬件平台,需要在设备树中添加LED相关的描述信息,以便U-Boot能够正确识别和初始化LED硬件。
4. 编译配置,在配置U-Boot编译选项时,需要确保使能了LED驱动相关的配置选项,以便将LED驱动代码编译进U-Boot镜像中。
总的来说,传统的U-Boot LED驱动编写涉及到硬件初始化、驱动代码编写、设备树配置和编译选项配置等多个方面。
针对具体的硬件平台和LED驱动需求,具体的编写方式会有所不同,但通常都会涉及到上述几个方面。
基于rk3568的linux驱动开发——gpio知识点 -回复

基于rk3568的linux驱动开发——gpio知识点-回复基于rk3568的Linux驱动开发——GPIO知识点GPIO(General Purpose Input/Output)是通用输入输出的意思,是嵌入式系统中的常用功能。
在rk3568芯片上,GPIO用于实现与外部设备的通信和控制,比如控制LED灯、键盘、电机等。
本文将介绍rk3568芯片上的GPIO控制器、GPIO驱动的开发以及GPIO 在Linux系统中的应用。
一、GPIO控制器在rk3568芯片中,GPIO控制器是用来控制GPIO端口的硬件模块。
每个GPIO控制器可以管理多个GPIO端口,每个GPIO端口可以被配置为输入或输出。
GPIO控制器通常包含寄存器用于配置和控制GPIO端口的功能,比如方向、电平等。
二、GPIO驱动的开发GPIO驱动是用于控制和管理GPIO功能的软件模块。
在Linux内核中,GPIO驱动通过sysfs接口暴露给用户空间,以便用户可以通过文件系统访问和控制GPIO端口。
以下是GPIO驱动的开发过程:1. 确定GPIO控制器和GPIO端口:首先需要确定要使用的GPIO控制器和GPIO端口。
在rk3568芯片手册中可以找到相应的信息。
2. 创建GPIO设备:在Linux内核中,GPIO驱动是通过GPIO子系统来管理的。
首先需要在设备树中添加GPIO设备描述,并分配一个唯一的GPIO号码。
3. 注册GPIO设备:在驱动的初始化函数中,需要调用相应的函数注册GPIO设备,以便系统能够识别和管理该设备。
4. 设置GPIO模式和方向:通过调用GPIO控制器的寄存器,可以设置GPIO端口的模式和方向。
例如,可以将GPIO端口配置为输入模式或输出模式。
5. 读取和写入GPIO值:读取GPIO值可以通过读取GPIO控制器的寄存器来实现,写入GPIO值可以通过写入GPIO控制器的寄存器来实现。
例如,可以将GPIO端口的电平设置为高或低。
韦东山嵌入式Linux学习笔记-1-为什么要学习嵌入式Linux

韦东⼭嵌⼊式Linux学习笔记-1-为什么要学习嵌⼊式Linux论单⽚机学习单⽚机的前途:没⼯作啊~没⼈会⽤⽉薪2万来招聘⼀个博⼠写本科⽣都能做的事;不要使⽤C51、STM32这种单⽚机专⽤的开发板;不要使⽤Keil等MDK,集成度太⾼的软件(内部封装了很多技术细节).嵌⼊式Linux与Windows的区别windows系统: 上电->BIOS->启动Windows内核->挂载C盘,D盘等系统盘,应⽤盘->启动应⽤程序;嵌⼊式Linux系统: 上电->BootLoader->启动Linux内核->挂载根⽂件系统->启动应⽤程序.BootLoader的功能要从Flash/SD卡读取内核,需要:1. 初始化时钟,初始化内存,设置⽹卡;2. 从Flash/SD卡中读取内核启动;3. 显⽰logo,需要操作LCD.* 那怎么写这些呢?* ⼀步步地写!从LED,时钟,⽹卡,Flash等⼀步步去写.(**本质就是单⽚机程序!**)**BootLoader是单⽚机程序⼤全.**Linux内核的功能内核要挂载根⽂件系统,意味着内核也要能操作硬件!,这就是驱动程序.简单驱动程序框架:驱动程序=软件框架+硬件配置.* (软件)应⽤程序调⽤: open, read, write;* (硬件)驱动程序执⾏: drv_open要配置硬件,GPIO设置为输出;drv_read要返回GPIO状态;drv_write要写GPIO的值.* 要掌握硬件开发的能⼒:学会看原理图,看芯⽚⼿册,知道怎么读写寄存器.开发嵌⼊式Linux系统的硬件需求* 开发板选择: `单⽚机->bootloader->linux驱动->APP(纯C++⽆界⾯应⽤程序,Qt/Android); `* 开发板种类:三星(S3C2440, S3C6410, S5PV210, EXYNOS4412), TI(AM437X,AM335X), Freescale(I.MX6), 国产芯⽚(全志,瑞芯微).* 选择原则:资料丰富-S3C2440为⾸选!* 使⽤S3C2440开发板,在Ubuntu下使⽤arm-linux-gcc⼯具来编译程序.JZ2440开发板上电* 插上电源,打开开关;可以看到linux的企鹅以及后⾯的Qt桌⾯;* 连接串⼝,在PC上打开串⼝⼯具`MobaXterm`,点击左上⾓的`Session`,点击弹出窗⼝的`Serial`,Serial Port选择 Prolific开头的那个端⼝,波特率选择115200, Advance Settings⾥的Serial Engine选择`PuTTY`,硬件流控制选择`None`,点击`OK`.* 按空格键,可以查看到开发板上运⾏的Linux内核系统,在这⾥可以运⾏Linux命令⾏指令. 可以理解为,这⾥直接连接了Linux开发板.嵌⼊式Linux开发概述。
基于rk3568的linux驱动开发——gpio知识点

基于rk3568的linux驱动开发——gpio知识点基于rk3568的Linux驱动开发——GPIO知识点一、引言GPIO(General Purpose Input/Output)通用输入/输出,是现代计算机系统中的一种常用接口,它可以根据需要配置为输入或输出。
通过GPIO 接口,我们可以与各种外设进行通信,如LED灯、按键、传感器等。
在基于Linux系统的嵌入式设备上开发驱动程序时,熟悉GPIO的使用是非常重要的一环。
本文将以RK3568芯片为例,详细介绍GPIO的相关知识点和在Linux驱动开发中的应用。
二、GPIO概述GPIO是系统中的一个基本的硬件资源,它可以通过软件的方式对其进行配置和控制。
在嵌入式设备中,通常将一部分GPIO引脚连接到外部可编程电路,以实现与外部设备的交互。
在Linux中,GPIO是以字符设备的形式存在,对应的设备驱动为"gpiolib"。
三、GPIO的驱动开发流程1. 导入头文件在驱动程序中,首先需要导入与GPIO相关的头文件。
对于基于RK3568芯片的开发,需要导入头文件"gpiolib.h"。
2. 分配GPIO资源在驱动程序中,需要使用到GPIO资源,如GPIO所在的GPIO Bank和GPIO Index等。
在RK3568芯片中,GPIO资源的分配是通过设备树(Device Tree)来进行的。
在设备树文件中,可以定义GPIO Bank和GPIO Index等信息,以及对应的GPIO方向(输入或输出)、电平(高电平或低电平)等属性。
在驱动程序中,可以通过设备树接口(Device Tree API)来获取这些GPIO资源。
3. GPIO的配置与控制在驱动程序中,首先要进行GPIO的初始化与配置。
可以通过函数"gpiod_get()"来打开指定的GPIO,并判断其是否有效。
如果成功打开GPIO,则可以使用函数"gpiod_direction_output()"或"gpiod_direction_input()"来设置GPIO的方向,分别作为输出或输入。
LED驱动程序

普通字符设备LED驱动程序(IO映射内存实现).驱动程序:[cpp] view plaincopyprint?01.#include <linux/module.h> //内核模块头文件02.#include <linux/moduleparam.h> //内核模块参数头文件03.#include <linux/kernel.h> //printk头文件04.05.#include<asm/io.h>//ioremap需要06.//包含有可装载模块需要的大量符合和函数的定义;07.#include <linux/init.h>08.//指定初始化和清除函数;09.10.//struct file_operactions 相关头文件11.#include <linux/fs.h>12.#include <asm/uaccess.h>13.14.//struct cdev 相关头文件15.#include <linux/types.h>16.#include <linux/cdev.h>17.18.//定义设备名称19.#define DEVICE_NAME "led2"20.21.//定义主次设备号22.static unsigned int LedMajor=0;23.static unsigned int LedMinor=0;24.25./* 注册字符设备*/26.static struct cdev *led_cdev;27.static dev_t dev; //设备号28.29.volatile unsigned int long *gpb_con = NULL;30.volatile unsigned int long *gpb_data = NULL;31.32.33.static int led_ioctl(struct inode *inode, struct file *file,34. unsigned int cmd, unsigned long arg)35.{36.37. if((cmd>1) | (cmd<0) | (arg>3) | (arg<0))38. return -EINV AL;39.40. switch(cmd)41. {42. case 0:43. *gpb_data&= ~(1<<(arg+5)); //044. break;45. case 1:46. *gpb_data|= (1<<(arg+5)); //147. break;48.49. default:50. return -EINV AL;51.52. }53.54. return 0;55.}56.57.58.static int led_open(struct inode *inode, struct file *file)59.{60. printk("led_open\n");61.62. //映射I/O内存63. gpb_con = (volatile unsigned long *)ioremap(0x56000010,16); //0x56000010为GPIOB控制寄存器的物理地址64. gpb_data = gpb_con+1; //这里+1是加了4个字节,因为指针+1是以指针的长度为单位的(unsigned long *)65.66. /* 配置GPB5,6,7,8为输出*/67. *gpb_con |= (1<<(5*2)) | (1<<(6*2)) | (1<<(7*2)) | (1<<(8*2));68. /* 初始化为灭*/69. *gpb_data |=(1<<5) | (1<<6) | (1<<7) | (1<<8);70.71. printk("leaving led_open\n");72. return 0;73.74.}75.76.static int led_release(struct inode *inode,struct file *file)77.{78.79. printk("close major=%d, minor=%d\n", imajor(inode), iminor(inode));80. return 0;81.}82.83.static struct file_operations chardev_fops={84. .owner = THIS_MODULE,85. .open = led_open,86. .release = led_release,87. .ioctl = led_ioctl,88.};89.90.91.static int __init dev_init(void)92.{93. int result;94./*分配设备编号*/95. if(LedMajor)96. {97. dev=MKDEV(LedMajor,LedMinor);//创建设备编号98. result=register_chrdev_region(dev,1,DEVICE_NAME);99. }100. else101. {102.result=alloc_chrdev_region(&dev,LedMinor,1,DEVICE_NAME); 103. LedMajor=MAJOR(dev);104. }105. if(result<0)106. {107. printk(KERN_W ARNING"LED: cannot get major %d \n",LedMajor);108. return result;109. }110./* 注册字符设备*/111. led_cdev=cdev_alloc();//为struct cdev 分配空间112.113. cdev_init(led_cdev,&chardev_fops);//初始化struct cdev 114.115. led_cdev->owner=THIS_MODULE;116.117. result=cdev_add(led_cdev,dev,1);118.119. if(result)120. printk("<1>Error %d while register led device!\n",result); 121.122. printk("initialzed.\n");123.124. return 0;125.}126.127.static void __exit dev_exit(void)128.{129. unregister_chrdev_region(MKDEV(LedMajor,LedMinor),1); 130. cdev_del(led_cdev);131.}132.133.module_init(dev_init);134.module_exit(dev_exit);135.MODULE_LICENSE("GPL");136.MODULE_AUTHOR("Bai");#include <linux/module.h> //内核模块头文件#include <linux/moduleparam.h> //内核模块参数头文件#include <linux/kernel.h> //printk头文件#include<asm/io.h>//ioremap需要//包含有可装载模块需要的大量符合和函数的定义;#include <linux/init.h>//指定初始化和清除函数;//struct file_operactions 相关头文件#include <linux/fs.h>#include <asm/uaccess.h>//struct cdev 相关头文件#include <linux/types.h>#include <linux/cdev.h>//定义设备名称#define DEVICE_NAME "led2"//定义主次设备号static unsigned int LedMajor=0;static unsigned int LedMinor=0;/* 注册字符设备*/static struct cdev *led_cdev;static dev_t dev; //设备号volatile unsigned int long *gpb_con = NULL;volatile unsigned int long *gpb_data = NULL;static int led_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg){if((cmd>1) | (cmd<0) | (arg>3) | (arg<0))return -EINV AL;switch(cmd){case 0:*gpb_data&= ~(1<<(arg+5)); //0break;case 1:*gpb_data|= (1<<(arg+5)); //1break;default:return -EINV AL;}return 0;}static int led_open(struct inode *inode, struct file *file){printk("led_open\n");//映射I/O内存gpb_con = (volatile unsigned long *)ioremap(0x56000010,16); //0x56000010为GPIOB控制寄存器的物理地址gpb_data = gpb_con+1; //这里+1是加了4个字节,因为指针+1是以指针的长度为单位的(unsigned long *)/* 配置GPB5,6,7,8为输出*/*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("leaving led_open\n");return 0;}static int led_release(struct inode *inode,struct file *file){printk("close major=%d, minor=%d\n", imajor(inode), iminor(inode));return 0;}static struct file_operations chardev_fops={.owner = THIS_MODULE,.open = led_open,.release = led_release,.ioctl = led_ioctl,};static int __init dev_init(void){int result;/*分配设备编号*/if(LedMajor){dev=MKDEV(LedMajor,LedMinor);//创建设备编号result=register_chrdev_region(dev,1,DEVICE_NAME);}else{result=alloc_chrdev_region(&dev,LedMinor,1,DEVICE_NAME);LedMajor=MAJOR(dev);}if(result<0){printk(KERN_W ARNING"LED: cannot get major %d \n",LedMajor);return result;}/* 注册字符设备*/led_cdev=cdev_alloc();//为struct cdev 分配空间cdev_init(led_cdev,&chardev_fops);//初始化struct cdevled_cdev->owner=THIS_MODULE;result=cdev_add(led_cdev,dev,1);if(result)printk("<1>Error %d while register led device!\n",result);printk("initialzed.\n");return 0;}static void __exit dev_exit(void){unregister_chrdev_region(MKDEV(LedMajor,LedMinor),1);cdev_del(led_cdev);}module_init(dev_init);module_exit(dev_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Bai");这段代码把GPB寄存器的物理地址映射到内存上,再进行操作。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
LED驱动学习:是一个char字符类型的驱动//配置模式为输出端口static unsigned int led_cfg_table [] = {S3C2410_GPB5_OUTP,S3C2410_GPB6_OUTP,S3C2410_GPB7_OUTP,S3C2410_GPB8_OUTP,};s3c2410_gpio_cfgpin(S3C2410_GPB5, S3C2410_GPB5_OUTP);s3c2410_gpio_cfgpin(37, 0x01 << 10);这个在\arch\arm\mach-s3c2410\include\mach\regs-gpio.h中定义#define S3C2410_GPB5 S3C2410_GPIONO(S3C2410_GPIO_BANKB, 5) #define S3C2410_GPB5_INP (0x00 << 10)#define S3C2410_GPB5_OUTP (0x01 << 10)#define S3C2410_GPB5_nXBACK (0x02 << 10)S3C2410_GPIONO(S3C2410_GPIO_BANKB, 5)#define S3C2410_GPIONO(bank,offset) ((bank) + (offset))#define S3C2410_GPIO_BANKA (32*0)#define S3C2410_GPIO_BANKB(32*1)static int __init dev_init(void){int ret;int i;for (i = 0; i < 4; i++) {s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);s3c2410_gpio_setpin(led_table[i], 0);}在驱动的初始化函数中经常看到,__init 前缀,这个在下面文件中定义file:/include/linux/init.h• /* These macros are used to mark some functions or•* initialized data (doesn't apply to uninitialized data)•* as `initialization' functions. The kernel can take this•* as hint that the function is used only during the initialization •* phase and free up used memory resources after•*•* Usage:•* For functions:•*•* You should add __init immediately before the function name, like: •*•* static void __init initme(int x, int y)•* {•* extern int z; z = x * y;•* }主要是将这个函数放在init段section中,这样可以在执行完成后,释放内存。
void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function){void __iomem *base = S3C24XX_GPIO_BASE(pin);unsigned long mask;unsigned long con;unsigned long flags;if (pin < S3C2410_GPIO_BANKB) {mask = 1 << S3C2410_GPIO_OFFSET(pin);} else {mask = 3 << S3C2410_GPIO_OFFSET(pin)*2; //3<<(37*2) }switch (function) {case S3C2410_GPIO_LEA VE:mask = 0;function = 0;break;case S3C2410_GPIO_INPUT:case S3C2410_GPIO_OUTPUT:case S3C2410_GPIO_SFN2:case S3C2410_GPIO_SFN3:if (pin < S3C2410_GPIO_BANKB) {function -= 1;function &= 1;function <<= S3C2410_GPIO_OFFSET(pin);} else {function &= 3;function <<= S3C2410_GPIO_OFFSET(pin)*2;}}/* modify the specified register wwith IRQs off */local_irq_save(flags);con = __raw_readl(base + 0x00);con &= ~mask;con |= function;__raw_writel(con, base + 0x00);local_irq_restore(flags);}#define S3C24XX_GPIO_BASE(x) S3C2410_GPIO_BASE(x)#define S3C2410_GPIO_BASE(pin) ((((pin) & ~31) >> 1) + S3C24XX_V A_GPIO)S3C24XX_V A_GPIO这个在\arch\arm\plat-s3c24xx\include\plat\map.h中定义,这个是Memory Map的定义:#define S3C2410_PA_GPIO (0x)#define S3C24XX_V A_GPIO ((S3C24XX_PA_GPIO - S3C24XX_PA_UART) + S3C24XX_V A_UART)#define S3C24XX_SZ_GPIO SZ_1M其中PA表示Physical Address,V A表示Virtual Address由pdf中的GPIO的定义可以看出是一致的。
/* UARTs */#define S3C24XX_V A_UART S3C_V A_UART#define S3C2410_PA_UART (0x)#define S3C_V A_UART S3C_ADDR(0x01000000) /* UART */#define S3C_ADDR(x) (S3C_ADDR_BASE + (x))#define S3C_ADDR_BASE(0xF4000000)__iomem是I/O空间的表示可能不同。
当使用__iomem时,compiler会忽略对变量的检查(因为用的是void __iomem)。
但sparse会对它进行检查,当__iomem的指针和正常的指针混用时,就会发出一些warnings 有个地方讲不通:(这个地方应该是都不满足switch的条件,所以,function不改变)#define S3C2410_GPIO_LEA VE (0xFFFFFFFF)#define S3C2410_GPIO_INPUT (0xFFFFFFF0) /* not available on A */#define S3C2410_GPIO_OUTPUT (0xFFFFFFF1)#define S3C2410_GPIO_IRQ (0xFFFFFFF2) /* not available for all */#define S3C2410_GPIO_SFN2 (0xFFFFFFF2) /* bank A => addr/cs/nand */#define S3C2410_GPIO_SFN3 (0xFFFFFFF3) /* not available on A */而#define S3C2410_GPB5_OUTP (0x01 << 10)所以,s3c2410_gpio_cfgpin(S3C2410_GPB5, S3C2410_GPB5_OUTP);switch (function)根本对不上号?#define __raw_readl(p) (*(unsigned long *)(p))#define __raw_writel(v,p) (*(unsigned long *)(p) = (v))*******************************static struct miscdevice misc = {.minor = MISC_DYNAMIC_MINOR,.name = DEVICE_NAME,.fops = &dev_fops,};驱动注册时,如果次号指定MISC_DYNAMIC_MINOR,则进行动态分配。
#define DEVICE_NAME "leds"include\linux在这个头文件中主要是misc(混合)设备注册和注销:其它类型---不能严格划分的设备类型,也叫混合类型有:1.结构体:struct miscdevice {int minor;const char *name;const struct file_operations *fops;struct list_head list;struct device *parent;struct device *this_device;};2.misc设备注册:extern int misc_register(struct miscdevice * misc);misc设备注销:extern int misc_deregister(struct miscdevice * misc);说明:上面的结构体是注册混合设备所需要的参数。
主要有:minor:次设备号,所有的misc设备共用一个主设备号,所以注册misc设备时只要次设备号就可以了。
利用次设备号来区分设备的。
name:misc设备名。
*fops:misc设备文件操作结构体。
其它三个参数很少用。
杂项设备(misc device)杂项设备也是在嵌入式系统中用得比较多的一种设备驱动。
在 Linux 内核的include\linux目录下有Miscdevice.h文件,要把自己定义的misc device从设备定义在这里。
其实是因为这些字符设备不符合预先确定的字符设备范畴,所有这些设备采用主编号10,一起归于misc device,其实misc_register就是用主标号10调用register_chrdev()的。