📄 at_wini.c
字号:
for(i = 0; i < SENSE_PACKETSIZE; i++) sense[i] = 0xff; r = atapi_sendpacket(packet, SENSE_PACKETSIZE); if (r != OK) { printf("request sense command failed\n"); return; } if (atapi_intr_wait() <= 0) { printf("WARNING: request response failed\n"); } if (sys_insw(w_wn->base_cmd + REG_DATA, SELF, (void *) sense, SENSE_PACKETSIZE) != OK) printf("WARNING: sense reading failed\n"); printf("sense data:"); for(i = 0; i < SENSE_PACKETSIZE; i++) printf(" %02x", sense[i]); printf("\n");}/*===========================================================================* * atapi_transfer * *===========================================================================*/PRIVATE int atapi_transfer(proc_nr, opcode, position, iov, nr_req)int proc_nr; /* process doing the request */int opcode; /* DEV_GATHER or DEV_SCATTER */off_t position; /* offset on device to read or write */iovec_t *iov; /* pointer to read or write request vector */unsigned nr_req; /* length of request vector */{ struct wini *wn = w_wn; iovec_t *iop, *iov_end = iov + nr_req; int r, s, errors, fresh; u64_t pos; unsigned long block; unsigned long dv_size = cv64ul(w_dv->dv_size); unsigned nbytes, nblocks, count, before, chunk; static u8_t packet[ATAPI_PACKETSIZE]; errors = fresh = 0; while (nr_req > 0 && !fresh) { /* The Minix block size is smaller than the CD block size, so we * may have to read extra before or after the good data. */ pos = add64ul(w_dv->dv_base, position); block = div64u(pos, CD_SECTOR_SIZE); before = rem64u(pos, CD_SECTOR_SIZE); /* How many bytes to transfer? */ nbytes = count = 0; for (iop = iov; iop < iov_end; iop++) { nbytes += iop->iov_size; if ((before + nbytes) % CD_SECTOR_SIZE == 0) count = nbytes; } /* Does one of the memory chunks end nicely on a CD sector multiple? */ if (count != 0) nbytes = count; /* Data comes in as words, so we have to enforce even byte counts. */ if ((before | nbytes) & 1) return(EINVAL); /* Which block on disk and how close to EOF? */ if (position >= dv_size) return(OK); /* At EOF */ if (position + nbytes > dv_size) nbytes = dv_size - position; nblocks = (before + nbytes + CD_SECTOR_SIZE - 1) / CD_SECTOR_SIZE; if (ATAPI_DEBUG) { printf("block=%lu, before=%u, nbytes=%u, nblocks=%u\n", block, before, nbytes, nblocks); } /* First check to see if a reinitialization is needed. */ if (!(wn->state & INITIALIZED) && w_specify() != OK) return(EIO); /* Build an ATAPI command packet. */ packet[0] = SCSI_READ10; packet[1] = 0; packet[2] = (block >> 24) & 0xFF; packet[3] = (block >> 16) & 0xFF; packet[4] = (block >> 8) & 0xFF; packet[5] = (block >> 0) & 0xFF; packet[7] = (nblocks >> 8) & 0xFF; packet[8] = (nblocks >> 0) & 0xFF; packet[9] = 0; packet[10] = 0; packet[11] = 0; /* Tell the controller to execute the packet command. */ r = atapi_sendpacket(packet, nblocks * CD_SECTOR_SIZE); if (r != OK) goto err; /* Read chunks of data. */ while ((r = atapi_intr_wait()) > 0) { count = r; if (ATAPI_DEBUG) { printf("before=%u, nbytes=%u, count=%u\n", before, nbytes, count); } while (before > 0 && count > 0) { /* Discard before. */ chunk = before; if (chunk > count) chunk = count; if (chunk > DMA_BUF_SIZE) chunk = DMA_BUF_SIZE; if ((s=sys_insw(wn->base_cmd + REG_DATA, SELF, tmp_buf, chunk)) != OK) panic(w_name(),"Call to sys_insw() failed", s); before -= chunk; count -= chunk; } while (nbytes > 0 && count > 0) { /* Requested data. */ chunk = nbytes; if (chunk > count) chunk = count; if (chunk > iov->iov_size) chunk = iov->iov_size; if ((s=sys_insw(wn->base_cmd + REG_DATA, proc_nr, (void *) iov->iov_addr, chunk)) != OK) panic(w_name(),"Call to sys_insw() failed", s); position += chunk; nbytes -= chunk; count -= chunk; iov->iov_addr += chunk; fresh = 0; if ((iov->iov_size -= chunk) == 0) { iov++; nr_req--; fresh = 1; /* new element is optional */ } } while (count > 0) { /* Excess data. */ chunk = count; if (chunk > DMA_BUF_SIZE) chunk = DMA_BUF_SIZE; if ((s=sys_insw(wn->base_cmd + REG_DATA, SELF, tmp_buf, chunk)) != OK) panic(w_name(),"Call to sys_insw() failed", s); count -= chunk; } } if (r < 0) { err: /* Don't retry if too many errors. */ if (atapi_debug) sense_request(); if (++errors == max_errors) { w_command = CMD_IDLE; if (atapi_debug) printf("giving up (%d)\n", errors); return(EIO); } if (atapi_debug) printf("retry (%d)\n", errors); } } w_command = CMD_IDLE; return(OK);}/*===========================================================================* * atapi_sendpacket * *===========================================================================*/PRIVATE int atapi_sendpacket(packet, cnt)u8_t *packet;unsigned cnt;{/* Send an Atapi Packet Command */ struct wini *wn = w_wn; pvb_pair_t outbyte[6]; /* vector for sys_voutb() */ int s; if (wn->state & IGNORING) return ERR; /* Select Master/Slave drive */ if ((s=sys_outb(wn->base_cmd + REG_DRIVE, wn->ldhpref)) != OK) panic(w_name(),"Couldn't select master/ slave drive",s); if (!w_waitfor(STATUS_BSY | STATUS_DRQ, 0)) { printf("%s: atapi_sendpacket: drive not ready\n", w_name()); return(ERR); } /* Schedule a wakeup call, some controllers are flaky. This is done with * a synchronous alarm. If a timeout occurs a SYN_ALARM message is sent * from HARDWARE, so that w_intr_wait() can call w_timeout() in case the * controller was not able to execute the command. Leftover timeouts are * simply ignored by the main loop. */ sys_setalarm(wakeup_ticks, 0);#if _WORD_SIZE > 2 if (cnt > 0xFFFE) cnt = 0xFFFE; /* Max data per interrupt. */#endif w_command = ATAPI_PACKETCMD; pv_set(outbyte[0], wn->base_cmd + REG_FEAT, 0); pv_set(outbyte[1], wn->base_cmd + REG_IRR, 0); pv_set(outbyte[2], wn->base_cmd + REG_SAMTAG, 0); pv_set(outbyte[3], wn->base_cmd + REG_CNT_LO, (cnt >> 0) & 0xFF); pv_set(outbyte[4], wn->base_cmd + REG_CNT_HI, (cnt >> 8) & 0xFF); pv_set(outbyte[5], wn->base_cmd + REG_COMMAND, w_command); if (atapi_debug) printf("cmd: %x ", w_command); if ((s=sys_voutb(outbyte,6)) != OK) panic(w_name(),"Couldn't write registers with sys_voutb()",s); if (!w_waitfor(STATUS_BSY | STATUS_DRQ, STATUS_DRQ)) { printf("%s: timeout (BSY|DRQ -> DRQ)\n", w_name()); return(ERR); } wn->w_status |= STATUS_ADMBSY; /* Command not at all done yet. */ /* Send the command packet to the device. */ if ((s=sys_outsw(wn->base_cmd + REG_DATA, SELF, packet, ATAPI_PACKETSIZE)) != OK) panic(w_name(),"sys_outsw() failed", s); { int p; if (atapi_debug) { printf("sent command:"); for(p = 0; p < ATAPI_PACKETSIZE; p++) { printf(" %02x", packet[p]); } printf("\n"); } } return(OK);}#endif /* ENABLE_ATAPI *//*===========================================================================* * w_other * *===========================================================================*/PRIVATE int w_other(dr, m)struct driver *dr;message *m;{ int r, timeout, prev; if (m->m_type != DEV_IOCTL ) { return EINVAL; } if (m->REQUEST == DIOCTIMEOUT) { if ((r=sys_datacopy(m->PROC_NR, (vir_bytes)m->ADDRESS, SELF, (vir_bytes)&timeout, sizeof(timeout))) != OK) return r; if (timeout == 0) { /* Restore defaults. */ timeout_ticks = DEF_TIMEOUT_TICKS; max_errors = MAX_ERRORS; wakeup_ticks = WAKEUP; w_silent = 0; } else if (timeout < 0) { return EINVAL; } else { prev = wakeup_ticks; if (!w_standard_timeouts) { /* Set (lower) timeout, lower error * tolerance and set silent mode. */ wakeup_ticks = timeout; max_errors = 3; w_silent = 1; if (timeout_ticks > timeout) timeout_ticks = timeout; } if ((r=sys_datacopy(SELF, (vir_bytes)&prev, m->PROC_NR, (vir_bytes)m->ADDRESS, sizeof(prev))) != OK) return r; } return OK; } else if (m->REQUEST == DIOCOPENCT) { int count; if (w_prepare(m->DEVICE) == NIL_DEV) return ENXIO; count = w_wn->open_ct; if ((r=sys_datacopy(SELF, (vir_bytes)&count, m->PROC_NR, (vir_bytes)m->ADDRESS, sizeof(count))) != OK) return r; return OK; } return EINVAL;}/*===========================================================================* * w_hw_int * *===========================================================================*/PRIVATE int w_hw_int(dr, m)struct driver *dr;message *m;{ /* Leftover interrupt(s) received; ack it/them. */ ack_irqs(m->NOTIFY_ARG); return OK;}/*===========================================================================* * ack_irqs * *===========================================================================*/PRIVATE void ack_irqs(unsigned int irqs){ unsigned int drive; for (drive = 0; drive < MAX_DRIVES && irqs; drive++) { if (!(wini[drive].state & IGNORING) && wini[drive].irq_need_ack && (wini[drive].irq_mask & irqs)) { if (sys_inb((wini[drive].base_cmd + REG_STATUS), &wini[drive].w_status) != OK) printf("couldn't ack irq on drive %d\n", drive); if (sys_irqenable(&wini[drive].irq_hook_id) != OK) printf("couldn't re-enable drive %d\n", drive); irqs &= ~wini[drive].irq_mask; } }}#define STSTR(a) if (status & STATUS_ ## a) { strcat(str, #a); strcat(str, " "); }#define ERRSTR(a) if (e & ERROR_ ## a) { strcat(str, #a); strcat(str, " "); }char *strstatus(int status){ static char str[200]; str[0] = '\0'; STSTR(BSY); STSTR(DRDY); STSTR(DMADF); STSTR(SRVCDSC); STSTR(DRQ); STSTR(CORR); STSTR(CHECK); return str;}char *strerr(int e){ static char str[200]; str[0] = '\0'; ERRSTR(BB); ERRSTR(ECC); ERRSTR(ID); ERRSTR(AC); ERRSTR(TK); ERRSTR(DM); return str;}#if ENABLE_ATAPI/*===========================================================================* * atapi_intr_wait * *===========================================================================*/PRIVATE int atapi_intr_wait(){/* Wait for an interrupt and study the results. Returns a number of bytes * that need to be transferred, or an error code. */ struct wini *wn = w_wn; pvb_pair_t inbyte[4]; /* vector for sys_vinb() */ int s; /* status for sys_vinb() */ int e; int len; int irr; int r; int phase; w_intr_wait(); /* Request series of device I/O. */ inbyte[0].port = wn->base_cmd + REG_ERROR; inbyte[1].port = wn->base_cmd + REG_CNT_LO; inbyte[2].port = wn->base_cmd + REG_CNT_HI; inbyte[3].port = wn->base_cmd + REG_IRR; if ((s=sys_vinb(inbyte, 4)) != OK) panic(w_name(),"ATAPI failed sys_vinb()", s); e = inbyte[0].value; len = inbyte[1].value; len |= inbyte[2].value << 8; irr = inbyte[3].value;#if ATAPI_DEBUG printf("wn %p S=%x=%s E=%02x=%s L=%04x I=%02x\n", wn, wn->w_status, strstatus(wn->w_status), e, strerr(e), len, irr);#endif if (wn->w_status & (STATUS_BSY | STATUS_CHECK)) { if (atapi_debug) { printf("atapi fail: S=%x=%s E=%02x=%s L=%04x I=%02x\n", wn->w_status, strstatus(wn->w_status), e, strerr(e), len, irr); } return ERR; } phase = (wn->w_status & STATUS_DRQ) | (irr & (IRR_COD | IRR_IO)); switch (phase) { case IRR_COD | IRR_IO: if (ATAPI_DEBUG) printf("ACD: Phase Command Complete\n"); r = OK; break; case 0: if (ATAPI_DEBUG) printf("ACD: Phase Command Aborted\n"); r = ERR; break; case STATUS_DRQ | IRR_COD: if (ATAPI_DEBUG) printf("ACD: Phase Command Out\n"); r = ERR; break; case STATUS_DRQ: if (ATAPI_DEBUG) printf("ACD: Phase Data Out %d\n", len); r = len; break; case STATUS_DRQ | IRR_IO: if (ATAPI_DEBUG) printf("ACD: Phase Data In %d\n", len); r = len; break; default: if (ATAPI_DEBUG) printf("ACD: Phase Unknown\n"); r = ERR; break; }#if 0 /* retry if the media changed */ XXX while (phase == (IRR_IO | IRR_COD) && (wn->w_status & STATUS_CHECK) && (e & ERROR_SENSE) == SENSE_UATTN && --try > 0);#endif wn->w_status |= STATUS_ADMBSY; /* Assume not done yet. */ return(r);}#endif /* ENABLE_ATAPI */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -