1/*
2 *
3 * @APPLE_LICENSE_HEADER_START@
4 *
5 * Copyright (c) 1998-2003 Apple Computer, Inc.  All Rights Reserved.
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25#include <machine/limits.h>			/* UINT_MAX */
26#include <libkern/OSByteOrder.h>
27
28#include <IOKit/network/IOEthernetController.h>
29#include <IOKit/network/IOEthernetInterface.h>
30#include <IOKit/network/IOGatedOutputQueue.h>
31
32#include <IOKit/IOTimerEventSource.h>
33#include <IOKit/assert.h>
34#include <IOKit/IOLib.h>
35#include <IOKit/IOService.h>
36#include <IOKit/IOBufferMemoryDescriptor.h>
37#include <IOKit/IOMessage.h>
38
39#include <IOKit/pwr_mgt/RootDomain.h>
40
41#if !TARGET_OS_IPHONE
42#include <IOKit/usb/IOUSBBus.h>
43#endif /* TARGET_OS_IPHONE */
44
45#include <IOKit/usb/IOUSBNub.h>
46#include <IOKit/usb/IOUSBDevice.h>
47#include <IOKit/usb/IOUSBPipe.h>
48#include <IOKit/usb/USB.h>
49#include <IOKit/usb/IOUSBInterface.h>
50
51#include <UserNotification/KUNCUserNotifications.h>
52
53extern "C"
54{
55    #include <sys/param.h>
56    #include <sys/mbuf.h>
57}
58
59#define DEBUG_NAME "AppleUSBCDCEEM"
60
61#include "AppleUSBCDCEEM.h"
62
63#define MIN_BAUD (50 << 1)
64
65static struct MediumTable
66{
67    UInt32	type;
68    UInt32	speed;
69}
70
71mediumTable[] =
72{
73    {kIOMediumEthernetNone,												0},
74    {kIOMediumEthernetAuto,												0},
75    {kIOMediumEthernet10BaseT 	 | kIOMediumOptionHalfDuplex,								10},
76    {kIOMediumEthernet10BaseT 	 | kIOMediumOptionFullDuplex,								10},
77    {kIOMediumEthernet100BaseTX  | kIOMediumOptionHalfDuplex,								100},
78    {kIOMediumEthernet100BaseTX  | kIOMediumOptionFullDuplex,								100}
79};
80
81#define super IOEthernetController
82
83OSDefineMetaClassAndStructors(AppleUSBCDCEEM, IOEthernetController);
84
85/****************************************************************************************************/
86//
87//		Function:	findCDCDriverEED
88//
89//		Inputs:		myDevice - Address of the controlling device
90//				dataAddr - my address
91//				dataInterfaceNum - the data interface number
92//
93//		Outputs:
94//
95//		Desc:		Finds the initiating CDC driver and confirm the interface number
96//
97/****************************************************************************************************/
98
99IOReturn findCDCDriverEED(IOUSBDevice *myDevice, void *dataAddr, UInt8 dataInterfaceNum)
100{
101    AppleUSBCDCEEM	*me = (AppleUSBCDCEEM *)dataAddr;
102    AppleUSBCDC		*CDCDriver = NULL;
103    bool		driverOK = false;
104    OSIterator		*iterator = NULL;
105    OSDictionary	*matchingDictionary = NULL;
106
107    XTRACE(me, 0, 0, "findCDCDriverEED");
108
109        // Get matching dictionary
110
111    matchingDictionary = IOService::serviceMatching("AppleUSBCDC");
112    if (!matchingDictionary)
113    {
114        XTRACE(me, 0, 0, "findCDCDriverEED - Couldn't create a matching dictionary");
115        return kIOReturnError;
116    }
117
118	// Get an iterator
119
120    iterator = IOService::getMatchingServices(matchingDictionary);
121    if (!iterator)
122    {
123        XTRACE(me, 0, 0, "findCDCDriverEED - No AppleUSBCDC driver found!");
124        matchingDictionary->release();
125        return kIOReturnError;
126    }
127
128#if 0
129	// Use iterator to find driver (there's only one so we won't bother to iterate)
130
131    CDCDriver = (AppleUSBCDC *)iterator->getNextObject();
132    if (CDCDriver)
133    {
134        driverOK = CDCDriver->confirmDriver(kUSBEthernetEmulationModel, dataInterfaceNum);
135    }
136#endif
137
138 	// Iterate until we find our matching CDC driver
139
140    CDCDriver = (AppleUSBCDC *)iterator->getNextObject();
141    while (CDCDriver)
142    {
143        XTRACE(me, 0, 0, "findCDCDriverEED - CDC driver candidate");
144
145        if (me->fDataInterface->GetDevice() == CDCDriver->getCDCDevice())
146        {
147            XTRACE(me, 0, 0, "findCDCDriverEED - Found our CDC driver");
148            driverOK = CDCDriver->confirmDriver(kUSBEthernetEmulationModel, dataInterfaceNum);
149            break;
150        }
151        CDCDriver = (AppleUSBCDC *)iterator->getNextObject();
152    }
153
154    matchingDictionary->release();
155    iterator->release();
156
157    if (!CDCDriver)
158    {
159        XTRACE(me, 0, 0, "findCDCDriverEED - CDC driver not found");
160        return kIOReturnError;
161    }
162
163    if (!driverOK)
164    {
165        XTRACE(me, kUSBEthernetEmulationModel, dataInterfaceNum, "findCDCDriverEED - Not my interface");
166        return kIOReturnError;
167    }
168
169    me->fConfigAttributes = CDCDriver->fbmAttributes;
170
171    return kIOReturnSuccess;
172
173}/* end findCDCDriverEED */
174
175#if LOG_DATA
176#define dumplen		32		// Set this to the number of bytes to dump and the rest should work out correct
177
178#define buflen		((dumplen*2)+dumplen)+3
179#define Asciistart	(dumplen*2)+3
180
181/****************************************************************************************************/
182//
183//		Function:	AppleUSBCDCEEM::USBLogData
184//
185//		Inputs:		Dir - direction
186//				Count - number of bytes
187//				buf - the data
188//
189//		Outputs:
190//
191//		Desc:		Puts the data in the log.
192//
193/****************************************************************************************************/
194
195void AppleUSBCDCEEM::USBLogData(UInt8 Dir, SInt32 Count, char *buf)
196{
197    SInt32	wlen;
198    UInt8	tDir = Dir;
199    SInt32	llen, rlen;
200    SInt16	i, Aspnt, Hxpnt;
201    UInt8	wchr;
202    char	LocBuf[buflen+1];
203
204    switch (tDir)
205    {
206        case kDataIn:
207            Log("AppleUSBCDCEEM: USBLogData - Read Complete, address = %8p, size = %8d\n", (void *)buf, (UInt)Count);
208            break;
209        case kDataOut:
210            Log("AppleUSBCDCEEM: USBLogData - Write, address = %8p, size = %8d\n", (void *)buf, (UInt)Count);
211            break;
212        case kDataOther:
213            Log("AppleUSBCDCEEM: USBLogData - Other, address = %8p, size = %8d\n", (void *)buf, (UInt)Count);
214            break;
215        case kDataNone:
216            tDir = kDataOther;
217            break;
218    }
219
220#if DUMPALL
221    wlen = Count;
222#else
223    if (Count > dumplen)
224    {
225        wlen = dumplen;
226    } else {
227        wlen = Count;
228    }
229#endif
230
231    if (wlen == 0)
232    {
233        Log("AppleUSBCDCEEM: USBLogData - No data, Count=0\n");
234        return;
235    }
236
237    rlen = 0;
238    do
239    {
240        memset(LocBuf, 0x20, buflen);
241
242        if (wlen > dumplen)
243        {
244            llen = dumplen;
245            wlen -= dumplen;
246        } else {
247            llen = wlen;
248            wlen = 0;
249        }
250        Aspnt = Asciistart;
251        Hxpnt = 0;
252        for (i=1; i<=llen; i++)
253        {
254            wchr = buf[i-1];
255            LocBuf[Hxpnt++] = Asciify(wchr >> 4);
256            LocBuf[Hxpnt++] = Asciify(wchr);
257            if ((wchr < 0x20) || (wchr > 0x7F)) 		// Non printable characters
258            {
259                LocBuf[Aspnt++] = 0x2E;				// Replace with a period
260            } else {
261                LocBuf[Aspnt++] = wchr;
262            }
263        }
264        LocBuf[Aspnt] = 0x00;
265
266		Log("%s\n", LocBuf);
267#if USE_IOL
268        IOSleep(Sleep_Time);					// Try and keep the log from overflowing
269#endif
270
271        rlen += llen;
272        buf = &buf[rlen];
273    } while (wlen != 0);
274
275}/* end USBLogData */
276
277/****************************************************************************************************/
278//
279//		Function:	AppleUSBCDCEEM::dumpData
280//
281//		Inputs:		buf - the data
282//				size - number of bytes
283//
284//		Outputs:	None
285//
286//		Desc:		Creates formatted data for the log (cannot be used at interrupt time)
287//
288/****************************************************************************************************/
289
290void AppleUSBCDCEEM::dumpData(char *buf, SInt32 size)
291{
292    SInt32	curr, len, dlen;
293
294    Log("AppleUSBCDCEEM: dumpData - Address = %8p, size = %8d\n", (void *)buf, (UInt)size);
295
296    dlen = 0;
297    len = size;
298
299    for (curr=0; curr<size; curr+=dumplen)
300    {
301        if (len > dumplen)
302        {
303            dlen = dumplen;
304        } else {
305            dlen = len;
306        }
307        Log("%8p ", (void *)&buf[curr]);
308        USBLogData(kDataNone, dlen, &buf[curr]);
309        len -= dlen;
310    }
311
312}/* end dumpData */
313#endif
314
315/****************************************************************************************************/
316//
317//		Method:		AppleUSBCDCEEM::dataReadComplete
318//
319//		Inputs:		obj - me
320//					param - pool index
321//					rc - return code
322//					remaining - what's left
323//
324//		Outputs:
325//
326//		Desc:		BulkIn pipe (Data interface) read completion routine
327//
328/****************************************************************************************************/
329
330void AppleUSBCDCEEM::dataReadComplete(void *obj, void *param, IOReturn rc, UInt32 remaining)
331{
332    AppleUSBCDCEEM	*me = (AppleUSBCDCEEM*)obj;
333    IOReturn		ior;
334	pipeInBuffers	*pipeBuf = (pipeInBuffers *)param;
335//    UInt32			poolIndx = (UInt32)param;
336	UInt16			EEMHeader;
337	UInt16			*EEMHeaderAddress = &EEMHeader;
338	SInt16			actualLen, dataLen, i = 0;
339	bool			done = false;
340
341    XTRACE(me, 0, pipeBuf->indx, "dataReadComplete");
342
343    if (rc == kIOReturnSuccess)
344    {
345		dataLen = me->fMax_Block_Size - remaining;
346        XTRACE(me, 0, dataLen, "dataReadComplete - data length");
347
348		while (!done)
349		{
350			EEMHeaderAddress[0] = pipeBuf->pipeInBuffer[i];
351			EEMHeaderAddress[1] = pipeBuf->pipeInBuffer[i+1];
352
353			if (EEMHeader & bmTypeCommand)
354			{
355
356					// Look at the command
357
358				me->processEEMCommand(EEMHeader, pipeBuf->indx, i+2, &actualLen);
359			} else {
360				actualLen = EEMHeader & frameLenMask;
361				meLogData(kDataIn, actualLen+2, &pipeBuf->pipeInBuffer[i]);
362
363					// Move the incoming bytes up the stack
364
365				me->receivePacket(&pipeBuf->pipeInBuffer[i+2], actualLen);
366			}
367			i += actualLen;
368			if (i >= dataLen)
369			{
370				done = true;
371			}
372		}
373    } else {
374        XTRACE(me, 0, rc, "dataReadComplete - Read completion io err");
375        if (rc != kIOReturnAborted)
376        {
377            rc = me->clearPipeStall(me->fInPipe);
378            if (rc != kIOReturnSuccess)
379            {
380                XTRACE(me, 0, rc, "dataReadComplete - clear stall failed (trying to continue)");
381            }
382        }
383    }
384
385        // Queue the next read, only if not aborted
386
387    if (rc != kIOReturnAborted)
388    {
389        ior = me->fInPipe->Read(pipeBuf->pipeInMDP, &pipeBuf->readCompletionInfo, NULL);
390        if (ior != kIOReturnSuccess)
391        {
392            XTRACE(me, 0, ior, "dataReadComplete - Failed to queue read");
393            pipeBuf->dead = true;
394        }
395    } else {
396        XTRACE(me, 0, 0, "dataReadComplete - Read terminated");
397        pipeBuf->dead = true;
398    }
399
400    return;
401
402}/* end dataReadComplete */
403
404/****************************************************************************************************/
405//
406//		Method:		AppleUSBCDCEEM::dataWriteComplete
407//
408//		Inputs:		obj - me
409//				param - pool index
410//				rc - return code
411//				remaining - what's left
412//
413//		Outputs:
414//
415//		Desc:		BulkOut pipe (Data interface) write completion routine
416//
417/****************************************************************************************************/
418
419void AppleUSBCDCEEM::dataWriteComplete(void *obj, void *param, IOReturn rc, UInt32 remaining)
420{
421    AppleUSBCDCEEM	*me = (AppleUSBCDCEEM *)obj;
422    mbuf_t			m;
423    UInt32			pktLen = 0;
424    UInt32			numbufs = 0;
425	pipeOutBuffers	*pipeBuf = (pipeOutBuffers *)param;
426//    UInt32		poolIndx = (UInt32)param;
427
428	XTRACE(me, rc, pipeBuf->indx, "dataWriteComplete");
429
430    if (me->fBufferPoolLock)
431    {
432        IOLockLock(me->fBufferPoolLock);
433    }
434
435    if (rc == kIOReturnSuccess)						// If operation returned ok
436    {
437        if (pipeBuf->m != NULL)						// Null means zero length write or command
438        {
439            m = pipeBuf->m;
440            while (m)
441			{
442				pktLen += mbuf_len(m);
443				numbufs++;
444				m = mbuf_next(m);
445			}
446            me->freePacket(pipeBuf->m);				// Free the mbuf
447            pipeBuf->m = NULL;
448
449            if ((pktLen % me->fOutPacketSize) == 0)			// If it was a multiple of max packet size then we need to do a zero length write
450            {
451                XTRACE(me, rc, pktLen, "dataWriteComplete - writing zero length packet");
452                pipeBuf->pipeOutMDP->setLength(0);
453                pipeBuf->writeCompletionInfo.parameter = (void *)pipeBuf;
454                me->fOutPipe->Write(pipeBuf->pipeOutMDP, &pipeBuf->writeCompletionInfo);
455            } else {
456                pipeBuf->avail = true;
457                if (me->fTxStalled)
458                {
459                    me->fTxStalled = false;
460                    me->fTransmitQueue->service(IOBasicOutputQueue::kServiceAsync);
461                }
462            }
463        } else {
464            pipeBuf->avail = true;					// Make the buffer available again
465            if (me->fTxStalled)
466            {
467                me->fTxStalled = false;
468                me->fTransmitQueue->service(IOBasicOutputQueue::kServiceAsync);
469            }
470        }
471    } else {
472        XTRACE(me, rc, pipeBuf->indx, "dataWriteComplete - IO err");
473
474        if (pipeBuf->m != NULL)
475        {
476            me->freePacket(pipeBuf->m);				// Free the mbuf anyway
477            pipeBuf->m = NULL;
478            pipeBuf->avail = true;
479            if (me->fTxStalled)
480            {
481                me->fTxStalled = false;
482                me->fTransmitQueue->service(IOBasicOutputQueue::kServiceAsync);
483            }
484        }
485        if (rc != kIOReturnAborted)
486        {
487            rc = me->clearPipeStall(me->fOutPipe);
488            if (rc != kIOReturnSuccess)
489            {
490                XTRACE(me, 0, rc, "dataWriteComplete - clear stall failed (trying to continue)");
491            }
492        }
493    }
494
495    if (me->fBufferPoolLock)
496    {
497        IOLockUnlock(me->fBufferPoolLock);
498    }
499
500    return;
501
502}/* end dataWriteComplete */
503
504/****************************************************************************************************/
505//
506//		Method:		AppleUSBCDCEEM::probe
507//
508//		Inputs:		provider - my provider
509//
510//		Outputs:	IOService - from super::probe, score - probe score
511//
512//		Desc:		Modify the probe score if necessary (we don't  at the moment)
513//
514/****************************************************************************************************/
515
516IOService* AppleUSBCDCEEM::probe( IOService *provider, SInt32 *score )
517{
518    IOService   *res;
519
520		// If our IOUSBInterface has a "do not match" property, it means that we should not match and need
521		// to bail.  See rdar://3716623
522
523    OSBoolean *boolObj = OSDynamicCast(OSBoolean, provider->getProperty("kDoNotClassMatchThisInterface"));
524    if (boolObj && boolObj->isTrue())
525    {
526        XTRACE(this, 0, 0, "probe - provider doesn't want us to match");
527        return NULL;
528    }
529
530    res = super::probe(provider, score);
531
532    return res;
533
534}/* end probe */
535
536/****************************************************************************************************/
537//
538//		Method:		AppleUSBCDCEEM::init
539//
540//		Inputs:		properties - data (keys and values) used to match
541//
542//		Outputs:	Return code - true (init successful), false (init failed)
543//
544//		Desc:		Initialize the driver.
545//
546/****************************************************************************************************/
547
548bool AppleUSBCDCEEM::init(OSDictionary *properties)
549{
550    UInt32	i;
551
552    XTRACE(this, 0, 0, "init");
553
554    if (super::init(properties) == false)
555    {
556        XTRACE(this, 0, 0, "init - initialize super failed");
557        return false;
558    }
559
560    for (i=0; i<kMaxOutBufPool; i++)
561    {
562        fPipeOutBuff[i].pipeOutMDP = NULL;
563        fPipeOutBuff[i].pipeOutBuffer = NULL;
564        fPipeOutBuff[i].m = NULL;
565        fPipeOutBuff[i].avail = false;
566        fPipeOutBuff[i].writeCompletionInfo.target = NULL;
567        fPipeOutBuff[i].writeCompletionInfo.action = NULL;
568        fPipeOutBuff[i].writeCompletionInfo.parameter = NULL;
569		fPipeOutBuff[i].indx = i;
570    }
571    fOutPoolIndex = 0;
572
573    for (i=0; i<kMaxInBufPool; i++)
574    {
575        fPipeInBuff[i].pipeInMDP = NULL;
576        fPipeInBuff[i].pipeInBuffer = NULL;
577        fPipeInBuff[i].dead = false;
578        fPipeInBuff[i].readCompletionInfo.target = NULL;
579        fPipeInBuff[i].readCompletionInfo.action = NULL;
580        fPipeInBuff[i].readCompletionInfo.parameter = NULL;
581		fPipeInBuff[i].indx = i;
582    }
583
584    return true;
585
586}/* end init*/
587
588/****************************************************************************************************/
589//
590//		Method:		AppleUSBCDCEEM::start
591//
592//		Inputs:		provider - my provider
593//
594//		Outputs:	Return code - true (it's me), false (sorry it probably was me, but I can't configure it)
595//
596//		Desc:		This is called once it has beed determined I'm probably the best
597//				driver for this device.
598//
599/****************************************************************************************************/
600
601bool AppleUSBCDCEEM::start(IOService *provider)
602{
603    OSNumber		*bufNumber = NULL;
604    UInt16		bufValue = 0;
605
606    XTRACE(this, 0, 0, "start");
607
608	return false;				// Don't load for EEM hardware at this time
609
610    if(!super::start(provider))
611    {
612        ALERT(0, 0, "start - start super failed");
613        return false;
614    }
615
616	// Get my USB provider - the interface
617
618    fDataInterface = OSDynamicCast(IOUSBInterface, provider);
619    if(!fDataInterface)
620    {
621        ALERT(0, 0, "start - provider invalid");
622        return false;
623    }
624
625    fDataInterfaceNumber = fDataInterface->GetInterfaceNumber();
626
627    if (findCDCDriverEED(fDataInterface->GetDevice(), this, fDataInterfaceNumber) != kIOReturnSuccess)
628    {
629        XTRACE(this, 0, 0, "start - Find CDC driver failed");
630		super::stop(provider);
631        return false;
632    }
633
634    fBufferPoolLock = IOLockAlloc();
635    if (!fBufferPoolLock)
636    {
637        ALERT(0, 0, "start - Buffer pool lock allocate failed");
638        return false;
639    }
640
641        // get workloop
642
643    fWorkLoop = getWorkLoop();
644    if (!fWorkLoop)
645    {
646        ALERT(0, 0, "start - getWorkLoop failed");
647        return false;
648    }
649
650    if (!configureData())
651    {
652        ALERT(0, 0, "start - configureData failed");
653        return false;
654    }
655
656		// Check for an input buffer pool override first
657
658	fInBufPool = 0;
659	fOutBufPool = 0;
660
661	bufNumber = (OSNumber *)provider->getProperty(inputTag);
662    if (bufNumber)
663    {
664		bufValue = bufNumber->unsigned16BitValue();
665		XTRACE(this, 0, bufValue, "start - Number of input buffers override value");
666        if (bufValue <= kMaxInBufPool)
667        {
668            fInBufPool = bufValue;
669        } else {
670            fInBufPool = kMaxInBufPool;
671        }
672	} else {
673		fInBufPool = 0;
674	}
675
676		// Now set up the real input buffer pool values (only if not overridden)
677
678	if (fInBufPool == 0)
679	{
680		bufNumber = NULL;
681		bufNumber = (OSNumber *)getProperty(inputTag);
682		if (bufNumber)
683		{
684			bufValue = bufNumber->unsigned16BitValue();
685			XTRACE(this, 0, bufValue, "start - Number of input buffers requested");
686			if (bufValue <= kMaxInBufPool)
687			{
688				fInBufPool = bufValue;
689			} else {
690				fInBufPool = kMaxInBufPool;
691			}
692		} else {
693			fInBufPool = kInBufPool;
694		}
695    }
696
697		// Check for an output buffer pool override
698
699	bufNumber = NULL;
700	bufNumber = (OSNumber *)provider->getProperty(outputTag);
701    if (bufNumber)
702    {
703		bufValue = bufNumber->unsigned16BitValue();
704		XTRACE(this, 0, bufValue, "start - Number of output buffers override value");
705        if (bufValue <= kMaxInBufPool)
706        {
707            fOutBufPool = bufValue;
708        } else {
709            fOutBufPool = kMaxOutBufPool;
710        }
711	} else {
712		fOutBufPool = 0;
713	}
714
715        // Now set up the real output buffer pool values (only if not overridden)
716
717	if (fOutBufPool == 0)
718	{
719		bufNumber = NULL;
720		bufNumber = (OSNumber *)getProperty(outputTag);
721		if (bufNumber)
722		{
723			bufValue = bufNumber->unsigned16BitValue();
724			XTRACE(this, 0, bufValue, "start - Number of output buffers requested");
725			if (bufValue <= kMaxOutBufPool)
726			{
727				fOutBufPool = bufValue;
728			} else {
729				fOutBufPool = kMaxOutBufPool;
730			}
731		} else {
732			fOutBufPool = kOutBufPool;
733		}
734	}
735
736    XTRACE(this, fInBufPool, fOutBufPool, "start - Buffer pools (input, output)");
737
738    if (!createNetworkInterface())
739    {
740        ALERT(0, 0, "start - createNetworkInterface failed");
741        return false;
742    }
743
744         // Looks like we're ok
745
746    fDataInterface->retain();
747    fWorkLoop->retain();
748    fTransmitQueue->retain();
749
750        // Ready to service interface requests
751
752    fNetworkInterface->registerService();
753
754    XTRACE(this, 0, 0, "start - successful");
755	Log(DEBUG_NAME ": Version number - %s, Input buffers %d, Output buffers %d\n", VersionNumber, fInBufPool, fOutBufPool);
756
757    return true;
758
759}/* end start */
760
761/****************************************************************************************************/
762//
763//		Method:		AppleUSBCDCEEM::stop
764//
765//		Inputs:		provider - my provider
766//
767//		Outputs:
768//
769//		Desc:		Stops the driver
770//
771/****************************************************************************************************/
772
773void AppleUSBCDCEEM::stop(IOService *provider)
774{
775
776    XTRACE(this, 0, 0, "stop");
777
778        // Release all resources
779
780    releaseResources();
781
782    if (fDataInterface)
783    {
784        fDataInterface->close(this);
785        fDataInterface->release();
786        fDataInterface = NULL;
787    }
788
789    if (fNetworkInterface)
790    {
791        fNetworkInterface->release();
792        fNetworkInterface = NULL;
793    }
794
795    if (fMediumDict)
796    {
797        fMediumDict->release();
798        fMediumDict = NULL;
799    }
800
801    if (fBufferPoolLock)
802    {
803        IOLockFree(fBufferPoolLock);
804        fBufferPoolLock = NULL;
805    }
806
807    if (fWorkLoop)
808    {
809        fWorkLoop->release();
810        fWorkLoop = NULL;
811    }
812
813    if (fTransmitQueue)
814    {
815        fTransmitQueue->release();
816        fTransmitQueue = NULL;
817    }
818
819    super::stop(provider);
820
821    return;
822
823}/* end stop */
824
825/****************************************************************************************************/
826//
827//		Method:		AppleUSBCDCEEM::configureData
828//
829//		Inputs:
830//
831//		Outputs:	return code - true (configure was successful), false (it failed)
832//
833//		Desc:		Finishes up the rest of the configuration
834//
835/****************************************************************************************************/
836
837bool AppleUSBCDCEEM::configureData()
838{
839    IOUSBFindInterfaceRequest		req;
840    const IOUSBInterfaceDescriptor	*altInterfaceDesc;
841    IOReturn				ior = kIOReturnSuccess;
842    UInt16				numends = 0;
843    UInt16				alt;
844
845    XTRACE(this, 0, 0, "configureData.");
846
847    if (!fDataInterface)
848    {
849        XTRACE(this, 0, 0, "configureData - Data interface is NULL");
850        return false;
851    }
852
853    if (!fDataInterface->open(this))
854    {
855        XTRACE(this, 0, 0, "configureData - open data interface failed");
856        fDataInterface->release();
857        fDataInterface = NULL;
858        return false;
859    }
860
861        // Check we have the correct interface (there maybe an alternate)
862
863    numends = fDataInterface->GetNumEndpoints();
864    if (numends < 2)
865    {
866        req.bInterfaceClass = kUSBDataClass;
867        req.bInterfaceSubClass = 0;
868        req.bInterfaceProtocol = 0;
869        req.bAlternateSetting = kIOUSBFindInterfaceDontCare;
870        altInterfaceDesc = fDataInterface->FindNextAltInterface(NULL, &req);
871        if (!altInterfaceDesc)
872        {
873            XTRACE(this, 0, 0, "configureData - FindNextAltInterface failed");
874            return false;
875        }
876        while (altInterfaceDesc)
877        {
878            numends = altInterfaceDesc->bNumEndpoints;
879            if (numends > 1)
880            {
881                alt = altInterfaceDesc->bAlternateSetting;
882                XTRACE(this, numends, alt, "configureData - Data Class interface (alternate) found");
883                ior = fDataInterface->SetAlternateInterface(this, alt);
884                if (ior == kIOReturnSuccess)
885                {
886                    XTRACE(this, 0, 0, "configureData - Alternate set");
887                    break;
888                } else {
889                    XTRACE(this, 0, 0, "configureData - SetAlternateInterface failed");
890                    return false;
891                }
892            } else {
893                XTRACE(this, 0, 0, "configureData - No endpoints this alternate");
894            }
895            altInterfaceDesc = fDataInterface->FindNextAltInterface(altInterfaceDesc, &req);
896        }
897    }
898
899    if (numends < 2)
900    {
901        XTRACE(this, 0, 0, "configureData - Could not find the correct interface");
902        return false;
903    }
904
905    return true;
906
907}/* end configureData */
908
909/****************************************************************************************************/
910//
911//		Method:		AppleUSBCDCEEM::createNetworkInterface
912//
913//		Inputs:
914//
915//		Outputs:	return Code - true (created and initialilzed ok), false (it failed)
916//
917//		Desc:		Creates and initializes the network interface
918//
919/****************************************************************************************************/
920
921bool AppleUSBCDCEEM::createNetworkInterface()
922{
923
924    XTRACE(this, 0, 0, "createNetworkInterface");
925
926            // Allocate memory for transmit queue
927
928    fTransmitQueue = (IOGatedOutputQueue *)getOutputQueue();
929    if (!fTransmitQueue)
930    {
931        ALERT(0, 0, "createNetworkInterface - Output queue initialization failed");
932        return false;
933    }
934
935        // Attach an IOEthernetInterface client
936
937    XTRACE(this, 0, 0, "createNetworkInterface - attaching and registering interface");
938
939    if (!attachInterface((IONetworkInterface **)&fNetworkInterface, false))
940    {
941        ALERT(0, 0, "createNetworkInterface - attachInterface failed");
942        return false;
943    }
944
945    XTRACE(this, 0, 0, "createNetworkInterface - Exiting, successful");
946
947    return true;
948
949}/* end createNetworkInterface */
950
951/****************************************************************************************************/
952//
953//		Method:		AppleUSBCDCEEM::enable
954//
955//		Inputs:		netif - the interface being enabled
956//
957//		Outputs:	Return code - kIOReturnSuccess or kIOReturnIOError
958//
959//		Desc:		Called by IOEthernetInterface client to enable the controller.
960//				This method is always called while running on the default workloop
961//				thread
962//
963/****************************************************************************************************/
964
965IOReturn AppleUSBCDCEEM::enable(IONetworkInterface *netif)
966{
967    IONetworkMedium	*medium;
968    IOMediumType    	mediumType = kIOMediumEthernet10BaseT | kIOMediumOptionFullDuplex;
969
970    XTRACE(this, 0, 0, "enable");
971
972    IOSleep(5);				// Just in case (to let start finish - on another thread)
973
974        // If an interface client has previously enabled us,
975        // and we know there can only be one interface client
976        // for this driver, then simply return success.
977
978    if (fNetifEnabled)
979    {
980        XTRACE(this, 0, 0, "enable - already enabled");
981        return kIOReturnSuccess;
982    }
983
984    if (!fReady)
985    {
986        if (!wakeUp())
987        {
988            XTRACE(this, 0, fReady, "enable - wakeUp failed");
989            return kIOReturnIOError;
990        }
991    }
992
993        // Mark the controller as enabled by the interface.
994
995    fNetifEnabled = true;
996
997        // Assume an active link (leave this in for now - until we know better)
998        // Should probably use the values returned in the Network Connection notification
999        // that is if we have an interrupt pipe, otherwise default to these
1000
1001    fLinkStatus = 1;
1002
1003    medium = IONetworkMedium::getMediumWithType(fMediumDict, mediumType);
1004    XTRACE(this, mediumType, 0, "enable - medium type");
1005    setLinkStatus(kIONetworkLinkActive | kIONetworkLinkValid, medium, 10 * 1000000);
1006    XTRACE(this, 0, 0, "enable - LinkStatus set");
1007
1008        // Start our IOOutputQueue object.
1009
1010    fTransmitQueue->setCapacity(TRANSMIT_QUEUE_SIZE);
1011    XTRACE(this, 0, TRANSMIT_QUEUE_SIZE, "enable - capicity set");
1012    fTransmitQueue->start();
1013    XTRACE(this, 0, 0, "enable - transmit queue started");
1014
1015    return kIOReturnSuccess;
1016
1017}/* end enable */
1018
1019/****************************************************************************************************/
1020//
1021//		Method:		AppleUSBCDCEEM::disable
1022//
1023//		Inputs:		netif - the interface being disabled
1024//
1025//		Outputs:	Return code - kIOReturnSuccess
1026//
1027//		Desc:		Called by IOEthernetInterface client to disable the controller.
1028//				This method is always called while running on the default workloop
1029//				thread
1030//
1031/****************************************************************************************************/
1032
1033IOReturn AppleUSBCDCEEM::disable(IONetworkInterface *netif)
1034{
1035
1036    XTRACE(this, 0, 0, "disable");
1037
1038        // Disable our IOOutputQueue object. This will prevent the
1039        // outputPacket() method from being called
1040
1041    fTransmitQueue->stop();
1042
1043        // Flush all packets currently in the output queue
1044
1045    fTransmitQueue->setCapacity(0);
1046    fTransmitQueue->flush();
1047
1048    putToSleep();
1049
1050    fNetifEnabled = false;
1051    fReady = false;
1052
1053    return kIOReturnSuccess;
1054
1055}/* end disable */
1056
1057/****************************************************************************************************/
1058//
1059//		Method:		AppleUSBCDCEEM::setWakeOnMagicPacket
1060//
1061//		Inputs:		active - true(wake), false(don't)
1062//
1063//		Outputs:	Return code - kIOReturnSuccess
1064//
1065//		Desc:		Set for wake on magic packet
1066//
1067/****************************************************************************************************/
1068
1069IOReturn AppleUSBCDCEEM::setWakeOnMagicPacket(bool active)
1070{
1071    IOUSBDevRequest	devreq;
1072    IOReturn		ior = kIOReturnSuccess;
1073
1074    XTRACE(this, 0, active, "setWakeOnMagicPacket");
1075
1076    fWOL = active;
1077
1078    if (fConfigAttributes & kUSBAtrRemoteWakeup)
1079    {
1080
1081            // Set/Clear the Device Remote Wake feature depending upon the active flag
1082
1083		devreq.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBStandard, kUSBDevice);
1084		if (active)
1085		{
1086			devreq.bRequest = kUSBRqSetFeature;
1087		} else {
1088			devreq.bRequest = kUSBRqClearFeature;
1089		}
1090		devreq.wValue = kUSBFeatureDeviceRemoteWakeup;
1091		devreq.wIndex = 0;
1092		devreq.wLength = 0;
1093		devreq.pData = 0;
1094
1095		ior = fDataInterface->GetDevice()->DeviceRequest(&devreq);
1096		if (ior == kIOReturnSuccess)
1097		{
1098			XTRACE(this, 0, ior, "setWakeOnMagicPacket - Set/Clear remote wake up feature successful");
1099		} else {
1100			XTRACE(this, 0, ior, "setWakeOnMagicPacket - Set/Clear remote wake up feature failed");
1101		}
1102    } else {
1103        XTRACE(this, 0, 0, "setWakeOnMagicPacket - Remote wake up not supported");
1104    }
1105
1106
1107    return kIOReturnSuccess;
1108
1109}/* end setWakeOnMagicPacket */
1110
1111/****************************************************************************************************/
1112//
1113//		Method:		AppleUSBCDCEEM::getPacketFilters
1114//
1115//		Inputs:		group - the filter group
1116//
1117//		Outputs:	Return code - kIOReturnSuccess and others
1118//				filters - the capability
1119//
1120//		Desc:		Set the filter capability for the driver
1121//
1122/****************************************************************************************************/
1123
1124IOReturn AppleUSBCDCEEM::getPacketFilters(const OSSymbol *group, UInt32 *filters) const
1125{
1126    IOReturn	rtn = kIOReturnSuccess;
1127
1128    XTRACE(this, 0, 0, "getPacketFilters");
1129
1130    if (group == gIOEthernetWakeOnLANFilterGroup)
1131    {
1132        if (fConfigAttributes & kUSBAtrRemoteWakeup)
1133        {
1134            *filters = kIOEthernetWakeOnMagicPacket;
1135        } else {
1136            *filters = 0;
1137        }
1138    } else {
1139        if (group == gIONetworkFilterGroup)
1140        {
1141            *filters = kIOPacketFilterUnicast | kIOPacketFilterBroadcast;
1142        } else {
1143            rtn = super::getPacketFilters(group, filters);
1144        }
1145    }
1146
1147    if (rtn != kIOReturnSuccess)
1148    {
1149        XTRACE(this, 0, rtn, "getPacketFilters - failed");
1150    }
1151
1152    return rtn;
1153
1154}/* end getPacketFilters */
1155
1156/****************************************************************************************************/
1157//
1158//		Method:		AppleUSBCDCEEM::selectMedium
1159//
1160//		Inputs:
1161//
1162//		Outputs:
1163//
1164//		Desc:		Lets us know if someone is playing with ifconfig
1165//
1166/****************************************************************************************************/
1167
1168IOReturn AppleUSBCDCEEM::selectMedium(const IONetworkMedium *medium)
1169{
1170
1171    XTRACE(this, 0, 0, "selectMedium");
1172
1173    setSelectedMedium(medium);
1174
1175    return kIOReturnSuccess;
1176
1177}/* end selectMedium */
1178
1179/****************************************************************************************************/
1180//
1181//		Method:		AppleUSBCDCEEM::getHardwareAddress
1182//
1183//		Inputs:
1184//
1185//		Outputs:	Return code - kIOReturnSuccess or kIOReturnError
1186//				ea - the address
1187//
1188//		Desc:		Make up an ethernet address for now
1189//					***** THIS IS TEMPORARY AND MUST BE CHANGED *****
1190//
1191/****************************************************************************************************/
1192
1193IOReturn AppleUSBCDCEEM::getHardwareAddress(IOEthernetAddress *ea)
1194{
1195    UInt32      i;
1196	OSNumber	*location;
1197    UInt32		locVal;
1198	UInt8		*rlocVal;
1199
1200    XTRACE(this, 0, 0, "getHardwareAddress");
1201
1202	location = (OSNumber *)fDataInterface->GetDevice()->getProperty(kUSBDevicePropertyLocationID);
1203	if (location)
1204	{
1205		locVal = location->unsigned32BitValue();
1206		rlocVal = (UInt8*)&locVal;
1207		ea->bytes[0] = 0x00;
1208		ea->bytes[1] = 0x03;
1209		for (i=0; i<4; i++)
1210		{
1211			ea->bytes[i+2] = rlocVal[i];
1212		}
1213	} else {
1214		XTRACE(this, 0, 0, "getHardwareAddress - Get location failed");
1215		return kIOReturnError;
1216	}
1217
1218    return kIOReturnSuccess;
1219
1220}/* end getHardwareAddress */
1221
1222/****************************************************************************************************/
1223//
1224//		Method:		AppleUSBCDCEEM::newVendorString
1225//
1226//		Inputs:
1227//
1228//		Outputs:	Return code - the vendor string
1229//
1230//		Desc:		Identifies the hardware vendor
1231//
1232/****************************************************************************************************/
1233
1234const OSString* AppleUSBCDCEEM::newVendorString() const
1235{
1236
1237    XTRACE(this, 0, 0, "newVendorString");
1238
1239    return OSString::withCString((const char *)defaultName);		// Maybe we should use the descriptors
1240
1241}/* end newVendorString */
1242
1243/****************************************************************************************************/
1244//
1245//		Method:		AppleUSBCDCEEM::newModelString
1246//
1247//		Inputs:
1248//
1249//		Outputs:	Return code - the model string
1250//
1251//		Desc:		Identifies the hardware model
1252//
1253/****************************************************************************************************/
1254
1255const OSString* AppleUSBCDCEEM::newModelString() const
1256{
1257
1258    XTRACE(this, 0, 0, "newModelString");
1259
1260    return OSString::withCString("USB");		// Maybe we should use the descriptors
1261
1262}/* end newModelString */
1263
1264/****************************************************************************************************/
1265//
1266//		Method:		AppleUSBCDCEEM::newRevisionString
1267//
1268//		Inputs:
1269//
1270//		Outputs:	Return code - the revision string
1271//
1272//		Desc:		Identifies the hardware revision
1273//
1274/****************************************************************************************************/
1275
1276const OSString* AppleUSBCDCEEM::newRevisionString() const
1277{
1278
1279    XTRACE(this, 0, 0, "newRevisionString");
1280
1281    return OSString::withCString("");
1282
1283}/* end newRevisionString */
1284
1285/****************************************************************************************************/
1286//
1287//		Method:		AppleUSBCDCEEM::setMulticastMode
1288//
1289//		Inputs:		active - true (set it), false (don't)
1290//
1291//		Outputs:	Return code - kIOReturnSuccess
1292//
1293//		Desc:		Sets multicast mode (not supported in this driver)
1294//
1295/****************************************************************************************************/
1296
1297IOReturn AppleUSBCDCEEM::setMulticastMode(bool active)
1298{
1299
1300    XTRACE(this, 0, active, "setMulticastMode");
1301
1302    return kIOReturnIOError;
1303
1304}/* end setMulticastMode */
1305
1306/****************************************************************************************************/
1307//
1308//		Method:		AppleUSBCDCEEM::setMulticastList
1309//
1310//		Inputs:		addrs - list of addresses
1311//				count - number in the list
1312//
1313//		Outputs:	Return code - kIOReturnSuccess or kIOReturnIOError
1314//
1315//		Desc:		Sets multicast list (not supported in this driver
1316//
1317/****************************************************************************************************/
1318
1319IOReturn AppleUSBCDCEEM::setMulticastList(IOEthernetAddress *addrs, UInt32 count)
1320{
1321//    bool	uStat;
1322
1323    XTRACE(this, 0, count, "setMulticastList");
1324
1325    return kIOReturnIOError;
1326
1327}/* end setMulticastList */
1328
1329/****************************************************************************************************/
1330//
1331//		Method:		AppleUSBCDCEEM::setPromiscuousMode
1332//
1333//		Inputs:		active - true (set it), false (don't)
1334//
1335//		Outputs:	Return code - kIOReturnSuccess
1336//
1337//		Desc:		Sets promiscuous mode (not supported by this driver)
1338//
1339/****************************************************************************************************/
1340
1341IOReturn AppleUSBCDCEEM::setPromiscuousMode(bool active)
1342{
1343
1344    XTRACE(this, 0, active, "setPromiscuousMode");
1345
1346    return kIOReturnIOError;
1347
1348}/* end setPromiscuousMode */
1349
1350/****************************************************************************************************/
1351//
1352//		Method:		AppleUSBCDCEEM::createOutputQueue
1353//
1354//		Inputs:
1355//
1356//		Outputs:	Return code - the output queue
1357//
1358//		Desc:		Creates the output queue
1359//
1360/****************************************************************************************************/
1361
1362IOOutputQueue* AppleUSBCDCEEM::createOutputQueue()
1363{
1364
1365    XTRACE(this, 0, 0, "createOutputQueue");
1366
1367    return IOBasicOutputQueue::withTarget(this, TRANSMIT_QUEUE_SIZE);
1368
1369}/* end createOutputQueue */
1370
1371/****************************************************************************************************/
1372//
1373//		Method:		AppleUSBCDCEEM::outputPacket
1374//
1375//		Inputs:		mbuf - the packet
1376//				param - optional parameter
1377//
1378//		Outputs:	Return code - kIOReturnOutputSuccess or kIOReturnOutputStall
1379//
1380//		Desc:		Packet transmission. The BSD mbuf needs to be formatted correctly
1381//				and transmitted
1382//
1383/****************************************************************************************************/
1384
1385UInt32 AppleUSBCDCEEM::outputPacket(mbuf_t pkt, void *param)
1386{
1387    UInt32	ior = kIOReturnSuccess;
1388
1389    XTRACE(this, 0, 0, "outputPacket");
1390
1391    if (!fLinkStatus)
1392    {
1393        XTRACE(this, 0, fLinkStatus, "outputPacket - link is down");
1394		fpNetStats->outputErrors++;
1395        freePacket(pkt);
1396        return kIOReturnOutputDropped;
1397    }
1398
1399    ior = USBTransmitPacket(pkt);
1400    if (ior != kIOReturnOutputStall)
1401    {
1402        freePacket(pkt);
1403    }
1404
1405    XTRACE(this, 0, ior, "outputPacket - Exit");
1406
1407    return ior;
1408
1409}/* end outputPacket */
1410
1411/****************************************************************************************************/
1412//
1413//		Method:		AppleUSBCDCEEM::configureInterface
1414//
1415//		Inputs:		netif - the interface being configured
1416//
1417//		Outputs:	Return code - true (configured ok), false (not)
1418//
1419//		Desc:		Finish the network interface configuration
1420//
1421/****************************************************************************************************/
1422
1423bool AppleUSBCDCEEM::configureInterface(IONetworkInterface *netif)
1424{
1425    IONetworkData	*nd;
1426
1427    XTRACE(this, 0, 0, "configureInterface");
1428
1429    if (super::configureInterface(netif) == false)
1430    {
1431        ALERT(0, 0, "configureInterface - super failed");
1432        return false;
1433    }
1434
1435        // Get a pointer to the statistics structure in the interface
1436
1437    nd = netif->getNetworkData(kIONetworkStatsKey);
1438    if (!nd || !(fpNetStats = (IONetworkStats *)nd->getBuffer()))
1439    {
1440        ALERT(0, 0, "configureInterface - Invalid network statistics");
1441        return false;
1442    }
1443
1444        // Get the Ethernet statistics structure
1445
1446    nd = netif->getParameter(kIOEthernetStatsKey);
1447    if (!nd || !(fpEtherStats = (IOEthernetStats*)nd->getBuffer()))
1448    {
1449        ALERT(0, 0, "configureInterface - Invalid ethernet statistics\n");
1450        return false;
1451    }
1452
1453    return true;
1454
1455}/* end configureInterface */
1456
1457/****************************************************************************************************/
1458//
1459//		Method:		AppleUSBCDCEEM::wakeUp
1460//
1461//		Inputs:
1462//
1463//		Outputs:	Return Code - true(we're awake), false(failed)
1464//
1465//		Desc:		Resumes the device it it was suspended and then gets all the data
1466//				structures sorted out and all the pipes ready.
1467//
1468/****************************************************************************************************/
1469
1470bool AppleUSBCDCEEM::wakeUp()
1471{
1472    IOReturn 	rtn = kIOReturnSuccess;
1473    UInt32	i;
1474    bool	readOK = false;
1475
1476    XTRACE(this, 0, 0, "wakeUp");
1477
1478    fReady = false;
1479
1480    setLinkStatus(0, 0);				// Initialize the link state
1481
1482    if (!allocateResources())
1483    {
1484        ALERT(0, 0, "wakeUp - allocateResources failed");
1485    	return false;
1486    }
1487
1488        // Kick off the data-in bulk pipe reads
1489
1490    for (i=0; i<fInBufPool; i++)
1491    {
1492        if (fPipeInBuff[i].pipeInMDP)
1493        {
1494            fPipeInBuff[i].readCompletionInfo.parameter = (void *)&fPipeInBuff[i];
1495            rtn = fInPipe->Read(fPipeInBuff[i].pipeInMDP, &fPipeInBuff[i].readCompletionInfo, NULL);
1496            if (rtn == kIOReturnSuccess)
1497            {
1498                readOK = true;
1499            } else {
1500                XTRACE(this, i, rtn, "wakeUp - Read failed");
1501            }
1502        }
1503    }
1504
1505    if (!readOK)
1506    {
1507
1508    	// We failed for some reason
1509
1510        ALERT(0, 0, "wakeUp - Starting the input pipe read(s) failed");
1511        return false;
1512    } else {
1513        if (!fMediumDict)
1514        {
1515            if (!createMediumTables())
1516            {
1517                ALERT(0, 0, "wakeUp - createMediumTables failed");
1518                return false;
1519            }
1520        }
1521
1522        fReady = true;
1523    }
1524
1525    return true;
1526
1527}/* end wakeUp */
1528
1529/****************************************************************************************************/
1530//
1531//		Method:		AppleUSBCDCEEM::putToSleep
1532//
1533//		Inputs:
1534//
1535//		Outputs:	Return Code - true(we're asleep), false(failed)
1536//
1537//		Desc:		Do clean up and suspend the device.
1538//
1539/****************************************************************************************************/
1540
1541void AppleUSBCDCEEM::putToSleep()
1542{
1543
1544    XTRACE(this, 0, 0, "putToSleep");
1545
1546    fReady = false;
1547
1548    setLinkStatus(0, 0);
1549
1550}/* end putToSleep */
1551
1552/****************************************************************************************************/
1553//
1554//		Method:		AppleUSBCDCEEM::createMediumTables
1555//
1556//		Inputs:
1557//
1558//		Outputs:	Return code - true (tables created), false (not created)
1559//
1560//		Desc:		Creates the medium tables
1561//
1562/****************************************************************************************************/
1563
1564bool AppleUSBCDCEEM::createMediumTables()
1565{
1566    IONetworkMedium	*medium;
1567    UInt64		maxSpeed;
1568    UInt32		i;
1569
1570    XTRACE(this, 0, 0, "createMediumTables");
1571
1572    maxSpeed = 100;
1573    fMediumDict = OSDictionary::withCapacity(sizeof(mediumTable) / sizeof(mediumTable[0]));
1574    if (fMediumDict == 0)
1575    {
1576        XTRACE(this, 0, 0, "createMediumTables - create dict. failed");
1577        return false;
1578    }
1579
1580    for (i = 0; i < sizeof(mediumTable) / sizeof(mediumTable[0]); i++)
1581    {
1582        medium = IONetworkMedium::medium(mediumTable[i].type, mediumTable[i].speed);
1583        if (medium && (medium->getSpeed() <= maxSpeed))
1584        {
1585            IONetworkMedium::addMedium(fMediumDict, medium);
1586            medium->release();
1587        }
1588    }
1589
1590    if (publishMediumDictionary(fMediumDict) != true)
1591    {
1592        XTRACE(this, 0, 0, "createMediumTables - publish dict. failed");
1593        return false;
1594    }
1595
1596    medium = IONetworkMedium::getMediumWithType(fMediumDict, kIOMediumEthernetAuto);
1597    setCurrentMedium(medium);
1598
1599    return true;
1600
1601}/* end createMediumTables */
1602
1603/****************************************************************************************************/
1604//
1605//		Method:		AppleUSBCDCEEM::allocateResources
1606//
1607//		Inputs:
1608//
1609//		Outputs:	return code - true (allocate was successful), false (it failed)
1610//
1611//		Desc:		Gets all the endpoints open and buffers allocated etc.
1612//
1613/****************************************************************************************************/
1614
1615bool AppleUSBCDCEEM::allocateResources()
1616{
1617    IOUSBFindEndpointRequest		epReq;
1618    UInt32				i;
1619
1620    XTRACE(this, 0, 0, "allocateResources.");
1621
1622        // Open all the end points
1623
1624    epReq.type = kUSBBulk;
1625    epReq.direction = kUSBIn;
1626    epReq.maxPacketSize	= 0;
1627    epReq.interval = 0;
1628    fInPipe = fDataInterface->FindNextPipe(0, &epReq);
1629    if (!fInPipe)
1630    {
1631        XTRACE(this, 0, 0, "allocateResources - no bulk input pipe.");
1632        return false;
1633    }
1634    XTRACE(this, epReq.maxPacketSize << 16 |epReq.interval, 0, "allocateResources - bulk input pipe.");
1635
1636    epReq.direction = kUSBOut;
1637    fOutPipe = fDataInterface->FindNextPipe(0, &epReq);
1638    if (!fOutPipe)
1639    {
1640        XTRACE(this, 0, 0, "allocateResources - no bulk output pipe.");
1641        return false;
1642    }
1643    fOutPacketSize = epReq.maxPacketSize;
1644    XTRACE(this, epReq.maxPacketSize << 16 |epReq.interval, 0, "allocateResources - bulk output pipe.");
1645
1646        // Allocate Memory Descriptor Pointer with memory for the data-in bulk pipe
1647
1648    for (i=0; i<fInBufPool; i++)
1649    {
1650//		fPipeInBuff[i].pipeInMDP = IOBufferMemoryDescriptor::withCapacity(fMax_Block_Size, kIODirectionIn);
1651        fPipeInBuff[i].pipeInMDP = IOBufferMemoryDescriptor::withOptions(kIODirectionIn | kIOMemoryPhysicallyContiguous, fMax_Block_Size, PAGE_SIZE);
1652        if (!fPipeInBuff[i].pipeInMDP)
1653        {
1654            XTRACE(this, 0, i, "allocateResources - Allocate input descriptor failed");
1655            return false;
1656        }
1657
1658		fPipeInBuff[i].pipeInMDP->setLength(fMax_Block_Size);
1659        fPipeInBuff[i].pipeInBuffer = (UInt8*)fPipeInBuff[i].pipeInMDP->getBytesNoCopy();
1660        XTRACE(this, 0, i, "allocateResources - input buffer");
1661        fPipeInBuff[i].dead = false;
1662        fPipeInBuff[i].readCompletionInfo.target = this;
1663        fPipeInBuff[i].readCompletionInfo.action = dataReadComplete;
1664        fPipeInBuff[i].readCompletionInfo.parameter = NULL;
1665    }
1666
1667        // Allocate Memory Descriptor Pointers with memory for the data-out bulk pipe pool
1668
1669    for (i=0; i<fOutBufPool; i++)
1670    {
1671//		fPipeOutBuff[i].pipeOutMDP = IOBufferMemoryDescriptor::withCapacity(fMax_Block_Size, kIODirectionOut);
1672        fPipeOutBuff[i].pipeOutMDP = IOBufferMemoryDescriptor::withOptions(kIODirectionOut | kIOMemoryPhysicallyContiguous, fMax_Block_Size, PAGE_SIZE);
1673        if (!fPipeOutBuff[i].pipeOutMDP)
1674        {
1675            XTRACE(this, 0, i, "allocateResources - Allocate output descriptor failed");
1676            return false;
1677        }
1678
1679		fPipeOutBuff[i].pipeOutMDP->setLength(fMax_Block_Size);
1680        fPipeOutBuff[i].pipeOutBuffer = (UInt8*)fPipeOutBuff[i].pipeOutMDP->getBytesNoCopy();
1681        XTRACE(this, 0, i, "allocateResources - output buffer");
1682        fPipeOutBuff[i].avail = true;
1683        fPipeOutBuff[i].writeCompletionInfo.target = this;
1684        fPipeOutBuff[i].writeCompletionInfo.action = dataWriteComplete;
1685        fPipeOutBuff[i].writeCompletionInfo.parameter = NULL;				// for now, filled in with pool index when sent
1686    }
1687
1688    return true;
1689
1690}/* end allocateResources */
1691
1692/****************************************************************************************************/
1693//
1694//		Method:		AppleUSBCDCEEM::releaseResources
1695//
1696//		Inputs:
1697//
1698//		Outputs:
1699//
1700//		Desc:		Frees up the resources allocated in allocateResources
1701//
1702/****************************************************************************************************/
1703
1704void AppleUSBCDCEEM::releaseResources()
1705{
1706    UInt32	i;
1707
1708    XTRACE(this, 0, 0, "releaseResources");
1709
1710    for (i=0; i<fOutBufPool; i++)
1711    {
1712        if (fPipeOutBuff[i].pipeOutMDP)
1713        {
1714            fPipeOutBuff[i].pipeOutMDP->release();
1715            fPipeOutBuff[i].pipeOutMDP = NULL;
1716            fPipeOutBuff[i].avail = false;
1717            fPipeOutBuff[i].writeCompletionInfo.target = NULL;
1718            fPipeOutBuff[i].writeCompletionInfo.action = NULL;
1719            fPipeOutBuff[i].writeCompletionInfo.parameter = NULL;
1720        }
1721    }
1722    fOutPoolIndex = 0;
1723
1724    for (i=0; i<fInBufPool; i++)
1725    {
1726        if (fPipeInBuff[i].pipeInMDP)
1727        {
1728            fPipeInBuff[i].pipeInMDP->release();
1729            fPipeInBuff[i].pipeInMDP = NULL;
1730            fPipeInBuff[i].dead = false;
1731            fPipeInBuff[i].readCompletionInfo.target = NULL;
1732            fPipeInBuff[i].readCompletionInfo.action = NULL;
1733            fPipeInBuff[i].readCompletionInfo.parameter = NULL;
1734        }
1735    }
1736
1737}/* end releaseResources */
1738
1739/****************************************************************************************************/
1740//
1741//		Method:		AppleUSBCDCEEM::getOutputBuffer
1742//
1743//		Inputs:		bufIndx - index of an available buffer
1744//
1745//		Outputs:	Return code - True (got one), False (none available)
1746//
1747//		Desc:		Get an available buffer from the output buffer pool
1748//
1749/****************************************************************************************************/
1750
1751bool AppleUSBCDCEEM::getOutputBuffer(UInt32 *bufIndx)
1752{
1753	bool	gotBuffer = false;
1754	UInt32	indx;
1755
1756	XTRACE(this, 0, 0, "getOutputBuffer");
1757
1758	if (fBufferPoolLock)
1759    {
1760        IOLockLock(fBufferPoolLock);
1761    } else {
1762		return false;
1763	}
1764
1765	while (!gotBuffer)
1766	{
1767			// Get an ouput buffer (use the hint first then if that's not available look for one)
1768
1769		indx = fOutPoolIndex;
1770		if (!fPipeOutBuff[indx].avail)
1771		{
1772			for (indx=0; indx<fOutBufPool; indx++)
1773			{
1774				if (fPipeOutBuff[indx].avail)
1775				{
1776					fOutPoolIndex = indx;
1777					gotBuffer = true;
1778					break;
1779				}
1780			}
1781		} else {
1782			gotBuffer = true;
1783		}
1784
1785		if (gotBuffer)
1786		{
1787			fPipeOutBuff[indx].avail = false;
1788			fOutPoolIndex++;
1789			if (fOutPoolIndex >= fOutBufPool)
1790			{
1791				fOutPoolIndex = 0;
1792			}
1793		}
1794        break;
1795    }
1796
1797	IOLockUnlock(fBufferPoolLock);
1798
1799	*bufIndx = indx;
1800
1801	return gotBuffer;
1802
1803}/* end getOutputBuffer */
1804
1805/****************************************************************************************************/
1806//
1807//		Method:		AppleUSBCDCEEM::USBTransmitPacket
1808//
1809//		Inputs:		packet - the packet
1810//
1811//		Outputs:	Return code - kIOReturnSuccess (transmit started), everything else (it didn't)
1812//
1813//		Desc:		Set up and then transmit the packet.
1814//
1815/****************************************************************************************************/
1816
1817IOReturn AppleUSBCDCEEM::USBTransmitPacket(mbuf_t packet)
1818{
1819    UInt32		numbufs = 0;			// number of mbufs for this packet
1820    mbuf_t		m;					// current mbuf
1821    UInt32		total_pkt_length = 0;
1822    UInt32		rTotal = 0;
1823    IOReturn	ior = kIOReturnSuccess;
1824    UInt32		indx;
1825
1826    XTRACE(this, 0, 0, "USBTransmitPacket");
1827
1828        // Count the number of mbufs in this packet
1829
1830    m = packet;
1831    while (m)
1832	{
1833		if (mbuf_len(m) != 0)
1834		{
1835			total_pkt_length += mbuf_len(m);
1836			numbufs++;
1837		}
1838		m = mbuf_next(m);
1839    }
1840
1841    XTRACE(this, total_pkt_length, numbufs, "USBTransmitPacket - Total packet length and Number of mbufs");
1842
1843	if (total_pkt_length > fMax_Block_Size)
1844    {
1845        XTRACE(this, 0, 0, "USBTransmitPacket - Bad packet size");	// Note for now and revisit later
1846		fpNetStats->outputErrors++;
1847        return kIOReturnInternalError;
1848    }
1849
1850    if (!getOutputBuffer(&indx))
1851	{
1852		ALERT(fOutBufPool, fOutPoolIndex, "USBTransmitPacket - Output buffer unavailable");
1853        fTxStalled = true;
1854		return kIOReturnOutputStall;
1855	}
1856
1857        // Start filling in the send buffer
1858
1859	m = packet;							// start with the first mbuf of the packet
1860    rTotal = 0;							// running total
1861    do
1862    {
1863        if (mbuf_len(m) == 0)			// Ignore zero length buffers
1864			continue;
1865
1866        bcopy(mbuf_data(m), &fPipeOutBuff[indx].pipeOutBuffer[rTotal], mbuf_len(m));
1867        rTotal += mbuf_len(m);
1868
1869    } while ((m = mbuf_next(m)) != 0);
1870
1871    LogData(kDataOut, rTotal, fPipeOutBuff[indx].pipeOutBuffer);
1872
1873    fPipeOutBuff[indx].m = packet;
1874    fPipeOutBuff[indx].writeCompletionInfo.parameter = (void *)&fPipeOutBuff[indx];
1875    fPipeOutBuff[indx].pipeOutMDP->setLength(rTotal);
1876    ior = fOutPipe->Write(fPipeOutBuff[indx].pipeOutMDP, &fPipeOutBuff[indx].writeCompletionInfo);
1877    if (ior != kIOReturnSuccess)
1878    {
1879        XTRACE(this, 0, ior, "USBTransmitPacket - Write failed");
1880        if (ior == kIOUSBPipeStalled)
1881        {
1882            fOutPipe->Reset();
1883            ior = fOutPipe->Write(fPipeOutBuff[indx].pipeOutMDP, &fPipeOutBuff[indx].writeCompletionInfo);
1884            if (ior != kIOReturnSuccess)
1885            {
1886                XTRACE(this, 0, ior, "USBTransmitPacket - Write really failed");
1887				fpNetStats->outputErrors++;
1888                return ior;
1889            }
1890        }
1891    }
1892
1893	fpNetStats->outputPackets++;
1894
1895    return ior;
1896
1897}/* end USBTransmitPacket */
1898
1899/****************************************************************************************************/
1900//
1901//		Method:		AppleUSBCDCEEM::USBSendCommand
1902//
1903//		Inputs:		command - the command to be sent
1904//					length - length of any data to be sent
1905//					anyData - any actual data (must be present if length > 0)
1906//
1907//		Outputs:	Return code - kIOReturnSuccess (transmit started), everything else (it didn't)
1908//
1909//		Desc:		Set up and a command packet.
1910//
1911/****************************************************************************************************/
1912
1913IOReturn AppleUSBCDCEEM::USBSendCommand(UInt16 command, UInt16 length, UInt8 *anyData)
1914{
1915	IOReturn	ior = kIOReturnSuccess;
1916    UInt32		indx;
1917    bool		gotBuffer = false;
1918	UInt16		EEMHeader = bmTypeCommand;
1919
1920    XTRACE(this, command, length, "USBSendCommand");
1921
1922	if ((length > 0) && (anyData == NULL))
1923	{
1924		return kIOReturnBadArgument;
1925	}
1926
1927		// Get an ouput buffer (use the hint first then if that's not available look for one)
1928
1929    if (fBufferPoolLock)
1930    {
1931        IOLockLock(fBufferPoolLock);
1932    }
1933
1934    indx = fOutPoolIndex;
1935    if (!fPipeOutBuff[indx].avail)
1936    {
1937        for (indx=0; indx<fOutBufPool; indx++)
1938        {
1939            if (fPipeOutBuff[indx].avail)
1940            {
1941                fOutPoolIndex = indx;
1942                gotBuffer = true;
1943                break;
1944            }
1945        }
1946        if (!gotBuffer)
1947        {
1948            XTRACE(this, fOutBufPool, fOutPoolIndex, "USBSendCommand - Output buffer unavailable");
1949			fpNetStats->outputErrors++;
1950            if (fBufferPoolLock)
1951            {
1952                IOLockUnlock(fBufferPoolLock);
1953            }
1954            return kIOReturnInternalError;
1955        }
1956    }
1957    fOutPoolIndex++;
1958    if (fOutPoolIndex >= fOutBufPool)
1959    {
1960        fOutPoolIndex = 0;
1961    }
1962
1963    if (fBufferPoolLock)
1964    {
1965        IOLockUnlock(fBufferPoolLock);
1966    }
1967
1968		// Now handle the data
1969
1970	EEMHeader |= command;
1971	EEMHeader |= length;
1972
1973	bcopy(&EEMHeader, fPipeOutBuff[indx].pipeOutBuffer, sizeof(EEMHeader));
1974	if (length > 0)
1975	{
1976		bcopy(anyData, &fPipeOutBuff[indx].pipeOutBuffer[2], length);
1977	}
1978
1979    LogData(kDataOut, length+2, fPipeOutBuff[indx].pipeOutBuffer);
1980
1981    fPipeOutBuff[indx].m = NULL;
1982    fPipeOutBuff[indx].writeCompletionInfo.parameter = (void *)indx;
1983    fPipeOutBuff[indx].pipeOutMDP->setLength(length+2);
1984    ior = fOutPipe->Write(fPipeOutBuff[indx].pipeOutMDP, &fPipeOutBuff[indx].writeCompletionInfo);
1985    if (ior != kIOReturnSuccess)
1986    {
1987        XTRACE(this, 0, ior, "USBSendCommand - Write failed");
1988        if (ior == kIOUSBPipeStalled)
1989        {
1990            fOutPipe->Reset();
1991            ior = fOutPipe->Write(fPipeOutBuff[indx].pipeOutMDP, &fPipeOutBuff[indx].writeCompletionInfo);
1992            if (ior != kIOReturnSuccess)
1993            {
1994                XTRACE(this, 0, ior, "USBSendCommand - Write really failed");
1995				fpNetStats->outputErrors++;
1996                return ior;
1997            }
1998        }
1999    }
2000
2001	fpNetStats->outputPackets++;
2002
2003    return ior;
2004
2005}/* end USBSendCommand */
2006
2007/****************************************************************************************************/
2008//
2009//		Method:		AppleUSBCDCEEM::clearPipeStall
2010//
2011//		Inputs:		thePipe - the pipe
2012//
2013//		Outputs:
2014//
2015//		Desc:		Clear a stall on the specified pipe.
2016//
2017/****************************************************************************************************/
2018
2019IOReturn AppleUSBCDCEEM::clearPipeStall(IOUSBPipe *thePipe)
2020{
2021    IOReturn 	rtn = kIOReturnSuccess;
2022
2023    XTRACE(this, 0, 0, "clearPipeStall");
2024
2025    rtn = thePipe->GetPipeStatus();
2026    if (rtn == kIOUSBPipeStalled)
2027    {
2028        rtn = thePipe->ClearPipeStall(true);
2029        if (rtn == kIOReturnSuccess)
2030        {
2031            XTRACE(this, 0, 0, "clearPipeStall - Successful");
2032        } else {
2033            XTRACE(this, 0, rtn, "clearPipeStall - Failed");
2034        }
2035    } else {
2036        XTRACE(this, 0, 0, "clearPipeStall - Pipe not stalled");
2037    }
2038
2039    return rtn;
2040
2041}/* end clearPipeStall */
2042
2043/****************************************************************************************************/
2044//
2045//		Method:		AppleUSBCDCEEM::receivePacket
2046//
2047//		Inputs:		packet - the packet
2048//				size - Number of bytes in the packet
2049//
2050//		Outputs:
2051//
2052//		Desc:		Build the mbufs and then send to the network stack.
2053//
2054/****************************************************************************************************/
2055
2056void AppleUSBCDCEEM::receivePacket(UInt8 *packet, UInt32 size)
2057{
2058    mbuf_t		m;
2059    UInt32		submit;
2060
2061    XTRACE(this, 0, size, "receivePacket");
2062
2063	if (size > fMax_Block_Size)
2064    {
2065        XTRACE(this, 0, 0, "receivePacket - Packet size error, packet dropped");
2066		fpNetStats->inputErrors++;
2067        return;
2068    }
2069
2070    m = allocatePacket(size);
2071    if (m)
2072    {
2073        bcopy(packet, mbuf_data(m), size);
2074        submit = fNetworkInterface->inputPacket(m, size);
2075        XTRACE(this, 0, submit, "receivePacket - Packets submitted");
2076		fpNetStats->inputPackets++;
2077    } else {
2078        XTRACE(this, 0, 0, "receivePacket - Buffer allocation failed, packet dropped");
2079		fpNetStats->inputErrors++;
2080    }
2081
2082}/* end receivePacket */
2083
2084/****************************************************************************************************/
2085//
2086//		Method:		AppleUSBCDCEEM::processEEMCommand
2087//
2088//		Inputs:		EEMHeader - the EEM packet header
2089//					poolIndx - Index into the buffer pool
2090//					dataIndx - Index into the buffer for the current command
2091//
2092//		Outputs:	len - actual length of the command
2093//
2094//		Desc:		Handle the EEM command.
2095//
2096/****************************************************************************************************/
2097
2098void AppleUSBCDCEEM::processEEMCommand(UInt16 EEMHeader, UInt32 poolIndx, SInt16 dataIndx, SInt16 *len)
2099{
2100	IOReturn 	rtn = kIOReturnSuccess;
2101	UInt16		EEMCommand;
2102	UInt16		param;
2103	UInt8		*buff = NULL;
2104
2105    XTRACE(this, EEMHeader, poolIndx, "processEEMCommand");
2106
2107	EEMCommand = EEMHeader & bmEEMCmdMask;
2108	param = EEMHeader & bmEEMCmdParamMask;
2109
2110	switch (EEMCommand)
2111    {
2112        case EEMEcho:
2113			XTRACE(this, EEMCommand, param, "processEEMCommand - Echo");
2114			if (param != 0)
2115			{
2116				buff = &fPipeInBuff[poolIndx].pipeInBuffer[2];
2117			}
2118			rtn = USBSendCommand(EEMEchoResponse, param, buff);
2119			if (rtn != kIOReturnSuccess)
2120			{
2121				XTRACE(this, 0, rtn, "processEEMCommand - Failed to send echo response");
2122			}
2123			*len = param + 2;
2124            break;
2125        case EEMEchoResponse:
2126			XTRACE(this, EEMCommand, param, "processEEMCommand - Echo Response");
2127
2128			*len = param + 2;
2129			break;
2130		case EEMSuspendHint:
2131			XTRACE(this, EEMCommand, param, "processEEMCommand - Suspend Hint");
2132
2133			*len = 2;
2134            break;
2135        case EEMResponseHint:
2136			XTRACE(this, EEMCommand, param, "processEEMCommand - Response Hint");
2137
2138			*len = 2;
2139			break;
2140		case EEMResponseCompleteHint:
2141			XTRACE(this, EEMCommand, param, "processEEMCommand - Response Hint Complete");
2142
2143			*len = 2;
2144            break;
2145        case EEMTickle:
2146			XTRACE(this, EEMCommand, param, "processEEMCommand - Tickle");
2147
2148			*len = 2;
2149			break;
2150		default:
2151            XTRACE(this, EEMCommand, param, "processEEMCommand - unknown command");
2152			*len = 2;
2153            break;
2154    }
2155
2156}/* end processEEMCommand */
2157
2158/****************************************************************************************************/
2159//
2160//		Method:		AppleUSBCDCEEM::message
2161//
2162//		Inputs:		type - message type
2163//				provider - my provider
2164//				argument - additional parameters
2165//
2166//		Outputs:	return Code - kIOReturnSuccess
2167//
2168//		Desc:		Handles IOKit messages.
2169//
2170/****************************************************************************************************/
2171
2172IOReturn AppleUSBCDCEEM::message(UInt32 type, IOService *provider, void *argument)
2173{
2174    UInt16	i;
2175    IOReturn	ior;
2176
2177    XTRACE(this, 0, type, "message");
2178
2179    switch (type)
2180    {
2181        case kIOMessageServiceIsTerminated:
2182            XTRACE(this, fReady, type, "message - kIOMessageServiceIsTerminated");
2183
2184            if (fReady)
2185            {
2186                if (!fTerminate)		// Check if we're already being terminated
2187                {
2188#if 0
2189		    // NOTE! This call below depends on the hard coded path of this KEXT. Make sure
2190		    // that if the KEXT moves, this path is changed!
2191		    KUNCUserNotificationDisplayNotice(
2192			0,		// Timeout in seconds
2193			0,		// Flags (for later usage)
2194			"",		// iconPath (not supported yet)
2195			"",		// soundPath (not supported yet)
2196			"/System/Library/Extensions/IOUSBFamily.kext/Contents/PlugIns/AppleUSBCDCEEM.kext",	// localizationPath
2197			"Unplug Header",		// the header
2198			"Unplug Notice",		// the notice - look in Localizable.strings
2199			"OK");
2200#endif
2201                }
2202            }
2203
2204            releaseResources();
2205            if (fDataInterface)
2206            {
2207                fDataInterface->close(this);
2208                fDataInterface->release();
2209                fDataInterface = NULL;
2210            }
2211            fTerminate = true;		// we're being terminated (unplugged)
2212            fLinkStatus = 0;		// and of course we're offline
2213            return kIOReturnSuccess;
2214        case kIOMessageServiceIsSuspended:
2215            XTRACE(this, 0, type, "message - kIOMessageServiceIsSuspended");
2216            break;
2217        case kIOMessageServiceIsResumed:
2218            XTRACE(this, 0, type, "message - kIOMessageServiceIsResumed");
2219            break;
2220        case kIOMessageServiceIsRequestingClose:
2221            XTRACE(this, 0, type, "message - kIOMessageServiceIsRequestingClose");
2222            break;
2223        case kIOMessageServiceWasClosed:
2224            XTRACE(this, 0, type, "message - kIOMessageServiceWasClosed");
2225            break;
2226        case kIOMessageServiceBusyStateChange:
2227            XTRACE(this, 0, type, "message - kIOMessageServiceBusyStateChange");
2228            break;
2229        case kIOUSBMessagePortHasBeenResumed:
2230            XTRACE(this, 0, type, "message - kIOUSBMessagePortHasBeenResumed");
2231            for (i=0; i<fInBufPool; i++)
2232            {
2233                if (fPipeInBuff[i].dead)			// If it's dead try and resurrect it
2234                {
2235                    ior = fInPipe->Read(fPipeInBuff[i].pipeInMDP, &fPipeInBuff[i].readCompletionInfo, NULL);
2236                    if (ior != kIOReturnSuccess)
2237                    {
2238                        XTRACE(this, 0, ior, "message - Read io error");
2239                    } else {
2240                        fPipeInBuff[i].dead = false;
2241                    }
2242                }
2243            }
2244            return kIOReturnSuccess;
2245        case kIOUSBMessageHubResumePort:
2246            XTRACE(this, 0, type, "message - kIOUSBMessageHubResumePort");
2247            break;
2248        default:
2249            XTRACE(this, 0, type, "message - unknown message");
2250            break;
2251    }
2252
2253    return super::message(type, provider, argument);
2254
2255}/* end message */