Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1162715
  • 博文数量: 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. { 
  11.     int status; 
  12.  
  13.     /* Claim our 256 reserved device numbers.  Then register a class
  14.      * that will key udev/mdev to add/remove /dev nodes.  Last, register
  15.      * the driver which manages those device numbers.
  16.      */ 
  17.     //设备驱动与主设备号一一对应,所以当用户打开主设备号为SPIDEV_MAJOR的设备节点时会调用spidev_fops相关函数BUILD_BUG_ON(N_SPI_MINORS > 256); 
  18.     status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);     
  19.     if (status < 0) 
  20.         return status; 
  21.  
  22.     spidev_class = class_create(THIS_MODULE, "spidev");     //创建spidev_class类 
  23.     if (IS_ERR(spidev_class)) { 
  24.         unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name); 
  25.         return PTR_ERR(spidev_class); 
  26.     } 
  27.  
  28.     status = spi_register_driver(&spidev_spi);  //注册spi_driver 
  29.     if (status < 0) { 
  30.         class_destroy(spidev_class); 
  31.         unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name); 
  32.     } 
  33.     return status; 
  34. } 


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


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


接下来我们看其他函数,这里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. { 
  4.     struct spidev_data  *spidev; 
  5.     ssize_t         status = 0; 
  6.  
  7.     /* chipselect only toggles at start or end of operation */ 
  8.     if (count > bufsiz) 
  9.         return -EMSGSIZE; 
  10.  
  11.     spidev = filp->private_data;     //取出open函数里设置的spidev_data 
  12.  
  13.     mutex_lock(&spidev->buf_lock); 
  14.     status = spidev_sync_read(spidev, count);   //读取数据,见下面分析 
  15.     if (status > 0) { 
  16.         unsigned long   missing; 
  17.  
  18.         missing = copy_to_user(buf, spidev->buffer, status); //向用户空间传送数据 
  19.         if (missing == status) 
  20.             status = -EFAULT; 
  21.         else 
  22.             status = status - missing; 
  23.     } 
  24.     mutex_unlock(&spidev->buf_lock); 
  25.  
  26.     return status; 
  27. } 


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

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


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

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


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

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


通过前面控制器驱动中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. { 
  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.     //得到spi_bitbang,它负责具体的数据发送,这里有个小技巧,在控制器驱动中我们知道spi_master->dev->p->driver_data恰好是struct s3c24xx_spi,而struct spi_bitbang恰好又是struct s3c24xx_spi的第一个成员,故此处可以得到struct spi_bitbang 
  14.     bitbang = spi_master_get_devdata(spi->master);    
  15.  
  16.     spin_lock_irqsave(&bitbang->lock, flags); 
  17.     if (!spi->max_speed_hz) 
  18.         status = -ENETDOWN; 
  19.     else { 
  20.         list_add_tail(&m->queue, &bitbang->queue);  //将message添加到bitbang的消息列表 
  21.         queue_work(bitbang->workqueue, &bitbang->work); //添加工作结构体到工作队列 
  22.     } 
  23.     spin_unlock_irqrestore(&bitbang->lock, flags); 
  24.  
  25.     return status; 
  26. } 


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

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


跟踪s3c24xx_spi_setupxfer函数:

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


跟踪s3c24xx_spi_chipsel函数:

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


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

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


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

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


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


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

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


追踪spidev_message函数:

[csharp]
  1. 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); //对msg进行初始化 
  13.     k_xfers = kcalloc(n_xfers, sizeof(*k_tmp), GFP_KERNEL); 
  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. //主要目的是构建一个spi_message,其实spi_ioc_transfer是spi_transfer的用户空间版本,或者说是映射,具体见英语注释 
  22.     buf = spidev->buffer; 
  23.     total = 0; 
  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) {    //在open中给spidev_data申请了bufsiz大小的buffer,不能超过此值 
  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 *) 
  45.                         (uintptr_t) u_tmp->tx_buf, 
  46.                     u_tmp->len)) 
  47.                 goto done; 
  48.         } 
  49.         buf += k_tmp->len; 
  50.          
  51. //初始化 
  52.         k_tmp->cs_change = !!u_tmp->cs_change; //当前transfer结束影响CS引脚? 
  53.         k_tmp->bits_per_word = u_tmp->bits_per_word; 
  54.         k_tmp->delay_usecs = u_tmp->delay_usecs;  //当前spi_transfer结束后延迟时间 
  55.         k_tmp->speed_hz = u_tmp->speed_hz;//传输速度,可以overwrite对应spi_device的值 
  56. #ifdef VERBOSE 
  57.         dev_dbg(&spi->dev, 
  58.             "  xfer len %zd %s%s%s%dbits %u usec %uHz\n", 
  59.             u_tmp->len, 
  60.             u_tmp->rx_buf ? "rx " : "", 
  61.             u_tmp->tx_buf ? "tx " : "", 
  62.             u_tmp->cs_change ? "cs " : "", 
  63.             u_tmp->bits_per_word ? : spi->bits_per_word, 
  64.             u_tmp->delay_usecs, 
  65.             u_tmp->speed_hz ? : spi->max_speed_hz); 
  66. #endif 
  67.         spi_message_add_tail(k_tmp, &msg); //将spi_transfer通过它的transfer_list字段挂到spi_message的transfer队列上 
  68.     } 
  69.  
  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, 
  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. } 



总结:

设备驱动完成的主要工作就是将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设备,调用其接口实现数据发送。

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