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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
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.
13 *
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]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * hci1394_ioctl.c
29 * Test ioctl's to support test/debug of the 1394 HW. hci1394_ioctl_enum_t is
30 * passed in cmd and a pointer to the appropriate structure (i.e.
31 * hci1394_ioctl_wrreg_t) is passed in arg.
32 */
33
34 #include <sys/conf.h>
35 #include <sys/modctl.h>
36 #include <sys/mkdev.h>
37 #include <sys/cred.h>
38 #include <sys/file.h>
39 #include <sys/types.h>
40 #include <sys/errno.h>
41 #include <sys/ddi.h>
42 #include <sys/sunddi.h>
43
44 #include <sys/1394/h1394.h>
45 #include <sys/1394/adapters/hci1394.h>
46 #include <sys/1394/adapters/hci1394_extern.h>
47 #include <sys/1394/adapters/hci1394_ioctl.h>
48
49
50 /* HCI1394_IOCTL_READ_SELFID for 32-bit apps in 64-bit kernel */
51 typedef struct hci1394_ioctl_readselfid32_s {
52 uint32_t buf;
53 uint_t count;
54 } hci1394_ioctl_readselfid32_t;
55
56
57 static int hci1394_ioctl_wrreg(hci1394_state_t *soft_state, void *arg,
58 int mode);
59 static int hci1394_ioctl_rdreg(hci1394_state_t *soft_state, void *arg,
60 int mode);
61 static int hci1394_ioctl_wrvreg(hci1394_state_t *soft_state, void *arg,
62 int mode);
63 static int hci1394_ioctl_rdvreg(hci1394_state_t *soft_state, void *arg,
64 int mode);
65 static int hci1394_ioctl_selfid_cnt(hci1394_state_t *soft_state, void *arg,
66 int mode);
67 static int hci1394_ioctl_busgen_cnt(hci1394_state_t *soft_state, void *arg,
68 int mode);
69 static int hci1394_ioctl_wrphy(hci1394_state_t *soft_state, void *arg,
70 int mode);
71 static int hci1394_ioctl_rdphy(hci1394_state_t *soft_state, void *arg,
72 int mode);
73 static int hci1394_ioctl_hbainfo(hci1394_state_t *soft_state, void *arg,
74 int mode);
75 static int hci1394_ioctl_read_selfid(hci1394_state_t *soft_state, void *arg,
76 int mode);
77 #ifdef _MULTI_DATAMODEL
78 static int hci1394_ioctl_read_selfid32(hci1394_state_t *soft_state,
79 hci1394_ioctl_readselfid32_t *read_selfid, int mode);
80 #endif
81
82
83 /* ARGSUSED */
84 int
hci1394_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)85 hci1394_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
86 int *rvalp)
87 {
88 hci1394_state_t *soft_state;
89 int instance;
90 int status;
91
92 instance = getminor(dev);
93 if (instance == -1) {
94 return (EBADF);
95 }
96
97 soft_state = ddi_get_soft_state(hci1394_statep, instance);
98 if (soft_state == NULL) {
99 return (EBADF);
100 }
101
102 status = 0;
103
104 switch (cmd) {
105 case HCI1394_IOCTL_WRITE_REG:
106 status = hci1394_ioctl_wrreg(soft_state, (void *)arg, mode);
107 break;
108 case HCI1394_IOCTL_READ_REG:
109 status = hci1394_ioctl_rdreg(soft_state, (void *)arg, mode);
110 break;
111 case HCI1394_IOCTL_READ_VREG:
112 status = hci1394_ioctl_rdvreg(soft_state, (void *)arg, mode);
113 break;
114 case HCI1394_IOCTL_WRITE_VREG:
115 status = hci1394_ioctl_wrvreg(soft_state, (void *)arg, mode);
116 break;
117 case HCI1394_IOCTL_RESET_BUS:
118 status = hci1394_ohci_bus_reset(soft_state->ohci);
119 break;
120 case HCI1394_IOCTL_SELFID_CNT:
121 status = hci1394_ioctl_selfid_cnt(soft_state, (void *)arg,
122 mode);
123 break;
124 case HCI1394_IOCTL_BUSGEN_CNT:
125 status = hci1394_ioctl_busgen_cnt(soft_state, (void *)arg,
126 mode);
127 break;
128 case HCI1394_IOCTL_READ_SELFID:
129 status = hci1394_ioctl_read_selfid(soft_state, (void *)arg,
130 mode);
131 break;
132 case HCI1394_IOCTL_READ_PHY:
133 status = hci1394_ioctl_rdphy(soft_state, (void *)arg, mode);
134 break;
135 case HCI1394_IOCTL_WRITE_PHY:
136 status = hci1394_ioctl_wrphy(soft_state, (void *)arg, mode);
137 break;
138 case HCI1394_IOCTL_HBA_INFO:
139 status = hci1394_ioctl_hbainfo(soft_state, (void *)arg, mode);
140 break;
141 default:
142 /*
143 * if we don't know what the ioctl is, forward it on to the
144 * services layer. The services layer will handle the devctl
145 * ioctl's along with any services layer private ioctls that
146 * it has defined.
147 */
148 status = h1394_ioctl(soft_state->drvinfo.di_sl_private, cmd,
149 arg, mode, credp, rvalp);
150 break;
151 }
152
153 return (status);
154 }
155
156
157 static int
hci1394_ioctl_wrreg(hci1394_state_t * soft_state,void * arg,int mode)158 hci1394_ioctl_wrreg(hci1394_state_t *soft_state, void *arg, int mode)
159 {
160 hci1394_ioctl_wrreg_t wrreg;
161 int status;
162
163
164 ASSERT(soft_state != NULL);
165 ASSERT(arg != NULL);
166
167 status = ddi_copyin(arg, &wrreg, sizeof (hci1394_ioctl_wrreg_t), mode);
168 if (status != 0) {
169 return (EFAULT);
170 }
171
172 hci1394_ohci_reg_write(soft_state->ohci, wrreg.addr, wrreg.data);
173
174 return (0);
175 }
176
177
178 static int
hci1394_ioctl_rdreg(hci1394_state_t * soft_state,void * arg,int mode)179 hci1394_ioctl_rdreg(hci1394_state_t *soft_state, void *arg, int mode)
180 {
181 hci1394_ioctl_rdreg_t rdreg;
182 int status;
183
184
185 ASSERT(soft_state != NULL);
186 ASSERT(arg != NULL);
187
188 status = ddi_copyin(arg, &rdreg, sizeof (hci1394_ioctl_rdreg_t), mode);
189 if (status != 0) {
190 return (EFAULT);
191 }
192
193 hci1394_ohci_reg_read(soft_state->ohci, rdreg.addr, &rdreg.data);
194
195 status = ddi_copyout(&rdreg, arg, sizeof (hci1394_ioctl_rdreg_t), mode);
196 if (status != 0) {
197 return (EFAULT);
198 }
199
200 return (0);
201 }
202
203
204 static int
hci1394_ioctl_wrvreg(hci1394_state_t * soft_state,void * arg,int mode)205 hci1394_ioctl_wrvreg(hci1394_state_t *soft_state, void *arg, int mode)
206 {
207 hci1394_ioctl_wrvreg_t wrvreg;
208 int status;
209
210
211 ASSERT(soft_state != NULL);
212 ASSERT(arg != NULL);
213
214 status = ddi_copyin(arg, &wrvreg, sizeof (hci1394_ioctl_wrvreg_t),
215 mode);
216 if (status != 0) {
217 return (EFAULT);
218 }
219
220 status = hci1394_vendor_reg_write(soft_state->vendor,
221 wrvreg.regset, wrvreg.addr, wrvreg.data);
222 if (status != DDI_SUCCESS) {
223 return (EINVAL);
224 }
225
226 return (0);
227 }
228
229
230 static int
hci1394_ioctl_rdvreg(hci1394_state_t * soft_state,void * arg,int mode)231 hci1394_ioctl_rdvreg(hci1394_state_t *soft_state, void *arg, int mode)
232 {
233 hci1394_ioctl_rdvreg_t rdvreg;
234 int status;
235
236
237 ASSERT(soft_state != NULL);
238 ASSERT(arg != NULL);
239
240 status = ddi_copyin(arg, &rdvreg, sizeof (hci1394_ioctl_rdvreg_t),
241 mode);
242 if (status != 0) {
243 return (EFAULT);
244 }
245
246 status = hci1394_vendor_reg_read(soft_state->vendor,
247 rdvreg.regset, rdvreg.addr, &rdvreg.data);
248 if (status != DDI_SUCCESS) {
249 return (EINVAL);
250 }
251
252 status = ddi_copyout(&rdvreg, arg, sizeof (hci1394_ioctl_rdvreg_t),
253 mode);
254 if (status != 0) {
255 return (EFAULT);
256 }
257
258 return (0);
259 }
260
261
262 static int
hci1394_ioctl_selfid_cnt(hci1394_state_t * soft_state,void * arg,int mode)263 hci1394_ioctl_selfid_cnt(hci1394_state_t *soft_state, void *arg, int mode)
264 {
265 hci1394_ioctl_selfid_cnt_t selfid_cnt;
266 int status;
267
268
269 ASSERT(soft_state != NULL);
270 ASSERT(arg != NULL);
271
272 selfid_cnt.count = soft_state->drvinfo.di_stats.st_selfid_count;
273
274 status = ddi_copyout(&selfid_cnt, arg,
275 sizeof (hci1394_ioctl_selfid_cnt_t), mode);
276 if (status != 0) {
277 return (EFAULT);
278 }
279
280 return (0);
281 }
282
283
284 static int
hci1394_ioctl_busgen_cnt(hci1394_state_t * soft_state,void * arg,int mode)285 hci1394_ioctl_busgen_cnt(hci1394_state_t *soft_state, void *arg, int mode)
286 {
287 hci1394_ioctl_busgen_cnt_t busgen_cnt;
288 int status;
289
290
291 ASSERT(soft_state != NULL);
292 ASSERT(arg != NULL);
293
294 busgen_cnt.count = hci1394_ohci_current_busgen(soft_state->ohci);
295
296 status = ddi_copyout(&busgen_cnt, arg,
297 sizeof (hci1394_ioctl_busgen_cnt_t), mode);
298 if (status != 0) {
299 return (EFAULT);
300 }
301
302 return (0);
303 }
304
305
306 static int
hci1394_ioctl_wrphy(hci1394_state_t * soft_state,void * arg,int mode)307 hci1394_ioctl_wrphy(hci1394_state_t *soft_state, void *arg, int mode)
308 {
309 hci1394_ioctl_wrphy_t wrphy;
310 int status;
311
312
313 ASSERT(soft_state != NULL);
314 ASSERT(arg != NULL);
315
316 status = ddi_copyin(arg, &wrphy, sizeof (hci1394_ioctl_wrphy_t), mode);
317 if (status != 0) {
318 return (EFAULT);
319 }
320
321 status = hci1394_ohci_phy_write(soft_state->ohci, wrphy.addr,
322 wrphy.data);
323 if (status != DDI_SUCCESS) {
324 return (EINVAL);
325 }
326
327 return (0);
328 }
329
330
331 static int
hci1394_ioctl_rdphy(hci1394_state_t * soft_state,void * arg,int mode)332 hci1394_ioctl_rdphy(hci1394_state_t *soft_state, void *arg, int mode)
333 {
334 hci1394_ioctl_rdphy_t rdphy;
335 int status;
336
337
338 ASSERT(soft_state != NULL);
339 ASSERT(arg != NULL);
340
341 status = ddi_copyin(arg, &rdphy, sizeof (hci1394_ioctl_rdphy_t), mode);
342 if (status != 0) {
343 return (EFAULT);
344 }
345
346 status = hci1394_ohci_phy_read(soft_state->ohci, rdphy.addr,
347 &rdphy.data);
348 if (status != DDI_SUCCESS) {
349 return (EINVAL);
350 }
351
352 status = ddi_copyout(&rdphy, arg, sizeof (hci1394_ioctl_rdphy_t), mode);
353 if (status != 0) {
354 return (EFAULT);
355 }
356
357 return (0);
358 }
359
360
361 static int
hci1394_ioctl_hbainfo(hci1394_state_t * soft_state,void * arg,int mode)362 hci1394_ioctl_hbainfo(hci1394_state_t *soft_state, void *arg, int mode)
363 {
364 hci1394_ioctl_hbainfo_t hbainfo;
365 int status;
366
367
368 ASSERT(soft_state != NULL);
369 ASSERT(arg != NULL);
370
371 hbainfo.pci_vendor_id = soft_state->vendor_info.vendor_id;
372 hbainfo.pci_device_id = soft_state->vendor_info.device_id;
373 hbainfo.pci_revision_id = soft_state->vendor_info.revision_id;
374 hbainfo.ohci_version = soft_state->vendor_info.ohci_version;
375 hbainfo.ohci_vendor_id = soft_state->vendor_info.ohci_vendor_id;
376 hbainfo.ohci_vregset_cnt = soft_state->vendor_info.vendor_reg_count;
377
378 status = ddi_copyout(&hbainfo, arg, sizeof (hci1394_ioctl_hbainfo_t),
379 mode);
380 if (status != 0) {
381 return (EFAULT);
382 }
383
384 return (0);
385 }
386
387
388 static int
hci1394_ioctl_read_selfid(hci1394_state_t * soft_state,void * arg,int mode)389 hci1394_ioctl_read_selfid(hci1394_state_t *soft_state, void *arg, int mode)
390 {
391 hci1394_ioctl_read_selfid_t read_selfid;
392 int status;
393 uint_t offset;
394 uint32_t data;
395 #ifdef _MULTI_DATAMODEL
396 hci1394_ioctl_readselfid32_t read_selfid32;
397 #endif
398
399
400 ASSERT(soft_state != NULL);
401 ASSERT(arg != NULL);
402
403 #ifdef _MULTI_DATAMODEL
404 switch (ddi_model_convert_from(mode & FMODELS)) {
405
406 /* 32-bit app in 64-bit kernel */
407 case DDI_MODEL_ILP32:
408 /* copy in the 32-bit version of the args */
409 status = ddi_copyin(arg, &read_selfid32,
410 sizeof (hci1394_ioctl_readselfid32_t), mode);
411 if (status != 0) {
412 return (EFAULT);
413 }
414
415 /*
416 * Use a special function to process the 32-bit user address
417 * pointer embedded in the structure we pass in arg.
418 */
419 status = hci1394_ioctl_read_selfid32(soft_state,
420 &read_selfid32, mode);
421 return (status);
422 default:
423 break;
424 }
425 #endif
426
427 /*
428 * if we got here, we either are a 64-bit app in a 64-bit kernel or a
429 * 32-bit app in a 32-bit kernel
430 */
431
432 /* copy in the args. We don't need to do any special conversions */
433 status = ddi_copyin(arg, &read_selfid,
434 sizeof (hci1394_ioctl_read_selfid_t), mode);
435 if (status != 0) {
436 return (EFAULT);
437 }
438
439 /*
440 * make sure we are not trying to copy more data than the selfid buffer
441 * can hold. count is in quadlets and max_selfid_size is in bytes.
442 */
443 if ((read_selfid.count * 4) > OHCI_MAX_SELFID_SIZE) {
444 return (EINVAL);
445 }
446
447 /*
448 * copy the selfid buffer one word at a time into the user buffer. The
449 * combination between having to do ddi_get32's (for endian reasons)
450 * and a ddi_copyout() make it easier to do it one word at a time.
451 */
452 for (offset = 0; offset < read_selfid.count; offset++) {
453 /* read word from selfid buffer */
454 hci1394_ohci_selfid_read(soft_state->ohci, offset, &data);
455
456 /* copy the selfid word into the user buffer */
457 status = ddi_copyout(&data, &read_selfid.buf[offset], 4, mode);
458 if (status != 0) {
459 return (EFAULT);
460 }
461 }
462
463 return (0);
464 }
465
466
467 #ifdef _MULTI_DATAMODEL
468 static int
hci1394_ioctl_read_selfid32(hci1394_state_t * soft_state,hci1394_ioctl_readselfid32_t * read_selfid,int mode)469 hci1394_ioctl_read_selfid32(hci1394_state_t *soft_state,
470 hci1394_ioctl_readselfid32_t *read_selfid, int mode)
471 {
472 int status;
473 uint_t offset;
474 uint32_t data;
475
476
477 ASSERT(soft_state != NULL);
478 ASSERT(read_selfid != NULL);
479
480 /*
481 * make sure we are not trying to copy more data than the selfid buffer
482 * can hold. count is in quadlets and max_selfid_size is in bytes.
483 */
484 if ((read_selfid->count * 4) > OHCI_MAX_SELFID_SIZE) {
485 return (EINVAL);
486 }
487
488 /*
489 * copy the selfid buffer one word at a time into the user buffer. The
490 * combination between having to do ddi_get32's (for endian reasons) and
491 * a ddi_copyout() make it easier to do it one word at a time.
492 */
493 for (offset = 0; offset < read_selfid->count; offset++) {
494 /* read word from selfid buffer */
495 hci1394_ohci_selfid_read(soft_state->ohci, offset, &data);
496 /* copy the selfid word into the user buffer */
497 status = ddi_copyout(&data,
498 (void *)(uintptr_t)(read_selfid->buf + (offset * 4)),
499 4, mode);
500 if (status != 0) {
501 return (EFAULT);
502 }
503 }
504
505 return (0);
506 }
507 #endif
508