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

📄 imm.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* imm.c   --  low level driver for the IOMEGA MatchMaker * parallel port SCSI host adapter. *  * (The IMM is the embedded controller in the ZIP Plus drive.) *  * Current Maintainer: David Campbell (Perth, Western Australia) *                     campbell@torque.net * * My unoffical company acronym list is 21 pages long: *      FLA:    Four letter acronym with built in facility for *              future expansion to five letters. */#include <linux/config.h>/* The following #define is to avoid a clash with hosts.c */#define IMM_CODE 1#define IMM_PROBE_SPP   0x0001#define IMM_PROBE_PS2   0x0002#define IMM_PROBE_ECR   0x0010#define IMM_PROBE_EPP17 0x0100#define IMM_PROBE_EPP19 0x0200void imm_reset_pulse(unsigned int base);static int device_check(int host_no);#include <linux/blk.h>#include <asm/io.h>#include <linux/parport.h>#include "sd.h"#include "hosts.h"typedef struct {    struct pardevice *dev;	/* Parport device entry         */    int base;			/* Actual port address          */    int base_hi;		/* Hi Base address for ECP-ISA chipset */    int mode;			/* Transfer mode                */    int host;			/* Host number (for proc)       */    Scsi_Cmnd *cur_cmd;		/* Current queued command       */    struct tq_struct imm_tq;	/* Polling interupt stuff       */    unsigned long jstart;	/* Jiffies at start             */    unsigned failed:1;		/* Failure flag                 */    unsigned dp:1;		/* Data phase present           */    unsigned rd:1;		/* Read data in data phase      */    unsigned p_busy:1;		/* Parport sharing busy flag    */} imm_struct;#define IMM_EMPTY \{	dev:		NULL,		\	base:		-1,		\	base_hi:	0,		\	mode:		IMM_AUTODETECT,	\	host:		-1,		\	cur_cmd:	NULL,		\	imm_tq:		{ routine: imm_interrupt },    \	jstart:		0,		\	failed:		0,		\	dp:		0,		\	rd:		0,		\	p_busy:		0		\}#include "imm.h"#define NO_HOSTS 4static imm_struct imm_hosts[NO_HOSTS] ={IMM_EMPTY, IMM_EMPTY, IMM_EMPTY, IMM_EMPTY};#define IMM_BASE(x)	imm_hosts[(x)].base#define IMM_BASE_HI(x)     imm_hosts[(x)].base_hiint parbus_base[NO_HOSTS] ={0x03bc, 0x0378, 0x0278, 0x0000};void imm_wakeup(void *ref){    imm_struct *imm_dev = (imm_struct *) ref;    if (!imm_dev->p_busy)	return;    if (parport_claim(imm_dev->dev)) {	printk("imm: bug in imm_wakeup\n");	return;    }    imm_dev->p_busy = 0;    imm_dev->base = imm_dev->dev->port->base;    if (imm_dev->cur_cmd)	imm_dev->cur_cmd->SCp.phase++;    return;}int imm_release(struct Scsi_Host *host){    int host_no = host->unique_id;    printk("Releasing imm%i\n", host_no);    parport_unregister_device(imm_hosts[host_no].dev);    return 0;}static int imm_pb_claim(int host_no){    if (parport_claim(imm_hosts[host_no].dev)) {	imm_hosts[host_no].p_busy = 1;	return 1;    }    if (imm_hosts[host_no].cur_cmd)	imm_hosts[host_no].cur_cmd->SCp.phase++;    return 0;}#define imm_pb_release(x) parport_release(imm_hosts[(x)].dev)/*************************************************************************** *                   Parallel port probing routines                        * ***************************************************************************/static Scsi_Host_Template driver_template = IMM;#include  "scsi_module.c"int imm_detect(Scsi_Host_Template * host){    struct Scsi_Host *hreg;    int ports;    int i, nhosts, try_again;    struct parport *pb;    /*     * unlock to allow the lowlevel parport driver to probe     * the irqs     */    spin_unlock_irq(&io_request_lock);    pb = parport_enumerate();    printk("imm: Version %s\n", IMM_VERSION);    nhosts = 0;    try_again = 0;    if (!pb) {	printk("imm: parport reports no devices.\n");	spin_lock_irq(&io_request_lock);	return 0;    }  retry_entry:    for (i = 0; pb; i++, pb = pb->next) {	int modes, ppb;	imm_hosts[i].dev =	    parport_register_device(pb, "imm", NULL, imm_wakeup,				    NULL, 0, (void *) &imm_hosts[i]);	if (!imm_hosts[i].dev)	    continue;	/* Claim the bus so it remembers what we do to the control	 * registers. [ CTR and ECP ]	 */	if (imm_pb_claim(i)) {	    unsigned long now = jiffies;	    while (imm_hosts[i].p_busy) {		schedule();	/* We are safe to schedule here */		if (time_after(jiffies, now + 3 * HZ)) {		    printk(KERN_ERR "imm%d: failed to claim parport because a "		      "pardevice is owning the port for too longtime!\n",			   i);		    spin_lock_irq(&io_request_lock);		    return 0;		}	    }	}	ppb = IMM_BASE(i) = imm_hosts[i].dev->port->base;	IMM_BASE_HI(i) = imm_hosts[i].dev->port->base_hi;	w_ctr(ppb, 0x0c);	modes = imm_hosts[i].dev->port->modes;	/* Mode detection works up the chain of speed	 * This avoids a nasty if-then-else-if-... tree	 */	imm_hosts[i].mode = IMM_NIBBLE;	if (modes & PARPORT_MODE_TRISTATE)	    imm_hosts[i].mode = IMM_PS2;	/* Done configuration */	imm_pb_release(i);	if (imm_init(i)) {	    parport_unregister_device(imm_hosts[i].dev);	    continue;	}	/* now the glue ... */	switch (imm_hosts[i].mode) {	case IMM_NIBBLE:	    ports = 3;	    break;	case IMM_PS2:	    ports = 3;	    break;	case IMM_EPP_8:	case IMM_EPP_16:	case IMM_EPP_32:	    ports = 8;	    break;	default:		/* Never gets here */	    continue;	}	host->can_queue = IMM_CAN_QUEUE;	host->sg_tablesize = imm_sg;	hreg = scsi_register(host, 0);	if(hreg == NULL)		continue;	hreg->io_port = pb->base;	hreg->n_io_port = ports;	hreg->dma_channel = -1;	hreg->unique_id = i;	imm_hosts[i].host = hreg->host_no;	nhosts++;    }    if (nhosts == 0) {	if (try_again == 1) {	    spin_lock_irq(&io_request_lock);	    return 0;	}	try_again = 1;	goto retry_entry;    } else {	spin_lock_irq (&io_request_lock);	return 1;		/* return number of hosts detected */    }}/* This is to give the imm driver a way to modify the timings (and other * parameters) by writing to the /proc/scsi/imm/0 file. * Very simple method really... (To simple, no error checking :( ) * Reason: Kernel hackers HATE having to unload and reload modules for * testing... * Also gives a method to use a script to obtain optimum timings (TODO) */static inline int imm_proc_write(int hostno, char *buffer, int length){    unsigned long x;    if ((length > 5) && (strncmp(buffer, "mode=", 5) == 0)) {	x = simple_strtoul(buffer + 5, NULL, 0);	imm_hosts[hostno].mode = x;	return length;    }    printk("imm /proc: invalid variable\n");    return (-EINVAL);}int imm_proc_info(char *buffer, char **start, off_t offset,		  int length, int hostno, int inout){    int i;    int len = 0;    for (i = 0; i < 4; i++)	if (imm_hosts[i].host == hostno)	    break;    if (inout)	return imm_proc_write(i, buffer, length);    len += sprintf(buffer + len, "Version : %s\n", IMM_VERSION);    len += sprintf(buffer + len, "Parport : %s\n", imm_hosts[i].dev->port->name);    len += sprintf(buffer + len, "Mode    : %s\n", IMM_MODE_STRING[imm_hosts[i].mode]);    /* Request for beyond end of buffer */    if (offset > len)	return 0;    *start = buffer + offset;    len -= offset;    if (len > length)	len = length;    return len;}#if IMM_DEBUG > 0#define imm_fail(x,y) printk("imm: imm_fail(%i) from %s at line %d\n",\	   y, __FUNCTION__, __LINE__); imm_fail_func(x,y);static inline void imm_fail_func(int host_no, int error_code)#elsestatic inline void imm_fail(int host_no, int error_code)#endif{    /* If we fail a device then we trash status / message bytes */    if (imm_hosts[host_no].cur_cmd) {	imm_hosts[host_no].cur_cmd->result = error_code << 16;	imm_hosts[host_no].failed = 1;    }}/* * Wait for the high bit to be set. *  * In principle, this could be tied to an interrupt, but the adapter * doesn't appear to be designed to support interrupts.  We spin on * the 0x80 ready bit.  */static unsigned char imm_wait(int host_no){    int k;    unsigned short ppb = IMM_BASE(host_no);    unsigned char r;    w_ctr(ppb, 0x0c);    k = IMM_SPIN_TMO;    do {	r = r_str(ppb);	k--;	udelay(1);    }    while (!(r & 0x80) && (k));    /*     * STR register (LPT base+1) to SCSI mapping:     *     * STR      imm     imm     * ===================================     * 0x80     S_REQ   S_REQ     * 0x40     !S_BSY  (????)     * 0x20     !S_CD   !S_CD     * 0x10     !S_IO   !S_IO     * 0x08     (????)  !S_BSY     *     * imm      imm     meaning     * ==================================     * 0xf0     0xb8    Bit mask     * 0xc0     0x88    ZIP wants more data     * 0xd0     0x98    ZIP wants to send more data     * 0xe0     0xa8    ZIP is expecting SCSI command data     * 0xf0     0xb8    end of transfer, ZIP is sending status     */    w_ctr(ppb, 0x04);    if (k)	return (r & 0xb8);    /* Counter expired - Time out occurred */    imm_fail(host_no, DID_TIME_OUT);    printk("imm timeout in imm_wait\n");    return 0;			/* command timed out */}static int imm_negotiate(imm_struct * tmp){    /*     * The following is supposedly the IEEE 1284-1994 negotiate     * sequence. I have yet to obtain a copy of the above standard     * so this is a bit of a guess...     *     * A fair chunk of this is based on the Linux parport implementation     * of IEEE 1284.     *     * Return 0 if data available     *        1 if no data available     */    unsigned short base = tmp->base;    unsigned char a, mode;    switch (tmp->mode) {    case IMM_NIBBLE:	mode = 0x00;	break;    case IMM_PS2:	mode = 0x01;	break;    default:	return 0;    }    w_ctr(base, 0x04);    udelay(5);    w_dtr(base, mode);    udelay(100);    w_ctr(base, 0x06);    udelay(5);    a = (r_str(base) & 0x20) ? 0 : 1;    udelay(5);    w_ctr(base, 0x07);    udelay(5);    w_ctr(base, 0x06);    if (a) {	printk("IMM: IEEE1284 negotiate indicates no data available.\n");	imm_fail(tmp->host, DID_ERROR);    }    return a;}/*  * Clear EPP timeout bit.  */static inline void epp_reset(unsigned short ppb){    int i;    i = r_str(ppb);    w_str(ppb, i);    w_str(ppb, i & 0xfe);}/*  * Wait for empty ECP fifo (if we are in ECP fifo mode only) */static inline void ecp_sync(unsigned short hostno){    int i, ppb_hi=IMM_BASE_HI(hostno);    if (ppb_hi == 0) return;    if ((r_ecr(ppb_hi) & 0xe0) == 0x60) { /* mode 011 == ECP fifo mode */        for (i = 0; i < 100; i++) {	    if (r_ecr(ppb_hi) & 0x01)	        return;	    udelay(5);	}        printk("imm: ECP sync failed as data still present in FIFO.\n");    }}

⌨️ 快捷键说明

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