1/* 2 * Copyright (c) 2009 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23/* 24 File: DVFamilyLib.c 25 26 Contains: This is the client API for talking to DV FireWire devices. 27 28 Version: xxx put version here xxx 29 30 Written by: Steve Smith 31 32 Copyright: � 1996-1999 by Apple Computer, Inc., all rights reserved. 33 34 File Ownership: 35 36 DRI: xxx put dri here xxx 37 38 Other Contact: xxx put other contact here xxx 39 40 Technology: xxx put technology here xxx 41 42 Writers: 43 44 (KW) Kevin Williams 45 (jkl) Jay Lloyd 46 (RS) Richard Sepulveda 47 (CP) Collin Pieper 48 (CLP) Collin Pieper 49 (AW) Adrienne Wang 50 (SS) Steve Smith 51 52 Change History (most recent first): 53 54 <30> 6/17/99 jkl Added fwClientID to DVGetLocalFWReferenceID call to make the 55 fwClientID part of the device info so IDH can execute 56 getDeviceStandard by itself. 57 <29> 1/4/99 GDW Changed DVFamily names. 58 <28> 12/9/98 SS DVGetDeviceInfo() now fills in the FireWire ID for the local 59 node in the DVDeviceInfo struct. DVGetDeviceClock now returns a 60 component instead of a component instance. 61 <27> 11/27/98 SS Changed DVIdle() to process all task-level events that are 62 queued, rather than just one. 63 <26> 11/23/98 SS DVCancelNotification() now removes any occurrance of the given 64 notification from the list of DV events that were queued for 65 task time. 66 <25> 11/20/98 SS Moved DVPostEvents() call to the bottom of all functions that 67 call it. 68 <24> 11/19/98 SS Added DVPostEvent() calls to Enable/Disable functions. Changed 69 PostEventSIH to queue certain events that need to be reported at 70 task level (see comments in PostEventSIH()). Added DVIdle() 71 call, but currently only calling it from a Notification Mgr 72 proc. 73 <23> 11/16/98 SS Beefed up DVGetDeviceInfo(). Notification now uses PB queues. 74 NotifyMeWhen now sets deviceID based on passed connectionID. 75 Changed DVPostEvent() to always run at secondary interrupt level 76 to solve some reentry problems. 77 <22> 11/13/98 SS Added DVGetDeviceClock() implementation. 78 <21> 11/6/98 KW in DVGetDeviceInfo, return if device is read enabled or write 79 enabled. Allows clients to determine if devices are availiable 80 for video in 81 <20> 10/30/98 SS More updates and bug fixes for hot swapping. 82 <19> 10/29/98 SS Was using local ptr before it was initialized in 83 DVOpenDeviceConnection(). Doh! 84 <18> 10/28/98 SS Changed open/close connection routines to reinstate 85 numConnections. Changed enable/disable read/write routines to 86 better police when they can occur, and to enable multiple 87 readers. These changes help address hot plugging, multiple 88 client and multiple device issues. 89 <17> 10/21/98 SS Changed DVEnableRead() and DVDisableRead() to enable multiple 90 readers, i.e. both vdig and sound input driver. 91 <16> 9/17/98 SS Restructured file & added Sean-like pragmas to make it easier to 92 find things. Added generic dv event notification support. Added 93 dummy Enable/Disable AVC transaction routines. Removed 94 AppleEvent support. 95 <15> 9/10/98 SS Somewhat gratuitous semantic change in the DV API to further 96 abstract the implementation, specifically, from DVDeviceRefNum 97 to DVDeviceConnectionID, and from DVOpen/CloseDriver to 98 DVOpen/CloseDeviceConnection. 99 <14> 9/3/98 SS Checked in first pass of dv device info stuff. 100 <13> 3/19/98 RS Remove DVNames usage due to strange crashes and its non-usage in 101 the current version of Oxcart. 102 <12> 3/16/98 SS Oops. I put the refNum stuff in the wrong place in DVOpenDriver. 103 I moved it and un-did Jay's changes. 104 <11> 3/15/98 jkl Commented out the return noErr line at the start of 105 DVOpenDriver. The exporter was failing when it called this and 106 expected to get a valid refNum. 107 <10> 3/12/98 SS Changed implementation of DV driver API to use deviceIDs and 108 refNums instead of driverIDs everywhere. DVDriverIDs are still 109 used internally for now. 110 <9> 3/8/98 RS Added DVIsEnabled() call to library. It returns whether 111 specified device is enabled. CP also eliminated OpenDriver and 112 CloseDriver function from library. 113 <8> 2/6/98 SS Backing out the disconnection checks for a6 build. 114 <7> 2/4/98 CP Change DVGetDevicesStandard to return our own standard types and 115 return an error for unknown standards... 116 <6> 1/26/98 CP Added more checks for disconnection errors... 117 <5> 1/21/98 SS Changed AVC stuff, so need to add #include "AVCSupport.h". 118 <4> 1/19/98 CP Added driver ID validation code and fixed a little bug in 119 DVDriverClose... 120 <3> 1/14/98 GDW New interfaces. 121 <2> 1/12/98 SS Checked in Collin's changes: added new API implementation, 122 removed multitude of specific AVC calls. Some functions formerly 123 in this file are now in DVFamilyInternal.c. 124 <1> 8/18/97 CLP first checked in 125 <9> 3/27/97 SS Forgot to take out debug breaks. 126 <8> 3/27/97 SS Moved global allocation/deallocation from the expert to 127 init/term routines. Added function to determine whether lib is 128 fully initialized. 129 <7> 3/5/97 AW minor change 130 <6> 3/4/97 AW Changed AVCEnableDVCGrab so that it checks if device is NTSC/PAL 131 and allocates mem appropriately 132 <5> 3/3/97 AW Fixed wrong command length in GetMediumInfo; added AVC commands 133 for setting/getting signals 134 <4> 2/19/97 SS Updated to 1.0a2 FSL 135 <3> 2/12/97 AW Updated to 1.0d18 FSL 136 <2> 10/31/96 SS Added helper routines for device control. 137 138*/ 139 140#include <Notification.h> 141 142#include "DVFamilyPriv.h" 143#include "DVFamilyInternal.h" 144#include "Processes.h" 145#include "AVCSupport.h" 146 147 148/////////////////////////////////////////////////////////////////////////// 149// 150// globals 151// 152/////////////////////////////////////////////////////////////////////////// 153 154DVFamilyDataPtr gpFamilyGlobals = nil; 155 156/////////////////////////////////////////////////////////////////////////// 157// 158// internal prototypes 159// 160/////////////////////////////////////////////////////////////////////////// 161 162OSStatus PostEventSIH( void* p1, void* p2 ); 163OSErr DVIdle( void ); 164void myNMHandler( NMRecPtr pNM ); 165 166#pragma mark ���������� Public Interface Calls ���������� 167 168//////////////////////////////////////////////////////////////////////////////// 169// These are the application level interfaces routines for the DVFamily 170//////////////////////////////////////////////////////////////////////////////// 171 172#pragma mark - 173#pragma mark ���������� Device Management ���������� 174 175////////////////////////////////////////////// 176// 177// DVCountDevices 178// 179// This routine counts the number of attatched DV devices 180// 181 182UInt32 DVCCountDevices( void ) 183{ 184 return( gpFamilyGlobals->numDVDrivers ); 185} 186 187////////////////////////////////////////////// 188// 189// DVGetIndDevice 190// 191// Given an index in the range of 1 to the number of devices returned by 192// DVCountDevices, DVGetIndDevice returns a deviceID. If you call DVGetIndDevice 193// repeatedly over the entire range of the index, it returns unique device IDs for 194// all currently connected and active DV devices. 195// 196//zzz maybe some speed optimizations for repetative calls would be nice 197// but how many DV devices are going to be connected to a machine anyway... 198 199OSErr DVCGetIndDevice( DVCDeviceID * pDVDevice, UInt32 index ) 200{ 201 DVDriverDataPtr pDVDriverData; 202 UInt32 i; 203 UInt32 count; 204 OSErr error = noErr; 205 206 if( (index <= gpFamilyGlobals->numDVDrivers) && (index > 0 ) ) 207 { 208 count = gpFamilyGlobals->numDVDrivers - index + 1; // cause devices are inserted at the head 209 pDVDriverData = gpFamilyGlobals->pDVDriverList; 210 for( i = 1; i < count; i++ ) 211 { 212 pDVDriverData = pDVDriverData->pNextDVDriverData; 213 } 214 *pDVDevice = (DVCDeviceID) pDVDriverData; 215 } 216 else 217 { 218 *pDVDevice = kInvalidDVDeviceID; 219 error = paramErr; 220 } 221 222 return( error ); 223} 224 225////////////////////////////////////////////// 226// 227// DVGetDeviceInfo 228// 229// This routine returns DV device info 230// 231 232OSErr DVCGetDeviceInfo( DVCDeviceID deviceID, DVCDeviceInfoPtr pInfo ) 233{ 234 OSErr error = noErr; 235 DVDriverDataPtr pDriverData; 236 register char *pSrc, *pDest; 237 int i; 238 239 // make sure we've got a valid driverID 240 // (actually, this could be a connID or a deviceID) 241 error = DVIsValidID( (DVDriverID) deviceID ); 242 if( error ) 243 return( error ); 244 245 // for now, the deviceID _is_ the ptr to data 246 pDriverData = (DVDriverDataPtr) deviceID; 247 248 pInfo->dvDeviceID = pDriverData->dvDriverID; 249 pInfo->uniqueID = pDriverData->uniqueID; 250 pInfo->vendorID = nil; // for now... 251 pInfo->regEntryID = pDriverData->deviceRegistryID; 252 253 pInfo->deviceIsOnline = !pDriverData->deviceDisconnected; 254 255 pInfo->AVCisEnabled = pDriverData->AVCEnabled; 256 257 pInfo->readChannel.isEnabled = pDriverData->readEnabled; 258 pInfo->writeChannel.isEnabled = pDriverData->writeEnabled; 259 260 // copy name str 261 pDest = (char*) &(pInfo->deviceName); 262 pSrc = (char*) &(pDriverData->name); 263 for( i = 0; i <= 255; i++ ) 264 pDest[i] = pSrc[i]; 265 266 // remember our local node id 267 pInfo->localNodeID = pDriverData->localID; 268 pInfo->fwClientID = pDriverData->fwClientID; 269 270 return( error ); 271} 272 273////////////////////////////////////////////// 274// 275// DVGetDeviceName 276// 277// This routine returns the name of a specific DV device 278// 279 280OSErr DVCGetDeviceName( DVCDeviceID deviceID, char * str ) 281{ 282 DVDriverDataPtr pDVDriverData; 283 OSErr error = noErr; 284 short i; 285 286 // make sure we've got a valid deviceID 287 error = DVIsValidID( (DVDriverID) deviceID ); 288 if( error ) 289 return( error ); 290 291 // extract our driver data pointer from our supposedly opaque reference 292 pDVDriverData = (DVDriverDataPtr) deviceID; 293 294 // copy name str 295 for( i = 0; i <= 255; i++ ) 296 str[i] = pDVDriverData->name[i]; 297 298 return( error ); 299} 300 301////////////////////////////////////////////// 302// 303// DVSetDeviceName 304// 305// This routine sets the name of a specific DV device 306// 307 308OSErr DVCSetDeviceName( DVCDeviceID deviceID, char * str ) 309{ 310 DVDriverDataPtr pDVDriverData; 311 OSErr error = noErr; 312 short i; 313 314 // make sure we've got a valid deviceID 315 error = DVIsValidID( (DVDriverID) deviceID ); 316 if( error ) 317 return( error ); 318 319 // extract our driver data pointer from our supposedly opaque reference 320 pDVDriverData = (DVDriverDataPtr) deviceID; 321 322 // copy name str 323 for( i = 0; i <= 255; i++ ) 324 pDVDriverData->name[i] = str[i]; 325 326//��� We aren't going to support DVNames in this version of Oxcart 327// // add name to prefs file (if add fails, don't pass error code back up to client) 328// DVAddName( &(pDVDriverData->uniqueID), pDVDriverData->name ); 329 330 return( error ); 331} 332 333////////////////////////////////////////////// 334// 335// DVOpenDeviceConnection 336// 337// This routine opens a connection to a particular driver 338// 339 340OSErr DVCOpenDeviceConnection( DVCDeviceID deviceID, DVCDeviceConnectionID *pConnID ) 341{ 342 DVDriverDataPtr pDVDriverData; 343 OSErr error = noErr; 344 345 // make sure we've got a valid deviceID 346 error = DVIsValidID( (DVDriverID) deviceID ); 347 if( error ) 348 return( error ); 349 350 // extract our driver data pointer from our supposedly opaque reference 351 pDVDriverData = (DVDriverDataPtr) deviceID; 352 353 // don't bother continuing if we're disconnected 354 if( pDVDriverData->deviceDisconnected ) 355 return( kDVDisconnectedErr ); 356 357 // add a connection 358 pDVDriverData->numConnections++; 359 360 // this is redundant, but we'll do it so we can possibly enhance 361 // multiple client support sometime in the future. 362 *pConnID = (DVCDeviceConnectionID) deviceID; 363 364 //zzz could actually open driver here, but advantage would probably be minimal... 365 366 return( error ); 367} 368 369////////////////////////////////////////////// 370// 371// DVCloseDeviceConnection 372// 373// This routine opens a connection to a particular driver 374// 375 376OSErr DVCCloseDeviceConnection( DVCDeviceConnectionID connID ) 377{ 378 DVDriverDataPtr pDVDriverData; 379 OSErr error = noErr; 380 381 // make sure we've got a valid deviceID 382 error = DVIsValidID( (DVDriverID) connID ); 383 if( error ) 384 return( error ); 385 386 // extract our driver data pointer from our supposedly opaque reference 387 pDVDriverData = (DVDriverDataPtr) connID; 388 389 // remove a connection 390 pDVDriverData->numConnections--; 391 392 //zzz for apple events managing driver disposal here would be good 393 if( ( pDVDriverData->numConnections == 0 ) && ( pDVDriverData->deviceDisconnected ) ) 394 DVDisposeDriver( (DVDriverID) connID ); 395 396 return( error ); 397} 398 399////////////////////////////////////////////// 400// 401// DVGetDeviceClock 402// 403// This routine opens a connection to a particular driver 404// 405 406OSErr DVCGetDeviceClock( DVCDeviceID deviceID, Component *clock ) 407{ 408 *clock = ((DVDriverDataPtr)deviceID)->clock; 409 410 return( noErr ); 411} 412 413 414#pragma mark - 415#pragma mark ���������� DV Event Notification Calls ���������� 416 417/////////////////////////////////////////////////////////////////////// 418// 419// DVNewNotification 420// 421// create new notification record 422// 423OSErr DVCNewNotification( DVCDeviceConnectionID connID, DVCNotifyProc notifyProc, 424 void *userData, DVCNotificationID *pNotifyID ) 425{ 426 DVNotificationEntryPtr pEntry; 427 DVCDeviceID deviceID; 428 OSErr error = noErr; 429 430 // check the parameters 431 if ( notifyProc == nil ) 432 error = paramErr; 433 434 // create new entry 435 if ( error == noErr ) 436 { 437 pEntry = (DVNotificationEntryPtr) 438 PoolAllocateResident( sizeof( DVNotificationEntry ), true ); 439 if ( pEntry == nil ) 440 error = memFullErr; 441 } 442 443 // get the deviceID from the connectionID 444 deviceID = (DVCDeviceID) connID; 445 446 // fill it out 447 if ( error == noErr ) 448 { 449 pEntry->deviceID = deviceID; 450 pEntry->wantedEvents = nil; 451 pEntry->notifyProc = notifyProc; 452 pEntry->userRefCon = userData; 453 454 *pNotifyID = (DVCNotificationID) pEntry; // notification id 455 456 // put new entry at the back of the line 457 error = PBEnqueueLast( (QElemPtr) pEntry, gpFamilyGlobals->notificationQueue ); 458 } 459 460 return error; 461} 462 463////////////////////////////////////////////// 464// 465// DVNotifyMeWhen 466// 467// activate notification 468// 469OSErr DVCNotifyMeWhen( DVCDeviceConnectionID connID, DVCNotificationID notifyID, UInt32 events) 470{ 471 DVNotificationEntryPtr pEntry; 472 DVCDeviceID deviceID; 473 OSErr error = noErr; 474 475 // check the parameters 476 if ( events & kDVEveryEvent == nil ) 477 error = paramErr; 478 479 // get the deviceID from the connectionID 480 deviceID = (DVCDeviceID) connID; 481 482 if ( error == noErr ) 483 { 484 pEntry = (DVNotificationEntryPtr) notifyID; 485 486 if ( pEntry != nil ) 487 { 488 pEntry->wantedEvents = events; 489 // this is sort of a back door - you can specify any device here 490 pEntry->deviceID = deviceID; 491 } 492 else 493 error = paramErr; 494 } 495 496 return error; 497} 498 499////////////////////////////////////////////// 500// 501// DVCancelNotification 502// 503// deactivate notification 504// 505OSErr DVCCancelNotification( DVCDeviceConnectionID connID, DVCNotificationID notifyID ) 506{ 507 DVNotificationEntryPtr pEntry; 508 OSErr error = noErr; 509 DVEventEntryPtr pEventEntry; 510 511 pEntry = (DVNotificationEntryPtr) notifyID; 512 513 if ( pEntry != nil ) 514 { 515 // don't notify this guy 516 pEntry->wantedEvents = 0L; 517 518 // check the queue to make sure he's not about to be notified. 519 pEventEntry = (DVEventEntryPtr) gpFamilyGlobals->receivedDVEvents->qHead; 520 while ( pEventEntry ) 521 { 522 if ( pEventEntry->eventRec.eventHeader.notifID == notifyID ) 523 PBDequeue( (QElemPtr) pEventEntry, gpFamilyGlobals->receivedDVEvents ); 524 // could be in the queue more than once, so keep going... 525 526 pEventEntry = (DVEventEntryPtr) pEventEntry->qLink; 527 } 528 } 529 else 530 error = paramErr; 531 532 return error; 533} 534 535////////////////////////////////////////////// 536// 537// DVDisposeNotification 538// 539// remove notification from list 540// 541OSErr DVCDisposeNotification( DVCDeviceConnectionID connID, DVCNotificationID notifyID ) 542{ 543 DVNotificationEntryPtr pEntry; 544 OSErr error = noErr; 545 546 // we're not going to do a check, but it's REAL important not to call 547 // this function from anywhere but task level. 548 549 // go find the entry and remove it from the list 550 pEntry = (DVNotificationEntryPtr) notifyID; 551 552 if ( pEntry != nil ) 553 { 554 PBDequeue( (QElemPtr) pEntry, gpFamilyGlobals->notificationQueue ); 555 PoolDeallocate( (void*) pEntry ); 556 } 557 else 558 error = paramErr; 559 560 return error; 561} 562 563 564#pragma mark - 565#pragma mark ���������� DV Isoch Read Calls ���������� 566 567////////////////////////////////////////////// 568// 569// DVEnableRead 570// 571// This routine initializes the driver for input 572// 573 574OSErr DVCEnableRead( DVCDeviceConnectionID connID ) 575{ 576 DVBasicCmdParams intParams; 577 OSErr error = noErr; 578 DVDriverDataPtr pDVDriverData; 579 DVCEventRecord theEvent; 580 581 // make sure we've got a valid driverID 582 error = DVIsValidID( (DVDriverID) connID ); 583 if( error ) 584 return( error ); 585 586 // extract our driver data pointer from our supposedly opaque reference 587 pDVDriverData = (DVDriverDataPtr) connID; 588 589 // make sure we're not already write enabled 590 if ( pDVDriverData->writeEnabled ) 591 return ( kAlreadyEnabledErr ); 592 593 // add a connection 594 pDVDriverData->numReaders++; 595 596 // if this is the first connection, call the driver 597 // to set the read up. 598 if ( pDVDriverData->numReaders == 1 ) 599 { 600 // set up driver's enable isoch read parameters 601 intParams.interfaceSelector = kDVCEnableIsochRead; 602 603 error = DVCallDriver( (DVDriverID) connID, (Ptr) &intParams ); 604 605 if ( error == noErr ) 606 pDVDriverData->readEnabled = true; 607 } 608 609 if ( error == noErr ) 610 { 611 // post a DV event to let the curious know... 612 theEvent.eventHeader.deviceID = (DVCDeviceID) connID; 613 theEvent.eventHeader.theEvent = kDVIsochReadEnabled; 614 DVCPostEvent( &theEvent ); 615 } 616 617 return( error ); 618} 619 620////////////////////////////////////////////// 621// 622// DVDisableRead 623// 624// This routine deinitializes the driver for input 625// 626 627OSErr DVCDisableRead( DVCDeviceConnectionID connID ) 628{ 629 DVBasicCmdParams intParams; 630 OSErr error = noErr; 631 DVDriverDataPtr pDVDriverData; 632 DVCEventRecord theEvent; 633 634 // make sure we've got a valid driverID 635 error = DVIsValidID( (DVDriverID) connID ); 636 if( error ) 637 return( error ); 638 639 // extract our driver data pointer from our supposedly opaque reference 640 pDVDriverData = (DVDriverDataPtr) connID; 641 642 // delete a connection 643 pDVDriverData->numReaders--; 644 645 // if this is the last connection, call the driver 646 // to tear down the read. 647 if ( pDVDriverData->numReaders == 0 ) 648 { 649 // set up driver's disable isoch read parameters 650 intParams.interfaceSelector = kDVCDisableIsochRead; 651 652 error = DVCallDriver( (DVDriverID) connID, (Ptr) &intParams ); 653 654 // even if there's an error, we're done 655 pDVDriverData->readEnabled = false; 656 } 657 658 if ( error == noErr ) 659 { 660 // post a DV event to let the curious know... 661 theEvent.eventHeader.deviceID = (DVCDeviceID) connID; 662 theEvent.eventHeader.theEvent = kDVIsochReadDisabled; 663 DVCPostEvent( &theEvent ); 664 } 665 666 return( error ); 667} 668 669////////////////////////////////////////////// 670// 671// DVReadFrame 672// 673// This routine reads a frame of data from the DV device 674// 675 676OSErr DVCReadFrame( DVCDeviceConnectionID connID, Ptr *ppReadBuffer, UInt32 * pSize ) 677{ 678 DVGetBufferParams intParams; 679 OSErr error = noErr; 680 681 // set up driver's enable isoch read parameters 682 intParams.interfaceSelector = kDVCReadIsochData; 683 intParams.ppBuffer = ppReadBuffer; 684 intParams.pBufferSize = pSize; 685 686 error = DVCallDriver( (DVDriverID) connID, (Ptr) &intParams ); 687 688 return( error ); 689} 690 691////////////////////////////////////////////// 692// 693// DVReleaseFrame 694// 695// This routine returns frame of data to the driver for use 696// 697 698OSErr DVCReleaseFrame( DVCDeviceConnectionID connID, Ptr pReadBuffer ) 699{ 700 DVPassBufferParams intParams; 701 OSErr error = noErr; 702 703 // set up driver's enable isoch read parameters 704 intParams.interfaceSelector = kDVCReleaseReadBuffer; 705 intParams.pBuffer = pReadBuffer; 706 707 error = DVCallDriver( (DVDriverID) connID, (Ptr) &intParams ); 708 709 return( error ); 710} 711 712#pragma mark - 713#pragma mark ���������� DV Isoch Write Calls ���������� 714 715////////////////////////////////////////////// 716// 717// DVEnableWrite 718// 719// This routine initializes the driver for output 720// 721 722OSErr DVCEnableWrite( DVCDeviceConnectionID connID ) 723{ 724 DVBasicCmdParams intParams; 725 DVDriverDataPtr pDVDriverData; 726 OSErr error = noErr; 727 DVCEventRecord theEvent; 728 729 // extract our driver data pointer from our supposedly opaque reference 730 pDVDriverData = (DVDriverDataPtr) connID; 731 732 // make sure we're not already enabled for reading or writing 733 if ( pDVDriverData->readEnabled || pDVDriverData->writeEnabled ) 734 return ( kAlreadyEnabledErr ); 735 736 // set up driver's enable isoch read parameters 737 intParams.interfaceSelector = kDVCEnableIsochWrite; 738 739 error = DVCallDriver( (DVDriverID) connID, (Ptr) &intParams ); 740 741 if ( error == noErr ) 742 { 743 pDVDriverData->writeEnabled = true; 744 745 // post a DV event to let the curious know... 746 theEvent.eventHeader.deviceID = (DVCDeviceID) connID; 747 theEvent.eventHeader.theEvent = kDVIsochWriteEnabled; 748 DVCPostEvent( &theEvent ); 749 } 750 751 return( error ); 752 753} 754 755////////////////////////////////////////////// 756// 757// DVDisableWrite 758// 759// This routine deinitializes the driver for output 760// 761 762OSErr DVCDisableWrite( DVCDeviceConnectionID connID ) 763{ 764 DVBasicCmdParams intParams; 765 DVDriverDataPtr pDVDriverData; 766 OSErr error = noErr; 767 DVCEventRecord theEvent; 768 769 // extract our driver data pointer from our supposedly opaque reference 770 pDVDriverData = (DVDriverDataPtr) connID; 771 772 // set up driver's enable isoch read parameters 773 intParams.interfaceSelector = kDVCDisableIsochWrite; 774 775 error = DVCallDriver( (DVDriverID) connID, (Ptr) &intParams ); 776 777 // even if there's an error, we're done 778 pDVDriverData->writeEnabled = false; 779 780 // post a DV event to let the curious know... 781 theEvent.eventHeader.deviceID = (DVCDeviceID) connID; 782 theEvent.eventHeader.theEvent = kDVIsochWriteDisabled; 783 DVCPostEvent( &theEvent ); 784 785 return( error ); 786 787} 788 789////////////////////////////////////////////// 790// 791// DVGetEmptyFrame 792// 793// This routine retrieves an empty frame from the driver for output 794// 795 796OSErr DVCGetEmptyFrame( DVCDeviceConnectionID connID, Ptr *ppEmptyFrameBuffer, UInt32 * pSize ) 797{ 798 DVGetBufferParams intParams; 799 OSErr error = noErr; 800 801 // set up driver's enable isoch read parameters 802 intParams.interfaceSelector = kDVCGetEmptyFrame; 803 intParams.ppBuffer = ppEmptyFrameBuffer; 804 intParams.pBufferSize = pSize; 805 806 error = DVCallDriver( (DVDriverID) connID, (Ptr) &intParams ); 807 return( error ); 808} 809 810////////////////////////////////////////////// 811// 812// DVWriteFrame 813// 814// This routine sends a frame of data to the camera 815// 816 817OSErr DVCWriteFrame( DVCDeviceConnectionID connID, Ptr pWriteBuffer ) 818{ 819 DVPassBufferParams intParams; 820 OSErr error = noErr; 821 822 // set up driver's enable isoch read parameters 823 intParams.interfaceSelector = kDVCWriteFrame; 824 intParams.pBuffer = pWriteBuffer; 825 826 error = DVCallDriver( (DVDriverID) connID, (Ptr) &intParams ); 827 return( error ); 828} 829 830#pragma mark - 831#pragma mark ���������� AVC Transaction Calls ���������� 832 833////////////////////////////////////////////// 834// 835// DVEnableAVCTransactions 836// 837// This routine initializes the driver for 838// performing avc transactions 839// 840OSErr DVCEnableAVCTransactions( DVCDeviceConnectionID connID ) 841{ 842 OSErr error = noErr; 843 844 return( error ); 845} 846 847////////////////////////////////////////////// 848// 849// DVDoAVCTransaction 850// 851// This routine sends a transaction block to the driver 852// 853 854OSErr DVCDoAVCTransaction( DVCDeviceConnectionID connID, AVCTransactionParamsPtr pParams ) 855{ 856 DVAVCTransactionParams transactionParams; 857 OSErr error = noErr; 858 859 // fill out the internal tansaction block 860 transactionParams.interfaceSelector = kAVCDoTransaction; 861 transactionParams.commandBufferPtr = pParams->commandBufferPtr; 862 transactionParams.commandLength = pParams->commandLength; 863 transactionParams.responseBufferPtr = pParams->responseBufferPtr; 864 transactionParams.responseBufferSize = pParams->responseBufferSize; 865 transactionParams.responseHandler = pParams->responseHandler; 866 867 error = DVCallDriver( (DVDriverID) connID, (Ptr) &transactionParams ); 868 869 return( error ); 870} 871 872////////////////////////////////////////////// 873// 874// DVDisableAVCTransactions 875// 876// This routine deinitializes the driver for 877// performing avc transactions 878// 879OSErr DVCDisableAVCTransactions( DVCDeviceConnectionID connID ) 880{ 881 OSErr error = noErr; 882 883 return( error ); 884} 885 886#pragma mark - 887#pragma mark ���������� To be discontinued... ���������� 888 889////////////////////////////////////////////// 890// 891// DVIsEnabled 892// 893// This routine tells if this device is enabled 894// 895 896OSErr DVCIsEnabled( DVCDeviceConnectionID connID, Boolean *isEnabled) 897{ 898 DVDriverDataPtr pDVDriverData; 899 OSErr error = noErr; 900 901 // make sure we've got a valid driverID 902 error = DVIsValidID( (DVDriverID) connID ); 903 if( error ) 904 return( error ); 905 906 pDVDriverData = (DVDriverDataPtr) connID; 907 908 // is it enabled 909 if( pDVDriverData->numConnections > 0) 910 *isEnabled = true; 911 else 912 *isEnabled = false; 913 914 return error; 915} 916 917////////////////////////////////////////////// 918// 919// DVGetDeviceStandard 920// 921// This routine returns the video standard 922// 923 924OSErr DVCGetDeviceStandard( DVCDeviceConnectionID connID, UInt32 * pStandard ) 925{ 926 AVCCTSFrameStruct avcFrame; 927 AVCTransactionParams transactionParams; 928 UInt8 responseBuffer[ 16 ]; 929 OSErr theErr = noErr; 930 UInt32 currentSignal, AVCStatus; 931 932 // fill up the avc frame 933 avcFrame.cmdType_respCode = kAVCStatusInquiryCommand; 934 avcFrame.headerAddress = 0x20; // for now 935 avcFrame.opcode = kAVCOutputSignalModeOpcode; 936 avcFrame.operand[ 0 ] = kAVCSignalModeDummyOperand; 937 938 // fill up the transaction parameter block 939 transactionParams.commandBufferPtr = (Ptr) &avcFrame; 940 transactionParams.commandLength = 4; 941 transactionParams.responseBufferPtr = (Ptr) responseBuffer; 942 transactionParams.responseBufferSize = 16; 943 transactionParams.responseHandler = nil; 944 945 theErr = DVCDoAVCTransaction( (DVDriverID) connID, &transactionParams ); 946 947 currentSignal = ((responseBuffer[ 2 ] << 8) | responseBuffer[ 3 ]); 948 AVCStatus = responseBuffer[ 0 ]; 949 950 *pStandard = kUnknownStandard; 951 switch (currentSignal & 0x000000ff) 952 { 953 case kAVCSignalModeSD525_60: 954 case kAVCSignalModeSDL525_60: 955 case kAVCSignalModeHD1125_60: 956 *pStandard = kNTSCStandard; 957 return( theErr ); 958 959 case kAVCSignalModeSD625_50: 960 case kAVCSignalModeSDL625_50: 961 case kAVCSignalModeHD1250_50: 962 *pStandard = kPALStandard; 963 return( theErr ); 964 965 default: 966 return( kUnknownStandardErr ); // how should I handle this? 967 } 968} 969 970#pragma mark - 971#pragma mark ���������� Private Interface Calls ���������� 972#pragma mark - 973 974/////////////////////////////////////////////////////////////////////// 975// 976// DVPostEvent 977// 978// used for sending the real notification 979// 980/////////////////////////////////////////////////////////////////////// 981OSErr DVCPostEvent( DVCEventRecordPtr pEvent ) 982{ 983 OSErr error = noErr; 984 985 // make sure it's a legit event 986 if ( (pEvent->eventHeader.theEvent & kDVEveryEvent) == nil ) 987 error = paramErr; 988 989 // get to secondary interrupt level as quickly as possible, where 990 // things are nice and synchronized... 991 error = CallSecondaryInterruptHandler2( (SecondaryInterruptHandler2) PostEventSIH, 992 nil, 993 pEvent, 994 nil ); 995 996 // now that we've pre-processed the event, give task level 997 // notifications a chance to run, if appropriate. 998 if ( CurrentExecutionLevel() == kTaskLevel ) 999 DVIdle(); 1000 1001 return( error ); 1002} 1003 1004 1005/////////////////////////////////////////////////////////////////////// 1006/////////////////////////////////////////////////////////////////////// 1007OSStatus 1008PostEventSIH( void* p1, void* p2 ) 1009{ 1010 DVCEventRecordPtr pEvent = (DVCEventRecordPtr) p1; 1011 DVEventEntryPtr pEventEntry; 1012 DVNotificationEntryPtr pEntry; 1013 OSErr error = noErr; 1014 1015 // We now have two broad classifications of events - ones that need to be 1016 // reported ASAP, which are stream related: 1017 // 1018 // kDVIsochReadComplete 1019 // kDVIsochWriteComplete 1020 // 1021 // and ones that are device management related, whose notifications will 1022 // probably generate massive amounts of task-level only Toolbox calls: 1023 // 1024 // kDVDeviceAdded 1025 // kDVDeviceRemoved 1026 // kDVIsochReadEnabled 1027 // kDVIsochReadDisabled 1028 // kDVIsochWriteEnabled 1029 // kDVIsochWriteDisabled 1030 // 1031 // We ship the low-latency notifications to secondary interrupt, while 1032 // the task level calls we queue and get back to them when someone 1033 // calls DVIdle(). 1034 // 1035 1036 // ok, so let's go find out who's waiting for this event 1037 1038 // go through list looking for the curious 1039 pEntry = (DVNotificationEntryPtr) gpFamilyGlobals->notificationQueue->qHead; 1040 while ( pEntry != nil ) 1041 { 1042 if ( (pEvent->eventHeader.theEvent & pEntry->wantedEvents) != nil ) 1043 { 1044 // only send notification if it's a global connection id or if 1045 // the event came from the same deviceID as this notif entry 1046 if ( (pEntry->deviceID == kDVGlobalEventConnectionID) || 1047 (pEvent->eventHeader.deviceID == pEntry->deviceID) ) 1048 { 1049 // we currently only support a one-shot notification, like clock callbacks 1050 pEntry->wantedEvents = nil; 1051 1052 // make sure the event contains this notification id 1053 pEvent->eventHeader.notifID = (DVCNotificationID) pEntry; 1054 1055 1056 // check before calling.. 1057 switch( pEvent->eventHeader.theEvent ) 1058 { 1059 case kDVIsochReadComplete: 1060 case kDVIsochWriteComplete: 1061 // process event immediately... 1062 error = (*pEntry->notifyProc)( pEvent, pEntry->userRefCon ); 1063 break; 1064 1065 case kDVDeviceAdded: 1066 case kDVDeviceRemoved: 1067 case kDVIsochReadEnabled: 1068 case kDVIsochReadDisabled: 1069 case kDVIsochWriteEnabled: 1070 case kDVIsochWriteDisabled: 1071 // queue the event and proc for later processing... 1072 1073 // get an entry 1074 error = PBDequeueFirst( gpFamilyGlobals->availableDVEvents, 1075 (QElemPtr*) &pEventEntry ); 1076 1077 // if we don't have any more available event elements, 1078 // we just drop the events on the floor 1079 1080 // copy the notify proc & refcon 1081 if ( error == noErr ) 1082 { 1083 pEventEntry->notifyProc = pEntry->notifyProc; 1084 pEventEntry->userRefCon = pEntry->userRefCon; 1085 } 1086 1087 // copy the event 1088 if ( error == noErr ) 1089 BlockCopy( pEvent, &(pEventEntry->eventRec), sizeof( DVCEventRecord ) ); 1090 1091 // queue it 1092 if ( error == noErr ) 1093 PBEnqueue( (QElemPtr) pEventEntry, gpFamilyGlobals->receivedDVEvents ); 1094 1095 // If we haven't already sent notification 1096 // to Notification Mgr to run tasks, do it now... 1097 if ( CompareAndSwap( false, true, &(gpFamilyGlobals->nmIsInstalled) ) ) 1098 NMInstall( &(gpFamilyGlobals->dvNMRec) ); 1099 1100 break; 1101 1102 default: 1103 break; 1104 } 1105 1106 } 1107 } 1108 1109 // next entry 1110 pEntry = (DVNotificationEntryPtr) pEntry->qLink; 1111 } 1112 1113 return( error ); 1114} 1115 1116 1117/////////////////////////////////////////////////////////////////////// 1118/////////////////////////////////////////////////////////////////////// 1119OSErr 1120DVIdle( void ) 1121{ 1122 DVEventEntryPtr pEventEntry; 1123 OSErr error = noErr; 1124 1125 // this routine should only get called at task level 1126 1127 // go see if there are any task level notifications that 1128 // need to be done. we take from the back end since that 1129 // was the oldest one. 1130 while( true ) 1131 { 1132 error = PBDequeueLast( gpFamilyGlobals->receivedDVEvents, 1133 (QElemPtr*) &pEventEntry ); 1134 1135 if ( error == noErr ) 1136 { 1137 if ( pEventEntry->notifyProc ) 1138 { 1139 // process it... 1140 error = (*pEventEntry->notifyProc)( &(pEventEntry->eventRec), pEventEntry->userRefCon ); 1141 } 1142 1143 // and put it back into available queue 1144 PBEnqueue( (QElemPtr) pEventEntry, gpFamilyGlobals->availableDVEvents ); 1145 } 1146 else 1147 // we're out of events (probably) 1148 break; 1149 } 1150 1151 return( error ); 1152} 1153 1154 1155/////////////////////////////////////////////////////////////////////// 1156/////////////////////////////////////////////////////////////////////// 1157void 1158myNMHandler( NMRecPtr pNM ) 1159{ 1160 do { 1161 DVIdle(); 1162 } while( CompareAndSwap( true, false, &(gpFamilyGlobals->nmIsInstalled) ) ); 1163 1164 // until next time... 1165 NMRemove( pNM ); 1166} 1167 1168 1169 1170