1/* 2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * The contents of this file constitute Original Code as defined in and 7 * are subject to the Apple Public Source License Version 1.1 (the 8 * "License"). You may not use this file except in compliance with the 9 * License. Please obtain a copy of the License at 10 * http://www.apple.com/publicsource and read it before using this file. 11 * 12 * This Original Code and all software distributed under the License are 13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 17 * License for the specific language governing rights and limitations 18 * under the License. 19 * 20 * @APPLE_LICENSE_HEADER_END@ 21 */ 22/* 23 * IOFWUserClientPsdAddrSpace.cpp 24 * IOFireWireFamily 25 * 26 * Created by NWG on Wed Dec 06 2000. 27 * Copyright (c) 2000-2002 Apple, Inc. All rights reserved. 28 * 29 */ 30/* 31 $Log: IOFWUserPseudoAddressSpace.cpp,v $ 32 Revision 1.25 2010/05/20 22:49:43 calderon 33 Fixes issues with offset argument of pseudo address space read handler being wrong. 34 35 Revision 1.24 2009/10/16 23:59:06 calderon 36 <rdar://problem/7046489> 10A402 AsyncTester results in Error-Server verified Incorrect number of bytes 37 <rdar://problem/7111060> PanicTracer: 3 panics at IOFireWireFamily : IOFWUserPseudoAddressSpace::doPacket 38 39 And some help for: 40 <rdar://problem/7116134> PanicTracer: 3 panics at com.apple.iokit.IOFireWireFamily 41 42 Revision 1.23 2008/09/12 23:44:05 calderon 43 <rdar://5971979/> PseudoAddressSpace skips/mangles packets 44 <rdar://5708169/> FireWire synchronous commands' headerdoc missing callback info 45 46 Revision 1.22 2008/05/06 03:26:57 collin 47 more K64 48 49 Revision 1.21 2008/04/11 00:52:37 collin 50 some K64 changes 51 52 Revision 1.20 2007/02/16 19:03:43 arulchan 53 *** empty log message *** 54 55 Revision 1.19 2007/02/14 21:58:29 collin 56 *** empty log message *** 57 58 Revision 1.18 2007/02/07 06:35:20 collin 59 *** empty log message *** 60 61 Revision 1.17 2007/01/24 04:10:13 collin 62 *** empty log message *** 63 64 Revision 1.16 2007/01/18 01:07:32 collin 65 *** empty log message *** 66 67 Revision 1.15 2007/01/17 03:46:26 collin 68 *** empty log message *** 69 70 Revision 1.14 2006/12/21 21:17:44 ayanowit 71 More changes necessary to eventually get support for 64-bit apps working (4222965). 72 73 Revision 1.13 2006/12/06 00:01:07 arulchan 74 Isoch Channel 31 Generic Receiver 75 76 Revision 1.12 2005/02/18 03:19:03 niels 77 fix isight 78 79 Revision 1.11 2003/09/20 00:54:17 collin 80 *** empty log message *** 81 82 Revision 1.10 2003/08/30 00:16:44 collin 83 *** empty log message *** 84 85 Revision 1.9 2003/08/20 23:33:37 niels 86 *** empty log message *** 87 88 Revision 1.8 2003/08/19 01:48:54 niels 89 *** empty log message *** 90 91 Revision 1.7 2003/07/24 06:30:58 collin 92 *** empty log message *** 93 94 Revision 1.6 2003/07/21 06:52:59 niels 95 merge isoch to TOT 96 97 Revision 1.4.4.2 2003/07/21 06:44:44 niels 98 *** empty log message *** 99 100 Revision 1.4.4.1 2003/07/01 20:54:07 niels 101 isoch merge 102 103 Revision 1.4 2003/04/18 20:32:06 collin 104 *** empty log message *** 105 106 Revision 1.3 2002/10/22 00:34:25 collin 107 fix user space lock transactions, publish GUID = 0 property in objects in the IOFireWire plane 108 109 Revision 1.2 2002/10/18 23:29:43 collin 110 fix includes, fix cast which fails on new compiler 111 112 Revision 1.1 2002/09/25 00:27:22 niels 113 flip your world upside-down 114 115 Revision 1.21 2002/08/06 21:10:06 wgulland 116 Add IOfireWireBus::isCompleteRequest(reqrefcon) 117 118 Revision 1.20 2002/08/06 19:44:57 niels 119 *** empty log message *** 120 121 Revision 1.19 2002/08/06 19:42:54 niels 122 now send conflict response if user pseudo address space can't receive a write because the queue is full in cases where the hardware has not already responded 'ack complete' 123 124*/ 125 126#ifndef __IOFWUserClientPseuAddrSpace_H__ 127#define __IOFWUserClientPseuAddrSpace_H__ 128 129#import <IOKit/firewire/IOFireWireNub.h> 130#import <IOKit/firewire/IOFireWireController.h> 131//#import <IOKit/firewire/FireLog.h> 132 133// protected 134#import <IOKit/firewire/IOFireWireLink.h> 135 136// private 137#import "IOFireWireUserClient.h" 138#import "IOFireWireLib.h" 139#import "IOFWUserPseudoAddressSpace.h" 140#import "IOFWRingBufferQ.h" 141 142// system 143#import <IOKit/assert.h> 144#import <IOKit/IOLib.h> 145#import <IOKit/IOWorkLoop.h> 146#import <IOKit/IOTypes.h> 147#import <IOKit/IOMessage.h> 148#import <IOKit/IOUserClient.h> 149 150// ============================================================ 151// 152// IOFWPacketHeader 153// 154// ============================================================ 155 156IOFWPacketHeader_t::IOFWPacketHeader_t() 157{ 158 CommonHeader.type = IOFWPacketHeader::kFree ; 159 CommonHeader.next = this ; 160 IOFWPacketHeaderGetSize(this) = 0 ; 161 IOFWPacketHeaderGetOffset(this) = 0 ; 162} 163 164io_user_reference_t& IOFWPacketHeaderGetSize(IOFWPacketHeader_t* hdr) 165{ 166 if( hdr->CommonHeader.type == IOFWPacketHeader::kSkippedPacket ) 167 return hdr->CommonHeader.headerSize; 168 else 169 return hdr->CommonHeader.args[1] ; 170} 171 172io_user_reference_t& IOFWPacketHeaderGetOffset(IOFWPacketHeader_t* hdr) 173{ 174 if( hdr->CommonHeader.type == IOFWPacketHeader::kSkippedPacket ) 175 return hdr->CommonHeader.headerOffset; 176 else 177 return hdr->CommonHeader.args[2] ; 178} 179 180void InitIncomingPacketHeader( 181 IOFWPacketHeader_t* header, 182 IOFWPacketHeader_t* next, 183 const IOByteCount len, 184 const IOByteCount offset, 185 OSAsyncReference64* ref, 186 UInt16 nodeID, 187 const IOFWSpeed& speed, 188 const FWAddress& addr, 189 const bool isLock) 190{ 191 header->CommonHeader.type = IOFWPacketHeader::kIncomingPacket ; 192 header->CommonHeader.next = next ; 193 IOFWPacketHeaderGetSize(header) = len ; 194 IOFWPacketHeaderGetOffset(header) = offset ; 195 header->CommonHeader.whichAsyncRef = ref ; 196 header->CommonHeader.argCount = 8; 197 198 header->IncomingPacket.commandID = (io_user_reference_t) header ; 199 header->IncomingPacket.nodeID = nodeID ; 200 header->IncomingPacket.speed = speed ; 201 header->IncomingPacket.addrHi = addr.addressHi; 202 header->IncomingPacket.addrLo = addr.addressLo; 203 header->IncomingPacket.isLock = isLock ; 204} 205 206void InitSkippedPacketHeader( 207 IOFWPacketHeader* header, 208 IOFWPacketHeader* next, 209 const IOByteCount offset, 210 OSAsyncReference64* ref) 211{ 212 header->CommonHeader.type = IOFWPacketHeader::kSkippedPacket ; 213 header->CommonHeader.next = next ; 214 IOFWPacketHeaderGetSize(header) = 0; 215 IOFWPacketHeaderGetOffset(header) = offset ; 216 header->CommonHeader.whichAsyncRef = ref ; 217 header->CommonHeader.argCount = 2; 218 219 header->SkippedPacket.commandID = (io_user_reference_t) header ; 220 header->SkippedPacket.skippedPacketCount= 1; 221} 222 223void InitReadPacketHeader( 224 IOFWPacketHeader* header, 225 IOFWPacketHeader* next, 226 IOByteCount len, 227 IOByteCount offset, 228 OSAsyncReference64* ref, 229 IOFWRequestRefCon reqrefcon, 230 UInt16 nodeID, 231 IOFWSpeed& speed, 232 FWAddress addr, 233 UInt32 generation) 234{ 235 header->CommonHeader.type = IOFWPacketHeader::kReadPacket ; 236 header->CommonHeader.next = next ; 237 IOFWPacketHeaderGetSize(header) = len ; 238 IOFWPacketHeaderGetOffset(header) = offset ; 239 header->CommonHeader.whichAsyncRef = ref ; 240 header->CommonHeader.argCount = 7 ; 241 242 header->ReadPacket.commandID = (io_user_reference_t) header ; 243 header->ReadPacket.nodeID = nodeID ; 244 header->ReadPacket.speed = speed ; 245 header->ReadPacket.addrHi = addr.addressHi ; 246 header->ReadPacket.addrLo = addr.addressLo ; 247 header->ReadPacket.reqrefcon = (io_user_reference_t)reqrefcon ; 248 header->ReadPacket.generation = generation ; 249} 250 251void InitLockPacketHeader( 252 IOFWPacketHeader* header, 253 IOFWPacketHeader* next, 254 IOByteCount len, 255 IOByteCount offset, 256 OSAsyncReference64* ref, 257 UInt16 nodeID, 258 IOFWSpeed& speed, 259 FWAddress addr, 260 const UInt32 generation, 261 IOFWRequestRefCon reqrefcon) 262{ 263 InitIncomingPacketHeader( header, next, len, offset, ref, nodeID, speed, addr, true ) ; 264 header->IncomingPacket.type = IOFWPacketHeader::kLockPacket ; 265 header->IncomingPacket.generation = generation ; 266 header->IncomingPacket.reqrefcon = (io_user_reference_t)reqrefcon; 267} 268 269Boolean IsSkippedPacketHeader( 270 IOFWPacketHeader* header) 271{ 272 return header->CommonHeader.type == IOFWPacketHeader::kSkippedPacket ; 273} 274 275Boolean IsFreePacketHeader( 276 IOFWPacketHeader* header) 277{ 278 return header->CommonHeader.type == IOFWPacketHeader::kFree ; 279} 280 281// ============================================================ 282// IOFWUserPseudoAddressSpace methods 283// ============================================================ 284 285OSDefineMetaClassAndStructors( IOFWUserPseudoAddressSpace, IOFWPseudoAddressSpace ) ; 286 287#if IOFIREWIREUSERCLIENTDEBUG > 0 288 289bool 290IOFWUserPseudoAddressSpace::serialize(OSSerialize *s) const 291{ 292 if (s->previouslySerialized(this)) 293 return true ; 294 295 char temp[256] ; 296 297 snprintf(temp, sizeof(temp), "addr=%x:%08x", fAddress.addressHi, (uint32_t)fAddress.addressLo) ; 298 299#ifdef __LP64__ 300 snprintf(temp+strlen(temp), sizeof(temp), ", backing-store-bytes=%llud", 301 fDesc ? fDesc->getLength() : 0) ; 302#else 303 snprintf(temp+strlen(temp), sizeof(temp), ", backing-store-bytes=%lud", 304 fDesc ? fDesc->getLength() : 0) ; 305#endif 306 307 if ( fFlags ) 308 { 309 snprintf(temp+strlen(temp), sizeof(temp), ", flags:") ; 310 if (fFlags & kFWAddressSpaceNoWriteAccess) 311 snprintf(temp+strlen(temp), sizeof(temp), " no-write") ; 312 if (fFlags & kFWAddressSpaceNoReadAccess) 313 snprintf(temp+strlen(temp), sizeof(temp), " no-read") ; 314 if (fFlags & kFWAddressSpaceAutoWriteReply) 315 snprintf(temp+strlen(temp), sizeof(temp), " auto-write") ; 316 if (fFlags & kFWAddressSpaceAutoReadReply) 317 snprintf(temp+strlen(temp), sizeof(temp), " auto-read") ; 318 if (fFlags & kFWAddressSpaceAutoCopyOnWrite) 319 snprintf(temp+strlen(temp), sizeof(temp), " copy-on-write") ; 320 if (fFlags & kFWAddressSpaceShareIfExists) 321 snprintf(temp+strlen(temp), sizeof(temp), " shared") ; 322 if (fFlags & kFWAddressSpaceExclusive) 323 snprintf(temp+strlen(temp), sizeof(temp), " exclusive") ; 324 } 325 else 326 { 327 snprintf(temp+strlen(temp), sizeof(temp), ", no flags") ; 328 } 329 330 OSString* string = OSString::withCString(temp) ; 331 if (!string) 332 return false ; 333 334 bool result = string->serialize(s) ; 335 string->release() ; 336 337 return result ; 338} 339 340#endif 341 342void 343IOFWUserPseudoAddressSpace::free() 344{ 345 if ( fPacketQueue ) 346 { 347 fPacketQueue->release(); 348 fPacketQueue = NULL; 349 } 350 351 if ( fBackingStorePrepared ) 352 fDesc->complete() ; 353 354 delete fLastWrittenHeader ; 355 356 if( fLock ) 357 { 358 IOLockFree( fLock ); 359 fLock = NULL; 360 } 361 362 IOFWPseudoAddressSpace::free() ; 363} 364 365// exporterCleanup 366// 367// 368 369void 370IOFWUserPseudoAddressSpace::exporterCleanup( const OSObject * self ) 371{ 372 IOFWUserPseudoAddressSpace * me = (IOFWUserPseudoAddressSpace*)self; 373 374 DebugLog("IOFWUserPseudoAddressSpace::exporterCleanup\n"); 375 376 me->deactivate(); 377} 378 379void 380IOFWUserPseudoAddressSpace::deactivate() 381{ 382 IOFWPseudoAddressSpace::deactivate() ; 383 384 IOLockLock(fLock) ; 385 386 fLastReadHeader = NULL ; 387 388 IOFWPacketHeader* firstHeader = fLastWrittenHeader ; 389 IOFWPacketHeader* tempHeader ; 390 391 if (fLastWrittenHeader) 392 { 393 while (fLastWrittenHeader->CommonHeader.next != firstHeader) 394 { 395 tempHeader = fLastWrittenHeader->CommonHeader.next ; 396 delete fLastWrittenHeader ; 397 fLastWrittenHeader = tempHeader ; 398 } 399 400 } 401 402 if ( fBackingStorePrepared ) 403 { 404 fDesc->complete() ; 405 fBackingStorePrepared = false ; 406 } 407 408 fWaitingForUserCompletion = false ; 409 410 IOLockUnlock(fLock) ; 411} 412 413bool 414IOFWUserPseudoAddressSpace::completeInit( IOFireWireUserClient* userclient, AddressSpaceCreateParams* params ) 415{ 416 Boolean status = true ; 417 418 fUserRefCon = params->refCon ; 419 fFlags = params->flags ; 420 fWaitingForUserCompletion = false ; 421 422 // set user client 423 fUserClient = userclient ; 424 425 // see if user specified a packet queue and queue size 426 if ( !params->queueBuffer && ( !(fFlags & kFWAddressSpaceAutoWriteReply) || !(fFlags & kFWAddressSpaceAutoReadReply) ) ) 427 { 428 DebugLog("IOFWUserPseudoAddressSpace::initAll: address space without queue buffer must have both auto-write and auto-read set\n") ; 429 status = false ; 430 } 431 432 // make packet queue 433 if ( status ) 434 { 435 if ( params->queueBuffer ) 436 { 437 fPacketQueue = IOFWRingBufferQ::withAddressRange( params->queueBuffer, params->queueSize, kIODirectionOutIn, fUserClient->getOwningTask() ) ; 438 439 if ( !fPacketQueue ) 440 { 441 DebugLog("%s %u: couldn't make fPacketQueue memory descriptor\n", __FILE__, __LINE__) ; 442 status = false ; 443 } 444 else 445 { 446 fPacketQueuePrepared = status ; 447 } 448 } 449 } 450 451 if ( status ) 452 { 453 // init the easy vars 454 fLastReadHeader = new IOFWPacketHeader ; 455 fLastWrittenHeader = fLastReadHeader ; 456 bzero(fLastWrittenHeader, sizeof(fLastWrittenHeader)); 457 458 // get a lock for the packet queue 459 fLock = IOLockAlloc() ; 460 461 if ( !fLock ) 462 { 463 DebugLog("%s %u: couldn't allocate lock\n", __FILE__, __LINE__) ; 464 status = false ; 465 } 466 } 467 468 // get a backing store if needed 469 if ( status ) 470 if ( NULL != params->backingStore ) 471 { 472 // Note: even though the memory descriptor is created with the size of the address space, 473 // rather than the size of the backingstore, this creation should fail if the size is outside 474 // of the task's allocation. Any bad read or writes will only affect the task. Furthermore, 475 // the backingstore is required to be the same size as the address space, per documentation. 476 fDesc = IOMemoryDescriptor::withAddressRange( params->backingStore, 477 params->size, 478 kIODirectionOutIn, 479 userclient->getOwningTask() ) ; 480 if (!fDesc) 481 { 482 DebugLog("%s %u: failed to make backing store memory descriptor\n", __FILE__, __LINE__) ; 483 status = false ; 484 } 485 486 if ( status ) 487 status = ( kIOReturnSuccess == fDesc->prepare() ) ; 488 489 fBackingStorePrepared = status ; 490 } 491 492 // set reader and writer callbacks based on access flags and user callback flags 493 if (status) 494 { 495 if (!(params->flags & kFWAddressSpaceNoWriteAccess)) 496 { 497 if (params->flags & kFWAddressSpaceAutoWriteReply) 498 { 499 if (params->backingStore) 500 fWriter = & IOFWUserPseudoAddressSpace::simpleWriter ; 501 else 502 { // this macro needs braces 503 DebugLog("IOFireWireUserClient::allocateAddressSpace(): can't create auto-write address space w/o backing store!\n") ; 504 } 505 } 506 else 507 { 508 fWriter = & IOFWUserPseudoAddressSpace::pseudoAddrSpaceWriter ; 509 fUserLocks = true ; 510 } 511 } 512 513 if (!(params->flags & kFWAddressSpaceNoReadAccess)) 514 { 515 if (params->flags & kFWAddressSpaceAutoReadReply) 516 { 517 if (params->backingStore) 518 fReader = & IOFWUserPseudoAddressSpace::simpleReader ; 519 else 520 { // this macro needs braces 521 DebugLog("IOFireWireUserClient::allocateAddressSpace(): can't create auto-read address space w/o backing store!\n") ; 522 } 523 } 524 else 525 { 526 fReader = & IOFWUserPseudoAddressSpace::pseudoAddrSpaceReader ; 527 fUserLocks &= true ; // &=, only set to true if true already 528 } 529 } 530 531 } 532 533 return status ; 534} 535 536bool 537IOFWUserPseudoAddressSpace::initPseudo( 538 IOFireWireUserClient* userclient, 539 IOFireWireLib::AddressSpaceCreateParams* params) 540{ 541 if ( !IOFWPseudoAddressSpace::initAll( userclient->getOwner()->getController(), & fAddress, params->size, NULL, NULL, this )) 542 { 543 DebugLog("IOFWUserPseudoAddressSpace::initPseudo: IOFWPseudoAddressSpace::initAll failed\n") ; 544 return false ; 545 } 546 547 bool result = completeInit( userclient, params ) ; 548 549 return result ; 550} 551 552bool 553IOFWUserPseudoAddressSpace::initFixed( 554 IOFireWireUserClient* userclient, 555 IOFireWireLib::AddressSpaceCreateParams* params ) 556{ 557 IOFWAddressSpace* addrSpace = userclient->getOwner()->getController()->getAddressSpace( FWAddress( kCSRRegisterSpaceBaseAddressHi, params->addressLo ) ) ; 558 559 fAddress = FWAddress( kCSRRegisterSpaceBaseAddressHi, params->addressLo ) ; 560 561 if ( addrSpace && !(params->flags & kFWAddressSpaceShareIfExists ) ) 562 return false ; 563 564 if ( !IOFWPseudoAddressSpace::initFixed( userclient->getOwner()->getController(), fAddress, params->size, NULL, NULL, this )) 565 return false ; 566 567 // mark this address space as exclusve 568 // it will fail in activate if there's a conflict 569 if( params->flags & kFWAddressSpaceExclusive ) 570 { 571 setExclusive( true ); 572 } 573 574 return completeInit( userclient, params ) ; 575} 576 577UInt32 IOFWUserPseudoAddressSpace::doLock(UInt16 nodeID, IOFWSpeed &speed, FWAddress addr, UInt32 inLen, 578 const UInt32 *newVal, UInt32 &outLen, UInt32 *oldVal, UInt32 type, 579 IOFWRequestRefCon refcon) 580{ 581 if ( fUserLocks ) 582 { 583 if(addr.addressHi != fBase.addressHi) 584 return kFWResponseAddressError; 585 if(addr.addressLo < fBase.addressLo) 586 return kFWResponseAddressError; 587 if(addr.addressLo + inLen > fBase.addressLo+fLen) 588 return kFWResponseAddressError; 589 if(!fReader) 590 return kFWResponseTypeError; 591 592 return doPacket( nodeID, speed, addr, inLen, newVal, refcon, IOFWPacketHeader::kLockPacket, oldVal ) ; 593 } 594 595 return IOFWPseudoAddressSpace::doLock( nodeID, speed, addr, inLen, newVal, outLen, oldVal, type, refcon ) ; 596} 597 598UInt32 599IOFWUserPseudoAddressSpace::doPacket( 600 UInt16 nodeID, 601 IOFWSpeed& speed, 602 FWAddress addr, 603 UInt32 len, 604 const void* buf, 605 IOFWRequestRefCon reqrefcon, 606 IOFWPacketHeader::QueueTag tag, 607 UInt32* oldVal) // oldVal only used in lock case 608{ 609 IOByteCount destOffset = 0 ; 610 bool skip = false ; 611 UInt32 response = kFWResponseComplete ; 612 613 IOLockLock(fLock) ; 614 615 // Process: 616 // 1. Is there enough space in queue for packet payload? 617 // 2. No? Create/reuse skip packet header, init, and notify 618 // 3. Create/reuse packet header 619 // 4. Init packet header 620 // 5. Write packet payload to queue 621 // 6. Send notification of next packet ??? 622 // ... 623 // 7. When client complete, mark header free and send notification for next packet ??? 624 625 DebugLog("doPacket\n"); 626 627 if ( !fPacketQueue ) DebugLog("\tdP fPacketQueue is invalid!\n"); 628 629 if ( tag == IOFWPacketHeader::kIncomingPacket || tag == IOFWPacketHeader::kLockPacket ) { 630 skip = !(fPacketQueue->isSpaceAvailable(len, &destOffset)); 631 } 632 633 DebugLog("\tdP Packet will %s fit. Length: %lu Available: %lu Payload: 0x%lx\n", skip ? "NOT" : " ", len, fPacketQueue->spaceAvailable(), *((UInt32 *)buf)); 634 635 IOFWPacketHeader * currentHeader = fLastWrittenHeader; 636 637 IOFireWireNub * owner = NULL; 638 IOFireWireController * controller = NULL; 639 if ( fUserClient ) 640 { 641 owner = fUserClient->getOwner(); 642 if ( owner ) 643 controller = owner->getController(); 644 } 645 646 if ( !controller ) 647 { 648 // userclient is terminating? 649 response = kFWResponseAddressError; 650 } 651 else 652 { 653 if ( skip ) 654 { 655 // create a skipped packet header if last one wasn't a skipped pkt, 656 // otherwise, bump count and reuse header 657 658 if (IsSkippedPacketHeader(fLastWrittenHeader)) 659 ++(fLastWrittenHeader->SkippedPacket.skippedPacketCount) ; 660 else 661 { 662 if (!IsFreePacketHeader(fLastWrittenHeader)) 663 { 664 if ( !IsFreePacketHeader(fLastWrittenHeader->CommonHeader.next) ) 665 { 666 IOFWPacketHeader* newHeader = new IOFWPacketHeader ; 667 newHeader->CommonHeader.next = fLastWrittenHeader->CommonHeader.next ; 668 fLastWrittenHeader->CommonHeader.next = newHeader ; 669 } 670 671 currentHeader = fLastWrittenHeader->CommonHeader.next ; 672 673 } 674 675 InitSkippedPacketHeader( 676 currentHeader, 677 currentHeader->CommonHeader.next, 678 destOffset, 679 & fSkippedPacketAsyncNotificationRef ) ; 680 681 fLastWrittenHeader = currentHeader ; 682 } 683 684 // if we can't handle the packet, and the hardware hasn't already responded, 685 // send kFWResponseConflictError 686 if ( ! controller->isCompleteRequest( reqrefcon ) ) 687 response = kFWResponseConflictError ; 688 } 689 else 690 { 691 if (!IsFreePacketHeader(fLastWrittenHeader)) 692 { 693 if ( !IsFreePacketHeader(fLastWrittenHeader->CommonHeader.next) ) 694 { 695 IOFWPacketHeader* newHeader = new IOFWPacketHeader ; 696 newHeader->CommonHeader.next = fLastWrittenHeader->CommonHeader.next ; 697 fLastWrittenHeader->CommonHeader.next = newHeader ; 698 } 699 700 } 701 702 currentHeader = fLastWrittenHeader->CommonHeader.next ; 703 bool enqueued = false; 704 705 switch(tag) 706 { 707 case IOFWPacketHeader::kIncomingPacket: 708 // save info in header 709 InitIncomingPacketHeader( 710 currentHeader, 711 currentHeader->CommonHeader.next, 712 len, 713 destOffset, 714 & fPacketAsyncNotificationRef, 715 nodeID, 716 speed, 717 addr) ; 718 719 // zzz this write should probably be eliminated when kFWAddressSpaceAutoCopyOnWrite is set.. 720 enqueued = fPacketQueue->enqueueBytes((void *)buf, len); 721 722 DebugLog("\tdP Write: Copy cmd ID: 0x%llx %s\n", currentHeader->IncomingPacket.commandID, enqueued ? "succeeded" : "failed"); 723 724 break ; 725 726 case IOFWPacketHeader::kLockPacket: 727 728 // save info in header 729 InitLockPacketHeader( 730 currentHeader, 731 currentHeader->CommonHeader.next, 732 len, 733 destOffset, 734 & fPacketAsyncNotificationRef, 735 nodeID, 736 speed, 737 addr, 738 controller->getGeneration(), 739 reqrefcon ) ; 740 741 // copy data to queue 742 enqueued = fPacketQueue->enqueueBytes((void *)buf, len); 743 response = kFWResponsePending ; 744 745 DebugLog("\tdP Lock: Copy cmd ID: 0x%llx %s\n", currentHeader->IncomingPacket.commandID, enqueued ? "succeeded" : "failed"); 746 747 break ; 748 749 case IOFWPacketHeader::kReadPacket: 750 751 InitReadPacketHeader( 752 currentHeader, 753 currentHeader->CommonHeader.next, 754 len, 755 addr.addressLo - fAddress.addressLo, 756 & fReadAsyncNotificationRef, 757 reqrefcon, 758 nodeID, 759 speed, 760 addr, 761 controller->getGeneration() ) ; 762 763 response = kFWResponsePending ; 764 765 DebugLog("\tdP Read: Proces cmd ID: 0x%llx\n", currentHeader->IncomingPacket.commandID); 766 767 break ; 768 769 default: 770 ErrorLog("%s %u: internal error: doPacket called with improper type\n", __FILE__, __LINE__) ; 771 break ; 772 } 773 774 fLastWrittenHeader = currentHeader ; 775 } 776 777 if( currentHeader->CommonHeader.type != IOFWPacketHeader::kFree ) 778 sendPacketNotification(currentHeader) ; 779 } 780 781 IOLockUnlock(fLock) ; 782 783 return response ; 784} 785 786UInt32 787IOFWUserPseudoAddressSpace::pseudoAddrSpaceReader( 788 void* refCon, 789 UInt16 nodeID, 790 IOFWSpeed& speed, 791 FWAddress addr, 792 UInt32 len, 793 IOMemoryDescriptor** buf, 794 IOByteCount* outOffset, 795 IOFWRequestRefCon reqrefcon) 796{ 797 IOFWUserPseudoAddressSpace* me = (IOFWUserPseudoAddressSpace*)refCon ; 798 799 if ( 0 == me->fReadAsyncNotificationRef[0] ) 800 return kFWResponseTypeError ; 801 802 return me->doPacket( nodeID, speed, addr, len, buf, reqrefcon, IOFWPacketHeader::kReadPacket) ; 803} 804 805UInt32 806IOFWUserPseudoAddressSpace::pseudoAddrSpaceWriter( 807 void* refCon, 808 UInt16 nodeID, 809 IOFWSpeed& speed, 810 FWAddress addr, 811 UInt32 len, 812 const void* buf, 813 IOFWRequestRefCon reqrefcon) 814{ 815 IOFWUserPseudoAddressSpace* me = (IOFWUserPseudoAddressSpace*)refCon ; 816 817 return me->doPacket( nodeID, speed, addr, len, buf, reqrefcon, IOFWPacketHeader::kIncomingPacket ) ; 818} 819 820void 821IOFWUserPseudoAddressSpace::setAsyncRef_Packet( 822 OSAsyncReference64 asyncRef) 823{ 824 bcopy(asyncRef, fPacketAsyncNotificationRef, sizeof(OSAsyncReference64)) ; 825} 826 827void 828IOFWUserPseudoAddressSpace::setAsyncRef_SkippedPacket( 829 OSAsyncReference64 asyncRef) 830{ 831 bcopy(asyncRef, fSkippedPacketAsyncNotificationRef, sizeof(OSAsyncReference64)) ; 832} 833 834void 835IOFWUserPseudoAddressSpace::setAsyncRef_Read( 836 OSAsyncReference64 asyncRef) 837{ 838 bcopy(asyncRef, fReadAsyncNotificationRef, sizeof(OSAsyncReference64)) ; 839} 840 841void 842IOFWUserPseudoAddressSpace::clientCommandIsComplete( 843 FWClientCommandID inCommandID, 844 IOReturn inResult) 845{ 846 IOLockLock(fLock) ; 847 848 if ( fWaitingForUserCompletion ) 849 { 850 IOFWPacketHeader* oldHeader = fLastReadHeader ; 851 IOFWPacketHeader::QueueTag type = oldHeader->CommonHeader.type ; 852 fLastReadHeader = fLastReadHeader->CommonHeader.next ; 853 854 DebugLog("Cplt cmdID: 0x%llx\n", oldHeader->IncomingPacket.commandID); 855 856 switch(type) 857 { 858 case IOFWPacketHeader::kLockPacket: 859 { 860 DebugLog("\tCplt lock\n"); 861 fUserClient->getOwner()->getController()->asyncLockResponse( oldHeader->IncomingPacket.generation, 862 oldHeader->IncomingPacket.nodeID, 863 oldHeader->IncomingPacket.speed, 864 fDesc,//fBackingStore 865 oldHeader->IncomingPacket.addrLo - fAddress.addressLo, 866 oldHeader->IncomingPacket.packetSize >> 1, 867 (void*)oldHeader->IncomingPacket.reqrefcon ) ; 868 } 869 // fall through 870 871 case IOFWPacketHeader::kIncomingPacket: 872 { 873 DebugLog("\tCplt write\n"); 874 fPacketQueue->dequeueBytes(oldHeader->IncomingPacket.packetSize); 875 break ; 876 } 877 878 case IOFWPacketHeader::kReadPacket: 879 { 880 DebugLog("\tCplt read\n"); 881 fUserClient->getOwner()->getController()->asyncReadResponse( oldHeader->ReadPacket.generation, 882 oldHeader->ReadPacket.nodeID, 883 oldHeader->ReadPacket.speed, 884 fDesc,//fBackingStore 885 oldHeader->ReadPacket.addrLo - fAddress.addressLo, 886 oldHeader->ReadPacket.packetSize, 887 (void*)oldHeader->ReadPacket.reqrefcon ) ; 888 break; 889 } 890 891 default: 892 // nothing... 893 DebugLog("\tCplt type %u\n", type); 894 break ; 895 } 896 897 oldHeader->CommonHeader.type = IOFWPacketHeader::kFree ; 898 fWaitingForUserCompletion = false ; 899 900 // send *next* packet notification 901 if ( fLastReadHeader->CommonHeader.type != IOFWPacketHeader::kFree ) 902 { 903 DebugLog("\tCplt sending next packet notification\n"); 904 sendPacketNotification(fLastReadHeader) ; 905 } 906 } 907 908 IOLockUnlock(fLock) ; 909} 910 911void 912IOFWUserPseudoAddressSpace::sendPacketNotification( 913 IOFWPacketHeader* inPacketHeader) 914{ 915 if (!fWaitingForUserCompletion) 916 { 917 if ( inPacketHeader->CommonHeader.type == IOFWPacketHeader::kIncomingPacket and (fFlags & kFWAddressSpaceAutoCopyOnWrite) != 0 ) 918 { 919 IOByteCount len = IOFWPacketHeaderGetSize(inPacketHeader) ; 920 void * bytes = IOMalloc( len ); 921 922 fPacketQueue->readBytes( IOFWPacketHeaderGetOffset( inPacketHeader ), bytes, len ); 923 924 fDesc->writeBytes( inPacketHeader->IncomingPacket.addrLo - fAddress.addressLo, 925 bytes, 926 len ) ; 927 928 IOFree( bytes, len ); 929 } 930 931 if (inPacketHeader->CommonHeader.whichAsyncRef[0]) 932 { 933 DebugLog("sPN cmdID 0x%llx\n", inPacketHeader->IncomingPacket.commandID); 934 #if 0 // debug logging 935 io_user_reference_t hdrSize = IOFWPacketHeaderGetSize(inPacketHeader); 936 io_user_reference_t hdrOffset = IOFWPacketHeaderGetOffset(inPacketHeader); 937 FireLog("\tsPN hdr: %p off %llu size %llu %s\n", inPacketHeader, hdrOffset, hdrSize, inPacketHeader->CommonHeader.type == IOFWPacketHeader::kSkippedPacket ? "SkippedPkt" : ""); 938 939 IOByteCount len = IOFWPacketHeaderGetSize(inPacketHeader) ; 940 void * bytes = IOMalloc( len ); 941 942 if ( inPacketHeader->CommonHeader.type == IOFWPacketHeader::kIncomingPacket || inPacketHeader->CommonHeader.type == IOFWPacketHeader::kLockPacket ) 943 { 944 fPacketQueue->readBytes( IOFWPacketHeaderGetOffset( inPacketHeader ), bytes, len ); 945 FireLog("\tsPN %lu 0x%x\n", len, *((UInt32 *)bytes)); 946 } 947 948 IOFree( bytes, len ); 949 #endif 950 951 IOFireWireUserClient::sendAsyncResult64(*(inPacketHeader->CommonHeader.whichAsyncRef), 952 kIOReturnSuccess, 953 (io_user_reference_t*)inPacketHeader->CommonHeader.args, 954 inPacketHeader->CommonHeader.argCount) ; 955 fWaitingForUserCompletion = true ; 956 } 957 } 958} 959 960#endif //__IOFWUserClientPseuAddrSpace_H__ 961