⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 at_wini.c

📁 minix3的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
	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 + -