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

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,

};

既然有总线了,那肯定是为设备和驱动服务的,当有设备或者驱动注册的时候就会引发总线的一系列动作,包括matchprobe的调用。这部分具体的代码我们等到后面在分析

380行注册一个类,同时/sys/class/下创建相应类目录

386ACPI表示高级配置和电源管理接口,这里与我们无关。

388proc文件系统相关内容,忽略

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-179io_portsio_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扯不上关系,就直接略过了。

95probe_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_arrayio_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

什么叫做hosthost即是主人,不过在linux的世界里他可没这么威风,至多也就是个没有脑子的工人,我们称之为主机控制器,实际上是个硬件比如一个专用的硬盘控制器。那么上级发了指令,XXX去干啥,然后host就按照指令要求去和下面的硬件打交道,当然这里的ide_host也就是描述这个硬件的属性的了,譬如位于总线的什么地方、中断号又是多少等等。

回到int ide_host_add1481行调用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_thwif_s都是与实际的ide接口相对应,然而对于ide接口的设备来所,真正的驱动器是在设备内部,为了描述这个设备内部驱动器的属性比如:介质类型(ideCDROM等)、传输位数(16bit32bit等)等就定义了一个ide_drive_s的数据结构,实际上也就是ide_drive_t。同时根据IDE SPCE我们了解到每个IDE接口能支持两个ide设备,分别对应主设备和从设备,这两个设备驱动器对应的信息都要记录在接口中,那么在这里呢就成了MAX_DRIVES。有了这个背景后上面的一段代码就不难理解了。另外,在阅读linux内核的时候我们应该注意很多单词词义上的区别,比如:drive指示的是驱动器,是硬件设备;driver指示的是软件驱动等,理解这些对我们驱动程序的阅读时是很有帮助的。

1272行这里还是重点提一下,毕竟代码的作者也注释了不少。我是这么理解的,就是说每个硬盘有一些他自己的识别信息比如厂商号,磁头、柱面的大小等等,有的硬盘有单独的扇区来存放,但有的没有。那么为了方便我们索性都弄个ID字段伪造一个,大小就是一个扇区的大小这里是512字节。记录在ide_drive_t里边。

回到ide_host_alloc()中来,继续向前走

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值