`
totoxian
  • 浏览: 1071234 次
  • 性别: Icon_minigender_2
  • 来自: 西安
文章分类
社区版块
存档分类
最新评论

linux 2.6.17-IDE驱动程序源代码分析

 
阅读更多

块设备子系统是Linux中一个很重要的模块,在inode中有个字段是block_device类型的,它指向一个块设备,但是注意这里的“块设备”和 设备驱动里面的块设备的差别是非常大的,这里的块设备是一个比较高层的概念,而最底层的块设备在文件系统还触及不到。还是按照往常的方式来分析一下代码:首先看一下
struct bus_type ide_bus_type = {
.name = "ide",
.match = ide_bus_match,
.uevent = ide_uevent,
.probe = generic_ide_probe,
.remove = generic_ide_remove,
.shutdown = generic_ide_shutdown,
.dev_attrs = ide_dev_attrs,
.suspend = generic_ide_suspend,
.resume = generic_ide_resume,
};
如果新加入一个设备或者驱动的时候就要进行枚举,这是很明了的了,一旦匹配成功则要调用总线或者驱动的
Probe函数,这里是generic_ide_probe:
static int generic_ide_probe(struct device *dev)
{
ide_drive_t *drive = to_ide_device(dev);
ide_driver_t *drv = to_ide_driver(dev->driver);
return drv->probe ? drv->probe(drive) : -ENODEV;
}
下面再看一个结构就好办了:
static ide_driver_t idedisk_driver = {
.gen_driver = {
.owner = THIS_MODULE,
.name = "ide-disk",
.bus = &ide_bus_type,
},
.probe = ide_disk_probe, //探测
.remove = ide_disk_remove, //移除
.shutdown = ide_device_shutdown, //关闭
.version = IDEDISK_VERSION,
.media = ide_disk, //媒介类型
.supports_dsc_overlap = 0,
.do_request = ide_do_rw_disk, //请求处理函数
.end_request = ide_end_request, //请求处理结束
.error = __ide_error,
.abort = __ide_abort,
.proc = idedisk_proc,
};
下面就要调用ide_disk_probe函数了,看一下代码:
static int ide_disk_probe(ide_drive_t *drive)
{
struct ide_disk_obj *idkp;
struct gendisk *g;
if (!strstr("ide-disk", drive->driver_req))
goto failed;
if (!drive->present)
goto failed;
if (drive->media != ide_disk)
goto failed;
idkp = kzalloc(sizeof(*idkp), GFP_KERNEL);
...
g = alloc_disk_node(1 hwif));
...
ide_init_disk(g, drive);
ide_register_subdriver(drive, &idedisk_driver);
kref_init(&idkp->kref);
idkp->drive = drive;
idkp->driver = &idedisk_driver;
idkp->disk = g;
g->private_data = &idkp->driver;
drive->driver_data = idkp;
idedisk_setup(drive);
if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
drive->attach = 0;
} else
drive->attach = 1;
g->minors = 1 strcpy(g->devfs_name, drive->devfs_name);
g->driverfs_dev = &drive->gendev;
...
g->fops = &idedisk_ops;
add_disk(g); //加入通用块设备体系
return 0;
...
}
回想一下统一的设备模型,主要是device_driver和device在主持大局,那么块设备中当然也少不了这两个老大其实在文件系统中是看不到它们的身影的,只有再往下才行,实际上它们就是:ide_driver_t和ide_drive_t。那么现在分析一下这个里面调用的几个函数:
struct ide_disk_obj {
ide_drive_t *drive;
ide_driver_t *driver;
struct gendisk *disk;
struct kref kref;
};
先说一下这个粘合结构,就是它将底层的ide_drive_t设备和文件系统的gendisk联系了起来,那么底层drive由
谁来驱动呢?当然是driver域了,这样它把设备和驱动也联系了起来
void ide_init_disk(struct gendisk *disk, ide_drive_t *drive)
{
ide_hwif_t *hwif = drive->hwif;
unsigned int unit = (drive->select.all >> 4) & 1;
disk->major = hwif->major;
disk->first_minor = unit sprintf(disk->disk_name, "hd%c", 'a' + hwif->index * MAX_DRIVES + unit);
disk->queue = drive->queue;
}
调用完之后这个函数,就要:
idkp->drive = drive;
idkp->driver = &idedisk_driver;
idkp->disk = g;
重要的是这个idedisk_driver,它是:
static ide_driver_t idedisk_driver = {
见上面的定义......
};
之后又有一个重量级的函数,idedisk_setup:
static void idedisk_setup (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
unsigned long long capacity;
idedisk_add_settings(drive);
if (drive->id_read == 0)
return;
if (drive->removable) {
if (id->model[0] != 'W' || id->model[1] != 'D') {
drive->doorlocking = 1;
}
}
(void)set_lba_addressing(drive, 1);
if (drive->addressing == 1) {
ide_hwif_t *hwif = HWIF(drive);
int max_s = 2048;
if (max_s > hwif->rqsize)
max_s = hwif->rqsize;
blk_queue_max_sectors(drive->queue, max_s);
}
...
init_idedisk_capacity (drive);
if (drive->addressing == 0 && drive->capacity64 > 1ULL drive->capacity64 = 1ULL }
if (drive->hwif->no_lba48_dma && drive->addressing)
...
}
这个函数主要就是建立完整的gendisk结构,以后就可以让block_device用了,而block_device让inode,address_space用,这样底层就和上层联系了起来。这里又涉及到了硬件和软件的问题,表现为设备结构和驱动程序的问题,我一直都有个疑问,就是blk_init_queue到底在哪里调用,register_blkdev和XX_probe的调用关系是什么?其实理解了硬件设备结构和设备驱动的关系后就好理解了,设备结构比如:scsi_device或ide_drive等都是在硬件总线枚举的时候被初始化的,而其驱动则是在模块加载时初始化的,相应的,请求队列是属于硬件设备的而不是属于驱动的,所以请求队列是在设备建立的时候初始化的,这个时候不管有没有驱动都初始化请求队列,下面分析调用过程:在总线枚举的时候,各个 总线上都游离着一些设备结构,比如pci总线上可能就会有ide设备结构,调用如下:
ide_generic_init调用ideprobe_init
ideprobe_init-->|for (index = 0; index if (probe[index])
probe_hwif(&ide_hwifs[index])
|for (index = 0; index if (probe[index])
hwif_init(&ide_hwifs[index]);-->|register_blkdev(hwif->major, hwif->name)
|init_irq(hwif)-->|request_irq(hwif->irq,&ide_intr,sa,hwif->name,hwgroup)
|for (index = 0; index ide_drive_t *drive = &hwif->drives[index];
if (!drive->present)
continue;
if (ide_init_queue(drive)) //这里初始化请求队列
...
......
|for (index = 0; index if (probe[index]) {
ide_hwif_t *hwif = &ide_hwifs[index];
int unit;
if (!hwif->present)
continue;
if (hwif->chipset == ide_unknown || hwif->chipset == ide_forced)
hwif->chipset = ide_generic;
for (unit = 0; unit if (hwif->drives[unit].present)
device_register(&hwif->drives[unit].gendev);
}
}
在设备结构初始化了以后,那么什么时候加载驱动的呢?遍查代码发现是一个idedisk_init
static int __init idedisk_init(void)
{
return driver_register(&idedisk_driver.gen_driver);
}
进一步的driver_register就很熟悉了,马上就到了ide_disk_probe函数,与上面分析的接在了一起,通过简单的推理,可以证明idedisk_init肯定发生在请求队列初始化之后,因为在ide_disk_probe中直接就用到了ide_drive的队列,并将之赋给新创建的gendisk的请求队列。下面看看整个过程:
static int __init ide_init(void)
{
devfs_mk_dir("ide");
system_bus_speed = ide_system_bus_speed();
bus_register(&ide_bus_type);
init_ide_data();
#ifdef CONFIG_BLK_DEV_ALI14XX
if (probe_ali14xx)
(void)ali14xx_init();
#endif
...
initializing = 1;
probe_for_hwifs();
initializing = 0;
return 0;
}
此处只关心ali14xx_init()
int __init ali14xx_init(void)
{
if (findPort()) {
if (ali14xx_probe())
...
}
static int __init ali14xx_probe(void)
{
ide_hwif_t *hwif, *mate;
if (!initRegisters())
...
hwif = &ide_hwifs[0];
mate = &ide_hwifs[1];
hwif->chipset = ide_ali14xx;
hwif->tuneproc = &ali14xx_tune_drive;
hwif->mate = mate;
...
probe_hwif_init(hwif);
...
}
int probe_hwif_init(ide_hwif_t *hwif)
{
return probe_hwif_init_with_fixup(hwif, NULL);
}
int probe_hwif_init_with_fixup(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif))
{
probe_hwif(hwif);
if (fixup)
fixup(hwif);
if (!hwif_init(hwif))
...
if (hwif->present) {
u16 unit = 0;
for (unit = 0; unit ide_drive_t *drive = &hwif->drives[unit];
if (drive->present) {
device_register(&drive->gendev);
}
}
}
...
}
这 个函数里最重要的回调有3个:probe_hwif和hwif_init还有device_register,其中最后一个最终调用 device_add,这样就有了一次probe的机会,probe_hwif首先看看设备的状态,然后hwif_init上面已经分析过了,只不过这里分析的是通过另一条路径到达hwif_init函数的,也就是说有两条内核调用路径都可以经历这一切。又是一个设备驱动。这几天分析了这么多的设备驱动,感觉只有把握住系统的框架才能更好的理解代码,进一步才能更好的修改代码,虽然这些天分析的代码数量很大,但是都是在一个框架内的,从usb到pci,再 到网卡驱动输入子系统,ide驱动,scsi驱动,都是这样的.在ide_init里还有一个重要的路径:
ide_init--> probe_for_hwifs
static void __init probe_for_hwifs (void)
{
#ifdef CONFIG_BLK_DEV_IDEPCI
ide_scan_pcibus(ide_scan_direction);
#endif
......
#ifdef CONFIG_BLK_DEV_IDE_PMAC
{
extern void pmac_ide_probe(void);
pmac_ide_probe();
}
#endif
......
}
static int __init ide_scan_pcidev(struct pci_dev *dev)
{
struct list_head *l;
struct pci_driver *d;
list_for_each(l, &ide_pci_drivers)
{
d = list_entry(l, struct pci_driver, node);
if(d->id_table)
{
const struct pci_device_id *id = pci_match_id(d->id_table, dev);
if(id != NULL)
{
if(d->probe(dev, id) >= 0)
{
dev->driver = d;
return 1;
}
}
}
}
return 0;
}
简单看一下pmac_ide_probe():
pmac_ide_probe(void)
{
...
macio_register_driver(&pmac_ide_macio_driver);
pci_register_driver(&pmac_ide_pci_driver);
}
看一下熟悉的结构:
static struct pci_driver pmac_ide_pci_driver = {
.name = "ide-pmac",
.id_table = pmac_ide_pci_match,
.probe = pmac_ide_pci_attach,
.suspend = pmac_ide_pci_suspend,
.resume = pmac_ide_pci_resume,
};
然后:
static int __devinit pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
{
ide_hwif_t *hwif;
struct device_node *np;
pmac_ide_hwif_t *pmif;
void __iomem *base;
unsigned long rbase, rlen;
int i, rc;
np = pci_device_to_OF_node(pdev);
if (np == NULL)
...
i = 0;
while (i ++i;
if (i >= MAX_HWIFS)
...
pmif = &pmac_ide;
hwif = &ide_hwifs;
if (pci_enable_device(pdev))
...
pci_set_master(pdev);
if (pci_request_regions(pdev, "Kauai ATA"))
...
hwif->pci_dev = pdev;
hwif->gendev.parent = &pdev->dev;
pmif->mdev = NULL;
pmif->node = np;
rbase = pci_resource_start(pdev, 0);
rlen = pci_resource_len(pdev, 0);
base = ioremap(rbase, rlen);
pmif->regbase = (unsigned long) base + 0x2000;
...
pmif->kauai_fcr = base;
pmif->irq = pdev->irq;
pci_set_drvdata(pdev, hwif);
rc = pmac_ide_setup_device(pmif, hwif);
...
}
这里和pci联系了起来

分享到:
评论

相关推荐

    kernel-default-2.6.17-jad1.i586.rpm

    kernel-default-2.6.17-jad1.i586.rpm 很多人都在找的lvs文件

    linux 2.6.17 提权

    在Linux系统中,"提权"是指通过某种方式获取比当前用户权限更...由于提供的压缩包文件名为"2.6.17.c",可能包含了针对这个内核版本的源码分析或漏洞利用示例,深入研究这些代码可以帮助我们更好地了解具体的提权技术。

    NET.tar.gz_arm-linux-gcc 4.0.2_linux 驱动 2.6_s3c2410 linux

    1. akae_cs8900_core.c:这是驱动程序的核心源代码文件,其中包含了实现 CS8900 控制器功能的函数和数据结构。 2. cs8900.h:这是一个头文件,定义了与 CS8900 控制器交互所需的常量、结构体和函数原型。它是 cs8900...

    Python库 | arcade-2.6.9.dev2-py3-none-any.whl

    《Python库 Arcade 2.6.9.dev2:游戏开发的新篇章》 在Python的世界里,Arcade库是一个为开发者提供强大游戏开发功能的利器。这个名为“arcade-2.6.9.dev2-py3-none-any.whl”的压缩包文件,包含了最新的2.6.9版本...

    radhat el5 安装oracle rac需要用到的包kernel-xen-2.6.18-53.el5.i686.rpm

    radhat el5 安装oracle rac需要用到的包kernel-xen-2.6.18-53.el5.i686.rpm

    非常实用的Linux实用手册

    ### 非常实用的Linux实用手册:解决无法启动的问题 #### 一、引言 在使用Linux的过程中,用户可能会遇到系统无法启动的情况。对于习惯于Windows系统的用户来说,第一反应往往是格式化并重新安装系统。然而,在...

    kernel-api-html-2.6.17.part02

    kernel-api-html-2.6.17.part02 全面系统讲解linux内核2.6.17 api函数,数据结构,应用函数

    kernel-api-html-2.6.17.part01

    两部分, linux内核 2.6.17 所有api函数,数据结构,应用函数。

    linux-2.6.14内核移植.doc

    使用`tar jxvf linux-2.6.14.1.tar.bz2`命令来解压缩内核源代码。 2. **编辑源文件**: - **arch/arm/mach-s3c2410/devs.c**: 添加头文件`<linux/mtd/partitions.h>`、`<asm/arch/nand.h>`和`<linux/mtd/nand.h...

    Linux Device Driver for IBM eHCA , eHEA-开源

    4. **开源软件**:这些驱动程序是开源的,意味着其源代码是公开的,允许社区开发者查看、修改和分发代码。这促进了技术的发展,因为全世界的程序员都可以贡献自己的智慧,改进或扩展驱动功能,同时也提供了更多的...

    Linux芯片级移植与底层驱动

    Linux芯片级移植与底层驱动是在ARM SoC(System on Chip)上让Linux操作系统成功运行的基础工作。这项工作涉及对Linux内核进行一系列定制,以适应特定硬件的运行环境。在Linux操作系统中,底层驱动主要负责与硬件...

    基于arm的linux启动代码分析.pdf

    ### 基于ARM的Linux启动代码分析 #### 概述 本文档旨在对基于ARM架构的Linux操作系统启动过程中的代码进行深入分析。ARM架构因其低功耗特性而在嵌入式系统领域广受欢迎,而Linux作为一款开源的操作系统,其在嵌入式...

    centos5安装smokeping

    [root@linux-a Smokeping-2.6.17]# ./configure --prefix=/usr/local/smokeping --sysconfdir=/etc/smokeping [root@linux-a Smokeping-2.6.17]# make && make install ``` 4. 创建配置文件和目录: ```bash ...

    Linux_期末考试试题8套(含答案).pdf

    ### Linux期末考试知识点详解 #### 一、选择题解析 **1. Linux 内核的稳定版本** - **选项分析**: - A. 2.5.24:此版本号中的“5”表示这是一个开发版本,因此不是稳定版。 - B. 2.6.17:此版本号中的“6”表示...

    W90x900 BSP中文资料

    - `linux-2.6.17.tar.gz`:Linux内核源码,版本为2.6.17。 - `arm_linux_4.2.tar.gz`:GCC编译器工具链,版本为4.2.0,用于将C/C++代码编译为ARM架构的机器码。 - `rootfs.tar.gz`:预构建的文件系统,包含了操作...

    基于ARMLinux的嵌入式数据库SQLite的移植及图形接口的开发

    1. **下载Linux内核源码**:选择适合ARM架构的Linux内核版本(如2.6.17)。 2. **打补丁**:如果使用的是旧版本内核,可能需要打补丁以修复bug或添加新特性。 3. **修改Makefile**:指定CPU架构(如`ARCH = arm`)和...

    基于linux2.6及S3C2410上的BOA的移植.pdf

    开发环境为Linux 2.6.17内核,使用u-boot 1.1.4作为引导加载器,BusyBox 1.1.3作为根文件系统,文件系统采用YAFFS,硬件平台为英培特公司的S3C2410开发板。通过这样的移植,用户可以使用Web浏览器远程管理并监控...

    基于ARM-Linux平台的红外光源视频采集的实现.pdf

    这通常需要特殊的红外传感器和合适的驱动程序。文中未详细阐述具体的红外光源处理方法,但通常涉及对红外光线的捕捉、处理和转换为数字信号的过程。此外,高帧率的实现通常需要优化DMA传输,减少数据处理延迟,以...

Global site tag (gtag.js) - Google Analytics