1 /*
2  * USB host chip emulation
3  *
4  * Copyright (c) 2012-2015 David Galvez. ARAnyM development team (see AUTHORS).
5  *
6  * This file is part of the ARAnyM project which builds a new and powerful
7  * TOS/FreeMiNT compatible virtual machine running on almost any hardware.
8  *
9  * ARAnyM is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * ARAnyM is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with ARAnyM; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23 
24 #include "sysdeps.h"
25 #include "usbhost.h"
26 #include "../../atari/usbhost/usbhost_nfapi.h"
27 
28 #define DEBUG 0
29 #include "debug.h"
30 
31 #include "SDL_compat.h"
32 #include <SDL_thread.h>
33 
34 /*--- Defines ---*/
35 
36 #define EINVFN	-32
37 
38 #define min1_t(type,x,y)	\
39 	({ type __x = (x); type __y = (y); __x < __y ? __x : __y; })
40 
41 /* Galvez: added to avoid the variables being shadowed warning */
42 #define min2_t(type,x,y)	\
43 	({ type __a = (x); type __b = (y); __a < __b ? __a : __b; })
44 
45 /* USBHOst runs at interrupt level 5 by default but can be reconfigured */
46 #if 0
47 # define INTLEVEL	3
48 # define TRIGGER_INTERRUPT	TriggerInt3()
49 #else
50 # define INTLEVEL	5
51 # define TRIGGER_INTERRUPT	TriggerInt5()
52 #endif
53 
54 /* --- Virtual Root Hub ---------------------------------------------------- */
55 
56 /* Device descriptor */
57 
58 static uint8 root_hub_dev_des[] = {
59 	0x12,			/*  uint8  bLength; */
60 	0x01,			/*  uint8  bDescriptorType; Device */
61 	0x00,			/*  uint16 bcdUSB; v1.1 */
62 	0x02,
63 	0x09,			/*  uint8  bDeviceClass; HUB_CLASSCODE */
64 	0x00,			/*  uint8  bDeviceSubClass; */
65 	0x00,			/*  uint8  bDeviceProtocol; */
66 	0x08,			/*  uint8  bMaxPacketSize0; 8 Bytes */
67 	0x00,			/*  uint16 idVendor; */
68 	0x00,
69 	0x00,			/*  uint16 idProduct; */
70 	0x00,
71 	0x00,			/*  uint16 bcdDevice; */
72 	0x00,
73 	0x00,			/*  uint8  iManufacturer; */
74 	0x01,			/*  uint8  iProduct; */
75 	0x00,			/*  uint8  iSerialNumber; */
76 	0x01			/*  uint8  bNumConfigurations; */
77 };
78 
79 /* Configuration descriptor */
80 
81 static uint8 root_hub_config_des[] = {
82 	0x09,			/*  uint8  bLength; */
83 	0x02,			/*  uint8  bDescriptorType; Configuration */
84 	0x19,			/*  uint16 wTotalLength; */
85 	0x00,
86 	0x01,			/*  uint8  bNumInterfaces; */
87 	0x01,			/*  uint8  bConfigurationValue; */
88 	0x00,			/*  uint8  iConfiguration; */
89 	0x40,			/*  uint8  bmAttributes;
90 				   Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
91 	0x00,			/*  uint8  MaxPower; */
92 
93 	/* interface */
94 	0x09,			/*  uint8  if_bLength; */
95 	0x04,			/*  uint8  if_bDescriptorType; Interface */
96 	0x00,			/*  uint8  if_bInterfaceNumber; */
97 	0x00,			/*  uint8  if_bAlternateSetting; */
98 	0x01,			/*  uint8  if_bNumEndpoints; */
99 	0x09,			/*  uint8  if_bInterfaceClass; HUB_CLASSCODE */
100 	0x00,			/*  uint8  if_bInterfaceSubClass; */
101 	0x00,			/*  uint8  if_bInterfaceProtocol; */
102 	0x00,			/*  uint8  if_iInterface; */
103 
104 	/* endpoint */
105 	0x07,			/*  uint8  ep_bLength; */
106 	0x05,			/*  uint8  ep_bDescriptorType; Endpoint */
107 	0x81,			/*  uint8  ep_bEndpointAddress; IN Endpoint 1 */
108 	0x03,			/*  uint8  ep_bmAttributes; Interrupt */
109 	0x00,			/*  uint16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
110 	0x02,
111 	0xff			/*  uint8  ep_bInterval; 255 ms */
112 };
113 
114 /* Standard string descriptors */
115 
116 static uint8 root_hub_str_index0[] = {
117 	0x04,			/*  uint8  bLength; */
118 	0x03,			/*  uint8  bDescriptorType; String-descriptor */
119 	0x09,			/*  uint8  lang ID */
120 	0x04,			/*  uint8  lang ID */
121 };
122 
123 static uint8 root_hub_str_index1[] = {
124 	0x22,			/*  uint8  bLength; */
125 	0x03,			/*  uint8  bDescriptorType; String-descriptor */
126 	'A',			/*  uint8  Unicode */
127 	0,			/*  uint8  Unicode */
128 	'R',			/*  uint8  Unicode */
129 	0,			/*  uint8  Unicode */
130 	'A',			/*  uint8  Unicode */
131 	0,			/*  uint8  Unicode */
132 	'N',			/*  uint8  Unicode */
133 	0,			/*  uint8  Unicode */
134 	'Y',			/*  uint8  Unicode */
135 	0,			/*  uint8  Unicode */
136 	'M',			/*  uint8  Unicode */
137 	0,			/*  uint8  Unicode */
138 	' ',			/*  uint8  Unicode */
139 	0,			/*  uint8  Unicode */
140 	' ',			/*  uint8  Unicode */
141 	0,			/*  uint8  Unicode */
142 	'R',			/*  uint8  Unicode */
143 	0,			/*  uint8  Unicode */
144 	'o',			/*  uint8  Unicode */
145 	0,			/*  uint8  Unicode */
146 	'o',			/*  uint8  Unicode */
147 	0,			/*  uint8  Unicode */
148 	't',			/*  uint8  Unicode */
149 	0,			/*  uint8  Unicode */
150 	' ',			/*  uint8  Unicode */
151 	0,			/*  uint8  Unicode */
152 	'H',			/*  uint8  Unicode */
153 	0,			/*  uint8  Unicode */
154 	'u',			/*  uint8  Unicode */
155 	0,			/*  uint8  Unicode */
156 	'b',			/*  uint8  Unicode */
157 	0,			/*  uint8  Unicode */
158 };
159 
160 /* Class descriptor */
161 static uint8 root_hub_class_des[] = {
162 	0x09,			/* uint8 bDescLength*/
163 	0x29,			/* uint8 bDescriptorType: 0x29 for hub */
164 	0x02,			/* uint8 bNbrPorts: 2 downstream ports */
165 	0x09,			/* uint16 wHubCharacteristics */
166 				/* Bit 0,1: individual port power switching */
167 				/* Bit 2: stand alone hub */
168 				/* Bit 3,4: individual port overcurrent protection */
169 	0x00,			/* Bit 8,15: reserved */
170 	0xff,			/* uint8 bPwrOn2PwrGood */
171 	0x00,			/* unit8 bHubContrCurrent */
172 	0x00,			/* uint8 DeviceRemovable */
173 	0xff,			/* uint8 PortPwrCtrlMask */
174 };
175 
176 /* Class status */
177 static uint8 root_hub_class_st[] = {
178 	0x00,			/* uint16 wHubStatus */
179 				/* Bit 0: Local power supply good */
180 				/* Bit 1: No overcurrent condition extsts */
181 	0x00,
182 	0x00,			/* uint16 wHubChange */
183 				/* Bit 0: No change has occurred to Local Power Status */
184 				/* Bit 1: No change has occurred to Local Power Status */
185 	0x00,
186 };
187 
188 /*--- Global variables ---*/
189 
190 virtual_usbdev_t virtual_device[USB_MAX_DEVICE];
191 int number_ports_used;
192 int reset_flag;
193 roothub_t roothub;
194 uint32 port_status[NUMBER_OF_PORTS];
195 
196 static libusb_device **devs;
197 static libusb_device *dev;
198 static libusb_device_handle *devh[USB_MAX_DEVICE];
199 static bool init_flag = false;
200 
201 /*--- Functions ---*/
202 
fill_port_status(unsigned int port_number,bool connected)203 void fill_port_status(unsigned int port_number, bool connected)
204 {
205 	D(bug("USBHost: fill_port_status()"));
206 
207 	if (connected)
208 		port_status[port_number] |= RH_PS_CCS;		/* Device attached */
209 	else
210 		port_status[port_number] &= ~RH_PS_CCS;		/* Device dettached */
211 
212 	port_status[port_number] |= RH_PS_CSC;			/* connect status change */
213 
214 	D(bug("USBHost: (After) P%d port_status %x", port_number, port_status[port_number]));
215 }
216 
217 
usbhost_get_device_list(void)218 int32 usbhost_get_device_list(void)
219 {
220 	int idx_dev = 0, idx_virtdev = 0;
221 	ssize_t cnt;
222 
223 	number_ports_used = 0;
224 
225 	cnt = libusb_get_device_list(NULL, &devs);
226 	D(bug("USBHost: Number of USB devices attached to host bus: %d", (int)cnt));
227 	if (cnt < 0)
228 		return (int32)cnt;
229 
230 	while ((dev = devs[idx_dev]) != NULL) {
231 		int r = libusb_open(dev, &devh[idx_dev]);
232 		if (r < 0) {
233 			D(bug("USBHost: Failed to open the device %d", idx_dev));
234 			goto try_another;
235 		}
236 		D(bug("USBHost: Device %d opened", idx_dev));
237 
238 		r = libusb_get_device_descriptor(dev, &virtual_device[idx_virtdev].dev_desc);
239 		if (r < 0) {
240 			D(bug("USBHost: Unable to get device descriptor %d", r));
241 			goto try_another;
242 		}
243 
244 		if (virtual_device[idx_virtdev].dev_desc.bDeviceClass == LIBUSB_CLASS_HUB) {
245 			D(bug("USBHost: Device is a HUB"));
246 			goto try_another;
247 		}
248 
249 		r = libusb_get_string_descriptor_ascii(
250 						devh[idx_dev],
251 						virtual_device[idx_virtdev].dev_desc.iProduct,
252 						(unsigned char *)virtual_device[idx_virtdev].product_name,
253 						MAX_PRODUCT_LENGTH);
254 		if (r < 0) {
255 			D(bug("USBHost: Unable to get string descriptor %d", r));
256 			goto try_another;
257 		}
258 
259 		r = libusb_get_config_descriptor(dev, 0, &virtual_device[idx_virtdev].config_desc);
260 		if (r < 0) {
261 			D(bug("USBHost: Unable to get configuration descriptor %d", r));
262 			goto try_another;
263 		}
264 		D(bug("USBHost: Number of interfaces %d", virtual_device[idx_virtdev].config_desc->bNumInterfaces));
265 
266 		virtual_device[idx_virtdev].idx_dev = idx_dev;
267 		virtual_device[idx_virtdev].virtdev_available = true;
268 		idx_virtdev++;
269 try_another:
270 		idx_dev++;
271 	}
272 
273 	return 0;
274 }
275 
276 
usbhost_release_device(int virtdev_index)277 int usbhost_release_device(int virtdev_index)
278 {
279 	D(bug("USBHost: Release device %d", virtdev_index));
280 
281 	int r = -1;
282 	int dev_index, if_index;
283 	int port_number;
284 	int no_of_ifaces;
285 
286 	dev_index = virtual_device[virtdev_index].idx_dev;
287 	no_of_ifaces = virtual_device[virtdev_index].config_desc->bNumInterfaces;
288 
289 	for (if_index = 0; if_index < no_of_ifaces; if_index++) {
290 		r = libusb_release_interface(devh[dev_index], if_index);
291 		if (r < 0) {
292 			D(bug("USBHost: Releasing interface %d failed", if_index));
293 		}
294 	}
295 	virtual_device[virtdev_index].connected = false;
296 	port_number = virtual_device[virtdev_index].port_number;
297 
298 	roothub.port[port_number].busy = false;
299 	roothub.port[port_number].atari_dev_idx = -1;
300 	fill_port_status(port_number, virtual_device[virtdev_index].connected);
301 
302 	return r;
303 }
304 
305 
usbhost_free_usb_devices(void)306 void usbhost_free_usb_devices(void)
307 {
308 	int i = 0;
309 
310 	while (devs[i] != NULL) {
311 		if (virtual_device[i].connected)
312 			usbhost_release_device(i);
313 
314 		libusb_close(devh[i]);
315 		devh[i] = NULL;
316 		i++;
317 	}
318 
319 	libusb_free_device_list(devs,0);
320 	memset(&virtual_device, 0, USB_MAX_DEVICE * sizeof(virtual_usbdev_t));
321 }
322 
323 
usbhost_claim_device(int virtdev_index)324 int usbhost_claim_device(int virtdev_index)
325 {
326 	D(bug("USBHost: Claim device %d", virtdev_index));
327 
328 	int r = -1;
329 	int dev_index, if_index;
330 	int no_of_ifaces;
331 
332 	dev_index = virtual_device[virtdev_index].idx_dev;
333 	no_of_ifaces = virtual_device[virtdev_index].config_desc->bNumInterfaces;
334 
335 	for (if_index = 0; if_index < no_of_ifaces; if_index++ ) {
336 		r = libusb_kernel_driver_active(devh[dev_index], if_index);
337 		if (r < 0) {
338 			D(bug("USBHost: Checking if kernel driver is active failed. Error %d", r));
339 			return -1;
340 		}
341 
342 		if (r == 1) {
343 		D(bug("USBHost: Kernel driver active for interface %d", if_index));
344 			D(bug("USBHost: Trying to detach it"));
345 			r = libusb_detach_kernel_driver(devh[dev_index], if_index);
346 		} else goto claim;
347 		if (r < 0) {
348 			D(bug("USBHost: Driver detaching failed"));
349 			return -1;
350 		}
351 
352 claim:	r = libusb_claim_interface(devh[dev_index], if_index);
353 		if (r < 0) {
354 		D(bug("USBHost: Claiming interface number %d failed", if_index));
355 		}
356 	}
357 
358 	virtual_device[virtdev_index].connected = true;
359 
360 	for (int i = 0; i < NUMBER_OF_PORTS; i++) {
361 		if (roothub.port[i].busy == true)
362 			continue;
363 		roothub.port[i].busy = true;
364 		roothub.port[i].port_number = i;
365 		roothub.port[i].libusb_dev_idx = dev_index;
366 		virtual_device[virtdev_index].port_number = i;
367 		break;
368 	}
369 
370 	fill_port_status(virtual_device[virtdev_index].port_number, virtual_device[virtdev_index].connected);
371 
372 	return r;
373 }
374 
375 
print_devs(libusb_device ** devs)376 void print_devs(libusb_device **devs)
377 {
378 	libusb_device *dev;
379 	int i = 0;
380 
381 	while ((dev = devs[i++]) != NULL) {
382 		struct libusb_device_descriptor desc;
383 		int r = libusb_get_device_descriptor(dev, &desc);
384 		if (r < 0) {
385 			panicbug("USBHost: failed to get device descriptor");
386 			return;
387 		}
388 
389 		printf("USBHost: %04x:%04x (bus %d, device %d)\n",
390 			desc.idVendor, desc.idProduct,
391 			libusb_get_bus_number(dev), libusb_get_device_address(dev));
392 	}
393 }
394 
395 
trigger_interrupt(void *)396 int trigger_interrupt(void *)
397 {
398 	D(bug("USBHost: send interrupt"));
399 
400 	for (;;) {
401 		for (int port_number = 0; port_number < NUMBER_OF_PORTS; port_number++) {
402 			if ((port_status[port_number] & RH_PS_CSC)) {
403 				TRIGGER_INTERRUPT;
404 				D(bug("USBHost: trigger interrupt. port_status[%d] %x", port_number, port_status[port_number]));
405 			}
406 		}
407 
408 		SDL_Delay(250);
409 	}
410 
411 	return 0;
412 }
413 
414 
usbhost_init_libusb(void)415 void usbhost_init_libusb(void)
416 {
417 	if (init_flag)
418 		return;
419 
420 	if (libusb_init(NULL)) {
421 		D(bug("USBHost: Imposible to start libusb"));
422 		return;
423 	}
424 
425 	libusb_set_debug(NULL, 3);
426 
427 	for (int i = 0; i < USB_MAX_DEVICE; i++) {
428 		virtual_device[i].connected = false;
429 		virtual_device[i].virtdev_available = false;
430 	}
431 
432 	for (int i = 0; i < NUMBER_OF_PORTS; i++) {
433 		roothub.port[i].libusb_dev_idx = 0;
434 		roothub.port[i].atari_dev_idx = -1;
435 	}
436 
437 	SDL_CreateNamedThread(trigger_interrupt, "USB", NULL);
438 
439 	usbhost_get_device_list();
440 
441 	init_flag = true;
442 }
443 
444 /*--- Private functions ---*/
445 
446 /*--- Support functions ---*/
447 
aranym_submit_rh_msg(uint32 pipe,memptr buffer,int32 transfer_len,devrequest * cmd)448 int32 USBHost::aranym_submit_rh_msg(uint32 pipe, memptr buffer, int32 transfer_len,
449 				    devrequest *cmd)
450 {
451 	D(bug("USBHost: aranym_submit_rh_msg()"));
452 
453 	int32 leni = transfer_len;
454 	int32 len = 0;
455 	uint32 datab[4];
456 	uint8 *data_buf = (uint8 *) datab;
457 	int32 stat = 0;
458 
459 	uint16 bmRType_bReq;
460 	uint16 wValue;
461 	uint16 wIndex;
462 	uint16 wLength;
463 
464 	if (usb_pipeint(pipe)) {
465 		D(bug("USBHost: Root-Hub submit IRQ: NOT implemented"));
466 		return -1;
467 	}
468 
469 	bmRType_bReq = cmd->requesttype | (cmd->request << 8);
470 	wValue = cmd->value;
471 	wIndex = cmd->index;
472 	wLength = cmd->length;
473 
474 	D(bug("USBHost: --- HUB ----------------------------------------"));
475 	D(bug("USBHost: submit rh urb, req=%x val=%#x index=%#x len=%d",
476 	    bmRType_bReq, wValue, wIndex, wLength));
477 	D(bug("USBHost: ------------------------------------------------"));
478 
479 	switch (bmRType_bReq) {
480 		case RH_GET_STATUS:
481 			D(bug("USBHost: RH_GET_STATUS"));
482 			*data_buf = (SDL_BYTEORDER == SDL_BIG_ENDIAN) ?
483 					(uint16) SDL_Swap16(1) : (uint16)(1) ;
484 			len = 2;
485 			break;
486 
487 		case RH_GET_STATUS | RH_INTERFACE:
488 			D(bug("USBHost: RH_GET_STATUS | RH_INTERFACE"));
489 			*data_buf = (SDL_BYTEORDER == SDL_BIG_ENDIAN) ?
490 					(uint16) SDL_Swap16(0) : (uint16)(0) ;
491 			len = 2;
492 			break;
493 
494 		case RH_GET_STATUS | RH_ENDPOINT:
495 			D(bug("USBHost: RH_GET_STATUS | RH_ENDPOINT"));
496 			*data_buf = (SDL_BYTEORDER == SDL_BIG_ENDIAN) ?
497 					(uint16) SDL_Swap16(0) : (uint16)(0) ;
498 			len = 2;
499 			break;
500 
501 		case RH_GET_STATUS | RH_CLASS:
502 			D(bug("USBHost: RH_GET_STATUS | RH_CLASS"));
503 			data_buf = root_hub_class_st;
504 			len = 4;
505 			break;
506 
507 		case RH_GET_STATUS | RH_OTHER | RH_CLASS:
508 			D(bug("USBHost: RH_GET_STATUS | RH_OTHER | RH_CLASS"));
509 			*(uint32 *)data_buf = (SDL_BYTEORDER == SDL_BIG_ENDIAN) ?
510 						SDL_Swap32(port_status[wIndex - 1]) :
511 						port_status[wIndex - 1];
512 			len = 4;
513 			break;
514 
515 		case RH_CLEAR_FEATURE | RH_ENDPOINT:
516 			D(bug("USBHost: RH_CLEAR_FEATURE | RH_ENDPOINT"));
517 			switch (wValue) {
518 				case RH_ENDPOINT_STALL:
519 					D(bug("USBHost: C_HUB_ENDPOINT_STALL"));
520 					len = 0;
521 					break;
522 			}
523 			break;
524 
525 		case RH_CLEAR_FEATURE | RH_CLASS:
526 			D(bug("USBHost: RH_CLEAR_FEATURE | RH_CLASS"));
527 			switch (wValue) {
528 				case RH_C_HUB_LOCAL_POWER:
529 					D(bug("USBHost: C_HUB_LOCAL_POWER"));
530 					len = 0;
531 					break;
532 
533 				case RH_C_HUB_OVER_CURRENT:
534 					D(bug("USBHost: C_HUB_OVER_CURRENT"));
535 					len = 0;
536 					break;
537 			}
538 			break;
539 
540 		case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
541 			D(bug("USBHost: RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS"));
542 			switch (wValue) {
543 				case RH_PORT_ENABLE:
544 					port_status[wIndex - 1] &= ~RH_PS_PES;
545 					len = 0;
546 					break;
547 
548 				case RH_PORT_SUSPEND:
549 					port_status[wIndex - 1] |= RH_PS_PSS;
550 					len = 0;
551 					break;
552 
553 				case RH_PORT_POWER:
554 					len = 0;
555 					break;
556 
557 				case RH_C_PORT_CONNECTION:
558 					port_status[wIndex - 1] &= ~RH_PS_CSC;
559 					len = 0;
560 					break;
561 
562 				case RH_C_PORT_ENABLE:
563 					port_status[wIndex - 1] &= ~RH_PS_PESC;
564 					len = 0;
565 					break;
566 
567 				case RH_C_PORT_SUSPEND:
568 					len = 0;
569 					break;
570 
571 				case RH_C_PORT_OVER_CURRENT:
572 					port_status[wIndex - 1] &= ~RH_PS_OCIC;
573 					len = 0;
574 					break;
575 
576 				case RH_C_PORT_RESET:
577 					port_status[wIndex - 1] &= ~RH_PS_PRSC;
578 					len = 0;
579 					break;
580 
581 				default:
582 					D(bug("USBHost: invalid wValue"));
583 					stat = USB_ST_STALLED;
584 			}
585 			break;
586 
587 		case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
588 			D(bug("USBHost: RH_SET_FEATURE | RH_OTHER | RH_CLASS"));
589 			switch (wValue) {
590 				case RH_PORT_SUSPEND:
591 					len = 0;
592 					break;
593 
594 				case RH_PORT_RESET:
595 					port_status[wIndex - 1] |= RH_PS_PRS;
596 					len = 0;
597 					break;
598 
599 				case RH_PORT_POWER:
600 					port_status[wIndex - 1] |= RH_PS_PPS;
601 					len = 0;
602 					break;
603 
604 				case RH_PORT_ENABLE:
605 					len = 0;
606 					break;
607 
608 				default:
609 					D(bug("USBHost: invalid wValue"));
610 					stat = USB_ST_STALLED;
611 			}
612 			break;
613 
614 		case RH_SET_ADDRESS:
615 			D(bug("USBHost: RH_SET_ADDRESS"));
616 			rh_devnum = wValue;
617 			len = 0;
618 			break;
619 
620 		case RH_GET_DESCRIPTOR:
621 			D(bug("USBHost: RH_GET_DESCRIPTOR: %x, %d", wValue, wLength));
622 			switch (wValue) {
623 				case (USB_DT_DEVICE << 8):	/* device descriptor */
624 					len = min1_t(uint32, leni,
625 												min2_t(uint32, sizeof(root_hub_dev_des), wLength));
626 					data_buf = root_hub_dev_des;
627 					break;
628 
629 				case (USB_DT_CONFIG << 8):	/* configuration descriptor */
630 					len = min1_t(uint32, leni,
631 												min2_t(uint32, sizeof(root_hub_config_des), wLength));
632 					data_buf = root_hub_config_des;
633 					break;
634 
635 				case ((USB_DT_STRING << 8) | 0x00):	/* string 0 descriptors */
636 					len = min1_t(uint32, leni,
637 												min2_t(uint32, sizeof(root_hub_str_index0), wLength));
638 					data_buf = root_hub_str_index0;
639 					break;
640 
641 				case ((USB_DT_STRING << 8) | 0x01):	/* string 1 descriptors */
642 					len = min1_t(uint32, leni,
643 												min2_t(uint32, sizeof(root_hub_str_index1), wLength));
644 					data_buf = root_hub_str_index1;
645 					break;
646 
647 				default:
648 					D(bug("USBHost: invalid wValue"));
649 
650 					stat = USB_ST_STALLED;
651 			}
652 			break;
653 
654 		case RH_GET_DESCRIPTOR | RH_CLASS:
655 			D(bug("USBHost: RH_GET_DESCRIPTOR | RH_CLASS"));
656 
657 			data_buf = root_hub_class_des;
658 			len = min1_t(uint32, leni,
659 				    min2_t(uint32, data_buf[0], wLength));
660 			break;
661 
662 		case RH_GET_CONFIGURATION:
663 			D(bug("USBHost: RH_GET_CONFIGURATION"));
664 			*(uint8 *) data_buf = 0x01;
665 			len = 1;
666 			break;
667 
668 		case RH_SET_CONFIGURATION:
669 			D(bug("USBHost: RH_SET_CONFIGURATION"));
670 			len = 0;
671 			break;
672 
673 		default:
674 			D(bug("USBHost: *** *** *** unsupported root hub command *** *** ***"));
675 			stat = USB_ST_STALLED;
676 	}
677 
678 	len = min1_t(uint32, len, leni);
679 
680 	if(buffer != 0)
681 		Host2Atari_memcpy(buffer, data_buf, len);
682 
683 	return (stat ? -1 : len);
684 }
685 
686 
rh_port_status(memptr rh)687 int32 USBHost::rh_port_status(memptr rh)
688 {
689 	for (int i = 0; i < NUMBER_OF_PORTS; i++) {
690 		WriteInt32(rh + 4 * i, port_status[i]);
691 	}
692 
693 	return 0;
694 }
695 
696 
697 /*--- API USB functions ---*/
698 
usb_lowlevel_init(void)699 int32 USBHost::usb_lowlevel_init(void)
700 {
701 	D(bug("\nUSBHost: usb_lowlevel_init()"));
702 
703 	rh_devnum = 0;
704 
705 	reset();
706 
707 	return 0;
708 }
709 
710 
usb_lowlevel_stop(void)711 int32 USBHost::usb_lowlevel_stop(void)
712 {
713 	D(bug("\nUSBHost: usb_lowlevel_stop()"));
714 
715 	return 0;
716 }
717 
718 
submit_control_msg(uint32 pipe,memptr buffer,int32 len,memptr devrequest)719 int32 USBHost::submit_control_msg(uint32 pipe, memptr buffer,
720 				int32 len, memptr devrequest)
721 {
722 	D(bug("\nUSBHost: submit_control_msg()"));
723 
724 	struct devrequest *cmd;
725 	uint8 *tempbuff;
726 
727 	int32 r = -1;
728 	unsigned int dev_idx = 0;
729 	int i;
730 
731 	uint16 bmRType;
732 	uint16 bReq;
733 	uint16 wValue;
734 	uint16 wIndex;
735 	uint16 wLength;
736 
737 	cmd = (struct devrequest *)Atari2HostAddr(devrequest);
738 	tempbuff = (uint8 *) Atari2HostAddr(buffer);
739 
740 	int32 devnum = usb_pipedevice(pipe);
741 	D(bug("USBHost: devnum %d ", devnum));
742 
743 	/* Control message is for the HUB? */
744 	if (devnum == rh_devnum)
745 		return aranym_submit_rh_msg(pipe, buffer, len, cmd);
746 
747 	bmRType = cmd->requesttype;
748 	bReq = cmd->request;
749 	wValue = cmd->value;
750 	wIndex = cmd->index;
751 	wLength = cmd->length;
752 
753 	D(bug("USBHost: bmRType %x, bReq %x, wValue %x, wIndex %x, wLength %x", bmRType, bReq, wValue, wIndex, wLength));
754 
755 	/* Don't allow to change device's addresses set by the host OS */
756 	if (bReq == USB_REQ_SET_ADDRESS) {
757 		for (i = 0; i < NUMBER_OF_PORTS; i++) {
758 			/*
759 			 * We need to be careful to don't assign to an empty port an already connected
760 			 * device during the virtual machine reboot. For this we've created the reset_flag
761 			 * which indicates that we are setting USB devices during a reboot scenario.
762 			 */
763 			if (((roothub.port[i].atari_dev_idx < 0) && !reset_flag) || ((roothub.port[i].atari_dev_idx >= 0) && reset_flag)) {
764 				roothub.port[i].atari_dev_idx = wValue;
765 				if (reset_flag)
766 					reset_flag = 0;
767 				break;
768 			}
769 		}
770 		D(bug("USBHost: Attempt to set device address"));
771 		r = 0;
772 	}
773 	else if ((bReq == USB_REQ_SET_CONFIGURATION) && (wValue > 1)) {	/* We only support one configuration per device */
774 		D(bug("USBHost: Attempt to change to configuration number %d ", wValue));
775 		r = -1;
776 	}
777 	else {
778 		for (i = 0; i < NUMBER_OF_PORTS; i++) {
779 			if (roothub.port[i].atari_dev_idx == devnum) {
780 				dev_idx = roothub.port[i].libusb_dev_idx;
781 				D(bug("USBHost: dev_idx %d ", dev_idx));
782 				break;
783 			}
784 		}
785 		r = libusb_control_transfer(devh[dev_idx], bmRType, bReq, wValue, wIndex, tempbuff, wLength, 0);
786 		D(bug("USBHost: bytes transmitted %d ", r));
787 	}
788 
789 	return r;
790 }
791 
792 
submit_int_msg(uint32,memptr,int32,int32)793 int32 USBHost::submit_int_msg(uint32 /* pipe */, memptr /* buffer */,
794 				int32 /* len*/, int32 /* interval*/)
795 {
796 	D(bug("\nUSBHost: submit_int_msg()"));
797 	D(bug("\nUSBHost: Function not supported yet"));
798 
799 	return -1;
800 }
801 
802 
submit_bulk_msg(uint32 pipe,memptr buffer,int32 len)803 int32 USBHost::submit_bulk_msg(uint32 pipe, memptr buffer, int32 len)
804 {
805 	D(bug("\nUSBHost: submit_bulk_msg()"));
806 
807 	uint8 *tempbuff;
808 
809 	int32 dir_out;
810 	uint8 endpoint;
811 	int32 devnum;
812 	int32 transferred;
813 	unsigned int dev_idx = 0;
814 	int i;
815 	int32 r;
816 
817 	tempbuff = (uint8 *)Atari2HostAddr(buffer);
818 
819 	dir_out = usb_pipeout(pipe);
820 	endpoint = usb_pipeendpoint(pipe) | (dir_out ? LIBUSB_ENDPOINT_OUT : LIBUSB_ENDPOINT_IN);
821 	devnum = usb_pipedevice(pipe);
822 	D(bug("USBHost: devnum %d ", devnum));
823 	D(bug("USBHost: pipe %x ", pipe));
824 	D(bug("USBHost: --- BULK -----------------------------------------------"));
825 	D(bug("USBHost: dev=%d endpoint=%d endpoint address= %x buf=%p size=%d dir_out=%d",
826 	    usb_pipedevice(pipe), usb_pipeendpoint(pipe), endpoint, tempbuff, len, dir_out));
827 
828 	for (i = 0; i < NUMBER_OF_PORTS; i++) {
829 		if (roothub.port[i].atari_dev_idx == devnum) {
830 			dev_idx = roothub.port[i].libusb_dev_idx;
831 			D(bug("USBHost: dev_idx %d ", dev_idx));
832 			break;
833 		}
834 	}
835 
836 	r = libusb_bulk_transfer(devh[dev_idx], endpoint, tempbuff, len, &transferred, 1000);
837 	D(bug("USBHost: return: %d len: %d transferred: %d", r, len, transferred));
838 
839 	return r;
840 }
841 
842 /*--- Public functions ---*/
843 
844 /* reset, called upon OS reboot */
reset()845 void USBHost::reset()
846 {
847 	D(bug("USBHost: reset"));
848 
849 	for (int i = 0; i < NUMBER_OF_PORTS; i++) {
850 		port_status[i] |= (RH_PS_PPS | RH_PS_PES);
851 		if (port_status[i] & RH_PS_CCS) {
852 			reset_flag = 1;
853 			port_status[i] |= RH_PS_CSC;
854 		}
855 	}
856 }
857 
858 /*--- Dispatcher ---*/
dispatch(uint32 fncode)859 int32 USBHost::dispatch(uint32 fncode)
860 {
861 	int32 ret;
862 
863 	D(bug("USBHost: dispatch(%u)", fncode));
864 	ret = EINVFN;
865 
866 	switch(fncode) {
867 		case GET_VERSION:
868 			D(bug("USBHost: getVersion"));
869 			ret = USBHOST_NFAPI_VERSION;
870 			break;
871 
872 		case USBHOST_INTLEVEL:
873 			D(bug("USBHost: getINTlevel"));
874 			ret = INTLEVEL;
875 			break;
876 
877 		case USBHOST_RH_PORT_STATUS:
878 			ret = rh_port_status(getParameter(0));
879 			break;
880 
881 		case USBHOST_LOWLEVEL_INIT:
882 			ret = usb_lowlevel_init();
883 			break;
884 
885 		case USBHOST_LOWLEVEL_STOP:
886 			ret = usb_lowlevel_stop();
887 			break;
888 
889 		case USBHOST_SUBMIT_CONTROL_MSG:
890 			ret = submit_control_msg(getParameter(0), getParameter(1), getParameter(2),
891 						getParameter(3));
892 			break;
893 
894 		case USBHOST_SUBMIT_INT_MSG:
895 			ret = submit_int_msg(getParameter(0), getParameter(1), getParameter(2),
896 						getParameter(3));
897 			break;
898 
899 		case USBHOST_SUBMIT_BULK_MSG:
900 			ret = submit_bulk_msg(getParameter(0), getParameter(1), getParameter(2));
901 			break;
902 		default:
903 			D(bug("USBHost: unimplemented function #%d", fncode));
904 			break;
905 	}
906 
907 	D(bug("USBHost: function returning with 0x%08x", ret));
908 
909 	return ret;
910 }
911 
912 
913 /*--- Constructor/destructor functions ---*/
914 
USBHost()915 USBHost::USBHost()
916 {
917 	for (int i = 0; i < NUMBER_OF_PORTS; i++) {
918 		port_status[i] = 0x0000; 	/* Clean before use */
919 	}
920 	D(bug("USBHost: created"));
921 }
922 
923 
~USBHost()924 USBHost::~USBHost()
925 {
926 	int i = USB_MAX_DEVICE - 1;
927 	unsigned int port_number = 0;
928 
929 	if (init_flag) {
930 		while (i >= 0) {
931 			if (devh[i] != NULL) {
932 			D(bug("USBHost: Trying to close device %d", i));
933 
934 			while (port_number < NUMBER_OF_PORTS) {
935 				if (roothub.port[port_number].libusb_dev_idx == i) {
936 					if (libusb_release_interface(devh[i], roothub.port[port_number].interface) < 0) {
937 						D(bug("USBHost: unable to release device interface"));
938 					}
939 					if (libusb_attach_kernel_driver(devh[i], roothub.port[port_number].interface) < 0) {
940 						D(bug("USBHost: unable to reattach kernel driver to interface"));
941 					}
942 					break;
943 				}
944 				port_number++;
945 			}
946 			libusb_close(devh[i]);
947 			devh[i] = NULL;
948 			D(bug("USBHost: %d device closed", i));
949 			}
950 			i--;
951 		}
952 
953 		usbhost_free_usb_devices();
954 		libusb_exit(NULL);
955 	}
956 
957 	D(bug("USBHost: destroyed"));
958 }
959 
960