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

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中一共支持9ide接口即“ide0~ide9”,这些接口名称是按他注册的先后次序来进行分配的,不同的接口对应到设备文件中的主设备号等信息是不一样了。既然这样那么哪些接口是已经注册占用了的,是肯定需要记录下来的,那么就产生了后面我们将要看到的ide_indexes 这个静态变量,她实际上就正好是个位图,这样的处理方式在内核中已经屡见不鲜了。如果bit0ide0占用了那么bit0就被设置为1。有了这个背景后我们再来看de_find_port_slot就容易多了。

1205行是个关于启动问题的,一般来讲用作底层引导的驱动盘我们一般是放在ide0ide1的位置,这里要是指明说我是不能boot的,那好bootable=0,后面再来修理你,谁叫你这么坦白呢?内核都告诉我们有些时候我们还是不能太诚实.

1206行和1205行一样的伎俩, 不过这里的意思是/* set for the second port of QD65xx */,好像是说第一个接口ide0是不行的了。

1220行要是前面人家说了ide0不要,那么就用(ide_indexes | i)把bit0屏蔽起来,当然我们要说的这个就没这么变态了,我们的要求不高generic就行,毕竟我们的名字就叫ide_generic。这句话连贯起来说就是如果不是所有的接口都被占用了(每一位都为1),那么就利用ffz去找吧。

1221ffz()这个函数就是传入的实参中查找第一个0,然后返回他的位偏移。比如ffz10110100B)的话,返回的就是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,我们终于回来了。

1485ide_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

1379ide_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中来.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值