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