相比于前面介绍的i2c子系统(见 http://www.linuxidc.com/Linux/2012-01/52782.htm ),spi子系统相对简单,和i2c的结构也很相似,这里主要介绍一下平台无关部分的代码。先概括的说一下,spi总线或者说是spi控制器用结构体struct spi_master来表述,而一般不会明显的主动实现这个结构而是借助板级的一些信息结构,利用spi的模型填充,存在板级信息的一条链表board_list,上面挂接着板级spi设备的描述信息,其挂接的结构是struct boardinfo,这个结构内部嵌入了具体的板级spi设备所需信息结构struct spi_board_info,对于要操控的spi设备,用struct spidev_data来描述,内嵌了具体设备信息结构struct spi_device,并通过struct spi_device->device_entry成员挂接到全局spi设备链表device_list,结构struct spi_device就是根据前面board_list上所挂的信息填充的,而driver端比较简单,用struct spi_driver来描述,一会儿会看到该结构和标准的platform非常相似,总括的说下一般编写流程:对于soc,spi控制器一般注册成platform,当driver匹配后,会根据platform_device等信息构造出spi_master,一般发生在driver的probe函数,并且注册该master,在master的注册过程中会去遍历board_list找到bus号相同的spi设备信息,并实例化它,好了先就说这么多,下面先看一下具体的数据结构。
一、spi相关的数据结构
先看一下spi设备的板级信息填充的结构:
[cpp]
- struct boardinfo {
- struct list_head list; //用于挂接到链表头board_list上
- unsigned n_board_info; //设备信息号,spi_board_info成员的编号
- struct spi_board_info board_info[0]; //内嵌的spi_board_info结构
- };
- //其中内嵌的描述spi设备的具体信息的结构struct spi_board_info为:
- struct spi_board_info {
- /* the device name and module name are coupled, like platform_bus;
- * “modalias” is normally the driver name.
- *
- * platform_data goes to spi_device.dev.platform_data,
- * controller_data goes to spi_device.controller_data,
- * irq is copied too
- */
- char modalias[SPI_NAME_SIZE]; //名字
- const void *platform_data; //如同注释写的指向spi_device.dev.platform_data
- void *controller_data; //指向spi_device.controller_data
- int irq; //中断号
- /* slower signaling on noisy or low voltage boards */
- u32 max_speed_hz; //时钟速率
- /* bus_num is board specific and matches the bus_num of some
- * spi_master that will probably be registered later.
- *
- * chip_select reflects how this chip is wired to that master;
- * it’s less than num_chipselect.
- */
- u16 bus_num; //所在的spi总线编号
- u16 chip_select;
- /* mode becomes spi_device.mode, and is essential for chips
- * where the default of SPI_CS_HIGH = 0 is wrong.
- */
- u8 mode; //模式
- /* … may need additional spi_device chip config data here.
- * avoid stuff protocol drivers can set; but include stuff
- * needed to behave without being bound to a driver:
- * – quirks like clock rate mattering when not selected
- */
- };
利用boardinfo->list成员会将自身挂接到全局的board_list链表上。
再来看一下spi控制器的表述结构:
[cpp]
- struct spi_master {
- struct device dev; //内嵌的标准dev结构
- /* other than negative (== assign one dynamically), bus_num is fully
- * board-specific. usually that simplifies to being SOC-specific.
- * example: one SOC has three SPI controllers, numbered 0..2,
- * and one board’s schematics might show it using SPI-2. software
- * would normally use bus_num=2 for that controller.
- */
- s16 bus_num; //标识的总线号
- /* chipselects will be integral to many controllers; some others
- * might use board-specific GPIOs.
- */
- u16 num_chipselect;
- /* some SPI controllers pose alignment requirements on DMAable
- * buffers; let protocol drivers know about these requirements.
- */
- u16 dma_alignment; //dma对其要求
- /* spi_device.mode flags understood by this controller driver */
- u16 mode_bits; //代表操作的spi_device.mode
- /* other constraints relevant to this driver */
- u16 flags; //另外的一些标志
- #define SPI_MASTER_HALF_DUPLEX BIT(0) /* can’t do full duplex */
- #define SPI_MASTER_NO_RX BIT(1) /* can’t do buffer read */
- #define SPI_MASTER_NO_TX BIT(2) /* can’t do buffer write */
- /* lock and mutex for SPI bus locking */
- spinlock_t bus_lock_spinlock;
- struct mutex bus_lock_mutex;
- /* flag indicating that the SPI bus is locked for exclusive use */
- bool bus_lock_flag;
- /* Setup mode and clock, etc (spi driver may call many times).
- *
- * IMPORTANT: this may be called when transfers to another
- * device are active. DO NOT UPDATE SHARED REGISTERS in ways
- * which could break those transfers.
- */
- int (*setup)(struct spi_device *spi); //设置模式
- /* bidirectional bulk transfers
- *
- * + The transfer() method may not sleep; its main role is
- * just to add the message to the queue.
- * + For now there’s no remove-from-queue operation, or
- * any other request management
- * + To a given spi_device, message queueing is pure fifo
- *
- * + The master’s main job is to process its message queue,
- * selecting a chip then transferring data
- * + If there are multiple spi_device children, the i/o queue
- * arbitration algorithm is unspecified (round robin, fifo,
- * priority, reservations, preemption, etc)
- *
- * + Chipselect stays active during the entire message
- * (unless modified by spi_transfer.cs_change != 0).
- * + The message transfers use clock and SPI mode parameters
- * previously established by setup() for this device
- */
- int (*transfer)(struct spi_device *spi, //传输函数
- struct spi_message *mesg);
- /* called on release() to free memory provided by spi_master */
- void (*cleanup)(struct spi_device *spi);
- };
而对于要操控的spi总线上的设备,其表述结构为:
[cpp]
- struct spi_device {
- struct device dev; //内嵌标准device结构体
- struct spi_master *master; //spi主控制器
- u32 max_speed_hz; //时钟速率
- 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_NO_CS 0x40 /* 1 dev/bus, no chipselect */
- #define SPI_READY 0x80 /* slave pulls low to pause */
- u8 bits_per_word;
- int irq; //中断号
- void *controller_state; //控制状态
- void *controller_data; //私有数据
- char modalias[SPI_NAME_SIZE]; //名字
- /*
- * 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
- * – …
- */
- };
再看一下对于spi设备结构更高层次的表述结构:
[cpp]
- struct spidev_data {
- dev_t devt;
- spinlock_t spi_lock;
- struct spi_device *spi; //指向spi设备结构
- struct list_head device_entry; //spi设备链表device_list挂接点
- /* buffer is NULL unless this device is open (users > 0) */
- struct mutex buf_lock;
- unsigned users;
- u8 *buffer;
- };
而driver端的表述结构struct spi_driver,具体如下:
[cpp]
- struct spi_driver {
- const struct spi_device_id *id_table; //匹配的设备表
- 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核心代码的初始化分析
首先看一下spi总线的注册代码很简单,位于driver/spi/spi.c下:
[cpp]
- static int __init spi_init(void)
- {
- int status;
- //其中buf为static u8 *buf,
- //SPI_BUFSIZ为#define SPI_BUFSIZ max(32,SMP_CACHE_BYTES)
- buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
- if (!buf) {
- status = -ENOMEM;
- goto err0;
- }
- //注册spi_bus
- status = bus_register(&spi_bus_type);
- if (status < 0)
- goto err1;
- //在sys/class下产生spi_master这个节点,用于自动产生设备节点
- //下面挂接的是控制器的节点
- status = class_register(&spi_master_class);
- if (status < 0)
- goto err2;
- return 0;
- err2:
- bus_unregister(&spi_bus_type);
- err1:
- kfree(buf);
- buf = NULL;
- err0:
- return status;
- }
- //其中注册bus结构为
- struct bus_type spi_bus_type = {
- .name = “spi”,
- .dev_attrs = spi_dev_attrs,
- .match = spi_match_device, //匹配函数
- .uevent = spi_uevent,
- .suspend = spi_suspend,
- .resume = spi_resume,
- };
- //类函数为
- static struct class spi_master_class = {
- .name = “spi_master”,
- .owner = THIS_MODULE,
- .dev_release = spi_master_release,
- };
- //顺便把driver与device的匹配函数也一起分析了吧,很简单
- static int spi_match_device(struct device *dev, struct device_driver *drv)
- {
- const struct spi_device *spi = to_spi_device(dev);
- const struct spi_driver *sdrv = to_spi_driver(drv);
- /* Attempt an OF style match */
- //利用of表进行匹配
- if (of_driver_match_device(dev, drv))
- return 1;
- //利用id表进行匹配
- if (sdrv->id_table)
- return !!spi_match_id(sdrv->id_table, spi);
- //利用名字进行匹配
- return strcmp(spi->modalias, drv->name) == 0;
- }
再看一下driver的注册,spi_register_driver函数:
[cpp]
- int spi_register_driver(struct spi_driver *sdrv)
- {
- //很类似于platfor的注册,很简单,
- //就不具体介绍了
- 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;
- //注册标准的driver,此时会去匹配bus设备链表上
- //支持的device,找到会调用相应函数
- return driver_register(&sdrv->driver);
- }
还有个板级信息的添加函数:
[cpp]
- int __init
- spi_register_board_info(struct spi_board_info const *info, unsigned n)
- {
- struct boardinfo *bi;
- bi = kmalloc(sizeof(*bi) + n * sizeof *info, GFP_KERNEL);
- if (!bi)
- return -ENOMEM;
- bi->n_board_info = n;
- memcpy(bi->board_info, info, n * sizeof *info);
- mutex_lock(&board_lock);
- list_add_tail(&bi->list, &board_list);
- mutex_unlock(&board_lock);
- return 0;
- }
函数很简单,利用定义的spi_board_info信息,填充了boardinfo结构,并挂到board_list链表。
最后来看一下一个重量级函数,master的注册函数:
[cpp]
- int spi_register_master(struct spi_master *master)
- {
- static atomic_t dyn_bus_id = ATOMIC_INIT((1<<15) – 1);
- struct device *dev = master->dev.parent;
- int status = -ENODEV;
- int dynamic = 0;
- //内嵌的标准设备结构必须初始化好
- if (!dev)
- return -ENODEV;
- /* even if it’s just one always-selected device, there must
- * be at least one chipselect
- */
- //支持的设备数量为0,出错返回
- if (master->num_chipselect == 0)
- return -EINVAL;
- /* convention: dynamically assigned bus IDs count down from the max */
- if (master->bus_num < 0) {
- /* FIXME switch to an IDR based scheme, something like
- * I2C now uses, so we can’t run out of “dynamic” IDs
- */
- //控制器编号(总线编号)不能小于0
- master->bus_num = atomic_dec_return(&dyn_bus_id);
- dynamic = 1;
- }
- spin_lock_init(&master->bus_lock_spinlock);
- mutex_init(&master->bus_lock_mutex);
- master->bus_lock_flag = 0;
- /* register the device, then userspace will see it.
- * registration fails if the bus ID is in use.
- */
- //设置master->dev的名字,形式为spi+bus_num,如:spi0
- dev_set_name(&master->dev, “spi%u”, master->bus_num);
- //注册master内嵌的标准device结构
- status = device_add(&master->dev);
- if (status < 0)
- goto done;
- dev_dbg(dev, “registered master %s%s/n”, dev_name(&master->dev),
- dynamic ? ” (dynamic)” : “”);
- /* populate children from any spi device tables */
- //重点哦,扫描并实例化spi设备
- scan_boardinfo(master);
- status = 0;
- /* Register devices from the device tree */
- of_register_spi_devices(master);
- done:
- return status;
- }
- //先来看scan_boardinfo这个分支
- static void scan_boardinfo(struct spi_master *master)
- {
- struct boardinfo *bi;
- mutex_lock(&board_lock);
- //找到我们注册的spi相关的板级信息结构体
- //还记得board_list吧
- list_for_each_entry(bi, &board_list, list) {
- struct spi_board_info *chip = bi->board_info;
- unsigned n;
- //因为可能存在多个spi总线,因此spi信息结构也会有
- //多个,找到bus号匹配的就对了
- for (n = bi->n_board_info; n > 0; n–, chip++) {
- if (chip->bus_num != master->bus_num)
- continue;
- /* NOTE: this relies on spi_new_device to
- * issue diagnostics when given bogus inputs
- */
- //找到了就要实例化它上面的设备了
- (void) spi_new_device(master, chip);
- }
- }
- mutex_unlock(&board_lock);
- }
- //跟进spi_new_device函数
- struct spi_device *spi_new_device(struct spi_master *master,
- struct spi_board_info *chip)
- {
- struct spi_device *proxy;
- int status;
- /* NOTE: caller did any chip->bus_num checks necessary.
- *
- * Also, unless we change the return value convention to use
- * error-or-pointer (not NULL-or-pointer), troubleshootability
- * suggests syslogged diagnostics are best here (ugh).
- */
- //为需要实例化的设备分配内存
- //同时会将bus成员制定为spi_bus_type,parent
- //指定为该master,层次关系
- proxy = spi_alloc_device(master);
- if (!proxy)
- return NULL;
- WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));
- //各个成员赋值,都是用我们注册的板级信息
- proxy->chip_select = chip->chip_select;
- proxy->max_speed_hz = chip->max_speed_hz;
- proxy->mode = chip->mode;
- proxy->irq = chip->irq;
- strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));
- proxy->dev.platform_data = (void *) chip->platform_data;
- proxy->controller_data = chip->controller_data;
- proxy->controller_state = NULL;
- //把该设备添加到spi总线
- status = spi_add_device(proxy);
- if (status < 0) {
- spi_dev_put(proxy);
- return NULL;
- }
- return proxy;
- }
- //继续spi_add_device函数
- int spi_add_device(struct spi_device *spi)
- {
- static DEFINE_MUTEX(spi_add_lock);
- struct device *dev = spi->master->dev.parent;
- struct device *d;
- int status;
- /* Chipselects are numbered 0..max; validate. */
- //spi设备的编号不能大于master定义的最大数目
- if (spi->chip_select >= spi->master->num_chipselect) {
- dev_err(dev, “cs%d >= max %d/n”,
- spi->chip_select,
- spi->master->num_chipselect);
- return -EINVAL;
- }
- /* Set the bus ID string */
- //设备节点名字,形式:spi0.0
- dev_set_name(&spi->dev, “%s.%u”, dev_name(&spi->master->dev),
- spi->chip_select);
- /* We need to make sure there’s no other device with this
- * chipselect **BEFORE** we call setup(), else we’ll trash
- * its configuration. Lock against concurrent add() calls.
- */
- mutex_lock(&spi_add_lock);
- //确保设备不会重复注册
- d = bus_find_device_by_name(&spi_bus_type, NULL, dev_name(&spi->dev));
- if (d != NULL) {
- dev_err(dev, “chipselect %d already in use/n”,
- spi->chip_select);
- put_device(d);
- status = -EBUSY;
- goto done;
- }
- /* Drivers may modify this initial i/o setup, but will
- * normally rely on the device being setup. Devices
- * using SPI_CS_HIGH can’t coexist well otherwise…
- */
- //设置spi模式和时钟速率
- //会调用spi->master->setup函数设置
- status = spi_setup(spi);
- if (status < 0) {
- dev_err(dev, “can’t %s %s, status %d/n”,
- “setup”, dev_name(&spi->dev), status);
- goto done;
- }
- /* Device may be bound to an active driver when this returns */
- //将该实例化的设备添加到总线
- status = device_add(&spi->dev);
- if (status < 0)
- dev_err(dev, “can’t %s %s, status %d/n”,
- “add”, dev_name(&spi->dev), status);
- else
- dev_dbg(dev, “registered child %s/n”, dev_name(&spi->dev));
- done:
- mutex_unlock(&spi_add_lock);
- return status;
- }
- //最后看下spi_setup函数
- int spi_setup(struct spi_device *spi)
- {
- unsigned bad_bits;
- int status;
- /* help drivers fail *cleanly* when they need options
- * that aren’t supported with their current master
- */
- //必须和当前的master设置的模式匹配
- bad_bits = spi->mode & ~spi->master->mode_bits;
- if (bad_bits) {
- dev_dbg(&spi->dev, “setup: unsupported mode bits %x/n”,
- bad_bits);
- return -EINVAL;
- }
- if (!spi->bits_per_word)
- spi->bits_per_word = 8;
- //最后调用控制器平台相关的setup成员设置该spi设备
- status = spi->master->setup(spi);
- dev_dbg(&spi->dev, “setup mode %d, %s%s%s%s”
- “%u bits/w, %u Hz max –> %d/n”,
- (int) (spi->mode & (SPI_CPOL | SPI_CPHA)),
- (spi->mode & SPI_CS_HIGH) ? “cs_high, “ : “”,
- (spi->mode & SPI_LSB_FIRST) ? “lsb, “ : “”,
- (spi->mode & SPI_3WIRE) ? “3wire, “ : “”,
- (spi->mode & SPI_LOOP) ? “loopback, “ : “”,
- spi->bits_per_word, spi->max_speed_hz,
- status);
- return status;
- }
- //回头看下一开始下面的那个分支of_register_spi_devices
- void of_register_spi_devices(struct spi_master *master)
- {
- struct spi_device *spi;
- struct device_node *nc;
- const __be32 *prop;
- int rc;
- int len;
- //如果定义了of_node成员才会走该分支
- if (!master->dev.of_node)
- return;
- //从控制器master->dev.of_node中去获取注册SPI设备spi_device的信息,然
- //后分配结构体spi_device并注册
- for_each_child_of_node(master->dev.of_node, nc) {
- /* Alloc an spi_device */
- spi = spi_alloc_device(master);
- if (!spi) {
- dev_err(&master->dev, “spi_device alloc error for %s/n”,
- nc->full_name);
- spi_dev_put(spi);
- continue;
- }
- /* Select device driver */
- if (of_modalias_node(nc, spi->modalias,
- sizeof(spi->modalias)) < 0) {
- dev_err(&master->dev, “cannot find modalias for %s/n”,
- nc->full_name);
- spi_dev_put(spi);
- continue;
- }
- /* Device address */
- prop = of_get_property(nc, “reg”, &len);
- if (!prop || len < sizeof(*prop)) {
- dev_err(&master->dev, “%s has no ‘reg’ property/n”,
- nc->full_name);
- spi_dev_put(spi);
- continue;
- }
- spi->chip_select = be32_to_cpup(prop);
- /* Mode (clock phase/polarity/etc.) */
- if (of_find_property(nc, “spi-cpha”, NULL))
- spi->mode |= SPI_CPHA;
- if (of_find_property(nc, “spi-cpol”, NULL))
- spi->mode |= SPI_CPOL;
- if (of_find_property(nc, “spi-cs-high”, NULL))
- spi->mode |= SPI_CS_HIGH;
- /* Device speed */
- prop = of_get_property(nc, “spi-max-frequency”, &len);
- if (!prop || len < sizeof(*prop)) {
- dev_err(&master->dev, “%s has no ‘spi-max-frequency’ property/n”,
- nc->full_name);
- spi_dev_put(spi);
- continue;
- }
- spi->max_speed_hz = be32_to_cpup(prop);
- /* IRQ */
- spi->irq = irq_of_parse_and_map(nc, 0);
- /* Store a pointer to the node in the device structure */
- of_node_get(nc);
- spi->dev.of_node = nc;
- /* Register the new device */
- request_module(spi->modalias);
- rc = spi_add_device(spi);
- if (rc) {
- dev_err(&master->dev, “spi_device register error %s/n”,
- nc->full_name);
- spi_dev_put(spi);
- }
- }
- }
三、spi设备文件的自动产生代码分析
这部分代码相当于注册了一个spi实际driver,既是核心平台无关代码,又是个具体实例,我们来看下一下具体做了什么,也好学习一spi_driver的各部分具体都需要做些什么,代码位于driver/spi/spidev.c下:
[cpp]
- 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);
- //注册主设备号为153的spi字符设备,spidev_fops结构下面会介绍
- //暂且不表
- status = register_chrdev(SPIDEV_MAJOR, “spi”, &spidev_fops);
- if (status < 0)
- return status;
- //在sys/class下产生spidev这个节点,udev会利用其在dev下产生spidev
- //这个设备节点
- 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);
- }
- //注册spi驱动,该函数上面已经分析过
- 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;
- }
- //先看一下spidev_spi_driver具体的结构
- 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.
- */
- };
- //利用bus的match函数匹配成功后将首先调用spidev_probe函数,我们具体看下该函数:
- static int __devinit spidev_probe(struct spi_device *spi)
- {
- struct spidev_data *spidev;
- int status;
- unsigned long minor;
- /* Allocate driver data */
- //申请spidev_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);
- //找到一个最小的次设备号
- //addr为内存区的起始地址,size为要查找的最大长度
- //返回第一个位为0的位号
- minor = find_first_zero_bit(minors, N_SPI_MINORS);
- if (minor < N_SPI_MINORS) {
- struct device *dev;
- //下面两句用于在sys/class/spidev下产生类似于
- //spidev%d.%d形式的节点,这样,udev等工具就可以
- //自动在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;
- }
- //如果成功标明刚才的次设备号已被占用
- //并且将该设备挂接到device_list链表
- if (status == 0) {
- set_bit(minor, minors);
- list_add(&spidev->device_entry, &device_list);
- }
- mutex_unlock(&device_list_lock);
- //设置spi->dev->p = spidev
- if (status == 0)
- spi_set_drvdata(spi, spidev);
- else
- kfree(spidev);
- return status;
- }
当我们利用板级信息添加一个设备的时候,该driver如果匹配到这个设备,那么就会自动为其创建设备节点,封装spidev_data
信息,并且挂到全局设备链表device_list。
最后看一下刚才注册的字符设备的统一操作集:
[cpp]
- 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,
- .open = spidev_open,
- .release = spidev_release,
- };
- //按应用的操作顺序先看下open函数
- static int spidev_open(struct inode *inode, struct file *filp)
- {
- struct spidev_data *spidev;
- int status = -ENXIO;
- mutex_lock(&device_list_lock);
- //遍历spi设备链表device_list,根据设备号找到spidev_data结构
- list_for_each_entry(spidev, &device_list, device_entry) {
- if (spidev->devt == inode->i_rdev) {
- status = 0;
- break;
- }
- }
- if (status == 0) {
- //buffer为空,为其申请内存
- if (!spidev->buffer) {
- spidev->buffer = kmalloc(bufsiz, GFP_KERNEL);
- if (!spidev->buffer) {
- dev_dbg(&spidev->spi->dev, “open/ENOMEM/n”);
- status = -ENOMEM;
- }
- }
- //设备用户使用量+1
- if (status == 0) {
- spidev->users++;
- //传到filp的私有成员,在read,write的时候可以从其得到该结构
- 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;
- }
- //再看read函数
- 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;
- }
- //跟进spidev_sync_read函数,下面的操作比较直白,简要分析下
- //只关注主流程
- 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);
- //调用spidev_sync继续
- return spidev_sync(spidev, &m);
- }
- //继续spidev_sync函数
- 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
- //继续调用spi_async函数
- 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;
- }
- //spi_async函数
- int spi_async(struct spi_device *spi, struct spi_message *message)
- {
- struct spi_master *master = spi->master;
- int ret;
- unsigned long flags;
- spin_lock_irqsave(&master->bus_lock_spinlock, flags);
- if (master->bus_lock_flag)
- ret = -EBUSY;
- else
- //好长…继续跟进
- ret = __spi_async(spi, message);
- spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);
- return ret;
- }
- //__spi_async函数
- static int __spi_async(struct spi_device *spi, struct spi_message *message)
- {
- struct spi_master *master = spi->master;
- /* Half-duplex links include original MicroWire, and ones with
- * only one data pin like SPI_3WIRE (switches direction) or where
- * either MOSI or MISO is missing. They can also be caused by
- * software limitations.
- */
- if ((master->flags & SPI_MASTER_HALF_DUPLEX)
- || (spi->mode & SPI_3WIRE)) {
- struct spi_transfer *xfer;
- unsigned flags = master->flags;
- list_for_each_entry(xfer, &message->transfers, transfer_list) {
- if (xfer->rx_buf && xfer->tx_buf)
- return -EINVAL;
- if ((flags & SPI_MASTER_NO_TX) && xfer->tx_buf)
- return -EINVAL;
- if ((flags & SPI_MASTER_NO_RX) && xfer->rx_buf)
- return -EINVAL;
- }
- }
- message->spi = spi;
- message->status = -EINPROGRESS;
- //最后调用master->transfer具体的平台相关的结构
- return master->transfer(spi, message);
- }
read函数就分析到此,至于write函数就不具体分析了,流程是相似的!
四、总结
根据前面的积累,这次简要分析了下spi设备驱动的模型,由于和i2c很相似,就不给出具体框图了,后面有时间会结合具体平台分析一下spi的实例,这次就到这里了 @^.^@