Beispiel #1
0
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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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);
}
Beispiel #4
0
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);
}
Beispiel #5
0
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();
		}

	}
}