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 * IOFWUserAsyncStreamListener.cpp 24 * IOFireWireFamily 25 * 26 * Created by Arul on Wed Nov 08 2006. 27 * Copyright (c) 2006 Apple, Inc. All rights reserved. 28 * 29 */ 30/* 31 $Log: IOFWUserAsyncStreamListener.cpp,v $ 32 Revision 1.6 2007/10/27 01:12:34 arulchan 33 fix for rdar://5558059 34 35 Revision 1.5 2007/02/16 19:03:43 arulchan 36 *** empty log message *** 37 38 Revision 1.4 2007/02/07 06:35:20 collin 39 *** empty log message *** 40 41 Revision 1.3 2007/01/15 23:29:04 arulchan 42 Fixed Skipped Packet Handler Notifications 43 44 Revision 1.2 2006/12/21 21:17:44 ayanowit 45 More changes necessary to eventually get support for 64-bit apps working (4222965). 46 47 Revision 1.1 2006/12/06 00:03:28 arulchan 48 Isoch Channel 31 Receiver 49 50*/ 51 52#import <IOKit/firewire/IOFireWireNub.h> 53#import <IOKit/firewire/IOFireWireController.h> 54 55 56// protected 57#import <IOKit/firewire/IOFireWireLink.h> 58 59// private 60#import "IOFireWireUserClient.h" 61#import "IOFireWireLib.h" 62#import "IOFWUserPseudoAddressSpace.h" 63#import "IOFWUserAsyncStreamListener.h" 64 65// system 66#import <IOKit/assert.h> 67#import <IOKit/IOLib.h> 68#import <IOKit/IOWorkLoop.h> 69#import <IOKit/IOTypes.h> 70#import <IOKit/IOMessage.h> 71#import <IOKit/IOUserClient.h> 72 73extern void InitSkippedPacketHeader( 74 IOFWPacketHeader* header, 75 IOFWPacketHeader* next, 76 const IOByteCount offset, 77 OSAsyncReference64* ref); 78 79Boolean IsAsyncStreamSkippedPacketHeader( 80 IOFWPacketHeader* header) 81{ 82 return header->CommonHeader.type == IOFWPacketHeader::kSkippedPacket ; 83} 84 85Boolean IsAsyncStreamFreePacketHeader( 86 IOFWPacketHeader* header) 87{ 88 return header->CommonHeader.type == IOFWPacketHeader::kFree ; 89} 90 91// ============================================================ 92// IOFWUserAsyncStreamListener methods 93// ============================================================ 94 95OSDefineMetaClassAndStructors( IOFWUserAsyncStreamListener, IOFWAsyncStreamListener ) ; 96 97#if IOFIREWIREUSERCLIENTDEBUG > 0 98 99bool 100IOFWUserAsyncStreamListener::serialize(OSSerialize *s) const 101{ 102 if (s->previouslySerialized(this)) 103 return true ; 104 105 char temp[256] ; 106 107 if ( fFlags ) 108 { 109 snprintf(temp+strlen(temp), sizeof(temp), ", flags:") ; 110 } 111 else 112 { 113 snprintf(temp+strlen(temp), sizeof(temp), ", no flags") ; 114 } 115 116 OSString* string = OSString::withCString(temp) ; 117 if (!string) 118 return false ; 119 120 bool result = string->serialize(s) ; 121 string->release() ; 122 123 return result ; 124} 125 126#endif 127 128void 129IOFWUserAsyncStreamListener::free() 130{ 131 if ( fPacketQueuePrepared ) 132 fPacketQueueBuffer->complete() ; 133 134 if ( fPacketQueueBuffer ) 135 fPacketQueueBuffer->release() ; 136 137 delete fLastWrittenHeader ; 138 139 if( fLock ) 140 { 141 IOLockFree( fLock ); 142 fLock = NULL; 143 } 144 145 IOFWAsyncStreamListener::free() ; 146} 147 148// exporterCleanup 149// 150// 151 152void 153IOFWUserAsyncStreamListener::exporterCleanup( OSObject * self, IOFWUserObjectExporter * exporter ) 154{ 155 IOFWUserAsyncStreamListener * me = (IOFWUserAsyncStreamListener*)self; 156 157 me->deactivate(); 158 159 ((IOFireWireUserClient*)exporter->getOwner())->getOwner()->getController()->removeAsyncStreamListener(me); 160} 161 162void 163IOFWUserAsyncStreamListener::deactivate() 164{ 165 IOFWAsyncStreamListener::TurnOffNotification() ; 166 167 IOLockLock(fLock) ; 168 169 fBufferAvailable = 0 ; // zzz do we need locking here to protect our data? 170 fLastReadHeader = NULL ; 171 172 IOFWPacketHeader* firstHeader = fLastWrittenHeader ; 173 IOFWPacketHeader* tempHeader ; 174 175 if (fLastWrittenHeader) 176 { 177 while (fLastWrittenHeader->CommonHeader.next != firstHeader) 178 { 179 tempHeader = fLastWrittenHeader->CommonHeader.next ; 180 delete fLastWrittenHeader ; 181 fLastWrittenHeader = tempHeader ; 182 } 183 184 } 185 186 fWaitingForUserCompletion = false ; 187 188 IOLockUnlock(fLock) ; 189} 190 191bool 192IOFWUserAsyncStreamListener::completeInit( IOFireWireUserClient* userclient, FWUserAsyncStreamListenerCreateParams* params ) 193{ 194 Boolean status = true ; 195 196 197 fUserRefCon = params->refCon ; 198 fFlags = params->flags ; 199 fWaitingForUserCompletion = false ; 200 201 // set user client 202 fUserClient = userclient ; 203 204 // see if user specified a packet queue and queue size 205 if ( !params->queueBuffer ) 206 { 207 DebugLog("IOFWUserAsyncStreamListener::initAll: async stream listener without queue buffer\n") ; 208 status = false ; 209 } 210 211 // make memory descriptor around queue 212 if ( status ) 213 { 214 if ( params->queueBuffer ) 215 { 216 fPacketQueueBuffer = IOMemoryDescriptor::withAddressRange( params->queueBuffer, 217 params->queueSize, 218 kIODirectionOutIn, 219 fUserClient->getOwningTask() ) ; 220 if ( !fPacketQueueBuffer ) 221 { 222 DebugLog("%s %u: couldn't make fPacketQueueBuffer memory descriptor\n", __FILE__, __LINE__) ; 223 status = false ; 224 } 225 226 if ( status ) 227 { 228 status = ( kIOReturnSuccess == fPacketQueueBuffer->prepare() ) ; 229 230 fPacketQueuePrepared = status ; 231 } 232 233 if ( status ) 234 fBufferAvailable = fPacketQueueBuffer->getLength() ; 235 } 236 } 237 238 if ( status ) 239 { 240 // init the easy vars 241 fLastReadHeader = new IOFWPacketHeader ; 242 fLastWrittenHeader = fLastReadHeader ; 243 244 fLastWrittenHeader->CommonHeader.whichAsyncRef = NULL; 245 246 // get a lock for the packet queue 247 fLock = IOLockAlloc() ; 248 249 if ( !fLock ) 250 { 251 DebugLog("%s %u: couldn't allocate lock\n", __FILE__, __LINE__) ; 252 status = false ; 253 } 254 } 255 256 257 if (status) 258 { 259 fUserLocks = true ; 260 } 261 262 return status ; 263} 264 265bool 266IOFWUserAsyncStreamListener::initAsyncStreamListener( 267 IOFireWireUserClient *userclient, 268 IOFireWireLib::FWUserAsyncStreamListenerCreateParams *params) 269{ 270 if ( !IOFWUserAsyncStreamListener::initAll( userclient->getOwner()->getController(), 271 params->channel, 272 IOFWUserAsyncStreamListener::asyncStreamListenerHandler, 273 this )) 274 { 275 DebugLog("IOFWUserAsyncStreamListener::initAsyncStreamListener failed\n") ; 276 return false ; 277 } 278 279 bool result = completeInit( userclient, params ) ; 280 281 return result ; 282} 283 284 285void 286IOFWUserAsyncStreamListener::doPacket( 287 UInt32 len, 288 const void* buf, 289 IOFWPacketHeader::QueueTag tag, 290 UInt32* oldVal) // oldVal only used in lock case 291{ 292 IOByteCount destOffset = 0 ; 293 bool wontFit = false ; 294 295 IOLockLock(fLock) ; 296 297 IOFWPacketHeader* currentHeader = fLastWrittenHeader ; 298 299 if ( tag == IOFWPacketHeader::kIncomingPacket ) 300 { 301 IOByteCount spaceAtEnd = fPacketQueueBuffer->getLength() ; 302 303 spaceAtEnd -= (IOFWPacketHeaderGetOffset(currentHeader) + IOFWPacketHeaderGetSize(currentHeader)) ; 304 305 if ( fBufferAvailable < len ) 306 { 307 wontFit = true ; 308 } 309 else 310 { 311 if (len <= spaceAtEnd) 312 destOffset = IOFWPacketHeaderGetOffset(currentHeader) + IOFWPacketHeaderGetSize(currentHeader) ; 313 else 314 { 315 if ( (len + spaceAtEnd) <= fBufferAvailable ) 316 destOffset = 0 ; 317 else 318 { 319 destOffset = IOFWPacketHeaderGetOffset(currentHeader) ; 320 wontFit = true ; 321 } 322 } 323 } 324 } 325 326 if (wontFit) 327 { 328 if (IsAsyncStreamSkippedPacketHeader(currentHeader)) 329 { 330 ++(currentHeader->SkippedPacket.skippedPacketCount) ; 331 } 332 else 333 { 334 if (!IsAsyncStreamFreePacketHeader(currentHeader)) 335 { 336 if ( !IsAsyncStreamFreePacketHeader(currentHeader->CommonHeader.next) ) 337 { 338 IOFWPacketHeader* newHeader = new IOFWPacketHeader ; 339 newHeader->CommonHeader.next = currentHeader->CommonHeader.next ; 340 currentHeader->CommonHeader.next = newHeader ; 341 } 342 343 currentHeader = currentHeader->CommonHeader.next ; 344 345 } 346 347 InitSkippedPacketHeader( 348 currentHeader, 349 currentHeader->CommonHeader.next, 350 destOffset, 351 & fSkippedPacketAsyncNotificationRef ) ; 352 353 fLastWrittenHeader = currentHeader ; 354 } 355 } 356 else 357 { 358 if (!IsAsyncStreamFreePacketHeader(currentHeader)) 359 { 360 if ( !IsAsyncStreamFreePacketHeader(currentHeader->CommonHeader.next) ) 361 { 362 IOFWPacketHeader* newHeader = new IOFWPacketHeader ; 363 newHeader->CommonHeader.next = currentHeader->CommonHeader.next ; 364 currentHeader->CommonHeader.next = newHeader ; 365 } 366 367 } 368 369 currentHeader = currentHeader->CommonHeader.next ; 370 371 FWAddress addr; 372 addr.addressHi = 0; addr.addressLo = 0; 373 374 IOFWSpeed speed = kFWSpeedInvalid; 375 376 InitIncomingPacketHeader( 377 currentHeader, 378 currentHeader->CommonHeader.next, 379 len, 380 destOffset, 381 & fPacketAsyncNotificationRef, 382 0, 383 speed, 384 addr, 385 false) ; 386 387 fPacketQueueBuffer->writeBytes(destOffset, buf, len) ; 388 389 fBufferAvailable -= len ; 390 391 fLastWrittenHeader = currentHeader ; 392 } 393 394 if( currentHeader->CommonHeader.type != IOFWPacketHeader::kFree ) 395 sendPacketNotification(currentHeader) ; 396 397 IOLockUnlock(fLock) ; 398} 399 400void 401IOFWUserAsyncStreamListener::asyncStreamListenerHandler( 402 void* refCon, 403 const void* buf) 404{ 405 IOFWUserAsyncStreamListener* me = (IOFWUserAsyncStreamListener*)refCon ; 406 ISOC_DATA_PKT *pkt = (ISOC_DATA_PKT*)buf; 407 408 me->doPacket( pkt->size+sizeof(ISOC_DATA_PKT), buf, IOFWPacketHeader::kIncomingPacket ) ; 409} 410 411void 412IOFWUserAsyncStreamListener::setAsyncStreamRef_Packet( 413 OSAsyncReference64 asyncRef) 414{ 415 bcopy(asyncRef, fPacketAsyncNotificationRef, sizeof(OSAsyncReference64)) ; 416} 417 418void 419IOFWUserAsyncStreamListener::setAsyncStreamRef_SkippedPacket( 420 OSAsyncReference64 asyncRef) 421{ 422 bcopy(asyncRef, fSkippedPacketAsyncNotificationRef, sizeof(OSAsyncReference64)) ; 423} 424 425void 426IOFWUserAsyncStreamListener::clientCommandIsComplete( 427 FWClientCommandID inCommandID) 428{ 429 IOLockLock(fLock) ; 430 431 if ( fWaitingForUserCompletion ) 432 { 433 IOFWPacketHeader* oldHeader = fLastReadHeader ; 434 fLastReadHeader = fLastReadHeader->CommonHeader.next ; 435 436 fBufferAvailable += oldHeader->IncomingPacket.packetSize ; 437 438 oldHeader->CommonHeader.type = IOFWPacketHeader::kFree ; 439 oldHeader->CommonHeader.whichAsyncRef = 0; 440 441 fWaitingForUserCompletion = false ; 442 } 443 if ( fLastReadHeader->CommonHeader.type != IOFWPacketHeader::kFree ) 444 sendPacketNotification(fLastReadHeader) ; 445 446 IOLockUnlock(fLock) ; 447} 448 449void 450IOFWUserAsyncStreamListener::sendPacketNotification( 451 IOFWPacketHeader* inPacketHeader) 452{ 453 if (!fWaitingForUserCompletion) 454 { 455 if (inPacketHeader->CommonHeader.whichAsyncRef[0]) 456 { 457 IOReturn ret = IOFireWireUserClient::sendAsyncResult64(*(inPacketHeader->CommonHeader.whichAsyncRef), 458 kIOReturnSuccess, 459 (io_user_reference_t *)inPacketHeader->CommonHeader.args, 460 inPacketHeader->CommonHeader.argCount) ; 461 462 if(ret == kIOReturnSuccess) 463 fWaitingForUserCompletion = true ; 464 } 465 } 466}