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

IDE总线、驱动注册(五)

一路走来,感觉和do_probe一起走了好久好久,现在他总算快要离我们而去了,还是回忆一下和他走过的快乐时光,do_probe做的最有意义的一件事情就是调用ide_dev_read_id完成了硬盘identify数据的读取。离开do_probe,回到probe_for_drives中来的时候发现我们还只是刚刚开始..

489-493行我想我们没有研究的必要了,毕竟是和ATAPI,出错有关了。

495行判断一下设备的存在性,要是设备都不在了,驱动在这唱独角戏也就没啥意思了.

499-526行是在identification 失败后才执行的处理,我们一路走来是看着他长大的,那么这段代码也就没有分析的必要了。

528行这个判断人家指名道姓问是不是ide硬盘,我们肯定得应声啦。

529行调用ide_disk_init_chs(),代码如下:

[ide_generic_init]->[ide_host_add]->[ide_host_register]-> [ide_probe_port]->[ probe_for_drives] ->[ ide_disk_init_chs]

60 static void ide_disk_init_chs(ide_drive_t *drive)

61 {

62 u16 *id = drive->id;

63

64 /* Extract geometry if we did not already have one for the drive */

65 if (!drive->cyl || !drive->head || !drive->sect) {

66 drive->cyl  = drive->bios_cyl  = id[ATA_ID_CYLS];

67 drive->head = drive->bios_head = id[ATA_ID_HEADS];

68 drive->sect = drive->bios_sect = id[ATA_ID_SECTORS];

69 }

70

71 /* Handle logical geometry translation by the drive */

72 if (ata_id_current_chs_valid(id)) {

73 drive->cyl  = id[ATA_ID_CUR_CYLS];

74 drive->head = id[ATA_ID_CUR_HEADS];

75 drive->sect = id[ATA_ID_CUR_SECTORS];

76 }

77

78 /* Use physical geometry if what we have still makes no sense */

79 if (drive->head > 16 && id[ATA_ID_HEADS] && id[ATA_ID_HEADS] <= 16) {

80 drive->cyl  = id[ATA_ID_CYLS];

81 drive->head = id[ATA_ID_HEADS];

82 drive->sect = id[ATA_ID_SECTORS];

83 }

84 }

这段代码就是利用我们刚才读取到的id信息来设置drive中的磁头、柱面、扇区等参数,具体的对应关系参考上面讲到的那个id数据的组织的那张表。相信理解起来难度不大。

回到do_probe中来,最后一句我们就解脱了,调用ide_disk_init_mult_count,看下源代码:

[ide_generic_init]->[ide_host_add]->[ide_host_register]-> [ide_probe_port]->[ probe_for_drives] ->[ ide_disk_init_mult_count]

86 static void ide_disk_init_mult_count(ide_drive_t *drive)

87 {

88 u16 *id = drive->id;

89 u8 max_multsect = id[ATA_ID_MAX_MULTSECT] & 0xff;

90

91 if (max_multsect) {

92 if ((max_multsect / 2) > 1)

93 id[ATA_ID_MULTSECT] = max_multsect | 0x100;

94 else

95 id[ATA_ID_MULTSECT] &= ~0x1ff;

96

97 drive->mult_req = id[ATA_ID_MULTSECT] & 0xff;

98

99 if (drive->mult_req)

100 drive->special_flags |= IDE_SFLAG_SET_MULTMODE;

101 }

102 }

我们知道对硬盘扇区的读写是可以多个扇区一起连续操作的,但是由于内部cash的容量限制这个扇区数量,所以这里就有了max_multsect的说法。

89ATA_ID_MAX_MULTSECT= 47,对应到spce中为:

Maximum sectors per inter-rupt on Read multiple and Write multiple

100行将这个特别的特性(多扇区操作),记录在flage当中。

离开probe_for_drive的时候难免有些伤感,重新回到久违了的ide_probe_port,好像也走到了尽头,最后722行使能了禁用已久的中断..

重新回到ide_host_register函数,接着往下走.

1408行既然ide_probe_port成功返回了,那么这个接口上肯定是挂接了硬盘,是物理存在的,所以说hwif->present=1也就合情合理了。

1410行这个接口既然probe完成了也就没有必要再说人家是在probing了。xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

1414行调用ide_register_port(),跟踪一下源码:

[ide_generic_init]->[ide_host_add]->[ide_host_register]-> [ide_register_port]

543 static int ide_register_port(ide_hwif_t *hwif)

544 {

545 int ret;

546

547 /* register with global device tree */

548 dev_set_name(&hwif->gendev, hwif->name);

549 dev_set_drvdata(&hwif->gendev, hwif);

550 if (hwif->gendev.parent == NULL)

551 hwif->gendev.parent = hwif->dev;

552 hwif->gendev.release = hwif_release_dev;

553

554 ret = device_register(&hwif->gendev);

555 if (ret < 0) {

556 printk(KERN_WARNING "IDE: %s: device_register error: %d/n",

557 __func__, ret);

558 goto out;

559 }

560

561 hwif->portdev = device_create(ide_port_class, &hwif->gendev,

562       MKDEV(0, 0), hwif, hwif->name);

563 if (IS_ERR(hwif->portdev)) {

564 ret = PTR_ERR(hwif->portdev);

565 device_unregister(&hwif->gendev);

566 }

567 out:

568 return ret;

569 }

548549行是和设备模型有关的内容,关于设备模型可以说是整个linux设备驱动的灵魂和精髓。网上也有很多关于设备模型的详细分析,这里推荐网上华清远见的一位牛人博客fun_abc的《Linux那些事儿之我是Sysfs.pdf》。这里就不对这两个函数进行详细分析了。

550-553行比较简单。

554行调用device_register注册刚刚初始化的gendev

561行为什么主次设备号均为0

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

回到ide_host_register,接着往下看.

1420-1421行如果设备当前还在系统中,就调用ide_port_tune_devices(hwif);代码如下;

[ide_generic_init]->[ide_host_add]->[ide_host_register]-> [ide_port_tune_devices]

727 static void ide_port_tune_devices(ide_hwif_t *hwif)

728 {

729 const struct ide_port_ops *port_ops = hwif->port_ops;

730 ide_drive_t *drive;

731 int i;

732

733 ide_port_for_each_present_dev(i, drive, hwif) {

734 ide_check_nien_quirk_list(drive);

735

736 if (port_ops && port_ops->quirkproc)

737 port_ops->quirkproc(drive);

738 }

739

740 ide_port_for_each_present_dev(i, drive, hwif) {

741 ide_set_max_pio(drive);

742

743 drive->dev_flags |= IDE_DFLAG_NICE1;

744

745 if (hwif->dma_ops)

746 ide_set_dma(drive);

747 }

748 }

734行从名字中看到quirk是跟有些变态的设备相关的,具体到代码里面看一下:

229 void ide_check_nien_quirk_list(ide_drive_t *drive)

230 {

231 const char **list, *m = (char *)&drive->id[ATA_ID_PROD];

232

233 for (list = nien_quirk_list; *list != NULL; list++)

234 if (strstr(m, *list) != NULL) {

235 drive->dev_flags |= IDE_DFLAG_NIEN_QUIRK;

236 return;

237 }

238 }

233nien_quirk_list定义为:

static const char *nien_quirk_list[] = {

"QUANTUM FIREBALLlct08 08",

"QUANTUM FIREBALLP KA6.4",

"QUANTUM FIREBALLP KA9.1",

"QUANTUM FIREBALLP KX13.6",

"QUANTUM FIREBALLP KX20.5",

"QUANTUM FIREBALLP KX27.3",

"QUANTUM FIREBALLP LM20.4",

"QUANTUM FIREBALLP LM20.5",

"FUJITSU MHZ2160BH G2",

NULL

};

回到ide_port_tune_devices中来,736-739行就跳过了。

741ide_set_max_pio,不妨来看下源代码,如下:

[ide_generic_init]->[ide_host_add]->[ide_host_register]-> [ide_port_tune_devices]->[ ide_set_max_pio]

1508 static inline void ide_set_max_pio(ide_drive_t *drive)

1509 {

1510 ide_set_pio(drive, 255);

1511 }

就是直接调用ide_set_pio,跟进代码:

[ide_generic_init]->[ide_host_add]->[ide_host_register]-> [ide_port_tune_devices]->[ ide_set_max_pio]->[ ide_set_pio]

176 /* req_pio == "255" for auto-tune */

177 void ide_set_pio(ide_drive_t *drive, u8 req_pio)

178 {

179 ide_hwif_t *hwif = drive->hwif;

180 const struct ide_port_ops *port_ops = hwif->port_ops;

181 u8 host_pio, pio;

182

183 if (port_ops == NULL || port_ops->set_pio_mode == NULL ||

184     (hwif->host_flags & IDE_HFLAG_NO_SET_MODE))

185 return;

186

187 BUG_ON(hwif->pio_mask == 0x00);

188

189 host_pio = fls(hwif->pio_mask) - 1;

190

191 pio = ide_get_best_pio_mode(drive, req_pio, host_pio);

192

193 /*

194  * TODO:

195  * - report device max PIO mode

196  * - check req_pio != 255 against device max PIO mode

197  */

198 printk(KERN_DEBUG "%s: host max PIO%d wanted PIO%d%s selected PIO%d/n",

199   drive->name, host_pio, req_pio,

200   req_pio == 255 ? "(auto-tune)" : "", pio);

201

202 (void)ide_set_pio_mode(drive, XFER_PIO_0 + pio);

203 }

183-185行的判断,一路走来我们也许发现了这个port_ops始终是没有被设置的,也就是说下面的所做的事情对我们来说就是没有意义的了,直接返回。 

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

回到ide_host_register,继续1424行的内容,这里调用ide_host_enable_irqs(host);代码如下:

[ide_generic_init]->[ide_host_add]->[ide_host_register]-> [ide_host_enable_irqs]

832 static void ide_host_enable_irqs(struct ide_host *host)

833 {

834 ide_hwif_t *hwif;

835 int i;

836

837 ide_host_for_each_port(i, hwif, host) {

838 if (hwif == NULL)

839 continue;

840

841 /* clear any pending IRQs */

842 hwif->tp_ops->read_status(hwif);

843

844 /* unmask IRQs */

845 if (hwif->io_ports.ctl_addr)

846 hwif->tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);

847 }

848 }

842行通过读取状态寄存器的值来清除中断标志

846行写控制寄存器使能中断

这段代码比较简单就不在多说了,接着回到ide_host_register…..

1426-1428行的代码又出现了..

1430hwif_init初始化接口,跟踪源码如下;

[ide_generic_init]->[ide_host_add]->[ide_host_register]-> [hwif_init]

969 static int hwif_init(ide_hwif_t *hwif)

970 {

971 if (!hwif->irq) {

972 printk(KERN_ERR "%s: disabled, no IRQ/n", hwif->name);

973 return 0;

974 }

975

976 if (register_blkdev(hwif->major, hwif->name))

977 return 0;

978

979 if (!hwif->sg_max_nents)

980 hwif->sg_max_nents = PRD_ENTRIES;

981

982 hwif->sg_table = kmalloc(sizeof(struct scatterlist)*hwif->sg_max_nents,

983  GFP_KERNEL);

984 if (!hwif->sg_table) {

985 printk(KERN_ERR "%s: unable to allocate SG table./n", hwif->name);

986 goto out;

987 }

988

989 sg_init_table(hwif->sg_table, hwif->sg_max_nents);

990

991 if (init_irq(hwif)) {

992 printk(KERN_ERR "%s: disabled, unable to get IRQ %d/n",

993 hwif->name, hwif->irq);

994 goto out;

995 }

996

997 blk_register_region(MKDEV(hwif->major, 0), MAX_DRIVES << PARTN_BITS,

998     THIS_MODULE, ata_probe, ata_lock, hwif);

999 return 1;

1000

1001 out:

1002 unregister_blkdev(hwif->major, hwif->name);

1003 return 0;

1004 }

976行调用register_blkdev(),每当看到register就觉得他异常的高级,这里当然也不例外。大名鼎鼎的块设备就是在这里和IDE硬盘发生了关系,一下子IDE硬盘驱动的身价也就太高了不少。这个函数估计再往下讲估计要扯到十万八千里了,反正来日方长,那天有心情了再来好好看他,下面回到IDE上来。

980行为了这一行,代码的作者写了N长的一段注释贴出来看一下:

98 /*

99  * Our Physical Region Descriptor (PRD) table should be large enough

100  * to handle the biggest I/O request we are likely to see.  Since requests

101  * can have no more than 256 sectors, and since the typical blocksize is

102  * two or more sectors, we could get by with a limit of 128 entries here for

103  * the usual worst case.  Most requests seem to include some contiguous blocks,

104  * further reducing the number of table entries required.

105  *

106  * The driver reverts to PIO mode for individual requests that exceed

107  * this limit (possible with 512 byte blocksizes, eg. MSDOS f/s), so handling

108  * 100% of all crazy scenarios here is not necessary.

109  *

110  * As it turns out though, we must allocate a full 4KB page for this,

111  * so the two PRD tables (ide0 & ide1) will each get half of that,

112  * allowing each to have about 256 entries (8 bytes each) from this.

113  */

114 #define PRD_BYTES       8

115 #define PRD_ENTRIES 256

99行有个Physical Region Descriptor,这是什么东西?下面先来了解一下她,一般来讲硬盘的每次读写都会牵涉到DMA的过程,而文件系统对硬盘的I/O请求不是连续的,数据所在的物理内存页也是不连续的,如果能够将这些不连续的内存页组合到一起,再启用DMA操作,那么这些数据就能够一次传输完成,这样也就能高效的传输数据。以Silicon Image 3114为例,可以将不连续的物理内存页和该页的长度组合放到physical region descriptor table 里,physical region descriptor table 结构如下:

有了这个背景以后接着往下看注释,就是说块设备一般最大的IO请求不会超过256扇区大小,而且一般来说这些请求都是又连续的,所以为其分配256个表项是能够满足的。同时每个表项含有8个字节,就是上面我们所看到的那个physical region descriptor table 结构图。

好了说完这些可能还是不知道他是干什么的,那也许是你还没有认识她的另一半scatter/gather的缘故。引用牛人的一段话来讲述scatter/gather的故事……

“她是一种用于高性能IO的标准技术。通常意味着一种DMA传输方式,对于一个给定的数据块,她老人家可能在内存中存在于一些离散的缓冲区,换言之,就是说一些不连续的内存缓冲区一起保存一个数据块,如果没有scatter/gather,那么当我们要建立一个从内存到磁盘的传输,那么操作系统通常会为每一个buffer做一次传输,或者干脆就是把这些不连续的buffer里边的冬冬全都移动到另一个很大的buffer里边,然后再开始传输.那么这两种方法显然都是效率不高的.毫无疑问,如果 操作系统/驱动程序/硬件 能够把这些来自内存中离散位置的数据收集起来(gather up)并转移她们到适当位置整个这个步骤是一个单一的操作的话,效率肯定就会更高.反之,如果要从磁盘向内存中传输,而有一个单一的操作能够把数据块直接分散开来(scatter)到达内存中需要的位置,而不再需要中间的那个块移动,或者别的方法,那么显然,效率总会更高.

DMA传输数据的过程中,要求源物理地址和目标物理地址必须是连续的。但是在某些计算机体系中,如IA架构,连续的存储器地址在物理上不一定是连续的,所以DMA传输要分成多次完成。如果在传输完一块物理上连续的数据后引起一次中断,然后再由主机进行下一块物理上连续的数据传输,那么这种方式就为block DMA方式。Scatter-gather DMA方式则不同,它使用一个链表描述物理上不连续的存储空间,然后把链表首地址告诉DMA masterDMA master在传输完一块物理连续的数据后,不用发起中断,而是根据链表来传输下一块物理上连续的数据,直到传输完毕后再发起一次中断。很显然,scatter-gather DMA方式比block DMA方式效率高。

一个小小的等号,引发了一连串的谜团,谁才是他真正的幕后黑手,答案就是DMA。好了言归正传,接下来.

982行有了前面的历史背景明显理解这句话也不是什么难事,就是分配PRD_ENTRIES个散列链表。其定义如下:

/* Scatter-gather list used to build the above */

struct scatterlist *sg_table;

int sg_max_nents; /* Maximum number of entries in it */

989行调用了sg_init_table(),函数内容很简单,不再详述..

[ide_generic_init]->[ide_host_add]->[ide_host_register]-> [hwif_init]->[ sg_init_table]

83 void sg_init_table(struct scatterlist *sgl, unsigned int nents)

84 {

85 memset(sgl, 0, sizeof(*sgl) * nents);

86 #ifdef CONFIG_DEBUG_SG

87 {

88 unsigned int i;

89 for (i = 0; i < nents; i++)

90 sgl[i].sg_magic = SG_MAGIC;

91 }

92 #endif

93 sg_mark_end(&sgl[nents - 1]);

94 }

991init_irq(),一看名字就知道是个不好惹得主,没办法还是得看,源码如下:

[ide_generic_init]->[ide_host_add]->[ide_host_register]-> [hwif_init]->[ init_irq]

850 /*

851  * This routine sets up the IRQ for an IDE interface.

852  */

853 static int init_irq (ide_hwif_t *hwif)

854 {

855 struct ide_io_ports *io_ports = &hwif->io_ports;

856 struct ide_host *host = hwif->host;

857 irq_handler_t irq_handler = host->irq_handler;

858 int sa = host->irq_flags;

859

860 if (irq_handler == NULL)

861 irq_handler = ide_intr;

862

863 if (request_irq(hwif->irq, irq_handler, sa, hwif->name, hwif))

864 goto out_up;

865

866 #if !defined(__mc68000__)

867 printk(KERN_INFO "%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name,

868 io_ports->data_addr, io_ports->status_addr,

869 io_ports->ctl_addr, hwif->irq);

870 #else

871 printk(KERN_INFO "%s at 0x%08lx on irq %d", hwif->name,

872 io_ports->data_addr, hwif->irq);

873 #endif /* __mc68000__ */

874 if (hwif->host->host_flags & IDE_HFLAG_SERIALIZE)

875 printk(KERN_CONT " (serialized)");

876 printk(KERN_CONT "/n");

877

878 return 0;

879 out_up:

880 return 1;

881 }

860-861行如果没有指定中断向量,那么就使用内核默认的。你瞧内核多为我们省心啊。为了减轻这个阶段的压力我们暂时缓口气,不去研究它了。后面会有机会的,跑不了.

863行估计写过驱动程序的大家都知道request_irq() 注册中断服务,这里就不深究他了。要想仔细研究中断的看ldd3去。

867-869行这里会在加载的时候打印我们地址的一些信息。

看完init_irq(),回到hwif_init….

997blk_register_region又是块设备那边的事情了,这里飘过

又到了ide_host_register时间,如果hwif_init一路顺风的话现在该返回1了,这样也就到了1438行了。

1439行如果还想在道上混的话,这句话估计还是要认识一下的。ide_port_setup_devices();看下源代码:

[ide_generic_init]->[ide_host_add]->[ide_host_register]-> [ide_port_setup_devices]

807 /*

808  * For any present drive:

809  * - allocate the block device queue

810  */

811 static int ide_port_setup_devices(ide_hwif_t *hwif)

812 {

813 ide_drive_t *drive;

814 int i, j = 0;

815

816 mutex_lock(&ide_cfg_mtx);

817 ide_port_for_each_present_dev(i, drive, hwif) {

818 if (ide_init_queue(drive)) {

819 printk(KERN_ERR "ide: failed to init %s/n",

820 drive->name);

821 drive->dev_flags &= ~IDE_DFLAG_PRESENT;

822 continue;

823 }

824

825 j++;

826 }

827 mutex_unlock(&ide_cfg_mtx);

828

829 return j;

830 }

818行这里为块设备分配请求队列,来看下源码:

[ide_generic_init]->[ide_host_add]->[ide_host_register]-> [ide_port_setup_devices]->[ ide_init_queue]

750 /*

751  * init request queue

752  */

753 static int ide_init_queue(ide_drive_t *drive)

754 {

755 struct request_queue *q;

756 ide_hwif_t *hwif = drive->hwif;

757 int max_sectors = 256;

758 int max_sg_entries = PRD_ENTRIES;

759

760 /*

761  * Our default set up assumes the normal IDE case,

762  * that is 64K segmenting, standard PRD setup

763  * and LBA28. Some drivers then impose their own

764  * limits and LBA48 we could raise it but as yet

765  * do not.

766  */

767

768 q = blk_init_queue_node(do_ide_request, NULL, hwif_to_node(hwif));

769 if (!q)

770 return 1;

771

772 q->queuedata = drive;

773 blk_queue_segment_boundary(q, 0xffff);

774

775 if (hwif->rqsize < max_sectors)

776 max_sectors = hwif->rqsize;

777 blk_queue_max_sectors(q, max_sectors);

778

779 #ifdef CONFIG_PCI

780 /* When we have an IOMMU, we may have a problem where pci_map_sg()

781  * creates segments that don't completely match our boundary

782  * requirements and thus need to be broken up again. Because it

783  * doesn't align properly either, we may actually have to break up

784  * to more segments than what was we got in the first place, a max

785  * worst case is twice as many.

786  * This will be fixed once we teach pci_map_sg() about our boundary

787  * requirements, hopefully soon. *FIXME*

788  */

789 if (!PCI_DMA_BUS_IS_PHYS)

790 max_sg_entries >>= 1;

791 #endif /* CONFIG_PCI */

792

793 blk_queue_max_hw_segments(q, max_sg_entries);

794 blk_queue_max_phys_segments(q, max_sg_entries);

795

796 /* assign drive queue */

797 drive->queue = q;

798

799 /* needs drive->queue to be set */

800 ide_toggle_bounce(drive, 1);

801

802 return 0;

803 }

可以说这个函数所做的所有工作纯粹是为了与块设备的接口。所以很多都调用了块设备那边的函数,这些内容以后将放在块设备驱动中详细分析。这里我们还是来简单看一下。

768行可以说把整个IDE驱动带入了高潮,因为以后块设备对IDE的设备的所有操作会全部落实到do_ide_request,那么这个函数也将作为我们后续分析硬盘设备的读写过程的一个突破口,另外上层块设备的操作与do_ide_request是靠设备节点联系起来的。hwif_to_node这个函数不是块设备的内容,这里还是可以小心地窥视一番……

static inline int hwif_to_node(ide_hwif_t *hwif)

{

return hwif->dev ? dev_to_node(hwif->dev) : -1;

}

772行把驱动器记录下面后面传入do_ide_request的参数就只剩下她,这可得记好了。

797行这里把分配的这个请求队列记录到驱动器中这是一一对应的。

关于ide_init_queue其他的内容和块设备关系较大,后面我们遇到了在来说效果会更明显一些。

ide_init_queue返回后,ide_port_setup_devices也就没有什么可分析的了。继续回到ide_host_register.

1446-1449ACPI表示高级配置和电源管理接口(Advanced Configuration and Power Management Interface相关,跳过

1457行看到这个函数名字hwif_register_devices(hwif);的时候有点小小的激动,因为在这个时候看到register_devices这样的字眼,估计这个长长的故事该走到尽头了。在讲述这个故事结局的时候还是先来把1464-1469行解决了。

1464-1469行看名字就知道是procsysfs文件系统的内容,好了不用在这里纠结了。

回到1457行去看个究竟.

[ide_generic_init]->[ide_host_add]->[ide_host_register]-> [hwif_register_devices]

1006 static void hwif_register_devices(ide_hwif_t *hwif)

1007 {

1008 ide_drive_t *drive;

1009 unsigned int i;

1010

1011 ide_port_for_each_present_dev(i, drive, hwif) {

1012 struct device *dev = &drive->gendev;

1013 int ret;

1014

1015 dev_set_name(dev, "%u.%u", hwif->index, i);

1016 dev_set_drvdata(dev, drive);

1017 dev->parent = &hwif->gendev;

1018 dev->bus = &ide_bus_type;

1019 dev->release = drive_release_dev;

1020

1021 ret = device_register(dev);

1022 if (ret < 0)

1023 printk(KERN_WARNING "IDE: %s: device_register error: "

1024     "%d/n", __func__, ret);

1025 }

1026 }

1012drive->gendev这个我们并不陌生,前面我们已经遇到了,并为他创建了设备节点了。

1015-1019行就是初始化这个drive->gendev,为真正的device_register准备。

1021行这句话看的我们心里比吃了蜜还甜,让我们总算到了总线枚举阶段。回忆刚开篇时我们讲到ide总线注册时候的machprobe,就知道下面该是总线表现的时候了。

离开hwif_register_devices以后所有关于ide_generic_init的故事就彻底结束了,带着悲喜交加的心情离开ide-generic.c,喜因为总是结束了这个ide_generic_init的咒语,悲因为ide的故事才刚刚开始呢!广告之后不要走开,后面的故事会更加精彩..

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值