linux驱动程序设计实例Word文档下载推荐.docx

上传人:b****5 文档编号:19223218 上传时间:2023-01-04 格式:DOCX 页数:27 大小:74.64KB
下载 相关 举报
linux驱动程序设计实例Word文档下载推荐.docx_第1页
第1页 / 共27页
linux驱动程序设计实例Word文档下载推荐.docx_第2页
第2页 / 共27页
linux驱动程序设计实例Word文档下载推荐.docx_第3页
第3页 / 共27页
linux驱动程序设计实例Word文档下载推荐.docx_第4页
第4页 / 共27页
linux驱动程序设计实例Word文档下载推荐.docx_第5页
第5页 / 共27页
点击查看更多>>
下载资源
资源描述

linux驱动程序设计实例Word文档下载推荐.docx

《linux驱动程序设计实例Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《linux驱动程序设计实例Word文档下载推荐.docx(27页珍藏版)》请在冰豆网上搜索。

linux驱动程序设计实例Word文档下载推荐.docx

{

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

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 农林牧渔 > 农学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1