社区
下载资源悬赏专区
帖子详情
DM9000驱动的注册过程下载
weixin_39820535
2019-05-17 10:00:16
linux中DM9000驱动注册过程,基予2.6.28内核,omap3530
相关下载链接:
//download.csdn.net/download/bindaz/2244725?utm_source=bbsseo
...全文
5
回复
打赏
收藏
DM9000驱动的注册过程下载
linux中DM9000驱动注册过程,基予2.6.28内核,omap3530 相关下载链接://download.csdn.net/download/bindaz/2244725?utm_source=bbsseo
复制链接
扫一扫
分享
转发到动态
举报
写回复
配置赞助广告
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复
打赏红包
DM9000
驱动
的
注册
过程
linux中
DM9000
驱动
注册
过程
,基予2.6.28内核,omap3530
unix分析关于UNIX的一些浅析
内核版本:2.6.31.6 首先在S3C2440平台的初始化函数中,主要是将开发平台的设备
注册
进了系统,也就是将device
注册
到了platform虚拟的总线上,并进行了一些初始化的工作,这里我们只关注I2C的部分。 static void __init smdk2440_machine_init(void) { s3c24xx_fb_set_platdata(&smdk2440_fb_info); s3c_i2c0_set_platdata(NULL); platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices)); smdk_machine_init(); } s3c_i2c0_set_platdata()函数将S3C2440上的I2C控制器进行了一些初始化,但是并没有写入硬件寄存器,仅仅是保存在了s3c2410_platform_i2c结构体中。 void __init s3c_i2c0_set_platdata(struct s3c2410_platform_i2c *pd) { struct s3c2410_platform_i2c *npd; if (!pd) pd = &default_i2c_data0; npd = kmemdup(pd, sizeof(struct s3c2410_platform_i2c), GFP_KERNEL); if (!npd) printk(KERN_ERR "%s: no memory for platform data\n", __func__); else if (!npd->cfg_gpio) npd->cfg_gpio = s3c_i2c0_cfg_gpio; /* s3c_i2c0_cfg_gpio为 配置I2C控制器GPIO函数指针 */ s3c_device_i2c0.dev.platform_data = npd; /*最后将struct device 中的platform_data指针直指向了初始化后的 s3c2410_platform_i2c结构体 */ } 函数s3c_i2c0_cfg_gpio()很简单,实际上就是配置GPIO为I2C的工作模式 void s3c_i2c0_cfg_gpio(struct platform_device *dev) { s3c2410_gpio_cfgpin(S3C2410_GPE(15), S3C2410_GPE15_IICSDA); s3c2410_gpio_cfgpin(S3C2410_GPE(14), S3C2410_GPE14_IICSCL); } s3c_i2c0_set_platdata(struct s3c2410_platform_i2c *pd)函数实际上就是把初始化数据段中的default_i2c_data0结构体复制过来,然后对GPIO进行配置的函数指针进行了初始化。default_i2c_data0结构体如下: static struct s3c2410_platform_i2c default_i2c_data0 __initdata = { .flags = 0, .slave_addr = 0x10, .frequency = 100*1000, .sda_delay = 100, }; s3c2410_platform_i2c结构体原型如下,根据英文注释即可大致理解其意思 /** * struct s3c2410_platform_i2c - Platform data for s3c I2C. * @bus_num: The bus number to use (if possible). * @flags: Any flags for the I2C bus (E.g. S3C_IICFLK_FILTER). * @slave_addr: The I2C address for the slave device (if enabled). * @frequency: The desired frequency in Hz of the bus. This is * guaranteed to not be exceeded. If the caller does * not care, use zero and the driver will select a * useful default. * @sda_delay: The delay (in ns) applied to SDA edges. * @cfg_gpio: A callback to configure the pins for I2C operation. */ struct s3c2410_platform_i2c { int bus_num; unsigned int flags; unsigned int slave_addr; unsigned long frequency; unsigned int sda_delay; void (*cfg_gpio)(struct platform_device *dev); }; 在函数smdk2440_machine_init(void)中,调用了 platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices)); 即将smdk2440_devices结构体数组中platform_device添加到了系统中,也就是添加到了platform总线上。smdk2440_devices的具体内容如下: static struct platform_device *smdk2440_devices[] __initdata = { &s3c_device_usb, &s3c_device_lcd, &s3c_device_wdt, &s3c_device_i2c0, &s3c_device_iis, &s3c_device_
dm9000
, &s3c_device_rtc, }; 其中s3c_device_i2c0保存了S3C2440中的I2C控制器的一些内部资源等信息,具体内容如下: struct platform_device s3c_device_i2c0 = { .name = "s3c2410-i2c", /*设备名,platform总线的match函数中会用设备名和
驱动
名的比较来绑定设备和
驱动
程序*/ #ifdef CONFIG_S3C_DEV_I2C1 .id = 0, #else .id = -1, #endif .num_resources = ARRAY_SIZE(s3c_i2c_resource), .resource = s3c_i2c_resource, }; 其中s3c_i2c_resource结构体保存了S3C2440中I2C控制器寄存器的物理地址和中断号等具体的硬件信息。 static struct resource s3c_i2c_resource[] = { [0] = { .start = S3C_PA_IIC, .end = S3C_PA_IIC + SZ_4K - 1, .flags = IORESOURCE_MEM, }, [1] = { .start = IRQ_IIC, .end = IRQ_IIC, .flags = IORESOURCE_IRQ, }, }; 在后面
注册
具体设备
驱动
时也会添加到paltform总线上,platform总线会将具体的设备和
驱动
进行绑定,这样
驱动
就可以操作具体的设备了。platform实际上是一个虚拟的总线,本质上也是一个设备。 好了,上面是一些板级的硬件设备资源向系统的
注册
,没有设计到具体的硬件操作,在加载
驱动
程序时,
驱动
程序会根据已经
注册
到系统的具体设备的硬件资源进行初始化,也就是进行一些硬件操作,控制硬件设备的正常工作,下面来分析
驱动
程序的加载
过程
。 S3C2440平台上的I2C的
驱动
程序在linux/drivers/i2c/busses/i2c-s3c2410.c文件中, 在
驱动
的加载程序中,将platform_driver类型的s3c24xx_i2c_driver
注册
到了系统中。 static int __init i2c_adap_s3c_init(void) { return platform_driver_register(&s3c24xx_i2c_driver); } 分析platform_driver_register(&s3c24xx_i2c_driver);的源代码可知,实际上是将s3c24xx_i2c_driver
注册
到了platform总线上。 int platform_driver_register(struct platform_driver *drv) { drv->driver.bus = &platform_bus_type; /*将device_driver中的probe,remove,shutdown函数指针指向platform_driver中的函数,后面进行
驱动
和设备绑定后会调用probe函数 */ if (drv->probe) drv->driver.probe = platform_drv_probe; if (drv->remove) drv->driver.remove = platform_drv_remove; if (drv->shutdown) drv->driver.shutdown = platform_drv_shutdown; return driver_register(&drv->driver); } 下图即为Linux 2.6中引入的设备
驱动
模型的结构图(只是个总体框架,并不是指这的platform总线,设备和
驱动
)。 总线上包括设备和
驱动
的集合,总线上所有设备组成双向循环链表,包含在platform_device的设备集合中,总线上所有
驱动
组成双向循环链表,包含在platform_dirver的
驱动
集合中。 platform_driver_register(struct platform_driver *drv)函数实际上是对driver_register(struct device_driver *drv)函数的一个简单封装。driver_register()函数的调用关系如下 driver_register() —>bus_add_driver(drv); —> driver_attach(drv); —> bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); bus_for_each_dev(drv->bus, NULL, drv, __driver_attach)函数会遍历总线上所有的设备,并调用__driver_attach函数,判断
驱动
是否和设备匹配,若匹配则将struct device中的 struct device_driver *driver指向此
驱动
,也就是进行了
驱动
和设备的绑定,若不匹配,则继续遍历下一个设备。事实上,在向总线
注册
设备时,同样会进行类似的操作,遍历总线上所有
驱动
程序,找到则进行设备与
驱动
程序的绑定。 static int __driver_attach(struct device *dev, void *data) { struct device_driver *drv = data; /* * Lock device and try to bind to it. We drop the error * here and always return 0, because we need to keep trying * to bind to devices and some drivers will return an error * simply if it didn't support the device. * * driver_probe_device() will spit a warning if there * is an error. */ /*调用platform总线的match()函数,即platform_match函数,判断设备和
驱动
是否匹配,若匹配则返真,找到对应的设备,继续执行后面的程序,若没有找到,则返回假,函数执行结束 。这里我们的I2C
驱动
找到了可以
驱动
的设备,所以会继续执行*/ if (!driver_match_device(drv, dev)) return 0; if (dev->parent) /* Needed for USB */ down(&dev->parent->sem); down(&dev->sem); /*设备是否已经找到
驱动
?显然,这里没有找到
驱动
,因为设备在向系统中platform总线
注册
时还没有
驱动
注册
到platform总线上,所以dev->drive = NULL */ if (!dev->driver) driver_probe_device(drv, dev); up(&dev->sem); if (dev->parent) up(&dev->parent->sem); return 0; } driver_probe_device(drv, dev)函数进行
驱动
与设备的绑定。 /** * driver_probe_device - attempt to bind device & driver together * @drv: driver to bind a device to * @dev: device to try to bind to the driver * * This function returns -ENODEV if the device is not registered, * 1 if the device is bound sucessfully and 0 otherwise. * * This function must be called with @dev->sem held. When called for a * USB interface, @dev->parent->sem must be held as well. */ int driver_probe_device(struct device_driver *drv, struct device *dev) { int ret = 0; if (!device_is_registered(dev)) //判断设备是否已经
注册
return -ENODEV; pr_debug("bus: '%s': %s: matched device %s with driver %s\n", drv->bus->name, __func__, dev_name(dev), drv->name); ret = really_probe(dev, drv); return ret; } really_probe函数中 进行device和driver的绑定,并调用用户在device_driver 中
注册
的probe()例程。 static int really_probe(struct device *dev, struct device_driver *drv) { int ret = 0; atomic_inc(&probe_count); pr_debug("bus: '%s': %s: probing driver %s with device %s\n", drv->bus->name, __func__, drv->name, dev_name(dev)); WARN_ON(!list_empty(&dev->devres_head)); /*将device中的device_driver指针指向了这个driver,即完成device和driver的绑定*/ dev->driver = drv; f (driver_sysfs_add(dev)) { printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n", __func__, dev_name(dev)); goto probe_failed; } /*若总线设置了probe函数,则调用总线的probe函数,然而platform总线并没有设置 */ if (dev->bus->probe) { ret = dev->bus->probe(dev); if (ret) goto probe_failed; } /* 否则,调用
驱动
注册
在device_driver里的probe,这个函数中一般进行获得硬件资源,初始化硬件等操作,这里实际调用了s3c24xx_i2c_probe函数*/ else if (drv->probe) { ret = drv->probe(dev); if (ret) goto probe_failed; } /*将设备添加到driver所支持的设备列表中(因为一个
驱动
可以支持多个设备),并通知bus上的设备,表明BUS_NOTIFY_BOUND_DRIVER */ driver_bound(dev); ret = 1; pr_debug("bus: '%s': %s: bound device %s to driver %s\n", drv->bus->name, __func__, dev_name(dev), drv->name); goto done; probe_failed: devres_release_all(dev); driver_sysfs_remove(dev); dev->driver = NULL; if (ret != -ENODEV && ret != -ENXIO) { /* driver matched but the probe failed */ printk(KERN_WARNING "%s: probe of %s failed with error %d\n", drv->name, dev_name(dev), ret); } /* * Ignore errors returned by ->probe so that the next driver can try * its luck. */ ret = 0; done: atomic_dec(&probe_count); wake_up(&probe_waitqueue); return ret; } 到这里,I2C设备软件层次上的
驱动
模型已经建立好了,接着会执行s3c24xx_i2c_probe函数,获取系统开始
注册
的一些硬件资源信息,进行硬件上的一些操作,以及真正的涉及到数据传输
驱动
程序的
注册
等操作。
【linux
驱动
分析】之
dm9000
驱动
分析
【linux
驱动
分析】之
dm9000
驱动
分析(一):
dm9000
原理及硬件分析 【linux
驱动
分析】之
dm9000
驱动
分析(一):
dm9000
原理及硬件分析 【linux
驱动
分析】之
dm9000
驱动
分析(二):定义在板文件中的资源和设备以及几个宏 【linux
驱动
分析】之
dm9000
驱动
分析(三):sk_buff结构分析 【linux
驱动
分析】之dm
Linux
DM9000
网卡
驱动
程序完全分析
说明1:本文分析基于内核源码版本为linux-2.6.31 说明2:本文在理解了linux中总线、设备和
驱动
模型的基础上加以分析代码 天猫爆款 联想 ibm ThinkPad E320 129862C 代替55C 笔记本 包邮 虽然Linux
驱动
程序应该是和具体的硬件平台分离的,但是为了更好的理解
DM9000
的
驱动
程序,这里还是结合一下Mini2440开发板,这样也可以更好的体会如何
嵌入式学习-
驱动
开发-lesson7.2-
DM9000
驱动
流程分析
lesson3
dm9000
网卡
驱动
深度分析 下面的
dm9000
的分析只是简单的分析,并不全面,可能会有一些遗漏和错误的地方,更加详细的
dm9000
分析,请参考下面这两位大牛的博客: zhongli_i大牛:
dm9000
网卡
驱动
分析1 http://blog.chinaunix.net/uid-26442066-id-3184195.html
dm9000
网卡
驱动
分析2 http
下载资源悬赏专区
12,781
社区成员
12,309,305
社区内容
发帖
与我相关
我的任务
下载资源悬赏专区
CSDN 下载资源悬赏专区
复制链接
扫一扫
分享
社区描述
CSDN 下载资源悬赏专区
其他
技术论坛(原bbs)
社区管理员
加入社区
获取链接或二维码
近7日
近30日
至今
加载中
查看更多榜单
社区公告
暂无公告
试试用AI创作助手写篇文章吧
+ 用AI写文章