## diffname pc/etherwavelan.c 1998/0625
## diff -e /dev/null /n/emeliedump/1998/0625/sys/src/brazil/pc/etherwavelan.c
0a
/*
*/
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
#include "etherif.h"
static int
reset(Ether* ether)
{
int slot;
if(ether->irq == 0)
ether->irq = 10;
if(ether->port == 0)
ether->port = 0x240;
if((slot = pcmspecial(ether->type, ether)) < 0)
return -1;
print("WaveLAN: slot %d, port 0x%uX irq %d\n", slot, ether->port, ether->irq);
return -1;
}
void
etherwavelanlink(void)
{
addethercard("WaveLAN", reset);
}
.
## diffname pc/etherwavelan.c 1999/0623
## diff -e /n/emeliedump/1998/0625/sys/src/brazil/pc/etherwavelan.c /n/emeliedump/1999/0623/sys/src/brazil/pc/etherwavelan.c
29c
print("#l%dWaveLAN: slot %d, port 0x%ulX irq %ld type %s\n", ether->ctlrno, slot, ether->port, ether->irq, ether->type);
/* create a receive buffer */
ctlr->rbp = rbpalloc(allocb);
/* map a piece of memory (Attribute memory) first */
m = pcmmap(slot, 0, 0x5000, 1);
if (m==0) {
return 1;
}
/* read ethernet address from the card and put in ether->ea */
pp = (char*)(KZERO|m->isa) + 0x0E00 + 2*0x10;
for(p = 0; p<sizeof(ether->ea); p++)
ether->ea[p] = (uchar) (*(pp+2*p))&0xFF;
// print("wavelan: dump of PSA memory\n");
// pp = (char *) (KZERO|m->isa) + 0x0E00;
// for(p=0; p<64; p++) {
// print("%2uX ", (*(pp+2*p)&0xFF));
// if (p%16==15) print("\n");
// }
/* read nwid from PSA into ctlr->nwid */
pp = (char*)(KZERO|m->isa) + 0x0E00;
ctlr->nwid[0] = *(pp+2*0x23);
ctlr->nwid[1] = *(pp+2*0x24);
/* access the configuration option register */
pp = (char *)(KZERO|m->isa) + 0x4000;
*pp = *pp | COR_SW_RESET;
delay(5);
*pp = (COR_LEVEL_IRQ | COR_CONFIG);
delay(5);
hacr_write_slow(port, HACR_RESET);
outb(HACR(port), HACR_DEFAULT);
if(inb(HASR(port)) & HASR_NO_CLK) {
print("wavelan: modem not connected\n");
return 1;
}
wavelan_mmc_init(ether, port); /* initialize modem */
outb(LCCR(port), OP0_RESET); /* reset the LAN controller */
delay(10);
if (wavelan_hw_config(port, ether) == FALSE)
return 1;
if (wavelan_diag(ether, port) == 1)
return 1;
wavelan_ru_start(ether, port);
print("wavelan: init done; receiver started\n");
iunlock(&ctlr->wlock);
ctlr->port = port;
ether->port = port;
ether->mbps = 2; /* 2 Mpbs */
ether->attach = attach;
ether->transmit = transmit;
ether->interrupt = interrupt;
ether->ifstat = ifstat;
ether->promiscuous = promiscuous;
ether->multicast = multicast;
ether->arg = ether;
return 0; /* reset succeeded */
.
27d
25a
}
.
24c
if((slot = pcmspecial(ether->type, ether)) < 0) {
print("could not find the PCMCIA WaveLAN card.\n");
.
22c
ether->port = 0x280;
port = ether->port;
.
19,20c
ctlr = ether->ctlr = malloc(sizeof(Ctlr));
ilock(&ctlr->wlock);
.
17c
int slot, p;
int port;
char *pp;
Ctlr *ctlr;
PCMmap *m;
.
13a
static void wavelan_receive(Ether *ether);
static int txstart(Ether *ether);
static void
hacr_write_slow(int base, uchar hacr)
{
outb(HACR(base), hacr);
/* delay might only be needed sometimes */
delay(1);
} /* hacr_write_slow */
static long
ifstat(Ether* ether, void* a, long n, ulong offset)
{
Ctlr *ctlr;
int len;
char *p;
ctlr = ether->ctlr;
p = malloc(READSTR);
len = snprint(p, READSTR, "interrupts: %lud\n", ctlr->interrupts);
len += snprint(p+len, READSTR-len, "upinterrupts: %lud\n", ctlr->upinterrupts);
len += snprint(p+len, READSTR-len, "dninterrupts: %lud\n", ctlr->dninterrupts);
len += snprint(p+len, READSTR-len, "int_errors: %lud\n", ctlr->int_errors);
len += snprint(p+len, READSTR-len, "read_errors: %lud\n", ctlr->read_errors);
len += snprint(p+len, READSTR-len, "out_packets: %lud\n", ctlr->out_packets);
len += snprint(p+len, READSTR-len, "tx_too_long: %lud\n", ctlr->tx_too_long);
len += snprint(p+len, READSTR-len, "tx_DMA_underrun: %lud\n", ctlr->tx_DMA_underrun);
len += snprint(p+len, READSTR-len, "tx_carrier_error: %lud\n", ctlr->tx_carrier_error);
len += snprint(p+len, READSTR-len, "tx_congestion: %lud\n", ctlr->tx_congestion);
len += snprint(p+len, READSTR-len, "tx_heart_beat: %lud\n", ctlr->tx_heart_beat);
len += snprint(p+len, READSTR-len, "rx_overflow: %lud\n", ctlr->rx_overflow);
len += snprint(p+len, READSTR-len, "rx_overrun: %lud\n", ctlr->rx_overrun);
len += snprint(p+len, READSTR-len, "rx_crc_error: %lud\n", ctlr->rx_crc);
len += snprint(p+len, READSTR-len, "rx_no_sfd: %lud\n", ctlr->rx_no_sfd);
len += snprint(p+len, READSTR-len, "rx_dropped: %lud\n", ctlr->rx_dropped);
len += snprint(p+len, READSTR-len, "tx_packets: %lud\n", ctlr->tx_packets);
len += snprint(p+len, READSTR-len, "rx_packets: %lud\n", ctlr->rx_packets);
snprint(p+len, READSTR-len, "in_packets: %lud\n", ctlr->in_packets);
n = readstr(offset, a, n, p);
free(p);
return n;
}
static void
attach(Ether* ether)
{
Ctlr *ctlr;
ctlr = ether->ctlr;
ilock(&ctlr->wlock);
if(ctlr->attached){
iunlock(&ctlr->wlock);
return;
}
ctlr->attached = 1;
iunlock(&ctlr->wlock);
}
static void
interrupt_handler(Ether *ether, uchar status)
{
Ctlr *ctlr;
int status0;
int tx_status;
int base;
ctlr = ether->ctlr;
base = ctlr->port;
status0 = status;
/* Return if no actual interrupt from i82593 */
if(!(status0 & SR0_INTERRUPT)) {
print("Wavelan: Interrupt from dead card\n");
return;
}
ctlr->status = status0; /* Save current status (for commands) */
if (status0 & SR0_RECEPTION) {
if((status0 & SR0_EVENT_MASK) == SR0_STOP_REG_HIT) {
print("wavelan: receive buffer overflow\n");
ctlr->rx_overflow++;
outb(LCCR(base), CR0_INT_ACK | OP0_NOP); /* Acknowledge the interrupt */
return;
}
wavelan_receive(ether);
if (status0 & SR0_EXECUTION)
print("wavelan_cs: interrupt is both rx and tx, status0 = %x\n",
status0);
outb(LCCR(base), CR0_INT_ACK | OP0_NOP); /* Acknowledge the interrupt */
return;
}
if (!(status0 & SR0_EXECUTION)) {
print("wavelan_cs: interrupt is neither rx or tx, status0 = %x\n",
status0);
outb(LCCR(base), CR0_INT_ACK | OP0_NOP); /* Acknowledge the interrupt */
return;
}
/* interrupt due to configure_done or IA_setup_done */
if ((status0 & SR0_EVENT_MASK) == SR0_CONFIGURE_DONE ||
(status0 & SR0_EVENT_MASK) == SR0_IA_SETUP_DONE) {
outb(LCCR(base), CR0_INT_ACK | OP0_NOP); /* Acknowledge the interrupt */
return;
}
/* so a transmit interrupt is remaining */
if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE ||
(status0 & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE) {
tx_status = inb(LCSR(base));
tx_status |= (inb(LCSR(base)) << 8);
if (!(tx_status & TX_OK)) {
if (tx_status & TX_FRTL) {
print("wavelan_cs: frame too long\n");
ctlr->tx_too_long++;
}
if (tx_status & TX_UND_RUN) {
/* print("wavelan_csd: DMA underrun\n"); */
ctlr->tx_DMA_underrun++;
}
if (tx_status & TX_LOST_CTS) {
/* print("wavelan: no CTS\n"); */
ctlr->tx_carrier_error++;
}
if (tx_status & TX_LOST_CRS) {
/* print("wavelan: lost CRS\n"); */
ctlr->tx_carrier_error++;
}
if (tx_status & TX_DEFER) {
/* print("wavelan: channel jammed\n"); */
ctlr->tx_congestion++;
}
if (tx_status & TX_COLL) {
if (tx_status & TX_MAX_COL) {
/* print("wavelan_cs: channel congestion\n"); */
ctlr->tx_congestion++;
}
}
if (tx_status & TX_HRT_BEAT) {
/* print("wavelan_cs: heart beat\n"); */
ctlr->tx_heart_beat++;
}
}
ctlr->tx_packets++;
ctlr->txbusy = 0;
outb(LCCR(base), CR0_INT_ACK | OP0_NOP); /* Acknowledge the interrupt */
txstart(ether); /* start new transfer if any */
return;
}
print("wavelan: unknown interrupt\n");
outb(LCCR(base), CR0_INT_ACK | OP0_NOP); /* Acknowledge the interrupt */
}
static Block*
rbpalloc(Block* (*f)(int))
{
Block *bp;
ulong addr;
/*
* The receive buffers must be on a 32-byte
* boundary for EISA busmastering.
*/
if(bp = f(ROUNDUP(sizeof(Etherpkt), 4) + 31)){
addr = (ulong)bp->base;
addr = ROUNDUP(addr, 32);
bp->rp = (uchar*)addr;
}
return bp;
}
static int
wavelan_cmd(Ether *ether, int base, char *str, int cmd, int result)
{
int status;
unsigned long spin;
/* Spin until the chip finishes executing its current command (if any) */
do {
outb(LCCR(base), OP0_NOP | CR0_STATUS_3);
status = inb(LCSR(base));
} while ((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE);
outb(LCCR(base), cmd); /* Send the command */
if(result == SR0_NO_RESULT) { /* Return immediately, if the command
doesn't return a result */
return(TRUE);
}
/* Busy wait while the LAN controller executes the command.
* Interrupts had better be enabled (or it will be a long wait).
* (We could enable just the WaveLAN's IRQ..., we do not bother this is only for setup commands)
*/
for(spin = 0; (spin < 10000000); spin++)
;
outb(LCCR(base), CR0_STATUS_0 | OP0_NOP);
status = inb(LCSR(base));
if(status & SR0_INTERRUPT){
if (((status & SR0_EVENT_MASK) == SR0_CONFIGURE_DONE) ||
((status & SR0_EVENT_MASK) == SR0_IA_SETUP_DONE) ||
((status & SR0_EVENT_MASK) == SR0_EXECUTION_ABORTED) ||
((status & SR0_EVENT_MASK) == SR0_DIAGNOSE_PASSED))
outb(LCCR(base), CR0_INT_ACK | OP0_NOP); /* acknowledge interrupt */
else
interrupt_handler(ether, status);
} else {
print("wavelan_cmd: %s timeout, status0 = 0x%uX\n", str, status);
outb(OP0_ABORT, LCCR(base));
spin = 0;
while(spin++ < 250) /* wait for the command to execute */
delay(1);
return 0;
}
if((status & SR0_EVENT_MASK) != result){
print("wavelan_cmd: %s failed, status0 = 0x%uX\n", str, status);
return 0;
}
return 1;
} /* wavelan_cmd */
static uchar
mmc_in(int base, uchar o)
{
while (inb(HASR(base)) & HASR_MMI_BUSY) ; /* Wait for MMC to go idle */
outb(MMR(base), o << 1); /* Set the read address */
outb(MMD(base), 0); /* Required dummy write */
while (inb(HASR(base)) & HASR_MMI_BUSY) ; /* Wait for MMC to go idle */
return((uchar) (inb(MMD(base))));
}
static int
read_ringbuf(Ether *ether, int addr, uchar *buf, int len)
{ Ctlr *ctlr;
int base;
int ring_ptr = addr;
int chunk_len;
uchar *buf_ptr = buf;
ctlr = ether->ctlr;
base = ctlr->port;
/* If buf is NULL, just increment the ring buffer pointer */
if (buf == 0)
return((ring_ptr - RX_BASE + len) % RX_SIZE + RX_BASE);
while (len > 0) {
/* Position the Program I/O Register at the ring buffer pointer */
outb(PIORL(base), ring_ptr & 0xff);
outb(PIORH(base), ((ring_ptr >> 8) & PIORH_MASK));
/* First, determine how much we can read without wrapping around the
ring buffer */
if ((addr + len) < (RX_BASE + RX_SIZE))
chunk_len = len;
else
chunk_len = RX_BASE + RX_SIZE - addr;
insb(PIOP(base), buf_ptr, chunk_len);
buf_ptr += chunk_len;
len -= chunk_len;
ring_ptr = (ring_ptr - RX_BASE + chunk_len) % RX_SIZE + RX_BASE;
}
return(ring_ptr);
} /* read_ringbuf */
static void
wavelan_hardware_send_packet(Ether *ether, void *buf, short length)
{
Ctlr *ctlr;
int base;
register ushort xmtdata_base = TX_BASE;
ctlr = ether->ctlr;
base = ctlr->port;
outb(PIORL(base), xmtdata_base & 0xff);
outb(PIORH(base), ((xmtdata_base >> 8) & PIORH_MASK) | PIORH_SEL_TX);
outb(PIOP(base), length & 0xff); /* lsb */
outb(PIOP(base), length >> 8); /* msb */
outsb(PIOP(base), buf, length); /* Send the data */
outb(PIOP(base), OP0_NOP); /* Indicate end of transmit chain */
/* Reset the transmit DMA pointer */
hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET);
outb(HACR(base), HACR_DEFAULT);
/* Send the transmit command */
wavelan_cmd(ether, base, "wavelan_hardware_send_packet(): transmit", OP0_TRANSMIT,
SR0_NO_RESULT);
} /* wavelan_hardware_send_packet */
static int
txstart(Ether *ether)
{
Ctlr *ctlr;
Block *bp;
int base, length;
int status;
ctlr = ether->ctlr;
base = ctlr->port;
for(;;) {
if(ctlr->txbp){
bp = ctlr->txbp;
ctlr->txbp = 0;
}
else{
bp = qget(ether->oq);
if(bp == nil)
break;
}
length = BLEN(bp);
length = (ETH_ZLEN < length) ? length : ETH_ZLEN;
outb(LCCR(base), OP0_NOP | CR0_STATUS_3);
status = inb(LCSR(base));
if ((status & SR3_EXEC_STATE_MASK) == SR3_EXEC_IDLE) {
wavelan_hardware_send_packet(ether, bp->rp, length);
freeb(bp);
ctlr->out_packets++;
}
else{
ctlr->txbp = bp;
if(ctlr->txbusy == 0){
ctlr->txbusy = 1;
}
break;
}
}
return 0;
} /* wavelan txstart */
static int
wavelan_start_of_frame(Ether *ether, int rfp, int wrap)
{
Ctlr *ctlr;
int base;
int rp, len;
ctlr = ether->ctlr;
base = ctlr->port;
rp = (rfp - 5 + RX_SIZE) % RX_SIZE;
outb(PIORL(base), rp & 0xff);
outb(PIORH(base), ((rp >> 8) & PIORH_MASK));
len = inb(PIOP(base));
len |= inb(PIOP(base)) << 8;
if (len > 1600) { /* Sanity check on size */
print("wavelan_cs: Received frame too large, rfp %d rp %d len 0x%x\n",
rfp, rp, len);
return -1;
}
if(len < 7){
print("wavelan_start_of_frame: Received null frame, rfp %d len 0x%x\n", rfp, len);
return(-1);
}
/* Wrap around buffer */
if(len > ((wrap - (rfp - len) + RX_SIZE) % RX_SIZE)) { /* magic formula ! */
print("wavelan_start_of_frame: wrap around buffer, wrap %d rfp %d len 0x%x\n",wrap, rfp, len);
return(-1);
}
return((rp - len + RX_SIZE) % RX_SIZE);
} /* wv_start_of_frame */
static void wavelan_read(Ether *ether, int fd_p, int sksize)
{
Ctlr *ctlr;
Block *bp;
uchar stats[3];
ctlr = ether->ctlr;
ctlr->rx_packets++;
if ((bp = rbpalloc(allocb)) == 0){
print("wavelan: could not rbpalloc(%d).\n", sksize);
ctlr->rx_dropped++;
return;
} else {
fd_p = read_ringbuf(ether, fd_p, ctlr->rbp->rp, sksize);
ctlr->rbp->wp = ctlr->rbp->rp + sksize;
/* read signal level, silence level and signal quality bytes */
read_ringbuf(ether, (fd_p+4) % RX_SIZE+RX_BASE, stats, 3);
/*
* Hand the packet to the Network Module
*/
etheriq(ether, ctlr->rbp, 1);
ctlr->in_packets++;
ctlr->rbp = bp;
return;
}
} /* wavelan_read */
static void
wavelan_receive(Ether *ether)
{
Ctlr *ctlr;
int base;
int newrfp, rp, len, f_start, status;
int i593_rfp, stat_ptr;
uchar c[4];
ctlr = ether->ctlr;
base = ctlr->port;
/* Get the new receive frame pointer from the i82593 chip */
outb(LCCR(base), CR0_STATUS_2 | OP0_NOP);
i593_rfp = inb(LCSR(base));
i593_rfp |= inb(LCSR(base)) << 8;
i593_rfp %= RX_SIZE;
/* Get the new receive frame pointer from the WaveLAN card.
* It is 3 bytes more than the increment of the i82593 receive
* frame pointer, for each packet. This is because it includes the
* 3 roaming bytes added by the mmc.
*/
newrfp = inb(RPLL(base));
newrfp |= inb(RPLH(base)) << 8;
newrfp %= RX_SIZE;
// print("wavelan_cs: i593_rfp %d stop %d newrfp %d ctlr->rfp %d\n",
// i593_rfp, ctlr->stop, newrfp, ctlr->rfp);
if (newrfp == ctlr->rfp)
print("wavelan_cs: odd RFPs: i593_rfp %d stop %d newrfp %d ctlr->rfp %d\n",
i593_rfp, ctlr->stop, newrfp, ctlr->rfp);
while(newrfp != ctlr->rfp) {
rp = newrfp;
/* Find the first frame by skipping backwards over the frames */
while (((f_start = wavelan_start_of_frame(ether,rp, newrfp)) != ctlr->rfp) && (f_start != -1))
rp = f_start;
if(f_start == -1){
print("wavelan_cs: cannot find start of frame ");
print(" i593_rfp %d stop %d newrfp %d ctlr->rfp %d\n",
i593_rfp, ctlr->stop, newrfp, ctlr->rfp);
ctlr->rfp = rp;
continue;
}
stat_ptr = (rp - 7 + RX_SIZE) % RX_SIZE;
read_ringbuf(ether, stat_ptr, c, 4);
status = c[0] | (c[1] << 8);
len = c[2] | (c[3] << 8);
if(!(status & RX_RCV_OK)) {
if(status & RX_NO_SFD) ctlr->rx_no_sfd++;
if(status & RX_CRC_ERR) ctlr->rx_crc++;
if(status & RX_OVRRUN) ctlr->rx_overrun++;
print("wavelan_cs: packet not received ok, status = 0x%x\n", status);
} else wavelan_read(ether, f_start, len - 2);
ctlr->rfp = rp; /* one packet processed, skip it */
}
/*
* Update the frame stop register, but set it to less than
* the full 8K to allow space for 3 bytes of signal strength
* per packet.
*/
ctlr->stop = (i593_rfp + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE;
outb(LCCR(base), OP0_SWIT_TO_PORT_1 | CR0_CHNL);
outb(LCCR(base), CR1_STOP_REG_UPDATE | (ctlr->stop >> RX_SIZE_SHIFT));
outb(LCCR(base), OP1_SWIT_TO_PORT_0);
} /* wavelan_receive */
static void
interrupt(Ureg*, void* arg)
{
Ether *ether;
Ctlr *ctlr;
int base;
ether = arg;
ctlr = ether->ctlr;
base = ctlr->port;
ilock(&ctlr->wlock);
ctlr->interrupts++;
outb(LCCR(base), CR0_STATUS_0 | OP0_NOP);
interrupt_handler(ether, inb(LCSR(base)));
iunlock(&ctlr->wlock);
}; /* wavelan interrupt */
static void
promiscuous()
{
;
};
static void
multicast()
{
;
};
static void
mmc_read(int base, uchar o, uchar *b, int n)
{
while (n-- > 0) {
while (inb(HASR(base)) & HASR_MMI_BUSY) ; /* Wait for MMC to go idle */
outb(MMR(base), o << 1); /* Set the read address */
o++;
outb(MMD(base), 0); /* Required dummy write */
while (inb(HASR(base)) & HASR_MMI_BUSY) ; /* Wait for MMC to go idle */
*b++ = (uchar)(inb(MMD(base))); /* Now do the actual read */
}
} /* mmc_read */
static void
fee_wait(int base, int del, int numb)
{ int count = 0;
while ((count++ < numb) && (mmc_in(base, MMC_EECTRL) & MMR_FEE_STATUS_BUSY))
delay(del);
if (count==numb) print("Wavelan: fee wait timed out\n");
}
static void
mmc_write_b(int base, uchar o, uchar b)
{
while (inb(HASR(base)) & HASR_MMI_BUSY) ; /* Wait for MMC to go idle */
outb(MMR(base), (uchar)((o << 1) | MMR_MMI_WR));
outb(MMD(base), (uchar)(b));
} /* mmc_write_b */
static void
mmc_write(int base, uchar o, uchar *b, int n)
{
o += n;
b += n;
while (n-- > 0 )
mmc_write_b(base, --o, *(--b));
} /* mmc_write */
static void wavelan_mmc_init(Ether *ether, int port)
{
Ctlr *ctlr;
mmw_t m;
ctlr = ether->ctlr;
memset(&m, 0x00, sizeof(m));
/*
* Set default modem control parameters.
* See NCR document 407-0024326 Rev. A.
*/
m.mmw_jabber_enable = 0x01;
m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN;
m.mmw_ifs = 0x20;
m.mmw_mod_delay = 0x04;
m.mmw_jam_time = 0x38;
m.mmw_encr_enable = 0;
m.mmw_des_io_invert = 0;
m.mmw_freeze = 0;
m.mmw_decay_prm = 0;
m.mmw_decay_updat_prm = 0;
m.mmw_loopt_sel = MMW_LOOPT_SEL_UNDEFINED;
m.mmw_thr_pre_set = 0x04; /* PCMCIA */
m.mmw_quality_thr = 0x03;
m.mmw_netw_id_l = ctlr->nwid[1]; /* use nwid of PSA memory */
m.mmw_netw_id_h = ctlr->nwid[0];
mmc_write(port, 0, (uchar *)&m, 37); /* size of mmw_t == 37 */
/* Start the modem's receive unit on version 2.00 */
/* 2.4 Gz: half-card ver */
/* 2.4 Gz */
/* 2.4 Gz: position ch # */
mmc_write_b(port, MMC_EEADDR, 0x0f); /* 2.4 Gz: named ch, wc=16 */
mmc_write_b(port, MMC_EECTRL,MMC_EECTRL_DWLD | /* 2.4 Gz: Download Synths */
MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */
fee_wait(port, 10, 100); /* 2.4 Gz: wait for download */
/* 2.4 Gz */
mmc_write_b(port, MMC_EEADDR,0x61); /* 2.4 Gz: default pwr, wc=2 */
mmc_write_b(port, MMC_EECTRL,MMC_EECTRL_DWLD | /* 2.4 Gz: Download Xmit Pwr */
MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */
fee_wait(port, 10, 100); /* 2.4 Gz: wait for download */
} /* wavelan_mmc_init */
int wavelan_diag(Ether *ether, int port)
{
if (wavelan_cmd(ether, port, "wavelan_diag(): diagnose", OP0_DIAGNOSE,
SR0_DIAGNOSE_PASSED)){
return 0;
}
print("wavelan_cs: i82593 Self Test failed!\n");
return 1;
} /* wavelan_diag */
int wavelan_hw_config(int base, Ether *ether)
{
struct i82593_conf_block cfblk;
memset(&cfblk, 0x00, sizeof(struct i82593_conf_block));
cfblk.d6mod = FALSE; /* Run in i82593 advanced mode */
cfblk.fifo_limit = 6; /* = 48 bytes rx and tx fifo thresholds */
cfblk.forgnesi = FALSE; /* 0=82C501, 1=AMD7992B compatibility */
cfblk.fifo_32 = 0;
cfblk.throttle_enb = TRUE;
cfblk.contin = TRUE; /* enable continuous mode */
cfblk.cntrxint = FALSE; /* enable continuous mode receive interrupts */
cfblk.addr_len = WAVELAN_ADDR_SIZE;
cfblk.acloc = TRUE; /* Disable source addr insertion by i82593 */
cfblk.preamb_len = 2; /* 7 byte preamble */
cfblk.loopback = FALSE;
cfblk.lin_prio = 0; /* conform to 802.3 backoff algoritm */
cfblk.exp_prio = 0; /* conform to 802.3 backoff algoritm */
cfblk.bof_met = 0; /* conform to 802.3 backoff algoritm */
cfblk.ifrm_spc = 6; /* 96 bit times interframe spacing */
cfblk.slottim_low = 0x10 & 0x7; /* 512 bit times slot time */
cfblk.slottim_hi = 0x10 >> 3;
cfblk.max_retr = 15;
cfblk.prmisc = FALSE; /* Promiscuous mode ?? */
cfblk.bc_dis = FALSE; /* Enable broadcast reception */
cfblk.crs_1 = TRUE; /* Transmit without carrier sense */
cfblk.nocrc_ins = FALSE; /* i82593 generates CRC */
cfblk.crc_1632 = FALSE; /* 32-bit Autodin-II CRC */
cfblk.crs_cdt = FALSE; /* CD not to be interpreted as CS */
cfblk.cs_filter = 0; /* CS is recognized immediately */
cfblk.crs_src = FALSE; /* External carrier sense */
cfblk.cd_filter = 0; /* CD is recognized immediately */
cfblk.min_fr_len = 64 >> 2; /* Minimum frame length 64 bytes */
cfblk.lng_typ = FALSE; /* Length field > 1500 = type field */
cfblk.lng_fld = TRUE; /* Disable 802.3 length field check */
cfblk.rxcrc_xf = TRUE; /* Don't transfer CRC to memory */
cfblk.artx = TRUE; /* Disable automatic retransmission */
cfblk.sarec = TRUE; /* Disable source addr trig of CD */
cfblk.tx_jabber = TRUE; /* Disable jabber jam sequence */
cfblk.hash_1 = FALSE; /* Use bits 0-5 in mc address hash */
cfblk.lbpkpol = TRUE; /* Loopback pin active high */
cfblk.fdx = FALSE; /* Disable full duplex operation */
cfblk.dummy_6 = 0x3f; /* all ones */
cfblk.mult_ia = FALSE; /* No multiple individual addresses */
cfblk.dis_bof = FALSE; /* Disable the backoff algorithm ?! */
cfblk.dummy_1 = TRUE; /* set to 1 */
cfblk.tx_ifs_retrig = 3; /* Hmm... Disabled */
cfblk.mc_all = FALSE; /* No multicast all mode */
cfblk.rcv_mon = 0; /* Monitor mode disabled */
cfblk.frag_acpt = TRUE;/* Do not accept fragments */
cfblk.tstrttrs = FALSE; /* No start transmission threshold */
cfblk.fretx = TRUE; /* FIFO automatic retransmission */
cfblk.syncrqs = TRUE; /* Synchronous DRQ deassertion... */
cfblk.sttlen = TRUE; /* 6 byte status registers */
cfblk.rx_eop = TRUE; /* Signal EOP on packet reception */
cfblk.tx_eop = TRUE; /* Signal EOP on packet transmission */
cfblk.rbuf_size = RX_SIZE>>11; /* Set receive buffer size */
cfblk.rcvstop = TRUE; /* Enable Receive Stop Register */
outb(PIORL(base), (TX_BASE & 0xff));
outb(PIORH(base), (((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX));
outb(PIOP(base), (sizeof(struct i82593_conf_block) & 0xff)); /* lsb */
outb(PIOP(base), (sizeof(struct i82593_conf_block) >> 8)); /* msb */
outsb(PIOP(base), ((char *) &cfblk), sizeof(struct i82593_conf_block));
/* reset transmit DMA pointer */
hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET);
outb(HACR(base), HACR_DEFAULT);
if(!wavelan_cmd(ether, base, "wavelan_hw_config(): configure", OP0_CONFIGURE,
SR0_CONFIGURE_DONE))
return(FALSE);
/* Initialize adapter's ethernet MAC address */
outb(PIORL(base), (TX_BASE & 0xff));
outb(PIORH(base), (((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX));
outb(PIOP(base), WAVELAN_ADDR_SIZE); /* byte count lsb */
outb(PIOP(base), 0); /* byte count msb */
outsb(PIOP(base), ðer->ea[0], WAVELAN_ADDR_SIZE);
/* reset transmit DMA pointer */
hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET);
outb(HACR(base), HACR_DEFAULT);
if(!wavelan_cmd(ether, base, "wavelan_hw_config(): ia-setup", OP0_IA_SETUP, SR0_IA_SETUP_DONE))
return(FALSE);
return(TRUE);
} /* wavelan_hw_config */
static void
wavelan_graceful_shutdown(Ether *ether, int base)
{
int status;
/* First, send the LAN controller a stop receive command */
wavelan_cmd(ether, base, "wavelan_graceful_shutdown(): stop-rcv", OP0_STOP_RCV,
SR0_NO_RESULT);
/* Then, spin until the receive unit goes idle */
do {
outb(LCCR(base), (OP0_NOP | CR0_STATUS_3));
status = inb(LCSR(base));
} while((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE);
/* Now, spin until the chip finishes executing its current command */
do {
outb(LCCR(base), (OP0_NOP | CR0_STATUS_3));
status = inb(LCSR(base));
} while ((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE);
} /* wavelan_graceful_shutdown */
static void
wavelan_ru_start(Ether *ether, int base)
{
Ctlr *ctlr;
ctlr = ether->ctlr;
/*
* We need to start from a quiescent state. To do so, we could check
* if the card is already running, but instead we just try to shut
* it down. First, we disable reception (in case it was already enabled).
*/
wavelan_graceful_shutdown(ether, base);
/* Now we know that no command is being executed. */
/* Set the receive frame pointer and stop pointer */
ctlr->rfp = 0;
outb(LCCR(base), OP0_SWIT_TO_PORT_1 | CR0_CHNL);
/* Reset ring management. This sets the receive frame pointer to 1 */
outb(LCCR(base), OP1_RESET_RING_MNGMT);
ctlr->stop = (0 + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE;
outb(LCCR(base), CR1_STOP_REG_UPDATE | (ctlr->stop >> RX_SIZE_SHIFT));
outb(LCCR(base), OP1_INT_ENABLE);
outb(LCCR(base), OP1_SWIT_TO_PORT_0);
/* Reset receive DMA pointer */
outb(HACR(base), HACR_PWR_STAT | HACR_RX_DMA_RESET);
delay(100);
outb(HACR(base), HACR_PWR_STAT);
delay(100);
/* Receive DMA on channel 1 */
wavelan_cmd(ether, base, "wavelan_ru_start(): rcv-enable",
(CR0_CHNL | OP0_RCV_ENABLE), SR0_NO_RESULT);
} /* wavelan_ru_start */
static void
transmit(Ether* ether)
{
Ctlr *ctlr;
ctlr = ether->ctlr;
ilock(&ctlr->wlock);
txstart(ether);
iunlock(&ctlr->wlock);
}
.
12a
#include "etherwavelan.h"
.
11d
2a
.
1a
* Port for WaveLAN I PCMCIA cards running on 2.4 GHz
* important: only works for WaveLAN I and PCMCIA 2.4 GHz cards
* Based on Linux driver by Anthony D. Joseph MIT a.o.
* We have not added the frequency, encryption and NWID selection stuff, this
* can be done with the WaveLAN provided DOS programs: instconf.exe, setconf.exe, wfreqsel.exe, etc.
* Gerard Smit 07/22/98
.
## diffname pc/etherwavelan.c 1999/0714
## diff -e /n/emeliedump/1999/0623/sys/src/brazil/pc/etherwavelan.c /n/emeliedump/1999/0714/sys/src/brazil/pc/etherwavelan.c
859a
}
.
858c
if (wavelan_diag(ether, port) == 1){
iofree(port);
.
856a
}
.
855c
if (wavelan_hw_config(port, ether) == FALSE){
iofree(port);
.
845a
iofree(port);
.
815a
iofree(port);
.
806a
if(ioalloc(port, 0x20, 0, "wavelan") < 0){
print("wavelan: port %d in use\n", port);
return -1;
}
.
## diffname pc/etherwavelan.c 2001/0118
## diff -e /n/emeliedump/1999/0714/sys/src/brazil/pc/etherwavelan.c /n/emeliedump/2001/0118/sys/src/9/pc/etherwavelan.c
894c
addethercard("wavelan", reset);
.
888c
DEBUG("#l%d: irq %ld port %lx type %s",
ether->ctlrno, ether->irq, ether->port, ether->type);
DEBUG(" %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX\n",
ether->ea[0], ether->ea[1], ether->ea[2],
ether->ea[3], ether->ea[4], ether->ea[5]);
iunlock(&ctlr->Lock);
return 0;
abort:
iunlock(&ctlr->Lock);
free(ctlr);
ether->ctlr = nil;
return -1;
.
883c
ether->ctl = ctl;
.
881a
ether->transmit = transmit;
.
880d
876,878c
ltv.type = WTyp_Mac;
ltv.len = 4;
if (w_inltv(ctlr, <v)){
print("#l%d: unable to read mac addr\n",
ether->ctlrno);
goto abort;
}
memmove(ether->ea, ltv.addr, Eaddrlen);
DEBUG("#l%d: %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX\n",
ether->ctlrno,
ether->ea[0], ether->ea[1], ether->ea[2],
ether->ea[3], ether->ea[4], ether->ea[5]);
ctlr->chan = ltv_ins(ctlr, WTyp_Chan);
ctlr->ptype = WDfltPType;
ctlr->apdensity = WDfltApDens;
ctlr->rtsthres = WDfltRtsThres;
ctlr->txrate = WDfltTxRate;
ctlr->maxlen = WMaxLen;
ctlr->pmena = 0;
ctlr->pmwait= 100;
// link to ether
ether->ctlr = ctlr;
ether->mbps = 10;
.
874c
w_intdis(ctlr);
if (w_cmd(ctlr,WCmdIni,0)){
print("#l%d: init failed\n", ether->ctlrno);
goto abort;
}
w_intdis(ctlr);
ltv_outs(ctlr, WTyp_Tick, 8);
.
872c
if (ioalloc(ether->port,WIOLen,0,"wavelan")<0){
print("#l%d: port 0x%lx in use\n",
ether->ctlrno, ether->port);
goto abort;
}
.
870c
DEBUG("#l%d: port=0x%lx irq=%ld\n",
ether->ctlrno, ether->port, ether->irq);
*ctlr->netname = *ctlr->wantname = *ctlr->nodename = 0;
for (i=0; i < ether->nopt; i++){
if (strncmp(ether->opt[i],"ssid=",4) == 0)
strncpy(ctlr->netname,ðer->opt[i][4],WNameLen);
if (strncmp(ether->opt[i],"net=",4) == 0)
strncpy(ctlr->wantname,ðer->opt[i][4],WNameLen);
if (strncmp(ether->opt[i],"node=",5) == 0)
strncpy(ctlr->nodename,ðer->opt[i][5],WNameLen);
}
ctlr->netname[WNameLen-1] = 0;
ctlr->wantname[WNameLen-1] = 0;
ctlr->nodename[WNameLen-1] =0;
.
866,868c
ether->arg = ctlr = (Ctlr*)emalloc(sizeof(Ctlr));
ilock(&ctlr->Lock);
if (ether->port==0)
ether->port=WDfltIOB;
ctlr->iob = ether->port;
if (ether->irq==0)
ether->irq=WDfltIRQ;
if ((ctlr->slot = pcmspecial("WaveLAN/IEEE", ether))<0){
DEBUG("no wavelan found\n");
goto abort;
.
861,863c
static void
interrupt(Ureg* ,void* arg)
{
Ether* ether = (Ether*) arg;
Ctlr* ctlr = (Ctlr*) ether->ctlr;
if (ctlr == 0)
return;
ilock(&ctlr->Lock);
ctlr->nints++;
w_intr(ether);
iunlock(&ctlr->Lock);
}
static int
reset(Ether* ether)
{
Ctlr* ctlr;
Wltv ltv;
int i;
if (ether->ctlr){
print("#l%d: only one card supported\n", ether->ctlrno);
return -1;
.
858,859d
856d
850,854c
if (ctlr == nil)
error("card not found");
if (ctlr->attached == 0)
error("card not attached");
ilock(&ctlr->Lock);
ltv_outs(ctlr, WTyp_Prom, (on?1:0));
iunlock(&ctlr->Lock);
}
.
847,848c
static void
promiscuous(void* arg, int on)
{
Ether* ether = (Ether*)arg;
Ctlr* ctlr = ether->ctlr;
.
835,845c
ilock(&ctlr->Lock);
ctlr->ntxrq++;
w_txstart(ether,0);
iunlock(&ctlr->Lock);
}
.
828,833c
if (ctlr == 0)
return;
.
817,826c
static void
transmit(Ether* ether)
{
Ctlr* ctlr = ether->ctlr;
.
814,815c
return n;
}
.
812c
iunlock(&ctlr->Lock);
poperror();
free(cb);
.
810a
else if(strcmp(cb->f[0], "ptype") == 0){
i = atoi(cb->f[1]);
if (i < 1 || i > 3 )
error("invalid wavelan port type");
ctlr->ptype = i;
}
else
error(Ebadctl);
if(ctlr->txbusy)
w_txdone(ctlr, WTxErrEv|1); // retry later.
w_enable(ether);
.
807,809c
if(strcmp(cb->f[0], "ssid") == 0)
strncpy(ctlr->netname, cb->f[1], WNameLen);
else if(strcmp(cb->f[0], "net") == 0)
strncpy(ctlr->wantname, cb->f[1], WNameLen);
else if(strcmp(cb->f[0], "node") == 0)
strncpy(ctlr->nodename, cb->f[1], WNameLen);
else if(strcmp(cb->f[0], "chan") == 0){
i = atoi(cb->f[1]);
if (i < 1 || i > 16 )
error("invalid wavelan channel");
ctlr->chan = i;
.
802,804c
ilock(&ctlr->Lock);
if(waserror()){
iunlock(&ctlr->Lock);
free(cb);
nexterror();
.
798,800c
cb = parsecmd(buf, n);
if(cb->nf < 2)
error(Ebadctl);
.
795,796c
if((ctlr = ether->ctlr) == nil)
error(Enonexist);
if(ctlr->attached == 0)
error(Eshutdown);
.
793c
Cmdbuf *cb;
.
789,791c
int i;
char *p;
.
786,787c
while(*p != 0 && *p != ' ' && *p != '\t' && *p != '\n')
p++;
*p = 0;
}
#define min(a,b) (((a)<(b))?(a):(b))
static long
ctl(Ether* ether, void* buf, long n)
.
784a
static void
termtoken(char *tok)
{
char *p = tok;
.
780,782c
n = strlen(token);
if(strncmp(p, token, n))
return 0;
p += n;
if(*p == 0)
return p;
if(*p != ' ' && *p != '\t' && *p != '\n')
return 0;
while(*p == ' ' || *p == '\t' || *p == '\n')
p++;
return p;
.
777,778c
int n;
.
772,775c
/* from ../port/netif.c
* BUG?: make me a library function.
*/
static char*
matchtoken(char *p, char *token)
.
768,770c
l+= snprint(p+l, READSTR-l, "ntxuframes: %lud\n",
ctlr->ntxuframes);
l+= snprint(p+l, READSTR-l, "ntxmframes: %lud\n",
ctlr->ntxmframes);
l+= snprint(p+l, READSTR-l, "ntxfrags: %lud\n",
ctlr->ntxfrags);
l+= snprint(p+l, READSTR-l, "ntxubytes: %lud\n",
ctlr->ntxubytes);
l+= snprint(p+l, READSTR-l, "ntxmbytes: %lud\n",
ctlr->ntxmbytes);
l+= snprint(p+l, READSTR-l, "ntxdeferred: %lud\n",
ctlr->ntxdeferred);
l+= snprint(p+l, READSTR-l, "ntxsretries: %lud\n",
ctlr->ntxsretries);
l+= snprint(p+l, READSTR-l, "ntxmultiretries: %lud\n",
ctlr->ntxmultiretries);
l+= snprint(p+l, READSTR-l, "ntxretrylimit: %lud\n",
ctlr->ntxretrylimit);
l+= snprint(p+l, READSTR-l, "ntxdiscards: %lud\n",
ctlr->ntxdiscards);
l+= snprint(p+l, READSTR-l, "nrxuframes: %lud\n",
ctlr->nrxuframes);
l+= snprint(p+l, READSTR-l, "nrxmframes: %lud\n",
ctlr->nrxmframes);
l+= snprint(p+l, READSTR-l, "nrxfrags: %lud\n",
ctlr->nrxfrags);
l+= snprint(p+l, READSTR-l, "nrxubytes: %lud\n",
ctlr->nrxubytes);
l+= snprint(p+l, READSTR-l, "nrxmbytes: %lud\n",
ctlr->nrxmbytes);
l+= snprint(p+l, READSTR-l, "nrxfcserr: %lud\n",
ctlr->nrxfcserr);
l+= snprint(p+l, READSTR-l, "nrxdropnobuf: %lud\n",
ctlr->nrxdropnobuf);
l+= snprint(p+l, READSTR-l, "nrxdropnosa: %lud\n",
ctlr->nrxdropnosa);
l+= snprint(p+l, READSTR-l, "nrxcantdecrypt: %lud\n",
ctlr->nrxcantdecrypt);
l+= snprint(p+l, READSTR-l, "nrxmsgfrag: %lud\n",
ctlr->nrxmsgfrag);
snprint(p+l, READSTR-l, "nrxmsgbadfrag: %lud\n",
ctlr->nrxmsgbadfrag);
n = readstr(offset, a, n, p);
free(p);
return n;
}
.
762,766c
l+= snprint(p+l, READSTR-l, "SSID name: %s\n",
ltv_inname(ctlr, WTyp_NetName));
l+= snprint(p+l, READSTR-l, "Net name: %s\n",
ltv_inname(ctlr, WTyp_WantName));
l+= snprint(p+l, READSTR-l, "Node name: %s\n",
ltv_inname(ctlr, WTyp_NodeName));
iunlock(&ctlr->Lock);
.
755,760c
// real card stats
ilock(&ctlr->Lock);
l+= snprint(p+l, READSTR-l, "\nCard stats: \n");
l+= snprint(p+l, READSTR-l, "Status: %ux\n",
csr_ins(ctlr, WR_Sts));
l+= snprint(p+l, READSTR-l, "Event status: %ux\n",
csr_ins(ctlr, WR_EvSts));
l+= snprint(p+l, READSTR-l, "Port type: %d\n",
ltv_ins(ctlr, WTyp_Ptype));
l+= snprint(p+l, READSTR-l, "Transmit rate: %d\n",
ltv_ins(ctlr, WTyp_TxRate));
l+= snprint(p+l, READSTR-l, "Channel: %d\n",
ltv_ins(ctlr, WTyp_Chan));
l+= snprint(p+l, READSTR-l, "AP density: %d\n",
ltv_ins(ctlr, WTyp_ApDens));
l+= snprint(p+l, READSTR-l, "Promiscuous mode: %d\n",
ltv_ins(ctlr, WTyp_Prom));
.
751,753c
if (n == 0 || ctlr == 0){
return 0;
}
p = malloc(READSTR);
l = snprint(p, READSTR, "Interrupts: %lud\n",
ctlr->nints);
l+= snprint(p+l, READSTR-l, "TxPackets: %lud\n",
ctlr->ntx);
l+= snprint(p+l, READSTR-l, "RxPackets: %lud\n",
ctlr->nrx);
l+= snprint(p+l, READSTR-l, "TxErrors: %lud\n",
ctlr->ntxerr);
l+= snprint(p+l, READSTR-l, "RxErrors: %lud\n",
ctlr->nrxerr);
l+= snprint(p+l, READSTR-l, "TxRequests: %lud\n",
ctlr->ntxrq);
l+= snprint(p+l, READSTR-l, "AllocEvs: %lud\n",
ctlr->nalloc);
l+= snprint(p+l, READSTR-l, "InfoEvs: %lud\n",
ctlr->ninfo);
l+= snprint(p+l, READSTR-l, "InfoDrop: %lud\n",
ctlr->nidrop);
l+= snprint(p+l, READSTR-l, "WatchDogs: %lud\n",
ctlr->nwatchdogs);
if (ctlr->attached)
l+= snprint(p+l, READSTR-l, "Card attached");
else
l+= snprint(p+l, READSTR-l, "Card not attached");
if (ctlr->txbusy)
l+= snprint(p+l, READSTR-l, ", tx busy\n");
else
l+= snprint(p+l, READSTR-l, "\n");
.
749c
static long
ifstat(Ether* ether, void* a, long n, ulong offset)
{
Ctlr* ctlr = (Ctlr*) ether->ctlr;
char* p;
int l;
.
747c
snprint(name, NAMELEN, "#l%dtimer", ether->ctlrno);
ctlr = (Ctlr*) ether->ctlr;
if (ctlr->attached == 0){
ilock(&ctlr->Lock);
rc = w_enable(ether);
iunlock(&ctlr->Lock);
if(rc == 0){
ctlr->attached = 1;
kproc(name, w_timer, ether);
} else
print("#l%d: enable failed\n",ether->ctlrno);
}
}
.
741,745c
if (ether->ctlr == 0)
return;
.
738,739c
Ctlr* ctlr;
char name[NAMELEN];
int rc;
.
734,736c
static void
attach(Ether* ether)
.
716,732c
// BUG: to be added.
}
.
699,714c
static void
multicast(void*, uchar*, int)
.
692,697d
686,690d
629,684c
void *r=malloc(size);
if (!r)
error(Enomem);
memset(r,0,size);
return r;
}
.
627c
static void*
emalloc(ulong size)
.
625a
if (tick % 10 == 0) {
if (ctlr->txtmout && --ctlr->txtmout == 0){
ctlr->nwatchdogs++;
w_txdone(ctlr, WTxErrEv|1); // 1: keep it busy
if (w_enable(ether))
DEBUG("wavelan: wdog enable failed\n");
if (ctlr->txbusy)
w_txstart(ether,1);
}
if (tick % 120 == 0)
if (ctlr->txbusy == 0)
w_cmd(ctlr, WCmdAskStats, WTyp_Stats);
}
iunlock(&ctlr->Lock);
}
pexit("terminated",0);
}
.
624a
if (csr_ins(ctlr, WR_EvSts)&WEvs)
w_intr(ether);
.
615,623c
// Seems that the card gets frames BUT does
// not send the interrupt; this is a problem because
// I suspect it runs out of receive buffers and
// stops receiving until a transmit watchdog
// reenables the card.
// The problem is serious because it leads to
// poor rtts.
// This can be seen clearly by commenting out
// the next if and doing a ping: it will stop
// receiving (although the icmp replies are being
// issued from the remote) after a few seconds.
// Of course this `bug' could be because I'm reading
// the card frames in the wrong way; due to the
// lack of documentation I cannot know.
.
613a
ilock(&ctlr->Lock);
.
612c
for(;;){
tsleep(&ctlr->timer, return0, 0, 50);
ctlr = (Ctlr*)ether->ctlr;
if (ctlr == 0)
break;
if (ctlr->attached == 0)
continue;
tick++;
.
598,610c
static void
w_timer(void* arg)
{
Ether* ether = (Ether*) arg;
Ctlr* ctlr = (Ctlr*)ether->ctlr;
int tick=0;
.
576,596c
// Watcher to ensure that the card still works properly and
// to request WStats updates once a minute.
// BUG: it runs much more often, see the comment below.
.
574c
if (ctlr->attached == 0){
csr_ack(ctlr, 0xffff);
csr_outs(ctlr, WR_IntEna, 0);
return;
}
for(i=0; i<7; i++){
csr_outs(ctlr, WR_IntEna, 0);
rc = csr_ins(ctlr, WR_EvSts);
csr_ack(ctlr, ~WEvs); // Not interested on them
if (rc & WRXEv){
w_rxdone(ether);
csr_ack(ctlr, WRXEv);
}
if (rc & WTXEv){
w_txdone(ctlr, rc);
csr_ack(ctlr, WTXEv);
}
if (rc & WAllocEv){
ctlr->nalloc++;
txid = csr_ins(ctlr, WR_Alloc);
csr_ack(ctlr, WAllocEv);
if (txid == ctlr->txdid){
if ((rc & WTXEv) == 0)
w_txdone(ctlr, rc);
}
}
if (rc & WInfoEv){
ctlr->ninfo++;
w_stats(ctlr);
csr_ack(ctlr, WInfoEv);
}
if (rc & WTxErrEv){
w_txdone(ctlr, rc);
csr_ack(ctlr, WTxErrEv);
}
if (rc & WIDropEv){
ctlr->nidrop++;
csr_ack(ctlr, WIDropEv);
}
w_intena(ctlr);
w_txstart(ether,0);
}
}
.
570,572c
int rc, txid, i;
Ctlr* ctlr = (Ctlr*) ether->ctlr;
.
568c
static void
w_intr(Ether *ether)
.
566a
sp = csr_ins(ctlr, WR_InfoId);
l.type = l.len = 0;
w_read(ctlr, sp, 0, &l, 4);
if (l.type == WTyp_Stats){
l.len--;
for (i = 0; i < l.len && p < pend ; i++){
rc = csr_ins(ctlr, WR_Data1);
if (rc > 0xf000)
rc = ~rc & 0xffff;
p[i] += rc;
}
return 0;
}
return -1;
}
.
561,565c
int sp,i;
ushort rc;
Wltv l;
ulong* p = (ulong*)&ctlr->WStats;
ulong* pend= (ulong*)&ctlr->end;
.
558,559c
ctlr->txbusy = 0;
ctlr->txtmout= 0;
if (sts & WTxErrEv){
ctlr->ntxerr++;
if (sts&1) // it was a watchdog, stay busy to retry.
ctlr->txbusy = b;
} else
ctlr->ntx++;
}
static int
w_stats(Ctlr* ctlr)
.
553,556c
int b = ctlr->txbusy;
.
550,551c
static void
w_txdone(Ctlr* ctlr, int sts)
.
542,547c
w_write(ctlr, txid, WF_802_11_Off, ctlr->txbuf,
ctlr->txlen - ETHERHDRSIZE + 2);
if (w_cmd(ctlr, WCmdTxFree, txid)){
DEBUG("wavelan: transmit failed\n");
ctlr->txbusy=0; // added
ctlr->ntxerr++;
freeb(bp);
return -1;
}
ctlr->txtmout = 2;
freeb(bp);
return 0;
.
540a
bp = qget(ether->oq);
if (bp == 0)
return 0;
ep = (Etherpkt*) bp->rp;
ctlr->txbusy = 1;
// BUG: only IP/ARP/RARP seem to be ok for 802.3
// Other packets should be just copied to the board.
// The driver is not doing so, though.
// Besides, the Block should be used instead of txbuf,
// to save a memory copy.
memset(ctlr->txbuf,0,sizeof(ctlr->txbuf));
memset(&ctlr->txf,0,sizeof(ctlr->txf));
ctlr->txf.framectl = WF_Data;
memmove(ctlr->txf.addr1, ep->d, Eaddrlen);
memmove(ctlr->txf.addr2, ep->s, Eaddrlen);
memmove(ctlr->txf.dstaddr, ep->d, Eaddrlen);
memmove(ctlr->txf.srcaddr, ep->s, Eaddrlen);
memmove(&ctlr->txf.type,ep->type,2);
ctlr->txlen = BLEN(bp);
ctlr->txf.dlen = ctlr->txlen - WSnapHdrLen;
hnputs((uchar*)&ctlr->txf.dat[0], WSnap0);
hnputs((uchar*)&ctlr->txf.dat[1], WSnap1);
hnputs((uchar*)&ctlr->txf.len, ctlr->txlen - WSnapHdrLen);
if (ctlr->txlen - ETHERHDRSIZE > 1536){
print("wavelan: txbuf overflow");
freeb(bp);
return -1;
}
memmove(ctlr->txbuf, bp->rp+sizeof(ETHERHDRSIZE)+10,
ctlr->txlen - ETHERHDRSIZE );
retry:
w_write(ctlr, txid, 0, &ctlr->txf, sizeof(ctlr->txf));
.
539d
535,537c
Etherpkt* ep;
Ctlr* ctlr = (Ctlr*) ether->ctlr;
Block* bp;
int txid;
if (ctlr == 0 || ctlr->attached == 0 )
return -1;
if (ctlr->txbusy && again==0)
return -1;
txid = ctlr->txdid;
if (again){
bp = 0; // a watchdog reenabled the card.
goto retry; // must retry a previously failed tx.
.
530,533d
527,528c
ctlr->nrx++;
etheriq(ether,bp,1);
return;
rxerror:
freeb(bp);
ctlr->nrxerr++;
}
static int
w_txstart(Ether* ether, int again)
.
521,525c
sp = csr_ins(ctlr, WR_RXId);
l = w_read(ctlr, sp, 0, &f, sizeof(f));
if (l == 0){
DEBUG("wavelan: read frame error\n");
goto rxerror;
}
if (f.sts&WF_Err){
goto rxerror;
}
switch(f.sts){
case WF_1042:
case WF_Tunnel:
case WF_WMP:
l = f.dlen + WSnapHdrLen;
bp = iallocb(ETHERHDRSIZE + l + 2);
if (!bp)
goto rxerror;
ep = (Etherpkt*) bp->wp;
memmove(ep->d, f.addr1, Eaddrlen);
memmove(ep->s, f.addr2, Eaddrlen);
memmove(ep->type,&f.type,2);
bp->wp += ETHERHDRSIZE;
if (w_read(ctlr, sp, WF_802_11_Off, bp->wp, l+2) == 0){
DEBUG("wavelan: read 802.11 error\n");
goto rxerror;
}
bp->wp += l+2;
bp = trimblock(bp, 0, f.dlen+ETHERHDRSIZE);
break;
default:
l = ETHERHDRSIZE + f.dlen + 2;
bp = iallocb(l);
if (!bp)
goto rxerror;
if (w_read(ctlr, sp, WF_802_3_Off, bp->wp, l) == 0){
DEBUG("wavelan: read 800.3 error\n");
goto rxerror;
}
bp->wp += l;
}
.
518,519c
Ctlr* ctlr = (Ctlr*) ether->ctlr;
ushort sp;
WFrame f;
Block* bp=0;
ulong l;
Etherpkt* ep;
.
516c
w_rxdone(Ether* ether)
.
514a
.
513a
}
.
512a
if (w_cmd(ctlr, WCmdEna, 0)){
DEBUG("wavelan: Enable failed");
return -1;
}
ctlr->txdid = w_alloc(ctlr, 1518 + sizeof(WFrame) + 8);
ctlr->txmid = w_alloc(ctlr, 1518 + sizeof(WFrame) + 8);
if (ctlr->txdid == -1 || ctlr->txmid == -1)
DEBUG("wavelan: alloc failed");
ctlr->txbusy= 0;
w_intena(ctlr);
return 0;
.
511c
// BUG: set multicast addresses
.
506,509c
ltv_outs(ctlr, WTyp_Prom, (ether->prom?1:0));
.
504c
w_intdis(ctlr);
ltv_outs(ctlr, WTyp_Tick, 8);
ltv_outs(ctlr, WTyp_MaxLen, ctlr->maxlen);
ltv_outs(ctlr, WTyp_Ptype, ctlr->ptype);
ltv_outs(ctlr, WTyp_RtsThres, ctlr->rtsthres);
ltv_outs(ctlr, WTyp_TxRate, ctlr->txrate);
ltv_outs(ctlr, WTyp_ApDens, ctlr->apdensity);
ltv_outs(ctlr, WTyp_PM, ctlr->pmena);
ltv_outs(ctlr, WTyp_PMWait, ctlr->pmwait);
if (*ctlr->netname)
ltv_outstr(ctlr, WTyp_NetName, ctlr->netname);
if (*ctlr->wantname)
ltv_outstr(ctlr, WTyp_WantName, ctlr->wantname);
ltv_outs(ctlr, WTyp_Chan, ctlr->chan);
if (*ctlr->nodename)
ltv_outstr(ctlr, WTyp_NodeName, ctlr->nodename);
l.type = WTyp_Mac;
l.len = 4;
memmove(l.addr, ether->ea, Eaddrlen);
w_outltv(ctlr, &l);
.
502c
w_intdis(ctlr);
w_cmd(ctlr, WCmdDis, 0);
w_intdis(ctlr);
if(w_cmd(ctlr, WCmdIni, 0))
return -1;
.
498,500c
if (!ctlr)
return -1;
.
494,496c
Wltv l;
Ctlr* ctlr = (Ctlr*) ether->ctlr;
.
491,492c
if (w_cmd(ctlr, WCmdMalloc, len)==0)
for (i = 0; i<WTmOut; i++)
if (csr_ins(ctlr, WR_EvSts) & WAllocEv){
csr_ack(ctlr, WAllocEv);
rc=csr_ins(ctlr, WR_Alloc);
if (w_seek(ctlr, rc, 0, 0))
return -1;
len = len/2;
for (j=0; j<len; j++)
csr_outs(ctlr, WR_Data0, 0);
return rc;
}
return -1;
}
static int
w_enable(Ether* ether)
.
480,489c
static int
w_alloc(Ctlr* ctlr, int len)
{
int rc;
int i,j;
.
478a
DEBUG("wavelan: tx timeout\n");
return 0;
}
.
477c
static int
w_write(Ctlr* ctlr, int type, int off, void* buf, ulong len)
{
ushort *p = (ushort*)buf;
ulong l = len / 2;
int i,tries;
for (tries=0; tries < WTmOut; tries++){
if (w_seek(ctlr, type, off, 0)){
DEBUG("wavelan: w_write: seek failed\n");
return 0;
}
for (i = 0; i < l; i++)
csr_outs(ctlr, WR_Data0, p[i]);
csr_outs(ctlr, WR_Data0, 0xdead);
csr_outs(ctlr, WR_Data0, 0xbeef);
if (w_seek(ctlr, type, off + len, 0)){
DEBUG("wavelan: write seek failed\n");
return 0;
}
if (csr_ins(ctlr, WR_Data0) == 0xdead)
if (csr_ins(ctlr, WR_Data0) == 0xbeef)
return len;
DEBUG("wavelan: Hermes bug byte.\n");
return 0;
.
474,475d
469,472c
return n;
}
.
464,467c
} else
DEBUG("wavelan: w_read: seek failed");
.
452,462c
static int
w_read(Ctlr* ctlr, int type, int off, void* buf, ulong len)
{
ushort *p = (ushort*)buf;
int i, n;
n=0;
if (w_seek(ctlr, type, off, 1) == 0){
len /= 2;
for (i = 0; i < len; i++){
p[i] = csr_ins(ctlr, WR_Data1);
n += 2;
.
448,450d
445,446c
static char*
ltv_inname(Ctlr* ctlr, int type)
{
static char unk[] = "unknown";
static Wltv l;
memset(&l,0,sizeof(l));
l.type = type;
l.len = WNameLen/2+2;
if (w_inltv(ctlr, &l))
return unk;
if (l.name[2] == 0)
return unk;
return l.name+2;
}
.
436,443c
len = (strlen(val)+1)&~1;
memset(&l,0,sizeof(l));
l.type = type;
l.len = (len/2)+2;
l.val = len; // l.s[0] and l.s[1]
strncpy(l.s+2,val,strlen(val));
w_outltv(ctlr, &l);
}
.
430,434c
static void
ltv_outstr(Ctlr* ctlr, int type, char *val)
{
Wltv l;
int len;
.
427,428c
l.type = type;
l.len = 2;
l.val = 0;
w_inltv(ctlr, &l);
return l.val;
}
.
421,425c
Wltv l;
.
418,419c
static ushort
ltv_ins(Ctlr* ctlr, int type)
.
399,416c
l.type = type;
l.val = val;
l.len = 2;
w_outltv(ctlr, &l);
}
.
397c
static void
ltv_outs(Ctlr* ctlr, int type, ushort val)
{
Wltv l;
.
395c
if (w_seek(ctlr,l->type,0,1))
return;
csr_outs(ctlr, WR_Data1, l->len);
csr_outs(ctlr, WR_Data1, l->type);
p = &l->val;
len = l->len-1;
for (i=0; i<len; i++)
csr_outs(ctlr, WR_Data1, p[i]);
w_cmd(ctlr,WCmdAccWr,l->type);
}
.
391,393c
int i,len;
ushort *p;
.
386,389c
static void
w_outltv(Ctlr* ctlr, Wltv* l)
.
384a
p = &l->val;
len--;
for (i=0; i<len; i++)
p[i] = csr_ins(ctlr, WR_Data1);
return 0;
}
.
380,383c
len = csr_ins(ctlr, WR_Data1);
if (len > l->len)
return -1;
l->len = len;
if ((code=csr_ins(ctlr, WR_Data1)) != l->type){
DEBUG("wavelan: type %x != code %x\n",l->type,code);
return -1;
.
375,378c
if (w_seek(ctlr,l->type,0,1)){
DEBUG("wavelan: seek failed\n");
return -1;
.
370,372c
if (w_cmd(ctlr, WCmdAccRd, l->type)){
DEBUG("wavelan: access read failed\n");
.
364,368c
static int
w_inltv(Ctlr* ctlr, Wltv* l)
{
int i, len;
ushort *p,code;
.
361,362c
if (chan != 0 && chan != 1)
panic("wavelan: bad chan\n");
csr_outs(ctlr, sel[chan], id);
csr_outs(ctlr, off[chan], offset);
for (i=0; i<WTmOut; i++){
rc = csr_ins(ctlr, off[chan]);
if ((rc & (WBusyOff|WErrOff)) == 0)
return 0;
}
return -1;
}
.
357,359c
int i, rc;
static ushort sel[] = { WR_Sel0, WR_Sel1 };
static ushort off[] = { WR_Off0, WR_Off1 };
.
354,355c
static int
w_seek(Ctlr* ctlr, ushort id, ushort offset, int chan)
.
352a
return -1;
}
.
350,351d
331,348d
329a
if (rc&WResSts)
break;
return 0;
.
321,328c
static void
w_intena(Ctlr* ctlr)
{
csr_outs(ctlr, WR_IntEna, WEvs);
}
static int
w_cmd(Ctlr *ctlr, ushort cmd, ushort arg)
{
int i;
int rc;
csr_outs(ctlr, WR_Parm0, arg);
csr_outs(ctlr, WR_Cmd, cmd);
for (i = 0; i<WTmOut; i++){
rc = csr_ins(ctlr, WR_EvSts);
if ( rc&WCmdEv ){
rc = csr_ins(ctlr, WR_Sts);
csr_ack(ctlr, WCmdEv);
if ((rc&WCmdMsk) != (cmd&WCmdMsk))
.
311,319c
static void
w_intdis(Ctlr* ctlr)
{
csr_outs(ctlr, WR_IntEna, 0);
csr_ack(ctlr, 0xffff);
}
.
309a
// w_... routines do not ilock the Ctlr and should
// be called locked.
.
301,307c
char netname[WNameLen];
char wantname[WNameLen];
char nodename[WNameLen];
WFrame txf;
uchar txbuf[1536];
int txlen;
Stats;
WStats;
};
.
294,299c
int attached;
int slot;
int iob;
int ptype;
int apdensity;
int rtsthres;
int txbusy;
int txrate;
int txdid;
int txmid;
int txtmout;
int maxlen;
int chan;
int pmena;
int pmwait;
.
288,292c
Lock;
Rendez timer;
.
264,286c
struct Ctlr
.
254,262c
// What the driver thinks. Not what the card thinks.
struct Stats
{
ulong nints;
ulong nrx;
ulong ntx;
ulong ntxrq;
ulong nrxerr;
ulong ntxerr;
ulong nalloc; // allocation (reclaim) events
ulong ninfo;
ulong nidrop;
ulong nwatchdogs; // transmits time outs, actually
};
.
247,252c
ushort len;
ushort type;
union
{
struct {
ushort val;
ushort pad;
};
struct {
uchar addr[8];
};
struct {
char s[17*2];
};
struct {
char name[WNameLen];
};
};
};
.
244,245c
struct Wltv
.
213,242c
#define csr_outs(ctlr,r,arg) outs((ctlr)->iob+(r),(arg))
#define csr_ins(ctlr,r) ins((ctlr)->iob+(r))
#define csr_ack(ctlr,ev) outs((ctlr)->iob+WR_EvAck,(ev))
.
207,211c
WF_802_11_Off = 0x44,
WF_802_3_Off = 0x2e,
};
.
201,205c
WSnapK1 = 0xaa,
WSnapK2 = 0x00,
WSnapCtlr = 0x03,
WSnap0 = (WSnapK1|(WSnapK1<<8)),
WSnap1 = (WSnapK2|(WSnapCtlr<<8)),
WSnapHdrLen = 6,
.
195,199c
WF_Data = 0x0008,
.
192,193c
WF_Err = 0x0003,
WF_1042 = 0x2000,
WF_Tunnel = 0x4000,
WF_WMP = 0x6000,
.
182,190c
// Frame stuff
.
176,180c
WR_EvAck = 0x34,
WR_Data0 = 0x36,
WR_Data1 = 0x38,
.
174a
// Wavelan hermes registers
WR_Cmd = 0x00,
WCmdIni = 0x0000,
WCmdEna = 0x0001,
WCmdDis = 0x0002,
WCmdMalloc = 0x000a,
WCmdAskStats= 0x0011,
WCmdMsk = 0x003f,
WCmdAccRd = 0x0021,
WCmdAccWr = 0x0121,
WCmdTxFree = 0x000b|0x0100,
WR_Parm0 = 0x02,
WR_Parm1 = 0x04,
WR_Parm2 = 0x06,
WR_Sts = 0x08,
WR_InfoId = 0x10,
WR_Sel0 = 0x18,
WR_Sel1 = 0x1a,
WR_Off0 = 0x1c,
WR_Off1 = 0x1e,
WBusyOff = 0x8000,
WErrOff = 0x4000,
WResSts = 0x7f00,
WR_RXId = 0x20,
WR_Alloc = 0x22,
WR_EvSts = 0x30,
WR_IntEna = 0x32,
WCmdEv = 0x0010,
WRXEv = 0x0001,
WTXEv = 0x0002,
WTxErrEv = 0x0004,
WAllocEv = 0x0008,
WInfoEv = 0x0080,
WIDropEv = 0x2000,
WTickEv = 0x8000,
WEvs = WRXEv|WTXEv|WAllocEv|WInfoEv|WIDropEv,
.
173c
WMaxLen = 2304,
WNameLen = 32,
.
94,171c
WDfltApDens = 1,
WDfltRtsThres = 2347, // == disabled
WDfltTxRate = WTxAuto, // 2Mbps
.
92c
WPTypeManaged = 1,
WPTypeWDS = 2,
WPTypeAdHoc = 3,
WDfltPType = WPTypeManaged,
.
82,90c
WTmOut = 65536, // Cmd time out
.
72,80c
WIOLen = 0x40, // Hermes IO length
.
70c
WDfltIRQ = 3, // default irq
WDfltIOB = 0x100, // default IO base
.
67,68c
// Controller
enum
.
62,65d
40,60c
// Lucent's Length-Type-Value records to talk to the wavelan.
// most operational parameters are read/set using this.
enum
{
WTyp_Stats = 0xf100,
WTyp_Ptype = 0xfc00,
WTyp_Mac = 0xfc01,
WTyp_WantName= 0xfc02,
WTyp_Chan = 0xfc03,
WTyp_NetName = 0xfc04,
WTyp_ApDens = 0xfc06,
WTyp_MaxLen = 0xfc07,
WTyp_PM = 0xfc09,
WTyp_PMWait = 0xfc0c,
WTyp_NodeName= 0xfc0e,
WTyp_Tick = 0xfce0,
WTyp_RtsThres= 0xfc83,
WTyp_TxRate = 0xfc84,
WTx1Mbps = 0x0,
WTx2Mbps = 0x1,
WTxAuto = 0x3,
WTyp_Prom = 0xfc85,
};
.
33,38c
struct WFrame
{
ushort sts;
ushort rsvd0;
ushort rsvd1;
ushort qinfo;
ushort rsvd2;
ushort rsvd3;
ushort txctl;
ushort framectl;
ushort id;
uchar addr1[Eaddrlen];
uchar addr2[Eaddrlen];
uchar addr3[Eaddrlen];
ushort seqctl;
uchar addr4[Eaddrlen];
ushort dlen;
uchar dstaddr[Eaddrlen];
uchar srcaddr[Eaddrlen];
ushort len;
ushort dat[3];
ushort type;
};
.
28,31c
ulong ntxuframes; // unicast frames
ulong ntxmframes; // multicast frames
ulong ntxfrags; // fragments
ulong ntxubytes; // unicast bytes
ulong ntxmbytes; // multicast bytes
ulong ntxdeferred; // deferred transmits
ulong ntxsretries; // single retries
ulong ntxmultiretries; // multiple retries
ulong ntxretrylimit;
ulong ntxdiscards;
ulong nrxuframes; // unicast frames
ulong nrxmframes; // multicast frames
ulong nrxfrags; // fragments
ulong nrxubytes; // unicast bytes
ulong nrxmbytes; // multicast bytes
ulong nrxfcserr;
ulong nrxdropnobuf;
ulong nrxdropnosa;
ulong nrxcantdecrypt;
ulong nrxmsgfrag;
ulong nrxmsgbadfrag;
ulong end;
};
.
25,26c
typedef struct Ctlr Ctlr;
typedef struct Wltv Wltv;
typedef struct WFrame WFrame;
typedef struct Stats Stats;
typedef struct WStats WStats;
struct WStats
.
22,23c
#define DEBUG if(1)print
.
19d
2,7c
Lucent Wavelan IEEE 802.11 pcmcia.
There is almost no documentation for the card.
the driver is done using both the freebsd and the linux
driver as `documentation'.
Has been used with the card plugged in during all up time.
no cards removals/insertions yet.
For known BUGS see the comments below. Besides,
the driver keeps interrupts disabled for just too
long. When it gets robust, locks should be revisited.
.
## diffname pc/etherwavelan.c 2001/0119
## diff -e /n/emeliedump/2001/0118/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0119/sys/src/9/pc/etherwavelan.c
1056c
if(i < 1 || i > 3 )
.
1050c
if(i < 1 || i > 16 )
.
1022d
## diffname pc/etherwavelan.c 2001/0121
## diff -e /n/emeliedump/2001/0119/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0121/sys/src/9/pc/etherwavelan.c
1225a
.
1184,1186c
if (ctlr->chan == 0)
ctlr->chan = ltv_ins(ctlr, WTyp_Chan);
.
1145,1152c
for (i=0; i < ether->nopt; i++)
setopt(ctlr, ether->opt[i], ether->ctlrno);
.
1143c
ctlr->chan = 0;
ctlr->ptype= WDfltPType;
ctlr->keyid= 0;
.
1116a
static void
setopt(Ctlr* ctlr, char* opt, int no)
{
int i;
char k[64];
char *kn = &k[3];
WKey *kp;
char *ke;
int key;
if (strncmp(opt,"essid=",6) == 0){
if (ctlr->ptype == 3)
strncpy(ctlr->netname,opt+6,WNameLen);
else
strncpy(ctlr->wantname,opt+6,WNameLen);
iprint("essid %d %s\n", ctlr->ptype, opt+6);
}
else if (strncmp(opt,"station_name=",13) == 0){
// BUG?
// In my kernel, it seems that the max length of
// opt is 16, and I get "na" as node name
// when I say station_name=nautilus.
strncpy(ctlr->nodename, opt+13,WNameLen);
iprint("nodename %s\n", ctlr->nodename);
}
else if (strncmp(opt, "channel=",8) == 0){
i = atoi(opt+8);
if(i < 1 || i > 16 )
print("#l%d: channel (%d) not in [1-16]\n",no,i);
else
ctlr->chan = i;
iprint("chan %d\n", i);
}
else if (strncmp(opt, "ptype=",6) == 0){
i = atoi(opt+6);
if(i < 1 || i > 3 )
print("#l%d: port type (%d) not in [1-3]\n",no,i);
else
ctlr->ptype = i;
iprint("ptype %d\n", i);
}
else if (strncmp(opt, "key", 3) == 0){
if (opt[3] == 0 || opt[4] != '='){
print("#l%d: key option is not keyX=xxxx\n", no);
return;
}
strncpy(k,opt,64);
key = atoi(kn);
if (key < 1 || key > WNKeys){
print("#l%d: key number (%d) not in [1-%d]\n",
no, key, WNKeys);
return;
}
ctlr->keyid = key;
kp = &ctlr->key[key-1];
ke = opt+5;
while (*ke && *ke != ' ' && *ke != '\n' && *ke != '\t')
ke++;
kp->len = ke - (opt+5);
if (kp->len > WKeyLen)
kp->len = WKeyLen;
memset(kp->dat, 0, sizeof(kp->dat));
strncpy(kp->dat, opt+5, kp->len);
if (kp->len > WMinKeyLen)
kp->len = WKeyLen;
else if (kp->len > 0)
kp->len = WMinKeyLen;
iprint("key %d <%s> len %d\n", key, kp->dat, kp->len);
}
}
.
1062c
w_txdone(ctlr, WTxErrEv|1); // retry tx later.
.
1060a
.
1058a
else if(strncmp(cb->f[0], "key", 3) == 0){
strncpy(k,cb->f[0],64);
if (strcmp(cb->f[1], "off") == 0)
ctlr->keyid = 0;
else if (strcmp(cb->f[1], "exclude") == 0){
ctlr->xclear = 1;
}
else if (strcmp(cb->f[1], "include") == 0){
ctlr->xclear = 0;
}
else {
key = atoi(kn);
if (key < 1 || key > WNKeys)
error("key not in [1-4]");
ctlr->keyid = key;
kp = &ctlr->key[key-1];
kp->len = strlen(cb->f[1]);
if (kp->len > WKeyLen)
kp->len = WKeyLen;
memset(kp->dat, 0, sizeof(kp->dat));
strncpy(kp->dat, cb->f[1], kp->len);
if (kp->len > WMinKeyLen)
kp->len = WKeyLen;
else if (kp->len > 0)
kp->len = WMinKeyLen;
}
}
.
1056c
error("port type not in [1-3]");
.
1050c
error("channel not in [1-16]\n");
.
1047c
}
else if(strcmp(cb->f[0], "channel") == 0){
.
1041,1045c
if(strcmp(cb->f[0], "essid") == 0){
if (strcmp(cb->f[1],"default") == 0)
nessid = "";
else
nessid = cb->f[1];
if (ctlr->ptype == 3){
memset(ctlr->netname, 0, sizeof(ctlr->netname));
strncpy(ctlr->netname, nessid, WNameLen);
}
else {
memset(ctlr->wantname, 0, sizeof(ctlr->wantname));
strncpy(ctlr->wantname, nessid, WNameLen);
}
}
else if(strcmp(cb->f[0], "station_name") == 0){
memset(ctlr->nodename, 0, sizeof(ctlr->nodename));
.
1030a
.
1023a
char *nessid;
WKey *kp;
char k[64];
char *kn= &k[3];
int key;
.
986,1015d
984a
#undef PRINTSTR
#undef PRINTSTAT
.
939,980c
PRINTSTAT("ntxuframes: %lud\n", ctlr->ntxuframes);
PRINTSTAT("ntxmframes: %lud\n", ctlr->ntxmframes);
PRINTSTAT("ntxfrags: %lud\n", ctlr->ntxfrags);
PRINTSTAT("ntxubytes: %lud\n", ctlr->ntxubytes);
PRINTSTAT("ntxmbytes: %lud\n", ctlr->ntxmbytes);
PRINTSTAT("ntxdeferred: %lud\n", ctlr->ntxdeferred);
PRINTSTAT("ntxsretries: %lud\n", ctlr->ntxsretries);
PRINTSTAT("ntxmultiretries: %lud\n", ctlr->ntxmultiretries);
PRINTSTAT("ntxretrylimit: %lud\n", ctlr->ntxretrylimit);
PRINTSTAT("ntxdiscards: %lud\n", ctlr->ntxdiscards);
PRINTSTAT("nrxuframes: %lud\n", ctlr->nrxuframes);
PRINTSTAT("nrxmframes: %lud\n", ctlr->nrxmframes);
PRINTSTAT("nrxfrags: %lud\n", ctlr->nrxfrags);
PRINTSTAT("nrxubytes: %lud\n", ctlr->nrxubytes);
PRINTSTAT("nrxmbytes: %lud\n", ctlr->nrxmbytes);
PRINTSTAT("nrxfcserr: %lud\n", ctlr->nrxfcserr);
PRINTSTAT("nrxdropnobuf: %lud\n", ctlr->nrxdropnobuf);
PRINTSTAT("nrxdropnosa: %lud\n", ctlr->nrxdropnosa);
PRINTSTAT("nrxcantdecrypt: %lud\n", ctlr->nrxcantdecrypt);
PRINTSTAT("nrxmsgfrag: %lud\n", ctlr->nrxmsgfrag);
PRINTSTAT("nrxmsgbadfrag: %lud\n", ctlr->nrxmsgbadfrag);
USED(l);
.
915,936c
PRINTSTR("\nCard stats: \n");
PRINTSTAT("Status: %ux\n", csr_ins(ctlr, WR_Sts));
PRINTSTAT("Event status: %ux\n", csr_ins(ctlr, WR_EvSts));
PRINTSTAT("Port type: %d\n", ltv_ins(ctlr, WTyp_Ptype));
PRINTSTAT("Transmit rate: %d\n", ltv_ins(ctlr, WTyp_TxRate));
PRINTSTAT("Channel: %d\n", ltv_ins(ctlr, WTyp_Chan));
PRINTSTAT("AP density: %d\n", ltv_ins(ctlr, WTyp_ApDens));
PRINTSTAT("Promiscuous mode: %d\n", ltv_ins(ctlr, WTyp_Prom));
PRINTSTAT("SSID name: %s\n", ltv_inname(ctlr, WTyp_NetName));
PRINTSTAT("Net name: %s\n", ltv_inname(ctlr, WTyp_WantName));
PRINTSTAT("Node name: %s\n", ltv_inname(ctlr, WTyp_NodeName));
if (ltv_ins(ctlr, WTyp_HasCrypt) == 0)
PRINTSTR("WEP: not supported\n");
else {
if (ltv_ins(ctlr, WTyp_Crypt) == 0)
PRINTSTR("WEP: disabled\n");
else{
PRINTSTR("WEP: enabled\n");
i = ltv_ins(ctlr, WTyp_XClear);
k = ((i) ? "excluded" : "included");
PRINTSTAT("Clear packets: %s\n", k);
txid = ltv_ins(ctlr, WTyp_TxKey);
PRINTSTAT("Transmit key id: %d\n", txid);
if (txid >= 1 && txid <= WNKeys){
k = ltv_inkey(ctlr, txid);
if (SEEKEYS && k != nil)
PRINTSTAT("Transmit key: %s\n", k);
}
}
}
.
912a
if (ctlr->keyid){
PRINTSTR("Keys: ");
for (i = 0; i < WNKeys; i++)
if (ctlr->key[i].len == 0)
PRINTSTR("none ");
else {
if (SEEKEYS == 0)
PRINTSTR("set ");
else {
PRINTSTAT("%s ", ctlr->key[i].dat);
}
}
PRINTSTR("\n");
}
.
884,911c
l = 0;
PRINTSTAT("Interrupts: %lud\n", ctlr->nints);
PRINTSTAT("TxPackets: %lud\n", ctlr->ntx);
PRINTSTAT("RxPackets: %lud\n", ctlr->nrx);
PRINTSTAT("TxErrors: %lud\n", ctlr->ntxerr);
PRINTSTAT("RxErrors: %lud\n", ctlr->nrxerr);
PRINTSTAT("TxRequests: %lud\n", ctlr->ntxrq);
PRINTSTAT("AllocEvs: %lud\n", ctlr->nalloc);
PRINTSTAT("InfoEvs: %lud\n", ctlr->ninfo);
PRINTSTAT("InfoDrop: %lud\n", ctlr->nidrop);
PRINTSTAT("WatchDogs: %lud\n", ctlr->nwatchdogs);
k = ((ctlr->attached) ? "attached" : "not attached");
PRINTSTAT("Card %s", k);
k = ((ctlr->txbusy)? ", txbusy" : "");
PRINTSTAT("%s\n", k);
.
878c
int l, i;
int txid;
char* k;
.
872a
#define PRINTSTAT(fmt,val) l += snprint(p+l, READSTR-l, (fmt), (val))
#define PRINTSTR(fmt) l += snprint(p+l, READSTR-l, (fmt))
.
818a
}
.
817c
if (w_enable(ether)){
.
536a
wep = ltv_ins(ctlr, WTyp_HasCrypt);
iprint("wep %d\n", wep);
if (wep)
if (ctlr->keyid == 0)
ltv_outs(ctlr, WTyp_Crypt, 0);
else {
// BUG?
// I think it's ok, but don't know if
// the card needs a WEPing access point
// just to admit the keys.
ltv_outs(ctlr, WTyp_TxKey, ctlr->keyid);
memset(&l, 0, sizeof(l));
l.len = sizeof(ctlr->key[0])*WNKeys/2 + 1;
l.type= WTyp_Keys;
memmove(l.key, &ctlr->key[0],
sizeof(l.key[0])*WNKeys);
w_outltv(ctlr, &l);
ltv_outs(ctlr, WTyp_Crypt, wep);
ltv_outs(ctlr, WTyp_XClear, ctlr->xclear);
}
.
503a
ushort wep;
.
425a
static char*
ltv_inkey(Ctlr* ctlr, int id)
{
static char k[WKeyLen+1];
Wltv l;
int len;
int i;
id--;
memset(&l, 0, sizeof(l));
l.type = WTyp_Keys;
l.len = sizeof(l.key)/2 + 2; // BUG?
if (w_inltv(ctlr, &l))
return Unkname;
if (id <0 || id >=WNKeys){
DEBUG("wavelan: ltv_inkey: bad key id\n");
return Unkname;
}
for (i=0 ; i <WNKeys; i++){
// BUG: despite the checks, this seems to get nothing;
// although it could be that the card
// does not allow reading keys for security.
if (l.key[id].len != 0){
DEBUG("len=%d ", l.key[id].len);
}
if (l.key[id].dat[1] != 0){
DEBUG("dat1=%s ", l.key[id].dat+1);
}
if (l.key[id].dat[2] != 0){
DEBUG("dat2=%s ", l.key[id].dat+2);
}
if (l.key[id].dat[0] != 0){
DEBUG("%s ", l.key[id].dat);
}
else
DEBUG("none ");
}
DEBUG("\n");
if (l.key[id].dat[0] == 0)
return Nilname;
len = l.key[id].len;
if (len > WKeyLen)
len = WKeyLen;
memset(k, 0, sizeof(k));
memmove(k, l.key[id].dat, len);
k[WKeyLen] = 0;
return k;
}
.
421c
return Nilname;
.
419c
return Unkname;
.
412d
408a
static char Unkname[] = "who knows";
static char Nilname[] = "card does not tell";
.
261a
int keyid; // 0 if not using WEP
int xclear;
WKey key[WNKeys];
.
216a
struct {
WKey key[WNKeys];
};
.
197a
struct WKey
{
ushort len;
char dat[WKeyLen];
};
.
191a
.
132a
WNKeys = 4,
WKeyLen = 14,
WMinKeyLen = 5,
.
106a
WTyp_Keys = 0xfcb0,
WTyp_TxKey = 0xfcb1,
WTyp_HasCrypt= 0xfd4f,
.
99a
WTyp_Crypt = 0xfc20,
WTyp_XClear= 0xfc22,
.
33a
typedef struct WKey WKey;
.
28a
#define SEEKEYS 1
.
13c
WEP is not tested (see BUGs too).
.
## diffname pc/etherwavelan.c 2001/0122
## diff -e /n/emeliedump/2001/0121/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0122/sys/src/9/pc/etherwavelan.c
1408d
1304,1306c
Ctlr* ctlr;
Wltv ltv;
int i;
.
1297d
1269d
1261d
1253d
1245d
1238d
1233c
int i, key;
.
1219,1220c
Ether* ether = (Ether*) arg;
Ctlr* ctlr = (Ctlr*) ether->ctlr;
.
1202,1203c
Ether* ether = (Ether*)arg;
Ctlr* ctlr = ether->ctlr;
.
1170a
else if(strcmp(cb->f[0], "pm") == 0){
if(strcmp(cb->f[1], "off") == 0)
ctlr->pmena = 0;
else if(strcmp(cb->f[1], "on") == 0){
ctlr->pmena = 1;
if(cb->nf == 3){
i = atoi(cb->f[2]);
// check range here? what are the units?
ctlr->pmwait = i;
}
}
else
error(Ebadctl);
}
.
1144c
else if(strcmp(cb->f[0], "key") == 0){
.
1095d
1088c
int i, key;
.
1084d
979,983c
Ctlr *ctlr = (Ctlr*) ether->ctlr;
char *k, *p;
int l, i, txid;
.
974c
#define PRINTSTR(fmt) l += snprint(p+l, READSTR-l, (fmt))
.
952,954c
Ctlr* ctlr;
char name[NAMELEN];
int rc;
.
879,880c
Ether* ether = (Ether*) arg;
Ctlr* ctlr = (Ctlr*)ether->ctlr;
.
823,824c
int rc, txid, i;
Ctlr* ctlr = (Ctlr*) ether->ctlr;
.
798,802c
int sp,i;
ushort rc;
Wltv l;
ulong* p = (ulong*)&ctlr->WStats;
ulong* pend= (ulong*)&ctlr->end;
.
718,719c
Ctlr* ctlr = (Ctlr*) ether->ctlr;
Block* bp;
.
656,660c
Ctlr* ctlr = (Ctlr*) ether->ctlr;
ushort sp;
WFrame f;
Block* bp=0;
ulong l;
.
616d
600a
ltv_outs(ctlr, WTyp_PM, ctlr->pmena);
.
599d
579,581c
Wltv l;
Ctlr* ctlr = (Ctlr*) ether->ctlr;
ushort wep;
.
527,528c
ulong l = len / 2;
int i,tries;
.
507c
int i, n;
.
488,489c
// else
// DEBUG("none ");
.
460,461c
int i, len;
.
436c
static char Unkname[] = "who knows";
.
431c
l.val = len; // l.s[0] and l.s[1]
.
314a
.
285,286c
int keyid; // 0 if not using WEP
int xclear;
.
283c
int txlen;
.
262,276c
int attached;
int slot;
int iob;
int ptype;
int apdensity;
int rtsthres;
int txbusy;
int txrate;
int txdid;
int txmid;
int txtmout;
int maxlen;
int chan;
int pmena;
int pmwait;
.
254c
ulong nwatchdogs; // transmits time outs, actually
.
251c
ulong nalloc; // allocation (reclaim) events
.
208,209c
#define csr_ins(ctlr,r) ins((ctlr)->iob+(r))
#define csr_ack(ctlr,ev) outs((ctlr)->iob+WR_EvAck,(ev))
.
151c
WCmdAskStats = 0x0011,
.
136c
WDfltTxRate = WTxAuto, // 2Mbps
.
127c
WTmOut = 65536, // Cmd time out
.
125c
WIOLen = 0x40, // Hermes IO length
.
122,123c
WDfltIRQ = 3, // default irq
WDfltIOB = 0x100, // default IO base
.
92,114c
WTyp_Stats = 0xf100,
WTyp_Ptype = 0xfc00,
WTyp_Mac = 0xfc01,
WTyp_WantName = 0xfc02,
WTyp_Chan = 0xfc03,
WTyp_NetName = 0xfc04,
WTyp_ApDens = 0xfc06,
WTyp_MaxLen = 0xfc07,
WTyp_PM = 0xfc09,
WTyp_PMWait = 0xfc0c,
WTyp_NodeName = 0xfc0e,
WTyp_Crypt = 0xfc20,
WTyp_XClear = 0xfc22,
WTyp_Tick = 0xfce0,
WTyp_RtsThres = 0xfc83,
WTyp_TxRate = 0xfc84,
WTx1Mbps = 0x0,
WTx2Mbps = 0x1,
WTxAuto = 0x3,
WTyp_Prom = 0xfc85,
WTyp_Keys = 0xfcb0,
WTyp_TxKey = 0xfcb1,
WTyp_HasCrypt = 0xfd4f,
.
66,85c
ushort sts;
ushort rsvd0;
ushort rsvd1;
ushort qinfo;
ushort rsvd2;
ushort rsvd3;
ushort txctl;
ushort framectl;
ushort id;
uchar addr1[Eaddrlen];
uchar addr2[Eaddrlen];
uchar addr3[Eaddrlen];
ushort seqctl;
uchar addr4[Eaddrlen];
ushort dlen;
uchar dstaddr[Eaddrlen];
uchar srcaddr[Eaddrlen];
ushort len;
ushort dat[3];
ushort type;
.
50,54c
ulong nrxuframes; // unicast frames
ulong nrxmframes; // multicast frames
ulong nrxfrags; // fragments
ulong nrxubytes; // unicast bytes
ulong nrxmbytes; // multicast bytes
.
40,44c
ulong ntxuframes; // unicast frames
ulong ntxmframes; // multicast frames
ulong ntxfrags; // fragments
ulong ntxubytes; // unicast bytes
ulong ntxmbytes; // multicast bytes
.
36c
typedef struct WKey WKey;
.
## diffname pc/etherwavelan.c 2001/0123
## diff -e /n/emeliedump/2001/0122/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0123/sys/src/9/pc/etherwavelan.c
292d
254c
ulong nwatchdogs; // transmit time outs, actually
.
13c
(see BUGs).
.
## diffname pc/etherwavelan.c 2001/0124
## diff -e /n/emeliedump/2001/0123/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0124/sys/src/9/pc/etherwavelan.c
1139c
else if(strncmp(cb->f[0], "key", 3) == 0){
.
## diffname pc/etherwavelan.c 2001/0125
## diff -e /n/emeliedump/2001/0124/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0125/sys/src/9/pc/etherwavelan.c
1334c
*ctlr->netname = *ctlr->wantname = 0;
strcpy(ctlr->nodename, "wvlancard");
.
1255,1258c
// The max. length of an 'opt' is ISAOPTLEN in dat.h.
// It should be > 16 to give reasonable name lengths.
memset(ctlr->nodename, 0, sizeof(ctlr->nodename));
.
1252c
nessid = opt+6;
if (ctlr->ptype == 3){
memset(ctlr->netname, 0, sizeof(ctlr->netname));
strncpy(ctlr->netname, nessid, WNameLen);
}
else{
memset(ctlr->wantname, 0, sizeof(ctlr->wantname));
strncpy(ctlr->wantname, nessid, WNameLen);
}
.
1249,1250c
if (strcmp(opt+6, "default") == 0)
nessid = "";
.
1246c
int key;
.
1242,1243c
int i;
char k[64], *ke, *nessid;
.
1027c
if(i == 3)
PRINTSTAT("SSID name: %s\n", ltv_inname(ctlr, WTyp_NetName));
else
PRINTSTAT("Current name: %s\n", ltv_inname(ctlr, WTyp_CurName));
.
1022c
i = ltv_ins(ctlr, WTyp_Ptype);
PRINTSTAT("Port type: %d\n", i);
.
628,629c
memmove(l.key, &ctlr->key[0], sizeof(l.key[0])*WNKeys);
.
430,432c
l.len = (sizeof(l.type)+sizeof(l.slen)+sizeof(l.s))/2;
l.slen = (len+1) & ~1;
strncpy(l.s, val, len);
.
427,428c
len = strlen(val);
if(len > sizeof(l.s))
len = sizeof(l.s);
memset(&l, 0, sizeof(l));
.
231c
ushort slen;
char s[WNameLen];
.
117,118d
113a
WTyp_CurName = 0xfd41,
.
13d
## diffname pc/etherwavelan.c 2001/0126
## diff -e /n/emeliedump/2001/0125/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0126/sys/src/9/pc/etherwavelan.c
1308,1311c
// if (kp->len > WMinKeyLen)
// kp->len = WKeyLen;
// else if (kp->len > 0)
// kp->len = WMinKeyLen;
.
1164,1167c
// if (kp->len > WMinKeyLen)
// kp->len = WKeyLen;
// else if (kp->len > 0)
// kp->len = WMinKeyLen;
.
12a
BUGS: Endian, alignment and mem/io issues?
.
## diffname pc/etherwavelan.c 2001/0127
## diff -e /n/emeliedump/2001/0126/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0127/sys/src/9/pc/etherwavelan.c
1363a
delay(500);
.
1162c
// if (kp->len > WKeyLen)
.
595a
.
594d
591a
delay(100);
.
426a
delay(100);
.
402a
delay(100);
.
386a
delay(100);
.
316a
csr_outs(ctlr, WR_Parm1, 0);
csr_outs(ctlr, WR_Parm2, 0);
.
315a
if(csr_ins(ctlr, WR_Cmd) & WCmdBusy)
print("busy\n");
.
154a
WCmdBusy = 0x8000,
.
## diffname pc/etherwavelan.c 2001/0201
## diff -e /n/emeliedump/2001/0127/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0201/sys/src/9/pc/etherwavelan.c
1401a
if(ctlr->hascrypt = ltv_ins(ctlr, WTyp_HasCrypt))
ctlr->crypt = 1;
.
1373d
1359,1360c
for(i = 0; i < ether->nopt; i++){
//
// The max. length of an 'opt' is ISAOPTLEN in dat.h.
// It should be > 16 to give reasonable name lengths.
//
strcpy(buf, ether->opt[i]);
if(p = strchr(buf, '='))
*p = ' ';
option(ctlr, buf, strlen(buf));
}
.
1354,1355c
ctlr->ptype = WDfltPType;
ctlr->txkey = 0;
ctlr->keys.len = sizeof(WKey)*WNKeys/2 + 1;
ctlr->keys.type = WTyp_Keys;
.
1338c
if((ctlr = malloc(sizeof(Ctlr))) == nil)
return -1;
.
1331a
Wltv ltv;
Ctlr* ctlr;
char buf[ISAOPTLEN], *p;
.
1329,1330d
1254,1325d
1203,1204d
1201d
1197a
return r;
}
static long
ctl(Ether* ether, void* buf, long n)
{
Ctlr *ctlr;
if((ctlr = ether->ctlr) == nil)
error(Enonexist);
if(ctlr->attached == 0)
error(Eshutdown);
ilock(&ctlr->Lock);
if(option(ctlr, buf, n)){
iunlock(&ctlr->Lock);
error(Ebadctl);
}
.
1196c
r = -2;
free(cb);
.
1193c
r = -1;
.
1184c
else if(cistrcmp(cb->f[1], "on") == 0){
.
1181,1182c
else if(cistrcmp(cb->f[0], "pm") == 0){
if(cistrcmp(cb->f[1], "off") == 0)
.
1161,1179c
else
r = -1;
.
1159a
else
r = -1;
}
else if(cistrncmp(cb->f[0], "key", 3) == 0){
i = atoi(cb->f[0]+3);
if(i >= 1 && i <= WNKeys){
ctlr->txkey = i-1;
key = &ctlr->keys.keys[ctlr->txkey];
key->len = strlen(cb->f[1]);
if (key->len > WKeyLen)
key->len = WKeyLen;
memset(key->dat, 0, sizeof(key->dat));
memmove(key->dat, cb->f[1], key->len);
.
1154,1158c
else if(cistrcmp(cb->f[0], "crypt") == 0){
if(cistrcmp(cb->f[1], "off") == 0)
ctlr->crypt = 0;
else if(cistrcmp(cb->f[1], "on") == 0 && ctlr->hascrypt)
ctlr->crypt = 1;
else
r = -1;
}
else if(cistrcmp(cb->f[0], "clear") == 0){
if(cistrcmp(cb->f[1], "on") == 0)
ctlr->xclear = 0;
else if(cistrcmp(cb->f[1], "off") == 0 && ctlr->hascrypt)
.
1150,1152c
if(i >= 1 && i <= 3 )
ctlr->ptype = i;
else
r = -1;
.
1148c
else if(cistrcmp(cb->f[0], "mode") == 0){
.
1144,1146c
if(i >= 1 && i <= 16 )
ctlr->chan = i;
else
r = -1;
.
1142c
else if(cistrcmp(cb->f[0], "channel") == 0){
.
1138c
else if(cistrcmp(cb->f[0], "station") == 0){
.
1135c
strncpy(ctlr->wantname, p, WNameLen);
.
1133c
else{
.
1131c
strncpy(ctlr->netname, p, WNameLen);
.
1128,1129c
p = cb->f[1];
if(ctlr->ptype == 3){
.
1115,1126c
r = -1;
else if(cistrcmp(cb->f[0], "essid") == 0){
if (cistrcmp(cb->f[1],"default") == 0)
p = "";
.
1113d
1107,1110c
r = 0;
.
1102,1105d
1099,1100c
char *p;
int i, r;
WKey *key;
.
1095,1097c
static int
option(Ctlr* ctlr, char* buf, long n)
.
1057,1061d
1018,1024c
else if (SEEKEYS == 0)
PRINTSTR("set ");
else
PRINTSTAT("%s ", ctlr->keys.keys[i].dat);
}
.
1015,1016c
for (i = 0; i < WNKeys; i++){
if (ctlr->keys.keys[i].len == 0)
.
1013c
if (ctlr->txkey){
.
941,952d
627,644c
if (ctlr->hascrypt){
ltv_outs(ctlr, WTyp_Crypt, ctlr->crypt);
ltv_outs(ctlr, WTyp_TxKey, ctlr->txkey);
w_outltv(ctlr, &ctlr->keys);
ltv_outs(ctlr, WTyp_XClear, ctlr->xclear);
}
.
600d
592d
465,513d
434d
409d
392d
320,321d
317,318d
287,289c
int hascrypt; // card has encryption
int crypt; // encryption off/on
int txkey; // transmit key
Wltv keys; // default keys
int xclear; // exclude clear packets off/on
.
239c
WKey keys[WNKeys];
.
## diffname pc/etherwavelan.c 2001/0202
## diff -e /n/emeliedump/2001/0201/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0202/sys/src/9/pc/etherwavelan.c
1155,1156d
1082a
else if(cistrcmp(cb->f[0], "txkey") == 0){
if((i = atoi(cb->f[1])) >= 1 && i <= WNKeys)
ctlr->txkey = i-1;
else
r = -1;
}
.
1070,1071c
if((i = atoi(cb->f[0]+3)) >= 1 && i <= WNKeys){
.
1047,1048c
if(cistrcmp(cb->f[1], "managed") == 0)
ctlr->ptype = 1;
else if(cistrcmp(cb->f[1], "wds") == 0)
ctlr->ptype = 2;
else if(cistrcmp(cb->f[1], "adhoc") == 0)
ctlr->ptype = 3;
else if((i = atoi(cb->f[1])) >= 1 && i <= 3)
.
1040,1041c
if((i = atoi(cb->f[1])) >= 1 && i <= 16)
.
889c
snprint(name, sizeof(name), "#l%dtimer", ether->ctlrno);
.
883c
char name[64];
.
594d
591d
532d
479d
27d
16d
## diffname pc/etherwavelan.c 2001/0203
## diff -e /n/emeliedump/2001/0202/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0203/sys/src/9/pc/etherwavelan.c
1283c
return 0;
.
1266c
ether->mbps = 10;
.
1261,1262d
1248c
DEBUG("#l%d: %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX\n",
.
1243c
print("#l%d: unable to read mac addr\n",
.
1226,1239d
1207a
if(ctlr->hascrypt = ltv_ins(ctlr, WTyp_HasCrypt))
ctlr->crypt = 1;
.
1202c
w_intdis(ctlr);
if (w_cmd(ctlr,WCmdIni,0)){
print("#l%d: init failed\n", ether->ctlrno);
goto abort;
}
w_intdis(ctlr);
ltv_outs(ctlr, WTyp_Tick, 8);
.
1200c
DEBUG("#l%d: port=0x%lx irq=%ld\n",
.
1195a
if (ioalloc(ether->port,WIOLen,0,"wavelan")<0){
print("#l%d: port 0x%lx in use\n",
ether->ctlrno, ether->port);
goto abort;
}
.
1190c
.
1159c
static void
.
1106,1107c
static long
.
1079c
}
.
1028c
}
.
894c
}
.
870c
// BUG: to be added.
.
863c
}
.
855c
if (ctlr->txbusy)
.
840c
// issued from the remote) after a few seconds.
.
808c
// Watcher to ensure that the card still works properly and
.
806c
}
.
802c
.
771c
.
764c
csr_outs(ctlr, WR_IntEna, 0);
.
706c
ctlr->txbusy=0; // added
.
700c
w_write(ctlr, txid, 0, &ctlr->txf, sizeof(ctlr->txf));
.
697c
memmove(ctlr->txbuf, bp->rp+sizeof(ETHERHDRSIZE)+10,
.
676c
// The driver is not doing so, though.
.
673c
.
663,665c
if (again){
bp = 0; // a watchdog reenabled the card.
goto retry; // must retry a previously failed tx.
.
655,656c
Block* bp;
int txid;
.
652d
625,626c
bp->wp = bp->rp+(ETHERHDRSIZE+f.dlen);
.
529c
static int
.
484c
for (tries=0; tries < WTmOut; tries++){
.
447c
.
308c
csr_outs(ctlr, WR_IntEna, WEvs);
.
301c
csr_outs(ctlr, WR_IntEna, 0);
.
298c
static void
.
295c
// w_... routines do not ilock the Ctlr and should
.
257c
struct Ctlr
.
220c
union
.
88,89c
// most operational parameters are read/set using this.
enum
.
37c
struct WStats
.
## diffname pc/etherwavelan.c 2001/0204
## diff -e /n/emeliedump/2001/0203/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0204/sys/src/9/pc/etherwavelan.c
845c
w_intr(ether);
.
## diffname pc/etherwavelan.c 2001/0205
## diff -e /n/emeliedump/2001/0204/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0205/sys/src/9/pc/etherwavelan.c
14c
BUGS: check endian, alignment and mem/io issues.
TODO: automatic power management;
improve locking;
extract signal info;
remove copy in transmit.
.
## diffname pc/etherwavelan.c 2001/0207
## diff -e /n/emeliedump/2001/0205/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0207/sys/src/9/pc/etherwavelan.c
1229c
strcpy(ctlr->nodename, "Plan 9 STA");
.
924a
PRINTSTAT("Ticks: %ud\n", ctlr->ticks);
PRINTSTAT("TickIntr: %ud\n", ctlr->tickintr);
.
861c
if ((ctlr->ticks % 120) == 0)
.
851c
if ((ctlr->ticks % 10) == 0) {
.
849a
}
.
848c
if (csr_ins(ctlr, WR_EvSts)&WEvs){
ctlr->tickintr++;
.
829c
ctlr->ticks++;
.
820d
258a
int ticks;
int tickintr;
.
## diffname pc/etherwavelan.c 2001/0210
## diff -e /n/emeliedump/2001/0207/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0210/sys/src/9/pc/etherwavelan.c
1271c
ctlr->pmwait = 100;
ctlr->signal = 1;
ctlr->noise = 1;
.
972,973c
k = ((ctlr->xclear)? "excluded": "included");
.
955a
PRINTSTAT("Current Transmit rate: %d\n",
ltv_ins(ctlr, WTyp_CurTxRate));
.
917a
PRINTSTAT("Signal: %d\n", ctlr->signal-149);
PRINTSTAT("Noise: %d\n", ctlr->noise-149);
PRINTSTAT("SNR: %ud\n", ctlr->signal-ctlr->noise);
.
915c
.
913c
ether->oerrs = ctlr->ntxerr;
ether->crcs = ctlr->nrxfcserr;
ether->frames = 0;
ether->buffs = ctlr->nrxdropnobuf;
ether->overflows = 0;
//
// Offset must be zero or there's a possibility the
// new data won't match the previous read.
//
if(n == 0 || offset != 0)
.
911c
int i, l, txid;
.
849,852c
// if (csr_ins(ctlr, WR_EvSts)&WEvs){
// ctlr->tickintr++;
// w_intr(ether);
// }
.
810a
if (rc & WTXEv){
w_txdone(ctlr, rc);
csr_ack(ctlr, WTXEv);
}
if (rc & WAllocEv){
ctlr->nalloc++;
txid = csr_ins(ctlr, WR_Alloc);
csr_ack(ctlr, WAllocEv);
if (txid == ctlr->txdid){
if ((rc & WTXEv) == 0)
w_txdone(ctlr, rc);
}
}
if (rc & WInfoEv){
ctlr->ninfo++;
w_stats(ctlr);
csr_ack(ctlr, WInfoEv);
}
if (rc & WTxErrEv){
w_txdone(ctlr, rc);
csr_ack(ctlr, WTxErrEv);
}
if (rc & WIDropEv){
ctlr->nidrop++;
csr_ack(ctlr, WIDropEv);
}
w_intena(ctlr);
w_txstart(ether,0);
.
808,809c
if (rc & WRXEv){
w_rxdone(ether);
csr_ack(ctlr, WRXEv);
.
777,806c
csr_outs(ctlr, WR_IntEna, 0);
rc = csr_ins(ctlr, WR_EvSts);
csr_ack(ctlr, ~WEvs); // Not interested on them
.
772,775d
764c
int rc, txid;
.
746,750c
ltv.len = ltv.type = 0;
w_read(ctlr, sp, 0, <v, 4);
if (ltv.type == WTyp_Stats){
ltv.len--;
for (i = 0; i < ltv.len && p < pend ; i++){
.
739,741c
int i, rc, sp;
Wltv ltv;
.
704a
txid = ctlr->txdid;
.
703c
ctlr->txlen - ETHERHDRSIZE);
.
679c
// BUG: only IP/ARP/RARP seem to be ok for 802.3
.
667d
649c
rxerror:
.
646a
ctlr->signal = ((ctlr->signal*15)+((f.qinfo>>8) & 0xFF))/16;
ctlr->noise = ((ctlr->noise*15)+(f.qinfo & 0xFF))/16;
.
642c
bp->wp += len;
.
638c
if (w_read(ctlr, sp, WF_802_3_Off, bp->wp, len) == 0){
.
634,635c
len = ETHERHDRSIZE + f.dlen + 2;
bp = iallocb(len);
.
627c
if (w_read(ctlr, sp, WF_802_11_Off, bp->wp, len+2) == 0){
.
618,619c
len = f.dlen + WSnapHdrLen;
bp = iallocb(ETHERHDRSIZE + len + 2);
.
606,607c
len = w_read(ctlr, sp, 0, &f, sizeof(f));
if (len == 0){
.
602d
599c
int len, sp;
.
566,569c
ltv.len = 4;
ltv.type = WTyp_Mac;
memmove(ltv.addr, ether->ea, Eaddrlen);
w_outltv(ctlr, <v);
.
538c
Wltv ltv;
.
496,497c
outss((ctlr)->iob+(WR_Data0), buf, len/2);
.
486,488c
int tries;
.
480c
return len;
.
478a
return 0;
}
inss((ctlr)->iob+(WR_Data1), buf, len/2);
.
467,477c
if (w_seek(ctlr, type, off, 1)){
.
461c
return ltv.name+2;
.
459c
if (ltv.name[2] == 0)
.
454,457c
memset(<v,0,sizeof(ltv));
ltv.len = WNameLen/2+2;
ltv.type = type;
if (w_inltv(ctlr, <v))
.
452c
static Wltv ltv;
.
436,443c
if(len > sizeof(ltv.s))
len = sizeof(ltv.s);
memset(<v, 0, sizeof(ltv));
ltv.len = (sizeof(ltv.type)+sizeof(ltv.slen)+sizeof(ltv.s))/2;
ltv.type = type;
ltv.slen = (len+1) & ~1;
strncpy(ltv.s, val, len);
w_outltv(ctlr, <v);
.
432c
Wltv ltv;
.
430c
ltv_outstr(Ctlr* ctlr, int type, char* val)
.
422,426c
ltv.len = 2;
ltv.type = type;
ltv.val = 0;
if(w_inltv(ctlr, <v))
return -1;
return ltv.val;
.
420c
Wltv ltv;
.
417c
static int
.
411,414c
ltv.len = 2;
ltv.type = type;
ltv.val = val;
w_outltv(ctlr, <v);
.
409c
Wltv ltv;
.
397,403c
outss((ctlr)->iob+(WR_Data1), ltv, ltv->len+1);
w_cmd(ctlr, WCmdAccWr, ltv->type);
.
392,395c
if(w_seek(ctlr,ltv->type, 0, 1))
.
390c
w_outltv(Ctlr* ctlr, Wltv* ltv)
.
382,385c
if(ltv->len > 0)
inss((ctlr)->iob+(WR_Data1), <v->val, ltv->len-1);
.
377,379c
ltv->len = len;
if ((code=csr_ins(ctlr, WR_Data1)) != ltv->type){
DEBUG("wavelan: type %x != code %x\n",ltv->type,code);
.
375c
if (len > ltv->len)
.
370c
if (w_seek(ctlr,ltv->type,0,1)){
.
366c
if (w_cmd(ctlr, WCmdAccRd, ltv->type)){
.
363,364c
int len;
ushort code;
.
361c
w_inltv(Ctlr* ctlr, Wltv* ltv)
.
320,321c
int i, rc;
.
260a
int signal;
int noise;
.
210c
#define csr_outs(ctlr,r,arg) outs((ctlr)->iob+(r),(arg))
.
206c
WF_802_3_Off = 0x2e,
.
129c
WTmOut = 65536, // Cmd time out
.
127c
WIOLen = 0x40, // Hermes IO length
.
124,125c
WDfltIRQ = 3, // default irq
WDfltIOB = 0x100, // default IO base
.
117a
WTyp_CurTxRate = 0xfd44, // Current TX rate
.
108c
WTyp_Tick = 0xfce0,
.
91c
// Lucent's Length-Type-Value records to talk to the wavelan.
.
34,35c
typedef struct Ctlr Ctlr;
typedef struct Wltv Wltv;
.
17d
14c
BUGS: check endian, alignment and mem/io issues;
receive watchdog interrupts.
.
## diffname pc/etherwavelan.c 2001/0215
## diff -e /n/emeliedump/2001/0210/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0215/sys/src/9/pc/etherwavelan.c
1286,1290c
// DEBUG("#l%d: irq %ld port %lx type %s",
// ether->ctlrno, ether->irq, ether->port, ether->type);
// DEBUG(" %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX\n",
// ether->ea[0], ether->ea[1], ether->ea[2],
// ether->ea[3], ether->ea[4], ether->ea[5]);
.
1258,1261d
1214,1215c
// DEBUG("#l%d: port=0x%lx irq=%ld\n",
// ether->ctlrno, ether->port, ether->irq);
.
1147c
w_txstart(ether);
.
1131a
w_txstart(ether);
.
1130c
w_txdone(ctlr, WTxErrEv);
.
1052c
ctlr->ptype = WPTypeAdHoc;
.
1050c
ctlr->ptype = WPTypeWDS;
.
1048c
ctlr->ptype = WPTypeManaged;
.
845,846c
w_txstart(ether);
.
841c
w_txdone(ctlr, WTxErrEv);
.
794c
w_txstart(ether);
.
735c
for (i = 0; i < ltv.len && p < pend; i++){
.
728c
ulong* pend = (ulong*)&ctlr->end;
.
716,718c
else
.
713,714c
ctlr->txtmout = 0;
if (sts & WTxErrEv)
.
710,711d
704d
702c
else{
ctlr->txbusy = 1;
ctlr->txtmout = 2;
}
.
699,700d
697d
693,695c
if(w_cmd(ctlr, WCmdReclaim|WCmdTx, ctlr->txdid)){
.
687,691c
else{
len = BLEN(bp);
off = WF_802_3_Off;
ctlr->txf.dlen = len;
}
w_write(ctlr, ctlr->txdid, 0, &ctlr->txf, sizeof(ctlr->txf));
w_write(ctlr, ctlr->txdid, off, bp->rp, len+2);
.
658,685c
//
// If the packet header type field is > 1500 it is an IP or
// ARP datagram, otherwise it is an 802.3 packet. See RFC1042.
//
memset(&ctlr->txf, 0, sizeof(ctlr->txf));
if(((pkt->type[0]<<8)|pkt->type[1]) > 1500){
ctlr->txf.framectl = WF_Data;
memmove(ctlr->txf.addr1, pkt->d, Eaddrlen);
memmove(ctlr->txf.addr2, pkt->s, Eaddrlen);
memmove(ctlr->txf.dstaddr, pkt->d, Eaddrlen);
memmove(ctlr->txf.srcaddr, pkt->s, Eaddrlen);
memmove(&ctlr->txf.type, pkt->type, 2);
bp->rp += ETHERHDRSIZE;
len = BLEN(bp);
off = WF_802_11_Off;
ctlr->txf.dlen = len+ETHERHDRSIZE-WSnapHdrLen;
hnputs((uchar*)&ctlr->txf.dat[0], WSnap0);
hnputs((uchar*)&ctlr->txf.dat[1], WSnap1);
hnputs((uchar*)&ctlr->txf.len, len+ETHERHDRSIZE-WSnapHdrLen);
.
653,656c
if((bp = qget(ether->oq)) == nil)
return;
pkt = (Etherpkt*)bp->rp;
.
648,651c
if((ctlr = ether->ctlr) == nil || ctlr->attached == 0 || ctlr->txbusy)
return;
.
643,646c
Etherpkt *pkt;
Ctlr *ctlr;
Block *bp;
int len, off;
.
640,641c
static void
w_txstart(Ether* ether)
.
575c
ctlr->txbusy = 0;
.
292d
159d
156a
WCmdReclaim = 0x0100,
.
152a
WCmdTx = 0x000b,
.
126c
WDfltIOB = 0x180, // default IO base
.
17,18c
improve locking.
.
14a
multicast;
.
4,5c
the driver is done using both the FreeBSD, Linux and
original Plan 9 drivers as `documentation'.
.
## diffname pc/etherwavelan.c 2001/0216
## diff -e /n/emeliedump/2001/0215/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0216/sys/src/9/pc/etherwavelan.c
1171,1175d
## diffname pc/etherwavelan.c 2001/0404
## diff -e /n/emeliedump/2001/0216/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0404/sys/src/9/pc/etherwavelan.c
944a
// PRINTSTAT("Base station: %s\n", ltv_inname(ctlr, WTyp_BaseID));
}
.
943c
else {
.
117a
WTyp_BaseID = 0xfd42, // ID of the currently connected-to base station
.
## diffname pc/etherwavelan.c 2001/0405
## diff -e /n/emeliedump/2001/0404/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0405/sys/src/9/pc/etherwavelan.c
1195,1196c
// DEBUG("#l%d: port=0x%lx irq=%ld\n",
// ether->ctlrno, ether->port, ether->irq);
.
946c
ltv.type = WTyp_BaseID;
ltv.len = 4;
if (w_inltv(ctlr, <v))
print("#l%d: unable to read base station mac addr\n", ether->ctlrno);
l += snprint(p+l, READSTR-l, "Base station: %2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
ltv.addr[0], ltv.addr[1], ltv.addr[2], ltv.addr[3], ltv.addr[4], ltv.addr[5]);
.
944a
Wltv ltv;
.
116a
WTyp_StationID = 0xfd20,
.
## diffname pc/etherwavelan.c 2001/0411
## diff -e /n/emeliedump/2001/0405/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0411/sys/src/9/pc/etherwavelan.c
917c
if (ctlr->hascrypt){
.
## diffname pc/etherwavelan.c 2001/0504
## diff -e /n/emeliedump/2001/0411/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0504/sys/src/9/pc/etherwavelan.c
32c
#define SEEKEYS 0
.
## diffname pc/etherwavelan.c 2001/0505
## diff -e /n/emeliedump/2001/0504/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0505/sys/src/9/pc/etherwavelan.c
437a
.
436a
// This should be ltv.slen = len; according to Axel Belinfante
.
## diffname pc/etherwavelan.c 2001/0509
## diff -e /n/emeliedump/2001/0505/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0509/sys/src/9/pc/etherwavelan.c
1202,1203c
if ((ctlr->slot = pcmspecial("TrueMobile 1150", ether))<0){
DEBUG("no wavelan found\n");
goto abort;
}
.
## diffname pc/etherwavelan.c 2001/0527
## diff -e /n/emeliedump/2001/0509/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0527/sys/src/9/pc/etherwavelan.c
1236c
option(ctlr, ether->opt[i], strlen(ether->opt[i]));
.
1229,1234c
if(p = strchr(ether->opt[i], '='))
.
1207,1208c
// DEBUG("#l%d: port=0x%lx irq=%ld\n",
// ether->ctlrno, ether->port, ether->irq);
.
1202,1205c
DEBUG("no wavelan found\n");
goto abort;
.
1183a
if (ether->ctlr){
print("#l%d: only one card supported\n", ether->ctlrno);
return -1;
}
.
1182c
char *p;
.
951,957d
948,949c
else
.
920c
if (ctlr->txkey){
.
440d
437,438d
119d
117d
32c
#define SEEKEYS 1
.
## diffname pc/etherwavelan.c 2001/0623
## diff -e /n/emeliedump/2001/0527/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0623/sys/src/9/pc/etherwavelan.c
1269a
iofree(ether->port);
abort1:
.
1190c
goto abort1;
.
## diffname pc/etherwavelan.c 2001/0907
## diff -e /n/emeliedump/2001/0623/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0907/sys/src/9/pc/etherwavelan.c
1197,1198c
// DEBUG("#l%d: port=0x%lx irq=%ld\n",
// ether->ctlrno, ether->port, ether->irq);
.
1194,1195c
if ((ctlr->slot = pcmspecial("TrueMobile 1150", ether))<0){
DEBUG("no wavelan found\n");
goto abort;
}
.
1171,1175d
944a
ltv.type = WTyp_BaseID;
ltv.len = 4;
if (w_inltv(ctlr, <v))
print("#l%d: unable to read base station mac addr\n", ether->ctlrno);
l += snprint(p+l, READSTR-l, "Base station: %2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
ltv.addr[0], ltv.addr[1], ltv.addr[2], ltv.addr[3], ltv.addr[4], ltv.addr[5]);
}
.
943c
else {
Wltv ltv;
.
915c
if (ctlr->hascrypt){
.
435a
.
434a
// This should be ltv.slen = len; according to Axel Belinfante
.
117a
WTyp_BaseID = 0xfd42, // ID of the currently connected-to base station
.
116a
WTyp_StationID = 0xfd20,
.
32c
#define SEEKEYS 0
.
## diffname pc/etherwavelan.c 2001/0912
## diff -e /n/emeliedump/2001/0907/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0912/sys/src/9/pc/etherwavelan.c
1220a
ctlr->createibss = 0;
.
1052a
else if(cistrcmp(cb->f[0], "ibss") == 0){
if(cistrcmp(cb->f[1], "on") == 0)
ctlr->createibss = 1;
else
ctlr->createibss = 0;
}
.
543a
ltv_outs(ctlr, WTyp_CreateIBSS, ctlr->createibss);
.
276a
int createibss;
.
121a
WTyp_Tick = 0xfce0,
.
108c
WTyp_CreateIBSS = 0xfc81,
.
## diffname pc/etherwavelan.c 2001/0914
## diff -e /n/emeliedump/2001/0912/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/0914/sys/src/9/pc/etherwavelan.c
462c
if(len >= sizeof ltv.s)
len = sizeof ltv.s - 1;
ltv.s[len] = '\0';
return ltv.s;
.
460c
len = ltv.slen;
if(len == 0 || ltv.s[0] == 0)
.
453a
int len;
.
441c
ltv.slen = len;
.
## diffname pc/etherwavelan.c 2001/1010
## diff -e /n/emeliedump/2001/0914/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/1010/sys/src/9/pc/etherwavelan.c
1220a
.
1215,1216c
for (i=0; wavenames[i]; i++)
if ((ctlr->slot = pcmspecial(wavenames[i], ether))>=0)
break;
name = wavenames[i];
if (name == nil){
for (i=0; i<ether->nopt; i++){
if (cistrncmp(ether->opt[i], "id=", 3) == 0){
name = ðer->opt[i][3];
if ((ctlr->slot = pcmspecial(name, ether)) < 0)
name = nil;
}
}
if (name == nil){
.
1196c
char *name, *p;
.
1189a
static char* wavenames[] = {
"WaveLAN/IEEE",
"TrueMobile 1150",
nil,
};
.
## diffname pc/etherwavelan.c 2001/1015
## diff -e /n/emeliedump/2001/1010/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/1015/sys/src/9/pc/etherwavelan.c
1207a
ctlr->ctlrno = ether->ctlrno;
.
1192a
"Instant Wireless ; Network PC CARD",
.
344c
if((rc&WCmdMsk) != (cmd&WCmdMsk) || (rc&WResSts)){
print("#l%d: cmd %.4ux: status %.4ux\n", ctlr->ctlrno, cmd, rc);
return -1;
}
return 0;
.
342a
rc = csr_ins(ctlr, WR_Sts);
csr_ack(ctlr, WCmdEv);
.
331,341c
for(i=0; i<WTmOut; i++)
if(csr_ins(ctlr, WR_EvSts)&WCmdEv)
break;
if(i==WTmOut){
print("#l%d: execing cmd %.4ux: %.4ux\n", ctlr->ctlrno, cmd, csr_ins(ctlr, WR_EvSts));
return -1;
.
328a
for(i=0; i<WTmOut; i++)
if((csr_ins(ctlr, WR_Cmd)&WCmdBusy) == 0)
break;
if(i==WTmOut){
print("#l%d: issuing cmd %.4ux: %.4ux\n", ctlr->ctlrno, cmd, csr_ins(ctlr, WR_Cmd));
return -1;
}
.
303a
int ctlrno;
.
## diffname pc/etherwavelan.c 2001/1016
## diff -e /n/emeliedump/2001/1015/sys/src/9/pc/etherwavelan.c /n/emeliedump/2001/1016/sys/src/9/pc/etherwavelan.c
1339c
addethercard("wavelan", wavelanpcmciareset);
addethercard("wavelanpci", wavelanpcireset);
.
1335a
static struct {
int vid;
int did;
} wavelanpci[] = {
0x1260, 0x3873, /* Intersil Prism2.5 */
};
static Ctlr *ctlrhead, *ctlrtail;
static void
wavelanpciscan(void)
{
int i;
ulong pa;
Pcidev *p;
Ctlr *ctlr;
p = nil;
while(p = pcimatch(p, 0, 0)){
for(i=0; i<nelem(wavelanpci); i++)
if(p->vid == wavelanpci[i].vid && p->did == wavelanpci[i].did)
break;
if(i==nelem(wavelanpci))
continue;
/*
* On the Prism, bar[0] is the memory-mapped register address (4KB),
*/
if(p->mem[0].size != 4096){
print("wavelanpci: %.4ux %.4ux: unlikely mmio size\n", p->vid, p->did);
continue;
}
ctlr = malloc(sizeof(Ctlr));
ctlr->pcidev = p;
pa = upamalloc(p->mem[0].bar&~0xF, p->mem[0].size, 0);
if(pa == 0){
print("wavelanpci: %.4ux %.4ux: upamalloc 0x%.8lux %d failed\n", p->vid, p->did, p->mem[0].bar&~0xF, p->mem[0].size);
free(ctlr);
continue;
}
ctlr->mmb = (ushort*)KADDR(pa);
if(ctlrhead != nil)
ctlrtail->next = ctlr;
else
ctlrhead = ctlr;
ctlrtail = ctlr;
pcisetbme(p);
}
}
static int
wavelanpcireset(Ether *ether)
{
int i;
Ctlr *ctlr;
if(ctlrhead == nil)
wavelanpciscan();
/*
* Allow plan9.ini to set vid, did?
*/
for(ctlr=ctlrhead; ctlr!=nil; ctlr=ctlr->next)
if(ctlr->active == 0)
break;
if(ctlr == nil)
return -1;
ilock(ctlr);
ether->irq = ctlr->pcidev->intl;
ether->tbdf = ctlr->pcidev->tbdf;
/*
* Really hard reset.
*/
csr_outs(ctlr, WR_PciCor, 0x0080);
delay(250);
csr_outs(ctlr, WR_PciCor, 0x0000);
delay(500);
for(i=0; i<2*10; i++){
if(!(csr_ins(ctlr, WR_Cmd)&WCmdBusy))
break;
delay(100);
}
if(i >= 2*10)
print("wavelan pci %.4ux %.4ux: reset timeout %.4ux\n",
ctlr->pcidev->vid, ctlr->pcidev->did, csr_ins(ctlr, WR_Cmd));
if(genreset(ether, ctlr) < 0){
iunlock(ctlr);
ether->ctlr = nil;
return -1;
}
iunlock(ctlr);
return 0;
}
.
1327,1333c
static int
wavelanpcmciareset(Ether *ether)
{
int i;
Ctlr *ctlr;
if((ctlr = malloc(sizeof(Ctlr))) == nil)
return -1;
ilock(ctlr);
ctlr->ctlrno = ether->ctlrno;
if (ether->port==0)
ether->port=WDfltIOB;
ctlr->iob = ether->port;
if (ether->irq==0)
ether->irq=WDfltIRQ;
if (ioalloc(ether->port,WIOLen,0,"wavelan")<0){
print("#l%d: port 0x%lx in use\n",
ether->ctlrno, ether->port);
goto abort1;
}
/*
* If id= is specified, card must match. Otherwise try generic.
*/
ctlr->slot = -1;
for(i=0; i<ether->nopt; i++){
if(cistrncmp(ether->opt[i], "id=", 3) == 0){
if((ctlr->slot = pcmspecial(ðer->opt[i][3], ether)) < 0)
return -1;
break;
}
}
if(ctlr->slot == -1){
for (i=0; wavenames[i]; i++)
if((ctlr->slot = pcmspecial(wavenames[i], ether))>=0)
break;
if(!wavenames[i]){
DEBUG("no wavelan found\n");
goto abort;
}
}
// DEBUG("#l%d: port=0x%lx irq=%ld\n",
// ether->ctlrno, ether->port, ether->irq);
if(genreset(ether, ctlr) < 0){
abort:
iofree(ether->port);
abort1:
iunlock(ctlr);
free(ctlr);
ether->ctlr = nil;
return -1;
}
iunlock(ctlr);
return 0;
.
1325a
}
.
1324d
1291c
return -1;
.
1260c
return -1;
.
1217,1256d
1214,1215d
1212a
char *p;
.
1210c
genreset(Ether* ether, Ctlr *ctlr)
.
1199c
iunlock(ctlr);
.
1196c
ilock(ctlr);
.
1185c
iunlock(ctlr);
.
1183c
ilock(ctlr);
.
1170c
iunlock(ctlr);
.
1167c
ilock(ctlr);
.
1154c
iunlock(ctlr);
.
1147c
iunlock(ctlr);
.
1145c
ilock(ctlr);
.
993c
iunlock(ctlr);
.
954c
ilock(ctlr);
.
923a
PRINTSTAT("Double Interrupts: %lud\n", ctlr->ndoubleint);
.
885c
iunlock(ctlr);
.
883c
ilock(ctlr);
.
859c
iunlock(ctlr);
.
841,844c
if (csr_ins(ctlr, WR_EvSts)&WEvs){
ctlr->tickintr++;
w_intr(ether);
}
.
824c
ilock(ctlr);
.
800,801d
768,769c
csr_ack(ctlr, ~WEvs); // Not interested in them
.
766d
505c
csr_outss(ctlr, WR_Data0, buf, len/2);
.
489c
csr_inss(ctlr, WR_Data1, buf, len/2);
.
411c
csr_outss(ctlr, WR_Data1, ltv, ltv->len+1);
.
401c
csr_inss(ctlr, WR_Data1, <v->val, ltv->len-1);
.
355a
if(rc&WResSts){
/*
* Don't print; this happens on every WCmdAccWr for some reason.
*/
if(0) print("#l%d: cmd %.4ux: status %.4ux\n", ctlr->ctlrno, cmd, rc);
return -1;
}
.
352c
if((rc&WCmdMsk) != (cmd&WCmdMsk)){
.
346,347c
/*
* WCmdIni can take a really long time.
*/
enum { IniTmOut = 2000 };
for(i=0; i<IniTmOut; i++){
if(csr_ins(ctlr, WR_EvSts)&WCmdEv)
break;
microdelay(100);
}
if(i < IniTmOut)
if(0) print("#l%d: long cmd %.4ux %d\n", ctlr->ctlrno, cmd, i);
if(i == IniTmOut){
print("#l%d: execing cmd %.4ux: %.4ux\n", ctlr->ctlrno, cmd, csr_ins(ctlr, WR_EvSts));
return -1;
}
.
309a
/*
* When we're using a PCI device and memory-mapped I/O,
* the registers are spaced out as though each takes 32 bits,
* even though they are only 16-bit registers. Thus,
* ctlr->mmb[reg] is the right way to access register reg,
* even though a priori you'd expect to use ctlr->mmb[reg/2].
*/
static void
csr_outs(Ctlr *ctlr, int reg, ushort arg)
{
if(ctlr->mmb)
ctlr->mmb[reg] = arg;
else
outs(ctlr->iob+reg, arg);
}
static ushort
csr_ins(Ctlr *ctlr, int reg)
{
if(ctlr->mmb)
return ctlr->mmb[reg];
else
return ins(ctlr->iob+reg);
}
static void
csr_ack(Ctlr *ctlr, int ev)
{
csr_outs(ctlr, WR_EvAck, ev);
}
static void
csr_inss(Ctlr *ctlr, int reg, void *dat, int ndat)
{
ushort *rp, *wp;
if(ctlr->mmb){
rp = &ctlr->mmb[reg];
wp = dat;
while(ndat-- > 0)
*wp++ = *rp;
}else
inss(ctlr->iob+reg, dat, ndat);
}
static void
csr_outss(Ctlr *ctlr, int reg, void *dat, int ndat)
{
ushort *rp, *wp;
if(ctlr->mmb){
rp = dat;
wp = &ctlr->mmb[reg];
while(ndat-- > 0)
*wp = *rp++;
}else
outss(ctlr->iob+reg, dat, ndat);
}
.
305a
/* for PCI-based devices */
Ctlr *next;
ushort *mmb;
int active;
Pcidev *pcidev;
.
254a
ulong ndoubleint;
.
218a
struct WStats
{
ulong ntxuframes; // unicast frames
ulong ntxmframes; // multicast frames
ulong ntxfrags; // fragments
ulong ntxubytes; // unicast bytes
ulong ntxmbytes; // multicast bytes
ulong ntxdeferred; // deferred transmits
ulong ntxsretries; // single retries
ulong ntxmultiretries; // multiple retries
ulong ntxretrylimit;
ulong ntxdiscards;
ulong nrxuframes; // unicast frames
ulong nrxmframes; // multicast frames
ulong nrxfrags; // fragments
ulong nrxubytes; // unicast bytes
ulong nrxmbytes; // multicast bytes
ulong nrxfcserr;
ulong nrxdropnobuf;
ulong nrxdropnosa;
ulong nrxcantdecrypt;
ulong nrxmsgfrag;
ulong nrxmsgbadfrag;
ulong end;
};
struct WFrame
{
ushort sts;
ushort rsvd0;
ushort rsvd1;
ushort qinfo;
ushort rsvd2;
ushort rsvd3;
ushort txctl;
ushort framectl;
ushort id;
uchar addr1[Eaddrlen];
uchar addr2[Eaddrlen];
uchar addr3[Eaddrlen];
ushort seqctl;
uchar addr4[Eaddrlen];
ushort dlen;
uchar dstaddr[Eaddrlen];
uchar srcaddr[Eaddrlen];
ushort len;
ushort dat[3];
ushort type;
};
.
215,217c
typedef struct Ctlr Ctlr;
typedef struct Wltv Wltv;
typedef struct WFrame WFrame;
typedef struct Stats Stats;
typedef struct WStats WStats;
typedef struct WKey WKey;
.
193a
WR_PciCor = 0x26,
WR_PciHcr = 0x2E,
.
34,90d
30c
#define DEBUG if(0){}else print
.
## diffname pc/etherwavelan.c 2002/0403
## diff -e /n/emeliedump/2001/1016/sys/src/9/pc/etherwavelan.c /n/emeliedump/2002/0403/sys/src/9/pc/etherwavelan.c
1497a
ctlr->active = 1;
.
1387,1388c
// print("#l%d: port 0x%lx in use\n",
// ether->ctlrno, ether->port);
.
481a
USED(code);
.
30c
#define DEBUG if(1){}else print
.
## diffname pc/etherwavelan.c 2002/0606
## diff -e /n/emeliedump/2002/0403/sys/src/9/pc/etherwavelan.c /n/emeliedump/2002/0606/sys/src/9/pc/etherwavelan.c
1523a
}
for(i = 0; i < ether->nopt; i++){
if(p = strchr(ether->opt[i], '='))
*p = ' ';
w_option(ctlr, ether->opt[i], strlen(ether->opt[i]));
.
1520c
if(wavelanreset(ether, ctlr) < 0){
.
1484a
char *p;
.
1425a
for(i = 0; i < ether->nopt; i++){
if(p = strchr(ether->opt[i], '='))
*p = ' ';
w_option(ctlr, ether->opt[i], strlen(ether->opt[i]));
}
.
1417c
if(wavelanreset(ether, ctlr) < 0){
.
1383a
.
1372a
char *p;
.
392,1369d
32,390d
30c
#include "wavelan.h"
.
7,19d
1,5c
/* Pci/pcmcia code for wavelan.c */
.
|