linux SPI驱动——spidev之driver(六)
一: spidev_init注册spidev
1: static int __init spidev_init(void)
2: {
3: int status;
4:
5: /* Claim our 256 reserved device numbers. Then register a class
6: * that will key udev/mdev to add/remove /dev nodes. Last, register
7: * the driver which manages those device numbers.
8: */
9: BUILD_BUG_ON(N_SPI_MINORS > 256);
10: /* 注册spi字符设备 */
11: status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);
12: if (status < 0) {
13: return status;
14: }
15: /* 为该设备创建一个class spidev */
16: spidev_class = class_create(THIS_MODULE, "spidev");
17: if (IS_ERR(spidev_class)) {
18: unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
19: return PTR_ERR(spidev_class);
20: }
21: /* register匹配到device ,最终调用prob函数 */
22: status = spi_register_driver(&spidev_spi_driver);
23: if (status < 0) {
24: class_destroy(spidev_class);
25: unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
26: }
27: return status;
28: }
29: module_init(spidev_init);
30:
31: static void __exit spidev_exit(void)
32: {
33: spi_unregister_driver(&spidev_spi_driver);
34: class_destroy(spidev_class);
35: unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
36: }
37: module_exit(spidev_exit);
38:
39: MODULE_AUTHOR("Andrea Paterniani, <a.paterniani@swapp-eng.it>");
40: MODULE_DESCRIPTION("User mode SPI device interface");
41: MODULE_LICENSE("GPL");
42: MODULE_ALIAS("spi:spidev");
总结:
1)注册一个字符设备,cat /proc/device 会查看到“153 spi”主设备号位153的设备
2) 创建一个class spidev ,”/sys/class/spidev/”
3) spi_register_driver 注册spi driver。
二:spidev_probe 函数
1: static int __devinit spidev_probe(struct spi_device *spi)
2: {
3: struct spidev_data *spidev;
4: int status;
5: unsigned long minor;
6:
7: /* Allocate driver data */
8: spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);
9: if (!spidev)
10: return -ENOMEM;
11:
12: /* Initialize the driver data */
13: spidev->spi = spi;
14: spin_lock_init(&spidev->spi_lock);
15: mutex_init(&spidev->buf_lock);
16:
17: INIT_LIST_HEAD(&spidev->device_entry);
18:
19: /* If we can allocate a minor number, hook up this device.
20: * Reusing minors is fine so long as udev or mdev is working.
21: */
22: mutex_lock(&device_list_lock);
23:
24: minor = find_first_zero_bit(minors, N_SPI_MINORS);
25: if (minor < N_SPI_MINORS) {
26: struct device *dev;
27:
28: spidev->devt = MKDEV(SPIDEV_MAJOR, minor);
29: dev = device_create(spidev_class, &spi->dev, spidev->devt,
30: spidev, "spidev%d.%d",
31: spi->master->bus_num, spi->chip_select);
32: status = IS_ERR(dev) ? PTR_ERR(dev) : 0;
33: } else {
34: dev_dbg(&spi->dev, "no minor number available!\n");
35: status = -ENODEV;
36: }
37: if (status == 0) {
38: set_bit(minor, minors);
39: list_add(&spidev->device_entry, &device_list);
40: }
41:
42: mutex_unlock(&device_list_lock);
43:
44: if (status == 0)
45: spi_set_drvdata(spi, spidev);
46: else
47: kfree(spidev);
48:
49: return status;
50: }
1: int spi_register_driver(struct spi_driver *sdrv)
2: {
3: sdrv->driver.bus = &spi_bus_type;
4: if (sdrv->probe)
5: sdrv->driver.probe = spi_drv_probe;
6: if (sdrv->remove)
7: sdrv->driver.remove = spi_drv_remove;
8: if (sdrv->shutdown)
9: sdrv->driver.shutdown = spi_drv_shutdown;
10: return driver_register(&sdrv->driver);
11: }
1: static int spi_drv_probe(struct device *dev)
2: {
3: const struct spi_driver *sdrv = to_spi_driver(dev->driver);
4:
5: return sdrv->probe(to_spi_device(dev));
6: }
2)追踪driver_register(&sdrv->driver);
1: int driver_register(struct device_driver *drv)
2: {
3: int ret;
4: struct device_driver *other;
5:
6: BUG_ON(!drv->bus->p);
7:
8: if ((drv->bus->probe && drv->probe) ||
9: (drv->bus->remove && drv->remove) ||
10: (drv->bus->shutdown && drv->shutdown))
11: printk(KERN_WARNING "Driver '%s' needs updating - please use "
12: "bus_type methods\n", drv->name);
13:
14: other = driver_find(drv->name, drv->bus);
15: if (other) {
16: put_driver(other);
17: printk(KERN_ERR "Error: Driver '%s' is already registered, "
18: "aborting...\n", drv->name);
19: return -EBUSY;
20: }
21:
22: ret = bus_add_driver(drv);
23: if (ret)
24: return ret;
25: ret = driver_add_groups(drv, drv->groups);
26: if (ret)
27: bus_remove_driver(drv);
28: return ret;
29: }
再看一下driver_attach函数
1: int driver_attach(struct device_driver *drv)
2: {
3: return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
4: }
1: int bus_for_each_dev(struct bus_type *bus, struct device *start,
2: void *data, int (*fn)(struct device *, void *))
3: {
4: struct klist_iter i;
5: struct device *dev;
6: int error = 0;
7:
8: if (!bus)
9: return -EINVAL;
10:
11: klist_iter_init_node(&bus->p->klist_devices, &i,
12: (start ? &start->p->knode_bus : NULL));
13: while ((dev = next_device(&i)) && !error)
14: error = fn(dev, data);
15: klist_iter_exit(&i);
16: return error;
17: }
1: static int __driver_attach(struct device *dev, void *data)
2: {
3: struct device_driver *drv = data;
4:
5:
6: if (!driver_match_device(drv, dev))
7: return 0;
8:
9: if (dev->parent) /* Needed for USB */
10: device_lock(dev->parent);
11: device_lock(dev);
12: if (!dev->driver)
13: driver_probe_device(drv, dev);
14: device_unlock(dev);
15: if (dev->parent)
16: device_unlock(dev->parent);
17:
18: return 0;
19: }
我们再继续查看一下driver_probe_device函数的调用:
1: int driver_probe_device(struct device_driver *drv, struct device *dev)
2: {
3: int ret = 0;
4:
5: if (!device_is_registered(dev))
6: return -ENODEV;
7:
8: pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
9: drv->bus->name, __func__, dev_name(dev), drv->name);
10:
11: pm_runtime_get_noresume(dev);
12: pm_runtime_barrier(dev);
13:
ret = really_probe(dev, drv);
14: pm_runtime_put_sync(dev);
15:
16: return ret;
17: }
linux SPI驱动——spidev之driver(六)的更多相关文章
- linux SPI驱动——spidev之deive(五)
1.定义board设备 1: struct spi_board_info { 2: /* the device name and module name are coupled, like platf ...
- linux驱动基础系列--linux spi驱动框架分析
前言 主要是想对Linux 下spi驱动框架有一个整体的把控,因此会忽略某些细节,同时里面涉及到的一些驱动基础,比如平台驱动.设备模型等也不进行详细说明原理.如果有任何错误地方,请指出,谢谢! spi ...
- Linux spi驱动分析(二)----SPI核心(bus、device_driver和device)
一.spi总线注册 这里所说的SPI核心,就是指/drivers/spi/目录下spi.c文件中提供给其他文件的函数,首先看下spi核心的初始化函数spi_init(void).程序如下: 点击(此处 ...
- linux设备驱动归纳总结(六):3.中断的上半部和下半部——tasklet【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-100005.html linux设备驱动归纳总结(六):3.中断的上半部和下半部——tasklet x ...
- linux设备驱动归纳总结(六):2.分享中断号【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-90837.html xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...
- linux设备驱动归纳总结(六):1.中断的实现【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-90740.html linux设备驱动归纳总结(六):1.中断的实现 xxxxxxxxxxxxxxxx ...
- linux驱动基础系列--linux spi驱动框架分析(续)
前言 这篇文章是对linux驱动基础系列--linux spi驱动框架分析的补充,主要是添加了最新的linux内核里设备树相关内容. spi设备树相关信息 如之前的文章里所述,控制器的device和s ...
- linux设备驱动归纳总结(六):1.中断的实现
linux设备驱动归纳总结(六):1.中断的实现 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...
- 【Linux开发】linux设备驱动归纳总结(六):3.中断的上半部和下半部——工作队列
linux设备驱动归纳总结(六):3.中断的上半部和下半部--工作队列 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...
随机推荐
- 【HDOJ5975】Aninteresting game(BIT原理)
题意:给定n个区间,第i个区间的范围是[i-lowbit(i)+1,i].一共有q组询问,询问有两种: 1 x y:询问sigma lowbit(i) (x<=i<=y) 2.x:询问有几 ...
- jquery bind event, use on. $(document).on("click","#a",function(){alert(1)}) [#document]
$(document).on("click","#a",function(){alert(1)}) [#document] as a replacement o ...
- js 数组知识复习
2.Array类型 2.1 创建数组 两种方式: 1.new Array(); //创建一个空数组 var arr1 = new Array(); //创建一个长度为10的空数组, var arr2 ...
- poj 2778 DNA Sequence 状态及状态转移 AC自动机 矩阵快速幂
题目链接 题意 给定\(m\)个字符串,问长度为\(n\)的字符串中有多少个不包含那\(m\)个字符串. (字符集为\(A,T,C,G\),\(m\leq 10\),长度\(\leq 10\),\(n ...
- linux多线程学习笔记五--线程安全【转】
转自:http://blog.csdn.net/kkxgx/article/details/7506085 版权声明:本文为博主原创文章,未经博主允许不得转载. 一,线程安全基础 一个函数被称为线程安 ...
- python日期时间相关
参考: http://www.coder4.com/archives/2239 http://www.cnblogs.com/lhj588/archive/2012/04/23/2466653.htm ...
- webview reload 错误 Error Domain=WebKitErrorDomain Code=102 "Frame load interrupted"
在某个特定的场合先需要对WKWebView进行一次reload,但是直接回走到失败的代理方法中并报如下的错误 Error Domain=WebKitErrorDomain Code=102 " ...
- shell高级-----创建函数
基本脚本函数 1.创建函数 有两种格式可以用来在bash shell脚本中创建函数.第一种采用关键字function.后跟分配给该代码的函数名. function name { commands } ...
- 在typescript中import第三方类库clipboard报错
一.问题 在实际开发项目中就遇到了这样的问题,需要在Vue+Typescript项目中添加复制文本的功能,就找了clipboard插件,先是新建了一个新的项目用来实验看看是否好用,都写好了以后发给别人 ...
- [转] 使用SVN进行源码管理
原文地址:gyzhao's, 使用SVN进行源码管理(下) 软件下载 1. Viusal SVN, Download(官网),安装该软件之前,请先安装TortoiseSVN,Download. 2. ...