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