基于S3C2440的嵌入式Linux驱动——SPI子系统解读(四)

来源:互联网 发布:cocos2d js入门教程 编辑:程序博客网 时间:2024/06/11 18:48
本系列文章对Linux设备模型中的SPI子系统进行讲解。SPI子系统的讲解将分为4个部分。

   第一部分,将对SPI子系统整体进行描述,同时给出SPI的相关数据结构,最后描述SPI总线的注册。基于S3C2440的嵌入式Linux驱动——SPI子系统解读(一)

   第二部分,该文将对SPI的主控制器(master)驱动进行描述。          基于S3C2440的嵌入式Linux驱动——SPI子系统解读(二)

   第三部分,该文将对SPI设备驱动,也称protocol 驱动,进行讲解。基于S3C2440的嵌入式Linux驱动——SPI子系统解读(三)

   第四部分,即本篇文章,通过SPI设备驱动留给用户层的API,我们将从上到下描述数据是如何通过SPI的protocol 驱动,由bitbang 中转,最后由master驱动将

                    数据传输出去。

本文属于第部分。

7. write,read和ioctl综述

      在spi设备驱动层提供了两种数据传输方式。一种是半双工方式,write方法提供了半双工读访问,read方法提供了半双工写访问。另一种就是全双工方式,ioctl调用将同时完成数据的传送与发送。

     在后面的描述中,我们将对write和ioctl方法做出详细的描述,而read方法和write极其相似,将不多做介绍。

     接下来首先看看write方法是如何实现的。

8. write方法

8.1 spidev_write

 在用户空间执行open打开设备文件以后,就可以执行write系统调用,该系统调用将会执行我们提供的write方法。代码如下:

 下列代码位于drivers/spi/spidev.c中。    

[cpp] view plaincopyprint?
  1. /* Write-only message with current device setup */  
  2. static ssize_t  
  3. spidev_write(struct file *filp, const char __user *buf,  
  4.         size_t count, loff_t *f_pos)  
  5. {  
  6.     struct spidev_data  *spidev;  
  7.     ssize_t         status = 0;  
  8.     unsigned long       missing;  
  9.   
  10.     /* chipselect only toggles at start or end of operation */  
  11.     if (count > bufsiz)  /*数据大于4096字节*/  
  12.         return -EMSGSIZE;  
  13.   
  14.     spidev = filp->private_data;  
  15.   
  16.     mutex_lock(&spidev->buf_lock);  
  17.     /*将用户层的数据拷贝至buffer中,buffer在open方法中分配*/  
  18.     missing = copy_from_user(spidev->buffer, buf, count);   
  19.     if (missing == 0) {  
  20.         status = spidev_sync_write(spidev, count);  
  21.     } else  
  22.         status = -EFAULT;  
  23.     mutex_unlock(&spidev->buf_lock);  
  24.   
  25.     return status;  
  26. }  
在这里,做的事情很少,主要就是从用户空间将需要发送的数据复制过来。然后调用spidev_sync_write。

8.2 spidev_sync_write

下列代码位于drivers/spi/spidev.c中。 

[cpp] view plaincopyprint?
  1. static inline ssize_t  
  2. spidev_sync_write(struct spidev_data *spidev, size_t len)  
  3. {  
  4.     struct spi_transfer t = {  
  5.             .tx_buf     = spidev->buffer,  
  6.             .len        = len,  
  7.         };  
  8.     struct spi_message  m;  
  9.   
  10.     spi_message_init(&m);  
  11.     spi_message_add_tail(&t, &m);  
  12.     return spidev_sync(spidev, &m);  
  13. }  
  14.   
  15. static inline void spi_message_init(struct spi_message *m)  
  16. {  
  17.     memset(m, 0, sizeof *m);  
  18.     INIT_LIST_HEAD(&m->transfers);    /*初始化链表头*/  
  19. }  
  20.   
  21. spi_message_add_tail(struct spi_transfer *t, struct spi_message *m)  
  22. {  
  23.     list_add_tail(&t->transfer_list, &m->transfers);/*添加transfer_list*/  
  24. }  
在这里,创建了transfer和message。spi_transfer包含了要发送数据的信息。然后初始化了message中的transfer链表头,并将spi_transfer添加到了transfer链表中。也就是以spi_message的transfers为链表头的链表中,包含了transfer,而transfer正好包含了需要发送的数据。由此可见message其实是对transfer的封装。
最后,调用了spidev_sync,并将创建的spi_message作为参数传入。

8.3  spidev_sync

下列代码位于drivers/spi/spidev.c中。 

[cpp] view plaincopyprint?
  1. static ssize_t  
  2. spidev_sync(struct spidev_data *spidev, struct spi_message *message)  
  3. {  
  4.     DECLARE_COMPLETION_ONSTACK(done);   /*创建completion*/  
  5.     int status;  
  6.   
  7.     message->complete = spidev_complete;/*定义complete方法*/  
  8.     message->context = &done;            /*complete方法的参数*/  
  9.   
  10.     spin_lock_irq(&spidev->spi_lock);  
  11.     if (spidev->spi == NULL)  
  12.         status = -ESHUTDOWN;  
  13.     else  
  14.         status = spi_async(spidev->spi, message);/*异步,用complete来完成同步*/  
  15.     spin_unlock_irq(&spidev->spi_lock);  
  16.   
  17.     if (status == 0) {  
  18.         wait_for_completion(&done); /*在bitbang_work中调用complete方法来唤醒*/  
  19.         status = message->status;  
  20.         if (status == 0)  
  21.             status = message->actual_length; /*返回发送的字节数*/  
  22.     }  
  23.     return status;  
  24. }  
在这里,初始化了completion,这个东东将实现write系统调用的同步。在后面我们将会看到如何实现的。

随后调用了spi_async,从名字上可以看出该函数是异步的,也就是说该函数返回后,数据并没有被发送出去。因此使用了wait_for_completion来等待数据的发送完成,达到同步的目的。

8.4 spi_async

下列代码位于drivers/spi/spi.h中。 

[cpp] view plaincopyprint?
  1. /** 
  2.  * spi_async - asynchronous SPI transfer 
  3.  * @spi: device with which data will be exchanged 
  4.  * @message: describes the data transfers, including completion callback 
  5.  * Context: any (irqs may be blocked, etc) 
  6.  * 
  7.  * This call may be used in_irq and other contexts which can't sleep, 
  8.  * as well as from task contexts which can sleep. 
  9.  * 
  10.  * The completion callback is invoked in a context which can't sleep. 
  11.  * Before that invocation, the value of message->status is undefined. 
  12.  * When the callback is issued, message->status holds either zero (to 
  13.  * indicate complete success) or a negative error code.  After that 
  14.  * callback returns, the driver which issued the transfer request may 
  15.  * deallocate the associated memory; it's no longer in use by any SPI 
  16.  * core or controller driver code. 
  17.  * 
  18.  * Note that although all messages to a spi_device are handled in 
  19.  * FIFO order, messages may go to different devices in other orders. 
  20.  * Some device might be higher priority, or have various "hard" access 
  21.  * time requirements, for example. 
  22.  * 
  23.  * On detection of any fault during the transfer, processing of 
  24.  * the entire message is aborted, and the device is deselected. 
  25.  * Until returning from the associated message completion callback, 
  26.  * no other spi_message queued to that device will be processed. 
  27.  * (This rule applies equally to all the synchronous transfer calls, 
  28.  * which are wrappers around this core asynchronous primitive.) 
  29.  */  
  30. static inline int  
  31. spi_async(struct spi_device *spi, struct spi_message *message)  
  32. {  
  33.     message->spi = spi;       /*指出执行transfer的SPI接口*/  
  34.     return spi->master->transfer(spi, message);    /*即调用spi_bitbang_transfer*/  
  35. }  
这个函数仅仅保存了spi_device信息后,然后调用了master的transfer方法,该方法在spi_bitbang_start中定义为spi_bitbang_transfer。

8.5 spi_bitbang_transfer

下列代码位于drivers/spi/spi_bitbang.c中。 

[cpp] view plaincopyprint?
  1. /** 
  2.  * spi_bitbang_transfer - default submit to transfer queue 
  3.  */  
  4. int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m)  
  5. {  
  6.     struct spi_bitbang  *bitbang;  
  7.     unsigned long       flags;  
  8.     int         status = 0;  
  9.   
  10.     m->actual_length = 0;  
  11.     m->status = -EINPROGRESS;  
  12.   
  13.     bitbang = spi_master_get_devdata(spi->master);  
  14.   
  15.     spin_lock_irqsave(&bitbang->lock, flags);  
  16.     if (!spi->max_speed_hz)  
  17.         status = -ENETDOWN;  
  18.     else {  
  19.         /*下面的工作队列和queue在spi_bitbang_start函数中初始化*/  
  20.         list_add_tail(&m->queue, &bitbang->queue);    /*将message添加到bitbang的queue链表中*/  
  21.         queue_work(bitbang->workqueue, &bitbang->work);    /*提交工作到工作队列*/  
  22.     }  
  23.     spin_unlock_irqrestore(&bitbang->lock, flags);  
  24.   
  25.     return status;  
  26. }  

这里将message添加到了bitbang的queue链表中。然后提交了一个工作到工作队列,随后函数返回到spi_async,又返回到spidev_sync中。为方便将spidev_sync的部分代码列出:

[cpp] view plaincopyprint?
  1. status = spi_async(spidev->spi, message);/*异步,用complete来完成同步*/  
  2.     spin_unlock_irq(&spidev->spi_lock);  
  3.   
  4.     if (status == 0) {  
  5.         wait_for_completion(&done); /*在bitbang_work中调用complete方法来唤醒*/  
  6.         status = message->status;  
  7.         if (status == 0)  
  8.             status = message->actual_length; /*返回发送的字节数*/  
  9.     }  
  10.     return status;  
 当spi_async函数返回后,需要发送的数据已经通过工作的形式添加到了工作队列,在稍后的工作执行时,将完成数据的发送。随后调用了wait_for_completion等待数据的发送完成。到此,可以看出completion的使用是用来完成同步I/O的

8.6 bitbang_work

  在上一节最后添加了工作bitbang->work到工作队列中,在过一段时候后,内核将以进程执行该work。而work即为在spi_bitbang_start中定义的bitbang_work函数。我们来看下这个函数。

  下列代码位于drivers/spi/spi_bitbang.c中。 

[cpp] view plaincopyprint?
  1. /* 
  2.  * SECOND PART ... simple transfer queue runner. 
  3.  * 
  4.  * This costs a task context per controller, running the queue by 
  5.  * performing each transfer in sequence.  Smarter hardware can queue 
  6.  * several DMA transfers at once, and process several controller queues 
  7.  * in parallel; this driver doesn't match such hardware very well. 
  8.  * 
  9.  * Drivers can provide word-at-a-time i/o primitives, or provide 
  10.  * transfer-at-a-time ones to leverage dma or fifo hardware. 
  11.  */  
  12. static void bitbang_work(struct work_struct *work)  
  13. {  
  14.     struct spi_bitbang    *bitbang =  
  15.         container_of(work, struct spi_bitbang, work);    /*获取spi_bitbang*/  
  16.     unsigned long        flags;  
  17.   
  18.     spin_lock_irqsave(&bitbang->lock, flags);    /*自旋锁加锁*/  
  19.     bitbang->busy = 1;        /*bitbang忙碌*/  
  20.     while (!list_empty(&bitbang->queue)) {    /*有spi_message*/  
  21.         struct spi_message    *m;  
  22.         struct spi_device    *spi;  
  23.         unsigned        nsecs;  
  24.         struct spi_transfer    *t = NULL;  
  25.         unsigned        tmp;  
  26.         unsigned        cs_change;  
  27.         int            status;  
  28.         int            (*setup_transfer)(struct spi_device *,  
  29.                         struct spi_transfer *);  
  30.   
  31.         m = container_of(bitbang->queue.next, struct spi_message,/*获取spi_message*/  
  32.                 queue);          
  33.         list_del_init(&m->queue);        /*以获取spi_message,删除该spi_message*/  
  34.         spin_unlock_irqrestore(&bitbang->lock, flags);/*释放自旋锁*/  
  35.   
  36.         /* FIXME this is made-up ... the correct value is known to 
  37.          * word-at-a-time bitbang code, and presumably chipselect() 
  38.          * should enforce these requirements too? 
  39.          */  
  40.         nsecs = 100;  
  41.   
  42.         spi = m->spi;  
  43.         tmp = 0;  
  44.         cs_change = 1;  
  45.         status = 0;  
  46.         setup_transfer = NULL;  
  47.   
  48.         /*遍历,获取所有的spi_transfer*/  
  49.         list_for_each_entry (t, &m->transfers, transfer_list) {      
  50.   
  51.             /* override or restore speed and wordsize */  
  52.             if (t->speed_hz || t->bits_per_word) { /*如果这两个参数有任何一个已经设置了,本例中没有定义*/  
  53.                 setup_transfer = bitbang->setup_transfer;  
  54.                 if (!setup_transfer) {  
  55.                     status = -ENOPROTOOPT;  
  56.                     break;  
  57.                 }  
  58.             }  
  59.             if (setup_transfer) {        /*本例中为NULL*/  
  60.                 status = setup_transfer(spi, t);  
  61.                 if (status < 0)  
  62.                     break;  
  63.             }  
  64.   
  65.             /* set up default clock polarity, and activate chip; 
  66.              * this implicitly updates clock and spi modes as 
  67.              * previously recorded for this device via setup(). 
  68.              * (and also deselects any other chip that might be 
  69.              * selected ...) 
  70.              */  
  71.             if (cs_change) {                                /*初值为1*/  
  72.                 bitbang->chipselect(spi, BITBANG_CS_ACTIVE);/*即调用s3c24xx_spi_chipsel,激活CS信号,写寄存器,设置SPI模式*/  
  73.                 ndelay(nsecs);                                /*延迟100纳秒*/  
  74.             }  
  75.             cs_change = t->cs_change;                        /*保存cs_change*/                  
  76.             if (!t->tx_buf && !t->rx_buf && t->len) {        /*检查参数*/  
  77.                 status = -EINVAL;  
  78.                 break;  
  79.             }  
  80.   
  81.             /* transfer data.  the lower level code handles any 
  82.              * new dma mappings it needs. our caller always gave 
  83.              * us dma-safe buffers. 
  84.              */  
  85.             if (t->len) {  
  86.                 /* REVISIT dma API still needs a designated 
  87.                  * DMA_ADDR_INVALID; ~0 might be better. 
  88.                  */  
  89.                 if (!m->is_dma_mapped)  
  90.                     t->rx_dma = t->tx_dma = 0;            /*不使用DMA*/  
  91.                 status = bitbang->txrx_bufs(spi, t);    /*即调用s3c24xx_spi_txrx,开始发送数据,status为已发送数据的大小*/  
  92.             }  
  93.             if (status > 0)  
  94.                 m->actual_length += status;    /*保存已发送字节*/  
  95.             if (status != t->len) {    /*要求发送和已发送的大小不同*/  
  96.                 /* always report some kind of error */  
  97.                 if (status >= 0)  
  98.                     status = -EREMOTEIO;  
  99.                 break;  
  100.             }  
  101.             status = 0;  
  102.   
  103.             /* protocol tweaks before next transfer */  
  104.             if (t->delay_usecs)  
  105.                 udelay(t->delay_usecs);    /*延迟*/  
  106.   
  107.             if (!cs_change)/*判断是否需要禁止CS,为1表示要求在两次数据传输之间禁止CS*/  
  108.                 continue;  
  109.             if (t->transfer_list.next == &m->transfers)    /*没有transfer*/  
  110.                 break;  
  111.   
  112.             /* sometimes a short mid-message deselect of the chip 
  113.              * may be needed to terminate a mode or command 
  114.              */  
  115.             ndelay(nsecs);    /*延迟*/  
  116.             bitbang->chipselect(spi, BITBANG_CS_INACTIVE);    /*禁止CS*/  
  117.             ndelay(nsecs);  
  118.         }    /*遍历spi_transfer结束*/  
  119.   
  120.         m->status = status;  
  121.         m->complete(m->context); /*调用complete,一个message处理完毕*/  
  122.   
  123.         /* restore speed and wordsize */  
  124.         if (setup_transfer)  
  125.             setup_transfer(spi, NULL);  
  126.   
  127.         /* normally deactivate chipselect ... unless no error and 
  128.          * cs_change has hinted that the next message will probably 
  129.          * be for this chip too. 
  130.          */  
  131.         if (!(status == 0 && cs_change)) {  
  132.             ndelay(nsecs);  
  133.             bitbang->chipselect(spi, BITBANG_CS_INACTIVE);    /*禁止CS*/  
  134.             ndelay(nsecs);  
  135.         }  
  136.   
  137.         spin_lock_irqsave(&bitbang->lock, flags);  
  138.     }  
  139.     bitbang->busy = 0;      
  140.     spin_unlock_irqrestore(&bitbang->lock, flags);  
  141. }  
本函数中,调用了两个方法bibang->chipselect和bitbang->txrx_bufs,这两个方法实际调用了s3c24xx_spi_chipsel和s3c24xx_spi_txrx函数,这两个函数都是master驱动层提供的函数。s3c24xx_spi_chipsel已经在4.2.2节中给出,该函数设置控制寄存器并激活CS信号。s3c24xx_spi_txrx函数的实参t,即为spi_transfer,函数完成该spi_transfer中数据的发送,并返回已发送的字节数。然后,判断是否需要禁止CS。接着遍历到下一个spi_transfer,再次发送数据。当所有spi_transfer发送完成以后,将调用complete方法,从而让在spidev_sync函数中等待completion的函数返回。下面,先来来看下数据是怎么发送出去的,也就是s3c24xx_spi_txrx函数。最后,看看complete方法。

8.7 s3c24xx_spi_txrx 和s3c24xx_spi_irq

下列代码位于deivers/spi/s3c24xx.c。

[cpp] view plaincopyprint?
  1. static inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count)  
  2. {  
  3.     return hw->tx ? hw->tx[count] : 0;    /*发送缓冲区指针是否为空,空则发送0*/  
  4. }  
  5.   
  6. static int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t)/*bitbang.txrx_bufs方法*/  
  7. {  
  8.     struct s3c24xx_spi *hw = to_hw(spi);  
  9.   
  10.     dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",  
  11.         t->tx_buf, t->rx_buf, t->len);  
  12.     /*保存transfer相关数据到s3c24xx_sp结构中*/  
  13.     hw->tx = t->tx_buf;  
  14.     hw->rx = t->rx_buf;  
  15.     hw->len = t->len;  
  16.     hw->count = 0;  
  17.   
  18.     init_completion(&hw->done);    /*初始化completion*/  
  19.   
  20.     /* send the first byte */    /*发送第一个数据,tx[0]*/  
  21.     writeb(hw_txbyte(hw, 0), hw->regs + S3C2410_SPTDAT);  
  22.   
  23.     wait_for_completion(&hw->done);/*等待completion*/  
  24.   
  25.     return hw->count;  /*返回发送的字节数*/  
  26. }  
  27.   
  28. static irqreturn_t s3c24xx_spi_irq(int irq, void *dev)  
  29. {  
  30.     struct s3c24xx_spi *hw = dev;  
  31.     unsigned int spsta = readb(hw->regs + S3C2410_SPSTA);/*获取状态寄存器*/  
  32.     unsigned int count = hw->count;  
  33.   
  34.     if (spsta & S3C2410_SPSTA_DCOL) {    /*发生错误*/  
  35.         dev_dbg(hw->dev, "data-collision\n");  
  36.         complete(&hw->done);    /*唤醒等待complete的进程*/  
  37.         goto irq_done;  
  38.     }  
  39.   
  40.     if (!(spsta & S3C2410_SPSTA_READY)) {/*未就绪*/  
  41.         dev_dbg(hw->dev, "spi not ready for tx?\n");  
  42.         complete(&hw->done);    /*唤醒等待complete的进程*/  
  43.         goto irq_done;  
  44.     }  
  45.   
  46.     hw->count++;/*增加计数*/  
  47.   
  48.     if (hw->rx)  
  49.         hw->rx[count] = readb(hw->regs + S3C2410_SPRDAT);/*读取数据*/  
  50.   
  51.     count++;    /*增加计数*/  
  52.   
  53.     if (count < hw->len)         /*未发送完毕,则继续发送*/  
  54.         writeb(hw_txbyte(hw, count), hw->regs + S3C2410_SPTDAT);  
  55.     else  
  56.         complete(&hw->done);    /*发送完毕,唤醒等待complete的进程*/  
  57.   
  58.  irq_done:  
  59.     return IRQ_HANDLED;  
  60. }   
在s3c24xx_spi_txrx函数中,首先发送了待发送数据中的第一个字节,随后就调用wait_for_completion来等待剩余的数据发送完成。

NOTE:这里的completion是master驱动层的,spi设备驱动也有一个completion,用于IO同步,不要混淆。

当第一个数据发送完成以后,SPI中断产生,开始执行中断服务程序。在中断服务程序中,将判断是否需要读取数据,如果是则从寄存器中读取数据。

NOTE:如果是使用read系统调用,那么在此发送的数据将是0。

随后发送下一个数据,直到数据发送完成。发送完成后调用complete,使在s3c24xx_spi_txrx的wait_for_completion得以返回。接着,s3c24xx_spi_txrx就将返回已发送的字节数。

NOTE:其实该中断服务子程序实现了全双工数据的传输,只不过特定于具体的系统调用,从而分为了半双工读和写。

8.8 complete方法

在8.6节的bitbang_work中,当一个message的所有数据发送完成以后,将会调用complete函数。该函数如下:

[cpp] view plaincopyprint?
  1. /* 
  2.  * We can't use the standard synchronous wrappers for file I/O; we 
  3.  * need to protect against async removal of the underlying spi_device. 
  4.  */  
  5. static void spidev_complete(void *arg)  
  6. {  
  7.     complete(arg);  
  8. }  
该函数将使在spidev_sync函数中的wait_for_completion得以返回,从而完成了同步IO。

至此,整个write系统调用的流程均以讲解完毕,在这其中也对在master和protocol中未曾给出的函数做出了一一讲解,最后,对第8章进行小结。

8.9 小结


   从示意图中,我们可以很清除看到函数的调用过程:先调用spi设备驱动层,随后调用bitbang中间层,最后调用了master驱动层来完成数据的传输。

9. read方法

read方法和write方法基本差不多,关键的区别在于其发送的数据为0,而在s3c24xx_spi_txrx中断服务程序中将读取数据寄存器。下面仅仅给出函数调用示意图。



在这里给出spidev_read和spidev_sync_read,方便读者进行对比。

[cpp] view plaincopyprint?
  1. /* Read-only message with current device setup */  
  2. static ssize_t  
  3. spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)  
  4. {  
  5.     struct spidev_data  *spidev;  
  6.     ssize_t         status = 0;  
  7.   
  8.     /* chipselect only toggles at start or end of operation */  
  9.     if (count > bufsiz)  /*如果读取的字节数大于缓冲区的大小,则报错*/  
  10.         return -EMSGSIZE;  
  11.   
  12.     spidev = filp->private_data; /*获取spidev*/  
  13.   
  14.     mutex_lock(&spidev->buf_lock);   /*加锁,对buffer进行互斥房屋内*/  
  15.     status = spidev_sync_read(spidev, count);  
  16.     if (status > 0) {  
  17.         unsigned long   missing;  
  18.   
  19.         missing = copy_to_user(buf, spidev->buffer, status);  
  20.         if (missing == status)  
  21.             status = -EFAULT;  
  22.         else  
  23.             status = status - missing;  
  24.     }  
  25.     mutex_unlock(&spidev->buf_lock);  
  26.   
  27.     return status;  
  28. }  
  29.   
  30. static inline ssize_t  
  31. spidev_sync_read(struct spidev_data *spidev, size_t len)  
  32. {  
  33.     struct spi_transfer    t = {  
  34.             .rx_buf        = spidev->buffer,  
  35.             .len        = len,  
  36.         };  
  37.     struct spi_message    m;  
  38.   
  39.     spi_message_init(&m);    /*初始化message*/  
  40.     spi_message_add_tail(&t, &m);    /*添加transfer*/  
  41.     return spidev_sync(spidev, &m);  
  42. }  

10. ioctl方法
   这一章节中,我们将看一下SPI子系统是如何使用ioctl系统调用来实现全双工读写。

10.1 spi_ioc_transfer

   在使用ioctl时,用户空间要使用一个数据结构来封装需要传输的数据,该结构为spi_ioc_transfe。而在write系统调用时,只是简单的从用户空间复制数据过来。该结构中的很多字段将被复制到spi_transfer结构中相应的字段。也就是说一个spi_ioc_transfer表示一个spi_transfer,用户空间可以定义多个spi_ioc_transfe,最后以数组形式传递给ioctl。

   下面同时给出ioctl中cmd的值。其中SPI_IOC_MASSAGE用于实现全双工IO,而其他的用于设置或者读取某个特定值。

   下列数据结构位于:include/linux/spi/spidev.h。

[cpp] view plaincopyprint?
  1. /** 
  2.  * struct spi_ioc_transfer - describes a single SPI transfer 
  3.  * @tx_buf: Holds pointer to userspace buffer with transmit data, or null. 
  4.  *  If no data is provided, zeroes are shifted out. 
  5.  * @rx_buf: Holds pointer to userspace buffer for receive data, or null. 
  6.  * @len: Length of tx and rx buffers, in bytes. 
  7.  * @speed_hz: Temporary override of the device's bitrate. 
  8.  * @bits_per_word: Temporary override of the device's wordsize. 
  9.  * @delay_usecs: If nonzero, how long to delay after the last bit transfer 
  10.  *  before optionally deselecting the device before the next transfer. 
  11.  * @cs_change: True to deselect device before starting the next transfer. 
  12.  * 
  13.  * This structure is mapped directly to the kernel spi_transfer structure; 
  14.  * the fields have the same meanings, except of course that the pointers 
  15.  * are in a different address space (and may be of different sizes in some 
  16.  * cases, such as 32-bit i386 userspace over a 64-bit x86_64 kernel). 
  17.  * Zero-initialize the structure, including currently unused fields, to 
  18.  * accomodate potential future updates. 
  19.  * 
  20.  * SPI_IOC_MESSAGE gives userspace the equivalent of kernel spi_sync(). 
  21.  * Pass it an array of related transfers, they'll execute together. 
  22.  * Each transfer may be half duplex (either direction) or full duplex. 
  23.  * 
  24.  *  struct spi_ioc_transfer mesg[4]; 
  25.  *  ... 
  26.  *  status = ioctl(fd, SPI_IOC_MESSAGE(4), mesg); 
  27.  * 
  28.  * So for example one transfer might send a nine bit command (right aligned 
  29.  * in a 16-bit word), the next could read a block of 8-bit data before 
  30.  * terminating that command by temporarily deselecting the chip; the next 
  31.  * could send a different nine bit command (re-selecting the chip), and the 
  32.  * last transfer might write some register values. 
  33.  */  
  34. struct spi_ioc_transfer {  
  35.     __u64       tx_buf;  
  36.     __u64       rx_buf;  
  37.   
  38.     __u32       len;  
  39.     __u32       speed_hz;  
  40.   
  41.     __u16       delay_usecs;  
  42.     __u8        bits_per_word;  
  43.     __u8        cs_change;  
  44.     __u32       pad;  
  45.   
  46.     /* If the contents of 'struct spi_ioc_transfer' ever change 
  47.      * incompatibly, then the ioctl number (currently 0) must change; 
  48.      * ioctls with constant size fields get a bit more in the way of 
  49.      * error checking than ones (like this) where that field varies. 
  50.      * 
  51.      * NOTE: struct layout is the same in 64bit and 32bit userspace. 
  52.      */  
  53. };  
  54.   
  55. /* not all platforms use <asm-generic/ioctl.h> or _IOC_TYPECHECK() ... */  
  56. #define SPI_MSGSIZE(N) \                /*SPI_MSGSIZE不能大于4KB*/  
  57.     ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \  
  58.         ? ((N)*(sizeof (struct spi_ioc_transfer))) : 0)  
  59. #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])  
  60.   
  61.   
  62. /* Read / Write of SPI mode (SPI_MODE_0..SPI_MODE_3) */  
  63. #define SPI_IOC_RD_MODE            _IOR(SPI_IOC_MAGIC, 1, __u8)  
  64. #define SPI_IOC_WR_MODE            _IOW(SPI_IOC_MAGIC, 1, __u8)  
  65.   
  66. /* Read / Write SPI bit justification */  
  67. #define SPI_IOC_RD_LSB_FIRST        _IOR(SPI_IOC_MAGIC, 2, __u8)  
  68. #define SPI_IOC_WR_LSB_FIRST        _IOW(SPI_IOC_MAGIC, 2, __u8)  
  69.   
  70. /* Read / Write SPI device word length (1..N) */  
  71. #define SPI_IOC_RD_BITS_PER_WORD    _IOR(SPI_IOC_MAGIC, 3, __u8)  
  72. #define SPI_IOC_WR_BITS_PER_WORD    _IOW(SPI_IOC_MAGIC, 3, __u8)  
  73.   
  74. /* Read / Write SPI device default max speed hz */  
  75. #define SPI_IOC_RD_MAX_SPEED_HZ        _IOR(SPI_IOC_MAGIC, 4, __u32)  
  76. #define SPI_IOC_WR_MAX_SPEED_HZ        _IOW(SPI_IOC_MAGIC, 4, __u32)  

10.2 spidev_ioctl

在用户空间执行ioctl系统调用时,将会执行spidev_ioctl方法,我们来看下。

下列代码位于drivers/spi/spidev.c

[cpp] view plaincopyprint?
  1. <SPAN style="FONT-SIZE: 12px">static long  
  2. spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  
  3. {  
  4.     int         err = 0;  
  5.     int         retval = 0;  
  6.     struct spidev_data  *spidev;  
  7.     struct spi_device   *spi;  
  8.     u32         tmp;  
  9.     unsigned        n_ioc;  
  10.     struct spi_ioc_transfer *ioc;  
  11.   
  12.     /* Check type and command number */  
  13.     if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC)    /*如果幻数不想等,则报错*/  
  14.         return -ENOTTY;  
  15.   
  16.     /* Check access direction once here; don't repeat below. 
  17.      * IOC_DIR is from the user perspective, while access_ok is 
  18.      * from the kernel perspective; so they look reversed. 
  19.      */  
  20.      /*对用户空间的指针进行检查,分成读写两部分检查*/  
  21.     if (_IOC_DIR(cmd) & _IOC_READ、  
  22.         err = !access_ok(VERIFY_WRITE,  /*access_ok成功返回1*/  
  23.                 (void __user *)arg, _IOC_SIZE(cmd));  
  24.     if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)  
  25.         err = !access_ok(VERIFY_READ,  
  26.                 (void __user *)arg, _IOC_SIZE(cmd));  
  27.     if (err)  
  28.         return -EFAULT;  
  29.   
  30.     /* guard against device removal before, or while, 
  31.      * we issue this ioctl. 
  32.      */  
  33.     spidev = filp->private_data;     /*获取spidev*/  
  34.     spin_lock_irq(&spidev->spi_lock);  
  35.     spi = spi_dev_get(spidev->spi);      /*增加引用技术,并获取spi_device*/  
  36.     spin_unlock_irq(&spidev->spi_lock);  
  37.   
  38.     if (spi == NULL)  
  39.         return -ESHUTDOWN;  
  40.   
  41.     /* use the buffer lock here for triple duty: 
  42.      *  - prevent I/O (from us) so calling spi_setup() is safe; 
  43.      *  - prevent concurrent SPI_IOC_WR_* from morphing 
  44.      *    data fields while SPI_IOC_RD_* reads them; 
  45.      *  - SPI_IOC_MESSAGE needs the buffer locked "normally". 
  46.      */  
  47.     mutex_lock(&spidev->buf_lock);   /*加锁互斥体*/  
  48.   
  49.     switch (cmd) {  
  50.     /* read requests */     /*读取请求*/  
  51.     case SPI_IOC_RD_MODE:  
  52.         retval = __put_user(spi->mode & SPI_MODE_MASK,  
  53.                     (__u8 __user *)arg);  
  54.         break;  
  55.     case SPI_IOC_RD_LSB_FIRST:  
  56.         retval = __put_user((spi->mode & SPI_LSB_FIRST) ?  1 : 0,  
  57.                     (__u8 __user *)arg);  
  58.         break;  
  59.     case SPI_IOC_RD_BITS_PER_WORD:  
  60.         retval = __put_user(spi->bits_per_word, (__u8 __user *)arg);  
  61.         break;  
  62.     case SPI_IOC_RD_MAX_SPEED_HZ:  
  63.         retval = __put_user(spi->max_speed_hz, (__u32 __user *)arg);  
  64.         break;  
  65.   
  66.     /* write requests */    /*写请求*/  
  67.     case SPI_IOC_WR_MODE:     
  68.         retval = __get_user(tmp, (u8 __user *)arg);  
  69.         if (retval == 0) {          /*__get_user调用成功*/  
  70.             u8  save = spi->mode;    /*保存原先的值*/  
  71.   
  72.             if (tmp & ~SPI_MODE_MASK) {  
  73.                 retval = -EINVAL;  
  74.                 break;              /*模式有错误,则跳出switch*/  
  75.             }  
  76.   
  77.             tmp |= spi->mode & ~SPI_MODE_MASK;/*这步貌似多此一举????*/  
  78.             spi->mode = (u8)tmp;  
  79.             retval = spi_setup(spi);/*调用master->setup方法,即s3c24xx_spi_setup*/  
  80.             if (retval < 0)  
  81.                 spi->mode = save;    /*调用不成功,恢复参数*/  
  82.             else  
  83.                 dev_dbg(&spi->dev, "spi mode %02x\n", tmp);  
  84.         }  
  85.         break;  
  86.     case SPI_IOC_WR_LSB_FIRST:  
  87.         retval = __get_user(tmp, (__u8 __user *)arg);  
  88.         if (retval == 0) {  
  89.             u8  save = spi->mode;  
  90.   
  91.             if (tmp)                /*参数为正整数,设置为LSB*/  
  92.                 spi->mode |= SPI_LSB_FIRST;  
  93.             else                    /*参数为0,设置为非LSB*/  
  94.                 spi->mode &= ~SPI_LSB_FIRST;  
  95.             retval = spi_setup(spi);/*调用master->setup方法,即s3c24xx_spi_setup?/  
  96.             if (retval < 0) 
  97.                 spi->mode = save;    /*调用不成功,恢复参数*/  
  98.             else  
  99.                 dev_dbg(&spi->dev, "%csb first\n",  
  100.                         tmp ? 'l' : 'm');  
  101.         }  
  102.         break;  
  103.     case SPI_IOC_WR_BITS_PER_WORD:  
  104.         retval = __get_user(tmp, (__u8 __user *)arg);  
  105.         if (retval == 0) {  
  106.             u8  save = spi->bits_per_word;  
  107.   
  108.             spi->bits_per_word = tmp;  
  109.             retval = spi_setup(spi);    /*调用master->setup方法,即s3c24xx_spi_setup*/   
  110.             if (retval < 0)  
  111.                 spi->bits_per_word = save;  
  112.             else  
  113.                 dev_dbg(&spi->dev, "%d bits per word\n", tmp);  
  114.         }  
  115.         break;  
  116.     case SPI_IOC_WR_MAX_SPEED_HZ:  
  117.         retval = __get_user(tmp, (__u32 __user *)arg);  
  118.         if (retval == 0) {  
  119.             u32 save = spi->max_speed_hz;  
  120.   
  121.             spi->max_speed_hz = tmp;  
  122.             retval = spi_setup(spi);    /*调用master->setup方法,即s3c24xx_spi_setup*/   
  123.             if (retval < 0)  
  124.                 spi->max_speed_hz = save;  
  125.             else  
  126.                 dev_dbg(&spi->dev, "%d Hz (max)\n", tmp);  
  127.         }  
  128.         break;  
  129.   
  130.     default:  
  131.         /* segmented and/or full-duplex I/O request */  /*全双工,接受发送数据*/  
  132.         if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0))  
  133.                 || _IOC_DIR(cmd) != _IOC_WRITE) {  
  134.             retval = -ENOTTY;  
  135.             break;  
  136.         }  
  137.   
  138.         tmp = _IOC_SIZE(cmd);       /*获取参数的大小,参数为spi_ioc_transfer数组*/  
  139.         if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) {/*检查tmp是否为后者的整数倍*/  
  140.             retval = -EINVAL;  
  141.             break;  
  142.         }  
  143.         n_ioc = tmp / sizeof(struct spi_ioc_transfer); /*计算共有几个spi_ioc_transfer*/  
  144.         if (n_ioc == 0)  
  145.             break;  
  146.   
  147.         /* copy into scratch area */  
  148.         ioc = kmalloc(tmp, GFP_KERNEL);  
  149.         if (!ioc) {  
  150.             retval = -ENOMEM;  
  151.             break;  
  152.         }  
  153.         /*从用户空间拷贝spi_ioc_transfer数组,不对用户空间指针进行检查*/  
  154.         if (__copy_from_user(ioc, (void __user *)arg, tmp)) {  
  155.             kfree(ioc);  
  156.             retval = -EFAULT;  
  157.             break;  
  158.         }  
  159.   
  160.         /* translate to spi_message, execute */  
  161.         retval = spidev_message(spidev, ioc, n_ioc);  
  162.         kfree(ioc);  
  163.         break;  
  164.     }  
  165.   
  166.     mutex_unlock(&spidev->buf_lock);  
  167.     spi_dev_put(spi);   /*减少引用计数*/  
  168.     return retval;  
  169. }</SPAN>  
 在函数中,首先对cmd进行了一些列的检查。随后使用switch语句来判读cmd,并执行相应的功能。cmd的第一部分为读请求,分别从寄存器读取4个参数。第二部分为写请求,分别用于修改4个参数并写入寄存器。剩余的第三部分就是全双工读写请求,这是会先计算共有多少个spi_ioc_transfer,然后分配空间,从用户空间将spi_ioc_transfer数组拷贝过来,然后将该数组和数组个数作为参数调用spidev_message。

10.3 spidev_message

[cpp] view plaincopyprint?
  1. <SPAN style="FONT-SIZE: 12px">static int spidev_message(struct spidev_data *spidev,  
  2.         struct spi_ioc_transfer *u_xfers, unsigned n_xfers)  
  3. {  
  4.     struct spi_message  msg;  
  5.     struct spi_transfer *k_xfers;  
  6.     struct spi_transfer *k_tmp;  
  7.     struct spi_ioc_transfer *u_tmp;  
  8.     unsigned        n, total;  
  9.     u8          *buf;  
  10.     int         status = -EFAULT;  
  11.       
  12.     spi_message_init(&msg);     /*初始化message*/  
  13.     k_xfers = kcalloc(n_xfers, sizeof(*k_tmp), GFP_KERNEL); /*分配内存,并清0*/  
  14.     if (k_xfers == NULL)  
  15.         return -ENOMEM;  
  16.   
  17.     /* Construct spi_message, copying any tx data to bounce buffer. 
  18.      * We walk the array of user-provided transfers, using each one 
  19.      * to initialize a kernel version of the same transfer. 
  20.      */  
  21.     buf = spidev->buffer;    /*所有的spi_transfer共享该buffer*/  
  22.     total = 0;    
  23.     /*遍历spi_ioc_transfer数组,拷贝相应的参数至spi_transfer数组*/  
  24.     for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;  
  25.             n;  
  26.             n--, k_tmp++, u_tmp++) {  
  27.         k_tmp->len = u_tmp->len;  
  28.   
  29.         total += k_tmp->len;  
  30.         if (total > bufsiz) {  /*缓冲区长度为4096字节*/  
  31.             status = -EMSGSIZE;  
  32.             goto done;  
  33.         }  
  34.   
  35.         if (u_tmp->rx_buf) { /*需要接受收据*/  
  36.             k_tmp->rx_buf = buf;  
  37.             if (!access_ok(VERIFY_WRITE, (u8 __user *)  /*检查指针*/  
  38.                         (uintptr_t) u_tmp->rx_buf,  
  39.                         u_tmp->len))  
  40.                 goto done;  
  41.         }  
  42.         if (u_tmp->tx_buf) { /*需要发送数据*/  
  43.             k_tmp->tx_buf = buf;  
  44.             if (copy_from_user(buf, (const u8 __user *) /*将用户空间待发送的数据拷贝至buf中*/  
  45.                         (uintptr_t) u_tmp->tx_buf,  
  46.                     u_tmp->len))  
  47.                 goto done;  
  48.         }  
  49.         buf += k_tmp->len;       /*修改buf指针,指向下一个transfer的缓冲区首地址*/  
  50.         /*复制四个参数*/  
  51.         k_tmp->cs_change = !!u_tmp->cs_change;  
  52.         k_tmp->bits_per_word = u_tmp->bits_per_word;  
  53.         k_tmp->delay_usecs = u_tmp->delay_usecs;  
  54.         k_tmp->speed_hz = u_tmp->speed_hz;  
  55. #ifdef VERBOSE   
  56.         dev_dbg(&spi->dev,  
  57.             "  xfer len %zd %s%s%s%dbits %u usec %uHz\n",  
  58.             u_tmp->len,  
  59.             u_tmp->rx_buf ? "rx " : "",  
  60.             u_tmp->tx_buf ? "tx " : "",  
  61.             u_tmp->cs_change ? "cs " : "",  
  62.             u_tmp->bits_per_word ? : spi->bits_per_word,  
  63.             u_tmp->delay_usecs,  
  64.             u_tmp->speed_hz ? : spi->max_speed_hz);  
  65. #endif   
  66.         spi_message_add_tail(k_tmp, &msg); /*添加spi_transfer到message的链表中*/  
  67.     }  
  68.   
  69.     /*spidev_sync->spi_async->spi_bitbang_transfer->bitbang_work->s3c24xx_spi_txrx*/  
  70.     status = spidev_sync(spidev, &msg);   
  71.     if (status < 0)  
  72.         goto done;  
  73.   
  74.     /* copy any rx data out of bounce buffer */  
  75.     buf = spidev->buffer;  
  76.     for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) {  
  77.         if (u_tmp->rx_buf) {  
  78.             if (__copy_to_user((u8 __user *)  
  79.                     (uintptr_t) u_tmp->rx_buf, buf,  /*从buf缓冲区复制数据到用户空间*/  
  80.                     u_tmp->len)) {  
  81.                 status = -EFAULT;  
  82.                 goto done;  
  83.             }  
  84.         }  
  85.         buf += u_tmp->len;  
  86.     }  
  87.     status = total;  
  88.   
  89. done:  
  90.     kfree(k_xfers);  
  91.     return status;  
  92. }</SPAN>  
 首先,根据spi_ioc_transfer的个数,分配了同样个数的spi_transfer,把spi_ioc_transfer中的信息复制给spi_transfer,然后将spi_transfer添加到spi_message的链

 表中。接着。执行了spidev_sync,这个东西似乎似曾相识,这个函数就 8.3  小结的函数。之后的过程就和前面的write、read一样了。

 其实,这个函数的作用就是把所需要完成的数据传输任务转换成spi_transfer,然后添加到message的连表中。

 从spidev_sync返回以后,数据传输完毕,将读取到的数据,复制到用户空间。至此,整个ioctl系统调用的过程就结束了。

10.4 小结


事实上,全速工io和半双工io的执行过程基本一样,只不过ioctl需要一个专用的结构体来封装传输的任务,接着将该任务转换成对应的spi_transfer,最后交给spidev_sync。

11. 结束语

   本系列文章先从最底层的master驱动开始讲解,接着描述了高层的spi设备驱动,然后,通过系统调用接口,从上至下的讲解了整个函数的调用过程。最终,

   我们可以很清除看到半双工读和半双写的区别和相似之处,以及半双工IO和全双工IO的区别和相似之处。

   最后,希望该系列文章能帮助你了解Linux的SPI子系统。

   谢谢!