| 
	一、spidev簡(jiǎn)單介紹 
	         如果在內(nèi)核中配置spidev,會(huì)在“/dev”目錄下產(chǎn)生設(shè)備節(jié)點(diǎn),通過(guò)此節(jié)點(diǎn)可以操作掛載在該SPI總線(xiàn)上的設(shè)備,接下來(lái)將從驅(qū)動(dòng)層和應(yīng)用層 
 
	 來(lái)分析程序。 
 
	 二、spidev驅(qū)動(dòng)層 
	 2.1、驅(qū)動(dòng)注冊(cè) 
	         分析一個(gè)設(shè)備驅(qū)動(dòng),一般都是從module_init和module_exit處開(kāi)始,本文也不例外,程序如下: 
 
	
	
		
			
				#define SPIDEV_MAJOR            153    /* assigned */
				#define N_SPI_MINORS            32    /* ... up to 256 */
				
				static DECLARE_BITMAP(minors, N_SPI_MINORS);
				static struct spi_driver spidev_spi_driver = {
				    .driver = {
				        .name =        "spidev",
				        .owner =    THIS_MODULE,
				    },
				    .probe =    spidev_probe,
				    .remove =    __devexit_p(spidev_remove),
				
				    /* NOTE: suspend/resume methods are not necessary here.
				     * We don't do anything except pass the requests to/from
				     * the underlying controller. The refrigerator handles
				     * most issues; the controller driver handles the rest.
				     */
				};
				
				/*-------------------------------------------------------------------------*/
				
				static int __init spidev_init(void)
				{
				    int status;
				
				    /* Claim our 256 reserved device numbers. Then register a class
				     * that will key udev/mdev to add/remove /dev nodes. Last, register
				     * the driver which manages those device numbers.
				     */
				    BUILD_BUG_ON(N_SPI_MINORS > 256);
				    status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);
				    if (status < 0)
				        return status;
				
				    spidev_class = class_create(THIS_MODULE, "spidev");
				    if (IS_ERR(spidev_class)) {
				        unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
				        return PTR_ERR(spidev_class);
				    }
				
				    status = spi_register_driver(&spidev_spi_driver);
				    if (status < 0) {
				        class_destroy(spidev_class);
				        unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
				    }
				    return status;
				}
				module_init(spidev_init);
				
				static void __exit spidev_exit(void)
				{
				    spi_unregister_driver(&spidev_spi_driver);
				    class_destroy(spidev_class);
				    unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
				}
				module_exit(spidev_exit);
				
				MODULE_AUTHOR("Andrea Paterniani, <a.paterniani@swapp-eng.it>");
				MODULE_DESCRIPTION("User mode SPI device interface");
				MODULE_LICENSE("GPL");
				MODULE_ALIAS("spi:spidev"); 
			 
	        說(shuō)明: 
 
	         1) 在驅(qū)動(dòng)注冊(cè)函數(shù)中,首先注冊(cè)函數(shù)操作集spidev_fops,該內(nèi)容將在2.3中具體講述。 
 
	         2) 生成spidev設(shè)備類(lèi),此類(lèi)的表現(xiàn)是在“/sys/class”目錄下生成一個(gè)名為spidev目錄。 
 
	         3) 注冊(cè)spi驅(qū)動(dòng)。 
 
	         4) 退出函數(shù)是注冊(cè)函數(shù)的相反過(guò)程,就是釋放注冊(cè)函數(shù)中注冊(cè)的資源。 
 
	 2.2、探測(cè)和移除函數(shù) 
	         探測(cè)函數(shù)程序如下: 
 
	
	
		
			
				static int __devinit spidev_probe(struct spi_device *spi)
				{
				    struct spidev_data    *spidev;
				    int            status;
				    unsigned long        minor;
				
				    /* Allocate driver data */
				    spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);
				    if (!spidev)
				        return -ENOMEM;
				
				    /* Initialize the driver data */
				    spidev->spi = spi;
				    spin_lock_init(&spidev->spi_lock);
				    mutex_init(&spidev->buf_lock);
				
				    INIT_LIST_HEAD(&spidev->device_entry);
				
				    /* If we can allocate a minor number, hook up this device.
				     * Reusing minors is fine so long as udev or mdev is working.
				     */
				    mutex_lock(&device_list_lock);
				    minor = find_first_zero_bit(minors, N_SPI_MINORS);
				    if (minor < N_SPI_MINORS) {
				        struct device *dev;
				
				        spidev->devt = MKDEV(SPIDEV_MAJOR, minor);
				        dev = device_create(spidev_class, &spi->dev, spidev->devt,
				                    spidev, "spidev%d.%d",
				                    spi->master->bus_num, spi->chip_select);
				        status = IS_ERR(dev) ? PTR_ERR(dev) : 0;
				    } else {
				        dev_dbg(&spi->dev, "no minor number available!\n");
				        status = -ENODEV;
				    }
				    if (status == 0) {
				        set_bit(minor, minors);
				        list_add(&spidev->device_entry, &device_list);
				    }
				    mutex_unlock(&device_list_lock);
				
				    if (status == 0)
				        spi_set_drvdata(spi, spidev);
				    else
				        kfree(spidev);
				
				    return status;
				} 
			 
	        說(shuō)明: 
 
	         1) 首先聲明spidev_data結(jié)構(gòu)體內(nèi)存。 
 
	         2) 初始化其成員變量。 
 
	         3) 在位圖中尋找第一個(gè)未被用到的位。 
 
	         4) 如果位圖尋找正確,創(chuàng)建“/dev”目錄下的設(shè)備節(jié)點(diǎn)。 
 
	         4) 將spidev結(jié)構(gòu)體中的鏈表插入局部全局鏈表device_list中,以便在函數(shù)操作集中的open函數(shù)中使用             
 
	         移除函數(shù)如下: 
 
	
	
		
			
				static int __devexit spidev_remove(struct spi_device *spi)
				{
				    struct spidev_data    *spidev = spi_get_drvdata(spi);
				
				    /* make sure ops on existing fds can abort cleanly */
				    spin_lock_irq(&spidev->spi_lock);
				    spidev->spi = NULL;
				    spi_set_drvdata(spi, NULL);
				    spin_unlock_irq(&spidev->spi_lock);
				
				    /* prevent new opens */
				    mutex_lock(&device_list_lock);
				    list_del(&spidev->device_entry);
				    device_destroy(spidev_class, spidev->devt);
				    clear_bit(MINOR(spidev->devt), minors);
				    if (spidev->users == 0)
				        kfree(spidev);
				    mutex_unlock(&device_list_lock);
				
				    return 0;
				} 
			 
	        說(shuō)明: 
 
	         1) 移除函數(shù)就是探測(cè)函數(shù)的相反過(guò)程,主要就是釋放探測(cè)函數(shù)中申請(qǐng)的資源。 
 
	 2.2、函數(shù)操作集spidev_fop 
	         spidev_fop具體如下: 
 
	
	
		
			
				static const struct file_operations spidev_fops = {
				    .owner =    THIS_MODULE,
				    /* REVISIT switch to aio primitives, so that userspace
				     * gets more complete API coverage. It'll simplify things
				     * too, except for the locking.
				     */
				    .write =    spidev_write,
				    .read =        spidev_read,
				    .unlocked_ioctl = spidev_ioctl,
				    .compat_ioctl = spidev_compat_ioctl,
				    .open =        spidev_open,
				    .release =    spidev_release,
				    .llseek =    no_llseek,
				}; 
			 
	        首先看下打開(kāi)函數(shù)spidev_open,程序如下: 
 
	
	
		
			
				static int spidev_open(struct inode *inode, struct file *filp)
				{
				    struct spidev_data    *spidev;
				    int            status = -ENXIO;
				
				    mutex_lock(&device_list_lock);
				
				    list_for_each_entry(spidev, &device_list, device_entry) {
				        if (spidev->devt == inode->i_rdev) {
				            status = 0;
				            break;
				        }
				    }
				    if (status == 0) {
				        if (!spidev->buffer) {
				            spidev->buffer = kmalloc(bufsiz, GFP_KERNEL);
				            if (!spidev->buffer) {
				                dev_dbg(&spidev->spi->dev, "open/ENOMEM\n");
				                status = -ENOMEM;
				            }
				        }
				        if (status == 0) {
				            spidev->users++;
				            filp->private_data = spidev;
				            nonseekable_open(inode, filp);
				        }
				    } else
				        pr_debug("spidev: nothing for minor %d\n", iminor(inode));
				
				    mutex_unlock(&device_list_lock);
				    return status;
				} 
			 
	        說(shuō)明: 
 
	         1) 程序首先上本地全局互斥鎖。 
 
	         2) 遍歷鏈表device_list,通過(guò)設(shè)備號(hào)找到在探測(cè)函數(shù)中創(chuàng)建的設(shè)備結(jié)構(gòu)體spidev。 
 
	         3) 如果尋找成功,將其保存在file的私有成員中,供其他操作集中的函數(shù)使用。 
 
	        realease函數(shù)如下: 
 
	
	
		
			
				static int spidev_release(struct inode *inode, struct file *filp)
				{
				    struct spidev_data    *spidev;
				    int            status = 0;
				
				    mutex_lock(&device_list_lock);
				    spidev = filp->private_data;
				    filp->private_data = NULL;
				
				    /* last close? */
				    spidev->users--;
				    if (!spidev->users) {
				        int        dofree;
				
				        kfree(spidev->buffer);
				        spidev->buffer = NULL;
				
				        /* ... after we unbound from the underlying device? */
				        spin_lock_irq(&spidev->spi_lock);
				        dofree = (spidev->spi == NULL);
				        spin_unlock_irq(&spidev->spi_lock);
				
				        if (dofree)
				            kfree(spidev);
				    }
				    mutex_unlock(&device_list_lock);
				
				    return status;
				} 
			 
	        說(shuō)明: 
 
	        1) 首先減少使用次數(shù)。 
 
	        2) 釋放傳輸buf空間。 
 
	        3) 釋放結(jié)構(gòu)體內(nèi)存。 
 
	         spi讀數(shù)據(jù)函數(shù)如下: 
 
	
	
		
			
				static inline ssize_t
				spidev_sync_read(struct spidev_data *spidev, size_t len)
				{
				    struct spi_transfer    t = {
				            .rx_buf        = spidev->buffer,
				            .len        = len,
				        };
				    struct spi_message    m;
				
				    spi_message_init(&m);
				    spi_message_add_tail(&t, &m);
				    return spidev_sync(spidev, &m);
				}
				static ssize_t
				spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
				{
				    struct spidev_data    *spidev;
				    ssize_t            status = 0;
				
				    /* chipselect only toggles at start or end of operation */
				    if (count > bufsiz)
				        return -EMSGSIZE;
				
				    spidev = filp->private_data;
				
				    mutex_lock(&spidev->buf_lock);
				    status = spidev_sync_read(spidev, count);
				    if (status > 0) {
				        unsigned long    missing;
				
				        missing = copy_to_user(buf, spidev->buffer, status);
				        if (missing == status)
				            status = -EFAULT;
				        else
				            status = status - missing;
				    }
				    mutex_unlock(&spidev->buf_lock);
				
				    return status;
				} 
			 
	        說(shuō)明: 
 
	         1) 進(jìn)入讀函數(shù)中,首先上互斥鎖。 
 
	         2) 然后調(diào)用spidev_sync_read函數(shù)讀數(shù)據(jù)。 
 
	         3) 如果讀取成功,將讀取到的數(shù)據(jù)拷貝到應(yīng)用層。 
 
	         4) 解互斥鎖。 
 
	         5) 在spidev_sync_read函數(shù)中,首先定義一個(gè)傳輸結(jié)構(gòu)體spi_transfer,由于是讀操作,所以只初始化其接收buf。 
 
	         6) 初始化spi_message,調(diào)用函數(shù)spidev_sync傳輸數(shù)據(jù),其具體程序如下: 
 
	
	
		
			
				static ssize_t
				spidev_sync(struct spidev_data *spidev, struct spi_message *message)
				{
				    DECLARE_COMPLETION_ONSTACK(done);
				    int status;
				
				    message->complete = spidev_complete;
				    message->context = &done;
				
				    spin_lock_irq(&spidev->spi_lock);
				    if (spidev->spi == NULL)
				        status = -ESHUTDOWN;
				    else
				        status = spi_async(spidev->spi, message);
				    spin_unlock_irq(&spidev->spi_lock);
				
				    if (status == 0) {
				        wait_for_completion(&done);
				        status = message->status;
				        if (status == 0)
				            status = message->actual_length;
				    }
				    return status;
				} 
			 
	        說(shuō)明: 
 
	         1) 首先定義并初始化一個(gè)completion。 
 
	         2) 上自旋鎖,調(diào)用spi_async函數(shù)傳輸數(shù)據(jù),spi_async就是在Linux核心中提供的傳輸函數(shù)。 
 
	         3) 如果調(diào)用傳輸函數(shù)成功,則等待。 
 
	         3) wait_for_completion(&done);等待傳輸完成,如果傳輸正確,函數(shù)返回值為傳輸?shù)淖止?jié)數(shù)。 
 
	         函數(shù)操作集寫(xiě)函數(shù)spidev_write程序如下: 
 
	
	
		
			
				static inline ssize_t
				spidev_sync_write(struct spidev_data *spidev, size_t len)
				{
				    struct spi_transfer    t = {
				            .tx_buf        = spidev->buffer,
				            .len        = len,
				        };
				    struct spi_message    m;
				
				    spi_message_init(&m);
				    spi_message_add_tail(&t, &m);
				    return spidev_sync(spidev, &m);
				}
				static ssize_t
				spidev_write(struct file *filp, const char __user *buf,
				        size_t count, loff_t *f_pos)
				{
				    struct spidev_data    *spidev;
				    ssize_t            status = 0;
				    unsigned long        missing;
				
				    /* chipselect only toggles at start or end of operation */
				    if (count > bufsiz)
				        return -EMSGSIZE;
				
				    spidev = filp->private_data;
				
				    mutex_lock(&spidev->buf_lock);
				    missing = copy_from_user(spidev->buffer, buf, count);
				    if (missing == 0) {
				        status = spidev_sync_write(spidev, count);
				    } else
				        status = -EFAULT;
				    mutex_unlock(&spidev->buf_lock);
				
				    return status;
				} 
			 
	        說(shuō)明: 
 
	         1) 寫(xiě)函數(shù)首先上互斥鎖,然后從應(yīng)用層拷貝需要寫(xiě)的數(shù)據(jù)。 
 
	         2) 如果拷貝成功,調(diào)用函數(shù)spidev_sync_write完成寫(xiě)數(shù)據(jù)。 
 
	         3) 解互斥鎖。 
 
	         4) spidev_sync_write函數(shù)中,首先定義spi_transfer傳輸結(jié)構(gòu)體,由于是寫(xiě),此結(jié)構(gòu)體只有tx_buf。 
 
	         5) 初始化spi_message,然后調(diào)用spidev_sync傳輸數(shù)據(jù),此函數(shù)在上面的讀操作中已經(jīng)講述。 
 
	         ioctl函數(shù)如下: 
 
	
	
		
			
				static long
				spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
				{
				    int            err = 0;
				    int            retval = 0;
				    struct spidev_data    *spidev;
				    struct spi_device    *spi;
				    u32            tmp;
				    unsigned        n_ioc;
				    struct spi_ioc_transfer    *ioc;
				
				    /* Check type and command number */
				    if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC)
				        return -ENOTTY;
				
				    /* Check access direction once here; don't repeat below.
				     * IOC_DIR is from the user perspective, while access_ok is
				     * from the kernel perspective; so they look reversed.
				     */
				    if (_IOC_DIR(cmd) & _IOC_READ)
				        err = !access_ok(VERIFY_WRITE,
				                (void __user *)arg, _IOC_SIZE(cmd));
				    if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)
				        err = !access_ok(VERIFY_READ,
				                (void __user *)arg, _IOC_SIZE(cmd));
				    if (err)
				        return -EFAULT;
				
				    /* guard against device removal before, or while,
				     * we issue this ioctl.
				     */
				    spidev = filp->private_data;
				    spin_lock_irq(&spidev->spi_lock);
				    spi = spi_dev_get(spidev->spi);
				    spin_unlock_irq(&spidev->spi_lock);
				
				    if (spi == NULL)
				        return -ESHUTDOWN;
				
				    /* use the buffer lock here for triple duty:
				     * - prevent I/O (from us) so calling spi_setup() is safe;
				     * - prevent concurrent SPI_IOC_WR_* from morphing
				     * data fields while SPI_IOC_RD_* reads them;
				     * - SPI_IOC_MESSAGE needs the buffer locked "normally".
				     */
				    mutex_lock(&spidev->buf_lock);
				
				    switch (cmd) {
				    /* read requests */
				    case SPI_IOC_RD_MODE:
				        retval = __put_user(spi->mode & SPI_MODE_MASK,
				                    (__u8 __user *)arg);
				        break;
				    case SPI_IOC_RD_LSB_FIRST:
				        retval = __put_user((spi->mode & SPI_LSB_FIRST) ? 1 : 0,
				                    (__u8 __user *)arg);
				        break;
				    case SPI_IOC_RD_BITS_PER_WORD:
				        retval = __put_user(spi->bits_per_word, (__u8 __user *)arg);
				        break;
				    case SPI_IOC_RD_MAX_SPEED_HZ:
				        retval = __put_user(spi->max_speed_hz, (__u32 __user *)arg);
				        break;
				
				    /* write requests */
				    case SPI_IOC_WR_MODE:
				        retval = __get_user(tmp, (u8 __user *)arg);
				        if (retval == 0) {
				            u8    save = spi->mode;
				
				            if (tmp & ~SPI_MODE_MASK) {
				                retval = -EINVAL;
				                break;
				            }
				
				            tmp |= spi->mode & ~SPI_MODE_MASK;
				            spi->mode = (u8)tmp;
				            retval = spi_setup(spi);
				            if (retval < 0)
				                spi->mode = save;
				            else
				                dev_dbg(&spi->dev, "spi mode %02x\n", tmp);
				        }
				        break;
				    case SPI_IOC_WR_LSB_FIRST:
				        retval = __get_user(tmp, (__u8 __user *)arg);
				        if (retval == 0) {
				            u8    save = spi->mode;
				
				            if (tmp)
				                spi->mode |= SPI_LSB_FIRST;
				            else
				                spi->mode &= ~SPI_LSB_FIRST;
				            retval = spi_setup(spi);
				            if (retval < 0)
				                spi->mode = save;
				            else
				                dev_dbg(&spi->dev, "%csb first\n",
				                        tmp ? 'l' : 'm');
				        }
				        break;
				    case SPI_IOC_WR_BITS_PER_WORD:
				        retval = __get_user(tmp, (__u8 __user *)arg);
				        if (retval == 0) {
				            u8    save = spi->bits_per_word;
				
				            spi->bits_per_word = tmp;
				            retval = spi_setup(spi);
				            if (retval < 0)
				                spi->bits_per_word = save;
				            else
				                dev_dbg(&spi->dev, "%d bits per word\n", tmp);
				        }
				        break;
				    case SPI_IOC_WR_MAX_SPEED_HZ:
				        retval = __get_user(tmp, (__u32 __user *)arg);
				        if (retval == 0) {
				            u32    save = spi->max_speed_hz;
				
				            spi->max_speed_hz = tmp;
				            retval = spi_setup(spi);
				            if (retval < 0)
				                spi->max_speed_hz = save;
				            else
				                dev_dbg(&spi->dev, "%d Hz (max)\n", tmp);
				        }
				        break;
				
				    default:
				        /* segmented and/or full-duplex I/O request */
				        if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0))
				                || _IOC_DIR(cmd) != _IOC_WRITE) {
				            retval = -ENOTTY;
				            break;
				        }
				
				        tmp = _IOC_SIZE(cmd);
				        if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) {
				            retval = -EINVAL;
				            break;
				        }
				        n_ioc = tmp / sizeof(struct spi_ioc_transfer);
				        if (n_ioc == 0)
				            break;
				
				        /* copy into scratch area */
				        ioc = kmalloc(tmp, GFP_KERNEL);
				        if (!ioc) {
				            retval = -ENOMEM;
				            break;
				        }
				        if (__copy_from_user(ioc, (void __user *)arg, tmp)) {
				            kfree(ioc);
				            retval = -EFAULT;
				            break;
				        }
				
				        /* translate to spi_message, execute */
				        retval = spidev_message(spidev, ioc, n_ioc);
				        kfree(ioc);
				        break;
				    }
				
				    mutex_unlock(&spidev->buf_lock);
				    spi_dev_put(spi);
				    return retval;
				} 
			 
	        說(shuō)明: 
 
	        1) 函數(shù)首先判斷命令是否有效,如果無(wú)效,直接退出。 
 
	        2) 上互斥鎖。 
 
	         3) switch分支中,前面的case都是支持對(duì)SPI設(shè)備的設(shè)置,包括模式、傳輸位、位方向和最大速率等。 
 
	         4) 在設(shè)置分支中,最后調(diào)用spi_setup實(shí)現(xiàn)設(shè)置,此函數(shù)最終是調(diào)用總線(xiàn)驅(qū)動(dòng)中的gsc3280_spi_setup(struct spi_device *spi) 
 
	實(shí)現(xiàn)設(shè)置。 
 
	         5) default分支中是進(jìn)行數(shù)據(jù)傳輸?shù)姆种?,首先判斷是否是有效的?shù)據(jù),如果不是,退出switch分支。 
 
	        6) 申請(qǐng)內(nèi)存,復(fù)制從應(yīng)用層傳過(guò)來(lái)的數(shù)據(jù)。 
 
	        7) 調(diào)用spidev_message函數(shù)實(shí)現(xiàn)數(shù)據(jù)傳輸。 
 
	        8) 解互斥鎖,退出。 
 
	         spidev_message函數(shù)如下: 
 
	
	
		
			
				static int spidev_message(struct spidev_data *spidev,
				        struct spi_ioc_transfer *u_xfers, unsigned n_xfers)
				{
				    struct spi_message    msg;
				    struct spi_transfer    *k_xfers;
				    struct spi_transfer    *k_tmp;
				    struct spi_ioc_transfer *u_tmp;
				    unsigned        n, total;
				    u8            *buf;
				    int            status = -EFAULT;
				
				    spi_message_init(&msg);
				    k_xfers = kcalloc(n_xfers, sizeof(*k_tmp), GFP_KERNEL);
				    if (k_xfers == NULL)
				        return -ENOMEM;
				
				    /* Construct spi_message, copying any tx data to bounce buffer.
				     * We walk the array of user-provided transfers, using each one
				     * to initialize a kernel version of the same transfer.
				     */
				    buf = spidev->buffer;
				    total = 0;
				    for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;
				            n;
				            n--, k_tmp++, u_tmp++) {
				        k_tmp->len = u_tmp->len;
				
				        total += k_tmp->len;
				        if (total > bufsiz) {
				            status = -EMSGSIZE;
				            goto done;
				        }
				
				        if (u_tmp->rx_buf) {
				            k_tmp->rx_buf = buf;
				            if (!access_ok(VERIFY_WRITE, (u8 __user *)
				                        (uintptr_t) u_tmp->rx_buf,
				                        u_tmp->len))
				                goto done;
				        }
				        if (u_tmp->tx_buf) {
				            k_tmp->tx_buf = buf;
				            if (copy_from_user(buf, (const u8 __user *)
				                        (uintptr_t) u_tmp->tx_buf,
				                    u_tmp->len))
				                goto done;
				        }
				        buf += k_tmp->len;
				
				        k_tmp->cs_change = !!u_tmp->cs_change;
				        k_tmp->bits_per_word = u_tmp->bits_per_word;
				        k_tmp->delay_usecs = u_tmp->delay_usecs;
				        k_tmp->speed_hz = u_tmp->speed_hz;
				#ifdef VERBOSE
				        dev_dbg(&spidev->spi->dev,
				            "  xfer len %zd %s%s%s%dbits %u usec %uHz\n",
				            u_tmp->len,
				            u_tmp->rx_buf ? "rx " : "",
				            u_tmp->tx_buf ? "tx " : "",
				            u_tmp->cs_change ? "cs " : "",
				            u_tmp->bits_per_word ? : spidev->spi->bits_per_word,
				            u_tmp->delay_usecs,
				            u_tmp->speed_hz ? : spidev->spi->max_speed_hz);
				#endif
				        spi_message_add_tail(k_tmp, &msg);
				    }
				
				    status = spidev_sync(spidev, &msg);
				    if (status < 0)
				        goto done;
				
				    /* copy any rx data out of bounce buffer */
				    buf = spidev->buffer;
				    for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) {
				        if (u_tmp->rx_buf) {
				            if (__copy_to_user((u8 __user *)
				                    (uintptr_t) u_tmp->rx_buf, buf,
				                    u_tmp->len)) {
				                status = -EFAULT;
				                goto done;
				            }
				        }
				        buf += u_tmp->len;
				    }
				    status = total;
				
				done:
				    kfree(k_xfers);
				    return status;
				} 
			 
	        說(shuō)明: 
 
	        1) 申請(qǐng)傳輸?shù)慕Y(jié)構(gòu)體內(nèi)存。 
 
	         2) 通過(guò)for循環(huán),對(duì)spi_ioc_transfer類(lèi)型的數(shù)據(jù)進(jìn)行轉(zhuǎn)換。 
 
	        3) 轉(zhuǎn)換中,首先對(duì)本次傳輸?shù)臄?shù)據(jù)大小進(jìn)行累計(jì),如果總傳輸量超出buf的大小,直接退出。 
 
	         4) 如果本次傳輸是接收,則設(shè)置接收數(shù)組,并對(duì)buf進(jìn)行檢查,查看是否可讀。 
 
	         5) 如果本次傳輸是寫(xiě),則從應(yīng)用層拷貝數(shù)據(jù)。 
 
	        6) 對(duì)傳輸中參數(shù)進(jìn)行賦值,包括速度、模式、速率等等。 
 
	        7) 調(diào)用spidev_sync進(jìn)行數(shù)據(jù)傳輸。 
 
	        8) 將接收數(shù)據(jù)拷貝到應(yīng)用層。 
 
	三、應(yīng)用層 
	        在應(yīng)用層提供了二中驅(qū)動(dòng)的測(cè)試程序,在“/documenation/spi”目錄下,文件名稱(chēng)為spidev_test.c中,具體程序如下: 
 
	
	
		
			
				int main(int argc, char *argv[])
				{
				    int ret = 0;
				    int fd;
				
				    parse_opts(argc, argv);
				
				    fd = open(device, O_RDWR);
				    if (fd < 0)
				        pabort("can't open device");
				
				    /*
				     * spi mode
				     */
				    ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
				    if (ret == -1)
				        pabort("can't set spi mode");
				
				    ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
				    if (ret == -1)
				        pabort("can't get spi mode");
				
				    /*
				     * bits per word
				     */
				    ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
				    if (ret == -1)
				        pabort("can't set bits per word");
				
				    ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
				    if (ret == -1)
				        pabort("can't get bits per word");
				
				    /*
				     * max speed hz
				     */
				    ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
				    if (ret == -1)
				        pabort("can't set max speed hz");
				
				    ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
				    if (ret == -1)
				        pabort("can't get max speed hz");
				
				    printf("spi mode: %d\n", mode);
				    printf("bits per word: %d\n", bits);
				    printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
				
				    transfer(fd);
				
				    close(fd);
				
				    return ret;
				} 
			 
	        說(shuō)明: 
 
	        1) 首先打開(kāi)設(shè)備。 
 
	        2) 然后設(shè)置工作模式、位大小和速率等。 
 
	         3) 傳輸數(shù)據(jù) 
 |