Chinaunix首页 | 论坛 | 博客
  • 博客访问: 168523
  • 博文数量: 109
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 147
  • 用 户 组: 普通用户
  • 注册时间: 2015-01-23 16:12
文章分类

全部博文(109)

文章存档

2015年(109)

我的朋友

分类: LINUX

2015-02-02 11:52:08

一.spidev.c文件

看一个设备驱动的方法:

module_init标识的入口初始化函数spidev_init,(module_exit标识的出口函数)

设备与设备驱动匹配时候调用的probe方法spidev_probe

设备驱动的操作函数集file_operations--->spidev_fops

@@open方法spidev_open
进行检查, 重点是以后三条语句,其他的见下面代码注释:

  1. spidev->users++; //spidev_data使用者计数++ 
  2. filp->private_data = spidev; //spidev_data放在文件的私有数据里 
  3. nonseekable_open(inode, filp);  //设置文件的打开模式(文件读写指针不会跟随读写操作移动)

 


@@read方法spidev_read
spidev = filp->private_data;=========>>status = spidev_sync_read(spidev, count);===========>>
spidev_sync(spidev, &m);==========>>status = spi_async(spidev->spi, message);===========>>
wait_for_completion(&done);========>>到了这一步是重点,在spi_async()方法中,使用以下语句将要做的事情加到workqueue中
list_add_tail(&m->queue, &bitbang->queue);
queue_work(bitbang->workqueue, &bitbang->work);
此后所有的处理程序便转移到在之前初始化的work方法中看以下代码:

点击(此处)折叠或打开

  1. static void bitbang_work(struct work_struct *work)
  2. {
  3.     struct spi_bitbang    *bitbang =
  4.         container_of(work, struct spi_bitbang, work);
  5.     unsigned long        flags;
  6.     int            do_setup = -1;
  7.     int            (*setup_transfer)(struct spi_device *,
  8.                     struct spi_transfer *);
  9.     setup_transfer = bitbang->setup_transfer;
  10.     spin_lock_irqsave(&bitbang->lock, flags);
  11.     bitbang->busy = 1;
  12.     while (!list_empty(&bitbang->queue)) {
  13.         struct spi_message    *m;
  14.         struct spi_device    *spi;
  15.         unsigned        nsecs;
  16.         struct spi_transfer    *t = NULL;
  17.         unsigned        tmp;
  18.         unsigned        cs_change;
  19.         int            status;
  20.         m = container_of(bitbang->queue.next, struct spi_message,
  21.                 queue);
  22.         list_del_init(&m->queue);
  23.         spin_unlock_irqrestore(&bitbang->lock, flags);
  24.         /* FIXME this is made-up ... the correct value is known to
  25.          * word-at-a-time bitbang code, and presumably chipselect()
  26.          * should enforce these requirements too?
  27.          */
  28.         nsecs = 100;
  29.         spi = m->spi;
  30.         tmp = 0;
  31.         cs_change = 1;
  32.         status = 0;
  33.         list_for_each_entry (t, &m->transfers, transfer_list) {
  34.             /* override speed or wordsize? */
  35.             if (t->speed_hz || t->bits_per_word)
  36.                 do_setup = 1;
  37.             /* init (-1) or override (1) transfer params */
  38.             if (do_setup != 0) {
  39.                 if (!setup_transfer) {
  40.                     status = -ENOPROTOOPT;
  41.                     break;
  42.                 }
  43.                 status = setup_transfer(spi, t);
  44.                 if (status < 0)
  45.                     break;
  46.             }
  47.             /* set up default clock polarity, and activate chip;
  48.              * this implicitly updates clock and spi modes as
  49.              * previously recorded for this device via setup().
  50.              * (and also deselects any other chip that might be
  51.              * selected ...)
  52.              */
  53.             if (cs_change) {
  54.                 bitbang->chipselect(spi, BITBANG_CS_ACTIVE);
  55.                 ndelay(nsecs);
  56.             }
  57.             cs_change = t->cs_change;
  58.             if (!t->tx_buf && !t->rx_buf && t->len) {
  59.                 status = -EINVAL;
  60.                 break;
  61.             }
  62.             /* transfer data. the lower level code handles any
  63.              * new dma mappings it needs. our caller always gave
  64.              * us dma-safe buffers.
  65.              */
  66.             if (t->len) {
  67.                 /* REVISIT dma API still needs a designated
  68.                  * DMA_ADDR_INVALID; ~0 might be better.
  69.                  */
  70.                 if (!m->is_dma_mapped)
  71.                     t->rx_dma = t->tx_dma = 0;
  72.                 status = bitbang->txrx_bufs(spi, t);
  73.             }
  74.             if (status > 0)
  75.                 m->actual_length += status;
  76.             if (status != t->len) {
  77.                 /* always report some kind of error */
  78.                 if (status >= 0)
  79.                     status = -EREMOTEIO;
  80.                 break;
  81.             }
  82.             status = 0;
  83.             /* protocol tweaks before next transfer */
  84.             if (t->delay_usecs)
  85.                 udelay(t->delay_usecs);
  86.             if (!cs_change)
  87.                 continue;
  88.             if (t->transfer_list.next == &m->transfers)
  89.                 break;
  90.             /* sometimes a short mid-message deselect of the chip
  91.              * may be needed to terminate a mode or command
  92.              */
  93.             ndelay(nsecs);
  94.             bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
  95.             ndelay(nsecs);
  96.         }
  97.         m->status = status;
  98.         m->complete(m->context);
  99.         /* restore speed and wordsize if it was overridden */
  100.         if (do_setup == 1)
  101.             setup_transfer(spi, NULL);
  102.         do_setup = 0;
  103.         /* normally deactivate chipselect ... unless no error and
  104.          * cs_change has hinted that the next message will probably
  105.          * be for this chip too.
  106.          */
  107.         if (!(status == 0 && cs_change)) {
  108.             ndelay(nsecs);
  109.             bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
  110.             ndelay(nsecs);
  111.         }
  112.         spin_lock_irqsave(&bitbang->lock, flags);
  113.     }
  114.     bitbang->busy = 0;
  115.     spin_unlock_irqrestore(&bitbang->lock, flags);
  116. }

结束处理所有任务后,见上面红色底纹部分解除wait_for_completion(&done);
最后missing = copy_to_user(buf, spidev->buffer, status);将数据发送到用户空间

@@write方法spidev_write
与上面open方式基本相同

@@ioctl方法spidev_ioctl
具体的详解见下面章节(三,四)

下面是spidev.c添加注释部分

 

 

  1. #include  
  2. #include  
  3. #include  
  4. #include  
  5. #include  
  6. #include  
  7. #include  
  8. #include  
  9. #include  
  10. #include  
  11. #include  
  12. #include  
  13. #include  
  14.  
  15. #define SPIDEV_MAJOR            153 //spidev主设备号 
  16. #define N_SPI_MINORS            32  /* ... up to 256 */ 
  17. static DECLARE_BITMAP(minors, N_SPI_MINORS);    //声明次设备位图 
  18. #define SPI_MODE_MASK (SPI_CPHA|SPI_CPOL|SPI_CS_HIGH|SPI_LSB_FIRST|SPI_3WIRE|SPI_LOOP|SPI_NO_CS|SPI_READY) 
  19.  
  20. struct spidev_data { 
  21.     dev_t   devt;               //设备号 
  22.     spinlock_t  spi_lock;       //自旋锁 
  23.     struct spi_device   *spi;   //spi设备结构体 
  24.     struct list_head    device_entry; 
  25.     struct mutex    buf_lock;   //互斥锁 
  26.     unsigned        users;      //使用者计数 
  27.     u8          *buffer;        //缓冲区 
  28. }; 
  29.  
  30. static LIST_HEAD(device_list);  //声明spi设备链表 
  31. static DEFINE_MUTEX(device_list_lock);  //定义互斥锁 
  32. static unsigned bufsiz = 4096;  //最大传输缓冲区大小 
  33. module_param(bufsiz, uint, S_IRUGO); 
  34. MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message"); 
  35.  
  36. static void spidev_complete(void *arg) 
  37.     complete(arg);  //调用complete 
  38.  
  39. static ssize_t spidev_sync(struct spidev_data *spidev, struct spi_message *message) 
  40.     DECLARE_COMPLETION_ONSTACK(done); 
  41.     int status; 
  42.  
  43.     message->complete = spidev_complete; //设置spi消息的complete方法 回调函数 
  44.     message->context = &done; 
  45.  
  46.     spin_lock_irq(&spidev->spi_lock); 
  47.     if (spidev->spi == NULL) //判断是否有指定对应的spi设备 
  48.         status = -ESHUTDOWN; 
  49.     else 
  50.         status = spi_async(spidev->spi, message);    //spi异步同步 
  51.     spin_unlock_irq(&spidev->spi_lock); 
  52.  
  53.     if (status == 0) { 
  54.         wait_for_completion(&done); //等待传输完成 
  55.         status = message->status;    //获取spi消息传输事务状态 
  56.         if (status == 0) 
  57.             status = message->actual_length; //status等于传输的实际长度 
  58.     } 
  59.     return status;  //返回实际传输长度 
  60.  
  61. static inline ssize_t spidev_sync_write(struct spidev_data *spidev, size_t len) 
  62.     struct spi_transfer t = { 
  63.             .tx_buf     = spidev->buffer,    //发送缓冲区 
  64.             .len        = len,  //发送数据长度 
  65.         }; 
  66.     struct spi_message  m; 
  67.  
  68.     spi_message_init(&m);   //初始化spi消息(初始化spi传递事务队列) 
  69.     spi_message_add_tail(&t, &m);   //添加spr传递到该队列 
  70.     return spidev_sync(spidev, &m); //同步读写 
  71.  
  72. static inline ssize_t spidev_sync_read(struct spidev_data *spidev, size_t len) 
  73.     struct spi_transfer t = { 
  74.             .rx_buf     = spidev->buffer,    //接收缓冲区 
  75.             .len        = len,  //接收数据长度 
  76.         }; 
  77.     struct spi_message  m; 
  78.  
  79.     spi_message_init(&m);   //初始化spi消息(初始化spi传递事务队列) 
  80.     spi_message_add_tail(&t, &m);   //添加spr传递到该队列 
  81.     return spidev_sync(spidev, &m); //同步读写 
  82.  
  83. static ssize_t spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) 
  84.     struct spidev_data  *spidev; 
  85.     ssize_t status = 0; 
  86.  
  87.     if (count > bufsiz)  //传输数据大于缓冲区容量 
  88.         return -EMSGSIZE; 
  89.     spidev = filp->private_data; //从文件私有数据指针获取spidev_data 
  90.     mutex_lock(&spidev->buf_lock);   //上互斥锁 
  91.     status = spidev_sync_read(spidev, count);   //同步读,返回传输数据长度 
  92.     if (status > 0) { 
  93.         unsigned long   missing;    //丢失的数据个数 
  94.         missing = copy_to_user(buf, spidev->buffer, status); //内核空间复制到用户空间 
  95.         if (missing == status)      //丢失的数据个数等于要传输的数据个数 
阅读(1345) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~