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

📄 ppa.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 3 页
字号:
	"	outb %%al,(%%dx)\n" \	"	subl $2,%%edx\n"static inline int ppa_byte_in(unsigned short base, char *buffer, int len){    int i;    for (i = len; i; i--) {        *buffer++ = r_dtr(base);        w_ctr(base, 0x27);        w_ctr(base, 0x25);    }    return 1;			/* All went well - we hope! */}#define NIBBLE_IN(reg) \	"	incl %%edx\n" \	"	movb $0x04,%%al\n" \	"	outb %%al,(%%dx)\n" \	"	decl %%edx\n" \	"	inb (%%dx),%%al\n" \	"	andb $0xf0,%%al\n" \	"	movb %%al," #reg "\n" \	"	incl %%edx\n" \	"	movb $0x06,%%al\n" \	"	outb %%al,(%%dx)\n" \	"	decl %%edx\n" \	"	inb (%%dx),%%al\n" \	"	shrb $4,%%al\n" \	"	orb %%al," #reg "\n"static inline int ppa_nibble_in(unsigned short str_p, char *buffer, int len){    for (; len; len--) {        unsigned char h;        w_ctr(base, 0x4);        h = r_str(base) & 0xf0;        w_ctr(base, 0x6);        *buffer++ = h | ((r_str(base) & 0xf0) >> 4);    }    return 1;			/* All went well - we hope! */}#else				/* Old style C routines */static inline int ppa_byte_out(unsigned short base, const char *buffer, int len){    unsigned short ctr_p = base + 2;    int i;    for (i = len; i; i--) {	outb(*buffer++, base);	outb(0xe, ctr_p);	outb(0xc, ctr_p);    }    return 1;			/* All went well - we hope! */}static inline int ppa_byte_in(unsigned short base, char *buffer, int len){    unsigned short ctr_p = base + 2;    int i;    for (i = len; i; i--) {	*buffer++ = inb(base);	outb(0x27, ctr_p);	outb(0x25, ctr_p);    }    return 1;			/* All went well - we hope! */}static inline int ppa_nibble_in(unsigned short str_p, char *buffer, int len){    unsigned short ctr_p = str_p + 1;    unsigned char h, l;    int i;    for (i = len; i; i--) {	outb(0x4, ctr_p);	h = inb(str_p);	outb(0x6, ctr_p);	l = inb(str_p);	*buffer++ = (h & 0xf0) | ((l & 0xf0) >> 4);    }    return 1;			/* All went well - we hope! */  }  #endif  static inline int ppa_epp_out(unsigned short epp_p, unsigned short str_p, const char *buffer, int len){    int i;    for (i = len; i; i--) {	outb(*buffer++, epp_p);#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC	if (inb(str_p) & 0x01)	    return 0;  #endif    }    return 1;  }  static int ppa_out(int host_no, char *buffer, int len){    int r;    unsigned short ppb = PPA_BASE(host_no);    r = ppa_wait(host_no);    if ((r & 0x50) != 0x40) {	ppa_fail(host_no, DID_ERROR);	return 0;    }    switch (ppa_hosts[host_no].mode) {    case PPA_NIBBLE:    case PPA_PS2:	/* 8 bit output, with a loop */	r = ppa_byte_out(ppb, buffer, len);	break;    case PPA_EPP_32:    case PPA_EPP_16:    case PPA_EPP_8:	epp_reset(ppb);	w_ctr(ppb, 0x4);#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC	r = ppa_epp_out(ppb + 4, ppb + 1, buffer, len);#else	if (!(((long) buffer | len) & 0x03))	    outsl(ppb + 4, buffer, len >> 2);	else	    outsb(ppb + 4, buffer, len);	w_ctr(ppb, 0xc);	r = !(r_str(ppb) & 0x01);#endif	w_ctr(ppb, 0xc);	ecp_sync(ppb);	break;    default:	printk("PPA: bug in ppa_out()\n");	r = 0;    }    return r;}static inline int ppa_epp_in(int epp_p, int str_p, char *buffer, int len){    int i;    for (i = len; i; i--) {	*buffer++ = inb(epp_p);#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC	if (inb(str_p) & 0x01)	    return 0;#endif    }    return 1;  }  static int ppa_in(int host_no, char *buffer, int len){    int r;    unsigned short ppb = PPA_BASE(host_no);    r = ppa_wait(host_no);    if ((r & 0x50) != 0x50) {	ppa_fail(host_no, DID_ERROR);	return 0;    }    switch (ppa_hosts[host_no].mode) {    case PPA_NIBBLE:	/* 4 bit input, with a loop */	r = ppa_nibble_in(ppb + 1, buffer, len);	w_ctr(ppb, 0xc);	break;    case PPA_PS2:	/* 8 bit input, with a loop */	w_ctr(ppb, 0x25);	r = ppa_byte_in(ppb, buffer, len);	w_ctr(ppb, 0x4);	w_ctr(ppb, 0xc);	break;    case PPA_EPP_32:    case PPA_EPP_16:    case PPA_EPP_8:	epp_reset(ppb);	w_ctr(ppb, 0x24);#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC	r = ppa_epp_in(ppb + 4, ppb + 1, buffer, len);  #else	if (!(((long) buffer | len) & 0x03))	    insl(ppb + 4, buffer, len >> 2);	else	    insb(ppb + 4, buffer, len);	w_ctr(ppb, 0x2c);	r = !(r_str(ppb) & 0x01);#endif	w_ctr(ppb, 0x2c);	ecp_sync(ppb);	break;    default:	printk("PPA: bug in ppa_ins()\n");	r = 0;	break;    }    return r;}/* end of ppa_io.h */static inline void ppa_d_pulse(unsigned short ppb, unsigned char b){    w_dtr(ppb, b);    w_ctr(ppb, 0xc);    w_ctr(ppb, 0xe);    w_ctr(ppb, 0xc);    w_ctr(ppb, 0x4);    w_ctr(ppb, 0xc);}static void ppa_disconnect(int host_no){    unsigned short ppb = PPA_BASE(host_no);    ppa_d_pulse(ppb, 0);    ppa_d_pulse(ppb, 0x3c);    ppa_d_pulse(ppb, 0x20);    ppa_d_pulse(ppb, 0xf);}static inline void ppa_c_pulse(unsigned short ppb, unsigned char b){    w_dtr(ppb, b);    w_ctr(ppb, 0x4);    w_ctr(ppb, 0x6);    w_ctr(ppb, 0x4);    w_ctr(ppb, 0xc);}static inline void ppa_connect(int host_no, int flag){    unsigned short ppb = PPA_BASE(host_no);    ppa_c_pulse(ppb, 0);    ppa_c_pulse(ppb, 0x3c);    ppa_c_pulse(ppb, 0x20);    if ((flag == CONNECT_EPP_MAYBE) &&	IN_EPP_MODE(ppa_hosts[host_no].mode))	ppa_c_pulse(ppb, 0xcf);    else	ppa_c_pulse(ppb, 0x8f);}static int ppa_select(int host_no, int target){    int k;    unsigned short ppb = PPA_BASE(host_no);    /*     * Bit 6 (0x40) is the device selected bit.     * First we must wait till the current device goes off line...     */    k = PPA_SELECT_TMO;    do {	k--;    } while ((r_str(ppb) & 0x40) && (k));    if (!k)	return 0;    w_dtr(ppb, (1 << target));    w_ctr(ppb, 0xe);    w_ctr(ppb, 0xc);    w_dtr(ppb, 0x80);		/* This is NOT the initator */    w_ctr(ppb, 0x8);    k = PPA_SELECT_TMO;    do {	k--;    }    while (!(r_str(ppb) & 0x40) && (k));    if (!k)	return 0;    return 1;}/*  * This is based on a trace of what the Iomega DOS 'guest' driver does. * I've tried several different kinds of parallel ports with guest and * coded this to react in the same ways that it does. *  * The return value from this function is just a hint about where the * handshaking failed. *  */static int ppa_init(int host_no){    int retv;    unsigned short ppb = PPA_BASE(host_no);    ppa_disconnect(host_no);    ppa_connect(host_no, CONNECT_NORMAL);    retv = 2;			/* Failed */    w_ctr(ppb, 0xe);    if ((r_str(ppb) & 0x08) == 0x08)	retv--;    w_ctr(ppb, 0xc);    if ((r_str(ppb) & 0x08) == 0x00)	retv--;    /* This is a SCSI BUS reset signal */    if (!retv) {	w_dtr(ppb, 0x40);	w_ctr(ppb, 0x08);	udelay(30);	w_ctr(ppb, 0x0c);	udelay(1000);		/* Allow devices to settle down */    }    ppa_disconnect(host_no);    udelay(1000);		/* Another delay to allow devices to settle */    if (!retv)	retv = device_check(host_no);    return retv;}static inline int ppa_send_command(Scsi_Cmnd * cmd){    int host_no = cmd->host->unique_id;    int k;    w_ctr(PPA_BASE(host_no), 0x0c);    for (k = 0; k < cmd->cmd_len; k++)	if (!ppa_out(host_no, &cmd->cmnd[k], 1))	    return 0;    return 1;}/* * The bulk flag enables some optimisations in the data transfer loops, * it should be true for any command that transfers data in integral * numbers of sectors. *  * The driver appears to remain stable if we speed up the parallel port * i/o in this function, but not elsewhere. */static int ppa_completion(Scsi_Cmnd * cmd){    /* Return codes:     * -1     Error     *  0     Told to schedule     *  1     Finished data transfer     */    int host_no = cmd->host->unique_id;    unsigned short ppb = PPA_BASE(host_no);    unsigned long start_jiffies = jiffies;    unsigned char r, v;    int fast, bulk, status;    v = cmd->cmnd[0];    bulk = ((v == READ_6) ||	    (v == READ_10) ||	    (v == WRITE_6) ||	    (v == WRITE_10));    /*     * We only get here if the drive is ready to comunicate,     * hence no need for a full ppa_wait.     */    r = (r_str(ppb) & 0xf0);    while (r != (unsigned char) 0xf0) {	/*	 * If we have been running for more than a full timer tick	 * then take a rest.	 */	if (jiffies > start_jiffies + 1)	    return 0;	if (((r & 0xc0) != 0xc0) || (cmd->SCp.this_residual <= 0)) {	    ppa_fail(host_no, DID_ERROR);	    return -1;		/* ERROR_RETURN */	}	/* determine if we should use burst I/O */ fast = (bulk && (cmd->SCp.this_residual >= PPA_BURST_SIZE))	    ? PPA_BURST_SIZE : 1;	if (r == (unsigned char) 0xc0)	    status = ppa_out(host_no, cmd->SCp.ptr, fast);	else	    status = ppa_in(host_no, cmd->SCp.ptr, fast);	cmd->SCp.ptr += fast;	cmd->SCp.this_residual -= fast;	if (!status) {	    ppa_fail(host_no, DID_BUS_BUSY);	    return -1;		/* ERROR_RETURN */	}	if (cmd->SCp.buffer && !cmd->SCp.this_residual) {	    /* if scatter/gather, advance to the next segment */	    if (cmd->SCp.buffers_residual--) {		cmd->SCp.buffer++;		cmd->SCp.this_residual = cmd->SCp.buffer->length;		cmd->SCp.ptr = cmd->SCp.buffer->address;	    }	}	/* Now check to see if the drive is ready to comunicate */	r = (r_str(ppb) & 0xf0);	/* If not, drop back down to the scheduler and wait a timer tick */	if (!(r & 0x80))	    return 0;    }    return 1;			/* FINISH_RETURN */}/* * Since the PPA itself doesn't generate interrupts, we use * the scheduler's task queue to generate a stream of call-backs and * complete the request when the drive is ready. */static void ppa_interrupt(void *data){    ppa_struct *tmp = (ppa_struct *) data;    Scsi_Cmnd *cmd = tmp->cur_cmd;    if (!cmd) {	printk("PPA: bug in ppa_interrupt\n");	return;    }    if (ppa_engine(tmp, cmd)) {	tmp->ppa_tq.data = (void *) tmp;	tmp->ppa_tq.sync = 0;	queue_task(&tmp->ppa_tq, &tq_timer);	return;    }    /* Command must of completed hence it is safe to let go... */#if PPA_DEBUG > 0    switch ((cmd->result >> 16) & 0xff) {    case DID_OK:	break;    case DID_NO_CONNECT:	printk("ppa: no device at SCSI ID %i\n", cmd->target);	break;    case DID_BUS_BUSY:	printk("ppa: BUS BUSY - EPP timeout detected\n");	break;    case DID_TIME_OUT:	printk("ppa: unknown timeout\n");	break;    case DID_ABORT:	printk("ppa: told to abort\n");	break;    case DID_PARITY:	printk("ppa: parity error (???)\n");	break;    case DID_ERROR:	printk("ppa: internal driver error\n");	break;    case DID_RESET:	printk("ppa: told to reset device\n");	break;    case DID_BAD_INTR:	printk("ppa: bad interrupt (???)\n");	break;    default:	printk("ppa: bad return code (%02x)\n", (cmd->result >> 16) & 0xff);    }  #endif      if (cmd->SCp.phase > 1)	ppa_disconnect(cmd->host->unique_id);    tmp->cur_cmd = 0;    cmd->scsi_done(cmd);    return;}static int ppa_engine(ppa_struct * tmp, Scsi_Cmnd * cmd){    int host_no = cmd->host->unique_id;    unsigned short ppb = PPA_BASE(host_no);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -