Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1144355
  • 博文数量: 146
  • 博客积分: 190
  • 博客等级: 入伍新兵
  • 技术积分: 5225
  • 用 户 组: 普通用户
  • 注册时间: 2012-06-06 08:24
个人简介

慢行者

文章分类

全部博文(146)

文章存档

2013年(145)

2012年(1)

分类: LINUX

2013-04-26 11:12:35

Allein.Cao原创作品,转载请注明出处:

http://blog.csdn.net/alleincao/article/details/7525977


内核版本:2.6.32.2

硬件:S3C2440

设备驱动是在core之上的模块,向上给应用程序提供file_operations接口,应用程序可以通过设备节点访问驱动程序,向下通过core向控制器模块发送数据,控制器模块将数据发送到物理总线上。

spidev.c是一个典型的设备驱动程序,前面提到在linux中,一般都会采用设备驱动和控制器驱动分离的思想,两者通过一个core进行关联,目的是最大程度保证代码的可移植性,我们以应用程序调用为主线,详细分析spi驱动的数据流流向。

首先来看

[csharp]
  1. static struct spi_driver spidev_spi = {         //spi_driver 
  2.     .driver = { 
  3.         .name =     "spidev",       //spi_bus_type上spi_despi_devie与spi_driver匹配依赖于此名字 
  4.         .owner =    THIS_MODULE, 
  5.     }, 
  6.     .probe =    spidev_probe,                   //probe函数 
  7.     .remove =   __devexit_p(spidev_remove),//编译为模块or编译到内核?内核则为NULL,模块为spidev_remove 
  8. }; 
  9. static int __init spidev_init(void
  10.     int status; 
  11.  
  12.     /* Claim our 256 reserved device numbers.  Then register a class
  13.      * that will key udev/mdev to add/remove /dev nodes.  Last, register
  14.      * the driver which manages those device numbers.
  15.      */ 
  16.     //设备驱动与主设备号一一对应,所以当用户打开主设备号为SPIDEV_MAJOR的设备节点时会调用spidev_fops相关函数BUILD_BUG_ON(N_SPI_MINORS > 256); 
  17.     status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);     
  18.     if (status < 0) 
  19.         return status; 
  20.  
  21.     spidev_class = class_create(THIS_MODULE, "spidev");     //创建spidev_class类 
  22.     if (IS_ERR(spidev_class)) { 
  23.         unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name); 
  24.         return PTR_ERR(spidev_class); 
  25.     } 
  26.  
  27.     status = spi_register_driver(&spidev_spi);  //注册spi_driver 
  28.     if (status < 0) { 
  29.         class_destroy(spidev_class); 
  30.         unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name); 
  31.     } 
  32.     return status; 


spidev_probe函数的调用在spi_bus_type的match函数即spi_match_device函数调用之后进行,它的实现相对简单,主要是分配并初始化spidev_data结构体,将其添加到device_list链表,执行完此函数,所有spi_bus_type上spi_devie和spi_driver匹配完毕:

[csharp]
  1. static int spidev_probe(struct spi_device *spi) //其入口参数是spi_bus_type上的spi_device 
  2.     struct  *spidev; 
  3.     int         status; 
  4.     unsigned long       minor; 
  5.  
  6.     /* Allocate driver data */ 
  7.     spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);  //每个spi_device对应一个spidev_data 
  8.     if (!spidev) 
  9.         return -ENOMEM; 
  10.  
  11.     /* Initialize the driver data */ 
  12.     spidev->spi = spi; 
  13.     spin_lock_init(&spidev->spi_lock); 
  14.     mutex_init(&spidev->buf_lock); 
  15.  
  16.     INIT_LIST_HEAD(&spidev->device_entry); 
  17.  
  18.     /* If we can allocate a minor number, hook up this device.
  19.      * Reusing minors is fine so long as udev or mdev is working.
  20.      */ 
  21.     mutex_lock(&device_list_lock); 
  22.     minor = find_first_zero_bit(minors, N_SPI_MINORS);  //找到第一个0位,作为次设备号,见下面分析 
  23.     if (minor < N_SPI_MINORS) { 
  24.         struct device *dev; 
  25.  
  26.         spidev->devt = MKDEV(SPIDEV_MAJOR, minor); 
  27.         dev = device_create(spidev_class, &spi->dev, spidev->devt, 
  28.                     spidev, "spidev%d.%d"
  29.                     spi->master->bus_num, spi->chip_select); 
  30.         status = IS_ERR(dev) ? PTR_ERR(dev) : 0; 
  31.     } else
  32.         dev_dbg(&spi->dev, "no minor number available!\n"); 
  33.         status = -ENODEV; 
  34.     } 
  35.     if (status == 0) { 
  36.         set_bit(minor, minors);     //设置相应位 
  37.         list_add(&spidev->device_entry, &device_list);   //添加到device_list链表 
  38.     } 
  39.     mutex_unlock(&device_list_lock); 
  40.  
  41.     if (status == 0) 
  42.         spi_set_drvdata(spi, spidev);       //设置私有数据spi_device–>dev->p->driver_data 
  43.     else 
  44.         kfree(spidev); 
  45.  
  46.     return status; 


接下来,我们分析该驱动的调用流程,即file_operations中的成员函数:

[csharp]
  1. static const struct file_operations spidev_fops = { 
  2.     .owner =    THIS_MODULE, 
  3.     /* REVISIT switch to aio primitives, so that userspace
  4.      * gets more complete API coverage.  It'll simplify things
  5.      * too, except for the locking.
  6.      */ 
  7.     .write =    spidev_write, 
  8.     .read =     spidev_read, 
  9.     .unlocked_ioctl = spidev_ioctl, 
  10.     .open =     spidev_open, 
  11.     .release =  spidev_release, 
  12. }; 


首先,我们来开open函数spidev_open,其主要目的就是根据用户打开的设备节点的设备号找到对应的spidev_data,也就自然找到对应的spi_device(通过spidev_data->spi,其在probe函数中赋值),这样就很自然地实现用户空间访问spi设备:

[csharp]
  1. static int spidev_open(struct inode *inode, struct file *filp) 
  2.     struct spidev_data  *spidev; 
  3.     int         status = -ENXIO; 
  4.  
  5.     lock_kernel(); 
  6.     mutex_lock(&device_list_lock); 
  7.  
  8. //根据设备号找到对应的spidev,很自然可以找到对应的spi_device 
  9.     list_for_each_entry(spidev, &device_list, device_entry) { 
  10.         if (spidev->devt == inode->i_rdev) {   
  11.             status = 0; 
  12.             break
  13.         } 
  14.     } 
  15.     if (status == 0) { 
  16.         if (!spidev->buffer) {       //buffer没分配则分配buffer 
  17.             spidev->buffer = kmalloc(bufsiz, GFP_KERNEL);     
  18.             if (!spidev->buffer) { 
  19.                 dev_dbg(&spidev->spi->dev, "open/ENOMEM\n"); 
  20.                 status = -ENOMEM; 
  21.             } 
  22.         } 
  23.         if (status == 0) { 
  24.             spidev->users++; 
  25.             filp->private_data = spidev; //保存私有数据,供后面的read write等函数直接调用 
  26.             nonseekable_open(inode, filp); 
  27.         } 
  28.     } else 
  29.         pr_debug("spidev: nothing for minor %d\n", iminor(inode)); 
  30.  
  31.     mutex_unlock(&device_list_lock); 
  32.     unlock_kernel(); 
  33.     return status; 


接下来我们看其他函数,这里read函数和write函数很类似,我们以read函数为例进行分析:

[csharp]
  1. static ssize_t  
  2. spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) 
  3.     struct spidev_data  *spidev; 
  4.     ssize_t         status = 0; 
  5.  
  6.     /* chipselect only toggles at start or end of operation */ 
  7.     if (count > bufsiz) 
  8.         return -EMSGSIZE; 
  9.  
  10.     spidev = filp->private_data;     //取出open函数里设置的spidev_data 
  11.  
  12.     mutex_lock(&spidev->buf_lock); 
  13.     status = spidev_sync_read(spidev, count);   //读取数据,见下面分析 
  14.     if (status > 0) { 
  15.         unsigned long   missing; 
  16.  
  17.         missing = copy_to_user(buf, spidev->buffer, status); //向用户空间传送数据 
  18.         if (missing == status) 
  19.             status = -EFAULT; 
  20.         else 
  21.             status = status - missing; 
  22.     } 
  23.     mutex_unlock(&spidev->buf_lock); 
  24.  
  25.     return status; 


接下来,我们跟踪spidev_sync_read函数:

[csharp]
  1. static inline ssize_t spidev_sync_read(struct spidev_data *spidev, size_t len) 
  2.     struct spi_transfer t = { 
  3.             .rx_buf     = spidev->buffer, 
  4.             .len        = len, 
  5.         }; 
  6.     struct spi_message  m; 
  7.  
  8.     spi_message_init(&m);           //初始化spi_message 
  9.     spi_message_add_tail(&t, &m);   //将spi_transfer添加到spi_message的transfers 
  10.     return spidev_sync(spidev, &m); //见下面分析 


接下来,我们跟踪spidev_sync函数:

[csharp]
  1. static ssize_t spidev_sync(struct spidev_data *spidev, struct spi_message *message) 
  2.     DECLARE_COMPLETION_ONSTACK(done); 
  3.     int status; 
  4.  
  5.     message->complete = spidev_complete; //消息完成调用函数 
  6.     message->context = &done;                //消息完成调用函数参数 
  7.  
  8.     spin_lock_irq(&spidev->spi_lock); 
  9.     if (spidev->spi == NULL) //没有对应的spi_device则出错返回,最终依赖于spi_device进行数据收发 
  10.         status = -ESHUTDOWN; 
  11.     else 
  12.         status = spi_async(spidev->spi, message); //异步传输函数,位于spi.c中,见下面分析 
  13.     spin_unlock_irq(&spidev->spi_lock); 
  14.  
  15.     if (status == 0) { 
  16.         wait_for_completion(&done); //等待消息完成 
  17.         status = message->status; 
  18.         if (status == 0) 
  19.             status = message->actual_length; 
  20.     } 
  21.     return status; 


接下来,我们跟踪spi_async函数:

[csharp]
  1. int spi_async(struct spi_device *spi, struct spi_message *message) 
  2.     struct spi_master *master = spi->master; 
  3.  
  4.     /* Half-duplex links include original MicroWire, and ones with
  5.      * only one data pin like SPI_3WIRE (switches direction) or where
  6.      * either MOSI or MISO is missing.  They can also be caused by
  7.      * software limitations.
  8.      */ 
  9.     if ((master->flags & SPI_MASTER_HALF_DUPLEX)     //半双工? 
  10.             || (spi->mode & SPI_3WIRE)) { 
  11.         struct spi_transfer *xfer; 
  12.         unsigned flags = master->flags; 
  13.  
  14.         list_for_each_entry(xfer, &message->transfers, transfer_list) { 
  15.             if (xfer->rx_buf && xfer->tx_buf) 
  16.                 return -EINVAL; 
  17.             if ((flags & SPI_MASTER_NO_TX) && xfer->tx_buf) 
  18.                 return -EINVAL; 
  19.             if ((flags & SPI_MASTER_NO_RX) && xfer->rx_buf) 
  20.                 return -EINVAL; 
  21.         } 
  22.     } 
  23.  
  24.     message->spi = spi;   
  25.     message->status = -EINPROGRESS; 
  26.     return master->transfer(spi, message);       //最终调用spi_master的transfer函数 


通过前面控制器驱动中spi_bitbang_start函数分析,我们知道spi_master的transfer函数其实是spi_bitbang_transfer,该函数不执行数据的具体发送,仅仅是将message消息添加到spi_bitbang的队列中:

[csharp]
  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.     struct spi_bitbang  *bitbang; 
  6.     unsigned long       flags; 
  7.     int         status = 0; 
  8.  
  9.     m->actual_length = 0; 
  10.     m->status = -EINPROGRESS; 
  11.  
  12.     //得到spi_bitbang,它负责具体的数据发送,这里有个小技巧,在控制器驱动中我们知道spi_master->dev->p->driver_data恰好是struct s3c24xx_spi,而struct spi_bitbang恰好又是struct s3c24xx_spi的第一个成员,故此处可以得到struct spi_bitbang 
  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.         list_add_tail(&m->queue, &bitbang->queue);  //将message添加到bitbang的消息列表 
  20.         queue_work(bitbang->workqueue, &bitbang->work); //添加工作结构体到工作队列 
  21.     } 
  22.     spin_unlock_irqrestore(&bitbang->lock, flags); 
  23.  
  24.     return status; 


通过前面控制器驱动中spi_bitbang_start函数分析,structspi_bitbang中的工作函数是bitbang_work,我们来看其实现:

[csharp]
  1. static void bitbang_work(struct work_struct *work) 
  2.     struct spi_bitbang  *bitbang = container_of(work, struct spi_bitbang, work); 
  3.     unsigned long       flags; 
  4.     int         do_setup = -1; 
  5.     int         (*setup_transfer)(struct spi_device *, 
  6.                     struct spi_transfer *); 
  7.  
  8.     setup_transfer = bitbang->setup_transfer;    // s3c24xx_spi_setupxfer,在控制器驱动中赋值 
  9.  
  10.     spin_lock_irqsave(&bitbang->lock, flags); 
  11.     bitbang->busy = 1;                       //置位忙标志  
  12.     while (!list_empty(&bitbang->queue)) {       //读取bitbang链表中的message进行发送 
  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.  
  21.         m = container_of(bitbang->queue.next, struct spi_message, 
  22.                 queue); 
  23.         list_del_init(&m->queue); 
  24.         spin_unlock_irqrestore(&bitbang->lock, flags); 
  25.  
  26.         /* FIXME this is made-up ... the correct value is known to
  27.          * word-at-a-time bitbang code, and presumably chipselect()
  28.          * should enforce these requirements too?
  29.          */ 
  30.         nsecs = 100; 
  31.  
  32.         spi = m->spi; 
  33.         tmp = 0; 
  34.         cs_change = 1; 
  35.         status = 0; 
  36.      
  37. //逐个取出消息中的每个spi_transfer,每个message通过链表可以包括多个spi_transfer 
  38.         list_for_each_entry (t, &m->transfers, transfer_list) { 
  39.  
  40.             /* override speed or wordsize? */ 
  41.             if (t->speed_hz || t->bits_per_word)  //每个spi_tranfer的发送接收频率完全可能不同 
  42.                 do_setup = 1;        
  43.  
  44.             /* init (-1) or override (1) transfer params */      
  45.             if (do_setup != 0) { 
  46.                 if (!setup_transfer) { 
  47.                     status = -ENOPROTOOPT; 
  48.                     break
  49.                 } 
  50.                 status = setup_transfer(spi, t); //根据spi_tranfer要求更新控制器预分频寄存器状态以改变通讯频率,见下面分析 
  51.                 if (status < 0) 
  52.                     break
  53.             } 
  54.  
  55.             /* set up default clock polarity, and activate chip;
  56.              * this implicitly updates clock and spi modes as
  57.              * previously recorded for this device via setup().
  58.              * (and also deselects any other chip that might be
  59.              * selected ...)
  60.              */ 
  61.             if (cs_change) { 
  62.                 bitbang->chipselect(spi, BITBANG_CS_ACTIVE); // 激活CS信号,通过s3c24xx_spi_chipsel函数实现,见下面分析 
  63.                 ndelay(nsecs); 
  64.             } 
  65.             cs_change = t->cs_change;  //发送完当前spi_tranfer之后,需要改变CS引脚状态? 
  66.             if (!t->tx_buf && !t->rx_buf && t->len) { 
  67.                 status = -EINVAL; 
  68.                 break
  69.             } 
  70.  
  71.             /* transfer data.  the lower level code handles any
  72.              * new dma mappings it needs. our caller always gave
  73.              * us dma-safe buffers.
  74.              */ 
  75.             if (t->len) { 
  76.                 /* REVISIT dma API still needs a designated
  77.                  * DMA_ADDR_INVALID; ~0 might be better.
  78.                  */ 
  79.                 if (!m->is_dma_mapped) 
  80.                     t->rx_dma = t->tx_dma = 0; 
  81.                 status = bitbang->txrx_bufs(spi, t);  // s3c24xx_spi_txrx函数,在控制器probe函数中初始化,见下面分析 
  82.             } 
  83.             if (status > 0) 
  84.                 m->actual_length += status;  //数据统计 
  85.             if (status != t->len) { 
  86.                 /* always report some kind of error */ 
  87.                 if (status >= 0) 
  88.                     status = -EREMOTEIO; 
  89.                 break
  90.             } 
  91.             status = 0; 
  92.  
  93.             /* protocol tweaks before next transfer */ 
  94.             if (t->delay_usecs) 
  95.                 udelay(t->delay_usecs); 
  96.  
  97.             if (!cs_change) 
  98.                 continue
  99.             if (t->transfer_list.next == &m->transfers)   //该message中所有transfers传送完毕? 
  100.                 break
  101.  
  102.             /* sometimes a short mid-message deselect of the chip
  103.              * may be needed to terminate a mode or command
  104.              */ 
  105.             ndelay(nsecs); 
  106.             bitbang->chipselect(spi, BITBANG_CS_INACTIVE);       //取消片选 
  107.             ndelay(nsecs); 
  108.         } 
  109.  
  110.         m->status = status; 
  111.         m->complete(m->context);  //消息完成函数,通知spidev_sync函数消息完成 
  112.  
  113.         /* restore speed and wordsize if it was overridden */ 
  114.         if (do_setup == 1)  //恢复到spi_device 中对传输速率的设置 
  115.             setup_transfer(spi, NULL);  //NULL代表以spi_device而不是spi_transfer的设置来设置sppre寄存器 
  116.         do_setup = 0; 
  117.  
  118.         /* normally deactivate chipselect ... unless no error and
  119.          * cs_change has hinted that the next message will probably
  120.          * be for this chip too.
  121.          */ 
  122.         if (!(status == 0 && cs_change)) { 
  123.             ndelay(nsecs); 
  124.             bitbang->chipselect(spi, BITBANG_CS_INACTIVE);   //正常情况取消当前设备片选 
  125.             ndelay(nsecs); 
  126.         } 
  127.  
  128.         spin_lock_irqsave(&bitbang->lock, flags); 
  129.     } 
  130.     bitbang->busy = 0; 
  131.     spin_unlock_irqrestore(&bitbang->lock, flags); 


跟踪s3c24xx_spi_setupxfer函数:

[csharp]
  1. static int s3c24xx_spi_setupxfer(struct spi_device *spi, 
  2.                  struct spi_transfer *t) 
  3.     struct s3c24xx_spi_devstate *cs = spi->controller_state; 
  4.     struct s3c24xx_spi *hw = to_hw(spi); 
  5.     int ret; 
  6.  
  7.     ret = s3c24xx_spi_update_state(spi, t);     //在控制器驱动程序中已经讲述 
  8.     if (!ret) 
  9.         writeb(cs->sppre, hw->regs + S3C2410_SPPRE);  //设置SPPRE硬件寄存器改变数据速率 
  10.  
  11.     return ret; 


跟踪s3c24xx_spi_chipsel函数:

[csharp]
  1. static void s3c24xx_spi_chipsel(struct spi_device *spi, int value) 
  2.     struct s3c24xx_spi_devstate *cs = spi->controller_state; //读取当前控制器状态 
  3.     struct s3c24xx_spi *hw = to_hw(spi); 
  4.     unsigned int cspol = spi->mode & SPI_CS_HIGH ? 1 : 0; 
  5.  
  6.     /* change the chipselect state and the state of the spi engine clock */ 
  7.  
  8.     switch (value) { 
  9.     case BITBANG_CS_INACTIVE: 
  10.         hw->set_cs(hw->pdata, spi->chip_select, cspol^1); //在BSP中注册或者s3c24xx_spi_gpiocs,见s3c24xx_spi_probe 
  11.         writeb(cs->spcon, hw->regs + S3C2410_SPCON); 
  12.         break
  13.  
  14.     case BITBANG_CS_ACTIVE: 
  15.         writeb(cs->spcon | S3C2410_SPCON_ENSCK, 
  16.                hw->regs + S3C2410_SPCON); 
  17.         hw->set_cs(hw->pdata, spi->chip_select, cspol); 
  18.         break
  19.     } 


此处,消息的发送是基于中断模式进行的,跟踪s3c24xx_spi_txrx函数:

[csharp]
  1. static int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t) 
  2.     struct s3c24xx_spi *hw = to_hw(spi); 
  3.  
  4.     dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n"
  5.         t->tx_buf, t->rx_buf, t->len); 
  6.  
  7.     hw->tx = t->tx_buf; 
  8.     hw->rx = t->rx_buf; 
  9.     hw->len = t->len; 
  10.     hw->count = 0; 
  11.  
  12.     init_completion(&hw->done); 
  13.  
  14.     /* send the first byte */ 
  15.     writeb(hw_txbyte(hw, 0), hw->regs + S3C2410_SPTDAT); //将发送数据写入寄存器,如果是读数据,则发送0,具体解释可以参考spi_transfer结构体的英语解释 
  16.  
  17.     wait_for_completion(&hw->done);  //等待结束 
  18.  
  19.     return hw->count; 


当数据发送完成后,触发中断,我们跟踪控制器驱动中probe函数中注册的中断处理函数:

[csharp]
  1. static irqreturn_t s3c24xx_spi_irq(int irq, void *dev) 
  2.     struct s3c24xx_spi *hw = dev; 
  3.     unsigned int spsta = readb(hw->regs + S3C2410_SPSTA); 
  4.     unsigned int count = hw->count; 
  5.  
  6.     if (spsta & S3C2410_SPSTA_DCOL) {  //判断有无错误发生 
  7.         dev_dbg(hw->dev, "data-collision\n"); 
  8.         complete(&hw->done); 
  9.         goto irq_done; 
  10.     } 
  11.  
  12.     if (!(spsta & S3C2410_SPSTA_READY)) { 
  13.         dev_dbg(hw->dev, "spi not ready for tx?\n"); 
  14.         complete(&hw->done); 
  15.         goto irq_done; 
  16.     } 
  17.  
  18.     hw->count++; 
  19.  
  20.     if (hw->rx) 
  21.         hw->rx[count] = readb(hw->regs + S3C2410_SPRDAT); //读取数据 
  22.  
  23.     count++; 
  24.  
  25.     if (count < hw->len) 
  26.         writeb(hw_txbyte(hw, count), hw->regs + S3C2410_SPTDAT); 
  27.     else 
  28.         complete(&hw->done);  //通知完成数据读写 
  29.  
  30. irq_done: 
  31.     return IRQ_HANDLED; 


至此,对一个SPI设备的操作读操作完成,写操作与此类似,读者可以自行分析!


接下来,我们分析ioctl函数,有了前面的基础,分析ioctl就非常简单啦,我们在此只把一些要点说明一下,不做详细讲解,其实前面都已经讲过啦:

[csharp]
  1. static long 
  2. spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 
  3.     int         err = 0; 
  4.     int         retval = 0; 
  5.     struct spidev_data  *spidev; 
  6.     struct spi_device   *spi; 
  7.     u32         tmp; 
  8.     unsigned        n_ioc; 
  9.     struct spi_ioc_transfer *ioc; 
  10.  
  11.     /* Check type and command number */ 
  12.     if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC) 
  13.         return -ENOTTY; 
  14.  
  15.     /* Check access direction once here; don't repeat below.
  16.      * IOC_DIR is from the user perspective, while access_ok is
  17.      * from the kernel perspective; so they look reversed.
  18.      */ 
  19.     if (_IOC_DIR(cmd) & _IOC_READ) 
  20.         err = !access_ok(VERIFY_WRITE,      //对访问用户空间进行合法性校验 
  21.                 (void __user *)arg, _IOC_SIZE(cmd)); 
  22.     if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE) 
  23.         err = !access_ok(VERIFY_READ, 
  24.                 (void __user *)arg, _IOC_SIZE(cmd)); 
  25.     if (err) 
  26.         return -EFAULT; 
  27.  
  28.     /* guard against device removal before, or while,
  29.      * we issue this ioctl.
  30.      */ 
  31.     spidev = filp->private_data; 
  32.     spin_lock_irq(&spidev->spi_lock); 
  33.     spi = spi_dev_get(spidev->spi); 
  34.     spin_unlock_irq(&spidev->spi_lock); 
  35.  
  36.     if (spi == NULL) 
  37.         return -ESHUTDOWN; 
  38.     mutex_lock(&spidev->buf_lock); 
  39.  
  40.     switch (cmd) { 
  41.     /* read requests */ 
  42.     case SPI_IOC_RD_MODE:       //读取信息 
  43.         retval = __put_user(spi->mode & SPI_MODE_MASK, 
  44.                     (__u8 __user *)arg); 
  45.         break
  46.     case SPI_IOC_RD_LSB_FIRST: 
  47.         retval = __put_user((spi->mode & SPI_LSB_FIRST) ?  1 : 0, 
  48.                     (__u8 __user *)arg); 
  49.         break
  50.     case SPI_IOC_RD_BITS_PER_WORD: 
  51.         retval = __put_user(spi->bits_per_word, (__u8 __user *)arg); 
  52.         break
  53.     case SPI_IOC_RD_MAX_SPEED_HZ: 
  54.         retval = __put_user(spi->max_speed_hz, (__u32 __user *)arg); 
  55.         break
  56.  
  57.     /* write requests */ 
  58.     case SPI_IOC_WR_MODE: 
  59.         retval = __get_user(tmp, (u8 __user *)arg); 
  60.         if (retval == 0) { 
  61.             u8  save = spi->mode; 
  62.  
  63.             if (tmp & ~SPI_MODE_MASK) { 
  64.                 retval = -EINVAL; 
  65.                 break
  66.             } 
  67.  
  68.             tmp |= spi->mode & ~SPI_MODE_MASK; 
  69.             spi->mode = (u8)tmp; 
  70.             retval = spi_setup(spi);    //调用s3c24xx_spi_setup,前面已经分析过 
  71.             if (retval < 0) 
  72.                 spi->mode = save; 
  73.             else 
  74.                 dev_dbg(&spi->dev, "spi mode %02x\n", tmp); 
  75.         } 
  76.         break
  77.     case SPI_IOC_WR_LSB_FIRST: 
  78.         retval = __get_user(tmp, (__u8 __user *)arg); 
  79.         if (retval == 0) { 
  80.             u8  save = spi->mode; 
  81.  
  82.             if (tmp) 
  83.                 spi->mode |= SPI_LSB_FIRST; 
  84.             else 
  85.                 spi->mode &= ~SPI_LSB_FIRST; 
  86.             retval = spi_setup(spi); 
  87.             if (retval < 0) 
  88.                 spi->mode = save; 
  89.             else 
  90.                 dev_dbg(&spi->dev, "%csb first\n"
  91.                         tmp ? 'l' : 'm'); 
  92.         } 
  93.         break
  94.     case SPI_IOC_WR_BITS_PER_WORD: 
  95.         retval = __get_user(tmp, (__u8 __user *)arg); 
  96.         if (retval == 0) { 
  97.             u8  save = spi->bits_per_word; 
  98.  
  99.             spi->bits_per_word = tmp; 
  100.             retval = spi_setup(spi); 
  101.             if (retval < 0) 
  102.                 spi->bits_per_word = save; 
  103.             else 
  104.                 dev_dbg(&spi->dev, "%d bits per word\n", tmp); 
  105.         } 
  106.         break
  107.     case SPI_IOC_WR_MAX_SPEED_HZ: 
  108.         retval = __get_user(tmp, (__u32 __user *)arg); 
  109.         if (retval == 0) { 
  110.             u32 save = spi->max_speed_hz; 
  111.  
  112.             spi->max_speed_hz = tmp; 
  113.             retval = spi_setup(spi); 
  114.             if (retval < 0) 
  115.                 spi->max_speed_hz = save; 
  116.             else 
  117.                 dev_dbg(&spi->dev, "%d Hz (max)\n", tmp); 
  118.         } 
  119.         break
  120.  
  121.     default
  122.         /* segmented and/or full-duplex I/O request */ 
  123.         if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0)) 
  124.                 || _IOC_DIR(cmd) != _IOC_WRITE) { 
  125.             retval = -ENOTTY; 
  126.             break
  127.         } 
  128.  
  129.         tmp = _IOC_SIZE(cmd);           //读取数据大小 
  130.         if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) { //必须是spi_ioc_transfer的整数倍 
  131.             retval = -EINVAL; 
  132.             break
  133.         } 
  134.         n_ioc = tmp / sizeof(struct spi_ioc_transfer);      //无数据传送? 
  135.         if (n_ioc == 0) 
  136.             break
  137.  
  138.         /* copy into scratch area */ 
  139.         ioc = kmalloc(tmp, GFP_KERNEL); 
  140.         if (!ioc) { 
  141.             retval = -ENOMEM; 
  142.             break
  143.         } 
  144.         if (__copy_from_user(ioc, (void __user *)arg, tmp)) { //拷贝用户空间数据 
  145.             kfree(ioc);  
  146.             retval = -EFAULT; 
  147.             break
  148.         } 
  149.  
  150.         /* translate to spi_message, execute */ 
  151.         retval = spidev_message(spidev, ioc, n_ioc);    //见英语注释 
  152.         kfree(ioc); 
  153.         break
  154.     } 
  155.  
  156.     mutex_unlock(&spidev->buf_lock); 
  157.     spi_dev_put(spi); 
  158.     return retval; 


追踪spidev_message函数:

[csharp]
  1. static int spidev_message(struct spidev_data *spidev, 
  2.         struct spi_ioc_transfer *u_xfers, unsigned n_xfers) 
  3.     struct spi_message  msg; 
  4.     struct spi_transfer *k_xfers; 
  5.     struct spi_transfer *k_tmp; 
  6.     struct spi_ioc_transfer *u_tmp; 
  7.     unsigned        n, total; 
  8.     u8          *buf; 
  9.     int         status = -EFAULT; 
  10.  
  11.     spi_message_init(&msg); //对msg进行初始化 
  12.     k_xfers = kcalloc(n_xfers, sizeof(*k_tmp), GFP_KERNEL); 
  13.     if (k_xfers == NULL) 
  14.         return -ENOMEM; 
  15.  
  16.     /* Construct spi_message, copying any tx data to bounce buffer.
  17.      * We walk the array of user-provided transfers, using each one
  18.      * to initialize a kernel version of the same transfer.
  19.      */ 
  20. //主要目的是构建一个spi_message,其实spi_ioc_transfer是spi_transfer的用户空间版本,或者说是映射,具体见英语注释 
  21.     buf = spidev->buffer; 
  22.     total = 0; 
  23.     for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers; 
  24.             n; 
  25.             n--, k_tmp++, u_tmp++) { 
  26.         k_tmp->len = u_tmp->len; 
  27.  
  28.         total += k_tmp->len;     //传输数据总量 
  29.         if (total > bufsiz) {    //在open中给spidev_data申请了bufsiz大小的buffer,不能超过此值 
  30.             status = -EMSGSIZE; 
  31.             goto done; 
  32.         } 
  33.  
  34.         if (u_tmp->rx_buf) {     //接收数据? 
  35.             k_tmp->rx_buf = buf; 
  36.             if (!access_ok(VERIFY_WRITE, (u8 __user *) 
  37.                         (uintptr_t) u_tmp->rx_buf, 
  38.                         u_tmp->len)) 
  39.                 goto done; 
  40.         } 
  41.         if (u_tmp->tx_buf) { //发送数据? 
  42.             k_tmp->tx_buf = buf; 
  43.             if (copy_from_user(buf, (const u8 __user *) 
  44.                         (uintptr_t) u_tmp->tx_buf, 
  45.                     u_tmp->len)) 
  46.                 goto done; 
  47.         } 
  48.         buf += k_tmp->len; 
  49.          
  50. //初始化 
  51.         k_tmp->cs_change = !!u_tmp->cs_change; //当前transfer结束影响CS引脚? 
  52.         k_tmp->bits_per_word = u_tmp->bits_per_word; 
  53.         k_tmp->delay_usecs = u_tmp->delay_usecs;  //当前spi_transfer结束后延迟时间 
  54.         k_tmp->speed_hz = u_tmp->speed_hz;//传输速度,可以overwrite对应spi_device的值 
  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通过它的transfer_list字段挂到spi_message的transfer队列上 
  67.     } 
  68.  
  69.     status = spidev_sync(spidev, &msg); //前面已经分析过,此处飘过 
  70.     if (status < 0) 
  71.         goto done; 
  72.  
  73.     /* copy any rx data out of bounce buffer */ 
  74.     buf = spidev->buffer; 
  75.     for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) { 
  76.         if (u_tmp->rx_buf) { 
  77.             if (__copy_to_user((u8 __user *)        //拷贝数据到用户空间 
  78.                     (uintptr_t) u_tmp->rx_buf, buf, 
  79.                     u_tmp->len)) { 
  80.                 status = -EFAULT; 
  81.                 goto done; 
  82.             } 
  83.         } 
  84.         buf += u_tmp->len; 
  85.     } 
  86.     status = total; 
  87.  
  88. done: 
  89.     kfree(k_xfers); 
  90.     return status; 



总结:

设备驱动完成的主要工作就是将spi_driver注册到spi_bus_type,经过前面控制器驱动程序分析我们知道,当控制器驱动注册时会扫描BSP中注册的设备链表将spi_device注册到sip_bus_type,这样,当spi_driver注册时会扫描spi_bus_type上的spi_device,如果其上的spi_device和spi_driver能通过spi_bus_type的match函数进行匹配,则会调用spi_driver的probe函数进行资源分配。

Spi子系统的主要目的是通过spi_bus_type实现spi_device和spi_driver的匹配,具体的用户接口还是通过file_operations来实现,在file_operations的接口函数中,通过次设备号找到对应的spi设备,调用其接口实现数据发送。

阅读(6594) | 评论(0) | 转发(3) |
给主人留下些什么吧!~~