1 /*
2  * dlgUsb.cpp - USB selection dialog
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 "sdlgui.h"
26 #include "dlgAlert.h"
27 #include "dlgUsb.h"
28 
29 #define DEBUG 0
30 #include "debug.h"
31 
32 #ifdef USBHOST_SUPPORT
33 /* Static variables */
34 
35 static char product[ENTRY_COUNT][MAX_PRODUCT_LENGTH];
36 static bool init_flag = false;
37 static const char *ALERT_TEXT =
38 
39 "        !!! ALERT !!!\n"
40 "\n"
41 "Getting a new USB device list\n"
42 "will disconnect any USB device\n"
43 "connected to Aranym\n"
44 "";
45 
46 #define SDLGUI_INCLUDE_USBDLG
47 #include "sdlgui.sdl"
48 
49 #define PLUG_BUTTON_OFFSET	PLUG_0
50 #define CONNECTED_INFO_OFFSET	CONNECTED_0
51 
52 /* Local functions */
53 
check_if_devices_connected(void)54 int DlgUsb::check_if_devices_connected(void)
55 {
56 	int i = 0;
57 
58 	while (i < USB_MAX_DEVICE) {
59 		if (virtual_device[i].connected == true)
60 			return 1;
61 		i++;
62 	}
63 
64 	return 0;
65 }
66 
67 
enable_buttons(void)68 void DlgUsb::enable_buttons(void)
69 {
70 	int i = 0;
71 
72 	while (i < ENTRY_COUNT) {
73 		if (virtual_device[i + ypos].virtdev_available == true)
74 			dlg[PLUG_BUTTON_OFFSET + i].state &= ~SG_DISABLED;
75 		else
76 			usbdlg[PLUG_BUTTON_OFFSET + i].state |= SG_DISABLED;
77 
78 		i++;
79 	}
80 }
81 
82 
disable_buttons(void)83 void DlgUsb::disable_buttons(void)
84 {
85 	int i = 0;
86 
87 	while (i < ENTRY_COUNT) {
88 		if (virtual_device[i + ypos].connected == false)
89 			usbdlg[PLUG_BUTTON_OFFSET + i].state |= SG_DISABLED;
90 		else
91 			usbdlg[PLUG_BUTTON_OFFSET + i].state &= ~SG_DISABLED;
92 		i++;
93 	}
94 }
95 
96 
reset_buttons_and_state(void)97 void DlgUsb::reset_buttons_and_state(void)
98 {
99 	int i = 0;
100 
101 	while (i < ENTRY_COUNT) {
102 		dlg[PLUG_BUTTON_OFFSET + i].state |= SG_DISABLED;
103 		dlg[CONNECTED_INFO_OFFSET + i].state |= SG_DISABLED;
104 		i++;
105 	}
106 
107 	init_flag = true;
108 }
109 
110 
clean_product_strings(void)111 void DlgUsb::clean_product_strings(void)
112 {
113 	int i = 0;
114 
115 	while (i < ENTRY_COUNT) {
116 		product[i][0] = '\0';
117 		i++;
118 	}
119 }
120 
121 /* Public functions */
122 
processDialog(void)123 int DlgUsb::processDialog(void)
124 {
125 	int retval = Dialog::GUI_CONTINUE;
126 	int virtdev_idx, virtdev_position;
127 	int32 r;
128 
129 	if (state == STATE_MAIN) { /* Process main USB dialog */
130 		switch(return_obj) {
131 
132 			case OK:
133 				retval = Dialog::GUI_CLOSE;
134 				break;
135 
136 			case GET_DEVICE_LIST:
137 				if ((r = check_if_devices_connected())) {
138 					state = STATE_ALERT;
139 					dlgAlert = (DlgAlert *) DlgAlertOpen(ALERT_TEXT, ALERT_OKCANCEL);
140 					SDLGui_Open(dlgAlert);
141 				} else {
142 					ypos = 0;
143 					reset_buttons_and_state();
144 					clean_product_strings();
145 					usbhost_free_usb_devices();
146 					usbhost_get_device_list();
147 					refreshentries = true;
148 				}
149 				break;
150 
151 			case USBHOSTDLG_UP:
152 				/* Scroll up */
153 				if (ypos > 0) {
154 					--ypos;
155 					refreshentries = true;
156 				}
157 				break;
158 
159 			case USBHOSTDLG_DOWN:
160 				/* Scroll down */
161 				if (ypos < (USB_MAX_DEVICE - ENTRY_COUNT)) {
162 					++ypos;
163 					refreshentries = true;
164 				}
165 				break;
166 		}
167 
168 		virtdev_idx = return_obj - PLUG_BUTTON_OFFSET + ypos;
169 		virtdev_position = return_obj - PLUG_BUTTON_OFFSET;
170 		/* User clicked on PLUG/UNPLUG buttons */
171 		if ((return_obj >= PLUG_BUTTON_OFFSET) && (return_obj <= PLUG_BUTTON_OFFSET + ENTRY_COUNT)) {
172 			if (virtual_device[virtdev_idx].connected == false) {
173 				if (usbhost_claim_device(virtdev_idx) != -1) {
174 					D(bug("dlgUsb: Device plugged"));
175 					dlg[CONNECTED_INFO_OFFSET + virtdev_position].state &= ~SG_DISABLED;
176 					virtual_device[virtdev_idx].connected = true;
177 					if ((++number_ports_used == NUMBER_OF_PORTS))
178 							refreshentries = true;
179 				}
180 			}
181 			else {
182 				if (usbhost_release_device(virtdev_idx) != -1) {
183 					D(bug("dlgUsb: Device unplugged"));
184 					dlg[CONNECTED_INFO_OFFSET + virtdev_position].state |= SG_DISABLED;
185 					virtual_device[virtdev_idx].connected = false;
186 					if (--number_ports_used < NUMBER_OF_PORTS)
187 						refreshentries = true;
188 				}
189 			}
190 		}
191 	}
192 	else { /* Process Alert dialog */
193 		state = STATE_MAIN;
194 		D(bug("dlgUsb: Process Alert dialog"));
195 		if (dlgAlert && dlgAlert->pressedOk()) {
196 			reset_buttons_and_state();
197 			clean_product_strings();
198 			usbhost_free_usb_devices();
199 			usbhost_get_device_list();
200 			refreshentries = true;
201 		}
202 	}
203 	if (refreshentries) {
204 		refreshEntries();
205 	}
206 
207 	return_obj = -1;
208 	return retval;
209 }
210 
211 
refreshEntries(void)212 void DlgUsb::refreshEntries(void)
213 {
214 	if (refreshentries) {
215 		int i;
216 
217 		for (i = 0; i < ENTRY_COUNT; i++) {
218 			if ((i + ypos) < USB_MAX_DEVICE) {
219 				/* Copy entries to dialog: */
220 				strcpy(product[i], virtual_device[i + ypos].product_name);
221 				/* Grey/Ungrey CONNECTED info string */
222 				if (virtual_device[i + ypos].connected == true) {
223 					dlg[CONNECTED_INFO_OFFSET + i].state &= ~SG_DISABLED;
224 				}
225 				else {
226 					dlg[CONNECTED_INFO_OFFSET + i].state |= SG_DISABLED;
227 				}
228 				/* Enable/disable PLUG/UNPLUG buttons */
229 				if (number_ports_used < NUMBER_OF_PORTS)
230 					enable_buttons();
231 				else
232 					disable_buttons();
233 			}
234 			else {
235 				/* Clear entry */
236 			}
237 		}
238 		refreshentries = false;
239 	}
240 }
241 
DlgUsb(SGOBJ * dlg)242 DlgUsb::DlgUsb(SGOBJ *dlg)
243 	: Dialog(dlg),
244 	  state(STATE_MAIN),
245 	  ypos(0),
246 	  refreshentries(true)
247 {
248 	if (init_flag == false) {
249 		reset_buttons_and_state();
250 		usbhost_init_libusb();
251 	}
252 	refreshEntries();
253 	for (int i = 0; i < ENTRY_COUNT; i++) {
254 		if ((virtual_device[i].virtdev_available == true && number_ports_used < NUMBER_OF_PORTS) ||
255 		    (virtual_device[i].connected         == true)) {
256 			dlg[PLUG_BUTTON_OFFSET + i].state &= ~SG_DISABLED;
257 		}
258 	}
259 }
260 
261 #else /* Function and variables for when USB not present */
262 
263 #define usbdlg nousbdlg
264 
265 #define SDLGUI_INCLUDE_NOUSBDLG
266 #include "sdlgui.sdl"
267 
268 
processDialog(void)269 int DlgUsb::processDialog(void)
270 {
271 	int retval = Dialog::GUI_CONTINUE;
272 
273 	if (return_obj == OK)
274 		retval = Dialog::GUI_CLOSE;
275 
276 	return retval;
277 }
278 
279 
DlgUsb(SGOBJ * dlg)280 DlgUsb::DlgUsb(SGOBJ *dlg)
281 	: Dialog(dlg)
282 {
283 
284 }
285 #endif /* USBHOST_SUPPORT */
286 
287 
~DlgUsb()288 DlgUsb::~DlgUsb()
289 {
290 
291 }
292 
293 
294 /* Private functios */
295 
confirm(void)296 void DlgUsb::confirm(void)
297 {
298 
299 }
300 
301 
DlgUsbOpen(void)302 Dialog *DlgUsbOpen(void)
303 {
304 	return new DlgUsb(usbdlg);
305 }
306