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 #ifndef NPROBE 124 extern int tnf_mod_load(void); 125 extern int tnf_mod_unload(struct modlinkage *mlp); 126 #endif 127 128 #define AV1394_INST2STATE(inst) (ddi_get_soft_state(av1394_statep, inst)) 129 #define AV1394_DEV2STATE(dev) \ 130 (ddi_get_soft_state(av1394_statep, AV1394_DEV2INST(dev))) 131 132 #define AV1394_TNF_ENTER(func) \ 133 TNF_PROBE_0_DEBUG(func##_enter, AV1394_TNF_INST_STACK, ""); 134 135 #define AV1394_TNF_EXIT(func) \ 136 TNF_PROBE_0_DEBUG(func##_exit, AV1394_TNF_INST_STACK, ""); 137 138 /* 139 * 140 * --- DDI/DKI entry points 141 * 142 */ 143 int 144 _init(void) 145 { 146 int error; 147 148 #ifndef NPROBE 149 (void) tnf_mod_load(); 150 #endif 151 error = ddi_soft_state_init(&av1394_statep, sizeof (av1394_inst_t), 1); 152 if (error != 0) { 153 #ifndef NPROBE 154 (void) tnf_mod_unload(&av1394_modlinkage); 155 #endif 156 return (error); 157 } 158 159 if ((error = mod_install(&av1394_modlinkage)) != 0) { 160 ddi_soft_state_fini(&av1394_statep); 161 #ifndef NPROBE 162 (void) tnf_mod_unload(&av1394_modlinkage); 163 #endif 164 } 165 166 return (error); 167 } 168 169 int 170 _fini(void) 171 { 172 int error; 173 174 if ((error = mod_remove(&av1394_modlinkage)) == 0) { 175 ddi_soft_state_fini(&av1394_statep); 176 #ifndef NPROBE 177 (void) tnf_mod_unload(&av1394_modlinkage); 178 #endif 179 } 180 181 return (error); 182 } 183 184 int 185 _info(struct modinfo *modinfop) 186 { 187 return (mod_info(&av1394_modlinkage, modinfop)); 188 } 189 190 /* 191 * attach 192 */ 193 static int 194 av1394_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 195 { 196 int instance = ddi_get_instance(dip); 197 av1394_inst_t *avp; 198 199 AV1394_TNF_ENTER(av1394_attach); 200 201 switch (cmd) { 202 case DDI_ATTACH: 203 break; 204 case DDI_RESUME: 205 if ((avp = AV1394_INST2STATE(instance)) == NULL) { 206 return (DDI_FAILURE); 207 } 208 return (av1394_cpr_resume(avp)); 209 default: 210 AV1394_TNF_EXIT(av1394_attach); 211 return (DDI_FAILURE); 212 } 213 214 if (ddi_soft_state_zalloc(av1394_statep, instance) != 0) { 215 TNF_PROBE_0(av1394_attach_error_soft_state_zalloc, 216 AV1394_TNF_INST_ERROR, ""); 217 AV1394_TNF_EXIT(av1394_attach); 218 return (DDI_FAILURE); 219 } 220 avp = AV1394_INST2STATE(instance); 221 222 if (av1394_t1394_attach(avp, dip) != DDI_SUCCESS) { 223 av1394_cleanup(avp, 1); 224 AV1394_TNF_EXIT(av1394_attach); 225 return (DDI_FAILURE); 226 } 227 228 mutex_init(&avp->av_mutex, NULL, MUTEX_DRIVER, 229 avp->av_attachinfo.iblock_cookie); 230 231 #ifndef __lock_lint 232 avp->av_dip = dip; 233 avp->av_instance = instance; 234 #endif 235 236 if (av1394_add_events(avp) != DDI_SUCCESS) { 237 av1394_cleanup(avp, 2); 238 AV1394_TNF_EXIT(av1394_attach); 239 return (DDI_FAILURE); 240 } 241 242 if (av1394_isoch_attach(avp) != DDI_SUCCESS) { 243 av1394_cleanup(avp, 3); 244 AV1394_TNF_EXIT(av1394_attach); 245 return (DDI_FAILURE); 246 } 247 248 if (av1394_async_attach(avp) != DDI_SUCCESS) { 249 av1394_cleanup(avp, 4); 250 AV1394_TNF_EXIT(av1394_attach); 251 return (DDI_FAILURE); 252 } 253 254 #ifndef __lock_lint 255 avp->av_dev_state = AV1394_DEV_ONLINE; 256 #endif 257 258 ddi_report_dev(dip); 259 260 AV1394_TNF_EXIT(av1394_attach); 261 return (DDI_SUCCESS); 262 } 263 264 static int 265 av1394_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 266 { 267 int instance = ddi_get_instance(dip); 268 av1394_inst_t *avp; 269 270 AV1394_TNF_ENTER(av1394_detach); 271 272 if ((avp = AV1394_INST2STATE(instance)) == NULL) { 273 TNF_PROBE_0(av1394_detach_error_instance, 274 AV1394_TNF_INST_ERROR, ""); 275 AV1394_TNF_EXIT(av1394_detach); 276 return (DDI_FAILURE); 277 } 278 279 switch (cmd) { 280 case DDI_DETACH: 281 av1394_cleanup(avp, AV1394_CLEANUP_LEVEL_MAX); 282 AV1394_TNF_EXIT(av1394_detach); 283 return (DDI_SUCCESS); 284 case DDI_SUSPEND: 285 return (av1394_cpr_suspend(avp)); 286 default: 287 AV1394_TNF_EXIT(av1394_detach); 288 return (DDI_FAILURE); 289 } 290 } 291 292 /*ARGSUSED*/ 293 static int 294 av1394_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 295 void **result) 296 { 297 dev_t dev = (dev_t)arg; 298 av1394_inst_t *avp; 299 int rval = DDI_FAILURE; 300 301 switch (infocmd) { 302 case DDI_INFO_DEVT2DEVINFO: 303 if ((avp = AV1394_DEV2STATE(dev)) != NULL) { 304 *result = avp->av_dip; 305 rval = DDI_SUCCESS; 306 } else { 307 *result = NULL; 308 } 309 break; 310 case DDI_INFO_DEVT2INSTANCE: 311 *result = (void *)(uintptr_t)AV1394_DEV2INST(dev); 312 rval = DDI_SUCCESS; 313 break; 314 } 315 316 return (rval); 317 } 318 319 /*ARGSUSED*/ 320 static int 321 av1394_open(dev_t *dev, int flag, int otyp, cred_t *cr) 322 { 323 av1394_inst_t *avp = AV1394_DEV2STATE(*dev); 324 int ret = ENXIO; 325 326 AV1394_TNF_ENTER(av1394_open); 327 if (avp != NULL) { 328 if (AV1394_DEV_IS_ISOCH(*dev)) { 329 ret = 0; 330 } else if (AV1394_DEV_IS_ASYNC(*dev)) { 331 ret = av1394_async_open(avp, flag); 332 } 333 } 334 AV1394_TNF_EXIT(av1394_open); 335 return (ret); 336 } 337 338 /*ARGSUSED*/ 339 static int 340 av1394_close(dev_t dev, int flag, int otyp, cred_t *cr) 341 { 342 av1394_inst_t *avp = AV1394_DEV2STATE(dev); 343 int ret = ENXIO; 344 345 AV1394_TNF_ENTER(av1394_close); 346 if (avp != NULL) { 347 if (AV1394_DEV_IS_ISOCH(dev)) { 348 ret = av1394_isoch_close(avp, flag); 349 } else if (AV1394_DEV_IS_ASYNC(dev)) { 350 ret = av1394_async_close(avp, flag); 351 } 352 } 353 AV1394_TNF_EXIT(av1394_close); 354 return (ret); 355 } 356 357 /*ARGSUSED*/ 358 static int 359 av1394_read(dev_t dev, struct uio *uiop, cred_t *cr) 360 { 361 av1394_inst_t *avp = AV1394_DEV2STATE(dev); 362 int ret = ENXIO; 363 364 AV1394_TNF_ENTER(av1394_read); 365 if (avp != NULL) { 366 if (AV1394_DEV_IS_ISOCH(dev)) { 367 ret = av1394_isoch_read(avp, uiop); 368 } else if (AV1394_DEV_IS_ASYNC(dev)) { 369 ret = av1394_async_read(avp, uiop); 370 } 371 } 372 AV1394_TNF_EXIT(av1394_read); 373 return (ret); 374 } 375 376 /*ARGSUSED*/ 377 static int 378 av1394_write(dev_t dev, struct uio *uiop, cred_t *cr) 379 { 380 av1394_inst_t *avp = AV1394_DEV2STATE(dev); 381 int ret = ENXIO; 382 383 AV1394_TNF_ENTER(av1394_write); 384 if (avp != NULL) { 385 if (AV1394_DEV_IS_ISOCH(dev)) { 386 ret = av1394_isoch_write(avp, uiop); 387 } else if (AV1394_DEV_IS_ASYNC(dev)) { 388 ret = av1394_async_write(avp, uiop); 389 } 390 } 391 AV1394_TNF_EXIT(av1394_write); 392 return (ret); 393 } 394 395 /*ARGSUSED*/ 396 static int 397 av1394_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rvalp) 398 { 399 av1394_inst_t *avp = AV1394_DEV2STATE(dev); 400 int ret = ENXIO; 401 402 AV1394_TNF_ENTER(av1394_ioctl); 403 if (avp != NULL) { 404 if (AV1394_DEV_IS_ISOCH(dev)) { 405 ret = av1394_isoch_ioctl(avp, cmd, arg, mode, rvalp); 406 } else if (AV1394_DEV_IS_ASYNC(dev)) { 407 ret = av1394_async_ioctl(avp, cmd, arg, mode, rvalp); 408 } 409 } 410 AV1394_TNF_EXIT(av1394_ioctl); 411 return (ret); 412 } 413 414 /*ARGSUSED*/ 415 static int 416 av1394_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len, 417 size_t *maplen, uint_t model) 418 { 419 av1394_inst_t *avp = AV1394_DEV2STATE(dev); 420 int ret = ENXIO; 421 422 AV1394_TNF_ENTER(av1394_devmap); 423 if ((avp != NULL) && (AV1394_DEV_IS_ISOCH(dev))) { 424 ret = av1394_isoch_devmap(avp, dhp, off, len, maplen, model); 425 } 426 AV1394_TNF_EXIT(av1394_devmap); 427 return (ret); 428 } 429 430 static int 431 av1394_poll(dev_t dev, short events, int anyyet, short *reventsp, 432 struct pollhead **phpp) 433 { 434 av1394_inst_t *avp = AV1394_DEV2STATE(dev); 435 int ret = ENXIO; 436 437 AV1394_TNF_ENTER(av1394_poll); 438 if ((avp != NULL) && AV1394_DEV_IS_ASYNC(dev)) { 439 ret = av1394_async_poll(avp, events, anyyet, reventsp, phpp); 440 } 441 AV1394_TNF_EXIT(av1394_poll); 442 return (ret); 443 } 444 445 446 /* 447 * 448 * --- configuration routines 449 * 450 * av1394_cleanup() 451 * Cleanup after attach 452 */ 453 static void 454 av1394_cleanup(av1394_inst_t *avp, int level) 455 { 456 ASSERT((level > 0) && (level <= AV1394_CLEANUP_LEVEL_MAX)); 457 458 AV1394_TNF_ENTER(av1394_cleanup); 459 switch (level) { 460 default: 461 av1394_async_detach(avp); 462 /* FALLTHRU */ 463 case 4: 464 av1394_isoch_detach(avp); 465 /* FALLTHRU */ 466 case 3: 467 av1394_remove_events(avp); 468 /* FALLTHRU */ 469 case 2: 470 av1394_t1394_detach(avp); 471 mutex_destroy(&avp->av_mutex); 472 /* FALLTHRU */ 473 case 1: 474 ddi_soft_state_free(av1394_statep, avp->av_instance); 475 } 476 AV1394_TNF_EXIT(av1394_cleanup); 477 } 478 479 static int 480 av1394_t1394_attach(av1394_inst_t *avp, dev_info_t *dip) 481 { 482 int ret; 483 484 AV1394_TNF_ENTER(av1394_t1394_attach); 485 486 ret = t1394_attach(dip, T1394_VERSION_V1, 0, &avp->av_attachinfo, 487 &avp->av_t1394_hdl); 488 489 if (ret != DDI_SUCCESS) { 490 TNF_PROBE_1(av1394_t1394_attach_error, AV1394_TNF_INST_ERROR, 491 "", tnf_int, ret, ret); 492 } 493 494 AV1394_TNF_EXIT(av1394_t1394_attach); 495 return (ret); 496 } 497 498 static void 499 av1394_t1394_detach(av1394_inst_t *avp) 500 { 501 AV1394_TNF_ENTER(av1394_t1394_detach); 502 503 (void) t1394_detach(&avp->av_t1394_hdl, 0); 504 505 AV1394_TNF_EXIT(av1394_t1394_detach); 506 } 507 508 static int 509 av1394_add_events(av1394_inst_t *avp) 510 { 511 ddi_eventcookie_t br_evc, rem_evc, ins_evc; 512 513 if (ddi_get_eventcookie(avp->av_dip, DDI_DEVI_BUS_RESET_EVENT, 514 &br_evc) != DDI_SUCCESS) { 515 TNF_PROBE_0(av1394_add_events_error_bus_reset_cookie, 516 AV1394_TNF_INST_ERROR, ""); 517 return (DDI_FAILURE); 518 } 519 if (ddi_add_event_handler(avp->av_dip, br_evc, av1394_bus_reset, 520 avp, &avp->av_reset_cb) != DDI_SUCCESS) { 521 TNF_PROBE_0(av1394_add_events_error_bus_reset_event, 522 AV1394_TNF_INST_ERROR, ""); 523 return (DDI_FAILURE); 524 } 525 526 if (ddi_get_eventcookie(avp->av_dip, DDI_DEVI_REMOVE_EVENT, 527 &rem_evc) != DDI_SUCCESS) { 528 (void) ddi_remove_event_handler(avp->av_reset_cb); 529 TNF_PROBE_0(av1394_add_events_error_remove_cookie, 530 AV1394_TNF_INST_ERROR, ""); 531 return (DDI_FAILURE); 532 } 533 if (ddi_add_event_handler(avp->av_dip, rem_evc, av1394_disconnect, 534 avp, &avp->av_remove_cb) != DDI_SUCCESS) { 535 (void) ddi_remove_event_handler(avp->av_reset_cb); 536 TNF_PROBE_0(av1394_add_events_error_remove_event, 537 AV1394_TNF_INST_ERROR, ""); 538 return (DDI_FAILURE); 539 } 540 541 if (ddi_get_eventcookie(avp->av_dip, DDI_DEVI_INSERT_EVENT, 542 &ins_evc) != DDI_SUCCESS) { 543 (void) ddi_remove_event_handler(avp->av_remove_cb); 544 (void) ddi_remove_event_handler(avp->av_reset_cb); 545 TNF_PROBE_0(av1394_add_events_error_insert_cookie, 546 AV1394_TNF_INST_ERROR, ""); 547 return (DDI_FAILURE); 548 } 549 if (ddi_add_event_handler(avp->av_dip, ins_evc, av1394_reconnect, 550 avp, &avp->av_insert_cb) != DDI_SUCCESS) { 551 (void) ddi_remove_event_handler(avp->av_remove_cb); 552 (void) ddi_remove_event_handler(avp->av_reset_cb); 553 TNF_PROBE_0(av1394_add_events_error_insert_event, 554 AV1394_TNF_INST_ERROR, ""); 555 return (DDI_FAILURE); 556 } 557 558 return (DDI_SUCCESS); 559 } 560 561 static void 562 av1394_remove_events(av1394_inst_t *avp) 563 { 564 ddi_eventcookie_t evc; 565 566 if (ddi_get_eventcookie(avp->av_dip, DDI_DEVI_INSERT_EVENT, 567 &evc) == DDI_SUCCESS) { 568 (void) ddi_remove_event_handler(avp->av_insert_cb); 569 } 570 571 if (ddi_get_eventcookie(avp->av_dip, DDI_DEVI_REMOVE_EVENT, 572 &evc) == DDI_SUCCESS) { 573 (void) ddi_remove_event_handler(avp->av_remove_cb); 574 } 575 576 if (ddi_get_eventcookie(avp->av_dip, DDI_DEVI_BUS_RESET_EVENT, 577 &evc) == DDI_SUCCESS) { 578 (void) ddi_remove_event_handler(avp->av_reset_cb); 579 } 580 } 581 582 /* 583 * 584 * --- CPR 585 * 586 */ 587 static int 588 av1394_cpr_suspend(av1394_inst_t *avp) 589 { 590 int ret; 591 592 AV1394_TNF_ENTER(av1394_cpr_suspend); 593 594 ret = av1394_isoch_cpr_suspend(avp); 595 596 if (ret == DDI_SUCCESS) { 597 mutex_enter(&avp->av_mutex); 598 avp->av_prev_dev_state = avp->av_dev_state; 599 avp->av_dev_state = AV1394_DEV_SUSPENDED; 600 mutex_exit(&avp->av_mutex); 601 } 602 603 AV1394_TNF_EXIT(av1394_cpr_suspend); 604 return (ret); 605 } 606 607 /* 608 * CPR resume should always succeed 609 */ 610 static int 611 av1394_cpr_resume(av1394_inst_t *avp) 612 { 613 AV1394_TNF_ENTER(av1394_cpr_resume); 614 615 mutex_enter(&avp->av_mutex); 616 avp->av_dev_state = avp->av_prev_dev_state; 617 mutex_exit(&avp->av_mutex); 618 619 (void) av1394_async_cpr_resume(avp); 620 621 AV1394_TNF_EXIT(av1394_cpr_resume); 622 return (DDI_SUCCESS); 623 } 624 625 /* 626 * 627 * --- callbacks 628 * 629 */ 630 /*ARGSUSED*/ 631 static void 632 av1394_bus_reset(dev_info_t *dip, ddi_eventcookie_t evc, void *arg, void *data) 633 { 634 av1394_inst_t *avp = arg; 635 636 AV1394_TNF_ENTER(av1394_bus_reset); 637 638 if (avp == NULL) { 639 AV1394_TNF_EXIT(av1394_bus_reset); 640 return; 641 } 642 643 mutex_enter(&avp->av_mutex); 644 avp->av_attachinfo.localinfo = *(t1394_localinfo_t *)data; 645 mutex_exit(&avp->av_mutex); 646 647 av1394_async_bus_reset(avp); 648 av1394_cmp_bus_reset(avp); 649 650 AV1394_TNF_EXIT(av1394_bus_reset); 651 } 652 653 /*ARGSUSED*/ 654 static void 655 av1394_disconnect(dev_info_t *dip, ddi_eventcookie_t evc, void *arg, void *data) 656 { 657 av1394_inst_t *avp = arg; 658 659 AV1394_TNF_ENTER(av1394_disconnect); 660 661 if (avp == NULL) { 662 AV1394_TNF_EXIT(av1394_disconnect); 663 return; 664 } 665 666 mutex_enter(&avp->av_mutex); 667 avp->av_dev_state = AV1394_DEV_DISCONNECTED; 668 mutex_exit(&avp->av_mutex); 669 670 AV1394_TNF_EXIT(av1394_disconnect); 671 } 672 673 /*ARGSUSED*/ 674 static void 675 av1394_reconnect(dev_info_t *dip, ddi_eventcookie_t evc, void *arg, void *data) 676 { 677 av1394_inst_t *avp = arg; 678 679 AV1394_TNF_ENTER(av1394_disconnect); 680 681 if (avp == NULL) { 682 AV1394_TNF_EXIT(av1394_disconnect); 683 return; 684 } 685 686 mutex_enter(&avp->av_mutex); 687 avp->av_dev_state = AV1394_DEV_ONLINE; 688 avp->av_attachinfo.localinfo = *(t1394_localinfo_t *)data; 689 mutex_exit(&avp->av_mutex); 690 691 av1394_async_reconnect(avp); 692 693 AV1394_TNF_EXIT(av1394_disconnect); 694 }