📄 cumana_2.c
字号:
/* * linux/drivers/acorn/scsi/cumana_2.c * * Copyright (C) 1997-2000 Russell King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Changelog: * 30-08-1997 RMK 0.0.0 Created, READONLY version. * 22-01-1998 RMK 0.0.1 Updated to 2.1.80. * 15-04-1998 RMK 0.0.1 Only do PIO if FAS216 will allow it. * 02-05-1998 RMK 0.0.2 Updated & added DMA support. * 27-06-1998 RMK Changed asm/delay.h to linux/delay.h * 18-08-1998 RMK 0.0.3 Fixed synchronous transfer depth. * 02-04-2000 RMK 0.0.4 Updated for new error handling code. */#include <linux/module.h>#include <linux/blk.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/ioport.h>#include <linux/sched.h>#include <linux/proc_fs.h>#include <linux/unistd.h>#include <linux/stat.h>#include <linux/delay.h>#include <linux/pci.h>#include <linux/init.h>#include <asm/dma.h>#include <asm/ecard.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/pgtable.h>#include "../../scsi/sd.h"#include "../../scsi/hosts.h"#include "fas216.h"#include <scsi/scsicam.h>/* Configuration */#define CUMANASCSI2_XTALFREQ 40#define CUMANASCSI2_ASYNC_PERIOD 200#define CUMANASCSI2_SYNC_DEPTH 7/* * List of devices that the driver will recognise */#define CUMANASCSI2_LIST { MANU_CUMANA, PROD_CUMANA_SCSI_2 }#define CUMANASCSI2_STATUS (0)#define STATUS_INT (1 << 0)#define STATUS_DRQ (1 << 1)#define STATUS_LATCHED (1 << 3)#define CUMANASCSI2_ALATCH (5)#define ALATCH_ENA_INT (3)#define ALATCH_DIS_INT (2)#define ALATCH_ENA_TERM (5)#define ALATCH_DIS_TERM (4)#define ALATCH_ENA_BIT32 (11)#define ALATCH_DIS_BIT32 (10)#define ALATCH_ENA_DMA (13)#define ALATCH_DIS_DMA (12)#define ALATCH_DMA_OUT (15)#define ALATCH_DMA_IN (14)#define CUMANASCSI2_PSEUDODMA (0x80)#define CUMANASCSI2_FAS216_OFFSET (0xc0)#define CUMANASCSI2_FAS216_SHIFT 0/* * Version */#define VER_MAJOR 0#define VER_MINOR 0#define VER_PATCH 4static struct expansion_card *ecs[MAX_ECARDS];/* * Use term=0,1,0,0,0 to turn terminators on/off */static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 };#define NR_SG 256typedef struct { FAS216_Info info; /* other info... */ unsigned int status; /* card status register */ unsigned int alatch; /* Control register */ unsigned int terms; /* Terminator state */ unsigned int dmaarea; /* Pseudo DMA area */ struct scatterlist sg[NR_SG]; /* Scatter DMA list */} CumanaScsi2_Info;#define CSTATUS_IRQ (1 << 0)#define CSTATUS_DRQ (1 << 1)/* Prototype: void cumanascsi_2_irqenable(ec, irqnr) * Purpose : Enable interrupts on Cumana SCSI 2 card * Params : ec - expansion card structure * : irqnr - interrupt number */static voidcumanascsi_2_irqenable(struct expansion_card *ec, int irqnr){ unsigned int port = (unsigned int)ec->irq_data; outb(ALATCH_ENA_INT, port);}/* Prototype: void cumanascsi_2_irqdisable(ec, irqnr) * Purpose : Disable interrupts on Cumana SCSI 2 card * Params : ec - expansion card structure * : irqnr - interrupt number */static voidcumanascsi_2_irqdisable(struct expansion_card *ec, int irqnr){ unsigned int port = (unsigned int)ec->irq_data; outb(ALATCH_DIS_INT, port);}static const expansioncard_ops_t cumanascsi_2_ops = { cumanascsi_2_irqenable, cumanascsi_2_irqdisable, NULL, NULL, NULL, NULL};/* Prototype: void cumanascsi_2_terminator_ctl(host, on_off) * Purpose : Turn the Cumana SCSI 2 terminators on or off * Params : host - card to turn on/off * : on_off - !0 to turn on, 0 to turn off */static voidcumanascsi_2_terminator_ctl(struct Scsi_Host *host, int on_off){ CumanaScsi2_Info *info = (CumanaScsi2_Info *)host->hostdata; if (on_off) { info->terms = 1; outb (ALATCH_ENA_TERM, info->alatch); } else { info->terms = 0; outb (ALATCH_DIS_TERM, info->alatch); }}/* Prototype: void cumanascsi_2_intr(irq, *dev_id, *regs) * Purpose : handle interrupts from Cumana SCSI 2 card * Params : irq - interrupt number * dev_id - user-defined (Scsi_Host structure) * regs - processor registers at interrupt */static voidcumanascsi_2_intr(int irq, void *dev_id, struct pt_regs *regs){ struct Scsi_Host *host = (struct Scsi_Host *)dev_id; fas216_intr(host);}/* Prototype: fasdmatype_t cumanascsi_2_dma_setup(host, SCpnt, direction, min_type) * Purpose : initialises DMA/PIO * Params : host - host * SCpnt - command * direction - DMA on to/off of card * min_type - minimum DMA support that we must have for this transfer * Returns : type of transfer to be performed */static fasdmatype_tcumanascsi_2_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp, fasdmadir_t direction, fasdmatype_t min_type){ CumanaScsi2_Info *info = (CumanaScsi2_Info *)host->hostdata; int dmach = host->dma_channel; outb(ALATCH_DIS_DMA, info->alatch); if (dmach != NO_DMA && (min_type == fasdma_real_all || SCp->this_residual >= 512)) { int bufs = SCp->buffers_residual; int pci_dir, dma_dir, alatch_dir; if (bufs) memcpy(info->sg + 1, SCp->buffer + 1, sizeof(struct scatterlist) * bufs); info->sg[0].address = SCp->ptr; info->sg[0].page = NULL; info->sg[0].length = SCp->this_residual; if (direction == DMA_OUT) pci_dir = PCI_DMA_TODEVICE, dma_dir = DMA_MODE_WRITE, alatch_dir = ALATCH_DMA_OUT; else pci_dir = PCI_DMA_FROMDEVICE, dma_dir = DMA_MODE_READ, alatch_dir = ALATCH_DMA_IN; pci_map_sg(NULL, info->sg, bufs + 1, pci_dir); disable_dma(dmach); set_dma_sg(dmach, info->sg, bufs + 1); outb(alatch_dir, info->alatch); set_dma_mode(dmach, dma_dir); enable_dma(dmach); outb(ALATCH_ENA_DMA, info->alatch); outb(ALATCH_DIS_BIT32, info->alatch); return fasdma_real_all; } /* * If we're not doing DMA, * we'll do pseudo DMA */ return fasdma_pio;}/* * Prototype: void cumanascsi_2_dma_pseudo(host, SCpnt, direction, transfer) * Purpose : handles pseudo DMA * Params : host - host * SCpnt - command * direction - DMA on to/off of card * transfer - minimum number of bytes we expect to transfer */static voidcumanascsi_2_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp, fasdmadir_t direction, int transfer){ CumanaScsi2_Info *info = (CumanaScsi2_Info *)host->hostdata; unsigned int length; unsigned char *addr; length = SCp->this_residual; addr = SCp->ptr; if (direction == DMA_OUT)#if 0 while (length > 1) { unsigned long word; unsigned int status = inb(info->status); if (status & STATUS_INT) goto end; if (!(status & STATUS_DRQ)) continue; word = *addr | *(addr + 1) << 8; outw (info->dmaarea); addr += 2; length -= 2; }#else printk ("PSEUDO_OUT???\n");#endif else { if (transfer && (transfer & 255)) { while (length >= 256) { unsigned int status = inb(info->status); if (status & STATUS_INT) goto end; if (!(status & STATUS_DRQ)) continue; insw(info->dmaarea, addr, 256 >> 1); addr += 256; length -= 256; } } while (length > 0) { unsigned long word; unsigned int status = inb(info->status); if (status & STATUS_INT) goto end; if (!(status & STATUS_DRQ)) continue; word = inw (info->dmaarea); *addr++ = word; if (--length > 0) { *addr++ = word >> 8; length --; } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -