spi(3)

浅析驱动注册函数driver_register()(转) 

    

int driver_register(struct device_driver * drv)

{

    if ((drv->bus->probe && drv->probe) ||

//drv和drv所属的bus之中只要1个提供该函数即可,否则也只能调用bus的函数,而不理会drv的

     (drv->bus->remove && drv->remove) ||

     (drv->bus->shutdown && drv->shutdown)) {

        printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name);

    }

    klist_init(&drv->klist_devices, NULL, NULL);//将drv驱动上的设备链表清空

    return bus_add_driver(drv);//将本drv驱动注册登记到drv->bus所在的总线上

}

void klist_init(struct klist * k, void (*get)(struct klist_node *),

        void (*put)(struct klist_node *))

{

    INIT_LIST_HEAD(&k->k_list);//链表初始化

    spin_lock_init(&k->k_lock);//锁初始化

    k->get = get;//引用计数操作自定义函数

    k->put = put;

}

int bus_add_driver(struct device_driver *drv)

{

    struct bus_type * bus = get_bus(drv->bus);

    int error = 0;

    if (!bus)

        return -EINVAL;

    pr_debug("bus %s: add driver %s\n", bus->name, drv->name);

    //kboj->name[KOBJ_NAME_LEN],如果KOBJ_NAME_LEN长度不够,会调用kmalloc申请

    //之后kobj->k_name指针或者指向kboj->name或者指向kmalloc返回地址

    error = kobject_set_name(&drv->kobj, "%s", drv->name);

    if (error)

        goto out_put_bus;

    //bus->drivers为kset集合类型,也正是管理本drv->kobj的kset集合

    drv->kobj.kset = &bus->drivers;

    //gliethttp_20071025 kobject_register()简单理解

    //把drv的kobj大张旗鼓的登记到管理它的kset集合上去,同时再根据层级关系创建相应的目录文件

    //gliethttp_20071026

    //注册登记该kobj,如果该kobj属于某个kset,那么将自己的entry节点挂接到该kset的list链表上,

    //以示自己需要该kset的滋润,同时kobj->parent=&kset->kobj,parent指向kset用来管理自己的kobj

    //如果该kobj不属于kset,而属于parent,那么简单的将parent的引用计数加1

    //对于kobj属于某个kset的情况,可以实现kset向下查找kobj,也可以实现kobj向上查找kset

    //对于kobj属于某个parent的情况,查找只能是单向的,只能kobj找到parent,parent不能查找

    //该parent挂接的kobj们

    //parent是用来明显建立亲子关系图的标志性变量,当然在kset也能若隐若现的显露出这种关系,

    //但总不如parent正宗和高效

    //之后调用create_dir()创建该kobj在sysfs中的目录文件

    //最后调用kobject_uevent()将KOBJ_ADD事件通知到用户空间的守护进程

    error = kobject_register(&drv->kobj);

    if (error)

        goto out_put_bus;

    if (drv->bus->drivers_autoprobe) {

    //gliethttp_20071025

    //driver提供自动匹配函数,那么现在就遍历所有设备

    //尝试将本driver匹配到相应设备上去

        error = driver_attach(drv);

        if (error)

            goto out_unregister;

    }

    //将本driver链接到bus总线上的klist_drivers的klist链表结尾处

    klist_add_tail(&drv->knode_bus, &bus->klist_drivers);

    module_add_driver(drv->owner, drv);

//gliethttp_20071026

//所以一个驱动需要维持住1个klist链条和一个kobj层次结构--驱动drv->kobj对象,内核一方面使用该kobj在sysfs中建立

//统一的与该kobj对应的目录对象供用户空间访问,另一方面使用该kobj的引用计数来获悉该kobj设备的繁忙与空闲情况,

//当本kobj对象的引用计数到达0时,只要其他条件允许,那么说明集成本kobj的结构体对象不再使用,内核得知这个情况很重要,

//因为这对内核进行进一步的决策提供了详细的证据资料,进而对物理设备进行细致的电源管理成了可能,

//如:当hub1上的所有端口设备都被拔掉之后,hub1就可以安全的进入省电模式了,而这个功能在2.4内核中是找不到的.

//如果从面向对象的角度来看待kset、kobj和driver的话,并不能清晰的说明问题,因为面向对象本身提供的封装、继承和多态

//并不能很好的说明kset、kobj和driver之间存在的实际关系,多少都有一些出入,因为linux毕竟不是用c++写的,不像eCos那样,

//虽然大家都努力借鉴面向对象的光辉思想来设计自己的程序,但是面向对象固有的若干弊端因素也是我们必须要剔除的,

//所以剥丝抽茧之后,呈现出来的东西,大多将处于中间态,当然不排除走极端的少数,所以我觉得使用单纯的面向对象思想来理解

//kset、kobj和driver这3者,最终都会带来理解上的麻烦,因为渗透在他们3者之间的设计思想与封装、继承、多态、类、

//虚函数、属性、方法、类属性和类方法等只是相似,而且"仅仅相似,有些影子,但并不是!"

//因此对于正常理解,最好抛弃单纯的面向对象方式(开始我就使用单纯的面向对象方式来理解,结果在若干单元上卡了壳儿,

//现在想来很是可笑,因为那些单元根本就不是面向对象所具有的,硬是要用面向对象来解决,那完全是在牵强)

//而是采用面向对象和c数据结构相结合的方式,

//而且在结合过程中,为了减少麻烦,最好偏向c数据结构多一点(gliethttp_20071026小感).

    //创建属性目录文件

    error = driver_add_attrs(bus, drv);

    if (error) {

        /* How the hell do we get out of this pickle? Give up */

        printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",

            __FUNCTION__, drv->name);

    }

    error = add_bind_files(drv);

    if (error) {

        /* Ditto */

        printk(KERN_ERR "%s: add_bind_files(%s) failed\n",

            __FUNCTION__, drv->name);

    }

    return error;

out_unregister:

    kobject_unregister(&drv->kobj);

out_put_bus:

    put_bus(bus);

    return error;

}

注册设备驱动程序
---------------------------------------------------
    在设备文件上发出的每个系统调用都由内核转化为相应设备驱动程序的对应函数的调用。为了完成这个操作,设备驱动程序必须注册自己。换句话说,注册一个设备驱动程序意味着把它对应的设备文件连接起来。如果设备文件对应的驱动程序以前没有注册,则对该设备文件的访问返回错误码 -ENODEV
    如果设备驱动程序被静态地编译进内核,则它的注册在内核初始化阶段进行。相反,如果驱动程序作为一个内核模块来编译,则它的注册在模块装入时进行。   
    一旦设备驱动程序被注册了,它就和设备文件的主设备号连接在一起,而不是和设备文件的路径连接在一起。这样,对设备文件的任何访问都会激活相应的设备驱动程序,而不用管所这用的路径名



内核版本:3.9.5

  • SPI控制器层(平台相关)

上一节讲了SPI核心层的注册和匹配函数,它是平台无关的.正是在核心层抽象了SPI控制器层的相同部分然后提供了统一的API给SPI设备层来使用.我们这一节就能看到,一个SPI控制器以platform_device的形式注册进内核,并且调用spi_register_board_info函数注册了spi_board_info结构.我们前面说过,struct spi_board_info结构是对spi_device的描述,其中的内从最终是要用来初始化struct spi_device实例的.

哎!闲话少说了,越说越糊涂.我们以davinci的dm365平台为例,来看看SPI控制器的相关内容.在arch/arm/mach-davinci/board-dm365-evm.c中有:

复制代码
 1 static struct spi_board_info dm365_evm_spi_info[] __initconst = {
 2     {
 3         .modalias    = "at25",
 4         .platform_data    = &at25640,
 5         .max_speed_hz    = 10 * 1000 * 1000,
 6         .bus_num    = 0,
 7         .chip_select    = 0,
 8         .mode        = SPI_MODE_0,
 9     },
10 };
11 
12 static __init void dm365_evm_init(void)
13 {
14     ……
15     dm365_init_spi0(BIT(0), dm365_evm_spi_info,
16             ARRAY_SIZE(dm365_evm_spi_info));
17 }
复制代码

dm365_evm_init这个函数是dm365平台初始化函数,我略去了和SPI无关的部分.可以看到其中调用了dm365_init_spi0函数,并且将一个struct spi_board_info这个结构类型的数组作为参数传了进去.那么来看看dm365_init_spi0函数,在arch/arm/mach-davinci/dm365.c中:

复制代码
 1 static u64 dm365_spi0_dma_mask = DMA_BIT_MASK(32);
 2 
 3 static struct davinci_spi_platform_data dm365_spi0_pdata = {
 4     .version     = SPI_VERSION_1,
 5     .num_chipselect = 2,
 6     .dma_event_q    = EVENTQ_3,
 7 };
 8 
 9 static struct resource dm365_spi0_resources[] = {
10     {
11         .start = 0x01c66000,
12         .end   = 0x01c667ff,
13         .flags = IORESOURCE_MEM,
14     },
15     {
16         .start = IRQ_DM365_SPIINT0_0,
17         .flags = IORESOURCE_IRQ,
18     },
19     {
20         .start = 17,
21         .flags = IORESOURCE_DMA,
22     },
23     {
24         .start = 16,
25         .flags = IORESOURCE_DMA,
26     },
27 };
28 
29 static struct platform_device dm365_spi0_device = {
30     .name = "spi_davinci",/*这个是和platform_driver匹配的依据,具体到davinci的板子就是davinci_spi_driver*/
31     .id = 0,/*对于SPI,这个值最后会在初始化spi_master的时候用来初始化master->bus_num*/
32     .dev = {
33         .dma_mask = &dm365_spi0_dma_mask,
34         .coherent_dma_mask = DMA_BIT_MASK(32),
35         .platform_data = &dm365_spi0_pdata,
36     },
37     .num_resources = ARRAY_SIZE(dm365_spi0_resources),
38     .resource = dm365_spi0_resources,
39 };
40 
41 void __init dm365_init_spi0(unsigned chipselect_mask,
42         const struct spi_board_info *info, unsigned len)
43 {
44     davinci_cfg_reg(DM365_SPI0_SCLK);
45     davinci_cfg_reg(DM365_SPI0_SDI);
46     davinci_cfg_reg(DM365_SPI0_SDO);
47 
48     /* not all slaves will be wired up */
49     if (chipselect_mask & BIT(0))
50         davinci_cfg_reg(DM365_SPI0_SDENA0);
51     if (chipselect_mask & BIT(1))
52         davinci_cfg_reg(DM365_SPI0_SDENA1);
53 
54     spi_register_board_info(info, len);
55 
56     platform_device_register(&dm365_spi0_device);
57 }
复制代码

第54行注册了struct spi_board_info实例,就是我们传进来的dm365_evm_spi_info.在设备移植时填充结构体spi_board_info是移植的重要工作.我们来看看这个函数的实现,在drivers/spi/spi.c中:

复制代码
 1 int spi_register_board_info(struct spi_board_info const *info, unsigned n)
 2 {
 3     struct boardinfo *bi;
 4     int i;
 5 
 6     bi = kzalloc(n * sizeof(*bi), GFP_KERNEL);/*为结构体boardinfo分配内存空间*/
 7     if (!bi)
 8         return -ENOMEM;
 9 
10     for (i = 0; i < n; i++, bi++, info++) {
11         struct spi_master *master;
12 
13         memcpy(&bi->board_info, info, sizeof(*info));
14         mutex_lock(&board_lock);
15         list_add_tail(&bi->list, &board_list);/*添加到板级描述符链表*/
16         list_for_each_entry(master, &spi_master_list, list)/*将SPI主机控制类链表所有的节点匹配板级信息的设备初始化*/
17             spi_match_master_to_boardinfo(master, &bi->board_info);
18         mutex_unlock(&board_lock);
19     }
20 
21     return 0;
22 }
复制代码

这里又看到了一个结构struct boardinfo,其实它简单的就像没穿裤子的女人,我们来看,在同文件中:

复制代码
 1 struct boardinfo {
 2     struct list_head    list;
 3     struct spi_board_info    board_info;
 4 };
 5 
 6 static LIST_HEAD(board_list);
 7 static LIST_HEAD(spi_master_list);
 8 
 9 /*
10  * Used to protect add/del opertion for board_info list and
11  * spi_master list, and their matching process
12  */
13 /*boardinfo链表操作锁*/
14 static DEFINE_MUTEX(board_lock);
复制代码

这个结构是一个板级相关信息链表,就是说它是一些描述spi_device的信息的集合.结构体boardinfo管理多个结构体spi_board_info,结构体spi_board_info中挂在SPI总线上的设备的平台信息.一个结构体spi_board_info对应着一个SPI设备spi_device.
同时我们也看到了,函数中出现的board_list和spi_master_list都是全局的链表,她们分别记录了系统中所有的boardinfo和所有的spi_master.至于spi_match_master_to_boardinfo函数是什么意思,我们后面还会遇到,到时候再讲.
dm365_init_spi0函数中第56行注册平台设备.我们看到这个platform_device的的name是"spi_davinci",那么就必然还存在一个名为"spi_davinci"的platform_driver.那好办了,搜一下发现在drivers/spi/spi_davinci.c中:

复制代码
 1 static struct platform_driver davinci_spi_driver = {
 2     .driver = {
 3         .name = "spi_davinci",
 4         .owner = THIS_MODULE,
 5         .of_match_table = davinci_spi_of_match,
 6     },
 7     .probe = davinci_spi_probe,
 8     .remove = davinci_spi_remove,
 9 };
10 module_platform_driver(davinci_spi_driver);
复制代码

Linux设备模型常识告诉我们,当系统中注册了一个名为"spi_davinci"的platform_device时,同时又住了一个名为"spi_davinci"的platform_driver.那么就会执行这里的probe回调.这里我们来看davinci_spi_probe函数.

复制代码
  1 static int davinci_spi_probe(struct platform_device *pdev)
  2 {
  3     struct spi_master *master;
  4     struct davinci_spi *dspi;/*davinci_spi这个结构用来描述具体的davinci平台上的spi控制器,等于说是对spi_master的一个封装*/
  5     struct davinci_spi_platform_data *pdata;
  6     struct resource *r, *mem;
  7     resource_size_t dma_rx_chan = SPI_NO_RESOURCE;
  8     resource_size_t    dma_tx_chan = SPI_NO_RESOURCE;
  9     int i = 0, ret = 0;
 10     u32 spipc0;
 11 
 12     /*分配master结构体,其中包括davinci_spi结构的内存空间,使用master.dev.driver_data指向它*/
 13     master = spi_alloc_master(&pdev->dev, sizeof(struct davinci_spi));
 14     if (master == NULL) {
 15         ret = -ENOMEM;
 16         goto err;
 17     }
 18 
 19     dev_set_drvdata(&pdev->dev, master);/*pdev->dev.device_private->driver_data = master*/
 20 
 21     dspi = spi_master_get_devdata(master);/*就是获取上文master.dev.driver_data指向的对象地址,其实就是davinci_spi结构对象的空间地址,将
 22     其赋给dspi*/
 23     if (dspi == NULL) {/*dspi不能为空哦*/
 24         ret = -ENOENT;
 25         goto free_master;
 26     }
 27 
 28     /*下面这几行就是填充dspi的pdata字段*/
 29     if (pdev->dev.platform_data) {
 30         pdata = pdev->dev.platform_data;/*具体到对于dm365来说就是dm365_spi0_pdata*/
 31         dspi->pdata = *pdata;
 32     } else {
 33         /* update dspi pdata with that from the DT */
 34         ret = spi_davinci_get_pdata(pdev, dspi);
 35         if (ret < 0)
 36             goto free_master;
 37     }
 38 
 39     /* pdata in dspi is now updated and point pdata to that */
 40     pdata = &dspi->pdata;/*pdata指针再指向dspi->pdata*/
 41 
 42     r = platform_get_resource(pdev, IORESOURCE_MEM, 0);/*获取IO资源*/
 43     if (r == NULL) {
 44         ret = -ENOENT;
 45         goto free_master;
 46     }
 47 
 48     dspi->pbase = r->start;
 49 
 50     mem = request_mem_region(r->start, resource_size(r), pdev->name);/*申请IO内存*/
 51     if (mem == NULL) {
 52         ret = -EBUSY;
 53         goto free_master;
 54     }
 55 
 56     dspi->base = ioremap(r->start, resource_size(r));/*建立内存映射*/
 57     if (dspi->base == NULL) {
 58         ret = -ENOMEM;
 59         goto release_region;
 60     }
 61 
 62     dspi->irq = platform_get_irq(pdev, 0);/*获取irq号*/
 63     if (dspi->irq <= 0) {
 64         ret = -EINVAL;
 65         goto unmap_io;
 66     }
 67 
 68     ret = request_threaded_irq(dspi->irq, davinci_spi_irq, dummy_thread_fn,
 69                  0, dev_name(&pdev->dev), dspi);/*申请spi中断,中断处理函数为davinci_spi_irq*/
 70     if (ret)
 71         goto unmap_io;
 72 
 73     /*设置bitbang的所属master*/
 74     dspi->bitbang.master = spi_master_get(master);
 75     if (dspi->bitbang.master == NULL) {
 76         ret = -ENODEV;
 77         goto irq_free;
 78     }
 79 
 80     dspi->clk = clk_get(&pdev->dev, NULL);/*获取spi时钟*/
 81     if (IS_ERR(dspi->clk)) {
 82         ret = -ENODEV;
 83         goto put_master;
 84     }
 85     clk_prepare_enable(dspi->clk);
 86 
 87     master->dev.of_node = pdev->dev.of_node;
 88     master->bus_num = pdev->id;/*bus_num*/
 89     master->num_chipselect = pdata->num_chipselect;/*保存SPI主机控制器支持的片选数量.具体到dm365可以看到dm365_spi0_pdata中将其定义为2*/
 90     master->setup = davinci_spi_setup;
 91 
 92     /*设置bitbang控制传输的相关函数*/
 93     dspi->bitbang.chipselect = davinci_spi_chipselect;
 94     dspi->bitbang.setup_transfer = davinci_spi_setup_transfer;
 95 
 96     dspi->version = pdata->version;/*具体到dm365可以看到dm365_spi0_pdata中将其定义为0*/
 97 
 98     dspi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP;
 99     if (dspi->version == SPI_VERSION_2)
100         dspi->bitbang.flags |= SPI_READY;
101 
102     r = platform_get_resource(pdev, IORESOURCE_DMA, 0);/*获取DMA资源,这作为输入缓冲*/
103     if (r)
104         dma_rx_chan = r->start;
105     r = platform_get_resource(pdev, IORESOURCE_DMA, 1);/*由参数就能知道davinci的DMA资源定义了两个,这里就获取第二个.这作为输出缓冲*/
106     if (r)
107         dma_tx_chan = r->start;
108 
109     dspi->bitbang.txrx_bufs = davinci_spi_bufs;/*传输数据最终要调用的函数*/
110     if (dma_rx_chan != SPI_NO_RESOURCE &&
111         dma_tx_chan != SPI_NO_RESOURCE) {
112         dspi->dma_rx_chnum = dma_rx_chan;
113         dspi->dma_tx_chnum = dma_tx_chan;
114 
115         ret = davinci_spi_request_dma(dspi);
116         if (ret)
117             goto free_clk;
118 
119         dev_info(&pdev->dev, "DMA: supported\n");
120         dev_info(&pdev->dev, "DMA: RX channel: %d, TX channel: %d, "
121                 "event queue: %d\n", dma_rx_chan, dma_tx_chan,
122                 pdata->dma_event_q);
123     }
124 
125     dspi->get_rx = davinci_spi_rx_buf_u8;
126     dspi->get_tx = davinci_spi_tx_buf_u8;
127 
128     init_completion(&dspi->done);/*初始化completion,用于实现同步I/O*/
129 
130     /* Reset In/OUT SPI module */
131     iowrite32(0, dspi->base + SPIGCR0);
132     udelay(100);
133     iowrite32(1, dspi->base + SPIGCR0);
134 
135     /* Set up SPIPC0.  CS and ENA init is done in davinci_spi_setup */
136     spipc0 = SPIPC0_DIFUN_MASK | SPIPC0_DOFUN_MASK | SPIPC0_CLKFUN_MASK;
137     iowrite32(spipc0, dspi->base + SPIPC0);
138 
139     /* initialize chip selects */
140     if (pdata->chip_sel) {/*davinci的pdata中chip_sel字段并没有设置,这里为空,因此不会进来*/
141         for (i = 0; i < pdata->num_chipselect; i++) {
142             if (pdata->chip_sel[i] != SPI_INTERN_CS)
143                 gpio_direction_output(pdata->chip_sel[i], 1);
144         }
145     }
146 
147     if (pdata->intr_line)/*dm365这个字段为空*/
148         iowrite32(SPI_INTLVL_1, dspi->base + SPILVL);
149     else
150         iowrite32(SPI_INTLVL_0, dspi->base + SPILVL);
151 
152     iowrite32(CS_DEFAULT, dspi->base + SPIDEF);
153 
154     /* master mode default */
155     set_io_bits(dspi->base + SPIGCR1, SPIGCR1_CLKMOD_MASK);
156     set_io_bits(dspi->base + SPIGCR1, SPIGCR1_MASTER_MASK);/*默认设置SPI主控制器工作在master方式*/
157     set_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK);
158 
159     ret = spi_bitbang_start(&dspi->bitbang);/*注册我们的主机SPI控制器*/
160     if (ret)
161         goto free_dma;
162 
163     dev_info(&pdev->dev, "Controller at 0x%p\n", dspi->base);
164 
165     return ret;
166 
167 free_dma:
168     dma_release_channel(dspi->dma_rx);
169     dma_release_channel(dspi->dma_tx);
170 free_clk:
171     clk_disable_unprepare(dspi->clk);
172     clk_put(dspi->clk);
173 put_master:
174     spi_master_put(master);/*减少引用计数*/
175 irq_free:
176     free_irq(dspi->irq, dspi);
177 unmap_io:
178     iounmap(dspi->base);
179 release_region:
180     release_mem_region(dspi->pbase, resource_size(r));
181 free_master:
182     kfree(master);
183 err:
184     return ret;
185 }
复制代码

该函数首先为spi_master结构体以及davinci_spi结构体分配了空间,同时,spi_master.dev.driver_data指向了davinci_spi.接着执行了该条语句:

pdata = pdev->dev.platform_data;/*具体到对于dm365来说就是dm365_spi0_pdata*/

dspi->pdata = *pdata;

NOTE:在这里获取platform_device.dev.platform_data,也就是平台设备的相关数据,这是平台设备移植最需要关注的地方.

随后,为master定义了setup方法,为bitbang定义了3个方法.之后获取了一系列的资源,同时注册了中断服务程序.接着再初始化了completion,这个东东将用于实现同步I/O,他的伟大之处后面会体现出来的.最后调用spi_bitbang_start注册主机控制器.我们来看这个函数,在drivers/spi/spi_bitbang.c中:

复制代码
 1 int spi_bitbang_start(struct spi_bitbang *bitbang)
 2 {
 3     struct spi_master *master = bitbang->master;
 4     int status;
 5 
 6     if (!master || !bitbang->chipselect)
 7         return -EINVAL;
 8 
 9     INIT_WORK(&bitbang->work, bitbang_work);/*初始化一个struct work,处理函数为bitbang_work*/
10     spin_lock_init(&bitbang->lock);/*初始化自旋锁*/
11     INIT_LIST_HEAD(&bitbang->queue);/*初始化链表头,链表为双向循环链表*/
12 
13     if (!master->mode_bits)
14         master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;
15 
16     /*检测bitbang中的函数是否都定义了,如果没定义,则默认使用spi_bitbang_xxx*/
17     if (!master->transfer)/*master的transfer方法没有定义过*/
18         master->transfer = spi_bitbang_transfer;/*使用默认的spi_bitbang_transfe方法*/
19     if (!bitbang->txrx_bufs) {/*如果bitbang没有txrx_bufs方法,其实对于davinci在davinci_spi_probe函数中定义过该方法*/
20         bitbang->use_dma = 0;
21         bitbang->txrx_bufs = spi_bitbang_bufs;
22         if (!master->setup) {
23             if (!bitbang->setup_transfer)
24                 bitbang->setup_transfer =
25                      spi_bitbang_setup_transfer;
26             master->setup = spi_bitbang_setup;
27             master->cleanup = spi_bitbang_cleanup;
28         }
29     } else if (!master->setup)/*对于davinci在davinci_spi_probe函数中定义过该方法*/
30         return -EINVAL;
31     if (master->transfer == spi_bitbang_transfer &&
32             !bitbang->setup_transfer)
33         return -EINVAL;
34 
35     /* this task is the only thing to touch the SPI bits */
36     bitbang->busy = 0;
37     bitbang->workqueue = create_singlethread_workqueue(
38             dev_name(master->dev.parent));/*创建bitbang的工作队列*/
39     if (bitbang->workqueue == NULL) {
40         status = -EBUSY;
41         goto err1;
42     }
43 
44     /* driver may get busy before register() returns, especially
45      * if someone registered boardinfo for devices
46      */
47     status = spi_register_master(master);/*注册spi控制器*/
48     if (status < 0)
49         goto err2;
50 
51     return status;
52 
53 err2:
54     destroy_workqueue(bitbang->workqueue);
55 err1:
56     return status;
57 }
58 EXPORT_SYMBOL_GPL(spi_bitbang_start);
复制代码

定义了控制器的transfer方法为spi_bitbang_transfer.创建了一个工作队列和一个工作bitbang_work,同时创建了一个链表.这些东东后面都会看到.最后,调用了spi_register_master函数,该函数将完成SPI控制器的注册,其中还牵涉到spi_device的注册.我们来看看这个函数.下列函数位于drivers/spi/spi.c:

复制代码
 1 int spi_register_master(struct spi_master *master)
 2 {
 3     static atomic_t        dyn_bus_id = ATOMIC_INIT((1<<15) - 1);
 4     struct device        *dev = master->dev.parent;
 5     struct boardinfo    *bi;
 6     int            status = -ENODEV;
 7     int            dynamic = 0;
 8 
 9     if (!dev)
10         return -ENODEV;
11 
12     status = of_spi_register_master(master);
13     if (status)
14         return status;
15 
16     /* even if it's just one always-selected device, there must
17      * be at least one chipselect
18      */
19     if (master->num_chipselect == 0)/*SPI主控制器支持的片选数当然不能为0,否则还怎么挂接从设备啊.一个接口对应一个master,一个master对应
20     一条SPI总线,一条总线上可能挂有多个设备,num_chipselect就表示该总线上的设备数*/
21         return -EINVAL;
22 
23     if ((master->bus_num < 0) && master->dev.of_node)
24         master->bus_num = of_alias_get_id(master->dev.of_node, "spi");
25 
26     /* convention:  dynamically assigned bus IDs count down from the max */
27     if (master->bus_num < 0) {/*总线号从最大开始减*/
28         /* FIXME switch to an IDR based scheme, something like
29          * I2C now uses, so we can't run out of "dynamic" IDs
30          */
31         master->bus_num = atomic_dec_return(&dyn_bus_id);
32         dynamic = 1;
33     }
34 
35     spin_lock_init(&master->bus_lock_spinlock);
36     mutex_init(&master->bus_lock_mutex);
37     master->bus_lock_flag = 0;/*这个标志指示SPI总线是否被锁*/
38 
39     /* register the device, then userspace will see it.
40      * registration fails if the bus ID is in use.
41      */
42     dev_set_name(&master->dev, "spi%u", master->bus_num);
43     status = device_add(&master->dev);/*向内核注册设备*/
44     if (status < 0)
45         goto done;
46     dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),
47             dynamic ? " (dynamic)" : "");
48 
49     /* If we're using a queued driver, start the queue */
50     if (master->transfer)/*对于具体到davinci,此字段在spi_bitbang_start中被初始化为spi_bitbang_transfer*/
51         dev_info(dev, "master is unqueued, this is deprecated\n");
52     else {
53         status = spi_master_initialize_queue(master);
54         if (status) {
55             device_unregister(&master->dev);
56             goto done;
57         }
58     }
59 
60     mutex_lock(&board_lock);
61     list_add_tail(&master->list, &spi_master_list);/*把这个SPI主机控制器添加进全局的spi_master_list链表*/
62     list_for_each_entry(bi, &board_list, list)/*遍历全局的board_list链表,为每一个boardinfo结构节点查找其中的指向的spi_board_info结构,通过
63     对spi_board_info的bus_bum和SPI主机控制器(spi_master)的bus_num进行匹配,来确定SPI从设备是否由此SPI主机控制器来控制.如果匹配,则通
64     过调用spi_new_device函数创建spi_device从设备,并且将其注册进内核*/
65         spi_match_master_to_boardinfo(master, &bi->board_info);
66     mutex_unlock(&board_lock);
67 
68     /* Register devices from the device tree and ACPI */
69     of_register_spi_devices(master);
70     acpi_register_spi_devices(master);
71 done:
72     return status;
73 }
74 EXPORT_SYMBOL_GPL(spi_register_master);
复制代码

该函数注释一目了然,我们来看看spi_match_master_to_boardinfo这个函数吧.在同文件中有:

复制代码
 1 /*使用SPI主控制类和板级信息匹配则添加一个新设备*/
 2 static void spi_match_master_to_boardinfo(struct spi_master *master,
 3                 struct spi_board_info *bi)
 4 {
 5     struct spi_device *dev;
 6 
 7     if (master->bus_num != bi->bus_num)/*通过bus_num对spi设备和master进行匹配*/
 8         return;
 9 
10     dev = spi_new_device(master, bi);/*执行到此,表示匹配完成,SPI设备由该SPI接口来控制,开始创建spi_device*/
11     if (!dev)
12         dev_err(master->dev.parent, "can't create new device for %s\n",
13             bi->modalias);
14 }
复制代码

地球人都知道这段代码什么意思,好了继续看spi_new_device函数.在同文件中:

复制代码
 1 struct spi_device *spi_new_device(struct spi_master *master,
 2                   struct spi_board_info *chip)
 3 {
 4     struct spi_device    *proxy;
 5     int            status;
 6 
 7     /* NOTE:  caller did any chip->bus_num checks necessary.
 8      *
 9      * Also, unless we change the return value convention to use
10      * error-or-pointer (not NULL-or-pointer), troubleshootability
11      * suggests syslogged diagnostics are best here (ugh).
12      */
13 
14     proxy = spi_alloc_device(master);/*分配spi_device结构,并初始化一些字段*/
15     if (!proxy)
16         return NULL;
17 
18     WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));
19 
20     /*从spi_board_info获取SPI从设备的参数*/
21     proxy->chip_select = chip->chip_select;
22     proxy->max_speed_hz = chip->max_speed_hz;
23     proxy->mode = chip->mode;
24     proxy->irq = chip->irq;
25     strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));
26     proxy->dev.platform_data = (void *) chip->platform_data;
27     proxy->controller_data = chip->controller_data;
28     proxy->controller_state = NULL;
29 
30     status = spi_add_device(proxy);/*将新设备添加进内核*/
31     if (status < 0) {
32         spi_dev_put(proxy);/*从内核模块中撤销这个SPI(从)设备,但是这貌似并没有释放spi_alloc_device开辟的内存.实质上这个函数只是减少
33     了SPI(从)设备的引用计数*/
34         return NULL;
35     }
36 
37     return proxy;
38 }
39 EXPORT_SYMBOL_GPL(spi_new_device);
复制代码

这个函数首先创建了spi_device结构,让后通过板级信息spi_board_info将SPI从设备的相关信息复制给spi_device结构,从而完成了spi_device结构的定义,最后调用spi_add_device,完成spi_device的注册.其中struct spi_board_info *chip这就是我们当初arch/arm/mach-davinci/board-dm365-evm.c中定义的dm365_evm_spi_info数组中的结构实例.

第25行我们就知道,这里注册的spi_device的modalias字段就被初始化为"at25".那么与其对应的spi_driver的device_driver中的name字段肯定为"at25".只有这样才能在SPI核心层的spi_match_device函数中匹配.搜了一遍内核,看到在drivers/msic/eeprom/at25.c中有:

复制代码
 1 static struct spi_driver at25_driver = {
 2     .driver = {
 3         .name        = "at25",
 4         .owner        = THIS_MODULE,
 5     },
 6     .probe        = at25_probe,/*与相应的SPI(从)设备spi_device匹配成功后,则调用这里的probe函数*/
 7     .remove        = at25_remove,
 8 };
 9 
10 module_spi_driver(at25_driver);
复制代码

第10行这个宏是SPI架构专门定义的,在include/linux/spi/spi.h中,我们来看:

1 #define module_spi_driver(__spi_driver) \
2     module_driver(__spi_driver, spi_register_driver, \
3             spi_unregister_driver)

让暴风雨来的更猛烈些吧,研究内核的孩纸都伤不起啊,我们只有硬着头皮往下看,在include/linux/device.h中:

复制代码
 1 #define module_driver(__driver, __register, __unregister, ...) \
 2 static int __init __driver##_init(void) \
 3 { \
 4     return __register(&(__driver) , ##__VA_ARGS__); \
 5 } \
 6 module_init(__driver##_init); \
 7 static void __exit __driver##_exit(void) \
 8 { \
 9     __unregister(&(__driver) , ##__VA_ARGS__); \
10 } \
11 module_exit(__driver##_exit);
复制代码

山重水复疑无路,柳暗花明又一村.这东东你让我说啥~没说的.相信大家也不想在听我唠叨.但是这里为什么多此一举写了这么一个叫宏,而不是像其他的linux模块那样直接写两个module_xxx呢?这是因为这个设备eeprom本身是不可插拔的,也就不需要什么加载卸载的过程,系统上电运行直接就注册了.
那么我们知道了,现在因为SPI子系统核心层我们已经注册了一条SPI总线,就是spi_bus_type.它里面的match回调函数我们已经看过了,就是spi_match_device.就是在这个函数中将完成这个spi_device和spi_driver的匹配,匹配成功就会去执行spi_driver的probe回调了.我们来看,at25_probe函数在drivers/msic/eeprom/at25.c中:

复制代码
  1 static int at25_probe(struct spi_device *spi)
  2 {
  3     struct at25_data    *at25 = NULL;/*这个结构其实就是对spi_device的封装,我们可以像理解面向对象那样将这个结构理解为对spi_device的实例*/
  4     struct spi_eeprom    chip;/*此结构用来作为记录一个SPI EEPROMS的句柄,它保存了platform_data的数据*/
  5     struct device_node    *np = spi->dev.of_node;
  6     int            err;
  7     int            sr;
  8     int            addrlen;
  9 
 10     /* Chip description */
 11     if (!spi->dev.platform_data) {/*具体到dm365平台,此platform_data就是arch/arm/mach-davinci/board-ddm365-evm.c中定义的的at25640*/
 12         if (np) {
 13             err = at25_np_to_chip(&spi->dev, np, &chip);
 14             if (err)
 15                 goto fail;
 16         } else {
 17             dev_err(&spi->dev, "Error: no chip description\n");
 18             err = -ENODEV;
 19             goto fail;
 20         }
 21     } else
 22         chip = *(struct spi_eeprom *)spi->dev.platform_data;
 23 
 24     /* For now we only support 8/16/24 bit addressing */
 25     if (chip.flags & EE_ADDR1)/*flags用来标志eeprom的位宽和读写模式,具体到dm365平台此flags为EE_ADDR2*/
 26         addrlen = 1;
 27     else if (chip.flags & EE_ADDR2)
 28         addrlen = 2;
 29     else if (chip.flags & EE_ADDR3)
 30         addrlen = 3;
 31     else {
 32         dev_dbg(&spi->dev, "unsupported address type\n");
 33         err = -EINVAL;
 34         goto fail;
 35     }
 36 
 37     /* Ping the chip ... the status register is pretty portable,
 38      * unlike probing manufacturer IDs.  We do expect that system
 39      * firmware didn't write it in the past few milliseconds!
 40      */
 41     /*ping一下芯片,状态寄存器是很容易被检测的,不像制造商ID那样麻烦.我们期待系统固件之前没有写入它.*/
 42     sr = spi_w8r8(spi, AT25_RDSR);/*同步的读取状态寄存器的值,返回的八位数据保存在sr中.spi_w8r8这个函数有可能会睡眠*/
 43     if (sr < 0 || sr & AT25_SR_nRDY) {
 44         dev_dbg(&spi->dev, "rdsr --> %d (%02x)\n", sr, sr);
 45         err = -ENXIO;
 46         goto fail;
 47     }
 48 
 49     if (!(at25 = kzalloc(sizeof *at25, GFP_KERNEL))) {/*以kmalloc分配内存,并清0*/
 50         err = -ENOMEM;
 51         goto fail;
 52     }
 53 
 54     mutex_init(&at25->lock);/*初始化互斥体*/
 55     at25->chip = chip;/*记录下spi_eeprom*/
 56     at25->spi = spi_dev_get(spi);/*记录下这个片子对应的spi_device*/
 57     dev_set_drvdata(&spi->dev, at25);/*spi->dev.device_private->driver_data = at25*/
 58     at25->addrlen = addrlen;/*我觉得应该可以理解为这个片子使用的位宽是多少个字节.那根据上文分析,此处值为2*/
 59 
 60     /* Export the EEPROM bytes through sysfs, since that's convenient.
 61      * And maybe to other kernel code; it might hold a board's Ethernet
 62      * address, or board-specific calibration data generated on the
 63      * manufacturing floor.
 64      *
 65      * Default to root-only access to the data; EEPROMs often hold data
 66      * that's sensitive for read and/or write, like ethernet addresses,
 67      * security codes, board-specific manufacturing calibrations, etc.
 68      */
 69     /*通过sysfs文件系统导出EEPROM的字节,因为这是很方便的.也许其他内核代码也是这样做的:比如保存板子的以太网地址,或者是生产商的特定板的校验数据.
 70     默认只有root用户能够访问的数据.EEPROMs经常保存一些敏感的读或写的数据,像是以太网地址,安全码,特定板的校准数据等*/
 71     sysfs_bin_attr_init(&at25->bin);/*初始化一个动态分配的bin_attribute属性*/
 72     at25->bin.attr.name = "eeprom";/*属性的名字*/
 73     at25->bin.attr.mode = S_IRUSR;/*属性的模式(用户可读)*/
 74     at25->bin.read = at25_bin_read;/*属性的读方法*/
 75     at25->mem.read = at25_mem_read;/*片子的内存读函数*/
 76 
 77     at25->bin.size = at25->chip.byte_len;
 78     if (!(chip.flags & EE_READONLY)) {/*flags用来标志eeprom的位宽和读写模式,具体到dm365平台此flags为EE_ADDR2*/
 79         at25->bin.write = at25_bin_write;/*如果eeprom片子不是只读的话,那么就设置属性的写方法*/
 80         at25->bin.attr.mode |= S_IWUSR;/*增加属性的模式(用户可写)*/
 81         at25->mem.write = at25_mem_write;/*片子的内存写函数*/
 82     }
 83 
 84     err = sysfs_create_bin_file(&spi->dev.kobj, &at25->bin);/*创建一个二进制的属性文件*/
 85     if (err)
 86         goto fail;
 87 
 88     if (chip.setup)/*如果片子定义了setup函数,具体到dm365平台,此platform_data就是arch/arm/mach-davinci/board-ddm365-evm.c中定义的的at25640里并没有
 89     定义这个函数,因此为空*/
 90         chip.setup(&at25->mem, chip.context);/*使用片子的setup函数做一些初始化*/
 91 
 92     dev_info(&spi->dev, "%Zd %s %s eeprom%s, pagesize %u\n",
 93         (at25->bin.size < 1024)
 94             ? at25->bin.size
 95             : (at25->bin.size / 1024),
 96         (at25->bin.size < 1024) ? "Byte" : "KByte",
 97         at25->chip.name,
 98         (chip.flags & EE_READONLY) ? " (readonly)" : "",
 99         at25->chip.page_size);
100     return 0;
101 fail:
102     dev_dbg(&spi->dev, "probe err %d\n", err);
103     kfree(at25);
104     return err;
105 }
复制代码

根据代码就能知道,这个spi_device实际上对应的是一个eeprom,而这里就是它的操作的一些初始化.也就是说,对于分析的这个davinci代码的实例,是dm365平台的,其开发板上应该是将eeprom通过spi总线挂接在了spi_master上.也就是挂接在了SOC上,因为我们的dm365片子本身就集成了spi_master.之后要访问eeprom其实回调最终的都是这里提供的一些接口.听起来有点黏糊,看个图吧:

哎,就写到这里,本人不会用visio,画个这图画了一下午~丢人啊!


Linux驱动修炼之道-SPI驱动框架源码分析(下)

这篇文档主要介绍spi数据传输过程。

当应用层要向设备传输数据的时候,会通过ioctl向设备驱动发送传输数据的命令。如图,向SPI从设备发送读写命令,实际的读写操作还是调用了主机控制器驱动的数据传输函数。transfer函数用于spi的IO传输。但是,transfer函数一般不会执行真正的传输操作,而是把要传输的内容放到一个队列里,然后调用一种类似底半部的机制进行真正的传输。这是因为,spi总线一般会连多个spi设备,而spi设备间的访问可能会并发。如果直接在transfer函数中实现传输,那么会产生竞态,spi设备互相间会干扰。所以,真正的spi传输与具体的spi控制器的实现有关,spi的框架代码中没有涉及。像spi设备的片选,根据具体设备进行时钟调整等等都在实现传输的代码中被调用。spi的传输命令都是通过结构spi_message定义,设备程序调用transfer函数将spi_message交给spi总线驱动,总线驱动再将message传到底半部排队,实现串行化传输。



在spidev.c中实现了file_operations:

  1. <span style="font-size:18px;">static struct file_operations spidev_fops = {  
  2.     .owner =    THIS_MODULE,  
  3.     .write =    spidev_write,  
  4.     .read =     spidev_read,  
  5.     .unlocked_ioctl = spidev_ioctl,  
  6.     .open =     spidev_open,  
  7.     .release =  spidev_release,  
  8. };</span>  
这里看spidev_ioctl的实现:

  1. <span style="font-size:18px;">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.     /*查看这个命令的幻数字段是否为'k'*/  
  13.     if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC)  
  14.         return -ENOTTY;  
  15.   
  16.     /*如果方向是用户空间从内核读,即内核向用户空间写,则检查用户空间的地址是否有效*/  
  17.     if (_IOC_DIR(cmd) & _IOC_READ)  
  18.         err = !access_ok(VERIFY_WRITE,  
  19.                 (void __user *)arg, _IOC_SIZE(cmd));  
  20.     /*如果方向是用户空间向内核写,即内核读用户空间,则检查用户空间的地址是否有效*/  
  21.     if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)  
  22.         err = !access_ok(VERIFY_READ,  
  23.                 (void __user *)arg, _IOC_SIZE(cmd));  
  24.     if (err)  
  25.         return -EFAULT;  
  26.   
  27.     /* guard against device removal before, or while, 
  28.      * we issue this ioctl. 
  29.      */  
  30.     spidev = filp->private_data;  
  31.     spin_lock_irq(&spidev->spi_lock);  
  32.     spi = spi_dev_get(spidev->spi);  
  33.     spin_unlock_irq(&spidev->spi_lock);  
  34.   
  35.     if (spi == NULL)  
  36.         return -ESHUTDOWN;  
  37.   
  38.     mutex_lock(&spidev->buf_lock);  
  39.   
  40.     switch (cmd) {  
  41.     /* read requests */  
  42.     case SPI_IOC_RD_MODE:  
  43.         /*因为已经进行了地址是否有效的检查,所以这里使用__put_user,__get_user,__copy_from_user可以节省几个时钟周期呢*/  
  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.     /*设置SPI模式*/  
  59.     case SPI_IOC_WR_MODE:  
  60.         retval = __get_user(tmp, (u8 __user *)arg);  
  61.         if (retval == 0) {  
  62.             /*先将之前的模式保存起来,一旦设置失败进行回复*/  
  63.             u8  save = spi->mode;  
  64.   
  65.             if (tmp & ~SPI_MODE_MASK) {  
  66.                 retval = -EINVAL;  
  67.                 break;  
  68.             }  
  69.   
  70.             tmp |= spi->mode & ~SPI_MODE_MASK;  
  71.             spi->mode = (u8)tmp;  
  72.             retval = spi_setup(spi);  
  73.             if (retval < 0)  
  74.                 spi->mode = save;  
  75.             else  
  76.                 dev_dbg(&spi->dev, "spi mode %02x\n", tmp);  
  77.         }  
  78.         break;  
  79.     case SPI_IOC_WR_LSB_FIRST:  
  80.         retval = __get_user(tmp, (__u8 __user *)arg);  
  81.         if (retval == 0) {  
  82.             u8  save = spi->mode;  
  83.   
  84.             if (tmp)  
  85.                 spi->mode |= SPI_LSB_FIRST;  
  86.             else  
  87.                 spi->mode &= ~SPI_LSB_FIRST;  
  88.             retval = spi_setup(spi);  
  89.             if (retval < 0)  
  90.                 spi->mode = save;  
  91.             else  
  92.                 dev_dbg(&spi->dev, "%csb first\n",  
  93.                         tmp ? 'l' : 'm');  
  94.         }  
  95.         break;  
  96.     case SPI_IOC_WR_BITS_PER_WORD:  
  97.         retval = __get_user(tmp, (__u8 __user *)arg);  
  98.         if (retval == 0) {  
  99.             u8  save = spi->bits_per_word;  
  100.   
  101.             spi->bits_per_word = tmp;  
  102.             retval = spi_setup(spi);  
  103.             if (retval < 0)  
  104.                 spi->bits_per_word = save;  
  105.             else  
  106.                 dev_dbg(&spi->dev, "%d bits per word\n", tmp);  
  107.         }  
  108.         break;  
  109.     case SPI_IOC_WR_MAX_SPEED_HZ:  
  110.         retval = __get_user(tmp, (__u32 __user *)arg);  
  111.         if (retval == 0) {  
  112.             u32 save = spi->max_speed_hz;  
  113.   
  114.             spi->max_speed_hz = tmp;  
  115.             retval = spi_setup(spi);  
  116.             if (retval < 0)  
  117.                 spi->max_speed_hz = save;  
  118.             else  
  119.                 dev_dbg(&spi->dev, "%d Hz (max)\n", tmp);  
  120.         }  
  121.         break;  
  122.   
  123.     default:  
  124.         /* segmented and/or full-duplex I/O request */  
  125.         if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0))  
  126.                 || _IOC_DIR(cmd) != _IOC_WRITE) {  
  127.             retval = -ENOTTY;  
  128.             break;  
  129.         }  
  130.         /*得到用户空间数据的大小*/  
  131.         tmp = _IOC_SIZE(cmd);  
  132.         /*如果这些数据不能分成spi_ioc_transfer的整数倍,则不能进行传输,spi_io_transfer是对spi_transfer的映射*/  
  133.         if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) {  
  134.             retval = -EINVAL;  
  135.             break;  
  136.         }  
  137.         /*计算出能分多少个spi_ioc_transfer*/  
  138.         n_ioc = tmp / sizeof(struct spi_ioc_transfer);  
  139.         if (n_ioc == 0)  
  140.             break;  
  141.   
  142.         /*在内核中分配装载这些数据的内存空间*/  
  143.         ioc = kmalloc(tmp, GFP_KERNEL);  
  144.         if (!ioc) {  
  145.             retval = -ENOMEM;  
  146.             break;  
  147.         }  
  148.         /*把用户空间的数据拷贝过来*/  
  149.         if (__copy_from_user(ioc, (void __user *)arg, tmp)) {  
  150.             kfree(ioc);  
  151.             retval = -EFAULT;  
  152.             break;  
  153.         }  
  154.   
  155.         /*进行数据传输*/  
  156.         <span style="color:#ff0000;">retval = spidev_message(spidev, ioc, n_ioc);</span>  
  157.         kfree(ioc);  
  158.         break;  
  159.     }  
  160.   
  161.     mutex_unlock(&spidev->buf_lock);  
  162.     spi_dev_put(spi);  
  163.     return retval;  
  164. }  
  165. </span>  

下面跟踪spidev_message看看:

  1. <span style="font-size:18px;">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.     /*初始化spi_message的tranfers链表头*/  
  12.     spi_message_init(&msg);  
  13.     /*分配n个spi_transfer的内存空间,一个spi_message由多个数据段spi_message组成*/  
  14.     k_xfers = kcalloc(n_xfers, sizeof(*k_tmp), GFP_KERNEL);  
  15.     if (k_xfers == NULL)  
  16.         return -ENOMEM;  
  17.   
  18.     buf = spidev->buffer;  
  19.     total = 0;  
  20.     /*这个for循环的主要任务是将所有的spi_transfer组装成一个spi_message*/  
  21.     for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;  
  22.             n;  
  23.             n--, k_tmp++, u_tmp++) {  
  24.         /*u_tmp是从用户空间传下来的spi_ioc_message的大小,spi_ioc_message是对spi_message的映射*/  
  25.         k_tmp->len = u_tmp->len;  
  26.         /*统计要传输数据的总量*/  
  27.         total += k_tmp->len;  
  28.         if (total > bufsiz) {  
  29.             status = -EMSGSIZE;  
  30.             goto done;  
  31.         }  
  32.         /*spi_transfer是一个读写的buffer对,如果是要接收则把buffer给接收的rx_buf*/  
  33.         if (u_tmp->rx_buf) {  
  34.             k_tmp->rx_buf = buf;  
  35.             if (!access_ok(VERIFY_WRITE, (u8 __user *)  
  36.                         (uintptr_t) u_tmp->rx_buf,  
  37.                         u_tmp->len))  
  38.                 goto done;  
  39.         }  
  40.         /*如果要传输,这个buffer给tx_buf使用,从用户空间拷过来要传输的数据*/  
  41.         if (u_tmp->tx_buf) {  
  42.             k_tmp->tx_buf = buf;  
  43.             if (copy_from_user(buf, (const u8 __user *)  
  44.                         (uintptr_t) u_tmp->tx_buf,  
  45.                     u_tmp->len))  
  46.                 goto done;  
  47.         }  
  48.         /*指向下一段内存*/  
  49.         buf += k_tmp->len;  
  50.         /*最后一个transfer传输完毕是否会影响片选*/  
  51.         k_tmp->cs_change = !!u_tmp->cs_change;  
  52.         /*每字长的字节数*/  
  53.         k_tmp->bits_per_word = u_tmp->bits_per_word;  
  54.         /*一段数据传输完需要一定的时间等待*/  
  55.         k_tmp->delay_usecs = u_tmp->delay_usecs;  
  56.         /*初始化传输速度*/  
  57.         k_tmp->speed_hz = u_tmp->speed_hz;  
  58.         /*将spi_transfer通过它的transfer_list字段挂到spi_message的transfer队列上*/  
  59.         spi_message_add_tail(k_tmp, &msg);  
  60.     }  
  61.     /*调用底层的传输函数*/  
  62.     <span style="color:#ff0000;">status = spidev_sync(spidev, &msg);</span>  
  63.     if (status < 0)  
  64.         goto done;  
  65.   
  66.     /* copy any rx data out of bounce buffer */  
  67.     buf = spidev->buffer;  
  68.     /*把传输数据拷贝到用户空间打印出来,可以查看是否传输成功*/  
  69.     for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) {  
  70.         if (u_tmp->rx_buf) {  
  71.             if (__copy_to_user((u8 __user *)  
  72.                     (uintptr_t) u_tmp->rx_buf, buf,  
  73.                     u_tmp->len)) {  
  74.                 status = -EFAULT;  
  75.                 goto done;  
  76.             }  
  77.         }  
  78.         buf += u_tmp->len;  
  79.     }  
  80.     status = total;  
  81.   
  82. done:  
  83.     kfree(k_xfers);  
  84.     return status;  
  85. }  
  86. </span>  

看spidev_sync的实现:

  1. <span style="font-size:18px;">static ssize_t  
  2. spidev_sync(struct spidev_data *spidev, struct spi_message *message)  
  3. {  
  4.     /*声明并初始化一个完成量*/  
  5.     DECLARE_COMPLETION_ONSTACK(done);  
  6.     int status;  
  7.     /*指定spi_message使用的唤醒完成量函数*/  
  8.     message->complete = spidev_complete;  
  9.     message->context = &done;  
  10.   
  11.     spin_lock_irq(&spidev->spi_lock);  
  12.     if (spidev->spi == NULL)  
  13.         status = -ESHUTDOWN;  
  14.     else  
  15.         /*调用spi核心中的函数进行数据传输*/  
  16.     <span style="color:#ff0000;"> status = spi_async(spidev->spi, message);</span>  
  17.     spin_unlock_irq(&spidev->spi_lock);  
  18.   
  19.     if (status == 0) {  
  20.         /*等待完成量被唤醒*/  
  21.         wait_for_completion(&done);  
  22.         status = message->status;  
  23.         if (status == 0)  
  24.             status = message->actual_length;  
  25.     }  
  26.     return status;  
  27. }  
  28. </span>  
spi_async在spi.h中定义的:
  1. <span style="font-size:18px;">static inline int  
  2. spi_async(struct spi_device *spi, struct spi_message *message)  
  3. {  
  4.     message->spi = spi;  
  5.     return spi->master->transfer(spi, message);  
  6. }  
  7. </span>  
这里的master->transfer是在spi_bitbang_start中进行赋值的:

bitbang->master->transfer= spi_bitbang_transfer;

看spi_bitbang_transfer的实现:

  1. <span style="font-size:18px;">int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m)  
  2. {  
  3.     struct spi_bitbang  *bitbang;  
  4.     unsigned long       flags;  
  5.     int         status = 0;  
  6.   
  7.     m->actual_length = 0;  
  8.     m->status = -EINPROGRESS;  
  9.     /*在spi_alloc_master函数中调用spi_master_set_devdata把struct s3c24xx_spi结构存放起来,而struct spi_bitbang正是struct s3c24xx_spi结构所包含的第一个结构*/  
  10.     bitbang = spi_master_get_devdata(spi->master);  
  11.   
  12.     spin_lock_irqsave(&bitbang->lock, flags);  
  13.     if (!spi->max_speed_hz)  
  14.         status = -ENETDOWN;  
  15.     else {  
  16.         /*把message加入到bitbang的等待队列中*/  
  17.         list_add_tail(&m->queue, &bitbang->queue);  
  18.         /*把bitbang-work加入bitbang->workqueue中,调度运行*/  
  19.         queue_work(bitbang->workqueue, &bitbang->work);  
  20.     }  
  21.     spin_unlock_irqrestore(&bitbang->lock, flags);  
  22.   
  23.     return status;  
  24. }  
  25. EXPORT_SYMBOL_GPL(spi_bitbang_transfer);  
  26. </span>  

分析工作队列的处理函数:


  1. <span style="font-size:18px;">static void bitbang_work(struct work_struct *work)  
  2. {  
  3.     struct spi_bitbang  *bitbang =  
  4.         container_of(work, struct spi_bitbang, work);  
  5.     unsigned long       flags;  
  6.   
  7.     spin_lock_irqsave(&bitbang->lock, flags);  
  8.     /*设置成忙状态*/  
  9.     bitbang->busy = 1;  
  10.     /*对bitqueue中的每一个spi_message进行处理*/  
  11.     while (!list_empty(&bitbang->queue)) {  
  12.         struct spi_message  *m;  
  13.         struct spi_device   *spi;  
  14.         unsigned        nsecs;  
  15.         struct spi_transfer *t = NULL;  
  16.         unsigned        tmp;  
  17.         unsigned        cs_change;  
  18.         int         status;  
  19.         int         (*setup_transfer)(struct spi_device *,  
  20.                         struct spi_transfer *);  
  21.   
  22.         m = container_of(bitbang->queue.next, struct spi_message,  
  23.                 queue);  
  24.         /*从队列中驱动这个spi_message*/  
  25.         list_del_init(&m->queue);  
  26.         spin_unlock_irqrestore(&bitbang->lock, flags);  
  27.   
  28.         nsecs = 100;  
  29.   
  30.         spi = m->spi;  
  31.         tmp = 0;  
  32.         cs_change = 1;  
  33.         status = 0;  
  34.         setup_transfer = NULL;  
  35.         /*对spi_message的transfers上的每个spi_transfer进行处理*/  
  36.         list_for_each_entry (t, &m->transfers, transfer_list) {  
  37.         。。。。。。。。。。。。。。。。。  
  38.             if (t->len) {                  
  39.                 if (!m->is_dma_mapped)  
  40.                     t->rx_dma = t->tx_dma = 0;  
  41.                 /*调用bitbang->txrx_bufs进行数据的传输,bitbang->txrx_bufs = s3c24xx_spi_txrx;这个在s3c24xx_spi_probe中进行赋值的*/  
  42.                 <span style="color:#ff0000;">status = bitbang->txrx_bufs(spi, t);</span>  
  43.             }  
  44.         。。。。。。。。。。。。。。。。  
  45.   
  46.         m->status = status;  
  47.         /*传输完成,唤醒刚才的那个完成变量*/  
  48.         m->complete(m->context);  
  49.   
  50.         /* restore speed and wordsize */  
  51.         if (setup_transfer)  
  52.             setup_transfer(spi, NULL);  
  53.         if (!(status == 0 && cs_change)) {  
  54.             ndelay(nsecs);  
  55.             bitbang->chipselect(spi, BITBANG_CS_INACTIVE);  
  56.             ndelay(nsecs);  
  57.         }  
  58.   
  59.         spin_lock_irqsave(&bitbang->lock, flags);  
  60.     }  
  61.     bitbang->busy = 0;  
  62.     spin_unlock_irqrestore(&bitbang->lock, flags);  
  63. }  
  64. </span>  
这个工作队列的处理函数中调用了spi controller driver中的传输函数:
  1. <span style="font-size:18px;">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;       //存放实际spi传输的数据数目  
  12.     /*初始化了完成量*/  
  13.     init_completion(&hw->done);  
  14.       
  15.     /* 
  16.      *只需发送第一个字节(如果发送为空,则发送0xff),中断中就会自动发送完其他字节(并接受数据) 
  17.      *直到所有数据发送完毕且所有数据接收完毕才返回 
  18.      */  
  19.     writeb(hw_txbyte(hw, 0), hw->regs + S3C2410_SPTDAT);  
  20.     /*等待完成量被唤醒*/  
  21.     wait_for_completion(&hw->done);  
  22.     return hw->count;  
  23. }  
  24. static inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count)  
  25. {  
  26.         return hw->tx ? hw->tx[count] : 0xff;  
  27.         //如果还有数据没接收完且要发送的数据经已发送完毕,发送空数据0xFF  
  28. }  
  29. </span>  
下面来分析中断函数:
  1. <span style="font-size:18px;">static irqreturn_t s3c24xx_spi_irq(int irq, void *dev)  
  2. {  
  3.     struct s3c24xx_spi *hw = dev;  
  4.     /*读取spi的状态寄存器*/  
  5.     unsigned int spsta = readb(hw->regs + S3C2410_SPSTA);  
  6.     unsigned int count = hw->count;  
  7.     /*检测冲突*/  
  8.     if (spsta & S3C2410_SPSTA_DCOL) {               
  9.         dev_dbg(hw->dev, "data-collision\n");   
  10.         /*唤醒完成量*/  
  11.         complete(&hw->done);  
  12.         goto irq_done;  
  13.     }  
  14.     /*设备忙*/  
  15.     if (!(spsta & S3C2410_SPSTA_READY)) {  
  16.         dev_dbg(hw->dev, "spi not ready for tx?\n");  
  17.         /*唤醒完成量*/  
  18.         complete(&hw->done);  
  19.         goto irq_done;  
  20.     }  
  21.   
  22.     hw->count++;  
  23.     /*接收数据*/  
  24.     if (hw->rx)  
  25.         hw->rx[count] = readb(hw->regs + S3C2410_SPRDAT);  
  26.   
  27.     count++;  
  28.     /*如果count小于需要发送或接收数据的数目,发送其他数据*/  
  29.     if (count < hw->len)  
  30.         writeb(hw_txbyte(hw, count), hw->regs + S3C2410_SPTDAT);  
  31.     else  
  32.         /*唤醒完成量,通知s3c24xx_spi_txrx函数*/  
  33.         complete(&hw->done);  
  34.   
  35.  irq_done:  
  36.     return IRQ_HANDLED;  
  37. }  
  38. </span>  
至此spi数据传输过程完成,如果不想为自己的SPI设备写驱动,那么可以用Linux自带的spidev.c提供的驱动程序,只要在登记时,把设备名设置成spidev就可以了。spidev.c会在device目录下自动为每一个匹配的SPI设备创建设备节点,节点名"spi%d"。之后,用户程序可以通过字符型设备的通用接口控制SPI设备。需要注意的是,spidev创建的设备在设备模型中属于虚拟设备,他的class是spidev_class,他的父设备是在boardinfo中定义的spi设备。





STM32是意法半导体公司推出的一系列32位微控制器系列,其中SPI3是STM32微控制器中的一种串行外设接口。 SPI(Serial Peripheral Interface)是一种常见的串行通信接口,在STM32中通过SPI3外设可以实现与其他设备的数据交换。SPI3是STM32中第三个独立的SPI外设,具有高速、全双工、同步的特点。 SPI3外设在STM32微控制器中的用途十分广泛。通过SPI3接口,可以与各种外设进行通信,如传感器、存储器、显示屏、通信模块等。SPI3支持主从模式的数据交换,并且可以支持多个从设备,实现多路数据传输。 SPI3外设在硬件上包含了多个寄存器和数据寄存器,通过设置这些寄存器可以配置SPI3的通信参数,如数据位数、数据传输速率、时钟极性与相位等。SPI3通过时钟极性和相位配置可以适配不同外设的时序要求。 在软件层面,可以通过编写对应的代码来初始化和配置SPI3外设,并通过读写寄存器和数据寄存器的方式进行数据收发。通常,发送数据通过SPI3的数据寄存器写入,接收数据则从SPI3的数据寄存器中读出。 综上所述,SPI3是STM32微控制器中的一种串行外设接口,用于实现与其他设备的数据交换。它具有高速、全双工、同步的特点,支持主从模式和多路数据传输。通过配置寄存器和数据寄存器,可以灵活地配置SPI3的通信参数,并通过读写数据寄存器进行数据收发。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值