1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * USBA: Solaris USB Architecture support
28  *
29  * ISSUES:
30  */
31 #define	USBA_FRAMEWORK
32 #include <sys/usb/usba.h>
33 #include <sys/usb/usba/hcdi.h>
34 #include <sys/usb/usba/genconsole.h>
35 #include <sys/usb/usba/usba_types.h>
36 #include <sys/usb/usba/usba_impl.h>
37 
38 /*
39  * Initialize USB polled support. This routine calls down to the lower
40  * layers to initialize any state information.
41  */
42 int
43 usb_console_input_init(dev_info_t		*dip,
44 			usb_pipe_handle_t	pipe_handle,
45 			uchar_t			**state_buf,
46 			usb_console_info_t	*console_input_info)
47 {
48 	int			ret;
49 	usba_device_t		*usba_device;
50 	usba_pipe_handle_data_t	*ph_data;
51 	usb_console_info_impl_t	*usb_console_input;
52 
53 	if (dip == NULL) {
54 
55 		return (USB_INVALID_ARGS);
56 	}
57 
58 	if (DEVI_IS_DEVICE_REMOVED(dip)) {
59 
60 		return (USB_FAILURE);
61 	}
62 
63 	usb_console_input = kmem_zalloc(
64 	    sizeof (struct usb_console_info_impl), KM_SLEEP);
65 
66 	/*
67 	 * Save the dip
68 	 */
69 	usb_console_input->uci_dip = dip;
70 
71 	/*
72 	 * Translate the dip into a device.
73 	 */
74 	usba_device = usba_get_usba_device(dip);
75 
76 	/*
77 	 * Get ph_data from pipe handle and hold the data
78 	 */
79 	if ((ph_data = usba_hold_ph_data(pipe_handle)) == NULL) {
80 		kmem_free(usb_console_input,
81 		    sizeof (struct usb_console_info_impl));
82 
83 		return (USB_INVALID_PIPE);
84 	}
85 
86 	/*
87 	 * Call the lower layer to initialize any state information
88 	 */
89 	ret = usba_device->usb_hcdi_ops->usba_hcdi_console_input_init(
90 	    ph_data, state_buf, usb_console_input);
91 
92 	if (ret != USB_SUCCESS) {
93 		kmem_free(usb_console_input,
94 		    sizeof (struct usb_console_info_impl));
95 	} else {
96 		*console_input_info = (usb_console_info_t)usb_console_input;
97 	}
98 
99 	usba_release_ph_data((usba_ph_impl_t *)pipe_handle);
100 
101 	return (ret);
102 }
103 
104 
105 /*
106  * Free up any resources that we allocated in the above initialization
107  * routine.
108  */
109 int
110 usb_console_input_fini(usb_console_info_t console_input_info)
111 {
112 	usb_console_info_impl_t		*usb_console_input;
113 	usba_device_t			*usba_device;
114 	int				ret;
115 
116 	usb_console_input = (usb_console_info_impl_t *)console_input_info;
117 
118 	/*
119 	 * Translate the dip into a device.
120 	 */
121 	usba_device = usba_get_usba_device(usb_console_input->uci_dip);
122 
123 	/*
124 	 * Call the lower layer to free any state information.
125 	 */
126 	ret = usba_device->usb_hcdi_ops->usba_hcdi_console_input_fini(
127 	    usb_console_input);
128 
129 	if (ret == USB_FAILURE) {
130 
131 		return (ret);
132 	}
133 
134 	/*
135 	 * We won't be needing this information anymore.
136 	 */
137 	kmem_free(usb_console_input, sizeof (struct usb_console_info_impl));
138 
139 	return (USB_SUCCESS);
140 }
141 
142 
143 /*
144  * This is the routine that OBP calls to save the USB state information
145  * before using the USB keyboard as an input device.  This routine,
146  * and all of the routines that it calls, are responsible for saving
147  * any state information so that it can be restored when OBP mode is
148  * over.  At this layer, this code is mainly just a pass through.
149  *
150  * Warning:  this code runs in polled mode.
151  */
152 int
153 usb_console_input_enter(usb_console_info_t console_input_info)
154 {
155 	usba_device_t				*usba_device;
156 	usb_console_info_impl_t			*usb_console_input;
157 
158 	usb_console_input = (usb_console_info_impl_t *)console_input_info;
159 
160 	/*
161 	 * Translate the dip into a device.
162 	 * Do this by directly looking at the dip, do not call
163 	 * usba_get_usba_device() because this function calls into the DDI.
164 	 * The ddi then tries to acquire a mutex and the machine hard hangs.
165 	 */
166 	usba_device = usba_polled_get_usba_device(usb_console_input->uci_dip);
167 
168 	/*
169 	 * Call the lower layer to save state information.
170 	 */
171 	usba_device->usb_hcdi_ops->usba_hcdi_console_input_enter(
172 	    usb_console_input);
173 
174 	return (USB_SUCCESS);
175 }
176 
177 
178 /*
179  * This is the routine that OBP calls when it wants to read a character.
180  * We will call to the lower layers to see if there is any input data
181  * available.  At this layer, this code is mainly just a pass through.
182  *
183  * Warning: This code runs in polled mode.
184  */
185 int
186 usb_console_read(usb_console_info_t console_input_info, uint_t *num_characters)
187 {
188 	usba_device_t				*usba_device;
189 	usb_console_info_impl_t			*usb_console_input;
190 
191 	usb_console_input = (usb_console_info_impl_t *)console_input_info;
192 
193 	/*
194 	 * Translate the dip into a device.
195 	 * Do this by directly looking at the dip, do not call
196 	 * usba_get_usba_device() because this function calls into the DDI.
197 	 * The ddi then tries to acquire a mutex and the machine hard hangs.
198 	 */
199 	usba_device = usba_polled_get_usba_device(usb_console_input->uci_dip);
200 
201 	/*
202 	 * Call the lower layer to get a a character.  Return the number
203 	 * of characters read into the buffer.
204 	 */
205 	return (usba_device->usb_hcdi_ops->usba_hcdi_console_read(
206 	    usb_console_input, num_characters));
207 }
208 
209 
210 /*
211  * This is the routine that OBP calls when it is giving up control of the
212  * USB keyboard.  This routine, and the lower layer routines that it calls,
213  * are responsible for restoring the controller state to the state it was
214  * in before OBP took control. At this layer, this code is mainly just a
215  * pass through.
216  *
217  * Warning: This code runs in polled mode.
218  */
219 int
220 usb_console_input_exit(usb_console_info_t console_input_info)
221 {
222 	usba_device_t				*usba_device;
223 	usb_console_info_impl_t			*usb_console_input;
224 
225 	usb_console_input = (usb_console_info_impl_t *)console_input_info;
226 
227 	/*
228 	 * Translate the dip into a device.
229 	 * Do this by directly looking at the dip, do not call
230 	 * usba_get_usba_device() because this function calls into the DDI.
231 	 * The ddi then tries to acquire a mutex and the machine hard hangs.
232 	 */
233 	usba_device = usba_polled_get_usba_device(usb_console_input->uci_dip);
234 
235 	/*
236 	 * Restore the state information.
237 	 */
238 	usba_device->usb_hcdi_ops->usba_hcdi_console_input_exit(
239 	    usb_console_input);
240 
241 	return (USB_SUCCESS);
242 }
243 
244 /*
245  * Initialize USB OBP support.	This routine calls down to the lower
246  * layers to initialize any state information.
247  */
248 int
249 usb_console_output_init(
250 	dev_info_t		*dip,
251 	usb_pipe_handle_t	pipe_handle,
252 	usb_console_info_t	*console_output_info)
253 {
254 	usba_device_t		*usb_device;
255 	usb_console_info_impl_t	*usb_console_output;
256 	int			ret;
257 
258 	/* Translate the dip into a device and check hcdi ops  */
259 	usb_device = usba_get_usba_device(dip);
260 	if (usb_device->usb_hcdi_ops->usba_hcdi_ops_version <
261 	    HCDI_OPS_VERSION_1 ||
262 	    usb_device->usb_hcdi_ops->usba_hcdi_console_output_init == NULL)
263 
264 		return (USB_FAILURE);
265 
266 	usb_console_output = kmem_zalloc(sizeof (struct usb_console_info_impl),
267 	    KM_SLEEP);
268 	usb_console_output->uci_dip = dip;
269 
270 	/*
271 	 * Call the lower layer to initialize any state information
272 	 */
273 	ret = usb_device->usb_hcdi_ops->usba_hcdi_console_output_init(
274 	    usba_get_ph_data(pipe_handle), usb_console_output);
275 
276 	if (ret == USB_FAILURE) {
277 		kmem_free(usb_console_output,
278 		    sizeof (struct usb_console_info_impl));
279 
280 		return (ret);
281 	}
282 
283 	*console_output_info = (usb_console_info_t)usb_console_output;
284 
285 	return (USB_SUCCESS);
286 }
287 
288 /*
289  * Free up any resources that we allocated in the above initialization
290  * routine.
291  */
292 int
293 usb_console_output_fini(usb_console_info_t console_output_info)
294 {
295 	usb_console_info_impl_t	*usb_console_output;
296 	usba_device_t		*usb_device;
297 	int			ret;
298 
299 	usb_console_output = (usb_console_info_impl_t *)console_output_info;
300 
301 	/*
302 	 * Translate the dip into a device.
303 	 */
304 	usb_device = usba_polled_get_usba_device(usb_console_output->uci_dip);
305 
306 	/*
307 	 * Call the lower layer to free any state information.
308 	 */
309 	ret = usb_device->usb_hcdi_ops->usba_hcdi_console_output_fini(
310 	    usb_console_output);
311 
312 	if (ret == USB_FAILURE) {
313 
314 		return (ret);
315 	}
316 
317 	/*
318 	 * We won't be needing this information anymore.
319 	 */
320 	kmem_free(usb_console_output, sizeof (struct usb_console_info_impl));
321 
322 	return (USB_SUCCESS);
323 }
324 
325 /*
326  * This is the routine that OBP calls to save the USB state information
327  * before using the USB device as an output device.  This routine,
328  * and all of the routines that it calls, are responsible for saving
329  * any state information so that it can be restored when OBP mode is
330  * over.  At this layer, this code is mainly just a pass through.
331  */
332 int
333 usb_console_output_enter(usb_console_info_t console_output_info)
334 {
335 	usba_device_t			    *usb_device;
336 	usb_console_info_impl_t		 *usb_console_output;
337 
338 	usb_console_output = (usb_console_info_impl_t *)console_output_info;
339 
340 	/*
341 	 * Translate the dip into a device.
342 	 */
343 	usb_device = usba_polled_get_usba_device(usb_console_output->uci_dip);
344 
345 	/*
346 	 * Call the lower layer to save state information.
347 	 */
348 	usb_device->usb_hcdi_ops->usba_hcdi_console_output_enter(
349 	    usb_console_output);
350 
351 	return (USB_SUCCESS);
352 }
353 
354 /*
355  * This is the routine that OBP calls when it wants to write a character.
356  * We will call to the lower layers to write any data
357  * At this layer, this code is mainly just a pass through.
358  */
359 int
360 usb_console_write(usb_console_info_t console_output_info,
361 	uchar_t *buf, uint_t num_characters, uint_t *num_characters_written)
362 {
363 	usba_device_t		*usb_device;
364 	usb_console_info_impl_t	*usb_console_output;
365 
366 	usb_console_output = (usb_console_info_impl_t *)console_output_info;
367 
368 	/*
369 	 * Translate the dip into a device.
370 	 */
371 	usb_device = usba_polled_get_usba_device(usb_console_output->uci_dip);
372 
373 	/*
374 	 * Call the lower layer to get a a character.  Return the number
375 	 * of characters read into the buffer.
376 	 */
377 	return (usb_device->usb_hcdi_ops->usba_hcdi_console_write(
378 	    usb_console_output, buf, num_characters,
379 	    num_characters_written));
380 }
381 
382 /*
383  * This is the routine that OBP calls when it is giving up control of the
384  * USB output device.  This routine, and the lower layer routines that it
385  * calls, are responsible for restoring the controller state to the state
386  * it was in before OBP took control. At this layer, this code is mainly
387  * just a pass through.
388  */
389 int
390 usb_console_output_exit(usb_console_info_t console_output_info)
391 {
392 	usba_device_t			 *usb_device;
393 	usb_console_info_impl_t		 *usb_console_output;
394 
395 	usb_console_output = (usb_console_info_impl_t *)console_output_info;
396 
397 	/*
398 	 * Translate the dip into a device.
399 	 */
400 	usb_device = usba_polled_get_usba_device(usb_console_output->uci_dip);
401 
402 	/*
403 	 * Restore the state information.
404 	 */
405 	usb_device->usb_hcdi_ops->usba_hcdi_console_output_exit(
406 	    usb_console_output);
407 
408 	return (USB_SUCCESS);
409 }
410