summaryrefslogtreecommitdiff
path: root/sys/src/9/pc/etherwavelan.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/9/pc/etherwavelan.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/9/pc/etherwavelan.c')
-rwxr-xr-xsys/src/9/pc/etherwavelan.c197
1 files changed, 197 insertions, 0 deletions
diff --git a/sys/src/9/pc/etherwavelan.c b/sys/src/9/pc/etherwavelan.c
new file mode 100755
index 000000000..e76905b52
--- /dev/null
+++ b/sys/src/9/pc/etherwavelan.c
@@ -0,0 +1,197 @@
+/* Pci/pcmcia code for wavelan.c */
+
+#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"
+
+#include "wavelan.h"
+
+static int
+wavelanpcmciareset(Ether *ether)
+{
+ int i;
+ char *p;
+ 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(&ether->opt[i][3], ether)) < 0)
+ goto abort;
+ 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(wavelanreset(ether, ctlr) < 0){
+ abort:
+ iofree(ether->port);
+ abort1:
+ iunlock(ctlr);
+ free(ctlr);
+ ether->ctlr = nil;
+ return -1;
+ }
+
+ for(i = 0; i < ether->nopt; i++){
+ if(p = strchr(ether->opt[i], '='))
+ *p = ' ';
+ w_option(ctlr, ether->opt[i], strlen(ether->opt[i]));
+ }
+
+ iunlock(ctlr);
+ return 0;
+}
+
+static struct {
+ int vid;
+ int did;
+} wavelanpci[] = {
+ 0x1260, 0x3873, /* Intersil Prism2.5 */
+ 0x1737, 0x0019, /* Linksys WPC-11 untested */
+};
+
+static Ctlr *ctlrhead, *ctlrtail;
+
+static void
+wavelanpciscan(void)
+{
+ int i;
+ void *mem;
+ 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;
+ mem = vmap(p->mem[0].bar&~0xF, p->mem[0].size);
+ if(mem == nil){
+ print("wavelanpci: %.4ux %.4ux: vmap 0x%.8lux %d failed\n", p->vid, p->did, p->mem[0].bar&~0xF, p->mem[0].size);
+ free(ctlr);
+ continue;
+ }
+ ctlr->mmb = mem;
+ if(ctlrhead != nil)
+ ctlrtail->next = ctlr;
+ else
+ ctlrhead = ctlr;
+ ctlrtail = ctlr;
+ pcisetbme(p);
+ }
+}
+
+static int
+wavelanpcireset(Ether *ether)
+{
+ int i;
+ char *p;
+ 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;
+
+ ctlr->active = 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(wavelanreset(ether, ctlr) < 0){
+ iunlock(ctlr);
+ ether->ctlr = nil;
+ return -1;
+ }
+
+ for(i = 0; i < ether->nopt; i++){
+ if(p = strchr(ether->opt[i], '='))
+ *p = ' ';
+ w_option(ctlr, ether->opt[i], strlen(ether->opt[i]));
+ }
+ iunlock(ctlr);
+ return 0;
+}
+
+void
+etherwavelanlink(void)
+{
+ addethercard("wavelan", wavelanpcmciareset);
+ addethercard("wavelanpci", wavelanpcireset);
+}