(华清远见)linux设备驱动开发

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

  嵌入式培训专家LinuxLinux设备驱动开发设备驱动开发  华清远见今天的内容Linux设备驱动的现状从non­os驱动到Linux驱动内核设施自旋锁、信号量、互斥量、完成量异步通知、信号阻塞与非阻塞内存与I/O操作,DMA中断,top half/bottom half字符设备驱动复杂设备驱动的框架LCD设备FRAMEBUFFERFLASH设备MTDTTY设备块设备用户空间的设备驱动设备驱动开发流程开发环境建设调试手段用户空间测试设备驱动的学习方法  华清远见Linux设备驱动的现状高需求Linux内核的绝大多数代码为设备驱动新设备、新芯片、新驱动的需求高门槛涉及到大量硬件操作涉及到内核基础知识涉及到并发控制与同步复杂的软件结构框架高回报  华清远见从non­os驱动到Linux驱动non­os驱动单刀直入简单直接提供APILinux驱动兵团战役复杂间接提供API应用软件SerialSendSerialRecv设备驱动LightOnLightOffFlashWrFlashRd硬件串口LEDFLASH硬件操作系统API操作系统驱动中独立于设备的接口驱动中的硬件操作用户应用程序non­os驱动与应用on­os驱动与应用  华清远见并发和竞态并发和竞态:对称多处理器(SMP)的多个CPU单CPU内进程与抢占它的进程中断(硬中断、软中断、Tasklet、底半部)与进程之间处理思路:lock() //锁定,拿虎符. . .critical section //临界区,调动军队. . .unlock()  //解锁定,归还虎符常用方法:中断屏蔽原子操作自旋锁信号量互斥体  华清远见原子变量接口•整型原子操作•设置原子变量的值•void atomic_set(atomic_t *v, int i); //设置原子变量的值为i•atomic_t v = ATOMIC_INIT(0); //定义原子变量v并初始化为0•̅获取原子变量的值•atomic_read(atomic_t *v);  //返回原子变量的值•原子变量加/减•void atomic_add(int i, atomic_t *v); //原子变量增加i•void atomic_sub(int i, atomic_t *v); //原子变量减少i•ξ原子变量自增/自减•void atomic_inc(atomic_t *v);    //原子变量增加1•void atomic_dec(atomic_t *v);    //原子变量减少1•η操作并测试•int atomic_inc_and_test(atomic_t *v);•int atomic_dec_and_test(atomic_t *v);•int atomic_sub_and_test(int i, atomic_t *v);•⎝操作并返回•int atomic_add_return(int i, atomic_t *v);•int atomic_sub_return(int i, atomic_t *v);•int atomic_inc_return(atomic_t *v);•int atomic_dec_return(atomic_t *v);•位原子操作•⎝设置/清除/反转位•void set_bit(nr, void *addr);•void clear_bit(nr, void *addr);•void change_bit(nr, void *addr);•测试位•test_bit(nr, void *addr);•η测试并操作位•int test_and_set_bit(nr, void *addr);•int test_and_clear_bit(nr, void *addr);•int test_and_change_bit(nr, void *addr);  华清远见自旋锁VS 信号量自旋锁:忙等待,无调度开销进程抢占被禁止锁定期间不能睡觉•spinlock_t lock;•spin_lock_init(&lock);•spin_lock (&lock) ; //获取自旋锁,保护临界区•. . ./ /临界区•spin_unlock (&lock) ; //解锁信号量拿不到就切换进程,有调度开销锁定期间可以睡觉,不用于中断上下文•//定义信号量•DECLARE_MUTEX(mount_sem);•down(&mount_sem);//获取信号量,保护临界区•. . .•critical section //临界区•. . .•up(&mount_sem);//释放信号量  华清远见设备访问方式读写函数读写读写系统调用资源不可获得资源可获得阻塞阻塞I/O返回返回用户空间poll()或select()poll系统调用资源状态变更非阻塞轮询I/O返回xxx_func()唤醒读写yyy_func()中断唤醒资源可获得资源状态变更唤醒读写函数阻塞读写系统调用返回返回读写函数读写系统调用资源可获得signal信号处理函数(进行读写)异步通知系统调用内核空间中断signal  华清远见阻塞非阻塞等待队列:进程等待被唤醒的一种机制阻塞与非阻塞使用模板1  static ssize_t xxx_write(struct file *file, const char *buffer, size_t count,2    loff_t *ppos)3  {4    ...5    DECLARE_WAITQUEUE(wait, current); //定义等待队列6    add_wait_queue(&xxx_wait, &wait);  //添加等待队列7  8    ret = count;9    /* 等待设备缓冲区可写*/10   do11   {12     avail = device_writable(...);13     if (avail  0)14       __set_current_state(TASK_INTERRUPTIBLE);//改变进程状态15 16     if (avail  0)17     {18       if (file­f_flags &O_NONBLOCK)  //非阻塞19       {20         if (!ret)21           ret =  ­ EAGAIN;22         goto out;23       }24       schedule();   //调度其他进程执行25       if (signal_pending(current))//如果是因为信号唤醒26       {27         if (!ret)28           ret =  ­ ERESTARTSYS;29         goto out;30       }31     }32   }while (avail  0);33 34   /* 写设备缓冲区*/35   device_write(...)36   out:37   remove_wait_queue(&xxx_wait, &wait);//将等待队列移出等待队列头38   set_current_state(TASK_RUNNING);//设置进程状态为TASK_RUNNING39   return ret;40 }   华清远见polling驱动中POLL模板•1  static unsigned int xxx_poll(struct file *filp, poll_table *wait)•2  {•3    unsigned int mask = 0;•4    struct xxx_dev *dev = filp­private_data; /*获得设备结构体指针*/•6    ...  •8    poll_wait(filp, &dev­wait, wait);•9  •10   if (...)//可读•11   {•12     mask |= POLLIN | POLLRDNORM; /*标示数据可获得*/•13   }   •15   if (...)//可写•16   {•17     mask |= POLLOUT | POLLWRNORM; /*标示数据可写入*/•18   }•19      •20   ...•21   return mask;•22 }用户空间POLL模板•fd_set fds; •FD_ZERO(&fds);•FD_SET(fd, &fds);•select(fd + 1, &rfds, &wfds, NULL, NULL);•if (FD_ISSET(fd, &fds))•{•   printf(Poll monitor:can be access\n);•}  华清远见异步I/O信号:软件意义上的“中断”驱动发出信号•kill_fasync(&dev­async_queue, SIGIO, POLL_IN);用户空间应用程序处理信号•24   signal(SIGIO, input_handler);•25   fcntl(STDIN_FILENO, F_SETOWN, getpid());•26   oflags = fcntl(STDIN_FILENO, F_GETFL);•27   fcntl(STDIN_FILENO, F_SETFL, oflags | FASYNC);•8  void input_handler(int num)•9  { ...•14   len = read(STDIN_FILENO, &data, MAX_LEN);•15 ... }fcntl(fd, F_SETOWN, getpid())fcntl(fd, F_GETFL)信号处理函数信号signal()绑定内核设置filp­f_owner设备驱动fasync()函数资源可获得释放导致执行内核空间用户空间  华清远见中断两个半部调度上半部中断(紧急的硬件操作)下半部(延缓的耗时操作)机制tasklet工作队列•1  /*定义tasklet和底半部函数并关联*/•2  void xxx_do_tasklet(unsigned long);•3  DECLARE_TASKLET(xxx_tasklet, xxx_do_tasklet, 0);4  •5  /*中断处理底半部*/•6  void xxx_do_tasklet(unsigned long)•7  {...•9  }•11 /*中断处理顶半部*/•12 irqreturn_t xxx_interrupt(int irq, void *dev_id, struct pt_regs *regs)•13 {...•15 tasklet_schedule(&xxx_tasklet);•16 ...}  华清远见内存与I/O访问内存空间与I/O空间Linux内核地址空间0896M4G物理内存3G4GLinux内核空间物理内存映射区vmalloc分配器区高端内存映射区专用页面映射区保留区内存申请kmalloc,get_free_pages:物理连续,线性映射vmalloc:物理非连续,非线性映射物理/虚拟地址映射静态映射ioremap, ioremap_nocachemmap:映射到用户空间  华清远见DMAcache一致性问题cache对象DMA缓冲区DMA缓冲区一致性缓冲区•void * dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle,

1 / 34
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功