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. Java数组排序和搜索

    如何排序数组并搜索其中的元素? 以下示例显示如何使用sort()和binarySearch()方法来完成任务.用户定义的方法printArray()用于显示数组输出: package com.yiib ...

  2. JUnit4 基本用法实例

    本教程介绍了在JUnit4中支持的基本注解. import org.junit.*; import static org.junit.Assert.*; import java.util.*; /** ...

  3. 使用appledoc 生成技术API文档具体解释

    一. 首先安装 appledoc 第一步:使用终端命令进行下载安装 git clone git://github.com/tomaz/appledoc.git cd ./appledoc sudo s ...

  4. C# Image与Base64编码互转函数

    public Bitmap GetImageFromBase64(string base64string) { byte[] b = Convert.FromBase64String(base64st ...

  5. php 区分0和空

    能够区分出来的有2,4,6 方法 public function test(){ $test=; if($test==''){ echo '<br />在php中1,0即为空'; //被输 ...

  6. vue路由跳转报错解决

    vue路由跳转: setTimeout(function () { console.log(this); this.$router.push("/login"); },800) 语 ...

  7. 前端常用linux命令

    文件和目录 cd /home 进入 '/ home' 目录' cd .. 返回上一级目录 cd ../.. 返回上两级目录 cd 进入个人的主目录 cd ~user1 进入个人的主目录 cd - 返回 ...

  8. nvm安装node和npm,个人踩坑记录

    我采用nvm-setup安装windows版本的nvm nvm安装node出现的问题: 1.node成功了,npm没成功 解决:在nvm 安装了node之后,输入npm找不到该命令,当时安装报错如下: ...

  9. jQuery实现自动调用和触发某个事件的方法

    1.比如我们通过jquery定义了一个点击事件,我们如何自动触发他: $(function(){    $('#button').click(function(){      alert('butto ...

  10. Android ScrollView 和ListView 一起使用的问题汇总

    1.ScrollView 嵌套 ListView  ,touch事件的截获问题. 参考 http://www.cnblogs.com/lqminn/archive/2013/03/02/2940194 ...