static void idle(struct net_device *dev) { unsigned long flags; int state; /* FIXME This is initialized to shut the warning up, but I need to * think this through again. */ struct xmitQel *q = NULL; int oops; int i; int base = dev->base_addr; spin_lock_irqsave(&txqueue_lock, flags); if(QInIdle) { spin_unlock_irqrestore(&txqueue_lock, flags); return; } QInIdle = 1; spin_unlock_irqrestore(&txqueue_lock, flags); /* this tri-states the IRQ line */ (void) inb_p(base+6); oops = 100; loop: if (0>oops--) { printk("idle: looped too many times\n"); goto done; } state = inb_p(base+6); if (state != inb_p(base+6)) goto loop; switch(state) { case 0xfc: /* incoming command */ if (debug & DEBUG_LOWER) printk("idle: fc\n"); handlefc(dev); break; case 0xfd: /* incoming data */ if(debug & DEBUG_LOWER) printk("idle: fd\n"); handlefd(dev); break; case 0xf9: /* result ready */ if (debug & DEBUG_LOWER) printk("idle: f9\n"); if(!mboxinuse[0]) { mboxinuse[0] = 1; qels[0].cbuf = rescbuf; qels[0].cbuflen = 2; qels[0].dbuf = resdbuf; qels[0].dbuflen = 2; qels[0].QWrite = 0; qels[0].mailbox = 0; enQ(&qels[0]); } inb_p(dev->base_addr+1); inb_p(dev->base_addr+0); if( wait_timeout(dev,0xf9) ) printk("timed out idle f9\n"); break; case 0xf8: /* ?? */ if (xmQhd) { inb_p(dev->base_addr+1); inb_p(dev->base_addr+0); if(wait_timeout(dev,0xf8) ) printk("timed out idle f8\n"); } else { goto done; } break; case 0xfa: /* waiting for command */ if(debug & DEBUG_LOWER) printk("idle: fa\n"); if (xmQhd) { q=deQ(); memcpy(ltdmacbuf,q->cbuf,q->cbuflen); ltdmacbuf[1] = q->mailbox; if (debug>1) { int n; printk("ltpc: sent command "); n = q->cbuflen; if (n>100) n=100; for(i=0;i<n;i++) printk("%02x ",ltdmacbuf[i]); printk("\n"); } handlecommand(dev); if(0xfa==inb_p(base+6)) { /* we timed out, so return */ goto done; } } else { /* we don't seem to have a command */ if (!mboxinuse[0]) { mboxinuse[0] = 1; qels[0].cbuf = rescbuf; qels[0].cbuflen = 2; qels[0].dbuf = resdbuf; qels[0].dbuflen = 2; qels[0].QWrite = 0; qels[0].mailbox = 0; enQ(&qels[0]); } else { printk("trouble: response command already queued\n"); goto done; } } break; case 0Xfb: /* data transfer ready */ if(debug & DEBUG_LOWER) printk("idle: fb\n"); if(q->QWrite) { memcpy(ltdmabuf,q->dbuf,q->dbuflen); handlewrite(dev); } else { handleread(dev); /* non-zero mailbox numbers are for commmands, 0 is for GETRESULT requests */ if(q->mailbox) { memcpy(q->dbuf,ltdmabuf,q->dbuflen); } else { /* this was a result */ mailbox[ 0x0f & ltdmabuf[0] ] = ltdmabuf[1]; mboxinuse[0]=0; } } break; } goto loop; done: QInIdle=0; /* now set the interrupts back as appropriate */ /* the first read takes it out of tri-state (but still high) */ /* the second resets it */ /* note that after this point, any read of base+6 will trigger an interrupt */ if (dev->irq) { inb_p(base+7); inb_p(base+7); } return; }
int main(int argc, char *argv[]) { struct sockaddr_in sockname; int max = -1, omax; /* the biggest value sd. for select */ int sd; /* our listen socket */ fd_set *readable = NULL , *writable = NULL; /* fd_sets for select */ u_short port; u_long p; char *ep; int i; /* * first, figure out what port we will listen on - it should * be our first parameter. */ if (argc != 2) usage(); errno = 0; p = strtoul(argv[1], &ep, 10); if (*argv[1] == '\0' || *ep != '\0') { /* parameter wasn't a number, or was empty */ fprintf(stderr, "%s - not a number\n", argv[1]); usage(); } if ((errno == ERANGE && p == ULONG_MAX) || (p > USHRT_MAX)) { /* It's a number, but it either can't fit in an unsigned * long, or is too big for an unsigned short */ fprintf(stderr, "%s - value out of range\n", argv[1]); usage(); } /* now safe to do this */ port = p; /* now before we get going, decide if we want to daemonize, that * is, run in the background like a real system process */ #ifndef DEBUG /* don't daemonize if we compile with -DDEBUG */ if (daemon(1, 0) == -1) err(1, "daemon() failed"); #endif /* now off to the races - let's set up our listening socket */ memset(&sockname, 0, sizeof(sockname)); sockname.sin_family = AF_INET; sockname.sin_port = htons(port); sockname.sin_addr.s_addr = htonl(INADDR_ANY); sd=socket(AF_INET,SOCK_STREAM,0); if ( sd == -1) err(1, "socket failed"); if (bind(sd, (struct sockaddr *) &sockname, sizeof(sockname)) == -1) err(1, "bind failed"); if (listen(sd,3) == -1) err(1, "listen failed"); /* * We're now bound, and listening for connections on "sd". * Each call to "accept" will return us a descriptor talking to * a connected client. */ /* * finally - the main loop. accept connections and deal with 'em */ #ifndef DEBUG /* * since we'll be running as a daemon if we're not compiled with * -DDEBUG, we better not be using printf - since stdout will be * unusable */ printf("Server up and listening for connections on port %u\n", port); #endif /* initialize all our connection structures */ for (i = 0; i < MAXCONN; i++) closecon(&connections[i], 1); for(;;) { int i; int maxfd = -1; /* the biggest value sd we are interested in.*/ /* * first we have to initialize the fd_sets to keep * track of readable and writable sockets. we have * to make sure we have fd_sets that are big enough * to hold our largest valued socket descriptor. * so first, we find the max value by iterating through * all the connections, and then we allocate fd sets * that are big enough, if they aren't already. */ omax = max; max = sd; /* the listen socket */ for (i = 0; i < MAXCONN; i++) { if (connections[i].sd > max) max = connections[i].sd; } if (max > omax) { /* we need bigger fd_sets allocated */ /* free the old ones - does nothing if they are NULL */ free(readable); free(writable); /* * this is how to allocate fd_sets for select */ readable = (fd_set *)calloc(howmany(max + 1, NFDBITS), sizeof(fd_mask)); if (readable == NULL) err(1, "out of memory"); writable = (fd_set *)calloc(howmany(max + 1, NFDBITS), sizeof(fd_mask)); if (writable == NULL) err(1, "out of memory"); omax = max; /* * note that calloc always returns 0'ed memory, * (unlike malloc) so these sets are all set to 0 * and ready to go */ } else { /* * our allocated sets are big enough, just make * sure they are cleared to 0. */ memset(readable, 0, howmany(max+1, NFDBITS) * sizeof(fd_mask)); memset(writable, 0, howmany(max+1, NFDBITS) * sizeof(fd_mask)); } /* * Now, we decide which sockets we are interested * in reading and writing, by setting the corresponding * bit in the readable and writable fd_sets. */ /* * we are always interesting in reading from the * listening socket. so put it in the read set. */ FD_SET(sd, readable); if (maxfd < sd) maxfd = sd; /* * now go through the list of connections, and if we * are interested in reading from, or writing to, the * connection's socket, put it in the readable, or * writable fd_set - in preparation to call select * to tell us which ones we can read and write to. */ for (i = 0; i<MAXCONN; i++) { if (connections[i].state == STATE_READING) { FD_SET(connections[i].sd, readable); if (maxfd < connections[i].sd) maxfd = connections[i].sd; } if (connections[i].state == STATE_WRITING) { FD_SET(connections[i].sd, writable); if (maxfd < connections[i].sd) maxfd = connections[i].sd; } } /* * finally, we can call select. we have filled in "readable" * and "writable" with everything we are interested in, and * when select returns, it will indicate in each fd_set * which sockets are readable and writable */ i = select(maxfd + 1, readable, writable, NULL,NULL); if (i == -1 && errno != EINTR) err(1, "select failed"); if (i > 0) { /* something is readable or writable... */ /* * First things first. check the listen socket. * If it was readable - we have a new connection * to accept. */ if (FD_ISSET(sd, readable)) { struct con *cp; int newsd; socklen_t slen; struct sockaddr_in sa; slen = sizeof(sa); newsd = accept(sd, (struct sockaddr *)&sa, &slen); if (newsd == -1) err(1, "accept failed"); cp = get_free_conn(); if (cp == NULL) { /* * we have no connection structures * so we close connection to our * client to not leave him hanging * because we are too busy to * service his request */ close(newsd); } else { /* * ok, if this worked, we now have a * new connection. set him up to be * READING so we do something with him */ cp->state = STATE_READING; cp->sd = newsd; cp->slen = slen; memcpy(&cp->sa, &sa, sizeof(sa)); } } /* * now, iterate through all of our connections, * check to see if they are readble or writable, * and if so, do a read or write accordingly */ for (i = 0; i<MAXCONN; i++) { if ((connections[i].state == STATE_READING) && FD_ISSET(connections[i].sd, readable)) handleread(&connections[i]); if ((connections[i].state == STATE_WRITING) && FD_ISSET(connections[i].sd, writable)) handlewrite(&connections[i]); } } } }