Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1154680
  • 博文数量: 241
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 2279
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-27 19:53
个人简介

JustForFun

文章分类

全部博文(241)

文章存档

2023年(8)

2022年(2)

2021年(3)

2020年(30)

2019年(11)

2018年(27)

2017年(54)

2016年(83)

2015年(23)

我的朋友

分类: LINUX

2018-12-16 21:55:09

 spi.c是spi子系统初始化的核心代码,由内核负责初始化
spidev.c是spi用户接口初始化的代码,编译的时候需要选择该模块
spi_sam.c是平台驱动的初始化代码,编译时需要选择spi s3c64xx模块
drivers/spi/spi_test.c 这个文件可以细看,是详细分析spi驱动的好文件。

spi.c也就是spi子系统的核心了,
spi_sam.c是s3c64xx系列芯片的SPI controller驱动,它向更上层的SPI核心层(spi.c)提供接口用来控制芯片的SPI controller,是一个被其他驱动使用的驱动。
spidev.c是在核心层基础之上将SPI controller模拟成一个字符型的驱动,向文件系统提供标准的文件系统接口,用来操作对应的SPI controller

////////////////////////////////////////////////////////////////////////////////////////////////////////////////

module_init(spidev_init);
/*-------------------------------------------------------------------------*/

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);
//字符设备注册,将SPI注册为字符设备,绑定操作函数集合spidev_fops
//注册字符设备,参数spidev_fops是struct file_operations的实例,这里就可以知道,用户程序的open、//write等操作最终会调用这里面的函数
    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.name);
        return PTR_ERR(spidev_class);
    }
 /*注册spidev的driver,可与modalias字段为"spidev"的spi_device匹配*/ 
    status = spi_register_driver(&spidev_spi);
    if (status < 0) {
        class_destroy(spidev_class);
        unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
    }
    return status;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////


static 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,
    .open =        spidev_open,
    .release =    spidev_release,
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
第12章 SPI只是一种总线,spi_driver的作用只是将SPI外设挂接在总线上,因此在spi_driver的probe()成员函数中,将注册SPI外设本身所属设备驱动的类型

static struct spi_driver spidev_spi = {
                    /*spidev的driver,可与modalias字段为"spidev"的spi_device匹配*/ 
                   //

                    //static struct spi_board_info __initdata sam_spi_devs[] = {
                    //   [0] = {    .modalias     = "spidev", /* Test Interface */
 

    .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.
     */
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
spi子系统初始化的核心代码在spi.c里

/**
 * spi_register_driver - register a SPI driver
 * @sdrv: the driver to register
 * Context: can sleep
 */
int spi_register_driver(struct spi_driver *sdrv)
{
//spi注册驱动的.bus注意看看
    sdrv->driver.bus = &spi_bus_type;
    if (sdrv->probe)
        sdrv->driver.probe = spi_drv_probe;
    if (sdrv->remove)
        sdrv->driver.remove = spi_drv_remove;
    if (sdrv->shutdown)
        sdrv->driver.shutdown = spi_drv_shutdown;
    return driver_register(&sdrv->driver);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
spi子系统初始化的核心代码在spi.c里

spi_bus_type对应SPI中的SPI BUS总线
struct bus_type spi_bus_type = {
    .name        = "spi",
    .dev_attrs    = spi_dev_attrs,
//驱动和设备匹配时调用.match函数进行匹配
//匹配成功后调用驱动的.probe函数
    .match        = spi_match_device,
    .uevent        = spi_uevent,
    .suspend    = spi_suspend,
    .resume        = spi_resume,
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
spi子系统初始化的核心代码在spi.c里

/* modalias support makes "modprobe $MODALIAS" new-style hotplug work,
 * and the sysfs version makes coldplug work too.
 */
//匹配函数
static int spi_match_device(struct device *dev, struct device_driver *drv)
{
    const struct spi_device    *spi = to_spi_device(dev);

    return strncmp(spi->modalias, drv->name, BUS_ID_SIZE) == 0;

  /*spidev的driver,可与modalias字段为"spidev"的spi_device匹配*/ 
  //

  //static struct spi_board_info __initdata sam_spi_devs[] = {
   //   [0] = {    .modalias     = "spidev", /* Test Interface */
//
//static struct spi_driver spidev_spi = {
  .driver = { .name =        "spidev",
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////

/*
 * INTERFACES between SPI master-side drivers and SPI infrastructure.
 * (There's no SPI slave support for Linux yet...)
 */
extern struct bus_type spi_bus_type;

/**
 * struct spi_device - Master side proxy for an SPI slave device
 * @dev: Driver model representation of the device.
 * @master: SPI controller used with the device.
 * @max_speed_hz: Maximum clock rate to be used with this chip
 *    (on this board); may be changed by the device's driver.
 *    The spi_transfer.speed_hz can override this for each transfer.
 * @chip_select: Chipselect, distinguishing chips handled by @master.
 * @mode: The spi mode defines how data is clocked out and in.
 *    This may be changed by the device's driver.
 *    The "active low" default for chipselect mode can be overridden
 *    (by specifying SPI_CS_HIGH) as can the "MSB first" default for
 *    each word in a transfer (by specifying SPI_LSB_FIRST).
 * @bits_per_word: Data transfers involve one or more words; word sizes
 *    like eight or 12 bits are common.  In-memory wordsizes are
 *    powers of two bytes (e.g. 20 bit samples use 32 bits).
 *    This may be changed by the device's driver, or left at the
 *    default (0) indicating protocol words are eight bit bytes.
 *    The spi_transfer.bits_per_word can override this for each transfer.
 * @irq: Negative, or the number passed to request_irq() to receive
 *    interrupts from this device.
 * @controller_state: Controller's runtime state
 * @controller_data: Board-specific definitions for controller, such as
 *    FIFO initialization parameters; from board_info.controller_data
 * @modalias: Name of the driver to use with this device, or an alias
 *    for that name.  This appears in the sysfs "modalias" attribute
 *    for driver coldplugging, and in uevents used for hotplugging

 *
 * A @spi_device is used to interchange data between an SPI slave
 * (usually a discrete chip) and CPU memory.
 *
 * In @dev, the platform_data is used to hold information about this
 * device that's meaningful to the device's protocol driver, but not
 * to its controller.  One example might be an identifier for a chip
 * variant with slightly different functionality; another might be
 * information about how this particular board wires the chip's pins.
 */
//用spi_device来描述一个SPI外设设备
struct spi_device {
    struct device        dev;
//
.modalias     = "spidev"的一对(设备和驱动)module_init(spidev_init)
 
//通过内部包含
struct spi_master    *master;成员
//与
.name    = "sam-spi",的一对(平台设备和驱动)module_init(sam_spi_init);联系起来,
//平台设备驱动
通过samspi_probe 函数------>spi_alloc_master产生并赋值struct spi_master实例
//见
static inline int spi_async(struct spi_device *spi, struct spi_message *message) 
    struct spi_master    *master;//对应的控制器指针
    u32            max_speed_hz; //spi通信的时钟
    u8            chip_select; //片选,用于区分同一总线上的不同设备
    u8            mode;
#define    SPI_CPHA    0x01            /* clock phase */
#define    SPI_CPOL    0x02            /* clock polarity */
#define    SPI_MODE_0    (0|0)            /* (original MicroWire) */
#define    SPI_MODE_1    (0|SPI_CPHA)
#define    SPI_MODE_2    (SPI_CPOL|0)
#define    SPI_MODE_3    (SPI_CPOL|SPI_CPHA)
#define    SPI_CS_HIGH    0x04            /* chipselect active high? */
#define    SPI_LSB_FIRST    0x08            /* per-word bits-on-wire */
#define    SPI_3WIRE    0x10            /* SI/SO signals shared */
#define    SPI_LOOP    0x20            /* loopback mode */
#define    SPI_SLAVE    0x40            /* SLAVE mode if this bit is set */

#define SPIDEV_MAX_BUFFSIZE    16384

    u8            bits_per_word;  //每个字长的比特数 
    int            irq; //使用的中断  
    void            *controller_state;
    void            *controller_data;
    char            modalias[32]; //名字  ,用来匹配

    /*
     * likely need more hooks for more protocol options affecting how
     * the controller talks to each chip, like:
     *  - memory packing (12 bit samples into low bits, others zeroed)
     *  - priority
     *  - drop chipselect after each word
     *  - chipselect delays
     *  - ...
     */
};
///////////////////////////////

/**
 * struct spi_driver - Host side "protocol" driver
 * @probe: Binds this driver to the spi device.  Drivers can verify
 *    that the device is actually present, and may need to configure
 *    characteristics (such as bits_per_word) which weren't needed for
 *    the initial configuration done during system setup.
 * @remove: Unbinds this driver from the spi device
 * @shutdown: Standard shutdown callback used during system state
 *    transitions such as powerdown/halt and kexec
 * @suspend: Standard suspend callback used during system state transitions
 * @resume: Standard resume callback used during system state transitions
 * @driver: SPI device drivers should initialize the name and owner
 *    field of this structure.
 *
 * This represents the kind of device driver that uses SPI messages to
 * interact with the hardware at the other end of a SPI link.  It's called
 * a "protocol" driver because it works through messages rather than talking
 * directly to SPI hardware (which is what the underlying SPI controller
 * driver does to pass those messages).  These protocols are defined in the
 * specification for the device(s) supported by the driver.
 *
 * As a rule, those device protocols represent the lowest level interface
 * supported by a driver, and it will support upper level interfaces too.
 * Examples of such upper levels include frameworks like MTD, networking,
 * MMC, RTC, filesystem character device nodes, and hardware monitoring.
 */
//用spi_driver来描述一个SPI外设驱动
struct spi_driver {
    int            (*probe)(struct spi_device *spi);
    int            (*remove)(struct spi_device *spi);
    void            (*shutdown)(struct spi_device *spi);
    int            (*suspend)(struct spi_device *spi, pm_message_t mesg);
    int            (*resume)(struct spi_device *spi);
    struct device_driver    driver;
};
图片
//spi_device与spi_master是同一个父设备,这是在spi_new_device()-->spi_alloc_device函数中设定的,
//一般这个设备是一个物理设备

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


/*-------------------------------------------------------------------------*/

/* Read-only message with current device setup */
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;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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 */
//设置SPI读模式
    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 */
//设置SPI成写模式
    case SPI_IOC_WR_MODE:
        retval = __get_user(tmp, (u8 __user *)arg);
        if (retval == 0) {
//先将SPI之前的模式保存起来,一旦设置失败,进行回复
            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);
//如果这些数据不能分成spi_ioc_transfer的整数倍,则不能进行传输
        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;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static int spidev_open(struct inode *inode, struct file *filp)
{
    struct spidev_data    *spidev;
    int            status = -ENXIO;

    lock_kernel();
    mutex_lock(&device_list_lock);
//    static LIST_HEAD(device_list);
//通过链表头device_list和节点 device_entry获取到包含成员device_entry的 struct spidev_data    *spidev;,而且是遍历链表
    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++;
//spidev_read是从filp->private_data里取出spidev
            filp->private_data = spidev;
            nonseekable_open(inode, filp);
        }
    } else
        pr_debug("spidev: nothing for minor %d\n", iminor(inode));

    mutex_unlock(&device_list_lock);
    unlock_kernel();
    return status;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

//-书中说probe是用来查询特定设备是否存在的函数
//驱动和设备匹配成功后会调用spidev_probe
//这个函数实现把spidev添加到device_list

static int 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);
//spidev->device_entry这个链表节点插入了device_list中,这样spidev就可以通过device_list而获取到了
        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;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

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的链表头
    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(&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 ? : spi->bits_per_word,
            u_tmp->delay_usecs,
            u_tmp->speed_hz ? : spi->max_speed_hz);
#endif
//将spi_transfer类型的实体k_tmp通过transfer_list字段挂到spi_message的transfer队列上
        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;
}
////////////////////////////////////////////////////////////////////////////////////////////////////


static ssize_t
spidev_sync(struct spidev_data *spidev, struct spi_message *message)
{
//声明并初始化一个完成量
    DECLARE_COMPLETION_ONSTACK(done);
    int status;
//指定spi_message结构实例的完成量complete函数指针赋值
//handle_msg函数有一行    if(msg->complete)  msg->complete(msg->context);
//这行调用的便是
spidev_complete这个函数
    message->complete = spidev_complete;
    message->context = &done;

    spin_lock_irq(&spidev->spi_lock);
    if (spidev->spi == NULL)
        status = -ESHUTDOWN;
    else
//调用spi核心中的函数进行数据传输
        status = spi_async(spidev->spi, message);
    spin_unlock_irq(&spidev->spi_lock);

    if (status == 0) {
//等待完成量被唤醒
//handle_msg函数有一行    if(msg->complete)  msg->complete(msg->context);
//这行调用的便是
spidev_complete这个函数 ,当msg->complete(msg->context);调用后此处被唤醒往下执行
        wait_for_completion(&done);
        status = message->status;
        if (status == 0)
            status = message->actual_length;
    }
    return status;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

static inline int
spi_async(struct spi_device *spi, struct spi_message *message)
{
    message->spi = spi;

//看看.name =        "spidev"的这对设备和驱动
//在这里与.name    = "sam-spi",的一对平台设备和驱动联系起来
//
module_init(spidev_init);与
//
module_init(sam_spi_init);这两个模块的连接点在这行程序里体现
//
struct spi_device里的master成员是什么时候赋值过去的?
//samspi_probe(struct platform_device *pdev)
------>spi_register_master(master);
//---------->scan_boardinfo(master);------->spi_new_device(master, chip);--------->proxy = spi_alloc_device(master);
///在spi_alloc_device函数里有一行spi->master = master;,返回值 return spi;
/////////这个便是调用samspi_transfer函数了。数据的发送传输
    return spi->master->transfer(spi, message);
}



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