static int control_write(struct vhci_usb_t * p, struct _ep * ep, uint8_t reqtype, uint8_t req, uint16_t wValue, uint16_t wIndex, uint16_t wLength, uint8_t * data) { assert((reqtype&0x80)==0); int ret; struct usbsetup buf = {reqtype,req,wValue,wIndex,wLength}; struct avr_io_usb pkt = {ep->epnum,sizeof (struct usbsetup), (char*)&buf}; avr_ioctl(p->avr, AVR_IOCTL_USB_SETUP, &pkt); usleep(10000); if (wLength>0) { pkt.sz = (wLength>ep->epsz ? ep->epsz : wLength); pkt.buf = data; while ( ret = avr_ioctl(p->avr, AVR_IOCTL_USB_WRITE, &pkt)) { if (ret==AVR_IOCTL_USB_NAK) {usleep(50000); continue; } if (ret==AVR_IOCTL_USB_STALL) {printf(" STALL\n"); return ret;} assert(ret==0); if (pkt.sz != ep->epsz) break; pkt.buf+=pkt.sz; wLength-=pkt.sz; pkt.sz = (wLength>ep->epsz ? ep->epsz : wLength); } } pkt.sz=0; while ( (ret = avr_ioctl(p->avr, AVR_IOCTL_USB_READ, &pkt)) == AVR_IOCTL_USB_NAK) { usleep(50000); } return ret; }
static void handle_status_change( struct vhci_usb_t * p, struct usb_vhci_port_stat*prev, struct usb_vhci_port_stat*curr) { if (~prev->status & USB_VHCI_PORT_STAT_POWER && curr->status & USB_VHCI_PORT_STAT_POWER) { avr_ioctl(p->avr, AVR_IOCTL_USB_VBUS, (void*) 1); if (p->attached) { if (usb_vhci_port_connect(p->fd, 1, USB_VHCI_DATA_RATE_FULL) < 0) { perror("port_connect"); abort(); } } } if (prev->status & USB_VHCI_PORT_STAT_POWER && ~curr->status & USB_VHCI_PORT_STAT_POWER) avr_ioctl(p->avr, AVR_IOCTL_USB_VBUS, 0); if (curr->change & USB_VHCI_PORT_STAT_C_RESET && ~curr->status & USB_VHCI_PORT_STAT_RESET && curr->status & USB_VHCI_PORT_STAT_ENABLE) { // printf("END OF RESET\n"); } if (~prev->status & USB_VHCI_PORT_STAT_RESET && curr->status & USB_VHCI_PORT_STAT_RESET) { avr_ioctl(p->avr, AVR_IOCTL_USB_RESET, NULL); usleep(50000); if (curr->status & USB_VHCI_PORT_STAT_CONNECTION) { if (usb_vhci_port_reset_done(p->fd, 1, 1) < 0) { perror("reset_done"); abort(); } } } if (~prev->flags & USB_VHCI_PORT_STAT_FLAG_RESUMING && curr->flags & USB_VHCI_PORT_STAT_FLAG_RESUMING) { printf("port resuming\n"); if (curr->status & USB_VHCI_PORT_STAT_CONNECTION) { printf(" completing\n"); if (usb_vhci_port_resumed(p->fd, 1) < 0) { perror("resumed"); abort(); } } } if (~prev->status & USB_VHCI_PORT_STAT_SUSPEND && curr->status & USB_VHCI_PORT_STAT_SUSPEND) printf("port suspedning\n"); if (prev->status & USB_VHCI_PORT_STAT_ENABLE && ~curr->status & USB_VHCI_PORT_STAT_ENABLE) printf("port disabled\n"); *prev = *curr; }
void uart_udp_connect(uart_udp_t * p, char uart) { // disable the stdio dump, as we are sending binary there uint32_t f = 0; avr_ioctl(p->avr, AVR_IOCTL_UART_GET_FLAGS(uart), &f); f &= ~AVR_UART_FLAG_STDIO; avr_ioctl(p->avr, AVR_IOCTL_UART_SET_FLAGS(uart), &f); avr_irq_t * src = avr_io_getirq(p->avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_OUTPUT); avr_irq_t * dst = avr_io_getirq(p->avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_INPUT); avr_irq_t * xon = avr_io_getirq(p->avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_OUT_XON); avr_irq_t * xoff = avr_io_getirq(p->avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_OUT_XOFF); if (src && dst) { avr_connect_irq(src, p->irq + IRQ_UART_UDP_BYTE_IN); avr_connect_irq(p->irq + IRQ_UART_UDP_BYTE_OUT, dst); } if (xon) avr_irq_register_notify(xon, uart_udp_xon_hook, p); if (xoff) avr_irq_register_notify(xoff, uart_udp_xoff_hook, p); }
static void avr_timer_reset(avr_io_t * port) { avr_timer_t * p = (avr_timer_t *)port; avr_cycle_timer_cancel(p->io.avr, avr_timer_tov, p); avr_cycle_timer_cancel(p->io.avr, avr_timer_compa, p); avr_cycle_timer_cancel(p->io.avr, avr_timer_compb, p); avr_cycle_timer_cancel(p->io.avr, avr_timer_compc, p); // check to see if the comparators have a pin output. If they do, // (try) to get the ioport corresponding IRQ and connect them // they will automagically be triggered when the comparator raises // it's own IRQ for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) { p->comp[compi].comp_cycles = 0; avr_ioport_getirq_t req = { .bit = p->comp[compi].com_pin }; if (avr_ioctl(port->avr, AVR_IOCTL_IOPORT_GETIRQ_REGBIT, &req) > 0) { // cool, got an IRQ // printf("%s-%c COMP%c Connecting PIN IRQ %d\n", __FUNCTION__, p->name, 'A'+compi, req.irq[0]->irq); avr_connect_irq(&port->irq[TIMER_IRQ_OUT_COMP + compi], req.irq[0]); } } avr_ioport_getirq_t req = { .bit = p->icp }; if (avr_ioctl(port->avr, AVR_IOCTL_IOPORT_GETIRQ_REGBIT, &req) > 0) { // cool, got an IRQ for the input capture pin // printf("%s-%c ICP Connecting PIN IRQ %d\n", __FUNCTION__, p->name, req.irq[0]->irq); avr_irq_register_notify(req.irq[0], avr_timer_irq_icp, p); } } static const char * irq_names[TIMER_IRQ_COUNT] = { [TIMER_IRQ_OUT_PWM0] = "8>pwm0", [TIMER_IRQ_OUT_PWM1] = "8>pwm1", [TIMER_IRQ_OUT_COMP + 0] = ">compa", [TIMER_IRQ_OUT_COMP + 1] = ">compb", [TIMER_IRQ_OUT_COMP + 2] = ">compc", }; static avr_io_t _io = { .kind = "timer", .reset = avr_timer_reset, .irq_names = irq_names, }; void avr_timer_init(avr_t * avr, avr_timer_t * p) { p->io = _io; avr_register_io(avr, &p->io); avr_register_vector(avr, &p->overflow); avr_register_vector(avr, &p->icr); // allocate this module's IRQ avr_io_setirqs(&p->io, AVR_IOCTL_TIMER_GETIRQ(p->name), TIMER_IRQ_COUNT, NULL); // marking IRQs as "filtered" means they don't propagate if the // new value raised is the same as the last one.. in the case of the // pwm value it makes sense not to bother. p->io.irq[TIMER_IRQ_OUT_PWM0].flags |= IRQ_FLAG_FILTERED; p->io.irq[TIMER_IRQ_OUT_PWM1].flags |= IRQ_FLAG_FILTERED; if (p->wgm[0].reg) // these are not present on older AVRs avr_register_io_write(avr, p->wgm[0].reg, avr_timer_write, p); avr_register_io_write(avr, p->cs[0].reg, avr_timer_write, p); // this assumes all the "pending" interrupt bits are in the same // register. Might not be true on all devices ? avr_register_io_write(avr, p->overflow.raised.reg, avr_timer_write_pending, p); /* * Even if the timer is 16 bits, we don't care to have watches on the * high bytes because the datasheet says that the low address is always * the trigger. */ for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) { avr_register_vector(avr, &p->comp[compi].interrupt); if (p->comp[compi].r_ocr) // not all timers have all comparators avr_register_io_write(avr, p->comp[compi].r_ocr, avr_timer_write_ocr, p); } avr_register_io_write(avr, p->r_tcnt, avr_timer_tcnt_write, p); avr_register_io_read(avr, p->r_tcnt, avr_timer_tcnt_read, p); }
static void * vhci_usb_thread( void * param) { struct vhci_usb_t * p = (struct vhci_usb_t*) param; struct _ep ep0 = { 0, 0 }; struct usb_vhci_port_stat port_status; int id, busnum; char*busid; p->fd = usb_vhci_open(1, &id, &busnum, &busid); if (p->fd < 0) { perror("open vhci failed"); printf("driver loaded, and access bits ok?\n"); abort(); } printf("Created virtual usb host with 1 port at %s (bus# %d)\n", busid, busnum); memset(&port_status, 0, sizeof port_status); bool avrattached = false; for (unsigned cycle = 0;; cycle++) { struct usb_vhci_work wrk; int res = usb_vhci_fetch_work(p->fd, &wrk); if (p->attached != avrattached) { if (p->attached && port_status.status & USB_VHCI_PORT_STAT_POWER) { if (usb_vhci_port_connect(p->fd, 1, USB_VHCI_DATA_RATE_FULL) < 0) { perror("port_connect"); abort(); } } if (!p->attached) { ep0.epsz = 0; //disconnect } avrattached = p->attached; } if (res < 0) { if (errno == ETIMEDOUT || errno == EINTR || errno == ENODATA) continue; perror("fetch work failed"); abort(); } switch (wrk.type) { case USB_VHCI_WORK_TYPE_PORT_STAT: handle_status_change(p, &port_status, &wrk.work.port_stat); break; case USB_VHCI_WORK_TYPE_PROCESS_URB: if (!ep0.epsz) ep0.epsz = get_ep0_size(p); wrk.work.urb.buffer = 0; wrk.work.urb.iso_packets = 0; if (wrk.work.urb.buffer_length) wrk.work.urb.buffer = malloc(wrk.work.urb.buffer_length); if (wrk.work.urb.packet_count) wrk.work.urb.iso_packets = malloc( wrk.work.urb.packet_count * sizeof(struct usb_vhci_iso_packet)); if (res) { if (usb_vhci_fetch_data(p->fd, &wrk.work.urb) < 0) { if (errno != ECANCELED) perror("fetch_data"); free(wrk.work.urb.buffer); free(wrk.work.urb.iso_packets); usb_vhci_giveback(p->fd, &wrk.work.urb); break; } } if (usb_vhci_is_control(wrk.work.urb.type) && !(wrk.work.urb.epadr & 0x7f)) { handle_ep0_control(p, &ep0, &wrk.work.urb); } else { struct avr_io_usb pkt = { wrk.work.urb.epadr, wrk.work.urb.buffer_actual, wrk.work.urb.buffer }; if (usb_vhci_is_out(wrk.work.urb.epadr)) res = avr_ioctl(p->avr, AVR_IOCTL_USB_WRITE, &pkt); else { pkt.sz = wrk.work.urb.buffer_length; res = avr_ioctl(p->avr, AVR_IOCTL_USB_READ, &pkt); wrk.work.urb.buffer_actual = pkt.sz; } if (res == AVR_IOCTL_USB_STALL) wrk.work.urb.status = USB_VHCI_STATUS_STALL; else if (res == AVR_IOCTL_USB_NAK) wrk.work.urb.status = USB_VHCI_STATUS_TIMEDOUT; else wrk.work.urb.status = USB_VHCI_STATUS_SUCCESS; } if (usb_vhci_giveback(p->fd, &wrk.work.urb) < 0) perror("giveback"); free(wrk.work.urb.buffer); free(wrk.work.urb.iso_packets); break; case USB_VHCI_WORK_TYPE_CANCEL_URB: printf("cancel urb\n"); break; default: printf("illegal work type\n"); abort(); } } }