int rtk_intr(void *arg) { struct rtk_softc *sc; struct ifnet *ifp; uint16_t status; int handled; sc = arg; ifp = &sc->ethercom.ec_if; if (!device_has_power(sc->sc_dev)) return 0; /* Disable interrupts. */ CSR_WRITE_2(sc, RTK_IMR, 0x0000); handled = 0; for (;;) { status = CSR_READ_2(sc, RTK_ISR); if (status == 0xffff) break; /* Card is gone... */ if (status) CSR_WRITE_2(sc, RTK_ISR, status); if ((status & RTK_INTRS) == 0) break; handled = 1; if (status & RTK_ISR_RX_OK) rtk_rxeof(sc); if (status & RTK_ISR_RX_ERR) rtk_rxeof(sc); if (status & (RTK_ISR_TX_OK|RTK_ISR_TX_ERR)) rtk_txeof(sc); if (status & RTK_ISR_SYSTEM_ERR) { rtk_reset(sc); rtk_init(ifp); } } /* Re-enable interrupts. */ CSR_WRITE_2(sc, RTK_IMR, RTK_INTRS); if (IFQ_IS_EMPTY(&ifp->if_snd) == 0) rtk_start(ifp); rnd_add_uint32(&sc->rnd_source, status); return handled; }
// Main int main(int argc, char **argv) { playerc_client_t *client; rtk_app_t *app; mainwnd_t *mainwnd; opt_t *opt; const char *host; int port; int i; int count; double rate; char section[256]; int device_count; device_t devices[PLAYER_MAX_DEVICES]; device_t *device; struct timeval tv, tc = {0, 0}; struct timespec st = {0, (1.0/GUI_UPDATE_RATE) * 1e9}; printf("PlayerViewer %s\n", PLAYER_VERSION); // Initialise rtk lib (after we have read the program options we // want). rtk_init(&argc, &argv); // Register signal handlers signal(SIGINT, sig_quit); signal(SIGQUIT, sig_quit); // Load program options opt = opt_init(argc, argv, NULL); if (!opt) { print_usage(); return -1; } // Pick out some important program options host = opt_get_string(opt, "", "host", NULL); if (!host) host = opt_get_string(opt, "", "h", "localhost"); port = opt_get_int(opt, "", "port", -1); if (port < 0) port = opt_get_int(opt, "", "p", 6665); rate = opt_get_double(opt, "", "rate", 5.0); if(rate < 0.0) rate = 0.0; // Connect to the server printf("Connecting to [%s:%d]\n", host, port); client = playerc_client_create(NULL, host, port); if (playerc_client_connect(client) != 0) { PRINT_ERR1("%s", playerc_error_str()); print_usage(); return -1; } if(rate == 0.0) { printf("Setting delivery mode to PLAYER_DATAMODE_PUSH\n"); // Change the server's data delivery mode. if (playerc_client_set_replace_rule(client, -1, -1, -1, -1, 0) != 0) { PRINT_ERR1("%s", playerc_error_str()); return -1; } // Change the server's data delivery mode. // PLAYERC_DATAMODE_PUSH, PLAYERC_DATAMODE_PULL if (playerc_client_datamode(client, PLAYERC_DATAMODE_PUSH) != 0) { PRINT_ERR1("%s", playerc_error_str()); return -1; } } // Get the available devices. if (playerc_client_get_devlist(client) != 0) { PRINT_ERR1("%s", playerc_error_str()); return -1; } // Create gui app = rtk_app_create(); // Create a window for most of the sensor data mainwnd = mainwnd_create(app, host, port); if (!mainwnd) return -1; // Create a list of available devices, with their gui proxies. device_count = 0; for (i = 0; i < client->devinfo_count; i++) { device = devices + device_count; device->addr = client->devinfos[i].addr; device->drivername = strdup(client->devinfos[i].drivername); // See if the device should be subscribed immediately. snprintf(section, sizeof(section), "%s:%d", interf_to_str(device->addr.interf), device->addr.index); device->subscribe = opt_get_int(opt, section, "", 0); device->subscribe = opt_get_int(opt, section, "subscribe", device->subscribe); if (device->addr.index == 0) { snprintf(section, sizeof(section), "%s", interf_to_str(device->addr.interf)); device->subscribe = opt_get_int(opt, section, "", device->subscribe); device->subscribe = opt_get_int(opt, section, "subscribe", device->subscribe); } // Allow for --position instead of --position2d if(device->addr.interf == PLAYER_POSITION2D_CODE) { snprintf(section, sizeof(section), "%s:%d", PLAYER_POSITION2D_STRING, device->addr.index); device->subscribe = opt_get_int(opt, section, "", device->subscribe); device->subscribe = opt_get_int(opt, section, "subscribe", device->subscribe); if (device->addr.index == 0) { snprintf(section, sizeof(section), "%s", PLAYER_POSITION2D_STRING); device->subscribe = opt_get_int(opt, section, "", device->subscribe); device->subscribe = opt_get_int(opt, section, "subscribe", device->subscribe); } } // Create the GUI proxy for this device. create_proxy(device, opt, mainwnd, client); device_count++; } // Print the list of available devices. printf("Available devices: %s:%d\n", host, port); for (i = 0; i < device_count; i++) { device = devices + i; snprintf(section, sizeof(section), "%s:%d", interf_to_str(device->addr.interf), device->addr.index); printf("%-16s %-40s", section, device->drivername); if (device->proxy) { if (device->subscribe) printf("subscribed"); else printf("ready"); } else printf("unsupported"); printf("\n"); } // Print out a list of unused options. opt_warn_unused(opt); // Start the gui; dont run in a separate thread and dont let it do // its own updates. rtk_app_main_init(app); // start out timer if in pull mode if(rate > 0.0) gettimeofday(&tv, NULL); while (!quit) { // Let gui process messages rtk_app_main_loop(app); if(rate == 0.0) // if we're in push mode { // see if there's data count = playerc_client_peek(client, 50); if (count < 0) { PRINT_ERR1("%s", playerc_error_str()); break; } if (count > 0) { /*proxy = */playerc_client_read_nonblock(client); } } else // we're in pull mode { // we only want to request new data at the target rate gettimeofday(&tc, NULL); if(((tc.tv_sec - tv.tv_sec) + (tc.tv_usec - tv.tv_usec)/1e6) > 1.0/rate) { tv = tc; // this requests a round of data from the server to be read playerc_client_requestdata(client); playerc_client_read_nonblock(client); } else { // sleep for the minimum time we can, so we don't use up too much // processor nanosleep(&st, NULL); } } // Update the devices for (i = 0; i < device_count; i++) { device = devices + i; if(device->proxy) (*(device->fnupdate)) (device->proxy); } // Update the main window if (mainwnd_update(mainwnd) != 0) break; } // Stop the gui rtk_app_main_term(app); // Destroy devices for (i = 0; i < device_count; i++) { device = devices + i; if (device->proxy) (*(device->fndestroy)) (device->proxy); free(device->drivername); } // Disconnect from server if (playerc_client_disconnect(client) != 0) { PRINT_ERR1("%s", playerc_error_str()); return -1; } playerc_client_destroy(client); // For some reason, either of the following calls makes the program // segfault on exit. I haven't figured out why, so I'm commenting them out. - BPG // Destroy the windows //mainwnd_destroy(mainwnd); // Destroy the gui //rtk_app_destroy(app); opt_term(opt); return 0; }
/* * A frame has been uploaded: pass the resulting mbuf chain up to * the higher level protocols. * * You know there's something wrong with a PCI bus-master chip design. * * The receive operation is badly documented in the datasheet, so I'll * attempt to document it here. The driver provides a buffer area and * places its base address in the RX buffer start address register. * The chip then begins copying frames into the RX buffer. Each frame * is preceded by a 32-bit RX status word which specifies the length * of the frame and certain other status bits. Each frame (starting with * the status word) is also 32-bit aligned. The frame length is in the * first 16 bits of the status word; the lower 15 bits correspond with * the 'rx status register' mentioned in the datasheet. * * Note: to make the Alpha happy, the frame payload needs to be aligned * on a 32-bit boundary. To achieve this, we copy the data to mbuf * shifted forward 2 bytes. */ static void rtk_rxeof(struct rtk_softc *sc) { struct mbuf *m; struct ifnet *ifp; uint8_t *rxbufpos, *dst; u_int total_len, wrap; uint32_t rxstat; uint16_t cur_rx, new_rx; uint16_t limit; uint16_t rx_bytes, max_bytes; ifp = &sc->ethercom.ec_if; cur_rx = (CSR_READ_2(sc, RTK_CURRXADDR) + 16) % RTK_RXBUFLEN; /* Do not try to read past this point. */ limit = CSR_READ_2(sc, RTK_CURRXBUF) % RTK_RXBUFLEN; if (limit < cur_rx) max_bytes = (RTK_RXBUFLEN - cur_rx) + limit; else max_bytes = limit - cur_rx; rx_bytes = 0; while ((CSR_READ_1(sc, RTK_COMMAND) & RTK_CMD_EMPTY_RXBUF) == 0) { rxbufpos = sc->rtk_rx_buf + cur_rx; bus_dmamap_sync(sc->sc_dmat, sc->recv_dmamap, cur_rx, RTK_RXSTAT_LEN, BUS_DMASYNC_POSTREAD); rxstat = le32toh(*(uint32_t *)rxbufpos); bus_dmamap_sync(sc->sc_dmat, sc->recv_dmamap, cur_rx, RTK_RXSTAT_LEN, BUS_DMASYNC_PREREAD); /* * Here's a totally undocumented fact for you. When the * RealTek chip is in the process of copying a packet into * RAM for you, the length will be 0xfff0. If you spot a * packet header with this value, you need to stop. The * datasheet makes absolutely no mention of this and * RealTek should be shot for this. */ total_len = rxstat >> 16; if (total_len == RTK_RXSTAT_UNFINISHED) break; if ((rxstat & RTK_RXSTAT_RXOK) == 0 || total_len < ETHER_MIN_LEN || total_len > (MCLBYTES - RTK_ETHER_ALIGN)) { ifp->if_ierrors++; /* * submitted by:[netbsd-pcmcia:00484] * Takahiro Kambe <*****@*****.**> * obtain from: * FreeBSD if_rl.c rev 1.24->1.25 * */ #if 0 if (rxstat & (RTK_RXSTAT_BADSYM|RTK_RXSTAT_RUNT| RTK_RXSTAT_GIANT|RTK_RXSTAT_CRCERR| RTK_RXSTAT_ALIGNERR)) { CSR_WRITE_2(sc, RTK_COMMAND, RTK_CMD_TX_ENB); CSR_WRITE_2(sc, RTK_COMMAND, RTK_CMD_TX_ENB|RTK_CMD_RX_ENB); CSR_WRITE_4(sc, RTK_RXCFG, RTK_RXCFG_CONFIG); CSR_WRITE_4(sc, RTK_RXADDR, sc->recv_dmamap->dm_segs[0].ds_addr); cur_rx = 0; } break; #else rtk_init(ifp); return; #endif } /* No errors; receive the packet. */ rx_bytes += total_len + RTK_RXSTAT_LEN; /* * Avoid trying to read more bytes than we know * the chip has prepared for us. */ if (rx_bytes > max_bytes) break; /* * Skip the status word, wrapping around to the beginning * of the Rx area, if necessary. */ cur_rx = (cur_rx + RTK_RXSTAT_LEN) % RTK_RXBUFLEN; rxbufpos = sc->rtk_rx_buf + cur_rx; /* * Compute the number of bytes at which the packet * will wrap to the beginning of the ring buffer. */ wrap = RTK_RXBUFLEN - cur_rx; /* * Compute where the next pending packet is. */ if (total_len > wrap) new_rx = total_len - wrap; else new_rx = cur_rx + total_len; /* Round up to 32-bit boundary. */ new_rx = roundup2(new_rx, sizeof(uint32_t)) % RTK_RXBUFLEN; /* * The RealTek chip includes the CRC with every * incoming packet; trim it off here. */ total_len -= ETHER_CRC_LEN; /* * Now allocate an mbuf (and possibly a cluster) to hold * the packet. Note we offset the packet 2 bytes so that * data after the Ethernet header will be 4-byte aligned. */ MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) { printf("%s: unable to allocate Rx mbuf\n", device_xname(sc->sc_dev)); ifp->if_ierrors++; goto next_packet; } if (total_len > (MHLEN - RTK_ETHER_ALIGN)) { MCLGET(m, M_DONTWAIT); if ((m->m_flags & M_EXT) == 0) { printf("%s: unable to allocate Rx cluster\n", device_xname(sc->sc_dev)); ifp->if_ierrors++; m_freem(m); m = NULL; goto next_packet; } } m->m_data += RTK_ETHER_ALIGN; /* for alignment */ m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = total_len; dst = mtod(m, void *); /* * If the packet wraps, copy up to the wrapping point. */ if (total_len > wrap) { bus_dmamap_sync(sc->sc_dmat, sc->recv_dmamap, cur_rx, wrap, BUS_DMASYNC_POSTREAD); memcpy(dst, rxbufpos, wrap); bus_dmamap_sync(sc->sc_dmat, sc->recv_dmamap, cur_rx, wrap, BUS_DMASYNC_PREREAD); cur_rx = 0; rxbufpos = sc->rtk_rx_buf; total_len -= wrap; dst += wrap; } /* * ...and now the rest. */ bus_dmamap_sync(sc->sc_dmat, sc->recv_dmamap, cur_rx, total_len, BUS_DMASYNC_POSTREAD); memcpy(dst, rxbufpos, total_len); bus_dmamap_sync(sc->sc_dmat, sc->recv_dmamap, cur_rx, total_len, BUS_DMASYNC_PREREAD); next_packet: CSR_WRITE_2(sc, RTK_CURRXADDR, (new_rx - 16) % RTK_RXBUFLEN); cur_rx = new_rx; if (m == NULL) continue; ifp->if_ipackets++; bpf_mtap(ifp, m); /* pass it on. */ (*ifp->if_input)(ifp, m); } }