上一章叙述了关于spi驱动的主控制器层的内容,接下来这一章将叙述spi驱动的从设备层。
我们首先从下图中梳理一下spi驱动的初始化流程:
由上图可知,在驱动初始化的最后一步就是通过调用spi从设备驱动层的spi_probe来完成的。
首先分析spi从设备驱动的入口函数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);
status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);
if (status < 0)
return status;
status = class_register(&spidev_class);
if (status < 0) {
unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
return status;
}
status = spi_register_driver(&spidev_spi);
if (status < 0) {
class_unregister(&spidev_class);
unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
}
return status;
}
此函数注册了一个spi字符型设备,并在最后调用了spi_register_driver()设备来注册了spi从设备驱动结构,从而使的程序配对成功后,直接调用spidev_probe()函数。
而spidev_probe()函数如下所示:
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;
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) {
spidev->dev.parent = &spi->dev;
spidev->dev.class = &spidev_class;
spidev->dev.devt = MKDEV(SPIDEV_MAJOR, minor);
snprintf(spidev->dev.bus_id, sizeof spidev->dev.bus_id,
"spidev%d.%d",
spi->master->bus_num, spi->chip_select);
status = device_register(&spidev->dev);
} else {
dev_dbg(&spi->dev, "no minor number available!\n");
status = -ENODEV;
}
if (status == 0) {
set_bit(minor, minors);
dev_set_drvdata(&spi->dev, spidev);
list_add(&spidev->device_entry, &device_list);
}
mutex_unlock(&device_list_lock);
if (status != 0)
kfree(spidev);
return status;
}
其中此函数的参数是在调用spi_new_device()后,新建的spi_device从设备结构。
由此可知,在此文件中的open、read和write等函数便均可通过spi_device从设备结构来关联到spi_master来实现其特定的功能。