您的位置:首页 > 运维架构 > Linux

linux IDE驱动分析之IDE总线、驱动注册(二)

2010-10-13 14:18 501 查看
IDE总线、驱动注册(二)

回到ide_host_alloc()中来,继续向前走…
1313行又遇到一个ide_find_port_slot(),源码如下:

[ide_generic_init]->[ide_host_add]->[ ide_host_alloc]->[ ide_find_port_slot]
1195 /**
1196 * ide_find_port_slot - find free port slot
1197 * @d: IDE port info
1198 *
1199 * Return the new port slot index or -ENOENT if we are out of free slots.
1200 */
1201
1202 static int ide_find_port_slot(const struct ide_port_info *d)
1203 {
1204 int idx = -ENOENT;
1205 u8bootable=(d&&(d->host_flags &
IDE_HFLAG_NON_BOOTABLE)) ? 0 : 1;
1206 u8 i = (d && (d->host_flags & IDE_HFLAG_QD_2ND_PORT)) ? 1 : 0;
1207
1208 /*
1209 * Claim an unassigned slot.
1210 *
1211 * Give preference to claiming other slots before claiming ide0/ide1,
1212 * just in case there's another interface yet-to-be-scanned
1213 * which uses ports 0x1f0/0x170 (the ide0/ide1 defaults).
1214 *
1215 * Unless there is a bootable card that does not use the standard
1216 * ports 0x1f0/0x170 (the ide0/ide1 defaults).
1217 */
1218 mutex_lock(&ide_cfg_mtx);
1219 if (bootable) {
1220 if ((ide_indexes | i) != (1 << MAX_HWIFS) - 1)
1221 idx = ffz(ide_indexes | i);
1222 } else {
1223 if ((ide_indexes | 3) != (1 << MAX_HWIFS) - 1)
1224 idx = ffz(ide_indexes | 3);
1225 else if ((ide_indexes & 3) != 3)
1226 idx = ffz(ide_indexes);
1227 }
1228 if (idx >= 0)
1229 ide_indexes |= (1 << idx);
1230 mutex_unlock(&ide_cfg_mtx);
1231
1232 return idx;
1233 }
1234
在linux中一共支持9个ide接口即“ide0~ide9”,这些接口名称是按他注册的先后次序来进行分配的,不同的接口对应到设备文件中的主设备号等信息是不一样了。既然这样那么哪些接口是已经注册占用了的,是肯定需要记录下来的,那么就产生了后面我们将要看到的ide_indexes 这个静态变量,她实际上就正好是个位图,这样的处理方式在内核中已经屡见不鲜了。如果bit0有ide0占用了那么bit0就被设置为1。有了这个背景后我们再来看de_find_port_slot就容易多了。
1205行是个关于启动问题的,一般来讲用作底层引导的驱动盘我们一般是放在ide0、ide1的位置,这里要是指明说我是不能boot的,那好bootable=0,后面再来修理你,谁叫你这么坦白呢?内核都告诉我们有些时候我们还是不能太诚实….
1206行和1205行一样的伎俩, 不过这里的意思是/* set for the second port of QD65xx */,好像是说第一个接口ide0是不行的了。
1220行要是前面人家说了ide0不要,那么就用(ide_indexes | i)把bit0屏蔽起来,当然我们要说的这个就没这么变态了,我们的要求不高generic就行,毕竟我们的名字就叫ide_generic。这句话连贯起来说就是如果不是所有的接口都被占用了(每一位都为1),那么就利用ffz去找吧。
1221行ffz()这个函数就是在传入的实参中查找第一个0,然后返回他的位偏移。比如ffz(10110100B)的话,返回的就是2。这里实际上就是找个空位。
Linux当编写驱动程序时,一般情况下不能使用C标准库的函数。Linux内核也提供了与标准库函数功能相同的一些函数,但二者还是稍有差别。和这个函数有点像的几个我一同在这里贴出来。



1222-1226行前面已经把关键的讲到了这里就不在重复。
1229行既然这个空位找了,那我们就不客气了地占住了。

回到ide_host_alloc()中来,继续向前走…
1322行又遇到一个 ide_init_port_data(hwif, idx);,源码如下:

[ide_generic_init]->[ide_host_add]->[ ide_host_alloc]->[ ide_init_port_data]
1160 static void ide_init_port_data(ide_hwif_t *hwif, unsigned int index)
1161 {
1162 /* fill in any non-zero initial values */
1163 hwif->index = index;
1164 hwif->major = ide_hwif_to_major[index];
1165
1166 hwif->name[0] = 'i';
1167 hwif->name[1] = 'd';
1168 hwif->name[2] = 'e';
1169 hwif->name[3] = '0' + index;
1170
1171 spin_lock_init(&hwif->lock);
1172
1173 init_timer(&hwif->timer);
1174 hwif->timer.function = &ide_timer_expiry;
1175 hwif->timer.data = (unsigned long)hwif;
1176
1177 init_completion(&hwif->gendev_rel_comp);
1178
1179 hwif->tp_ops = &default_tp_ops;
1180
1181 ide_port_init_devices_data(hwif);
1182 }
1183
1162-1170行很容易理解,找到了ide接口的序号,就用index来初始化接口的相关字段
1173-1175行这是和定时器有关的设置,目的很明确。我们知道任何一个对IDE接口的操作,都会有中断来响应ide操作的状态,但是当设备出错时也许就会有问题了,所以这里设置一个定时器的回调函数和相应函数的入口参数,并对其进行初始化
1179行很久以前提到过这个字段,现在就对他初始化为默认值了,这个操作是所有ide特性的接口所共有的。如下所示:

248 const struct ide_tp_ops default_tp_ops = {
249 .exec_command = ide_exec_command,
250 .read_status = ide_read_status,
251 .read_altstatus = ide_read_altstatus,
252 .write_devctl = ide_write_devctl,
253
254 .dev_select = ide_dev_select,
255 .tf_load = ide_tf_load,
256 .tf_read = ide_tf_read,
257
258 .input_data = ide_input_data,
259 .output_data = ide_output_data,
260 };
具体的后面用到再说。
1181行有调用了ide_port_init_devices_data,我们知道前面我们为接口的device分配了空间,还尚未初始化。这里就是要对这个device中的每一项单独进行设置。具体代码如下:

[ide_generic_init]->[ide_host_add]->[ ide_host_alloc]->[ ide_init_port_data]
->[ ide_port_init_devices_data]
1130 static void ide_port_init_devices_data(ide_hwif_t *hwif)
1131 {
1132 ide_drive_t *drive;
1133 int i;
1134
1135 ide_port_for_each_dev(i, drive, hwif) {
1136 u8 j = (hwif->index * MAX_DRIVES) + i;
1137 u16 *saved_id = drive->id;
1138
1139 memset(drive, 0, sizeof(*drive));
1140 memset(saved_id, 0, SECTOR_SIZE);
1141 drive->id = saved_id;
1142
1143 drive->media = ide_disk;
1144 drive->select = (i << 4) | ATA_DEVICE_OBS;
1145 drive->hwif = hwif;
1146 drive->ready_stat = ATA_DRDY;
1147 drive->bad_wstat = BAD_W_STAT;
1148 drive->special_flags = IDE_SFLAG_RECALIBRATE |
1149 IDE_SFLAG_SET_GEOMETRY;
1150 drive->name[0] = 'h';
1151 drive->name[1] = 'd';
1152 drive->name[2] = 'a' + j;
1153 drive->max_failures = IDE_DEFAULT_MAX_FAILURES;
1154
1155 INIT_LIST_HEAD(&drive->list);
1156 init_completion(&drive->gendev_rel_comp);
1157 }
1158 }

1135行是个宏定义
#define ide_port_for_each_dev(i, dev, port) /
for ((i) = 0; ((dev) = (port)->devices[i]) || (i) < MAX_DRIVES;
1139-1141行是对这些结构清零,特别是id字段。后面的这些就很简单了…这里随便提一下硬盘在linux中使用“hda”、“ hdb”来描述的。hda表示第一个接口上面的硬盘设备。
从ide_port_init_devices_data返回以后ide_init_port_data也就安全结束了。但是 ide_host_alloc的故事并没有完,回到故事中来….

1324-1327行这又是linux惯用的招式,目的就是你心中放着我,我心中存着你。
接口属于哪个host总要记下吧!对host来讲你是我所管辖的端口,你是谁我总要记录在案。
1330行要是分配host的时候你都没有端口,那还浪费表情作甚。直接kfree掉,然后返回。
1335行一路走过来好像一直没有关注接口下面的这个linux设备模型中的device,但是这里还是关联到了host->dev[0]。相信这个device日后还是有机会出头的。
1337-1342行搞了这么久host还不知道自己是谁多没意思。那就用接口信息里面的几个相关项来对他进行设置,好歹让人家知道自己的init_chipset,初始化接口芯片组的方法…
1345行如果一切正常没有争议,那分配的这个host就返回了,ide_host_alloc也就用他的曲折一生换回了一个鲜活的host….

久违了的ide_host_add,我们终于回来了。
1485行ide_host_register(host, d, hws);注册ide_host。不是别人正是我们刚刚alloc的那个host精灵。跟踪源码:
[ide_generic_init]->[ide_host_add]->[ ide_host_register]
1373 int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
1374 struct ide_hw **hws)
1375 {
1376 ide_hwif_t *hwif, *mate = NULL;
1377 int i, j = 0;
1378
1379 ide_host_for_each_port(i, hwif, host) {
1380 if (hwif == NULL) {
1381 mate = NULL;
1382 continue;
1383 }
1384
1385 ide_init_port_hw(hwif, hws[i]);
1386 ide_port_apply_params(hwif);
1387
1388 if ((i & 1) && mate) {
1389 hwif->mate = mate;
1390 mate->mate = hwif;
1391 }
1392
1393 mate = (i & 1) ? NULL : hwif;
1394
1395 ide_init_port(hwif, i & 1, d);
1396 ide_port_cable_detect(hwif);
1397
1398 hwif->port_flags |= IDE_PFLAG_PROBING;
1399
1400 ide_port_init_devices(hwif);
1401 }
1402
1403 ide_host_for_each_port(i, hwif, host) {
1404 if (hwif == NULL)
1405 continue;
1406
1407 if (ide_probe_port(hwif) == 0)
1408 hwif->present = 1;
1409
1410 hwif->port_flags &= ~IDE_PFLAG_PROBING;
1411
1412 if ((hwif->host_flags & IDE_HFLAG_4DRIVES) == 0 ||
1413 hwif->mate == NULL || hwif->mate->present == 0) {
1414 if (ide_register_port(hwif)) {
1415 ide_disable_port(hwif);
1416 continue;
1417 }
1418 }
1419
1420 if (hwif->present)
1421 ide_port_tune_devices(hwif);
1422 }
1423
1424 ide_host_enable_irqs(host);
1425
1426 ide_host_for_each_port(i, hwif, host) {
1427 if (hwif == NULL)
1428 continue;
1429
1430 if (hwif_init(hwif) == 0) {
1431 printk(KERN_INFO "%s: failed to initialize IDE "
1432 "interface/n", hwif->name);
1433 device_unregister(&hwif->gendev);
1434 ide_disable_port(hwif);
1435 continue;
1436 }
1437
1438 if (hwif->present)
1439 if (ide_port_setup_devices(hwif) == 0) {
1440 hwif->present = 0;
1441 continue;
1442 }
1443
1444 j++;
1445
1446 ide_acpi_init_port(hwif);
1447
1448 if (hwif->present)
1449 ide_acpi_port_init_devices(hwif);
1450 }
1451
1452 ide_host_for_each_port(i, hwif, host) {
1453 if (hwif == NULL)
1454 continue;
1455
1456 if (hwif->present)
1457 hwif_register_devices(hwif);
1458 }
1459
1460 ide_host_for_each_port(i, hwif, host) {
1461 if (hwif == NULL)
1462 continue;
1463
1464 ide_sysfs_register_port(hwif);
1465 ide_proc_register_port(hwif);
1466
1467 if (hwif->present)
1468 ide_proc_port_register_devices(hwif);
1469 }
1470
1471 return j ? 0 : -1;
1472 }
1473

1379行ide_host_for_each_port(i, hwif, host)还是个宏定义,看了名字就知道取host结构中的port来做实验。MAX_HOST_PORTS最大也就4个。
#define ide_host_for_each_port(i, port, host) /
for ((i) = 0; ((port) = (host)->ports[i]) || (i) < MAX_HOST_PORTS; (i)++)
1380-1383行要是取出来的port是个空的,那没得商量直接进入下一轮
1385行 ide_init_port_hw(hwif, hws[i]);,不说hws已经很多年来,依稀记得很久以前还在ide_generic_init中的时候,我们就对ide_hw这个结构进行过设置,那时说的是ide寄存器的地址等等都放在里面。现在他又要上阵了,源码如下:

[ide_generic_init]->[ide_host_add]->[ ide_host_register]->[ide_init_port_hw]
1184 static void ide_init_port_hw(ide_hwif_t *hwif, struct ide_hw *hw)
1185 {
1186 memcpy(&hwif->io_ports, &hw->io_ports, sizeof(hwif->io_ports));
1187 hwif->irq = hw->irq;
1188 hwif->dev = hw->dev;
1189 hwif->gendev.parent = hw->parent ? hw->parent : hw->dev;
1190 hwif->config_data = hw->config;
1191 }
和ide_host_register相比ide_init_port_hw就单纯多了。其实,单纯并不是说她没有脑子。Ide-hw里面有的hwif_s里面全有,那么为什么我们还大费心思的整出那么多的数据结构不嫌累的慌。其实我想这里主要是为了下面移植的时候好方便接口,Hwif太过复杂,设置起来也容易出错。所有就干脆先构建一个ide_hw,对驱动开发者来讲只需填充一下ide_hw即可,对于hwif_s我们大可不必知道,就能完成ide驱动的移植了。
好了,闲话少叙仍旧回到ide_host_register中来….
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: