IDE总线、驱动注册(一)
搜索刚才提到的内核源代码唯有ide.c中有这么一个module_init(ide_init),那么八成就是我们要找的入口了,那就先看看ide_init,源码如下:
365 /*
366 * This is gets invoked once during initialization, to set *everything* up
367 */
368 static int __init ide_init(void)
369 {
370 int ret;
371
372 printk(KERN_INFO "Uniform Multi-Platform E-IDE driver/n");
373
374 ret = bus_register(&ide_bus_type);
375 if (ret < 0) {
376 printk(KERN_WARNING "IDE: bus_register error: %d/n", ret);
377 return ret;
378 }
379
380 ide_port_class = class_create(THIS_MODULE, "ide_port");
381 if (IS_ERR(ide_port_class)) {
382 ret = PTR_ERR(ide_port_class);
383 goto out_port_class;
384 }
385
386 ide_acpi_init();
387
388 proc_ide_create();
389
390 return 0;
391
392 out_port_class:
393 bus_unregister(&ide_bus_type);
394
395 return ret;
396 }
374行,又见了总线注册bus_register,早在plateform总线中我们就对他进行了解剖,是设备模型中总线的发源地。在这里我们只是简单看一下这个bus_type 类型的ide_bus_type。
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,
};
既然有总线了,那肯定是为设备和驱动服务的,当有设备或者驱动注册的时候就会引发总线的一系列动作,包括match、probe的调用。这部分具体的代码我们等到后面在分析…
380行注册一个类,同时在/sys/class/下创建相应类目录
386行ACPI表示高级配置和电源管理接口,这里与我们无关。
388行proc文件系统相关内容,忽略…
392-397出错处理。
Ide_init()这个函数比较简单,就是完成了一次总线注册。总线我们找到了,那么设备和驱动是什么时候加载进来的呢?下面就到ide_generic.c这个文件下面找找答案了….还是那个module_init()。看看里面的代码:
87 static int __init ide_generic_init(void)
88 {
89 struct ide_hw hw, *hws[] = { &hw };
90 unsigned long io_addr;
91 int i, rc = 0, primary = 0, secondary = 0;
92
93 ide_generic_check_pci_legacy_iobases(&primary, &secondary);
94
95 if (!probe_mask) {
96 printk(KERN_INFODRV_NAME": please use/"probe_mask=0x3f/" "
97 "module parameter for probing all legacy ISA IDE ports/n");
98
99 if (primary == 0)
100 probe_mask |= 0x1;
101
102 if (secondary == 0)
103 probe_mask |= 0x2;
104 } else
105 printk(KERN_INFO DRV_NAME ": enforcing probing of I/O ports "
106 upon user request/n);
107
108 for (i = 0; i < ARRAY_SIZE(legacy_bases); i++) {
109 io_addr = legacy_bases[i];
110
111 if ((probe_mask & (1 << i)) && io_addr) {
112 if (!request_region(io_addr, 8, DRV_NAME)) {
113 printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX "
114 not free./n,
115 DRV_NAME, io_addr, io_addr + 7);
116 rc = -EBUSY;
117 continue;
118 }
119
120 if (!request_region(io_addr + 0x206, 1, DRV_NAME)) {
121 printk(KERN_ERR "%s: I/O resource 0x%lX "
122 not free./n,
123 DRV_NAME, io_addr + 0x206);
124 release_region(io_addr, 8);
125 rc = -EBUSY;
126 continue;
127 }
128
129 memset(&hw, 0, sizeof(hw));
130 ide_std_init_ports(&hw, io_addr, io_addr + 0x206);
131 #ifdef CONFIG_IA64
132 hw.irq = isa_irq_to_vector(legacy_irqs[i]);
133 #else
134 hw.irq = legacy_irqs[i];
135 #endif
136 rc = ide_host_add(&ide_generic_port_info, hws, 1, NULL);
137 if (rc) {
138 release_region(io_addr + 0x206, 1);
139 release_region(io_addr, 8);
140 }
141 }
142 }
143
144 return rc;
145 }
146
在这段代码的分析中关键要弄清一系列的数据结构,我们边走边说。进来就遇到ide_hw,他描述的是接口的一些寄存器地址,中断号等信息。
175 struct ide_hw {
176 union {
177 struct ide_io_ports io_ports;
178 unsigned long io_ports_array[IDE_NR_PORTS];
179 };
180
181 int irq; /* our irq number */
182 struct device *dev, *parent;
183 unsigned long config;
184 };
185
176-179行io_ports与io_ports_array以联合体的形式存在,ide_io_ports实际上与IDE接口所定义的内部寄存器偏移相对应的,结合下面这张表再来看ide_io_ports就显得比较清晰了。
IDE寄存器地址分配表
58 struct ide_io_ports {
59 unsigned long data_addr;
60
61 union {
62 unsigned long error_addr; /* read: error */
63 unsigned long feature_addr; /* write: feature */
64 };
65
66 unsigned long nsect_addr;
67 unsigned long lbal_addr;
68 unsigned long lbam_addr;
69 unsigned long lbah_addr;
70
71 unsigned long device_addr;
72
73 union {
74 unsigned long status_addr; /* 聽read: status 聽*/
75 unsigned long command_addr; /* write: command */
76 };
77
78 unsigned long ctl_addr;
79
80 unsigned long irq_addr;
81 };
82
59-76行与上面的表中的寄存器是一一对应的;
78行记录了控制基础器的地址,是单独列出的;
80行记录中断地址也成为单独的一项纪录在案;
回到ide_hw结构上来,181-183行就分别记录了接口的中断号,所对应的device以及配置值。
看完ide_hw的内容,我们进入ide_generic_init的分析:
93行是定义了PCI总线的,由pci总线驱动的。我们这里和PCI扯不上关系,就直接略过了。
95行probe_mask 这个是个模块参数对应的变量,关于内核参数和模块参数的相关内容请参考《内核对子系统或者模块的初始化.pdf 》,这里我们只需知道module_param(probe_mask, int, 0);说白了就是初始化probe_mask=0。既然我们加载的时候没有指定新的模块参数就直接使用probe_mask=0了,那么96-107行就直接是probe_mask=0x03;
108行是个for循环,执行次数和legacy_bases数组元素的个数有关,legacy_bases是在同一个文件中定义的数组里面指定了接口的基地址,基于ARM体系我们来看看他的定义:
static const u16 legacy_bases[] = { 0x1f0 };
static const int legacy_irqs[] = { IRQ_HARDDISK };
很显然这里的for也就只能执行一次了。
112-127行就是根据legacy_bases指定的地址来申请地址空间,112行申请的是命令寄存器地址空间共8个,120行申请的是控制寄存器地址空间,只有1个;
130行调用了ide_std_init_ports传递的参数是hw,命令和控制寄存器地址。一看名字和参数就不难想到,他其实就是把这些个刚申请了空间的地址填写到ide_hw所对应的项目中。为了保险还是看下源码(红色部分表明了函数的调用关系,方便阅读):
[ide_generic_init]->[ide_std_init_ports]
186 static inline void ide_std_init_ports(struct ide_hw *hw,
187 unsigned long io_addr,
188 unsigned long ctl_addr)
189 {
190 unsigned int i;
191
192 for (i = 0; i <= 7; i++)
193 hw->io_ports_array[i] = io_addr++;
194
195 hw->io_ports.ctl_addr = ctl_addr;
196 }
197
193行就是完成了命令寄存器的填充,看到他同时我们也就不难理解刚刚提到的那个io_ports_array和io_ports为什么定义成联合体的原因了,就是为了赋值方便。
回到ide_generic_init…..
131-135行我们只关心134行,就是将中断号填入hw中的irq段。
136行调用ide_host_add,这个函数中又将引入一系列的数据结构,后面我们将会各个击破…进入函数之前还是先看看传递的实参都有哪些。
首先,ide_generic_port_info,这是个ide_port_info结构:
1285 struct ide_port_info {
1286 char *name;
1287
1288 int (*init_chipset)(struct pci_dev *);
1289
1290 void (*get_lock)(irq_handler_t, void *);
1291 void (*release_lock)(void);
1292
1293 void (*init_iops)(ide_hwif_t *);
1294 void (*init_hwif)(ide_hwif_t *);
1295 int (*init_dma)(ide_hwif_t *,
1296 const struct ide_port_info *);
1297
1298 const struct ide_tp_ops *tp_ops;
1299 const struct ide_port_ops *port_ops;
1300 const struct ide_dma_ops *dma_ops;
1301
1302 struct ide_pci_enablebit enablebits[2];
1303
1304 hwif_chipset_t chipset;
1305
1306 u16 max_sectors; /* if < than the default one */
1307
1308 u32 host_flags;
1309
1310 int irq_flags;
1311
1312 u8 pio_mask;
1313 u8 swdma_mask;
1314 u8 mwdma_mask;
1315 u8 udma_mask;
1316 };
1317
这个结构比较简单,记录着端口的详细信息。包含了接口芯片类型,以及初始化的一些方法。特别注意1298-1300行的几个指针,这里暂时提一下留个印象后面碰到了我们再详细说他。同时这里的ide_generic_port_info比较简单,仅仅初始化了两项:
static const struct ide_port_info ide_generic_port_info = {
.host_flags = IDE_HFLAG_NO_DMA,
.chipset = ide_generic,
};
再看第二个参数是个指针的指针,hws是个指针数组,初始化为 *hws[] = { &hw };第三个参数是要添加的port数量,这里指定为1;第四个参数为NULL,我们后面再谈….
好了,该是进军ide_host_add的时候了。先贴源码;
[ide_generic_init]->[ide_host_add]
1475 int ide_host_add(const struct ide_port_info *d, struct ide_hw **hws,
1476 unsigned int n_ports, struct ide_host **hostp)
1477 {
1478 struct ide_host *host;
1479 int rc;
1480
1481 host = ide_host_alloc(d, hws, n_ports);
1482 if (host == NULL)
1483 return -ENOMEM;
1484
1485 rc = ide_host_register(host, d, hws);
1486 if (rc) {
1487 ide_host_free(host);
1488 return rc;
1489 }
1490
1491 if (hostp)
1492 *hostp = host;
1493
1494 return 0;
1495 }
1496
开篇引入一个新的数据结构ide_host,再看看函数名,也是和host相关的。那就先来看看ide_host吧…
773 struct ide_host {
774 ide_hwif_t *ports[MAX_HOST_PORTS + 1];
775 unsigned int n_ports;
776 struct device *dev[2];
777
778 int (*init_chipset)(struct pci_dev *);
779
780 void (*get_lock)(irq_handler_t, void *);
781 void (*release_lock)(void);
782
783 irq_handler_t irq_handler;
784
785 unsigned long host_flags;
786
787 int irq_flags;
788
789 void *host_priv;
790 ide_hwif_t *cur_port; /* for hosts requiring serialization */
791
792 /* used for hosts requiring serialization */
793 volatile unsigned long host_busy;
794 };
795
什么叫做host?host即是主人,不过在linux的世界里他可没这么威风,至多也就是个没有脑子的工人,我们称之为主机控制器,实际上是个硬件比如一个专用的硬盘控制器。那么上级发了指令,XXX去干啥,然后host就按照指令要求去和下面的硬件打交道,当然这里的ide_host也就是描述这个硬件的属性的了,譬如位于总线的什么地方、中断号又是多少等等。
回到int ide_host_add,1481行调用ide_host_alloc(),从函数名和返回值来看,应该是分配一个ide_host结构。源码如下:
[ide_generic_init]->[ide_host_add]->[ ide_host_alloc]
1285 struct ide_host *ide_host_alloc(const struct ide_port_info *d,
1286 struct ide_hw **hws, unsigned int n_ports)
1287 {
1288 struct ide_host *host;
1289 struct device *dev = hws[0] ? hws[0]->dev : NULL;
1290 int node = dev ? dev_to_node(dev) : -1;
1291 int i;
1292
1293 host = kzalloc_node(sizeof(*host), GFP_KERNEL, node);
1294 if (host == NULL)
1295 return NULL;
1296
1297 for (i = 0; i < n_ports; i++) {
1298 ide_hwif_t *hwif;
1299 int idx;
1300
1301 if (hws[i] == NULL)
1302 continue;
1303
1304 hwif = kzalloc_node(sizeof(*hwif), GFP_KERNEL, node);
1305 if (hwif == NULL)
1306 continue;
1307
1308 if (ide_port_alloc_devices(hwif, node) < 0) {
1309 kfree(hwif);
1310 continue;
1311 }
1312
1313 idx = ide_find_port_slot(d);
1314 if (idx < 0) {
1315 printk(KERN_ERR "%s: no free slot for interface/n",
1316 d ? d->name : "ide");
1317 ide_port_free_devices(hwif);
1318 kfree(hwif);
1319 continue;
1320 }
1321
1322 ide_init_port_data(hwif, idx);
1323
1324 hwif->host = host;
1325
1326 host->ports[i] = hwif;
1327 host->n_ports++;
1328 }
1329
1330 if (host->n_ports == 0) {
1331 kfree(host);
1332 return NULL;
1333 }
1334
1335 host->dev[0] = dev;
1336
1337 if (d) {
1338 host->init_chipset = d->init_chipset;
1339 host->get_lock = d->get_lock;
1340 host->release_lock = d->release_lock;
1341 host->host_flags = d->host_flags;
1342 host->irq_flags = d->irq_flags;
1343 }
1344
1345 return host;
1346 }
1347
1289行获取ide_hw中指定的device指针,前面的初始化中并未看到对该项的设置。
1290行是和内存分配相关的,牵连到内存的非一致存储结构(NUMA)问题,这里不详细分析,相关内容可以参考《linux情景分析》中的内存管理相关内容。
1297行又是个for循环,有几个接口就循环几次,这里仅仅循环一次。
1308行调用了ide_port_alloc_devices(),跟踪进入….
[ide_generic_init]->[ide_host_add]->[ ide_host_alloc]->[ ide_port_alloc_devices]
1253 static int ide_port_alloc_devices(ide_hwif_t *hwif, int node)
1254 {
1255 int i;
1256
1257 for (i = 0; i < MAX_DRIVES; i++) {
1258 ide_drive_t *drive;
1259
1260 drive = kzalloc_node(sizeof(*drive), GFP_KERNEL, node);
1261 if (drive == NULL)
1262 goto out_nomem;
1263
1264 /*
1265 * In order to keep things simple we have an id
1266 * block for all drives at all times. If the device
1267 * is pre ATA or refuses ATA/ATAPI identify we
1268 * will add faked data to this.
1269 *
1270 * Also note that 0 everywhere means "can't do X"
1271 */
1272 drive->id = kzalloc_node(SECTOR_SIZE, GFP_KERNEL, node);
1273 if (drive->id == NULL)
1274 goto out_nomem;
1275
1276 hwif->devices[i] = drive;
1277 }
1278 return 0;
1279
1280 out_nomem:
1281 ide_port_free_devices(hwif);
1282 return -ENOMEM;
1283 }
1284
1258行又涉及到一个重要的数据结构ide_drive_t,我们知道前面我们定义了ide_hwif_t和hwif_s都是与实际的ide接口相对应,然而对于ide接口的设备来所,真正的驱动器是在设备内部,为了描述这个设备内部驱动器的属性比如:介质类型(ide,CDROM等)、传输位数(16bit、32bit等)等就定义了一个ide_drive_s的数据结构,实际上也就是ide_drive_t。同时根据IDE SPCE我们了解到每个IDE接口能支持两个ide设备,分别对应主设备和从设备,这两个设备驱动器对应的信息都要记录在接口中,那么在这里呢就成了MAX_DRIVES。有了这个背景后上面的一段代码就不难理解了。另外,在阅读linux内核的时候我们应该注意很多单词词义上的区别,比如:drive指示的是驱动器,是硬件设备;driver指示的是软件驱动等,理解这些对我们驱动程序的阅读时是很有帮助的。
1272行这里还是重点提一下,毕竟代码的作者也注释了不少。我是这么理解的,就是说每个硬盘有一些他自己的识别信息比如厂商号,磁头、柱面的大小等等,有的硬盘有单独的扇区来存放,但有的没有。那么为了方便我们索性都弄个ID字段伪造一个,大小就是一个扇区的大小这里是512字节。记录在ide_drive_t里边。
回到ide_host_alloc()中来,继续向前走…