linux驱动程序设计实例Word文档下载推荐.docx
- 文档编号:19223218
- 上传时间:2023-01-04
- 格式:DOCX
- 页数:27
- 大小:74.64KB
linux驱动程序设计实例Word文档下载推荐.docx
《linux驱动程序设计实例Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《linux驱动程序设计实例Word文档下载推荐.docx(27页珍藏版)》请在冰豆网上搜索。
{
switch(cmd)
{
caseLED_ON:
at91_set_gpio_value(AT91_PIN_PC0,0);
//将PC0引脚置低
break;
caseLED_OFF:
at91_set_gpio_value(AT91_PIN_PC0,1);
//将PC1引脚置高
default:
printk("
novalidcmdinput!
\n"
);
}
structfile_operationsmy_led_ctl_ops={
.owner=THIS_MODULE,
.open=my_led_open,
.release=my_led_release,
.ioctl=my_led_ioctl,
/*初始化设备结构体*/
staticvoidmy_led_setup(structglobal_dev*dev,intindex)
interr;
intdevno=MKDEV(MY_LED_MAJOR,index);
cdev_init(&
dev->
cdev,&
my_led_ctl_ops);
dev->
cdev.owner=THIS_MODULE;
cdev.ops=&
my_led_ctl_ops;
err=cdev_add(&
cdev,devno,1);
if(err)
printk("
addmyledsetupfailed!
staticintmy_led_init(void)
intret;
dev_tdevno=MKDEV(MY_LED_MAJOR,0);
//创建设备号
printk("
myfirstdriver--led!
at91_set_GPIO_periph(AT91_PIN_PC0,1);
at91_set_gpio_output(AT91_PIN_PC0,1);
//对PC0引脚的初始化
ret=register_chrdev_region(devno,1,"
my_led"
//申请设备号
if(ret<
0){
my_ledinit_modulefailedwith%d\n"
ret);
returnret;
else
my_ledinit_modulesuccess!
global_devp=kmalloc(sizeof(structglobal_dev),GFP_KERNEL);
//申请设备内存
memset(global_devp,0,sizeof(structglobal_dev));
my_led_setup(global_devp,0);
returnret;
staticvoidmy_led_cleanup(void)
cdev_del(&
global_devp->
cdev);
//删除设备
kfree(global_devp);
//释放内存
unregister_chrdev_region(MKDEV(MY_LED_MAJOR,0),1);
//释放设备号
MODULE_LICENSE("
MYGPL"
MODULE_AUTHOR("
FANY"
module_init(my_led_init);
//注册设备
module_exit(my_led_cleanup);
//卸载设备
2:
如何将驱动驱动程序编译成模块
①在drivers目录下新建led目录,并在该目录下添加Kconfig,Makefile文件。
Kconfig:
Menu"
Mydriversupport"
Config
Trisate"
leddriver!
"
Help
Leddriver
Endmenu:
Makefile:
Obj-$(CONFIG_MY_LED)+=my_led.o
②修改linux/drivers目录下的Kconfig,Makefile文件
Kconfig:
Source"
drivers/led/Kconfig"
Makefile:
Obj-y+=my_led/
③修改体系结构目录arch/arm目录下的Kconfig文件,否则在配置菜单中将无法看到led的配置选项。
(如果是在drivers目录下新建一文件夹,并在其中添加驱动程序,必须相应的体系结构目录下添加配置选项)。
driver/led/Kconfig"
3.测试程序:
my_led_test.c
stdio.h>
string.h>
stdlib.h>
fcntl.h>
unistd.h>
#defineDEVICE_NAME"
/dev/my_led"
#defineLED_ON0
#defineLED_OFF1
intmain(void)
intfd;
inti;
printf("
my_led_drivertest!
fd=open(DEVICE_NAME,O_RDONLY);
if(fd==-1)
printf("
opendevice%serror!
DEVICE_NAME);
for(i=0;
i<
50;
i++)
ioctl(fd,LED_OFF);
sleep
(1);
ioctl(fd,LED_ON);
ret=close(fd);
ret=%d\n"
closemy_led_driver!
将测试程序编译成目标平台的可执行文件,并下载到开发板
GCC=/home/zzq/9G20/arm-2007q1/bin/arm-none-linux-gnueabi-gcc#交叉编译器的路径
My_led_test:
my_led_test.c
$(GCC)-omy_led_testmy_led_test.c
clean:
rm-fmy_led_test
学习总结:
熟悉驱动程序的架构,如何将驱动程序添加到内核即如何写测试程序。
二:
按键驱动设计
1.硬件部分:
PC4接按键。
2.驱动程序:
linux/interrupt.h>
linux/irq.h>
linux/sched.h>
linux/pm.h>
linux/sysctl.h>
linux/proc_fs.h>
linux/delay.h>
linux/input.h>
linux/gpio_keys.h>
asm/uaccess.h>
asm/io.h>
asm/irq.h>
mach/gpio.h>
#defineBUTTON_MAJOR245
#defineDEVICE_NAME"
/dev/button"
staticvolatileintev_press=0;
staticstructcdevbutton_cdev;
staticvoidbutton_do_tasklet(unsignedlongn);
DECLARE_TASKLET(button_tasklet,button_do_tasklet,0);
//定义tasklet并与处理函数关联起来
staticDECLARE_WAIT_QUEUE_HEAD(button_waitq);
//静态的初始化一个等待队列
structbutton_irq_desc{
intirq;
intirq_type;
intpin;
intnumber;
char*name;
staticstructbutton_irq_descbutton_irq[1]={{AT91_PIN_PB22,AT91_AIC_SRCTYPE_LOW,AT91_PIN_PB22,0,"
KEY0"
}};
staticintkey_values[1]={0};
//中断处理底半部
staticvoidbutton_do_tasklet(unsignedlongn)
wake_up_interruptible(&
button_waitq);
//唤醒队列
buttonpress!
//中断处理顶半部
staticirqreturn_tbutton_interrupt(intirq,void*dev_id,structpt_regs*regs)
intup;
staticintpress_down;
up=gpio_get_value(button_irq[0].pin);
irq\n"
/*按键消抖*/
if(up)press_down=1;
//当按键没有按下,置标志位为1.
if(!
up&
&
(press_down==1)){
press_down=0;
//当按键按下,置标志位为0.
ev_press=1;
at91_set_gpio_value(button_irq[0].pin,1);
key_values[button_irq[0].number]=!
up;
tasklet_schedule(&
button_tasklet);
returnIRQ_RETVAL(IRQ_HANDLED);
staticintbutton_open(structinode*inode,structfile*filp)
staticintbutton_release(structinode*inode,structfile*filp)
staticintbutton_read(structfile*filp,char__user*buff,size_tcount,loff_t*offp)
ev_press){//当按键没有按下时,读进程挂起,知道按键按下。
wait_event_interruptible(button_waitq,ev_press);
ev_press=0;
ret=copy_to_user(buff,(constvoid*)key_values,min(sizeof(key_values),count));
memset((void__user*)key_values,0,sizeof(key_values));
returnret?
-EFAULT:
min(sizeof(key_values),count);
staticstructfile_operationsbutton_fops={
.open=button_open,
.release=button_release,
.read=button_read,
staticintirq_init(void)
at91_set_gpio_input(button_irq[0].pin,1);
at91_set_deglitch(button_irq[0].pin,1);
//将PC0设置为中断功能
set_irq_type(button_irq[0].irq,button_irq[0].irq_type);
//设置中断类型
at91_set_gpio_value(button_irq[0].pin,1);
err=request_irq(button_irq[0].irq,button_interrupt,IRQF_DISABLED,\
button_irq[0].name,(void*)&
button_irq[0]);
//申请中断
if(err){
disable_irq(button_irq[0].irq);
free_irq(button_irq[0].irq,(void*)&
return-EBUSY;
}
staticint__initbutton_init(void)
intret,err;
ret=register_chrdev_region(MKDEV(BUTTON_MAJOR,0),1,DEVICE_NAME);
if(ret<
buttoninitfailedwith%d\n"
button_cdev,&
button_fops);
button_cdev.owner=THIS_MODULE;
button_cdev.ops=&
button_fops;
button_cdev,MKDEV(BUTTON_MAJOR,0),1);
if(err<
0){
keyaddfailed\n"
returnerr;
irq_init();
keydriveraddsuccess!
staticvoid__exitbutton_exit(void)
button_cdev);
unregister_chrdev_region(MKDEV(BUTTON_MAJOR,0),1);
disable_irq(button_irq[0].irq);
free_irq(button_irq[0].irq,(void*)&
unregisterkeydriver!
module_init(button_init);
module_exit(button_exit);
fany"
MODULE_DESCRIPTION("
Atmel9g20keyDriver"
GPL"
errno.h>
intfd,i;
intkey_value[1];
keytest!
fd=open(DEVICE_NAME,O_RDWR);
if(fd<
0)
opendevicesuccess!
while
(1){
ret=read(fd,key_value,1);
if(!
ret){
printf("
buttonnotpress!
}
else
key_value%d\n"
key_value);
close(fd);
closekeydriver!
4.学习总结:
在linux设备驱动程序中,中断处理程序通常分为两部分:
上半部和下半部。
上半部处理比较紧急的的硬件操作,比如简单的读取寄存器中的状态并清除中断标志后,进行登记中断的工作。
剩下的工作就由下半部来实现。
对阻塞与非阻塞进程的理解,阻塞:
在执行设备操作时,若不能获取设备资源则挂起,直到满足可操作的条件后再进行操作。
非阻塞操作:
在执行设备操作时,若不能获取设备资源则立即返回。
三:
总线驱动
AT91SAM9G20存储器映射图(截取部分),片选4接外设,利用总线对外设进行访问。
但是在linux驱动,不能对物理地址进行操作,可通过内存访问的机制实现对物理地址的访问。
将一段物理地址空间映射到虚拟地址空间中,然后对虚拟地址的操作即是对物理地址的操作。
3.1:
linux/errno.h>
linux/device.h>
linux/platform_device.h>
mach/at91sam9_smc.h>
mach/at91sam9260_matrix.h>
mach/at91sam9260.h>
mach/at91_pmc.h>
#include"
atmel9g20_liu.h"
structgr_liu_info{
void__iomem*virtbase;
void__iomem*regbase;
structresource*res;
u32flags;
staticstructgr_liu_infoliu_info;
staticstructcdevatmel9g20_liu_cdev;
unsignedshortliu_read(unsignedaddr)
addr&
=ATMEL9G20_LIU_MASK;
addr=addr<
<
1;
addr+=(unsignedlong)liu_info.regbase;
readthevirtualaddris0x%x\n"
addr);
returnreadw(addr)&
0xff;
//读IO内存。
EXPORT_SYMBOL(liu_read);
intliu_write(unsignedaddr,unsignedval)
writethevirtualaddris0x%x\n"
writew(val&
0xff,addr);
//写IO内存
EXPORT_SYMBOL(liu_write);
staticintatmel9g20_liu_open(structinode*inode,structfile*filp)
staticintatmel9g20_liu_release(structinode*inode,structfile*filp)
staticintatmel9g20_liu_ioctl(s
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- linux 驱动程序 设计 实例