void insw(int port, short *ptr, int len) { unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port); _insw(io_ptr, ptr, len); }
/** * Initialize disk device driver. Reserves memory for data structures * and register driver to the interrupt handler. * * @param desc Pointer to the PCI IO device descriptor of the controller * * @return Pointer to the device structure of the controller */ int disk_init(io_descriptor_t *desc) { /* Cast it */ pci_conf_t *pci = (pci_conf_t*)(uint64_t*) desc; /* Set bases to default values */ uint16_t iobase1 = IDE_PRIMARY_CMD_BASE; uint16_t iobase2 = IDE_SECONDARY_CMD_BASE; uint16_t ctrlbase1 = IDE_PRIMARY_CTRL_BASE; uint16_t ctrlbase2 = IDE_SECONDARY_CTRL_BASE; uint16_t busmaster = pci->bar4; uint32_t i, j, count = 0; uint16_t buf[256]; /* Check for compatability mode */ if(pci->prog_if & 0x1) { /* Native mode for channel 1 */ iobase1 = (uint16_t)pci->bar0; ctrlbase1 = (uint16_t)pci->bar1; /* Check if they can be relocated */ if(iobase1 & 0x1) iobase1--; if(ctrlbase1 & 0x1) ctrlbase1--; } if(pci->prog_if & 0x4) { /* Native mode for channel 2 */ iobase2 = (uint16_t)pci->bar2; ctrlbase2 = (uint16_t)pci->bar3; /* Check if they can be relocated */ if(iobase2 & 0x1) iobase2--; if(ctrlbase2 & 0x1) ctrlbase2--; } /* Setup Channels */ ide_channels[IDE_PRIMARY].busm = busmaster; ide_channels[IDE_PRIMARY].base = iobase1; ide_channels[IDE_PRIMARY].ctrl = ctrlbase1; ide_channels[IDE_PRIMARY].irq = IDE_PRIMARY_IRQ; ide_channels[IDE_PRIMARY].irq_wait = 0; ide_channels[IDE_PRIMARY].dma_phys = 0; ide_channels[IDE_PRIMARY].dma_virt = 0; ide_channels[IDE_PRIMARY].dma_buf_phys = 0; ide_channels[IDE_PRIMARY].dma_buf_virt = 0; ide_channels[IDE_SECONDARY].busm = busmaster; ide_channels[IDE_SECONDARY].base = iobase2; ide_channels[IDE_SECONDARY].ctrl = ctrlbase2; ide_channels[IDE_SECONDARY].irq = IDE_SECONDARY_IRQ; ide_channels[IDE_SECONDARY].irq_wait = 0; ide_channels[IDE_SECONDARY].dma_phys = 0; ide_channels[IDE_SECONDARY].dma_virt = 0; ide_channels[IDE_SECONDARY].dma_buf_phys = 0; ide_channels[IDE_SECONDARY].dma_buf_virt = 0; /* Install interrupts */ interrupt_register(IDE_PRIMARY_IRQ, (int_handler_t)ide_irq_handler0, 0); interrupt_register(IDE_SECONDARY_IRQ, (int_handler_t)ide_irq_handler1, 0); /* Disable Irqs, we use polling mode */ ide_write(IDE_PRIMARY, IDE_REGISTER_CTRL, 2); ide_write(IDE_SECONDARY, IDE_REGISTER_CTRL, 2); /* Enumerate devices */ /* We send an IDE_IDENTIFY command to each device, on * each channel, and see if it responds */ for(i = 0; i < IDE_CHANNELS_PER_CTRL; i++) { for(j = 0; j < IDE_DEVICES_PER_CHANNEL; j++) { /* Variables */ uint8_t error = 0, type = 0, status = 0; uint32_t lba28 = 0; uint64_t lba48 = 0; ide_devices[count].present = 0; //assume no drive /* Step 1. Select drive */ ide_write(i, IDE_REGISTER_HDDSEL, 0xA0 | (j << 4)); ide_delay(i); /* Step 2. Send IDE_IDENTIFY */ ide_write(i, IDE_REGISTER_SECCOUNT0, 0); ide_write(i, IDE_REGISTER_LBA0, 0); ide_write(i, IDE_REGISTER_LBA1, 0); ide_write(i, IDE_REGISTER_LBA2, 0); ide_write(i, IDE_REGISTER_LBA2, 0); ide_write(i, IDE_REGISTER_COMMAND, IDE_COMMAND_IDENTIFY); ide_delay(i); /* Step 3. Poll */ status = _inb(ide_channels[i].base + IDE_REGISTER_STATUS); if(status == 0 || status == 0x7F || status == 0xFF) { count++; continue; } /* Wuhuu! device is here */ while(1) { status = _inb(ide_channels[i].base + IDE_REGISTER_STATUS); if(status & 0x1) { error = 1; break; } if(!(status & IDE_ATA_BUSY) && (status & IDE_ATA_DRQ)) { break; } } /* Step 4. Probe for ATAPI */ if(error != 0) { /* Get type */ uint8_t cl = _inb(ide_channels[i].base + IDE_REGISTER_LBA1); uint8_t ch = _inb(ide_channels[i].base + IDE_REGISTER_LBA2); if(cl == 0x14 && ch == 0xEB) /* PATAPI */ type = 1; else if(cl == 0x69 && ch == 0x96) /* SATAPI */ type = 1; else { /* Unknown Type */ count++; continue; } /* Identify */ ide_write(i, IDE_REGISTER_COMMAND, IDE_COMMAND_PACKET); ide_delay(i); } /* Step 5. Read identification space */ _insw(ide_channels[i].base + IDE_REGISTER_DATA, 256, (uint8_t*)buf); /* Step 6. Read device parameters */ ide_devices[count].present = 1; ide_devices[count].type = type; ide_devices[count].channel = i; ide_devices[count].drive = j; ide_devices[count].signature = (*(uint16_t*)(buf)); ide_devices[count].capabilities = (*(uint16_t*)(buf + 49)); ide_devices[count].commandset = (*(uint32_t*)(buf + 82)); /* Step 7. Get geometry */ lba28 = (*(uint32_t*)(buf + 60)); lba48 = (*(uint64_t*)(buf + 100)); if(lba48) { ide_devices[count].totalsectors = lba48; ide_devices[count].cylinders = (*(uint16_t*)(buf + 1)); ide_devices[count].headspercylinder = (*(uint16_t*)(buf + 3)); ide_devices[count].secsperhead = (*(uint64_t*)(buf + 6)); ide_devices[count].flags |= 0x1; } else if(lba28 && !lba48) { ide_devices[count].totalsectors = lba28; ide_devices[count].cylinders = (*(uint16_t*)(buf + 1)); ide_devices[count].headspercylinder = (*(uint16_t*)(buf + 3)); ide_devices[count].secsperhead = (*(uint64_t*)(buf + 6)); } else { ide_devices[count].totalsectors = 0; ide_devices[count].cylinders = 0; ide_devices[count].headspercylinder = 0; ide_devices[count].secsperhead = 0; } /* Register filesystem */ ide_dev[count].real_device = &(ide_channels[0]); ide_dev[count].type = TYPECODE_DISK; ide_dev[count].generic_device = &ide_gbd[count]; ide_dev[count].io_address = count; /* Setup ide device */ ide_gbd[count].device = &ide_dev[count]; ide_gbd[count].write_block = ide_write_block; ide_gbd[count].read_block = ide_read_block; ide_gbd[count].block_size = ide_get_sectorsize; ide_gbd[count].total_blocks = ide_get_sectorcount; device_register(&ide_dev[count]); /* Increase count */ count++; } } return 0; }