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

📄 imm.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
static int imm_byte_out(unsigned short base, const char *buffer, int len){    int i;    w_ctr(base, 0x4);		/* apparently a sane mode */    for (i = len >> 1; i; i--) {	w_dtr(base, *buffer++);	w_ctr(base, 0x5);	/* Drop STROBE low */	w_dtr(base, *buffer++);	w_ctr(base, 0x0);	/* STROBE high + INIT low */    }    w_ctr(base, 0x4);		/* apparently a sane mode */    return 1;			/* All went well - we hope! */}static int imm_nibble_in(unsigned short base, char *buffer, int len){    unsigned char l;    int i;    /*     * The following is based on documented timing signals     */    w_ctr(base, 0x4);    for (i = len; i; i--) {	w_ctr(base, 0x6);	l = (r_str(base) & 0xf0) >> 4;	w_ctr(base, 0x5);	*buffer++ = (r_str(base) & 0xf0) | l;	w_ctr(base, 0x4);    }    return 1;			/* All went well - we hope! */}static int imm_byte_in(unsigned short base, char *buffer, int len){    int i;    /*     * The following is based on documented timing signals     */    w_ctr(base, 0x4);    for (i = len; i; i--) {	w_ctr(base, 0x26);	*buffer++ = r_dtr(base);	w_ctr(base, 0x25);    }    return 1;			/* All went well - we hope! */}static int imm_out(int host_no, char *buffer, int len){    int r;    unsigned short ppb = IMM_BASE(host_no);    r = imm_wait(host_no);    /*     * Make sure that:     * a) the SCSI bus is BUSY (device still listening)     * b) the device is listening     */    if ((r & 0x18) != 0x08) {	imm_fail(host_no, DID_ERROR);	printk("IMM: returned SCSI status %2x\n", r);	return 0;    }    switch (imm_hosts[host_no].mode) {    case IMM_EPP_32:    case IMM_EPP_16:    case IMM_EPP_8:	epp_reset(ppb);	w_ctr(ppb, 0x4);#ifdef CONFIG_SCSI_IZIP_EPP16	if (!(((long) buffer | len) & 0x01))	    outsw(ppb + 4, buffer, len >> 1);#else	if (!(((long) buffer | len) & 0x03))	    outsl(ppb + 4, buffer, len >> 2);#endif	else	    outsb(ppb + 4, buffer, len);	w_ctr(ppb, 0xc);	r = !(r_str(ppb) & 0x01);	w_ctr(ppb, 0xc);	ecp_sync(host_no);	break;    case IMM_NIBBLE:    case IMM_PS2:	/* 8 bit output, with a loop */	r = imm_byte_out(ppb, buffer, len);	break;    default:	printk("IMM: bug in imm_out()\n");	r = 0;    }    return r;}static int imm_in(int host_no, char *buffer, int len){    int r;    unsigned short ppb = IMM_BASE(host_no);    r = imm_wait(host_no);    /*     * Make sure that:     * a) the SCSI bus is BUSY (device still listening)     * b) the device is sending data     */    if ((r & 0x18) != 0x18) {	imm_fail(host_no, DID_ERROR);	return 0;    }    switch (imm_hosts[host_no].mode) {    case IMM_NIBBLE:	/* 4 bit input, with a loop */	r = imm_nibble_in(ppb, buffer, len);	w_ctr(ppb, 0xc);	break;    case IMM_PS2:	/* 8 bit input, with a loop */	r = imm_byte_in(ppb, buffer, len);	w_ctr(ppb, 0xc);	break;    case IMM_EPP_32:    case IMM_EPP_16:    case IMM_EPP_8:	epp_reset(ppb);	w_ctr(ppb, 0x24);#ifdef CONFIG_SCSI_IZIP_EPP16	if (!(((long) buffer | len) & 0x01))	    insw(ppb + 4, buffer, len >> 1);#else	if (!(((long) buffer | len) & 0x03))	    insl(ppb + 4, buffer, len >> 2);#endif	else	    insb(ppb + 4, buffer, len);	w_ctr(ppb, 0x2c);	r = !(r_str(ppb) & 0x01);	w_ctr(ppb, 0x2c);	ecp_sync(host_no);	break;    default:	printk("IMM: bug in imm_ins()\n");	r = 0;	break;    }    return r;}static int imm_cpp(unsigned short ppb, unsigned char b){    /*     * Comments on udelay values refer to the     * Command Packet Protocol (CPP) timing diagram.     */    unsigned char s1, s2, s3;    w_ctr(ppb, 0x0c);    udelay(2);			/* 1 usec - infinite */    w_dtr(ppb, 0xaa);    udelay(10);			/* 7 usec - infinite */    w_dtr(ppb, 0x55);    udelay(10);			/* 7 usec - infinite */    w_dtr(ppb, 0x00);    udelay(10);			/* 7 usec - infinite */    w_dtr(ppb, 0xff);    udelay(10);			/* 7 usec - infinite */    s1 = r_str(ppb) & 0xb8;    w_dtr(ppb, 0x87);    udelay(10);			/* 7 usec - infinite */    s2 = r_str(ppb) & 0xb8;    w_dtr(ppb, 0x78);    udelay(10);			/* 7 usec - infinite */    s3 = r_str(ppb) & 0x38;    /*     * Values for b are:     * 0000 00aa    Assign address aa to current device     * 0010 00aa    Select device aa in EPP Winbond mode     * 0010 10aa    Select device aa in EPP mode     * 0011 xxxx    Deselect all devices     * 0110 00aa    Test device aa     * 1101 00aa    Select device aa in ECP mode     * 1110 00aa    Select device aa in Compatible mode     */    w_dtr(ppb, b);    udelay(2);			/* 1 usec - infinite */    w_ctr(ppb, 0x0c);    udelay(10);			/* 7 usec - infinite */    w_ctr(ppb, 0x0d);    udelay(2);			/* 1 usec - infinite */    w_ctr(ppb, 0x0c);    udelay(10);			/* 7 usec - infinite */    w_dtr(ppb, 0xff);    udelay(10);			/* 7 usec - infinite */    /*     * The following table is electrical pin values.     * (BSY is inverted at the CTR register)     *     *       BSY  ACK  POut SEL  Fault     * S1    0    X    1    1    1     * S2    1    X    0    1    1     * S3    L    X    1    1    S     *     * L => Last device in chain     * S => Selected     *     * Observered values for S1,S2,S3 are:     * Disconnect => f8/58/78     * Connect    => f8/58/70     */    if ((s1 == 0xb8) && (s2 == 0x18) && (s3 == 0x30))	return 1;		/* Connected */    if ((s1 == 0xb8) && (s2 == 0x18) && (s3 == 0x38))	return 0;		/* Disconnected */    return -1;			/* No device present */}static inline int imm_connect(int host_no, int flag){    unsigned short ppb = IMM_BASE(host_no);    imm_cpp(ppb, 0xe0);		/* Select device 0 in compatible mode */    imm_cpp(ppb, 0x30);		/* Disconnect all devices */    if ((imm_hosts[host_no].mode == IMM_EPP_8) ||	(imm_hosts[host_no].mode == IMM_EPP_16) ||	(imm_hosts[host_no].mode == IMM_EPP_32))	return imm_cpp(ppb, 0x28);	/* Select device 0 in EPP mode */    return imm_cpp(ppb, 0xe0);	/* Select device 0 in compatible mode */}static void imm_disconnect(int host_no){    unsigned short ppb = IMM_BASE(host_no);    imm_cpp(ppb, 0x30);		/* Disconnect all devices */}static int imm_select(int host_no, int target){    int k;    unsigned short ppb = IMM_BASE(host_no);    /*     * Firstly we want to make sure there is nothing     * holding onto the SCSI bus.     */    w_ctr(ppb, 0xc);    k = IMM_SELECT_TMO;    do {	k--;    } while ((r_str(ppb) & 0x08) && (k));    if (!k)	return 0;    /*     * Now assert the SCSI ID (HOST and TARGET) on the data bus     */    w_ctr(ppb, 0x4);    w_dtr(ppb, 0x80 | (1 << target));    udelay(1);    /*     * Deassert SELIN first followed by STROBE     */    w_ctr(ppb, 0xc);    w_ctr(ppb, 0xd);    /*     * ACK should drop low while SELIN is deasserted.     * FAULT should drop low when the SCSI device latches the bus.     */    k = IMM_SELECT_TMO;    do {	k--;    }    while (!(r_str(ppb) & 0x08) && (k));    /*     * Place the interface back into a sane state (status mode)     */    w_ctr(ppb, 0xc);    return (k) ? 1 : 0;}static int imm_init(int host_no){    int retv;#if defined(CONFIG_PARPORT) || defined(CONFIG_PARPORT_MODULE)    if (imm_pb_claim(host_no))	while (imm_hosts[host_no].p_busy)	    schedule();		/* We can safe schedule here */#endif    retv = imm_connect(host_no, 0);    if (retv == 1) {	imm_reset_pulse(IMM_BASE(host_no));	udelay(1000);		/* Delay to allow devices to settle */	imm_disconnect(host_no);	udelay(1000);		/* Another delay to allow devices to settle */	retv = device_check(host_no);	imm_pb_release(host_no);	return retv;    }    imm_pb_release(host_no);    return 1;}static inline int imm_send_command(Scsi_Cmnd * cmd){    int host_no = cmd->host->unique_id;    int k;    /* NOTE: IMM uses byte pairs */    for (k = 0; k < cmd->cmd_len; k += 2)	if (!imm_out(host_no, &cmd->cmnd[k], 2))	    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 imm_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 = IMM_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 imm_wait.     */    w_ctr(ppb, 0x0c);    r = (r_str(ppb) & 0xb8);    /*     * while (device is not ready to send status byte)     *     loop;     */    while (r != (unsigned char) 0xb8) {	/*	 * If we have been running for more than a full timer tick	 * then take a rest.	 */	if (time_after(jiffies, start_jiffies + 1))	    return 0;	/*	 * FAIL if:	 * a) Drive status is screwy (!ready && !present)	 * b) Drive is requesting/sending more data than expected	 */	if (((r & 0x88) != 0x88) || (cmd->SCp.this_residual <= 0)) {	    imm_fail(host_no, DID_ERROR);	    return -1;		/* ERROR_RETURN */	}	/* determine if we should use burst I/O */	if (imm_hosts[host_no].rd == 0) {	    fast = (bulk && (cmd->SCp.this_residual >= IMM_BURST_SIZE)) ? IMM_BURST_SIZE : 2;	    status = imm_out(host_no, cmd->SCp.ptr, fast);	} else {	    fast = (bulk && (cmd->SCp.this_residual >= IMM_BURST_SIZE)) ? IMM_BURST_SIZE : 1;	    status = imm_in(host_no, cmd->SCp.ptr, fast);	}	cmd->SCp.ptr += fast;	cmd->SCp.this_residual -= fast;	if (!status) {	    imm_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;		/*		 * Make sure that we transfer even number of bytes		 * otherwise it makes imm_byte_out() messy.		 */		if (cmd->SCp.this_residual & 0x01)		    cmd->SCp.this_residual++;	    }	}	/* Now check to see if the drive is ready to comunicate */	w_ctr(ppb, 0x0c);	r = (r_str(ppb) & 0xb8);

⌨️ 快捷键说明

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