957至962行,一个SPI控制器用一个master来描述。这里使用SPI核心的spi_alloc_master函数请求分配master。它在drivers/spi/spi.c文件中定义:

 struct spi_master *spi_alloc_master(struct device *dev, unsigned size)
{
struct spi_master *master; if (!dev)
return NULL; master = kzalloc(size + sizeof *master, GFP_KERNEL);
if (!master)
return NULL; device_initialize(&master->dev);
master->dev.class = &spi_master_class;
master->dev.parent = get_device(dev);
spi_master_set_devdata(master, &master[]); return master;
}

478至480行,这里分配的内存大小是*master加size,包含了两部分内存。

482行,设备模型中的初始设备函数,不说。

483行,spi_master_class在SPI子系统初始化的时候就已经注册好了。

484行,设置当前设备的父设备,关于设备模型的。

485行,&master[1]就是master之后的另一部分内存的起始地址。

回到s3c64xx_spi_probe函数,966行,就是取出刚才申请的第二部分内存的起始地址。

966至980行,根据预先定义的变量、函数进行填充。

983行,有点意思,说明该驱动支持哪些SPI模式。

985至997行,写过Linux驱动都应该知道,IO内存映射。

999至1003行,SPI IO管脚配置,将相应的IO管脚设置为SPI功能。

1006至1032行,使能SPI时钟。

1034至1040行,创建单个线程的工作队列,用于数据收发操作。

1043行,硬件初始化,初始化SPI控制器寄存器。

1045至1048行,锁,工作队列等初始化。

1050至1054行,spi_register_master在drivers/spi/spi.c文件中定义:

 int spi_register_master(struct spi_master *master)
{
static atomic_t dyn_bus_id = ATOMIC_INIT((<<) - );
struct device *dev = master->dev.parent;
int status = -ENODEV;
int dynamic = ; if (!dev)
return -ENODEV; /* even if it's just one always-selected device, there must
00000522 * be at least one chipselect
00000523 */
if (master->num_chipselect == )
return -EINVAL; /* convention: dynamically assigned bus IDs count down from the max */
if (master->bus_num < ) {
/* FIXME switch to an IDR based scheme, something like
00000530 * I2C now uses, so we can't run out of "dynamic" IDs
00000531 */
master->bus_num = atomic_dec_return(&dyn_bus_id);
dynamic = ;
} spin_lock_init(&master->bus_lock_spinlock);
mutex_init(&master->bus_lock_mutex);
master->bus_lock_flag = ; /* register the device, then userspace will see it.
00000541 * registration fails if the bus ID is in use.
00000542 */
dev_set_name(&master->dev, "spi%u", master->bus_num);
status = device_add(&master->dev);
if (status < )
goto done;
dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),
dynamic ? " (dynamic)" : ""); /* populate children from any spi device tables */
scan_boardinfo(master);
status = ; /* Register devices from the device tree */
of_register_spi_devices(master);
done:
return status;
}

524行,一个SPI控制器至少有一个片选,因此片选数为0则出错。

528至534行,如果总线号小于0则动态分配一个总线号。

543至548行,把master加入到设备模型中。

551行,scan_boardinfo函数同样是在driver/spi/spi.c中定义:

 static void scan_boardinfo(struct spi_master *master)
{
struct boardinfo *bi; mutex_lock(&board_lock);
list_for_each_entry(bi, &board_list, list) {
struct spi_board_info *chip = bi->board_info;
unsigned n; for (n = bi->n_board_info; n > ; n--, chip++) {
if (chip->bus_num != master->bus_num)
continue;
/* NOTE: this relies on spi_new_device to
00000427 * issue diagnostics when given bogus inputs
00000428 */
(void) spi_new_device(master, chip);
}
}
mutex_unlock(&board_lock);
}

419至431做了两件事情,首先遍历board_list这个链表,每找到一个成员就将它的总线号与master的总线号进行比较,如果相等则调用spi_new_device函数创建一个spi设备。

 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.
00000343 *
00000344 * Also, unless we change the return value convention to use
00000345 * error-or-pointer (not NULL-or-pointer), troubleshootability
00000346 * suggests syslogged diagnostics are best here (ugh).
00000347 */ 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; status = spi_add_device(proxy);
if (status < ) {
spi_dev_put(proxy);
return NULL;
} return proxy;
}

349至351行,spi_alloc_device函数的定义:

 struct spi_device *spi_alloc_device(struct spi_master *master)
{
struct spi_device *spi;
struct device *dev = master->dev.parent; if (!spi_master_get(master))
return NULL; spi = kzalloc(sizeof *spi, GFP_KERNEL);
if (!spi) {
dev_err(dev, "cannot alloc spi_device\n");
spi_master_put(master);
return NULL;
} spi->master = master;
spi->dev.parent = dev;
spi->dev.bus = &spi_bus_type;
spi->dev.release = spidev_release;
device_initialize(&spi->dev);
return spi;
}

234至242行,错误检测和分配内存。

246行,该spi设备属于SPI子系统初始化时注册的那条叫“spi”的总线。

248行,设备模型方面的初始化,不说。

回到spi_new_device函数,355至362行,是一些赋值,其中359行比较关键,设备名字拷贝,362行,之前说过了,设置为NULL。看364行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. */
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 */
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
00000283 * chipselect **BEFORE** we call setup(), else we'll trash
00000284 * its configuration. Lock against concurrent add() calls.
00000285 */
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
00000298 * normally rely on the device being setup. Devices
00000299 * using SPI_CS_HIGH can't coexist well otherwise...
00000300 */
status = spi_setup(spi);
if (status < ) {
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 < )
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;
}

270至275行,片选号是从0开始的,如果大于或者等于片选数的话则返回出错。

288至295行,遍历spi总线,看是否已经注册过该设备。

301至306行,spi_setup函数的定义:

 int spi_setup(struct spi_device *spi)
{
unsigned bad_bits;
int status; /* help drivers fail *cleanly* when they need options
00000651 * that aren't supported with their current master
00000652 */
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 = ; 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;
}

653至658行,如果驱动不支持该设备的工作模式则返回出错。

663行,调用控制器驱动里的s3c64xx_spi_setup函数,只看前一部分代码:

 static int s3c64xx_spi_setup(struct spi_device *spi)
{
struct s3c64xx_spi_csinfo *cs = spi->controller_data;
struct s3c64xx_spi_driver_data *sdd;
struct s3c64xx_spi_info *sci;
struct spi_message *msg;
u32 psr, speed;
unsigned long flags;
int err = ; if (cs == NULL || cs->set_level == NULL) {
dev_err(&spi->dev, "No CS for SPI(%d)\n", spi->chip_select);
return -ENODEV;
} …

从797行就可以知道在实例化struct spi_board_info时,其controller_data成员就应该指向struct s3c64xx_spi_csinfo的对象。

spi_setup函数结束了,回到spi_add_device函数,309至314行,将该设备加入到设备模型。一直后退,回到spi_register_master函数,就剩下555行of_register_spi_devices这个函数,由于本文所讲的驱动没有使用到设备树方面的内容,所以该函数里什么也没做,直接返回。

到这里,SPI控制器驱动的初始化过程已经说完了。接下来要说的是SPI设备驱动。其实Linux中已经实现了一个通用的SPI设备驱动,另外还有一个是用IO口模拟的SPI驱动,在这里,只说前者。

初始化函数是在drivers/spi/spidev.c文件中定义:

 static int __init spidev_init(void)
{
int status; /* Claim our 256 reserved device numbers. Then register a class
00000663 * that will key udev/mdev to add/remove /dev nodes. Last, register
00000664 * the driver which manages those device numbers.
00000665 */
BUILD_BUG_ON(N_SPI_MINORS > ); status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);
if (status < )
return status; spidev_class = class_create(THIS_MODULE, "spidev");
if (IS_ERR(spidev_class)) {
unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
return PTR_ERR(spidev_class);
} status = spi_register_driver(&spidev_spi_driver);
if (status < ) {
class_destroy(spidev_class);
unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
}
return status;
}

668至670行,注册字符设备,参数spidev_fops是struct file_operations的实例,这里就可以知道,用户程序的open、write等操作最终会调用这里面的函数。

673至677行,创建spidev这一类设备,为后面自动生成设备节点做准备。

679至684行,注册spi设备驱动,spi_register_driver函数的定义在drivers/spi/spi.c中:

 int spi_register_driver(struct spi_driver *sdrv)
{
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);
}

184行,该驱动所属的总线。185至190行,一些函数指针的赋值。191行,将驱动注册进设备模型,注册成功的话就会在总线上寻找设备,调用总线上的match函数,看能否与之匹配起来,匹配成功的话,驱动中的probe函数就会被调用。

参数spidev_spi_driver是struct 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.
00000650 * We don't do anything except pass the requests to/from
00000651 * the underlying controller. The refrigerator handles
00000652 * most issues; the controller driver handles the rest.
00000653 */
};

下面看spidev_probe函数。在drivers/spi/spidev.c中定义的:

 static int __devinit spidev_probe(struct spi_device *spi)
{
struct spidev_data *spidev;
int status;
unsigned long minor; /* Allocate driver data */
spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);
if (!spidev)
return -ENOMEM; /* Initialize the driver data */
spidev->spi = spi;
spin_lock_init(&spidev->spi_lock);
mutex_init(&spidev->buf_lock); INIT_LIST_HEAD(&spidev->device_entry); /* If we can allocate a minor number, hook up this device.
00000584 * Reusing minors is fine so long as udev or mdev is working.
00000585 */
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) : ;
} else {
dev_dbg(&spi->dev, "no minor number available!\n");
status = -ENODEV;
}
if (status == ) { set_bit(minor, minors); list_add(&spidev->device_entry, &device_list);
}
mutex_unlock(&device_list_lock); if (status == )
spi_set_drvdata(spi, spidev);
else
kfree(spidev); return status;
}

Linux设备驱动剖析之SPI(二)的更多相关文章

  1. Linux设备驱动剖析之SPI(三)

    572至574行,分配内存,注意对象的类型是struct spidev_data,看下它在drivers/spi/spidev.c中的定义: struct spidev_data { dev_t de ...

  2. Linux设备驱动剖析之SPI(一)

    写在前面 初次接触SPI是因为几年前玩单片机的时候,由于普通的51单片机没有SPI控制器,所以只好用IO口去模拟.最近一次接触SPI是大三时参加的校内选拔赛,当时需要用2440去控制nrf24L01, ...

  3. Linux设备驱动剖析之SPI(四)

    781行之前没什么好说的,直接看783行,将work投入到工作队列里,然后就返回,在这里就可以回答之前为什么是异步的问题.以后在某个合适的时间里CPU会执行这个work指定的函数,这里是s3c64xx ...

  4. linux设备驱动归纳总结(二):模块的相关基础概念【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-59415.html linux设备驱动归纳总结(二):模块的相关基础概念 系统平台:Ubuntu 10 ...

  5. 【Linux开发】linux设备驱动归纳总结(二):模块的相关基础概念

    linux设备驱动归纳总结(二):模块的相关基础概念 系统平台:Ubuntu 10.04 开发平台:S3C2440开发板 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

  6. Linux设备驱动剖析之IIC(一)

    写在前面 由于IIC总线只需要两根线就可以完成读写操作,而且通信协议简单,一条总线上可以挂载多个设备,因此被广泛使用.但是IIC总线有一个缺点,就是传输速率比较低.本文基于Linux-2.6.36版本 ...

  7. Linux设备驱动剖析之Input(二)

    分别是总线类型.厂商号.产品号和版本号. 1156行,evbit,设备支持的事件类型的位图,每一位代表一种事件,比如EV_KEY.EV_REL事件等等.BITS_TO_LONGS(nr)是一个宏,假设 ...

  8. Linux设备驱动剖析之IIC(二)

    953行,适配器的编号大于MAX_ID_MASK是不行的,MAX_ID_MASK是一个宏,展开后的值为61. 957至968行,关于管理小整形ID数的,没怎么了解,略过. 974行,调用i2c_reg ...

  9. Linux设备驱动剖析之Input(四)

    static void input_pass_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) ...

随机推荐

  1. 第三百七十六节,Django+Xadmin打造上线标准的在线教育平台—创建用户操作app,在models.py文件生成5张表,用户咨询表、课程评论表、用户收藏表、用户消息表、用户学习表

    第三百七十六节,Django+Xadmin打造上线标准的在线教育平台—创建用户操作app,在models.py文件生成5张表,用户咨询表.课程评论表.用户收藏表.用户消息表.用户学习表 创建名称为ap ...

  2. e868. 获取和设置本地外观

    By default, Swing uses a cross-platform look and feel called Metal. In most cases, it is more desira ...

  3. e587. Filling Basic Shapes

    There are two ways to fill basic shapes like lines and rectangles. The first is to use specific draw ...

  4. c#中的对象生命周期

    无论是指类型的变量或是类类型的变量,其存储单元都是在栈中分配的,唯一不同的是类类型的变量实际上存储的是该类对象的指针,相当于vc6中的CType*,只是在.net平台的语言中将指针的概念屏蔽掉了.我们 ...

  5. svn -- 数据备份,版本回退,版本冲突,多仓库配置

    数据备份 差异存储法: 版本回退 版本冲突 原理图: 解决办法: 三种方案: 1)合理分配项目开发模块 wangcai:文章,邮件,会员 xiaoqiang:静态化,缓存,前台 2)合理分配项目开发时 ...

  6. IE8不支持数组的indexOf方法

    在IE8下有个js错误,但是在其它浏览器下(Firefox, Chrome, IE9)下面都很正常.后来调试发现原因是在IE8下,js数组没有indexOf方法. 在使用indexOf方法前,执行一下 ...

  7. vue 中view层中方法的使用

    1.使用filters computed:{ }, filters: { filterA: function(value) { return value + 'wh' } }, 2.用法:  {{it ...

  8. 录制iPhone屏幕并转成gif方案

    app的开发经常会碰到需要演示一个交互,或者一个bug的情况,通常涉及一连串的操作以及操作的反馈,这是文字,或截图都无法表达的,视频的话还得播放器参与,最好的一个想法应该是录制屏幕然后再转成gif图片 ...

  9. C语言的结构体

    举例,一个结构体的定义如下: typedef struct _foo { ]; int age; int sex; } foo; 对齐 如果直接对上面的结构体作sizeof()运算: printf( ...

  10. 【2018年12月14日】A股最便宜的股票

    新钢股份(SH600782) - 当前便宜指数:193.12 - 滚动扣非市盈率PE:2.91 - 动态市净率PB:0.96 - 动态年化股息收益率:1.75% - 新钢股份(SH600782)的历史 ...