1 /* vim: set sts=4:sw=4:ts=4:noexpandtab
4 Copyright 2012 Torbjorn Tyridal <ttyridal@gmail.com>
6 This file is part of simavr.
8 simavr is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 simavr is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with simavr. If not, see <http://www.gnu.org/licenses/>.
23 this avrsim part is an usb connection between an usb AVR and the virtual
24 host controller interface vhci-usb - making your sim-avr connect as a real
25 usb device to the developer machine.
27 You'll need vhci-usb and libusb_vhci to make it work.
28 http://sourceforge.net/projects/usb-vhci/
31 /* TODO iso endpoint support */
34 #include "libusb_vhci.h"
48 struct avr_irq_t * irq,
52 struct vhci_usb_t * p = (struct vhci_usb_t*) param;
53 p->attached = !!value;
54 printf("avr attached: %d\n", p->attached);
58 uint8_t reqtype; uint8_t req; uint16_t wValue; uint16_t wIndex; uint16_t wLength;
59 }__attribute__((__packed__));
66 char * setuprequests[] =
67 { "GET_STATUS", "CLEAR_FEAT", "", "SET_FEAT", "", "SET_ADDR", "GET_DESCR",
68 "SET_DESCR", "GET_CONF", "SET_CONF" };
72 struct vhci_usb_t * p,
84 { reqtype, req, wValue, wIndex, wLength };
85 struct avr_io_usb pkt =
86 { ep->epnum, sizeof(struct usbsetup), (uint8_t*) &buf };
88 avr_ioctl(p->avr, AVR_IOCTL_USB_SETUP, &pkt);
94 ret = avr_ioctl(p->avr, AVR_IOCTL_USB_READ, &pkt);
95 if (ret == AVR_IOCTL_USB_NAK) {
100 if (ret == AVR_IOCTL_USB_STALL) {
106 if (ep->epsz != pkt.sz)
111 wLength = pkt.buf - data;
115 while ((ret = avr_ioctl(p->avr, AVR_IOCTL_USB_WRITE, &pkt))
116 == AVR_IOCTL_USB_NAK) {
125 struct vhci_usb_t * p,
134 assert((reqtype&0x80)==0);
136 struct usbsetup buf =
137 { reqtype, req, wValue, wIndex, wLength };
138 struct avr_io_usb pkt =
139 { ep->epnum, sizeof(struct usbsetup), (uint8_t*) &buf };
141 avr_ioctl(p->avr, AVR_IOCTL_USB_SETUP, &pkt);
145 pkt.sz = (wLength > ep->epsz ? ep->epsz : wLength);
147 while ((ret = avr_ioctl(p->avr, AVR_IOCTL_USB_WRITE, &pkt)) != 0) {
148 if (ret == AVR_IOCTL_USB_NAK) {
152 if (ret == AVR_IOCTL_USB_STALL) {
157 if (pkt.sz != ep->epsz)
161 pkt.sz = (wLength > ep->epsz ? ep->epsz : wLength);
166 while ((ret = avr_ioctl(p->avr, AVR_IOCTL_USB_READ, &pkt))
167 == AVR_IOCTL_USB_NAK) {
174 handle_status_change(
175 struct vhci_usb_t * p,
176 struct usb_vhci_port_stat*prev,
177 struct usb_vhci_port_stat*curr)
179 if (~prev->status & USB_VHCI_PORT_STAT_POWER
180 && curr->status & USB_VHCI_PORT_STAT_POWER) {
181 avr_ioctl(p->avr, AVR_IOCTL_USB_VBUS, (void*) 1);
183 if (usb_vhci_port_connect(p->fd, 1, USB_VHCI_DATA_RATE_FULL) < 0) {
184 perror("port_connect");
189 if (prev->status & USB_VHCI_PORT_STAT_POWER
190 && ~curr->status & USB_VHCI_PORT_STAT_POWER)
191 avr_ioctl(p->avr, AVR_IOCTL_USB_VBUS, 0);
193 if (curr->change & USB_VHCI_PORT_STAT_C_RESET
194 && ~curr->status & USB_VHCI_PORT_STAT_RESET
195 && curr->status & USB_VHCI_PORT_STAT_ENABLE) {
196 // printf("END OF RESET\n");
198 if (~prev->status & USB_VHCI_PORT_STAT_RESET
199 && curr->status & USB_VHCI_PORT_STAT_RESET) {
200 avr_ioctl(p->avr, AVR_IOCTL_USB_RESET, NULL);
202 if (curr->status & USB_VHCI_PORT_STAT_CONNECTION) {
203 if (usb_vhci_port_reset_done(p->fd, 1, 1) < 0) {
204 perror("reset_done");
209 if (~prev->flags & USB_VHCI_PORT_STAT_FLAG_RESUMING
210 && curr->flags & USB_VHCI_PORT_STAT_FLAG_RESUMING) {
211 printf("port resuming\n");
212 if (curr->status & USB_VHCI_PORT_STAT_CONNECTION) {
213 printf(" completing\n");
214 if (usb_vhci_port_resumed(p->fd, 1) < 0) {
220 if (~prev->status & USB_VHCI_PORT_STAT_SUSPEND
221 && curr->status & USB_VHCI_PORT_STAT_SUSPEND)
222 printf("port suspedning\n");
223 if (prev->status & USB_VHCI_PORT_STAT_ENABLE
224 && ~curr->status & USB_VHCI_PORT_STAT_ENABLE)
225 printf("port disabled\n");
232 struct vhci_usb_t * p)
238 int res = control_read(p, &ep0, 0x80, 6, 1 << 8, 0, 8, data);
245 struct vhci_usb_t * p,
247 struct usb_vhci_urb * urb)
250 if (urb->bmRequestType &0x80) {
251 res = control_read(p,ep0,
259 urb->buffer_actual=res;
264 res = control_write(p,ep0,
272 if (res==AVR_IOCTL_USB_STALL)
273 urb->status = USB_VHCI_STATUS_STALL;
275 urb->status = USB_VHCI_STATUS_SUCCESS;
282 struct vhci_usb_t * p = (struct vhci_usb_t*) param;
285 struct usb_vhci_port_stat port_status;
288 p->fd = usb_vhci_open(1, &id, &busnum, &busid);
291 perror("open vhci failed");
292 printf("driver loaded, and access bits ok?\n");
295 printf("Created virtual usb host with 1 port at %s (bus# %d)\n", busid,
297 memset(&port_status, 0, sizeof port_status);
299 bool avrattached = false;
301 for (unsigned cycle = 0;; cycle++) {
302 struct usb_vhci_work wrk;
304 int res = usb_vhci_fetch_work(p->fd, &wrk);
306 if (p->attached != avrattached) {
307 if (p->attached && port_status.status & USB_VHCI_PORT_STAT_POWER) {
308 if (usb_vhci_port_connect(p->fd, 1, USB_VHCI_DATA_RATE_FULL)
310 perror("port_connect");
318 avrattached = p->attached;
322 if (errno == ETIMEDOUT || errno == EINTR || errno == ENODATA)
324 perror("fetch work failed");
329 case USB_VHCI_WORK_TYPE_PORT_STAT:
330 handle_status_change(p, &port_status, &wrk.work.port_stat);
332 case USB_VHCI_WORK_TYPE_PROCESS_URB:
334 ep0.epsz = get_ep0_size(p);
336 wrk.work.urb.buffer = 0;
337 wrk.work.urb.iso_packets = 0;
338 if (wrk.work.urb.buffer_length)
339 wrk.work.urb.buffer = malloc(wrk.work.urb.buffer_length);
340 if (wrk.work.urb.packet_count)
341 wrk.work.urb.iso_packets = malloc(
342 wrk.work.urb.packet_count
343 * sizeof(struct usb_vhci_iso_packet));
345 if (usb_vhci_fetch_data(p->fd, &wrk.work.urb) < 0) {
346 if (errno != ECANCELED)
347 perror("fetch_data");
348 free(wrk.work.urb.buffer);
349 free(wrk.work.urb.iso_packets);
350 usb_vhci_giveback(p->fd, &wrk.work.urb);
355 if (usb_vhci_is_control(wrk.work.urb.type)
356 && !(wrk.work.urb.epadr & 0x7f)) {
357 handle_ep0_control(p, &ep0, &wrk.work.urb);
360 struct avr_io_usb pkt =
361 { wrk.work.urb.epadr, wrk.work.urb.buffer_actual,
362 wrk.work.urb.buffer };
363 if (usb_vhci_is_out(wrk.work.urb.epadr))
364 res = avr_ioctl(p->avr, AVR_IOCTL_USB_WRITE, &pkt);
366 pkt.sz = wrk.work.urb.buffer_length;
367 res = avr_ioctl(p->avr, AVR_IOCTL_USB_READ, &pkt);
368 wrk.work.urb.buffer_actual = pkt.sz;
370 if (res == AVR_IOCTL_USB_STALL)
371 wrk.work.urb.status = USB_VHCI_STATUS_STALL;
372 else if (res == AVR_IOCTL_USB_NAK)
373 wrk.work.urb.status = USB_VHCI_STATUS_TIMEDOUT;
375 wrk.work.urb.status = USB_VHCI_STATUS_SUCCESS;
377 if (usb_vhci_giveback(p->fd, &wrk.work.urb) < 0)
379 free(wrk.work.urb.buffer);
380 free(wrk.work.urb.iso_packets);
382 case USB_VHCI_WORK_TYPE_CANCEL_URB:
383 printf("cancel urb\n");
386 printf("illegal work type\n");
396 struct vhci_usb_t * p)
401 pthread_create(&thread, NULL, vhci_usb_thread, p);
407 struct vhci_usb_t * p,
410 avr_irq_t * t = avr_io_getirq(p->avr, AVR_IOCTL_USB_GETIRQ(),
412 avr_irq_register_notify(t, vhci_usb_attach_hook, p);