void usb_enumerate(struct usbhub_s *hub) { u32 portcount = hub->portcount; hub->threads = portcount; hub->detectend = timer_calc(USB_TIME_SIGATT); // Launch a thread for every port. int i; for (i=0; i<portcount; i++) { struct usbdevice_s *usbdev = malloc_tmphigh(sizeof(*usbdev)); if (!usbdev) { warn_noalloc(); continue; } memset(usbdev, 0, sizeof(*usbdev)); usbdev->hub = hub; usbdev->port = i; run_thread(usb_hub_port_setup, usbdev); } // Wait for threads to complete. while (hub->threads) yield(); }
// Check if a SCSI device is ready to receive commands int scsi_is_ready(struct disk_op_s *op) { dprintf(6, "scsi_is_ready (drive=%p)\n", op->drive_gf); /* Retry TEST UNIT READY for 5 seconds unless MEDIUM NOT PRESENT is * reported by the device. If the device reports "IN PROGRESS", * 30 seconds is added. */ int in_progress = 0; u32 end = timer_calc(5000); for (;;) { if (timer_check(end)) { dprintf(1, "test unit ready failed\n"); return -1; } int ret = cdb_test_unit_ready(op); if (!ret) // Success break; struct cdbres_request_sense sense; ret = cdb_get_sense(op, &sense); if (ret) // Error - retry. continue; // Sense succeeded. if (sense.asc == 0x3a) { /* MEDIUM NOT PRESENT */ dprintf(1, "Device reports MEDIUM NOT PRESENT\n"); return -1; } if (sense.asc == 0x04 && sense.ascq == 0x01 && !in_progress) { /* IN PROGRESS OF BECOMING READY */ dprintf(1, "Waiting for device to detect medium... "); /* Allow 30 seconds more */ end = timer_calc(30000); in_progress = 1; } } return 0; }
// Reset a drive static void ata_reset(struct atadrive_s *adrive_gf) { struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf); u8 slave = GET_GLOBALFLAT(adrive_gf->slave); u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2); dprintf(6, "ata_reset drive=%p\n", &adrive_gf->drive); // Pulse SRST outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST, iobase2+ATA_CB_DC); udelay(5); outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2+ATA_CB_DC); msleep(2); // wait for device to become not busy. int status = await_not_bsy(iobase1); if (status < 0) goto done; if (slave) { // Change device. u32 end = timer_calc(IDE_TIMEOUT); for (;;) { outb(ATA_CB_DH_DEV1, iobase1 + ATA_CB_DH); status = ndelay_await_not_bsy(iobase1); if (status < 0) goto done; if (inb(iobase1 + ATA_CB_DH) == ATA_CB_DH_DEV1) break; // Change drive request failed to take effect - retry. if (timer_check(end)) { warn_timeout(); goto done; } } } else { // QEMU doesn't reset dh on reset, so set it explicitly. outb(ATA_CB_DH_DEV0, iobase1 + ATA_CB_DH); } // On a user-reset request, wait for RDY if it is an ATA device. u8 type=GET_GLOBALFLAT(adrive_gf->drive.type); if (type == DTYPE_ATA) status = await_rdy(iobase1); done: // Enable interrupts outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC); dprintf(6, "ata_reset exit status=%x\n", status); }
// Wait for the specified ide state static inline int await_ide(u8 mask, u8 flags, u16 base, u16 timeout) { u32 end = timer_calc(timeout); for (;;) { u8 status = inb(base+ATA_CB_STAT); if ((status & mask) == flags) return status; if (timer_check(end)) { warn_timeout(); return -1; } yield(); } }