欢迎来到淘文阁 - 分享文档赚钱的网站! | 帮助中心 好文档才是您的得力助手!
淘文阁 - 分享文档赚钱的网站
全部分类
  • 研究报告>
  • 管理文献>
  • 标准材料>
  • 技术资料>
  • 教育专区>
  • 应用文书>
  • 生活休闲>
  • 考试试题>
  • pptx模板>
  • 工商注册>
  • 期刊短文>
  • 图片设计>
  • ImageVerifierCode 换一换

    linux驱动程序设计实例.doc

    • 资源ID:63852654       资源大小:130.50KB        全文页数:18页
    • 资源格式: DOC        下载积分:20金币
    快捷下载 游客一键下载
    会员登录下载
    微信登录下载
    三方登录下载: 微信开放平台登录   QQ登录  
    二维码
    微信扫一扫登录
    下载资源需要20金币
    邮箱/手机:
    温馨提示:
    快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。
    如填写123,账号就是123,密码也是123。
    支付方式: 支付宝    微信支付   
    验证码:   换一换

     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    linux驱动程序设计实例.doc

    AT91SAM9G20驱动程序设计开发环境:Vmware + ubuntu10.04硬件平台:AT91SAM9G20Linux版本:linux2.6.27一:led驱动说明:因为设计的开发板上没有led灯,便通过PC0来演示,通过示波器来观察引脚端的电平变化。1.驱动程序:my_led.c#include <linux/kernel.h>#include <linux/init.h>#include <linux/module.h>#include <linux/fs.h>#include <linux/cdev.h>#include <linux/types.h>#include <asm/gpio.h>#define MY_LED_MAJOR250/定义主设备号#define LED_ON 0#define LED_OFF 1struct global_devstruct cdev cdev;/定义设备结构体struct global_dev *global_devp;/定义一个指向设备结构体的指针static int my_led_open(struct inode *inode, struct file *filp)filp->private_data = global_devp;return 0;static int my_led_release(struct inode *inode, struct file *file)return 0;static int my_led_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data)switch(cmd)case LED_ON:at91_set_gpio_value(AT91_PIN_PC0, 0);/将PC0引脚置低break;case LED_OFF:at91_set_gpio_value(AT91_PIN_PC0, 1);/将PC1引脚置高break;default:printk("no valid cmd input!n");break;return 0;struct file_operations my_led_ctl_ops =.owner = THIS_MODULE,.open = my_led_open,.release = my_led_release,.ioctl = my_led_ioctl,;/*初始化设备结构体*/static void my_led_setup(struct global_dev *dev, int index)int err;int devno = MKDEV(MY_LED_MAJOR, index);cdev_init(&dev->cdev, &my_led_ctl_ops);dev->cdev.owner = THIS_MODULE;dev->cdev.ops = &my_led_ctl_ops;err = cdev_add(&dev->cdev, devno, 1);if(err)printk("add my led setup failed!n");static int my_led_init(void)int ret;dev_t devno = MKDEV(MY_LED_MAJOR, 0);/创建设备号printk("my first driver-led!n");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) printk("my_led init_module failed with %dn", ret);return ret;elseprintk("my_led init_module success!n");global_devp = kmalloc(sizeof(struct global_dev), GFP_KERNEL);/申请设备内存memset(global_devp, 0, sizeof(struct global_dev);my_led_setup(global_devp, 0);return ret;static void my_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 "My driver support"Config Trisate "led driver!"Help Led driverEndmenu: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目录下新建一文件夹,并在其中添加驱动程序,必须相应的体系结构目录下添加配置选项)。Kconfig:Source "driver/led/Kconfig"3.测试程序:my_led_test.c#include <stdio.h>#include <string.h>#include <stdlib.h>#include <fcntl.h>#include <unistd.h>#define DEVICE_NAME "/dev/my_led"#define LED_ON0#define LED_OFF 1int main(void)int fd;int ret;int i;printf("my_led_driver test!n");fd = open(DEVICE_NAME, O_RDONLY);if(fd = -1)printf("open device %s error!n", DEVICE_NAME);for(i = 0; i < 50; i+)ioctl(fd, LED_OFF);sleep(1);ioctl(fd, LED_ON);sleep(1);ret = close(fd);printf("ret = %dn", ret);printf("close my_led_driver!n");return 0;将测试程序编译成目标平台的可执行文件,并下载到开发板GCC=/home/zzq/9G20/arm-2007q1/bin/arm-none-linux-gnueabi-gcc #交叉编译器的路径My_led_test:my_led_test.c $(GCC) -o my_led_test my_led_test.cclean: rm -f my_led_test学习总结:熟悉驱动程序的架构,如何将驱动程序添加到内核即如何写测试程序。二:按键驱动设计1.硬件部分:PC4接按键。2.驱动程序:#include <linux/module.h>#include <linux/cdev.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/interrupt.h>#include <linux/irq.h>#include <linux/sched.h>#include <linux/pm.h>#include <linux/sysctl.h>#include <linux/proc_fs.h>#include <linux/delay.h>#include <linux/input.h>#include <linux/gpio_keys.h>#include <asm/gpio.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/irq.h>#include <mach/gpio.h>#define BUTTON_MAJOR245#define DEVICE_NAME "/dev/button"static volatile int ev_press = 0;static struct cdev button_cdev;static void button_do_tasklet(unsigned long n);DECLARE_TASKLET(button_tasklet, button_do_tasklet, 0);/定义tasklet并与处理函数关联起来static DECLARE_WAIT_QUEUE_HEAD(button_waitq);/静态的初始化一个等待队列struct button_irq_desc int irq;int irq_type;int pin;int number;char *name;static struct button_irq_desc button_irq1 = AT91_PIN_PB22, AT91_AIC_SRCTYPE_LOW, AT91_PIN_PB22, 0, "KEY0" ;static int key_values1=0;/中断处理底半部static void button_do_tasklet(unsigned long n)wake_up_interruptible(&button_waitq);/唤醒队列printk("button press!n");/中断处理顶半部static irqreturn_t button_interrupt(int irq, void *dev_id, struct pt_regs *regs)int up; static int press_down;up = gpio_get_value(button_irq0.pin);printk("irqn");/*按键消抖*/if(up)press_down = 1;/当按键没有按下,置标志位为1.if(!up && (press_down = 1) press_down = 0; /当按键按下,置标志位为0.ev_press = 1;at91_set_gpio_value(button_irq0.pin, 1);key_valuesbutton_irq0.number = !up;tasklet_schedule(&button_tasklet);return IRQ_RETVAL(IRQ_HANDLED);static int button_open(struct inode *inode, struct file *filp)return 0;static int button_release(struct inode *inode, struct file *filp)return 0;static int button_read(struct file *filp, char _user *buff, size_t count, loff_t *offp)int ret;if(!ev_press) /当按键没有按下时,读进程挂起,知道按键按下。wait_event_interruptible(button_waitq, ev_press);ev_press = 0;ret = copy_to_user(buff, (const void *)key_values, min(sizeof(key_values), count);memset(void _user *)key_values, 0, sizeof(key_values);return ret ? -EFAULT:min(sizeof(key_values), count); static struct file_operations button_fops = .owner = THIS_MODULE,.open = button_open,.release = button_release,.read = button_read,;static int irq_init(void)int err;at91_set_gpio_input(button_irq0.pin, 1);at91_set_deglitch(button_irq0.pin, 1);/将PC0设置为中断功能set_irq_type(button_irq0.irq, button_irq0.irq_type);/设置中断类型at91_set_gpio_value(button_irq0.pin, 1);err = request_irq( button_irq0.irq, button_interrupt, IRQF_DISABLED, button_irq0.name, (void *)&button_irq0);/申请中断if ( err ) disable_irq(button_irq0.irq);free_irq(button_irq0.irq, (void *)&button_irq0);return -EBUSY;return 0;static int _init button_init(void)int ret, err;ret = register_chrdev_region(MKDEV(BUTTON_MAJOR, 0), 1, DEVICE_NAME);if(ret < 0) printk("button init failed with %dn", ret);return ret;cdev_init(&button_cdev, &button_fops);button_cdev.owner = THIS_MODULE;button_cdev.ops = &button_fops;err = cdev_add(&button_cdev, MKDEV(BUTTON_MAJOR, 0), 1);if( err<0 ) printk("key add failedn");return err;irq_init();printk("key driver add success!n");return 0;static void _exit button_exit(void)cdev_del(&button_cdev);unregister_chrdev_region(MKDEV(BUTTON_MAJOR, 0), 1);disable_irq(button_irq0.irq);free_irq(button_irq0.irq, (void *)&button_irq0);printk("unregister key driver!n");module_init(button_init);module_exit(button_exit);MODULE_AUTHOR("fany");MODULE_DESCRIPTION("Atmel9g20 key Driver");MODULE_LICENSE("GPL");3. 测试程序:#include <stdio.h>#include <string.h>#include <stdlib.h>#include <fcntl.h>#include <unistd.h>#include <errno.h>#define DEVICE_NAME "/dev/button"int main(void)int fd,i;int ret;int key_value1;printf("key test!n");fd = open(DEVICE_NAME, O_RDWR);if(fd < 0)printf("open device %s error!n", DEVICE_NAME);elseprintf("open device success!n");while(1) ret = read(fd, key_value, 1);if( !ret ) printf("button not press!n");elseprintf("button press!n");printf("key_value %dn", key_value);close(fd);printf("close key driver!n");return 0;4.学习总结:在linux设备驱动程序中,中断处理程序通常分为两部分:上半部和下半部。上半部处理比较紧急的的硬件操作,比如简单的读取寄存器中的状态并清除中断标志后,进行登记中断的工作。剩下的工作就由下半部来实现。对阻塞与非阻塞进程的理解,阻塞:在执行设备操作时,若不能获取设备资源则挂起,直到满足可操作的条件后再进行操作。非阻塞操作:在执行设备操作时,若不能获取设备资源则立即返回。三:总线驱动AT91SAM9G20存储器映射图(截取部分),片选4接外设,利用总线对外设进行访问。但是在linux驱动,不能对物理地址进行操作,可通过内存访问的机制实现对物理地址的访问。将一段物理地址空间映射到虚拟地址空间中,然后对虚拟地址的操作即是对物理地址的操作。3.1:总线驱动#include <linux/module.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/device.h>#include <linux/fs.h>#include <linux/platform_device.h>#include <linux/init.h>#include <linux/cdev.h>#include <asm/io.h>#include <asm/uaccess.h>#include <mach/gpio.h>#include <mach/at91sam9_smc.h>#include <mach/at91sam9260_matrix.h>#include <mach/at91sam9260.h>#include <mach/at91_pmc.h>#include "atmel9g20_liu.h"struct gr_liu_info void _iomem*virtbase;void _iomem*regbase;struct resource *res;u32flags;static struct gr_liu_info liu_info;static struct cdev atmel9g20_liu_cdev;unsigned short liu_read(unsigned addr)addr &= ATMEL9G20_LIU_MASK;addr = addr << 1;addr += (unsigned long)liu_info.regbase;printk("read the virtual addr is 0x%xn", addr);return readw(addr) & 0xff;/读IO内存。EXPORT_SYMBOL(liu_read);int liu_write(unsigned addr, unsigned val)addr &= ATMEL9G20_LIU_MASK;addr = addr << 1;addr += (unsigned long)liu_info.regbase;printk("write the virtual addr is 0x%xn", addr);writew(val&0xff, addr);/写IO内存return 0;EXPORT_SYMBOL(liu_write);static int atmel9g20_liu_open(struct inode *inode, struct file *filp)return 0;static int atmel9g20_liu_release(struct inode *inode, struct file *filp)return 0;static int atmel9g20_liu_ioctl(struct inode *inode, struct file *filp, unsigned cmd, unsigned long arg)int ret;liu_ctlf_t ctlf;switch (cmd) case LIU_IOCSET:ret = copy_from_user(&ctlf, (liu_ctlf_t _user *)arg, sizeof(liu_ctlf_t); if (ret)return ret; printk("input addr is 0x%x,input val is 0x%xn",ctlf.addr, ctlf.val);liu_write(ctlf.addr, ctlf.val);return ret;case LIU_IOCGET:ret = copy_from_user(&ctlf, (liu_ctlf_t _user *)arg, sizeof(liu_ctlf_t);if (ret) return ret;ctlf.val = liu_read(ctlf.addr);if (copy_to_user(void _user *)arg, &ctlf, sizeof(liu_ctlf_t)return -EFAULT;return ret;return -ENOTTY;static const struct file_operations atmel9g20_liu_fops = .owner= THIS_MODULE,.open=atmel9g20_liu_open,.ioctl=atmel9g20_liu_ioctl,.release=atmel9g20_liu_release,;static int _devinit liu_probe(struct platform_device *pdev)int ret = 0;if (pdev->num_resources != 1) ret = -ENODEV;goto err1;/IO内存的申请liu_info.res = request_mem_region(pdev->resource0.start, pdev->resource0.end - pdev->resource0.start + 1, "9g20-liu");if (!liu_info.res) printk("liu: can't get request mem region");ret = -ENOMEM;goto err1;/IO内存的映射liu_info.regbase = ioremap(pdev->resource0.start, pdev->resource0.end - pdev->resource0.start + 1);printk("request virtual addr liu_info.regbase=0x%xn",(unsigned int)liu_info.regbase);if (liu_info.regbase = NULL) printk("liu: can't get ioremap memn");ret = -ENOMEM;goto err2; dev_set_drvdata(&pdev->dev, &liu_info);printk("LIU probe done!n");return 0;err2:release_mem_region(pdev->resource0.start, pdev->resource0.end - pdev->resource0.start + 1);err1:return ret;static int liu_remove(struct platform_device *pdev)struct gr_liu_info *fi;fi = pdev->dev.driver_data;iounmap(fi->regbase);/解除映射,release_mem_region(pdev->resource0.start, pdev->resource0.end - pdev->resource0.start + 1);/释放内存fi->flags = 0x0;return 0;static struct platform_driver liu_driver = .probe = liu_probe,.remove = liu_remove,.driver = .name = "9g20-liu",.owner = THIS_MODULE,;/设置SMC寄存器static void cs4_init(void)at91_sys_write(AT91_MATRIX_EBICSA,at91_sys_read(AT91_MATRIX_EBICSA) | AT91_MATRIX_CS4A_SMC);/* Configure SMC CS4 */at91_sys_write(AT91_SMC_SETUP(4), AT91_SMC_NWESETUP_(2) | AT91_SMC_NCS_WRSETUP_(2) | AT91_SMC_NRDSETUP_(2) | AT91_SMC_NCS_RDSETUP_(2);at91_sys_write(AT91_SMC_PULSE(4), AT91_SMC_NWEPULSE_(12) | AT91_SMC_NCS_WRPULSE_(10) | AT91_SMC_NRDPULSE_(12) | AT91_SMC_NCS_RDPULSE_(10);at91_sys_write(AT91_SMC_CYCLE(4), AT91_SMC_NWECYCLE_(16) | AT91_SMC_NRDCYCLE_(16);at91_sys_write(AT91_SMC_MODE(4), AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_DBW_16 | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_TDF_(3);at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_PIOC);/* Enable CS4 */ at91_set_A_periph(AT91_PIN_PC8, 1); printk("*at91sam9g20ek_ebibus_cs4_init*n");static int _init atmel9g20_liu_init(void)int ret,err;ret = register_chrdev_region(MKDEV(LIU_MAJOR, 0), 1, "/dev/liu");if( ret < 0) printk("LIU init_module failed with %dn", ret);return ret;cdev_init(&atmel9g20_liu_cdev, &atmel9g20_liu_fops);atmel9g20_liu_cdev.owner = THIS_MODULE;atmel9g20_liu_cdev.ops = &atmel9g20_liu_fops;err = cdev_add(&atmel9g20_liu_cdev, MKDEV(LIU_MAJOR, 0), 1);if( err<0 ) printk("liu add failedn");return err;cs4_init();return platform_driver_register(&liu_driver);/注册平台设备。static void _exit atmel9g20_liu_cleanup(void)printk("atmel 9g20 liu exitn");cdev_del(&atmel9g20_liu_cdev);unregister_chrdev_region(MKDEV(LIU_MAJOR, 0), 1);platform_driver_unregister(&liu_driver);module_init(atmel9g20_liu_init);module_exit(atmel9g20_liu_cleanup);MODULE_AUTHOR("fany");MODULE_DESCRIPTION("Atmel9g20 liu Driver");MODULE_LICENSE("GPL");并在/arch/arm/mach-at91/board-sam9g20ek.c中初始化#define GR_LIU_BASE 0x#define GR_LIU_SIZE 0x1000static struct resource gr_liu_resource = .start= GR_LIU_BASE,.end= GR_LIU_BASE + GR_LIU_SIZE - 1,.flags= IORESOURCE_MEM,;static struct platform_device grd_liu = .name= "9g20-liu",.id= -1,.dev= .platform_data= NULL,.resource= gr_liu_resource,.num_resources= 1,;static void _init at91_add_device_liu(void) platform_device_register(&grd_liu); printk("*at91_add_device_liu*n");static void _init ek_board_init(void).at91_add_device_liu();3.2:总线驱动测试程序:#include <sys/types.h>#include <sys/fcntl.h>#include <sys/ioc

    注意事项

    本文(linux驱动程序设计实例.doc)为本站会员(飞****2)主动上传,淘文阁 - 分享文档赚钱的网站仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知淘文阁 - 分享文档赚钱的网站(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    关于淘文阁 - 版权申诉 - 用户使用规则 - 积分规则 - 联系我们

    本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

    工信部备案号:黑ICP备15003705号 © 2020-2023 www.taowenge.com 淘文阁 

    收起
    展开