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 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 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 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 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 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 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 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 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 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 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 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 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