Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / io / 1394 / adapters / hci1394_ioctl.c
blob47d89c7fd49c0c80f4b993f8e3cbb6d19a7ba770
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * hci1394_ioctl.c
31 * Test ioctl's to support test/debug of the 1394 HW. hci1394_ioctl_enum_t is
32 * passed in cmd and a pointer to the appropriate structure (i.e.
33 * hci1394_ioctl_wrreg_t) is passed in arg.
36 #include <sys/conf.h>
37 #include <sys/modctl.h>
38 #include <sys/mkdev.h>
39 #include <sys/cred.h>
40 #include <sys/file.h>
41 #include <sys/types.h>
42 #include <sys/errno.h>
43 #include <sys/ddi.h>
44 #include <sys/sunddi.h>
46 #include <sys/1394/h1394.h>
47 #include <sys/1394/adapters/hci1394.h>
48 #include <sys/1394/adapters/hci1394_extern.h>
49 #include <sys/1394/adapters/hci1394_ioctl.h>
52 /* HCI1394_IOCTL_READ_SELFID for 32-bit apps in 64-bit kernel */
53 typedef struct hci1394_ioctl_readselfid32_s {
54 uint32_t buf;
55 uint_t count;
56 } hci1394_ioctl_readselfid32_t;
59 static int hci1394_ioctl_wrreg(hci1394_state_t *soft_state, void *arg,
60 int mode);
61 static int hci1394_ioctl_rdreg(hci1394_state_t *soft_state, void *arg,
62 int mode);
63 static int hci1394_ioctl_wrvreg(hci1394_state_t *soft_state, void *arg,
64 int mode);
65 static int hci1394_ioctl_rdvreg(hci1394_state_t *soft_state, void *arg,
66 int mode);
67 static int hci1394_ioctl_selfid_cnt(hci1394_state_t *soft_state, void *arg,
68 int mode);
69 static int hci1394_ioctl_busgen_cnt(hci1394_state_t *soft_state, void *arg,
70 int mode);
71 static int hci1394_ioctl_wrphy(hci1394_state_t *soft_state, void *arg,
72 int mode);
73 static int hci1394_ioctl_rdphy(hci1394_state_t *soft_state, void *arg,
74 int mode);
75 static int hci1394_ioctl_hbainfo(hci1394_state_t *soft_state, void *arg,
76 int mode);
77 static int hci1394_ioctl_read_selfid(hci1394_state_t *soft_state, void *arg,
78 int mode);
79 #ifdef _MULTI_DATAMODEL
80 static int hci1394_ioctl_read_selfid32(hci1394_state_t *soft_state,
81 hci1394_ioctl_readselfid32_t *read_selfid, int mode);
82 #endif
85 /* ARGSUSED */
86 int
87 hci1394_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
88 int *rvalp)
90 hci1394_state_t *soft_state;
91 int instance;
92 int status;
94 instance = getminor(dev);
95 if (instance == -1) {
96 return (EBADF);
99 soft_state = ddi_get_soft_state(hci1394_statep, instance);
100 if (soft_state == NULL) {
101 return (EBADF);
104 status = 0;
106 switch (cmd) {
107 case HCI1394_IOCTL_WRITE_REG:
108 status = hci1394_ioctl_wrreg(soft_state, (void *)arg, mode);
109 break;
110 case HCI1394_IOCTL_READ_REG:
111 status = hci1394_ioctl_rdreg(soft_state, (void *)arg, mode);
112 break;
113 case HCI1394_IOCTL_READ_VREG:
114 status = hci1394_ioctl_rdvreg(soft_state, (void *)arg, mode);
115 break;
116 case HCI1394_IOCTL_WRITE_VREG:
117 status = hci1394_ioctl_wrvreg(soft_state, (void *)arg, mode);
118 break;
119 case HCI1394_IOCTL_RESET_BUS:
120 status = hci1394_ohci_bus_reset(soft_state->ohci);
121 break;
122 case HCI1394_IOCTL_SELFID_CNT:
123 status = hci1394_ioctl_selfid_cnt(soft_state, (void *)arg,
124 mode);
125 break;
126 case HCI1394_IOCTL_BUSGEN_CNT:
127 status = hci1394_ioctl_busgen_cnt(soft_state, (void *)arg,
128 mode);
129 break;
130 case HCI1394_IOCTL_READ_SELFID:
131 status = hci1394_ioctl_read_selfid(soft_state, (void *)arg,
132 mode);
133 break;
134 case HCI1394_IOCTL_READ_PHY:
135 status = hci1394_ioctl_rdphy(soft_state, (void *)arg, mode);
136 break;
137 case HCI1394_IOCTL_WRITE_PHY:
138 status = hci1394_ioctl_wrphy(soft_state, (void *)arg, mode);
139 break;
140 case HCI1394_IOCTL_HBA_INFO:
141 status = hci1394_ioctl_hbainfo(soft_state, (void *)arg, mode);
142 break;
143 default:
145 * if we don't know what the ioctl is, forward it on to the
146 * services layer. The services layer will handle the devctl
147 * ioctl's along with any services layer private ioctls that
148 * it has defined.
150 status = h1394_ioctl(soft_state->drvinfo.di_sl_private, cmd,
151 arg, mode, credp, rvalp);
152 break;
155 return (status);
159 static int
160 hci1394_ioctl_wrreg(hci1394_state_t *soft_state, void *arg, int mode)
162 hci1394_ioctl_wrreg_t wrreg;
163 int status;
166 ASSERT(soft_state != NULL);
167 ASSERT(arg != NULL);
169 status = ddi_copyin(arg, &wrreg, sizeof (hci1394_ioctl_wrreg_t), mode);
170 if (status != 0) {
171 return (EFAULT);
174 hci1394_ohci_reg_write(soft_state->ohci, wrreg.addr, wrreg.data);
176 return (0);
180 static int
181 hci1394_ioctl_rdreg(hci1394_state_t *soft_state, void *arg, int mode)
183 hci1394_ioctl_rdreg_t rdreg;
184 int status;
187 ASSERT(soft_state != NULL);
188 ASSERT(arg != NULL);
190 status = ddi_copyin(arg, &rdreg, sizeof (hci1394_ioctl_rdreg_t), mode);
191 if (status != 0) {
192 return (EFAULT);
195 hci1394_ohci_reg_read(soft_state->ohci, rdreg.addr, &rdreg.data);
197 status = ddi_copyout(&rdreg, arg, sizeof (hci1394_ioctl_rdreg_t), mode);
198 if (status != 0) {
199 return (EFAULT);
202 return (0);
206 static int
207 hci1394_ioctl_wrvreg(hci1394_state_t *soft_state, void *arg, int mode)
209 hci1394_ioctl_wrvreg_t wrvreg;
210 int status;
213 ASSERT(soft_state != NULL);
214 ASSERT(arg != NULL);
216 status = ddi_copyin(arg, &wrvreg, sizeof (hci1394_ioctl_wrvreg_t),
217 mode);
218 if (status != 0) {
219 return (EFAULT);
222 status = hci1394_vendor_reg_write(soft_state->vendor,
223 wrvreg.regset, wrvreg.addr, wrvreg.data);
224 if (status != DDI_SUCCESS) {
225 return (EINVAL);
228 return (0);
232 static int
233 hci1394_ioctl_rdvreg(hci1394_state_t *soft_state, void *arg, int mode)
235 hci1394_ioctl_rdvreg_t rdvreg;
236 int status;
239 ASSERT(soft_state != NULL);
240 ASSERT(arg != NULL);
242 status = ddi_copyin(arg, &rdvreg, sizeof (hci1394_ioctl_rdvreg_t),
243 mode);
244 if (status != 0) {
245 return (EFAULT);
248 status = hci1394_vendor_reg_read(soft_state->vendor,
249 rdvreg.regset, rdvreg.addr, &rdvreg.data);
250 if (status != DDI_SUCCESS) {
251 return (EINVAL);
254 status = ddi_copyout(&rdvreg, arg, sizeof (hci1394_ioctl_rdvreg_t),
255 mode);
256 if (status != 0) {
257 return (EFAULT);
260 return (0);
264 static int
265 hci1394_ioctl_selfid_cnt(hci1394_state_t *soft_state, void *arg, int mode)
267 hci1394_ioctl_selfid_cnt_t selfid_cnt;
268 int status;
271 ASSERT(soft_state != NULL);
272 ASSERT(arg != NULL);
274 selfid_cnt.count = soft_state->drvinfo.di_stats.st_selfid_count;
276 status = ddi_copyout(&selfid_cnt, arg,
277 sizeof (hci1394_ioctl_selfid_cnt_t), mode);
278 if (status != 0) {
279 return (EFAULT);
282 return (0);
286 static int
287 hci1394_ioctl_busgen_cnt(hci1394_state_t *soft_state, void *arg, int mode)
289 hci1394_ioctl_busgen_cnt_t busgen_cnt;
290 int status;
293 ASSERT(soft_state != NULL);
294 ASSERT(arg != NULL);
296 busgen_cnt.count = hci1394_ohci_current_busgen(soft_state->ohci);
298 status = ddi_copyout(&busgen_cnt, arg,
299 sizeof (hci1394_ioctl_busgen_cnt_t), mode);
300 if (status != 0) {
301 return (EFAULT);
304 return (0);
308 static int
309 hci1394_ioctl_wrphy(hci1394_state_t *soft_state, void *arg, int mode)
311 hci1394_ioctl_wrphy_t wrphy;
312 int status;
315 ASSERT(soft_state != NULL);
316 ASSERT(arg != NULL);
318 status = ddi_copyin(arg, &wrphy, sizeof (hci1394_ioctl_wrphy_t), mode);
319 if (status != 0) {
320 return (EFAULT);
323 status = hci1394_ohci_phy_write(soft_state->ohci, wrphy.addr,
324 wrphy.data);
325 if (status != DDI_SUCCESS) {
326 return (EINVAL);
329 return (0);
333 static int
334 hci1394_ioctl_rdphy(hci1394_state_t *soft_state, void *arg, int mode)
336 hci1394_ioctl_rdphy_t rdphy;
337 int status;
340 ASSERT(soft_state != NULL);
341 ASSERT(arg != NULL);
343 status = ddi_copyin(arg, &rdphy, sizeof (hci1394_ioctl_rdphy_t), mode);
344 if (status != 0) {
345 return (EFAULT);
348 status = hci1394_ohci_phy_read(soft_state->ohci, rdphy.addr,
349 &rdphy.data);
350 if (status != DDI_SUCCESS) {
351 return (EINVAL);
354 status = ddi_copyout(&rdphy, arg, sizeof (hci1394_ioctl_rdphy_t), mode);
355 if (status != 0) {
356 return (EFAULT);
359 return (0);
363 static int
364 hci1394_ioctl_hbainfo(hci1394_state_t *soft_state, void *arg, int mode)
366 hci1394_ioctl_hbainfo_t hbainfo;
367 int status;
370 ASSERT(soft_state != NULL);
371 ASSERT(arg != NULL);
373 hbainfo.pci_vendor_id = soft_state->vendor_info.vendor_id;
374 hbainfo.pci_device_id = soft_state->vendor_info.device_id;
375 hbainfo.pci_revision_id = soft_state->vendor_info.revision_id;
376 hbainfo.ohci_version = soft_state->vendor_info.ohci_version;
377 hbainfo.ohci_vendor_id = soft_state->vendor_info.ohci_vendor_id;
378 hbainfo.ohci_vregset_cnt = soft_state->vendor_info.vendor_reg_count;
380 status = ddi_copyout(&hbainfo, arg, sizeof (hci1394_ioctl_hbainfo_t),
381 mode);
382 if (status != 0) {
383 return (EFAULT);
386 return (0);
390 static int
391 hci1394_ioctl_read_selfid(hci1394_state_t *soft_state, void *arg, int mode)
393 hci1394_ioctl_read_selfid_t read_selfid;
394 int status;
395 uint_t offset;
396 uint32_t data;
397 #ifdef _MULTI_DATAMODEL
398 hci1394_ioctl_readselfid32_t read_selfid32;
399 #endif
402 ASSERT(soft_state != NULL);
403 ASSERT(arg != NULL);
405 #ifdef _MULTI_DATAMODEL
406 switch (ddi_model_convert_from(mode & FMODELS)) {
408 /* 32-bit app in 64-bit kernel */
409 case DDI_MODEL_ILP32:
410 /* copy in the 32-bit version of the args */
411 status = ddi_copyin(arg, &read_selfid32,
412 sizeof (hci1394_ioctl_readselfid32_t), mode);
413 if (status != 0) {
414 return (EFAULT);
418 * Use a special function to process the 32-bit user address
419 * pointer embedded in the structure we pass in arg.
421 status = hci1394_ioctl_read_selfid32(soft_state,
422 &read_selfid32, mode);
423 return (status);
424 default:
425 break;
427 #endif
430 * if we got here, we either are a 64-bit app in a 64-bit kernel or a
431 * 32-bit app in a 32-bit kernel
434 /* copy in the args. We don't need to do any special conversions */
435 status = ddi_copyin(arg, &read_selfid,
436 sizeof (hci1394_ioctl_read_selfid_t), mode);
437 if (status != 0) {
438 return (EFAULT);
442 * make sure we are not trying to copy more data than the selfid buffer
443 * can hold. count is in quadlets and max_selfid_size is in bytes.
445 if ((read_selfid.count * 4) > OHCI_MAX_SELFID_SIZE) {
446 return (EINVAL);
450 * copy the selfid buffer one word at a time into the user buffer. The
451 * combination between having to do ddi_get32's (for endian reasons)
452 * and a ddi_copyout() make it easier to do it one word at a time.
454 for (offset = 0; offset < read_selfid.count; offset++) {
455 /* read word from selfid buffer */
456 hci1394_ohci_selfid_read(soft_state->ohci, offset, &data);
458 /* copy the selfid word into the user buffer */
459 status = ddi_copyout(&data, &read_selfid.buf[offset], 4, mode);
460 if (status != 0) {
461 return (EFAULT);
465 return (0);
469 #ifdef _MULTI_DATAMODEL
470 static int
471 hci1394_ioctl_read_selfid32(hci1394_state_t *soft_state,
472 hci1394_ioctl_readselfid32_t *read_selfid, int mode)
474 int status;
475 uint_t offset;
476 uint32_t data;
479 ASSERT(soft_state != NULL);
480 ASSERT(read_selfid != NULL);
483 * make sure we are not trying to copy more data than the selfid buffer
484 * can hold. count is in quadlets and max_selfid_size is in bytes.
486 if ((read_selfid->count * 4) > OHCI_MAX_SELFID_SIZE) {
487 return (EINVAL);
491 * copy the selfid buffer one word at a time into the user buffer. The
492 * combination between having to do ddi_get32's (for endian reasons) and
493 * a ddi_copyout() make it easier to do it one word at a time.
495 for (offset = 0; offset < read_selfid->count; offset++) {
496 /* read word from selfid buffer */
497 hci1394_ohci_selfid_read(soft_state->ohci, offset, &data);
498 /* copy the selfid word into the user buffer */
499 status = ddi_copyout(&data,
500 (void *)(uintptr_t)(read_selfid->buf + (offset * 4)),
501 4, mode);
502 if (status != 0) {
503 return (EFAULT);
507 return (0);
509 #endif