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#include <CoreFoundation/CoreFoundation.h>
24
25#include "FWDebugging.h"
26#include "IOFireWireSBP2LibLUN.h"
27#include "IOFireWireSBP2LibLogin.h"
28#include "IOFireWireSBP2LibMgmtORB.h"
29#include "IOFireWireSBP2UserClientCommon.h"
30
31#include <System/libkern/OSCrossEndian.h>
32
33__BEGIN_DECLS
34#include <IOKit/iokitmig.h>
35#include <mach/mach.h>
36__END_DECLS
37
38//
39// static interface table for IOCFPlugInInterface
40//
41
42IOCFPlugInInterface IOFireWireSBP2LibLUN::sIOCFPlugInInterface =
43{
44    0,
45	&IOFireWireSBP2LibLUN::staticQueryInterface,
46	&IOFireWireSBP2LibLUN::staticAddRef,
47	&IOFireWireSBP2LibLUN::staticRelease,
48	1, 0, // version/revision
49	&IOFireWireSBP2LibLUN::staticProbe,
50	&IOFireWireSBP2LibLUN::staticStart,
51	&IOFireWireSBP2LibLUN::staticStop
52};
53
54//
55// static interface table for IOFireWireSBP2LibLUNInterface
56//
57
58IOFireWireSBP2LibLUNInterface IOFireWireSBP2LibLUN::sIOFireWireSBP2LibLUNInterface =
59{
60    0,
61	&IOFireWireSBP2LibLUN::staticQueryInterface,
62	&IOFireWireSBP2LibLUN::staticAddRef,
63	&IOFireWireSBP2LibLUN::staticRelease,
64	1, 0, // version/revision
65	&IOFireWireSBP2LibLUN::staticOpen,
66	&IOFireWireSBP2LibLUN::staticOpenWithSessionRef,
67	&IOFireWireSBP2LibLUN::staticGetSessionRef,
68	&IOFireWireSBP2LibLUN::staticClose,
69	&IOFireWireSBP2LibLUN::staticAddIODispatcherToRunLoop,
70	&IOFireWireSBP2LibLUN::staticRemoveIODispatcherFromRunLoop,
71	&IOFireWireSBP2LibLUN::staticSetMessageCallback,
72	&IOFireWireSBP2LibLUN::staticSetRefCon,
73	&IOFireWireSBP2LibLUN::staticGetRefCon,
74	&IOFireWireSBP2LibLUN::staticCreateLogin,
75	&IOFireWireSBP2LibLUN::staticCreateMgmtORB,
76};
77
78// IOFireWireSBP2LibFactory
79//
80// factory method
81
82void *IOFireWireSBP2LibFactory( CFAllocatorRef allocator, CFUUIDRef typeID )
83{
84	FWLOG(( "IOFireWireSBP2LibFactory called\n" ));
85
86    if( CFEqual(typeID, kIOFireWireSBP2LibTypeID) )
87        return (void *) IOFireWireSBP2LibLUN::alloc();
88    else
89        return NULL;
90}
91
92// alloc
93//
94// static allocator, called by factory method
95
96IOCFPlugInInterface ** IOFireWireSBP2LibLUN::alloc()
97{
98    IOFireWireSBP2LibLUN *	me;
99	IOCFPlugInInterface ** 	interface = NULL;
100
101    me = new IOFireWireSBP2LibLUN;
102    if( me )
103	{
104		// we return an interface here. queryInterface will not be called. call addRef here
105		me->addRef();
106        interface = (IOCFPlugInInterface **) &me->fIOCFPlugInInterface.pseudoVTable;
107    }
108
109	return interface;
110}
111
112// ctor
113//
114//
115
116IOFireWireSBP2LibLUN::IOFireWireSBP2LibLUN( void )
117{
118	// init cf plugin ref counting
119	fRefCount = 0;
120
121	// init user client connection
122	fConnection = MACH_PORT_NULL;
123	fService = MACH_PORT_NULL;
124
125	// init async callbacks
126	fAsyncPort = MACH_PORT_NULL;
127	fCFAsyncPort = NULL;
128	fCFRunLoopSource = NULL;
129	fMessageCallbackRoutine = NULL;
130	fMessageCallbackRefCon = NULL;
131
132	// create plugin interface map
133    fIOCFPlugInInterface.pseudoVTable = (IUnknownVTbl *) &sIOCFPlugInInterface;
134    fIOCFPlugInInterface.obj = this;
135
136	// create test driver interface map
137	fIOFireWireSBP2LibLUNInterface.pseudoVTable
138								= (IUnknownVTbl *) &sIOFireWireSBP2LibLUNInterface;
139	fIOFireWireSBP2LibLUNInterface.obj = this;
140
141	fFactoryId = kIOFireWireSBP2LibFactoryID;
142	CFRetain( fFactoryId );
143	CFPlugInAddInstanceForFactory( fFactoryId );
144}
145
146// dtor
147//
148//
149
150IOFireWireSBP2LibLUN::~IOFireWireSBP2LibLUN()
151{
152	CFPlugInRemoveInstanceForFactory( fFactoryId );
153	CFRelease( fFactoryId );
154}
155
156//////////////////////////////////////////////////////////////////
157// IUnknown methods
158//
159
160// queryInterface
161//
162//
163
164HRESULT IOFireWireSBP2LibLUN::staticQueryInterface( void * self, REFIID iid, void **ppv )
165{
166	return getThis(self)->queryInterface( iid, ppv );
167}
168
169HRESULT IOFireWireSBP2LibLUN::queryInterface( REFIID iid, void **ppv )
170{
171    CFUUIDRef uuid = CFUUIDCreateFromUUIDBytes(NULL, iid);
172    HRESULT result = S_OK;
173
174	if( CFEqual(uuid, IUnknownUUID) ||  CFEqual(uuid, kIOCFPlugInInterfaceID) )
175	{
176        *ppv = &fIOCFPlugInInterface;
177        addRef();
178    }
179	else if( CFEqual(uuid, kIOFireWireSBP2LibLUNInterfaceID) )
180	{
181        *ppv = &fIOFireWireSBP2LibLUNInterface;
182        addRef();
183    }
184    else
185        *ppv = 0;
186
187    if( !*ppv )
188        result = E_NOINTERFACE;
189
190    CFRelease( uuid );
191
192    return result;
193}
194
195// addRef
196//
197//
198
199UInt32 IOFireWireSBP2LibLUN::staticAddRef( void * self )
200{
201	return getThis(self)->addRef();
202}
203
204UInt32 IOFireWireSBP2LibLUN::addRef()
205{
206    fRefCount += 1;
207    return fRefCount;
208}
209
210// release
211//
212//
213
214UInt32 IOFireWireSBP2LibLUN::staticRelease( void * self )
215{
216	return getThis(self)->release();
217}
218
219UInt32 IOFireWireSBP2LibLUN::release( void )
220{
221	UInt32 retVal = fRefCount;
222
223	if( 1 == fRefCount-- )
224	{
225		delete this;
226    }
227
228	return retVal;
229}
230
231//////////////////////////////////////////////////////////////////
232// IOCFPlugInInterface methods
233//
234
235// probe
236//
237//
238
239IOReturn IOFireWireSBP2LibLUN::staticProbe( void * self, CFDictionaryRef propertyTable,
240											io_service_t service, SInt32 *order )
241{
242	return getThis(self)->probe( propertyTable, service, order );
243}
244
245IOReturn IOFireWireSBP2LibLUN::probe( CFDictionaryRef propertyTable,
246									  io_service_t service, SInt32 *order )
247{
248	// only load against LUN's
249    if( !service || !IOObjectConformsTo(service, "IOFireWireSBP2LUN") )
250        return kIOReturnBadArgument;
251
252	return kIOReturnSuccess;
253}
254
255// start
256//
257//
258
259IOReturn IOFireWireSBP2LibLUN::staticStart( void * self, CFDictionaryRef propertyTable,
260											io_service_t service )
261{
262	return getThis(self)->start( propertyTable, service );
263}
264
265IOReturn IOFireWireSBP2LibLUN::start( CFDictionaryRef propertyTable, io_service_t service )
266{
267	IOReturn status = kIOReturnSuccess;
268
269	FWLOG(( "IOFireWireSBP2LibLUN : start\n" ));
270
271	fService = service;
272    status = IOServiceOpen( fService, mach_task_self(),
273							kIOFireWireSBP2LibConnection, &fConnection );
274	if( !fConnection )
275		status = kIOReturnNoDevice;
276
277	if( status == kIOReturnSuccess )
278	{
279	    status = IOCreateReceivePort( kOSAsyncCompleteMessageID, &fAsyncPort );
280	}
281
282	FWLOG(( "IOFireWireSBP2LibLUN : IOServiceOpen status = 0x%08lx, connection = %d\n", (UInt32) status, fConnection ));
283
284	return status;
285}
286
287// stop
288//
289//
290
291IOReturn IOFireWireSBP2LibLUN::staticStop( void * self )
292{
293	return getThis(self)->stop();
294}
295
296IOReturn IOFireWireSBP2LibLUN::stop( void )
297{
298	FWLOG(( "IOFireWireSBP2LibLUN : stop\n" ));
299
300	removeIODispatcherFromRunLoop();
301
302	if( fConnection )
303	{
304		FWLOG(( "IOFireWireSBP2LibLUN : IOServiceClose connection = %d\n", fConnection ));
305        IOServiceClose( fConnection );
306        fConnection = MACH_PORT_NULL;
307    }
308
309	if( fAsyncPort != MACH_PORT_NULL )
310	{
311		FWLOG(( "IOFireWireSBP2LibLUN : release fAsyncPort\n" ));
312		mach_port_destroy( mach_task_self(), fAsyncPort );
313		fAsyncPort = MACH_PORT_NULL;
314	}
315
316	return kIOReturnSuccess;
317}
318
319//////////////////////////////////////////////////////////////////
320// IOFireWireSBP2LUN methods
321//
322
323// open
324//
325//
326
327IOReturn IOFireWireSBP2LibLUN::staticOpen( void * self )
328{
329	return getThis(self)->open();
330}
331
332IOReturn IOFireWireSBP2LibLUN::open( void )
333{
334	IOReturn status = kIOReturnSuccess;
335
336    if( !fConnection )
337		return kIOReturnNoDevice;
338
339	FWLOG(( "IOFireWireSBP2LUN : open\n" ));
340
341    uint32_t len = 0;
342    status = IOConnectCallScalarMethod( fConnection,
343										kIOFWSBP2UserClientOpen,
344										NULL, 0, NULL, &len );
345	return status;
346}
347
348// openWithSessionRef
349//
350//
351
352IOReturn IOFireWireSBP2LibLUN::staticOpenWithSessionRef( void * self, IOFireWireSessionRef sessionRef )
353{
354	return getThis(self)->openWithSessionRef( sessionRef );
355}
356
357IOReturn IOFireWireSBP2LibLUN::openWithSessionRef( IOFireWireSessionRef sessionRef )
358{
359	IOReturn status = kIOReturnSuccess;
360
361    if( !fConnection )
362		return kIOReturnNoDevice;
363
364	FWLOG(( "IOFireWireSBP2LUN : openWithSessionRef\n" ));
365
366    uint32_t len = 0;
367	uint64_t session_ref_64 = (uint64_t)sessionRef;
368    status = IOConnectCallScalarMethod( fConnection, kIOFWSBP2UserClientOpenWithSessionRef,
369										&session_ref_64, 1, NULL, &len );
370
371	return status;
372}
373
374// getSessionRef
375//
376//
377
378IOFireWireSessionRef IOFireWireSBP2LibLUN::staticGetSessionRef( void * self )
379{
380	return getThis(self)->getSessionRef();
381}
382
383IOFireWireSessionRef IOFireWireSBP2LibLUN::getSessionRef( void )
384{
385	IOReturn status = kIOReturnSuccess;
386	uint64_t sessionRef = 0;
387
388    if( !fConnection )
389		return (IOFireWireSessionRef)sessionRef;
390
391	FWLOG(( "IOFireWireSBP2LUN : getSessionRef\n" ));
392
393    uint32_t len = 1;
394    status = IOConnectCallScalarMethod( fConnection, kIOFWSBP2UserClientGetSessionRef,
395										NULL, 0, &sessionRef, &len );
396
397	if( status != kIOReturnSuccess )
398		sessionRef = 0; // just to make sure
399
400	return (IOFireWireSessionRef)sessionRef;
401}
402
403// close
404//
405//
406
407void IOFireWireSBP2LibLUN::staticClose( void * self )
408{
409	getThis(self)->close();
410}
411
412void IOFireWireSBP2LibLUN::close( void )
413{
414   if( !fConnection )
415		return;
416
417	FWLOG(( "IOFireWireSBP2LUN : close\n" ));
418
419    uint32_t len = 0;
420	IOConnectCallScalarMethod(	fConnection, kIOFWSBP2UserClientClose,
421								NULL, 0, NULL, &len );
422
423}
424
425// addIODispatcherToRunLoop
426//
427//
428
429IOReturn IOFireWireSBP2LibLUN::staticAddIODispatcherToRunLoop( void *self,
430												CFRunLoopRef cfRunLoopRef )
431{
432	return getThis(self)->addIODispatcherToRunLoop( cfRunLoopRef );
433}
434
435IOReturn IOFireWireSBP2LibLUN::addIODispatcherToRunLoop( CFRunLoopRef cfRunLoopRef )
436{
437	IOReturn 				status = kIOReturnSuccess;
438
439	FWLOG(( "IOFireWireSBP2LibLUN : addIODispatcherToRunLoop\n" ));
440
441	if( !fConnection )
442		return kIOReturnNoDevice;
443
444	if( status == kIOReturnSuccess )
445	{
446		CFMachPortContext context;
447		Boolean	shouldFreeInfo; // zzz what's this for?
448
449		context.version = 1;
450		context.info = this;
451		context.retain = NULL;
452		context.release = NULL;
453		context.copyDescription = NULL;
454
455		fCFAsyncPort = CFMachPortCreateWithPort( kCFAllocatorDefault, fAsyncPort,
456							(CFMachPortCallBack) IODispatchCalloutFromMessage,
457							&context, &shouldFreeInfo );
458		if( !fCFAsyncPort )
459			status = kIOReturnNoMemory;
460	}
461
462	if( status == kIOReturnSuccess )
463	{
464		fCFRunLoopSource = CFMachPortCreateRunLoopSource( kCFAllocatorDefault, fCFAsyncPort, 0 );
465		if( !fCFRunLoopSource )
466			status = kIOReturnNoMemory;
467	}
468
469	if( status == kIOReturnSuccess )
470	{
471		fCFRunLoop = cfRunLoopRef;
472		CFRunLoopAddSource( fCFRunLoop, fCFRunLoopSource, kCFRunLoopCommonModes );
473	}
474
475	if( status == kIOReturnSuccess )
476	{
477		io_async_ref64_t asyncRef;
478		mach_msg_type_number_t	size = 0;
479
480		asyncRef[kIOAsyncCalloutFuncIndex] = (uint64_t)&IOFireWireSBP2LibLUN::staticMessageCallback;
481		asyncRef[kIOAsyncCalloutRefconIndex] = (uint64_t)this;
482
483		status = IOConnectCallAsyncScalarMethod( fConnection, kIOFWSBP2UserClientSetMessageCallback, fAsyncPort, asyncRef, kOSAsyncRef64Count, NULL, 0, NULL, &size  );
484	}
485
486	return status;
487}
488
489// removeIODispatcherFromRunLoop
490//
491//
492
493void IOFireWireSBP2LibLUN::staticRemoveIODispatcherFromRunLoop( void * self )
494{
495	return getThis(self)->removeIODispatcherFromRunLoop();
496}
497
498void IOFireWireSBP2LibLUN::removeIODispatcherFromRunLoop( void )
499{
500	if( fCFRunLoopSource != NULL )
501	{
502		CFRunLoopRemoveSource( fCFRunLoop, fCFRunLoopSource, kCFRunLoopCommonModes );
503		CFRelease( fCFRunLoopSource );
504		fCFRunLoopSource = NULL;
505	}
506
507	if( fCFAsyncPort != NULL )
508	{
509		FWLOG(( "IOFireWireSBP2LibLUN : release fCFAsyncPort\n" ));
510		CFMachPortInvalidate( fCFAsyncPort );
511		CFRelease( fCFAsyncPort );
512		fCFAsyncPort = NULL;
513	}
514}
515
516// setMessageCallback
517//
518//
519
520void IOFireWireSBP2LibLUN::staticSetMessageCallback( void * self, void * refCon,
521													IOFWSBP2MessageCallback callback )
522{
523	getThis(self)->setMessageCallback( refCon, callback );
524}
525
526void IOFireWireSBP2LibLUN::setMessageCallback( void * refCon,
527													IOFWSBP2MessageCallback callback )
528{
529	fMessageCallbackRoutine = callback;
530	fMessageCallbackRefCon = refCon;
531}
532
533// createLogin
534//
535// create a login object
536
537IUnknownVTbl ** IOFireWireSBP2LibLUN::staticCreateLogin( void * self, REFIID iid )
538{
539	return getThis(self)->createLogin( iid );
540}
541
542IUnknownVTbl ** IOFireWireSBP2LibLUN::createLogin( REFIID iid )
543{
544	IOReturn status = kIOReturnSuccess;
545	IUnknownVTbl ** iunknown = NULL;
546
547	if( !fConnection )
548		status = kIOReturnError;
549
550	if( fAsyncPort == MACH_PORT_NULL )
551		status = kIOReturnError;
552
553	if( status == kIOReturnSuccess )
554	{
555		iunknown = IOFireWireSBP2LibLogin::alloc( fConnection, fAsyncPort );
556		if( iunknown == NULL )
557			status = kIOReturnNoMemory;
558	}
559
560	if( status == kIOReturnSuccess )
561	{
562		HRESULT res;
563		res = (*iunknown)->QueryInterface( iunknown, iid,
564										   (void **) &fLoginInterface );
565
566		if( res != S_OK )
567			status = kIOReturnError;
568	}
569
570	if( iunknown != NULL )
571	{
572		(*iunknown)->Release(iunknown);
573	}
574
575	if( status == kIOReturnSuccess )
576		return fLoginInterface;
577	else
578		return NULL;
579}
580
581// setRefCon
582//
583//
584
585void IOFireWireSBP2LibLUN::staticSetRefCon( void * self, void * refCon )
586{
587	getThis(self)->setRefCon( refCon );
588}
589
590void IOFireWireSBP2LibLUN::setRefCon( void * refCon )
591{
592	fRefCon = refCon;
593}
594
595// getRefCon
596//
597//
598
599void * IOFireWireSBP2LibLUN::staticGetRefCon( void * self )
600{
601	return getThis(self)->getRefCon();
602}
603
604void * IOFireWireSBP2LibLUN::getRefCon( void )
605{
606	return fRefCon;
607}
608
609// createMgmtORB
610//
611//
612
613IUnknownVTbl ** IOFireWireSBP2LibLUN::staticCreateMgmtORB( void * self, REFIID iid )
614{
615	return getThis(self)->createMgmtORB( iid );
616}
617
618IUnknownVTbl ** IOFireWireSBP2LibLUN::createMgmtORB( REFIID iid )
619{
620	IOReturn status = kIOReturnSuccess;
621	IUnknownVTbl ** iunknown = NULL;
622	IUnknownVTbl ** mgmtORB = NULL;
623
624	if( !fConnection )
625		status = kIOReturnError;
626
627	if( fAsyncPort == MACH_PORT_NULL )
628		status = kIOReturnError;
629
630	if( status == kIOReturnSuccess )
631	{
632		iunknown = IOFireWireSBP2LibMgmtORB::alloc( fConnection, fAsyncPort );
633		if( iunknown == NULL )
634			status = kIOReturnNoMemory;
635	}
636
637	if( status == kIOReturnSuccess )
638	{
639		HRESULT res;
640		res = (*iunknown)->QueryInterface( iunknown, iid,
641										   (void **) &mgmtORB );
642
643		if( res != S_OK )
644			status = kIOReturnError;
645	}
646
647	if( iunknown != NULL )
648	{
649		(*iunknown)->Release(iunknown);
650	}
651
652	if( status == kIOReturnSuccess )
653		return mgmtORB;
654	else
655		return NULL;
656}
657
658
659//////////////////////////////////////////////////////////////////
660// callback static methods
661//
662
663// messageCallback
664//
665//
666
667void IOFireWireSBP2LibLUN::staticMessageCallback( void *refcon, IOReturn result,
668													io_user_reference_t *args, int numArgs )
669{
670	((IOFireWireSBP2LibLUN*)refcon)->messageCallback( result, args, numArgs );
671}
672
673void IOFireWireSBP2LibLUN::messageCallback( IOReturn result, io_user_reference_t *args, int numArgs )
674{
675	FWLOG(( "IOFireWireSBP2LibLUN : messageCallback numArgs = %d\n", numArgs ));
676
677	FWSBP2ReconnectParams params;
678	void * outArgs = NULL;
679
680	UInt32 type = (UInt32)args[11];
681	if( type == kIOMessageFWSBP2ReconnectComplete ||
682		type == kIOMessageFWSBP2ReconnectFailed )
683	{
684		UInt32 statusBlock[8];
685
686		{
687			int i;
688
689			for( i = 0; i < 8; i++ )
690			{
691				IF_ROSETTA()
692				{
693					statusBlock[i] = OSSwapInt32( (UInt32)args[3+i] );
694				}
695				else
696				{
697					statusBlock[i] = (UInt32)args[3+i];
698				}
699			}
700		}
701
702		params.refCon = (void*)fRefCon;
703		params.generation = (UInt32)args[0];
704		params.status = (IOReturn)args[1];
705		params.reconnectStatusBlock = (FWSBP2StatusBlock*)&statusBlock;
706		params.reconnectStatusBlockLength = (UInt32)args[2];
707
708		outArgs = &params;
709	}
710
711	if( fMessageCallbackRoutine != NULL )
712		(fMessageCallbackRoutine)( fMessageCallbackRefCon, type, outArgs );
713
714}
715