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
usb_console_input_init(dev_info_t * dip,usb_pipe_handle_t pipe_handle,uchar_t ** state_buf,usb_console_info_t * console_input_info)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
usb_console_input_fini(usb_console_info_t console_input_info)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
usb_console_input_enter(usb_console_info_t console_input_info)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
usb_console_read(usb_console_info_t console_input_info,uint_t * num_characters)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
usb_console_input_exit(usb_console_info_t console_input_info)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
usb_console_output_init(dev_info_t * dip,usb_pipe_handle_t pipe_handle,usb_console_info_t * console_output_info)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
usb_console_output_fini(usb_console_info_t console_output_info)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
usb_console_output_enter(usb_console_info_t console_output_info)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
usb_console_write(usb_console_info_t console_output_info,uchar_t * buf,uint_t num_characters,uint_t * num_characters_written)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
usb_console_output_exit(usb_console_info_t console_output_info)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