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 */ 25 26 27 /* 28 * av1394 driver 29 */ 30 31 #include <sys/param.h> 32 #include <sys/errno.h> 33 #include <sys/cred.h> 34 #include <sys/conf.h> 35 #include <sys/modctl.h> 36 #include <sys/stat.h> 37 #include <sys/ddi.h> 38 #include <sys/sunddi.h> 39 40 #include <sys/1394/targets/av1394/av1394_impl.h> 41 42 /* DDI/DKI entry points */ 43 static int av1394_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 44 static int av1394_attach(dev_info_t *, ddi_attach_cmd_t); 45 static int av1394_detach(dev_info_t *, ddi_detach_cmd_t); 46 static int av1394_open(dev_t *, int, int, cred_t *); 47 static int av1394_close(dev_t, int, int, cred_t *); 48 static int av1394_read(dev_t, struct uio *, cred_t *); 49 static int av1394_write(dev_t, struct uio *, cred_t *); 50 static int av1394_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 51 static int av1394_devmap(dev_t, devmap_cookie_t, offset_t, size_t, 52 size_t *, uint_t); 53 static int av1394_poll(dev_t, short, int, short *, struct pollhead **); 54 55 /* configuration routines */ 56 static void av1394_cleanup(av1394_inst_t *, int); 57 static int av1394_t1394_attach(av1394_inst_t *, dev_info_t *); 58 static void av1394_t1394_detach(av1394_inst_t *); 59 static int av1394_add_events(av1394_inst_t *); 60 static void av1394_remove_events(av1394_inst_t *); 61 62 /* CPR */ 63 static int av1394_cpr_suspend(av1394_inst_t *); 64 static int av1394_cpr_resume(av1394_inst_t *); 65 66 /* callbacks */ 67 static void av1394_bus_reset(dev_info_t *, ddi_eventcookie_t, void *, 68 void *); 69 static void av1394_disconnect(dev_info_t *, ddi_eventcookie_t, void *, 70 void *); 71 static void av1394_reconnect(dev_info_t *, ddi_eventcookie_t, void *, 72 void *); 73 74 extern struct mod_ops mod_driverops; 75 76 struct cb_ops av1394_cb_ops = { 77 av1394_open, /* open */ 78 av1394_close, /* close */ 79 nulldev, /* strategy */ 80 nulldev, /* print */ 81 nulldev, /* dump */ 82 av1394_read, /* read */ 83 av1394_write, /* write */ 84 av1394_ioctl, /* ioctl */ 85 av1394_devmap, /* devmap */ 86 nulldev, /* mmap */ 87 nulldev, /* segmap */ 88 av1394_poll, /* poll */ 89 ddi_prop_op, /* cb_prop_op */ 90 NULL, /* streamtab */ 91 D_MP | D_NEW | D_HOTPLUG | D_DEVMAP 92 }; 93 94 static struct dev_ops av1394_ops = { 95 DEVO_REV, /* devo_rev */ 96 0, /* refcnt */ 97 av1394_getinfo, /* getinfo */ 98 nulldev, /* identify */ 99 nulldev, /* probe */ 100 av1394_attach, /* attach */ 101 av1394_detach, /* detach */ 102 nodev, /* reset */ 103 &av1394_cb_ops, /* driver operations */ 104 NULL, /* bus operations */ 105 NULL, /* power */ 106 ddi_quiesce_not_supported, /* devo_quiesce */ 107 }; 108 109 static struct modldrv av1394_modldrv = { 110 &mod_driverops, 111 "IEEE 1394 AV driver", 112 &av1394_ops 113 }; 114 115 static struct modlinkage av1394_modlinkage = { 116 MODREV_1, 117 &av1394_modldrv, 118 NULL, 119 }; 120 121 static void *av1394_statep; 122 123 #define AV1394_INST2STATE(inst) (ddi_get_soft_state(av1394_statep, inst)) 124 #define AV1394_DEV2STATE(dev) \ 125 (ddi_get_soft_state(av1394_statep, AV1394_DEV2INST(dev))) 126 127 /* 128 * 129 * --- DDI/DKI entry points 130 * 131 */ 132 int 133 _init(void) 134 { 135 int error; 136 137 error = ddi_soft_state_init(&av1394_statep, sizeof (av1394_inst_t), 1); 138 if (error != 0) { 139 return (error); 140 } 141 142 if ((error = mod_install(&av1394_modlinkage)) != 0) { 143 ddi_soft_state_fini(&av1394_statep); 144 } 145 146 return (error); 147 } 148 149 int 150 _fini(void) 151 { 152 int error; 153 154 if ((error = mod_remove(&av1394_modlinkage)) == 0) { 155 ddi_soft_state_fini(&av1394_statep); 156 } 157 158 return (error); 159 } 160 161 int 162 _info(struct modinfo *modinfop) 163 { 164 return (mod_info(&av1394_modlinkage, modinfop)); 165 } 166 167 /* 168 * attach 169 */ 170 static int 171 av1394_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 172 { 173 int instance = ddi_get_instance(dip); 174 av1394_inst_t *avp; 175 176 switch (cmd) { 177 case DDI_ATTACH: 178 break; 179 case DDI_RESUME: 180 if ((avp = AV1394_INST2STATE(instance)) == NULL) { 181 return (DDI_FAILURE); 182 } 183 return (av1394_cpr_resume(avp)); 184 default: 185 return (DDI_FAILURE); 186 } 187 188 if (ddi_soft_state_zalloc(av1394_statep, instance) != 0) { 189 return (DDI_FAILURE); 190 } 191 avp = AV1394_INST2STATE(instance); 192 193 if (av1394_t1394_attach(avp, dip) != DDI_SUCCESS) { 194 av1394_cleanup(avp, 1); 195 return (DDI_FAILURE); 196 } 197 198 mutex_init(&avp->av_mutex, NULL, MUTEX_DRIVER, 199 avp->av_attachinfo.iblock_cookie); 200 201 #ifndef __lock_lint 202 avp->av_dip = dip; 203 avp->av_instance = instance; 204 #endif 205 206 if (av1394_add_events(avp) != DDI_SUCCESS) { 207 av1394_cleanup(avp, 2); 208 return (DDI_FAILURE); 209 } 210 211 if (av1394_isoch_attach(avp) != DDI_SUCCESS) { 212 av1394_cleanup(avp, 3); 213 return (DDI_FAILURE); 214 } 215 216 if (av1394_async_attach(avp) != DDI_SUCCESS) { 217 av1394_cleanup(avp, 4); 218 return (DDI_FAILURE); 219 } 220 221 #ifndef __lock_lint 222 avp->av_dev_state = AV1394_DEV_ONLINE; 223 #endif 224 225 ddi_report_dev(dip); 226 227 return (DDI_SUCCESS); 228 } 229 230 static int 231 av1394_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 232 { 233 int instance = ddi_get_instance(dip); 234 av1394_inst_t *avp; 235 236 if ((avp = AV1394_INST2STATE(instance)) == NULL) { 237 return (DDI_FAILURE); 238 } 239 240 switch (cmd) { 241 case DDI_DETACH: 242 av1394_cleanup(avp, AV1394_CLEANUP_LEVEL_MAX); 243 return (DDI_SUCCESS); 244 case DDI_SUSPEND: 245 return (av1394_cpr_suspend(avp)); 246 default: 247 return (DDI_FAILURE); 248 } 249 } 250 251 /*ARGSUSED*/ 252 static int 253 av1394_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 254 void **result) 255 { 256 dev_t dev = (dev_t)arg; 257 av1394_inst_t *avp; 258 int rval = DDI_FAILURE; 259 260 switch (infocmd) { 261 case DDI_INFO_DEVT2DEVINFO: 262 if ((avp = AV1394_DEV2STATE(dev)) != NULL) { 263 *result = avp->av_dip; 264 rval = DDI_SUCCESS; 265 } else { 266 *result = NULL; 267 } 268 break; 269 case DDI_INFO_DEVT2INSTANCE: 270 *result = (void *)(uintptr_t)AV1394_DEV2INST(dev); 271 rval = DDI_SUCCESS; 272 break; 273 } 274 275 return (rval); 276 } 277 278 /*ARGSUSED*/ 279 static int 280 av1394_open(dev_t *dev, int flag, int otyp, cred_t *cr) 281 { 282 av1394_inst_t *avp = AV1394_DEV2STATE(*dev); 283 int ret = ENXIO; 284 285 if (avp != NULL) { 286 if (AV1394_DEV_IS_ISOCH(*dev)) { 287 ret = 0; 288 } else if (AV1394_DEV_IS_ASYNC(*dev)) { 289 ret = av1394_async_open(avp, flag); 290 } 291 } 292 return (ret); 293 } 294 295 /*ARGSUSED*/ 296 static int 297 av1394_close(dev_t dev, int flag, int otyp, cred_t *cr) 298 { 299 av1394_inst_t *avp = AV1394_DEV2STATE(dev); 300 int ret = ENXIO; 301 302 if (avp != NULL) { 303 if (AV1394_DEV_IS_ISOCH(dev)) { 304 ret = av1394_isoch_close(avp, flag); 305 } else if (AV1394_DEV_IS_ASYNC(dev)) { 306 ret = av1394_async_close(avp, flag); 307 } 308 } 309 return (ret); 310 } 311 312 /*ARGSUSED*/ 313 static int 314 av1394_read(dev_t dev, struct uio *uiop, cred_t *cr) 315 { 316 av1394_inst_t *avp = AV1394_DEV2STATE(dev); 317 int ret = ENXIO; 318 319 if (avp != NULL) { 320 if (AV1394_DEV_IS_ISOCH(dev)) { 321 ret = av1394_isoch_read(avp, uiop); 322 } else if (AV1394_DEV_IS_ASYNC(dev)) { 323 ret = av1394_async_read(avp, uiop); 324 } 325 } 326 return (ret); 327 } 328 329 /*ARGSUSED*/ 330 static int 331 av1394_write(dev_t dev, struct uio *uiop, cred_t *cr) 332 { 333 av1394_inst_t *avp = AV1394_DEV2STATE(dev); 334 int ret = ENXIO; 335 336 if (avp != NULL) { 337 if (AV1394_DEV_IS_ISOCH(dev)) { 338 ret = av1394_isoch_write(avp, uiop); 339 } else if (AV1394_DEV_IS_ASYNC(dev)) { 340 ret = av1394_async_write(avp, uiop); 341 } 342 } 343 return (ret); 344 } 345 346 /*ARGSUSED*/ 347 static int 348 av1394_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rvalp) 349 { 350 av1394_inst_t *avp = AV1394_DEV2STATE(dev); 351 int ret = ENXIO; 352 353 if (avp != NULL) { 354 if (AV1394_DEV_IS_ISOCH(dev)) { 355 ret = av1394_isoch_ioctl(avp, cmd, arg, mode, rvalp); 356 } else if (AV1394_DEV_IS_ASYNC(dev)) { 357 ret = av1394_async_ioctl(avp, cmd, arg, mode, rvalp); 358 } 359 } 360 return (ret); 361 } 362 363 /*ARGSUSED*/ 364 static int 365 av1394_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len, 366 size_t *maplen, uint_t model) 367 { 368 av1394_inst_t *avp = AV1394_DEV2STATE(dev); 369 int ret = ENXIO; 370 371 if ((avp != NULL) && (AV1394_DEV_IS_ISOCH(dev))) { 372 ret = av1394_isoch_devmap(avp, dhp, off, len, maplen, model); 373 } 374 return (ret); 375 } 376 377 static int 378 av1394_poll(dev_t dev, short events, int anyyet, short *reventsp, 379 struct pollhead **phpp) 380 { 381 av1394_inst_t *avp = AV1394_DEV2STATE(dev); 382 int ret = ENXIO; 383 384 if ((avp != NULL) && AV1394_DEV_IS_ASYNC(dev)) { 385 ret = av1394_async_poll(avp, events, anyyet, reventsp, phpp); 386 } 387 return (ret); 388 } 389 390 391 /* 392 * 393 * --- configuration routines 394 * 395 * av1394_cleanup() 396 * Cleanup after attach 397 */ 398 static void 399 av1394_cleanup(av1394_inst_t *avp, int level) 400 { 401 ASSERT((level > 0) && (level <= AV1394_CLEANUP_LEVEL_MAX)); 402 403 switch (level) { 404 default: 405 av1394_async_detach(avp); 406 /* FALLTHRU */ 407 case 4: 408 av1394_isoch_detach(avp); 409 /* FALLTHRU */ 410 case 3: 411 av1394_remove_events(avp); 412 /* FALLTHRU */ 413 case 2: 414 av1394_t1394_detach(avp); 415 mutex_destroy(&avp->av_mutex); 416 /* FALLTHRU */ 417 case 1: 418 ddi_soft_state_free(av1394_statep, avp->av_instance); 419 } 420 } 421 422 static int 423 av1394_t1394_attach(av1394_inst_t *avp, dev_info_t *dip) 424 { 425 int ret; 426 427 ret = t1394_attach(dip, T1394_VERSION_V1, 0, &avp->av_attachinfo, 428 &avp->av_t1394_hdl); 429 430 return (ret); 431 } 432 433 static void 434 av1394_t1394_detach(av1394_inst_t *avp) 435 { 436 (void) t1394_detach(&avp->av_t1394_hdl, 0); 437 } 438 439 static int 440 av1394_add_events(av1394_inst_t *avp) 441 { 442 ddi_eventcookie_t br_evc, rem_evc, ins_evc; 443 444 if (ddi_get_eventcookie(avp->av_dip, DDI_DEVI_BUS_RESET_EVENT, 445 &br_evc) != DDI_SUCCESS) { 446 return (DDI_FAILURE); 447 } 448 if (ddi_add_event_handler(avp->av_dip, br_evc, av1394_bus_reset, 449 avp, &avp->av_reset_cb) != DDI_SUCCESS) { 450 return (DDI_FAILURE); 451 } 452 453 if (ddi_get_eventcookie(avp->av_dip, DDI_DEVI_REMOVE_EVENT, 454 &rem_evc) != DDI_SUCCESS) { 455 (void) ddi_remove_event_handler(avp->av_reset_cb); 456 return (DDI_FAILURE); 457 } 458 if (ddi_add_event_handler(avp->av_dip, rem_evc, av1394_disconnect, 459 avp, &avp->av_remove_cb) != DDI_SUCCESS) { 460 (void) ddi_remove_event_handler(avp->av_reset_cb); 461 return (DDI_FAILURE); 462 } 463 464 if (ddi_get_eventcookie(avp->av_dip, DDI_DEVI_INSERT_EVENT, 465 &ins_evc) != DDI_SUCCESS) { 466 (void) ddi_remove_event_handler(avp->av_remove_cb); 467 (void) ddi_remove_event_handler(avp->av_reset_cb); 468 return (DDI_FAILURE); 469 } 470 if (ddi_add_event_handler(avp->av_dip, ins_evc, av1394_reconnect, 471 avp, &avp->av_insert_cb) != DDI_SUCCESS) { 472 (void) ddi_remove_event_handler(avp->av_remove_cb); 473 (void) ddi_remove_event_handler(avp->av_reset_cb); 474 return (DDI_FAILURE); 475 } 476 477 return (DDI_SUCCESS); 478 } 479 480 static void 481 av1394_remove_events(av1394_inst_t *avp) 482 { 483 ddi_eventcookie_t evc; 484 485 if (ddi_get_eventcookie(avp->av_dip, DDI_DEVI_INSERT_EVENT, 486 &evc) == DDI_SUCCESS) { 487 (void) ddi_remove_event_handler(avp->av_insert_cb); 488 } 489 490 if (ddi_get_eventcookie(avp->av_dip, DDI_DEVI_REMOVE_EVENT, 491 &evc) == DDI_SUCCESS) { 492 (void) ddi_remove_event_handler(avp->av_remove_cb); 493 } 494 495 if (ddi_get_eventcookie(avp->av_dip, DDI_DEVI_BUS_RESET_EVENT, 496 &evc) == DDI_SUCCESS) { 497 (void) ddi_remove_event_handler(avp->av_reset_cb); 498 } 499 } 500 501 /* 502 * 503 * --- CPR 504 * 505 */ 506 static int 507 av1394_cpr_suspend(av1394_inst_t *avp) 508 { 509 int ret; 510 511 ret = av1394_isoch_cpr_suspend(avp); 512 513 if (ret == DDI_SUCCESS) { 514 mutex_enter(&avp->av_mutex); 515 avp->av_prev_dev_state = avp->av_dev_state; 516 avp->av_dev_state = AV1394_DEV_SUSPENDED; 517 mutex_exit(&avp->av_mutex); 518 } 519 520 return (ret); 521 } 522 523 /* 524 * CPR resume should always succeed 525 */ 526 static int 527 av1394_cpr_resume(av1394_inst_t *avp) 528 { 529 mutex_enter(&avp->av_mutex); 530 avp->av_dev_state = avp->av_prev_dev_state; 531 mutex_exit(&avp->av_mutex); 532 533 (void) av1394_async_cpr_resume(avp); 534 535 return (DDI_SUCCESS); 536 } 537 538 /* 539 * 540 * --- callbacks 541 * 542 */ 543 /*ARGSUSED*/ 544 static void 545 av1394_bus_reset(dev_info_t *dip, ddi_eventcookie_t evc, void *arg, void *data) 546 { 547 av1394_inst_t *avp = arg; 548 549 if (avp == NULL) { 550 return; 551 } 552 553 mutex_enter(&avp->av_mutex); 554 avp->av_attachinfo.localinfo = *(t1394_localinfo_t *)data; 555 mutex_exit(&avp->av_mutex); 556 557 av1394_async_bus_reset(avp); 558 av1394_cmp_bus_reset(avp); 559 } 560 561 /*ARGSUSED*/ 562 static void 563 av1394_disconnect(dev_info_t *dip, ddi_eventcookie_t evc, void *arg, void *data) 564 { 565 av1394_inst_t *avp = arg; 566 567 if (avp == NULL) { 568 return; 569 } 570 571 mutex_enter(&avp->av_mutex); 572 avp->av_dev_state = AV1394_DEV_DISCONNECTED; 573 mutex_exit(&avp->av_mutex); 574 } 575 576 /*ARGSUSED*/ 577 static void 578 av1394_reconnect(dev_info_t *dip, ddi_eventcookie_t evc, void *arg, void *data) 579 { 580 av1394_inst_t *avp = arg; 581 582 if (avp == NULL) { 583 return; 584 } 585 586 mutex_enter(&avp->av_mutex); 587 avp->av_dev_state = AV1394_DEV_ONLINE; 588 avp->av_attachinfo.localinfo = *(t1394_localinfo_t *)data; 589 mutex_exit(&avp->av_mutex); 590 591 av1394_async_reconnect(avp); 592 } 593