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"
46 static void vhci_usb_attach_hook(struct avr_irq_t * irq, uint32_t value, void * param)
48 struct vhci_usb_t * p = (struct vhci_usb_t*)param;
50 printf("avr attached: %d\n",p->attached);
54 uint8_t reqtype; uint8_t req; uint16_t wValue; uint16_t wIndex; uint16_t wLength;
55 }__attribute__((__packed__));
62 char * setuprequests[] = {"GET_STATUS","CLEAR_FEAT","","SET_FEAT","","SET_ADDR","GET_DESCR","SET_DESCR","GET_CONF","SET_CONF"};
64 static int control_read(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)
68 struct usbsetup buf = {reqtype,req,wValue,wIndex,wLength};
69 struct avr_io_usb pkt = {ep->epnum,sizeof (struct usbsetup), (char*)&buf};
71 avr_ioctl(p->avr, AVR_IOCTL_USB_SETUP, &pkt);
77 ret = avr_ioctl(p->avr, AVR_IOCTL_USB_READ, &pkt);
78 if (ret==AVR_IOCTL_USB_NAK) {printf(" NAK\n");usleep(50000); continue; }
79 if (ret==AVR_IOCTL_USB_STALL) {printf(" STALL\n"); return ret;}
82 if (ep->epsz != pkt.sz) break;
90 while ( (ret = avr_ioctl(p->avr, AVR_IOCTL_USB_WRITE, &pkt)) == AVR_IOCTL_USB_NAK) {
97 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)
99 assert((reqtype&0x80)==0);
101 struct usbsetup buf = {reqtype,req,wValue,wIndex,wLength};
102 struct avr_io_usb pkt = {ep->epnum,sizeof (struct usbsetup), (char*)&buf};
104 avr_ioctl(p->avr, AVR_IOCTL_USB_SETUP, &pkt);
108 pkt.sz = (wLength>ep->epsz ? ep->epsz : wLength);
110 while ( ret = avr_ioctl(p->avr, AVR_IOCTL_USB_WRITE, &pkt)) {
111 if (ret==AVR_IOCTL_USB_NAK) {usleep(50000); continue; }
112 if (ret==AVR_IOCTL_USB_STALL) {printf(" STALL\n"); return ret;}
114 if (pkt.sz != ep->epsz) break;
117 pkt.sz = (wLength>ep->epsz ? ep->epsz : wLength);
122 while ( (ret = avr_ioctl(p->avr, AVR_IOCTL_USB_READ, &pkt)) == AVR_IOCTL_USB_NAK) {
129 static void handle_status_change(struct vhci_usb_t * p, struct usb_vhci_port_stat*prev, struct usb_vhci_port_stat*curr)
131 if (~prev->status & USB_VHCI_PORT_STAT_POWER && curr->status & USB_VHCI_PORT_STAT_POWER) {
132 avr_ioctl(p->avr, AVR_IOCTL_USB_VBUS, (void*)1);
134 if (usb_vhci_port_connect(p->fd, 1, USB_VHCI_DATA_RATE_FULL) <0) {
135 perror("port_connect");
140 if (prev->status & USB_VHCI_PORT_STAT_POWER && ~curr->status & USB_VHCI_PORT_STAT_POWER)
141 avr_ioctl(p->avr, AVR_IOCTL_USB_VBUS, 0);
143 if (curr->change & USB_VHCI_PORT_STAT_C_RESET &&
144 ~curr->status & USB_VHCI_PORT_STAT_RESET &&
145 curr->status & USB_VHCI_PORT_STAT_ENABLE) {
146 // printf("END OF RESET\n");
148 if (~prev->status & USB_VHCI_PORT_STAT_RESET &&
149 curr->status & USB_VHCI_PORT_STAT_RESET) {
150 avr_ioctl(p->avr, AVR_IOCTL_USB_RESET, NULL);
152 if (curr->status & USB_VHCI_PORT_STAT_CONNECTION) {
153 if (usb_vhci_port_reset_done(p->fd,1,1)<0) {
154 perror("reset_done");
159 if (~prev->flags & USB_VHCI_PORT_STAT_FLAG_RESUMING &&
160 curr->flags & USB_VHCI_PORT_STAT_FLAG_RESUMING) {
161 printf("port resuming\n");
162 if (curr->status & USB_VHCI_PORT_STAT_CONNECTION) {
163 printf(" completing\n");
164 if (usb_vhci_port_resumed(p->fd,1)<0) {
170 if (~prev->status & USB_VHCI_PORT_STAT_SUSPEND &&
171 curr->status & USB_VHCI_PORT_STAT_SUSPEND)
172 printf("port suspedning\n");
173 if (prev->status & USB_VHCI_PORT_STAT_ENABLE &&
174 ~curr->status & USB_VHCI_PORT_STAT_ENABLE)
175 printf("port disabled\n");
180 static int get_ep0_size(struct vhci_usb_t * p)
182 struct _ep ep0 = {0,8};
185 int res = control_read(p, &ep0, 0x80, 6, 1<<8,0,8,data);
190 static void handle_ep0_control(struct vhci_usb_t * p, struct _ep * ep0, struct usb_vhci_urb * urb)
193 if (urb->bmRequestType &0x80) {
194 res = control_read(p,ep0,
202 urb->buffer_actual=res;
207 res = control_write(p,ep0,
215 if (res==AVR_IOCTL_USB_STALL)
216 urb->status = USB_VHCI_STATUS_STALL;
218 urb->status = USB_VHCI_STATUS_SUCCESS;
222 static void * vhci_usb_thread(void * param)
224 struct vhci_usb_t * p = (struct vhci_usb_t*)param;
225 struct _ep ep0 = {0,0};
226 struct usb_vhci_port_stat port_status;
227 int id,busnum;char*busid;
228 p->fd = usb_vhci_open(1, &id, &busnum, &busid);
232 perror("open vhci failed");
233 printf("driver loaded, and access bits ok?\n");
236 printf("Created virtual usb host with 1 port at %s (bus# %d)\n",busid,busnum);
237 memset(&port_status,0,sizeof port_status);
239 bool avrattached=false;
241 for(unsigned cycle=0;;cycle++) {
242 struct usb_vhci_work wrk;
244 int res = usb_vhci_fetch_work(p->fd, &wrk);
246 if (p->attached != avrattached) {
247 if (p->attached && port_status.status & USB_VHCI_PORT_STAT_POWER) {
248 if (usb_vhci_port_connect(p->fd, 1, USB_VHCI_DATA_RATE_FULL) <0) {
249 perror("port_connect");
257 avrattached=p->attached;
261 if( errno == ETIMEDOUT || errno == EINTR || errno == ENODATA) continue;
262 perror("fetch work failed");
267 case USB_VHCI_WORK_TYPE_PORT_STAT:
268 handle_status_change(p, &port_status, &wrk.work.port_stat);
270 case USB_VHCI_WORK_TYPE_PROCESS_URB:
272 ep0.epsz = get_ep0_size(p);
274 wrk.work.urb.buffer=0;
275 wrk.work.urb.iso_packets=0;
276 if (wrk.work.urb.buffer_length)
277 wrk.work.urb.buffer = malloc(wrk.work.urb.buffer_length);
278 if (wrk.work.urb.packet_count)
279 wrk.work.urb.iso_packets = malloc(wrk.work.urb.packet_count * sizeof (struct usb_vhci_iso_packet));
281 if (usb_vhci_fetch_data(p->fd, &wrk.work.urb)<0) {
282 if (errno != ECANCELED) perror("fetch_data");
283 free(wrk.work.urb.buffer);
284 free(wrk.work.urb.iso_packets);
285 usb_vhci_giveback(p->fd, &wrk.work.urb);
290 if(usb_vhci_is_control(wrk.work.urb.type) && !(wrk.work.urb.epadr & 0x7f)) {
291 handle_ep0_control(p, &ep0, &wrk.work.urb);
294 struct avr_io_usb pkt = {wrk.work.urb.epadr, wrk.work.urb.buffer_actual, wrk.work.urb.buffer};
295 if (usb_vhci_is_out(wrk.work.urb.epadr))
296 res=avr_ioctl(p->avr, AVR_IOCTL_USB_WRITE, &pkt);
298 pkt.sz = wrk.work.urb.buffer_length;
299 res=avr_ioctl(p->avr, AVR_IOCTL_USB_READ, &pkt);
300 wrk.work.urb.buffer_actual=pkt.sz;
302 if (res==AVR_IOCTL_USB_STALL)
303 wrk.work.urb.status = USB_VHCI_STATUS_STALL;
304 else if (res==AVR_IOCTL_USB_NAK)
305 wrk.work.urb.status = USB_VHCI_STATUS_TIMEDOUT;
307 wrk.work.urb.status = USB_VHCI_STATUS_SUCCESS;
309 if (usb_vhci_giveback(p->fd, &wrk.work.urb)<0)
311 free(wrk.work.urb.buffer);
312 free(wrk.work.urb.iso_packets);
314 case USB_VHCI_WORK_TYPE_CANCEL_URB:
315 printf("cancel urb\n");
318 printf("illegal work type\n");
326 void vhci_usb_init(struct avr_t * avr, struct vhci_usb_t * p)
331 pthread_create(&thread, NULL, vhci_usb_thread, p);
335 void vhci_usb_connect(struct vhci_usb_t * p, char uart)
337 avr_irq_t * t = avr_io_getirq(p->avr, AVR_IOCTL_USB_GETIRQ(), USB_IRQ_ATTACH);
338 avr_irq_register_notify(t, vhci_usb_attach_hook, p);