/* * Either use the shared memory (if enabled on the board) or put the packet * out through the ASIC FIFO. */ static void el2_block_output(struct device *dev, int count, const unsigned char *buf, int start_page) { unsigned short int *wrd; int boguscount; /* timeout counter */ unsigned short word; /* temporary for better machine code */ if (ei_status.word16) /* Tx packets go into bank 0 on EL2/16 card */ outb(EGACFR_RSEL|EGACFR_TCM, E33G_GACFR); else outb(EGACFR_NORM, E33G_GACFR); if (dev->mem_start) { /* Shared memory transfer */ unsigned long dest_addr = dev->mem_start + ((start_page - ei_status.tx_start_page) << 8); memcpy_toio(dest_addr, buf, count); outb(EGACFR_NORM, E33G_GACFR); /* Back to bank1 in case on bank0 */ return; } /* * No shared memory, put the packet out the other way. * Set up then start the internal memory transfer to Tx Start Page */ word = (unsigned short)start_page; outb(word&0xFF, E33G_DMAAH); outb(word>>8, E33G_DMAAL); outb_p((ei_status.interface_num ? ECNTRL_AUI : ECNTRL_THIN ) | ECNTRL_OUTPUT | ECNTRL_START, E33G_CNTRL); /* * Here I am going to write data to the FIFO as quickly as possible. * Note that E33G_FIFOH is defined incorrectly. It is really * E33G_FIFOL, the lowest port address for both the byte and * word write. Variable 'count' is NOT checked. Caller must supply a * valid count. Note that I may write a harmless extra byte to the * 8390 if the byte-count was not even. */ wrd = (unsigned short int *) buf; count = (count + 1) >> 1; for(;;) { boguscount = 0x1000; while ((inb(E33G_STATUS) & ESTAT_DPRDY) == 0) { if(!boguscount--) { printk("%s: FIFO blocked in el2_block_output.\n", dev->name); el2_reset_8390(dev); goto blocked; } } if(count > WRD_COUNT) { outsw(E33G_FIFOH, wrd, WRD_COUNT); wrd += WRD_COUNT; count -= WRD_COUNT; } else { outsw(E33G_FIFOH, wrd, count); break; } } blocked: ; outb_p(ei_status.interface_num==0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL); return; }
static irqreturn_t eata_pio_int_handler(int irq, void *dev_id) { unsigned int eata_stat = 0xfffff; struct scsi_cmnd *cmd; hostdata *hd; struct eata_ccb *cp; unsigned long base; unsigned int x, z; struct Scsi_Host *sh; unsigned short zwickel = 0; unsigned char stat, odd; irqreturn_t ret = IRQ_NONE; for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->prev) { if (sh->irq != irq) continue; if (inb(sh->base + HA_RSTATUS) & HA_SBUSY) continue; int_counter++; ret = IRQ_HANDLED; hd = SD(sh); cp = &hd->ccb[0]; cmd = cp->cmd; base = cmd->device->host->base; do { stat = inb(base + HA_RSTATUS); if (stat & HA_SDRQ) { if (cp->DataIn) { z = 256; odd = 0; while ((cmd->SCp.Status) && ((z > 0) || (odd))) { if (odd) { *(cmd->SCp.ptr) = zwickel >> 8; IncStat(&cmd->SCp, 1); odd = 0; } x = min_t(unsigned int, z, cmd->SCp.this_residual / 2); insw(base + HA_RDATA, cmd->SCp.ptr, x); z -= x; IncStat(&cmd->SCp, 2 * x); if ((z > 0) && (cmd->SCp.this_residual == 1)) { zwickel = inw(base + HA_RDATA); *(cmd->SCp.ptr) = zwickel & 0xff; IncStat(&cmd->SCp, 1); z--; odd = 1; } } while (z > 0) { zwickel = inw(base + HA_RDATA); z--; } } else { /* cp->DataOut */ odd = 0; z = 256; while ((cmd->SCp.Status) && ((z > 0) || (odd))) { if (odd) { zwickel += *(cmd->SCp.ptr) << 8; IncStat(&cmd->SCp, 1); outw(zwickel, base + HA_RDATA); z--; odd = 0; } x = min_t(unsigned int, z, cmd->SCp.this_residual / 2); outsw(base + HA_RDATA, cmd->SCp.ptr, x); z -= x; IncStat(&cmd->SCp, 2 * x); if ((z > 0) && (cmd->SCp.this_residual == 1)) { zwickel = *(cmd->SCp.ptr); zwickel &= 0xff; IncStat(&cmd->SCp, 1); odd = 1; } } while (z > 0 || odd) { outw(zwickel, base + HA_RDATA); z--; odd = 0; } } } }
void os_outsw(void *port, HPT_U16 *buffer, HPT_U32 count) { outsw((unsigned)(HPT_UPTR)port, (void *)buffer, count); }
void x86_bus_space_io_write_multi_2(bus_space_handle_t h, bus_size_t o, const u_int16_t *ptr, bus_size_t cnt) { outsw(h + o, ptr, cnt); }
static void isicom_tx(unsigned long _data) { unsigned long flags, base; unsigned int retries; short count = (BOARD_COUNT-1), card; short txcount, wrd, residue, word_count, cnt; struct isi_port *port; struct tty_struct *tty; /* find next active board */ card = (prev_card + 1) & 0x0003; while (count-- > 0) { if (isi_card[card].status & BOARD_ACTIVE) break; card = (card + 1) & 0x0003; } if (!(isi_card[card].status & BOARD_ACTIVE)) goto sched_again; prev_card = card; count = isi_card[card].port_count; port = isi_card[card].ports; base = isi_card[card].base; spin_lock_irqsave(&isi_card[card].card_lock, flags); for (retries = 0; retries < 100; retries++) { if (inw(base + 0xe) & 0x1) break; udelay(2); } if (retries >= 100) goto unlock; tty = tty_port_tty_get(&port->port); if (tty == NULL) goto put_unlock; for (; count > 0; count--, port++) { /* port not active or tx disabled to force flow control */ if (!(port->port.flags & ASYNC_INITIALIZED) || !(port->status & ISI_TXOK)) continue; txcount = min_t(short, TX_SIZE, port->xmit_cnt); if (txcount <= 0 || tty->stopped || tty->hw_stopped) continue; if (!(inw(base + 0x02) & (1 << port->channel))) continue; pr_debug("txing %d bytes, port%d.\n", txcount, port->channel + 1); outw((port->channel << isi_card[card].shift_count) | txcount, base); residue = NO; wrd = 0; while (1) { cnt = min_t(int, txcount, (SERIAL_XMIT_SIZE - port->xmit_tail)); if (residue == YES) { residue = NO; if (cnt > 0) { wrd |= (port->port.xmit_buf[port->xmit_tail] << 8); port->xmit_tail = (port->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1); port->xmit_cnt--; txcount--; cnt--; outw(wrd, base); } else { outw(wrd, base); break; } } if (cnt <= 0) break; word_count = cnt >> 1; outsw(base, port->port.xmit_buf+port->xmit_tail, word_count); port->xmit_tail = (port->xmit_tail + (word_count << 1)) & (SERIAL_XMIT_SIZE - 1); txcount -= (word_count << 1); port->xmit_cnt -= (word_count << 1); if (cnt & 0x0001) { residue = YES; wrd = port->port.xmit_buf[port->xmit_tail]; port->xmit_tail = (port->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1); port->xmit_cnt--; txcount--; } } InterruptTheCard(base); if (port->xmit_cnt <= 0) port->status &= ~ISI_TXOK; if (port->xmit_cnt <= WAKEUP_CHARS) tty_wakeup(tty); } put_unlock: tty_kref_put(tty); unlock: spin_unlock_irqrestore(&isi_card[card].card_lock, flags); /* schedule another tx for hopefully in about 10ms */ sched_again: mod_timer(&tx, jiffies + msecs_to_jiffies(10)); }
static void t595_transmit( struct nic *nic, const char *d, /* Destination */ unsigned int t, /* Type */ unsigned int s, /* size */ const char *p) /* Packet */ { register int len; int pad; int status; #ifdef EDEBUG printf("{l=%d,t=%hX}",s+ETH_HLEN,t); #endif /* swap bytes of type */ t= htons(t); len=s+ETH_HLEN; /* actual length of packet */ pad = padmap[len & 3]; /* * The 3c595 automatically pads short packets to minimum ethernet length, * but we drop packets that are too large. Perhaps we should truncate * them instead? */ if (len + pad > ETH_FRAME_LEN) { return; } /* drop acknowledgements */ while(( status=inb(BASE + VX_W1_TX_STATUS) )& TXS_COMPLETE ) { if(status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) { outw(TX_RESET, BASE + VX_COMMAND); outw(TX_ENABLE, BASE + VX_COMMAND); } outb(0x0, BASE + VX_W1_TX_STATUS); } while (inw(BASE + VX_W1_FREE_TX) < len + pad + 4) { /* no room in FIFO */ } outw(len, BASE + VX_W1_TX_PIO_WR_1); outw(0x0, BASE + VX_W1_TX_PIO_WR_1); /* Second dword meaningless */ /* write packet */ outsw(BASE + VX_W1_TX_PIO_WR_1, d, ETH_ALEN/2); outsw(BASE + VX_W1_TX_PIO_WR_1, nic->node_addr, ETH_ALEN/2); outw(t, BASE + VX_W1_TX_PIO_WR_1); outsw(BASE + VX_W1_TX_PIO_WR_1, p, s / 2); if (s & 1) outb(*(p+s - 1), BASE + VX_W1_TX_PIO_WR_1); while (pad--) outb(0, BASE + VX_W1_TX_PIO_WR_1); /* Padding */ /* wait for Tx complete */ while((inw(BASE + VX_STATUS) & S_COMMAND_IN_PROGRESS) != 0) ; }
/* * The driver enables interrupts as much as possible. In order to do this, * (a) the device-interrupt is disabled before entering hd_request(), * and (b) the timeout-interrupt is disabled before the sti(). * * Interrupts are still masked (by default) whenever we are exchanging * data/cmds with a drive, because some drives seem to have very poor * tolerance for latency during I/O. The IDE driver has support to unmask * interrupts for non-broken hardware, so use that driver if required. */ static void hd_request(void) { unsigned int block, nsect, sec, track, head, cyl; struct hd_i_struct *disk; struct request *req; if (do_hd) return; repeat: del_timer(&device_timer); local_irq_enable(); req = CURRENT; if (!req) { do_hd = NULL; return; } if (reset) { local_irq_disable(); reset_hd(); return; } disk = req->rq_disk->private_data; block = req->sector; nsect = req->nr_sectors; if (block >= get_capacity(req->rq_disk) || ((block+nsect) > get_capacity(req->rq_disk))) { printk("%s: bad access: block=%d, count=%d\n", req->rq_disk->disk_name, block, nsect); end_request(req, 0); goto repeat; } if (disk->special_op) { if (do_special_op(disk, req)) goto repeat; return; } sec = block % disk->sect + 1; track = block / disk->sect; head = track % disk->head; cyl = track / disk->head; #ifdef DEBUG printk("%s: %sing: CHS=%d/%d/%d, sectors=%d, buffer=%p\n", req->rq_disk->disk_name, req_data_dir(req) == READ ? "read" : "writ", cyl, head, sec, nsect, req->buffer); #endif if (blk_fs_request(req)) { switch (rq_data_dir(req)) { case READ: hd_out(disk, nsect, sec, head, cyl, ATA_CMD_PIO_READ, &read_intr); if (reset) goto repeat; break; case WRITE: hd_out(disk, nsect, sec, head, cyl, ATA_CMD_PIO_WRITE, &write_intr); if (reset) goto repeat; if (wait_DRQ()) { bad_rw_intr(); goto repeat; } outsw(HD_DATA, req->buffer, 256); break; default: printk("unknown hd-command\n"); end_request(req, 0); break; } } }