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