// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/acorn/scsi/eesox.c * * Copyright (C) 1997-2005 Russell King * * This driver is based on experimentation. Hence, it may have made * assumptions about the particular card that I have available, and * may not be reliable! * * Changelog: * 01-10-1997 RMK Created, READONLY version * 15-02-1998 RMK READ/WRITE version * added DMA support and hardware definitions * 14-03-1998 RMK Updated DMA support * Added terminator control * 15-04-1998 RMK Only do PIO if FAS216 will allow it. * 27-06-1998 RMK Changed asm/delay.h to linux/delay.h * 02-04-2000 RMK 0.0.3 Fixed NO_IRQ/NO_DMA problem, updated for new * error handling code.
*/ #include <linux/module.h> #include <linux/blkdev.h> #include <linux/kernel.h> #include <linux/string.h> #include <linux/ioport.h> #include <linux/proc_fs.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> #include <linux/dma-mapping.h> #include <linux/pgtable.h>
/* Prototype: fasdmatype_t eesoxscsi_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_t
eesoxscsi_dma_setup(struct Scsi_Host *host, struct scsi_pointer *SCp,
fasdmadir_t direction, fasdmatype_t min_type)
{ struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata; struct device *dev = scsi_get_device(host); int dmach = info->info.scsi.dma;
if (dmach != NO_DMA &&
(min_type == fasdma_real_all || SCp->this_residual >= 512)) { int bufs, map_dir, dma_dir;
disable_dma(dmach);
set_dma_sg(dmach, info->sg, bufs);
set_dma_mode(dmach, dma_dir);
enable_dma(dmach); return fasdma_real_all;
} /* * We don't do DMA, we only do slow PIO * * Some day, we will do Pseudo DMA
*/ return fasdma_pseudo;
}
staticvoid eesoxscsi_buffer_in(void *buf, int length, void __iomem *base)
{ constvoid __iomem *reg_fas = base + EESOX_FAS216_OFFSET; constvoid __iomem *reg_dmastat = base + EESOX_DMASTAT; constvoid __iomem *reg_dmadata = base + EESOX_DMADATA; registerconstunsignedlong mask = 0xffff;
do { unsignedint status;
/* * Interrupt request?
*/
status = readb(reg_fas + (REG_STAT << EESOX_FAS216_SHIFT)); if (status & STAT_INT) break;
/* * DMA request active?
*/
status = readb(reg_dmastat); if (!(status & EESOX_STAT_DMA)) continue;
/* * Get number of bytes in FIFO
*/
status = readb(reg_fas + (REG_CFIS << EESOX_FAS216_SHIFT)) & CFIS_CF; if (status > 16)
status = 16; if (status > length)
status = length;
/* * Align buffer.
*/ if (((u32)buf) & 2 && status >= 2) {
*(u16 *)buf = readl(reg_dmadata);
buf += 2;
status -= 2;
length -= 2;
}
if (status >= 2) {
*(u16 *)buf = readl(reg_dmadata);
buf += 2;
length -= 2;
}
} while (length);
}
staticvoid eesoxscsi_buffer_out(void *buf, int length, void __iomem *base)
{ constvoid __iomem *reg_fas = base + EESOX_FAS216_OFFSET; constvoid __iomem *reg_dmastat = base + EESOX_DMASTAT; void __iomem *reg_dmadata = base + EESOX_DMADATA;
do { unsignedint status;
/* * Interrupt request?
*/
status = readb(reg_fas + (REG_STAT << EESOX_FAS216_SHIFT)); if (status & STAT_INT) break;
/* * DMA request active?
*/
status = readb(reg_dmastat); if (!(status & EESOX_STAT_DMA)) continue;
/* * Get number of bytes in FIFO
*/
status = readb(reg_fas + (REG_CFIS << EESOX_FAS216_SHIFT)) & CFIS_CF; if (status > 16)
status = 16;
status = 16 - status; if (status > length)
status = length;
status &= ~1;
/* * Align buffer.
*/ if (((u32)buf) & 2 && status >= 2) {
writel(*(u16 *)buf << 16, reg_dmadata);
buf += 2;
status -= 2;
length -= 2;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.