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 "AppleUSBCDCECMData"
60
61#include "AppleUSBCDCECM.h"
62#include "AppleUSBCDCECMData.h"
63#include "linkup.h"
64
65#define MIN_BAUD (50 << 1)
66
67static IOPMPowerState gOurPowerStates[kNumCDCStates] =
68{
69    {1,0,0,0,0,0,0,0,0,0,0,0},
70    {1,IOPMDeviceUsable,IOPMPowerOn,IOPMPowerOn,0,0,0,0,0,0,0,0}
71};
72
73static struct MediumTable
74{
75    UInt32	type;
76    UInt32	speed;
77}
78
79mediumTable[] =
80{
81    { kIOMediumEthernetNone,																0    },
82    { kIOMediumEthernetAuto,																0    },
83    { kIOMediumEthernet10BaseT    | kIOMediumOptionHalfDuplex,								10   },
84    { kIOMediumEthernet10BaseT    | kIOMediumOptionFullDuplex,								10   },
85    { kIOMediumEthernet10BaseT    | kIOMediumOptionFullDuplex | kIOMediumOptionFlowControl,	10   },
86    { kIOMediumEthernet100BaseTX  | kIOMediumOptionHalfDuplex,								100  },
87    { kIOMediumEthernet100BaseTX  | kIOMediumOptionFullDuplex,								100  },
88    { kIOMediumEthernet100BaseTX  | kIOMediumOptionFullDuplex | kIOMediumOptionFlowControl,	100  },
89    { kIOMediumEthernet1000BaseTX | kIOMediumOptionFullDuplex,								1000 },
90    { kIOMediumEthernet1000BaseTX | kIOMediumOptionFullDuplex | kIOMediumOptionFlowControl,	1000 }
91};
92
93#define super IOEthernetController
94
95OSDefineMetaClassAndStructors(AppleUSBCDCECMData, IOEthernetController);
96
97/****************************************************************************************************/
98//
99//		Function:	findCDCDriverED
100//
101//		Inputs:		myDevice - Address of the controlling device
102//				dataAddr - my address
103//				dataInterfaceNum - the data interface number
104//
105//		Outputs:
106//
107//		Desc:		Finds the initiating CDC driver and confirm the interface number
108//
109/****************************************************************************************************/
110
111IOReturn findCDCDriverED(IOUSBDevice *myDevice, void *dataAddr, UInt8 dataInterfaceNum)
112{
113    AppleUSBCDCECMData	*me = (AppleUSBCDCECMData *)dataAddr;
114    AppleUSBCDC		*CDCDriver = NULL;
115    bool		driverOK = false;
116    OSIterator		*iterator = NULL;
117    OSDictionary	*matchingDictionary = NULL;
118    UInt16		i;
119
120    XTRACE(me, 0, 0, "findCDCDriverED");
121
122        // Get matching dictionary
123
124    matchingDictionary = IOService::serviceMatching("AppleUSBCDC");
125    if (!matchingDictionary)
126    {
127        XTRACE(me, 0, 0, "findCDCDriverED - Couldn't create a matching dictionary");
128        return kIOReturnError;
129    }
130
131	// Get an iterator
132
133    iterator = IOService::getMatchingServices(matchingDictionary);
134    if (!iterator)
135    {
136        XTRACE(me, 0, 0, "findCDCDriverED - No AppleUSBCDC driver found!");
137        matchingDictionary->release();
138        return kIOReturnError;
139    }
140
141#if 0
142	// Use iterator to find driver (there's only one so we won't bother to iterate)
143
144    CDCDriver = (AppleUSBCDC *)iterator->getNextObject();
145    if (CDCDriver)
146    {
147        driverOK = CDCDriver->confirmDriver(kUSBEthernetControlModel, dataInterfaceNum);
148    }
149#endif
150
151 	// Iterate until we find our matching CDC driver
152
153    CDCDriver = (AppleUSBCDC *)iterator->getNextObject();
154    while (CDCDriver)
155    {
156        XTRACEP(me, 0, CDCDriver, "findCDCDriverED - CDC driver candidate");
157
158        if (me->fDataInterface->GetDevice() == CDCDriver->getCDCDevice())
159        {
160            XTRACEP(me, 0, CDCDriver, "findCDCDriverED - Found our CDC driver");
161            driverOK = CDCDriver->confirmDriver(kUSBEthernetControlModel, dataInterfaceNum);
162            break;
163        }
164        CDCDriver = (AppleUSBCDC *)iterator->getNextObject();
165    }
166
167    matchingDictionary->release();
168    iterator->release();
169
170    if (!CDCDriver)
171    {
172        XTRACE(me, 0, 0, "findCDCDriverED - CDC driver not found");
173        return kIOReturnNotReady;
174    }
175
176    if (!driverOK)
177    {
178        XTRACE(me, kUSBEthernetControlModel, dataInterfaceNum, "findCDCDriverED - Not my interface");
179        return kIOReturnError;
180    }
181
182    me->fConfigAttributes = CDCDriver->fbmAttributes;
183
184    for (i=0; i<6; i++)
185    {
186        me->fEthernetaddr[i] = CDCDriver->fCacheEaddr[i];
187    }
188
189    return kIOReturnSuccess;
190
191}/* end findCDCDriverED */
192
193/****************************************************************************************************/
194//
195//		Function:	findControlDriverED
196//
197//		Inputs:		me - my address
198//
199//		Outputs:
200//
201//		Desc:		Finds our matching control driver
202//
203/****************************************************************************************************/
204
205IOReturn findControlDriverED(AppleUSBCDCECMData *me)
206{
207    AppleUSBCDCECMControl	*tempDriver = NULL;
208    OSIterator			*iterator = NULL;
209    OSDictionary		*matchingDictionary = NULL;
210
211    XTRACE(me, 0, 0, "findControlDriverED");
212
213	me->fControlDriver = NULL;
214
215        // Get matching dictionary
216
217    matchingDictionary = IOService::serviceMatching("AppleUSBCDCECMControl");
218    if (!matchingDictionary)
219    {
220        XTRACE(me, 0, 0, "findControlDriverED - Couldn't create a matching dictionary");
221        return kIOReturnError;
222    }
223
224	// Get an iterator
225
226    iterator = IOService::getMatchingServices(matchingDictionary);
227    if (!iterator)
228    {
229        XTRACE(me, 0, 0, "findControlDriverED - No AppleUSBCDCECMControl drivers found (iterator)");
230        matchingDictionary->release();
231        return kIOReturnError;
232    }
233
234	// Iterate until we find our matching driver
235
236    tempDriver = (AppleUSBCDCECMControl *)iterator->getNextObject();
237    while (tempDriver)
238    {
239        XTRACEP(me, 0, tempDriver, "findControlDriverED - Control driver candidate");
240        if (tempDriver->checkInterfaceNumber((AppleUSBCDCECMData *)me))
241        {
242            XTRACEP(me, 0, tempDriver, "findControlDriverED - Found our control driver");
243            me->fControlDriver = tempDriver;
244            break;
245        }
246        tempDriver = (AppleUSBCDCECMControl *)iterator->getNextObject();
247    }
248
249    matchingDictionary->release();
250    iterator->release();
251
252    if (!me->fControlDriver)
253    {
254        XTRACE(me, 0, 0, "findControlDriverED - Failed");
255        return kIOReturnError;
256    }
257
258    return kIOReturnSuccess;
259
260}/* end findControlDriverED */
261
262#if LOG_DATA
263#define dumplen		32		// Set this to the number of bytes to dump and the rest should work out correct
264
265#define buflen		((dumplen*2)+dumplen)+3
266#define Asciistart	(dumplen*2)+3
267
268/****************************************************************************************************/
269//
270//		Function:	AppleUSBCDCECMData::USBLogData
271//
272//		Inputs:		Dir - direction
273//				Count - number of bytes
274//				buf - the data
275//
276//		Outputs:
277//
278//		Desc:		Puts the data in the log.
279//
280/****************************************************************************************************/
281
282void AppleUSBCDCECMData::USBLogData(UInt8 Dir, SInt32 Count, char *buf)
283{
284    SInt32	wlen;
285    UInt8	tDir = Dir;
286    SInt32	llen, rlen;
287    SInt16	i, Aspnt, Hxpnt;
288    UInt8	wchr;
289    char	LocBuf[buflen+1];
290
291    XTRACE(0, 0, Count, "USBLogData >>>>");
292
293
294    switch (tDir)
295    {
296        case kDataIn:
297            Log("AppleUSBCDCECMData: USBLogData - Read Complete, address = %8p, size = %8d\n", (void *)buf, (UInt)Count);
298            break;
299        case kDataOut:
300            Log("AppleUSBCDCECMData: USBLogData - Write, address = %8p, size = %8d\n", (void *)buf, (UInt)Count);
301            break;
302        case kDataOther:
303            Log("AppleUSBCDCECMData: USBLogData - Other, address = %8p, size = %8d\n", (void *)buf, (UInt)Count);
304            break;
305        case kDataNone:
306            tDir = kDataOther;
307            break;
308    }
309
310#if DUMPALL
311    wlen = Count;
312#else
313    if (Count > dumplen)
314    {
315        wlen = dumplen;
316    } else {
317        wlen = Count;
318    }
319#endif
320
321    if (wlen == 0)
322    {
323        Log("AppleUSBCDCECMData: USBLogData - No data, Count=0\n");
324        return;
325    }
326
327    rlen = 0;
328    do
329    {
330        memset(LocBuf, 0x20, buflen);
331
332        if (wlen > dumplen)
333        {
334            llen = dumplen;
335            wlen -= dumplen;
336        } else {
337            llen = wlen;
338            wlen = 0;
339        }
340        Aspnt = Asciistart;
341        Hxpnt = 0;
342        for (i=1; i<=llen; i++)
343        {
344            wchr = buf[i-1];
345            LocBuf[Hxpnt++] = Asciify(wchr >> 4);
346            LocBuf[Hxpnt++] = Asciify(wchr);
347            if ((wchr < 0x20) || (wchr > 0x7F)) 		// Non printable characters
348            {
349                LocBuf[Aspnt++] = 0x2E;				// Replace with a period
350            } else {
351                LocBuf[Aspnt++] = wchr;
352            }
353        }
354        LocBuf[Aspnt] = 0x00;
355
356		Log("%s\n", LocBuf);
357#if USE_IOL
358        IOSleep(Sleep_Time);					// Try and keep the log from overflowing
359#endif
360        rlen += llen;
361        buf = &buf[rlen];
362    } while (wlen != 0);
363
364    XTRACE(0, Dir, Count, "USBLogData <<<<");
365
366}/* end USBLogData */
367
368/****************************************************************************************************/
369//
370//		Function:	AppleUSBCDCECMData::dumpData
371//
372//		Inputs:		buf - the data
373//				size - number of bytes
374//
375//		Outputs:	None
376//
377//		Desc:		Creats formatted data for the log (cannot be used at interrupt time)
378//
379/****************************************************************************************************/
380
381void AppleUSBCDCECMData::dumpData(char *buf, SInt32 size)
382{
383    SInt32	curr, len, dlen;
384
385    Log("AppleUSBCDCECMData: dumpData - Address = %8p, size = %8d\n", (void *)buf, (UInt)size);
386
387    dlen = 0;
388    len = size;
389
390    for (curr=0; curr<size; curr+=dumplen)
391    {
392        if (len > dumplen)
393        {
394            dlen = dumplen;
395        } else {
396            dlen = len;
397        }
398        Log("%8p ", (void *)&buf[curr]);
399        USBLogData(kDataNone, dlen, &buf[curr]);
400        len -= dlen;
401    }
402
403}/* end dumpData */
404#endif
405
406/****************************************************************************************************/
407//
408//		Method:		AppleUSBCDCECMData::dataReadComplete
409//
410//		Inputs:		obj - me
411//				param - pool index
412//				rc - return code
413//				remaining - what's left
414//
415//		Outputs:
416//
417//		Desc:		BulkIn pipe (Data interface) read completion routine
418//
419/****************************************************************************************************/
420
421void AppleUSBCDCECMData::dataReadComplete(void *obj, void *param, IOReturn rc, UInt32 remaining)
422{
423    AppleUSBCDCECMData	*me = (AppleUSBCDCECMData*)obj;
424    IOReturn			ior;
425	pipeInBuffers		*pipeInBuff = (pipeInBuffers *)param;
426
427    XTRACE(me, 0, pipeInBuff->indx, "dataReadComplete");
428
429    if (me->fTerminate) //rcs revisit for IOUSBFamily 2.0
430        return;
431
432    if (rc == kIOReturnSuccess)	// If operation returned ok
433    {
434        XTRACE(me, 0, me->fControlDriver->fMax_Block_Size - remaining, "dataReadComplete - data length");
435
436        meLogData(kDataIn, (me->fControlDriver->fMax_Block_Size - remaining), pipeInBuff->pipeInBuffer);
437
438			// If the link is down we're probably in the state where the device is not sending interrupts
439			// If we're in the ready state then we probably need to start things up
440
441		if (me->fLinkStatus == kLinkDown)
442		{
443			XTRACE(me, 0, me->fReady, "dataReadComplete - Link is down, checking ready state");
444			if (me->fReady)
445			{
446				me->linkStatusChange(kLinkUp);
447			}
448		}
449
450            // Move the incoming bytes up the stack
451
452        me->receivePacket(pipeInBuff->pipeInBuffer, me->fControlDriver->fMax_Block_Size - remaining);
453
454    } else {
455        XTRACE(me, 0, rc, "dataReadComplete - Read completion io err");
456        if (rc != kIOReturnAborted)
457        {
458			me->fDeferredClear = true;
459#if 0
460            rc = me->clearPipeStall(me->fInPipe);
461            if (rc != kIOReturnSuccess)
462            {
463                XTRACE(me, 0, rc, "dataReadComplete - clear stall failed (trying to continue)");
464            }
465#endif
466        }
467    }
468
469        // Queue the next read, only if not aborted
470
471    if (rc != kIOReturnAborted)
472    {
473        ior = me->fInPipe->Read(pipeInBuff->pipeInMDP, &pipeInBuff->readCompletionInfo, NULL);
474        if (ior != kIOReturnSuccess)
475        {
476            XTRACE(me, 0, ior, "dataReadComplete - Failed to queue read");
477            pipeInBuff->dead = true;
478        }
479    } else {
480        XTRACE(me, pipeInBuff->indx, 0, "dataReadComplete - Read terminated");
481        pipeInBuff->dead = true;
482    }
483
484    return;
485
486}/* end dataReadComplete */
487
488/****************************************************************************************************/
489//
490//		Method:		AppleUSBCDCECMData::dataWriteComplete
491//
492//		Inputs:		obj - me
493//				param - pool index
494//				rc - return code
495//				remaining - what's left
496//
497//		Outputs:
498//
499//		Desc:		BulkOut pipe (Data interface) write completion routine
500//
501/****************************************************************************************************/
502
503void AppleUSBCDCECMData::dataWriteComplete(void *obj, void *param, IOReturn rc, UInt32 remaining)
504{
505    AppleUSBCDCECMData	*me = (AppleUSBCDCECMData *)obj;
506    mbuf_t		m;
507    UInt32		pktLen = 0;
508//    UInt32		poolIndx = (UInt32)param;
509	pipeOutBuffers	*pipeOutBuff = (pipeOutBuffers *)param;
510
511    if (rc == kIOReturnSuccess)						// If operation returned ok
512    {
513        XTRACE(me, rc, pipeOutBuff->indx, "dataWriteComplete");
514
515        if (pipeOutBuff->m != NULL)			// Null means zero length write
516        {
517            m = pipeOutBuff->m;
518			while (m)
519			{
520				pktLen += mbuf_len(m);
521				m = mbuf_next(m);
522			}
523
524            me->freePacket(pipeOutBuff->m);		// Free the mbuf
525            pipeOutBuff->m = NULL;
526
527            if ((pktLen % me->fOutPacketSize) == 0)			// If it was a multiple of max packet size then we need to do a zero length write
528            {
529                XTRACE(me, rc, pktLen, "dataWriteComplete - writing zero length packet");
530//                pipeOutBuff->pipeOutMDP->setLength(0);
531                pipeOutBuff->writeCompletionInfo.parameter = (void *)pipeOutBuff;
532//                me->fOutPipe->Write(pipeOutBuff->pipeOutMDP, &pipeOutBuff->writeCompletionInfo);
533				me->fOutPipe->Write(pipeOutBuff->pipeOutMDP, 2000, 5000, 0, &pipeOutBuff->writeCompletionInfo);
534            } else {
535                pipeOutBuff->avail = true;
536                if (me->fTxStalled)
537                {
538                    me->fTxStalled = false;
539                    me->fTransmitQueue->service(IOBasicOutputQueue::kServiceAsync);
540                }
541            }
542        } else {
543            pipeOutBuff->avail = true;			// Make the buffer available again
544            if (me->fTxStalled)
545            {
546                me->fTxStalled = false;
547                me->fTransmitQueue->service(IOBasicOutputQueue::kServiceAsync);
548            }
549        }
550    } else {
551        XTRACE(me, rc, pipeOutBuff->indx, "dataWriteComplete - IO err");
552
553        if (pipeOutBuff->m != NULL)
554        {
555            me->freePacket(pipeOutBuff->m);		// Free the mbuf anyway
556            pipeOutBuff->m = NULL;
557        }
558
559        pipeOutBuff->avail = true;
560        if (me->fTxStalled)
561        {
562            me->fTxStalled = false;
563            me->fTransmitQueue->service(IOBasicOutputQueue::kServiceAsync);
564        }
565
566        if (rc != kIOReturnAborted)
567        {
568			me->fDeferredClear = true;
569#if 0
570            rc = me->clearPipeStall(me->fOutPipe);
571            if (rc != kIOReturnSuccess)
572            {
573                XTRACE(me, 0, rc, "dataWriteComplete - clear stall failed (trying to continue)");
574            }
575#endif
576        }
577    }
578
579    return;
580
581}/* end dataWriteComplete */
582
583/****************************************************************************************************/
584//
585//		Method:		AppleUSBCDCECMData::init
586//
587//		Inputs:		properties - data (keys and values) used to match
588//
589//		Outputs:	Return code - true (init successful), false (init failed)
590//
591//		Desc:		Initialize the driver.
592//
593/****************************************************************************************************/
594
595bool AppleUSBCDCECMData::init(OSDictionary *properties)
596{
597    UInt32	i;
598
599    XTRACE(this, 0, 0, "init");
600
601    if (super::init(properties) == false)
602    {
603        XTRACE(this, 0, 0, "init - initialize super failed");
604        return false;
605    }
606
607    fAltInterface = -1;
608    fTerminate = false;
609	fResetState = kResetNormal;
610	fSleeping = false;
611	fDeferredClear = false;
612
613	fLinkStatus = kLinkDown;
614	fUpSpeed = 10000000;				// Set to 10 until we know better (bits/sec)
615    fDownSpeed = 10000000;				// Same here
616
617    fQueueStarted = false;              // State of the IO output queue
618    fTxStalled = false;
619
620    for (i=0; i<kMaxOutBufPool; i++)
621    {
622        fPipeOutBuff[i].pipeOutMDP = NULL;
623        fPipeOutBuff[i].pipeOutBuffer = NULL;
624        fPipeOutBuff[i].m = NULL;
625        fPipeOutBuff[i].avail = false;
626        fPipeOutBuff[i].writeCompletionInfo.target = NULL;
627        fPipeOutBuff[i].writeCompletionInfo.action = NULL;
628        fPipeOutBuff[i].writeCompletionInfo.parameter = NULL;
629		fPipeOutBuff[i].indx = i;
630    }
631    fOutPoolIndex = 0;
632
633    for (i=0; i<kMaxInBufPool; i++)
634    {
635        fPipeInBuff[i].pipeInMDP = NULL;
636        fPipeInBuff[i].pipeInBuffer = NULL;
637        fPipeInBuff[i].dead = false;
638        fPipeInBuff[i].readCompletionInfo.target = NULL;
639        fPipeInBuff[i].readCompletionInfo.action = NULL;
640        fPipeInBuff[i].readCompletionInfo.parameter = NULL;
641		fPipeInBuff[i].indx = i;
642    }
643
644    return true;
645
646}/* end init*/
647
648/****************************************************************************************************/
649//
650//		Method:		AppleUSBCDCECMData::probe
651//
652//		Inputs:		provider - my provider
653//
654//		Outputs:	IOService - from super::probe, score - probe score
655//
656//		Desc:		Modify the probe score if necessary (we don't at the moment)
657//
658/****************************************************************************************************/
659
660IOService* AppleUSBCDCECMData::probe(IOService *provider, SInt32 *score)
661{
662    IOService   *res;
663
664		// If our IOUSBInterface has a "do not match" property, it means that we should not match and need
665		// to bail.  See rdar://3716623
666
667    OSBoolean *boolObj = OSDynamicCast(OSBoolean, provider->getProperty("kDoNotClassMatchThisInterface"));
668    if (boolObj && boolObj->isTrue())
669    {
670        XTRACE(this, 0, 0, "probe - provider doesn't want us to match");
671        return NULL;
672    }
673
674    res = super::probe(provider, score);
675
676    return res;
677
678}/* end probe */
679
680/****************************************************************************************************/
681//
682//		Method:		AppleUSBCDCECMData::start
683//
684//		Inputs:		provider - my provider
685//
686//		Outputs:	Return code - true (it's me), false (sorry it probably was me, but I can't configure it)
687//
688//		Desc:		This is called once it has beed determined I'm probably the best
689//				driver for this device.
690//
691/****************************************************************************************************/
692
693bool AppleUSBCDCECMData::start(IOService *provider)
694{
695	IOReturn	ret = kIOReturnSuccess;
696	UInt16		devDriverCount = 0;
697    OSNumber	*bufNumber = NULL;
698    OSBoolean   *enumerateOnWake;
699    UInt16		bufValue = 0;
700    IOUSBDevice *usbDevice;
701
702
703    XTRACE(this, 0, 0, "start");
704
705		// Get my USB provider - the interface
706
707    fDataInterface = OSDynamicCast(IOUSBInterface, provider);
708    if(!fDataInterface)
709    {
710        ALERT(0, 0, "start - provider invalid");
711        return false;
712    }
713
714    fDataInterfaceNumber = fDataInterface->GetInterfaceNumber();
715
716		// See if we can find/wait for the CDC driver
717
718	while (1)
719	{
720		ret = findCDCDriverED(fDataInterface->GetDevice(), this, fDataInterfaceNumber);
721		if (ret == kIOReturnSuccess)
722		{
723			XTRACE (this, 0, 0, "start: Found the CDC device driver");
724			break;
725		} else {
726			if (ret == kIOReturnNotReady)
727			{
728				devDriverCount++;
729				XTRACE(this, devDriverCount, fDataInterfaceNumber, "start - Waiting for CDC device driver...");
730				if (devDriverCount > 9)
731				{
732					break;
733				}
734				IOSleep(100);
735			} else {
736				break;
737			}
738		}
739	}
740
741		// If we didn't find him then we have to bail
742
743	if (ret != kIOReturnSuccess)
744	{
745		ALERT(0, fDataInterfaceNumber, "start - Find CDC driver for ECM data interface failed");
746		return false;
747	}
748
749		// Now we can start for real
750
751	if(!super::start(provider))
752    {
753        ALERT(0, 0, "start - start super failed");
754        return false;
755    }
756
757        // get workloop - check it first as createOutputQueue is called very early
758
759	if (!fWorkLoop)
760	{
761		fWorkLoop = getWorkLoop();
762		if (!fWorkLoop)
763		{
764			ALERT(0, 0, "start - getWorkLoop failed");
765			return false;
766		}
767	}
768
769    if (!configureData())
770    {
771        ALERT(0, 0, "start - configureData failed");
772        return false;
773    }
774
775		// Check for an input buffer pool override first
776
777	fInBufPool = 0;
778	fOutBufPool = 0;
779
780	bufNumber = (OSNumber *)provider->getProperty(inputTag);
781    if (bufNumber)
782    {
783		bufValue = bufNumber->unsigned16BitValue();
784		XTRACE(this, 0, bufValue, "start - Number of input buffers override value");
785        if (bufValue <= kMaxInBufPool)
786        {
787            fInBufPool = bufValue;
788        } else {
789            fInBufPool = kMaxInBufPool;
790        }
791	} else {
792		fInBufPool = 0;
793	}
794
795		// Now set up the real input buffer pool values (only if not overridden)
796
797	if (fInBufPool == 0)
798	{
799		bufNumber = NULL;
800		bufNumber = (OSNumber *)getProperty(inputTag);
801		if (bufNumber)
802		{
803			bufValue = bufNumber->unsigned16BitValue();
804			XTRACE(this, 0, bufValue, "start - Number of input buffers requested");
805			if (bufValue <= kMaxInBufPool)
806			{
807				fInBufPool = bufValue;
808			} else {
809				fInBufPool = kMaxInBufPool;
810			}
811		} else {
812			fInBufPool = kInBufPool;
813		}
814    }
815
816		// Check for an output buffer pool override
817
818	bufNumber = NULL;
819	bufNumber = (OSNumber *)provider->getProperty(outputTag);
820    if (bufNumber)
821    {
822		bufValue = bufNumber->unsigned16BitValue();
823		XTRACE(this, 0, bufValue, "start - Number of output buffers override value");
824        if (bufValue <= kMaxOutBufPool)
825        {
826            fOutBufPool = bufValue;
827        } else {
828            fOutBufPool = kMaxOutBufPool;
829        }
830	} else {
831		fOutBufPool = 0;
832	}
833
834        // Now set up the real output buffer pool values (only if not overridden)
835
836	if (fOutBufPool == 0)
837	{
838		bufNumber = NULL;
839		bufNumber = (OSNumber *)getProperty(outputTag);
840		if (bufNumber)
841		{
842			bufValue = bufNumber->unsigned16BitValue();
843			XTRACE(this, 0, bufValue, "start - Number of output buffers requested");
844			if (bufValue <= kMaxOutBufPool)
845			{
846				fOutBufPool = bufValue;
847			} else {
848				fOutBufPool = kMaxOutBufPool;
849			}
850		} else {
851			fOutBufPool = kOutBufPool;
852		}
853	}
854
855
856    //Do not automatically re-enumerate CDC ECM devices on wake
857    fEnumOnWake = FALSE;
858    UInt16 myVID = fDataInterface->GetDevice()->GetVendorID();
859    UInt16 myPID = fDataInterface->GetDevice()->GetProductID();
860
861    char vendorString[20];
862    char productString[20];
863    snprintf(vendorString, sizeof(vendorString), "0x%X", myVID);
864    snprintf(productString, sizeof(productString), "0x%X", myPID);
865
866    cdc_LogToMessageTracer(CDC_ASL_DOMAIN, "AppleUSBCDCECMData", vendorString, productString, 0, 0);
867
868    XTRACE(this, fInBufPool, fOutBufPool, "start - Buffer pools (input, output)");
869
870    if (findControlDriverED(this) != kIOReturnSuccess)
871    {
872        ALERT(0, 0, "start - Find control driver failed");
873    }
874
875    if (!createNetworkInterface())
876    {
877        ALERT(0, 0, "start - createNetworkInterface failed");
878        return false;
879    }
880
881         // Looks like we're ok (being defensive here)
882
883	if (fDataInterface)
884		fDataInterface->retain();
885	if (fWorkLoop)
886		fWorkLoop->retain();
887	if (fTransmitQueue)
888		fTransmitQueue->retain();
889
890        // Ready to service interface requests
891
892//rcs radar://10369195 We now registerService in createNetworkInterface
893//	if (fNetworkInterface)
894//		fNetworkInterface->registerService();
895
896    XTRACE(this, 0, 0, "start - successful");
897	Log(DEBUG_NAME ": Version number - %s, Input buffers %d, Output buffers %d\n", VersionNumber, fInBufPool, fOutBufPool);
898
899    return true;
900
901}/* end start */
902
903/****************************************************************************************************/
904//
905//		Method:		AppleUSBCDCECMData::stop
906//
907//		Inputs:		provider - my provider
908//
909//		Outputs:
910//
911//		Desc:		Stops the driver
912//
913/****************************************************************************************************/
914
915void AppleUSBCDCECMData::stop(IOService *provider)
916{
917
918    XTRACE(this, 0, 0, "stop");
919
920    fReady = false;
921
922        // Release all resources
923
924    releaseResources();
925
926    if (fDataInterface)
927    {
928        fDataInterface->close(this);
929        fDataInterface->release();
930        fDataInterface = NULL;
931    }
932
933    if (fNetworkInterface)
934    {
935        detachInterface(fNetworkInterface, FALSE);
936
937        fNetworkInterface->release();
938        fNetworkInterface = NULL;
939    }
940
941    if (fMediumDict)
942    {
943        fMediumDict->release();
944        fMediumDict = NULL;
945    }
946
947    if (fWorkLoop)
948    {
949        fWorkLoop->release();
950        fWorkLoop = NULL;
951    }
952
953    if (fTransmitQueue)
954    {
955        fTransmitQueue->release();
956        fTransmitQueue = NULL;
957    }
958
959    super::stop(provider);
960
961    return;
962
963}/* end stop */
964
965/****************************************************************************************************/
966//
967//		Method:		AppleUSBCDCECMData::configureData
968//
969//		Inputs:
970//
971//		Outputs:	return code - true (configure was successful), false (it failed)
972//
973//		Desc:		Finishes up the rest of the configuration
974//
975/****************************************************************************************************/
976
977bool AppleUSBCDCECMData::configureData()
978{
979    IOUSBFindInterfaceRequest		req;
980    const IOUSBInterfaceDescriptor	*altInterfaceDesc;
981    IOReturn				ior = kIOReturnSuccess;
982    UInt16				numends = 0;
983    UInt16				alt;
984
985    XTRACE(this, 0, 0, "configureData.");
986
987    if (!fDataInterface)
988    {
989        XTRACE(this, 0, 0, "configureData - Data interface is NULL");
990        return false;
991    }
992
993    if (!fDataInterface->open(this))
994    {
995        XTRACE(this, 0, 0, "configureData - open data interface failed");
996        return false;
997    }
998
999        // Check we have the correct interface (there maybe an alternate)
1000
1001    numends = fDataInterface->GetNumEndpoints();
1002    if (numends < 2)
1003    {
1004        req.bInterfaceClass = kUSBDataClass;
1005        req.bInterfaceSubClass = 0;
1006        req.bInterfaceProtocol = 0;
1007        req.bAlternateSetting = kIOUSBFindInterfaceDontCare;
1008        altInterfaceDesc = fDataInterface->FindNextAltInterface(NULL, &req);
1009        if (!altInterfaceDesc)
1010        {
1011            XTRACE(this, 0, 0, "configureData - FindNextAltInterface failed");
1012            return false;
1013        }
1014        while (altInterfaceDesc)
1015        {
1016            numends = altInterfaceDesc->bNumEndpoints;
1017            if (numends > 1)
1018            {
1019                alt = altInterfaceDesc->bAlternateSetting;
1020                XTRACE(this, numends, alt, "configureData - Data Class interface (alternate) found");
1021                ior = fDataInterface->SetAlternateInterface(this, alt);
1022                if (ior == kIOReturnSuccess)
1023                {
1024                    fAltInterface = alt;
1025                    XTRACE(this, 0, 0, "configureData - Alternate set");
1026                    break;
1027                } else {
1028                    XTRACE(this, 0, 0, "configureData - SetAlternateInterface failed");
1029                    return false;
1030                }
1031            } else {
1032                XTRACEP(this, 0, altInterfaceDesc, "configureData - No endpoints this alternate");
1033            }
1034            altInterfaceDesc = fDataInterface->FindNextAltInterface(altInterfaceDesc, &req);
1035        }
1036    }
1037
1038    if (numends < 2)
1039    {
1040        XTRACE(this, 0, 0, "configureData - Could not find the correct interface");
1041        return false;
1042    }
1043
1044    return true;
1045
1046}/* end configureData */
1047
1048/****************************************************************************************************/
1049//
1050//		Method:		AppleUSBCDCECMData::createNetworkInterface
1051//
1052//		Inputs:
1053//
1054//		Outputs:	return Code - true (created and initialilzed ok), false (it failed)
1055//
1056//		Desc:		Creates and initializes the network interface
1057//
1058/****************************************************************************************************/
1059
1060bool AppleUSBCDCECMData::createNetworkInterface()
1061{
1062
1063    XTRACE(this, 0, 0, "createNetworkInterface");
1064
1065            // Allocate memory for transmit queue
1066
1067    fTransmitQueue = (IOGatedOutputQueue *)getOutputQueue();
1068    if (!fTransmitQueue)
1069    {
1070        ALERT(0, 0, "createNetworkInterface - Output queue initialization failed");
1071        return false;
1072    }
1073
1074        // Allocate Timer event source
1075
1076    fTimerSource = IOTimerEventSource::timerEventSource(this, timerFired);
1077    if (fTimerSource == NULL)
1078    {
1079        ALERT(0, 0, "createNetworkInterface - Allocate Timer event source failed");
1080        return false;
1081    }
1082
1083	if (fWorkLoop)
1084	{
1085		if (fWorkLoop->addEventSource(fTimerSource) != kIOReturnSuccess)
1086		{
1087			ALERT(0, 0, "createNetworkInterface - Add Timer event source failed");
1088			return false;
1089		}
1090	}
1091
1092        // Attach an IOEthernetInterface client
1093
1094    XTRACE(this, 0, 0, "createNetworkInterface - attaching and registering interface");
1095
1096//rcs radar://10369195 attach interface and register at the same time..
1097//    if (!attachInterface((IONetworkInterface **)&fNetworkInterface, false))
1098    if (!attachInterface((IONetworkInterface **)&fNetworkInterface))
1099    {
1100        ALERT(0, 0, "createNetworkInterface - attachInterface failed");
1101        return false;
1102    }
1103
1104    XTRACE(this, 0, 0, "createNetworkInterface - Exiting, successful");
1105
1106    return true;
1107
1108}/* end createNetworkInterface */
1109
1110/****************************************************************************************************/
1111//
1112//		Method:		AppleUSBCDCECMData::enable
1113//
1114//		Inputs:		netif - the interface being enabled
1115//
1116//		Outputs:	Return code - kIOReturnSuccess or kIOReturnIOError
1117//
1118//		Desc:		Called by IOEthernetInterface client to enable the controller.
1119//				This method is always called while running on the default workloop
1120//				thread
1121//
1122/****************************************************************************************************/
1123
1124IOReturn AppleUSBCDCECMData::enable(IONetworkInterface *netif)
1125{
1126    IOReturn				ior = kIOReturnSuccess;
1127
1128    XTRACEP(this, 0, netif, "enable");
1129
1130    IOSleep(5);				// Just in case (to let start finish - on another thread)
1131
1132        // If an interface client has previously enabled us,
1133        // and we know there can only be one interface client
1134        // for this driver, then simply return success.
1135
1136    if (fNetifEnabled)
1137    {
1138        XTRACE(this, 0, 0, "enable - already enabled");
1139        return kIOReturnSuccess;
1140    }
1141
1142    if (!fControlDriver)
1143    {
1144        if (findControlDriverED(this) != kIOReturnSuccess)
1145        {
1146            ALERT(0, 0, "enable - Find control driver failed");
1147            return kIOReturnIOError;
1148        }
1149    }
1150
1151    if (!fReady)
1152    {
1153        if (!wakeUp())
1154        {
1155            XTRACE(this, 0, fReady, "enable - wakeUp failed");
1156            return kIOReturnIOError;
1157        }
1158    }
1159
1160    if (!fControlDriver->dataAcquired(fpNetStats, fpEtherStats))
1161    {
1162        XTRACE(this, 0, 0, "enable - dataAcquired to Control failed");
1163        return kIOReturnIOError;
1164    }
1165
1166        // Mark the controller as enabled by the interface.
1167
1168    setLinkStatusDown();
1169
1170
1171    fNetifEnabled = true;
1172
1173    fControlDriver->USBSetPacketFilter();
1174    XTRACE(this, 0, fControlDriver->fPacketFilter, "enable - packet filter applied+");
1175
1176    return ior;
1177
1178}/* end enable */
1179
1180/****************************************************************************************************/
1181//
1182//		Method:		AppleUSBCDCECMData::disable
1183//
1184//		Inputs:		netif - the interface being disabled
1185//
1186//		Outputs:	Return code - kIOReturnSuccess
1187//
1188//		Desc:		Called by IOEthernetInterface client to disable the controller.
1189//				This method is always called while running on the default workloop
1190//				thread
1191//
1192/****************************************************************************************************/
1193
1194IOReturn AppleUSBCDCECMData::disable(IONetworkInterface *netif)
1195{
1196    UInt16	packetFilter;
1197    bool    result;
1198    IOReturn err;
1199
1200
1201    XTRACE(this, 0, 0, "AppleUSBCDCECMData::disable");
1202
1203    putToSleep();
1204
1205    fNetifEnabled = false;
1206    fReady = false;
1207
1208         // Tell the Control driver the port's been disabled
1209		 // If reset state's not normal then he already knows
1210
1211	if (fResetState == kResetNormal)
1212	{
1213		if (fControlDriver)
1214		{
1215            packetFilter = fControlDriver->fPacketFilter;           //save the packet filter setting
1216
1217            fControlDriver->fPacketFilter = kPACKET_TYPE_DISABLED;  //Per Realtech SetPacketFilter (0)
1218            result = fControlDriver->USBSetPacketFilter();
1219			fControlDriver->dataReleased();
1220            XTRACE(this, 0, result, "AppleUSBCDCECMData::disable USBSetPacketFilter");
1221
1222            fControlDriver->fPacketFilter = packetFilter;
1223		}
1224	}
1225
1226//	fDataInterface->GetDevice()->ReEnumerateDevice(0);
1227
1228    err = fDataInterface->SetAlternateInterface (this, kResetNormal);  //Per Realtech set Alternate Interface setting 0
1229
1230    XTRACE(this, err, kResetNormal, "AppleUSBCDCECMData::disable -- SetAlternateInterface <<<");
1231
1232    fDataInterface->GetDevice()->SuspendDevice(true);
1233
1234    XTRACE(this, 0, true, "AppleUSBCDCECMData::disable -- SuspendDevice <<<");
1235
1236
1237    return kIOReturnSuccess;
1238
1239}/* end disable */
1240
1241/****************************************************************************************************/
1242//
1243//		Method:		AppleUSBCDCECMData::setWakeOnMagicPacket
1244//
1245//		Inputs:		active - true(wake), false(don't)
1246//
1247//		Outputs:	Return code - kIOReturnSuccess
1248//
1249//		Desc:		Set for wake on magic packet
1250//
1251/****************************************************************************************************/
1252
1253IOReturn AppleUSBCDCECMData::setWakeOnMagicPacket(bool active)
1254{
1255    IOUSBDevRequest	devreq;
1256    IOReturn		ior = kIOReturnSuccess;
1257
1258    XTRACE(this, 0, active, "setWakeOnMagicPacket");
1259
1260    fWOL = active;
1261
1262    if (fConfigAttributes & kUSBAtrRemoteWakeup)
1263    {
1264
1265            // Set/Clear the Device Remote Wake feature depending upon the active flag
1266
1267		devreq.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBStandard, kUSBDevice);
1268		if (active)
1269		{
1270			devreq.bRequest = kUSBRqSetFeature;
1271		} else {
1272			devreq.bRequest = kUSBRqClearFeature;
1273		}
1274		devreq.wValue = kUSBFeatureDeviceRemoteWakeup;
1275		devreq.wIndex = 0;
1276		devreq.wLength = 0;
1277		devreq.pData = 0;
1278
1279		ior = fDataInterface->GetDevice()->DeviceRequest(&devreq);
1280		if (ior == kIOReturnSuccess)
1281		{
1282			XTRACE(this, 0, ior, "setWakeOnMagicPacket - Set/Clear remote wake up feature successful");
1283		} else {
1284			XTRACE(this, 0, ior, "setWakeOnMagicPacket - Set/Clear remote wake up feature failed");
1285		}
1286    } else {
1287        XTRACE(this, 0, 0, "setWakeOnMagicPacket - Remote wake up not supported");
1288    }
1289
1290
1291    return kIOReturnSuccess;
1292
1293}/* end setWakeOnMagicPacket */
1294
1295/****************************************************************************************************/
1296//
1297//		Method:		AppleUSBCDCECMData::getPacketFilters
1298//
1299//		Inputs:		group - the filter group
1300//
1301//		Outputs:	Return code - kIOReturnSuccess and others
1302//				filters - the capability
1303//
1304//		Desc:		Set the filter capability for the driver
1305//
1306/****************************************************************************************************/
1307
1308IOReturn AppleUSBCDCECMData::getPacketFilters(const OSSymbol *group, UInt32 *filters) const
1309{
1310    IOReturn	rtn = kIOReturnSuccess;
1311
1312    XTRACEP(this, group, filters, "getPacketFilters");
1313
1314    if (group == gIOEthernetWakeOnLANFilterGroup)
1315    {
1316        if (fConfigAttributes & kUSBAtrRemoteWakeup)
1317        {
1318            *filters = kIOEthernetWakeOnMagicPacket;
1319        } else {
1320            *filters = 0;
1321        }
1322    } else {
1323        if (group == gIONetworkFilterGroup)
1324        {
1325            *filters = kIOPacketFilterUnicast | kIOPacketFilterBroadcast | kIOPacketFilterMulticast | kIOPacketFilterMulticastAll | kIOPacketFilterPromiscuous;
1326        } else {
1327            rtn = super::getPacketFilters(group, filters);
1328        }
1329    }
1330
1331    if (rtn != kIOReturnSuccess)
1332    {
1333        XTRACE(this, 0, rtn, "getPacketFilters - failed");
1334    }
1335
1336    return rtn;
1337
1338}/* end getPacketFilters */
1339
1340/****************************************************************************************************/
1341//
1342//		Method:		AppleUSBCDCECMData::getMaxPacketSize
1343//
1344//		Inputs:
1345//
1346//		Outputs:	Return code - kIOReturnSuccess or kIOReturnIOError
1347//					maxSize - the max size we currently support
1348//
1349//		Desc:		Set the max size from the descriptors of this device
1350//
1351/****************************************************************************************************/
1352
1353IOReturn AppleUSBCDCECMData::getMaxPacketSize(UInt32 *maxSize) const
1354{
1355    IOReturn	rtn = kIOReturnSuccess;
1356
1357    XTRACE(this, 0, 0, "getMaxPacketSize");
1358
1359	if (fControlDriver)
1360	{
1361		XTRACE(this, 0, fControlDriver->fMax_Block_Size, "getMaxPacketSize - Setting max size");
1362		//The CDC Spec for fMax_Block_Size does not include  the length of the CRC
1363		//IOEthernetController expects the CRC length to be included in the transfer size
1364		*maxSize = fControlDriver->fMax_Block_Size + kIOEthernetCRCSize;                //JRW <rdar://problem/14756797>
1365	} else {
1366		rtn = kIOReturnIOError;				// If we don't have a control driver by now we're in trouble...
1367		XTRACE(this, 0, 0, "getMaxPacketSize - No control driver???");
1368	}
1369
1370    return rtn;
1371
1372}/* end getMaxPacketSize */
1373
1374/****************************************************************************************************/
1375//
1376//		Method:		AppleUSBCDCECMData::selectMedium
1377//
1378//		Inputs:
1379//
1380//		Outputs:
1381//
1382//		Desc:		Lets us know if someone is playing with ifconfig
1383//
1384/****************************************************************************************************/
1385
1386IOReturn AppleUSBCDCECMData::selectMedium(const IONetworkMedium *medium)
1387{
1388    IOMediumType	mType;
1389
1390    XTRACE(this, 0, 0, "selectMedium");
1391
1392    if (fTerminate)
1393	{
1394		XTRACE(this, 0, 0, "selectMedium - Device unplugged");
1395		return kIOReturnIOError;
1396	}
1397
1398	if (!medium)
1399	{
1400		XTRACE(this, 0, 0, "selectMedium - No medium defined");
1401		return kIOReturnError;
1402	}
1403
1404	mType = medium->getType();
1405	XTRACE(this, 0, mType, "selectMedium - Type");
1406
1407	if ((mType & kIOMediumNetworkTypeMask) != kIOMediumEthernet)
1408	{
1409		XTRACE(this, 0, 0, "selectMedium - Not ethernet medium");
1410		return kIOReturnBadArgument;
1411	}
1412
1413        // Check the type (auto and none is really all we can accept)
1414
1415    switch (mType & (kIOMediumNetworkTypeMask | kIOMediumSubTypeMask))
1416	{
1417        case kIOMediumEthernetNone:
1418			XTRACE(this, 0, 0, "selectMedium - None, link going down");
1419            setSelectedMedium(medium);
1420            linkStatusChange(kLinkDown);
1421
1422            break;
1423		case kIOMediumEthernetAuto:
1424			XTRACE(this, 0, 0, "selectMedium - Auto, link going up");
1425            setSelectedMedium(medium);
1426            linkStatusChange(kLinkUp);
1427
1428            break;
1429        default:
1430			XTRACE(this, 0, 0, "selectMedium - Unsupported");
1431            return kIOReturnUnsupported;
1432    }
1433
1434    return kIOReturnSuccess;
1435
1436}/* end selectMedium */
1437
1438/****************************************************************************************************/
1439//
1440//		Method:		AppleUSBCDCECMData::getHardwareAddress
1441//
1442//		Inputs:
1443//
1444//		Outputs:	Return code - kIOReturnSuccess or kIOReturnError
1445//				ea - the address
1446//
1447//		Desc:		Get the ethernet address from the hardware (actually the descriptor)
1448//
1449/****************************************************************************************************/
1450
1451IOReturn AppleUSBCDCECMData::getHardwareAddress(IOEthernetAddress *ea)
1452{
1453    UInt32      i;
1454
1455    XTRACE(this, 0, 0, "getHardwareAddress");
1456
1457    if (fControlDriver)
1458    {
1459        for (i=0; i<6; i++)
1460        {
1461            ea->bytes[i] = fControlDriver->fEaddr[i];
1462        }
1463    } else {					// Use cached address
1464        for (i=0; i<6; i++)
1465        {
1466            ea->bytes[i] = fEthernetaddr[i];
1467        }
1468    }
1469
1470    return kIOReturnSuccess;
1471
1472}/* end getHardwareAddress */
1473
1474/****************************************************************************************************/
1475//
1476//		Method:		AppleUSBCDCECMData::newVendorString
1477//
1478//		Inputs:
1479//
1480//		Outputs:	Return code - the vendor string
1481//
1482//		Desc:		Identifies the hardware vendor
1483//
1484/****************************************************************************************************/
1485
1486const OSString* AppleUSBCDCECMData::newVendorString() const
1487{
1488
1489    XTRACE(this, 0, 0, "newVendorString");
1490
1491    return OSString::withCString((const char *)defaultName);		// Maybe we should use the descriptors
1492
1493}/* end newVendorString */
1494
1495/****************************************************************************************************/
1496//
1497//		Method:		AppleUSBCDCECMData::newModelString
1498//
1499//		Inputs:
1500//
1501//		Outputs:	Return code - the model string
1502//
1503//		Desc:		Identifies the hardware model
1504//
1505/****************************************************************************************************/
1506
1507const OSString* AppleUSBCDCECMData::newModelString() const
1508{
1509
1510    XTRACE(this, 0, 0, "newModelString");
1511
1512    return OSString::withCString("USB");		// Maybe we should use the descriptors
1513
1514}/* end newModelString */
1515
1516/****************************************************************************************************/
1517//
1518//		Method:		AppleUSBCDCECMData::newRevisionString
1519//
1520//		Inputs:
1521//
1522//		Outputs:	Return code - the revision string
1523//
1524//		Desc:		Identifies the hardware revision
1525//
1526/****************************************************************************************************/
1527
1528const OSString* AppleUSBCDCECMData::newRevisionString() const
1529{
1530
1531    XTRACE(this, 0, 0, "newRevisionString");
1532
1533    return OSString::withCString("");
1534
1535}/* end newRevisionString */
1536
1537/****************************************************************************************************/
1538//
1539//		Method:		AppleUSBCDCECMData::setMulticastMode
1540//
1541//		Inputs:		active - true (set it), false (don't)
1542//
1543//		Outputs:	Return code - kIOReturnSuccess
1544//
1545//		Desc:		Sets multicast mode
1546//
1547/****************************************************************************************************/
1548
1549IOReturn AppleUSBCDCECMData::setMulticastMode(IOEnetMulticastMode active)
1550{
1551
1552    XTRACE(this, 0, active, "setMulticastMode");
1553
1554    if (!fReady)
1555    {
1556        return kIOReturnSuccess;
1557    }
1558
1559    if (fControlDriver)
1560    {
1561        if (active)
1562        {
1563            fControlDriver->fPacketFilter |= kPACKET_TYPE_MULTICAST;
1564        } else {
1565            fControlDriver->fPacketFilter &= ~kPACKET_TYPE_MULTICAST;
1566        }
1567
1568   fControlDriver->USBSetPacketFilter();
1569
1570        return kIOReturnSuccess;
1571    }
1572
1573    return kIOReturnIOError;
1574
1575}/* end setMulticastMode */
1576
1577/****************************************************************************************************/
1578//
1579//		Method:		AppleUSBCDCECMData::setMulticastList
1580//
1581//		Inputs:		addrs - list of addresses
1582//                  count - number in the list
1583//
1584//		Outputs:	Return code - kIOReturnSuccess or kIOReturnIOError
1585//
1586//		Desc:		Sets multicast list
1587//
1588/****************************************************************************************************/
1589
1590IOReturn AppleUSBCDCECMData::setMulticastList(IOEthernetAddress *addrs, UInt32 count)
1591{
1592    bool	uStat;
1593
1594    XTRACE(this, 0, count, "setMulticastList");
1595
1596    if (!fReady)
1597    {
1598        return kIOReturnSuccess;
1599    }
1600
1601    if (fControlDriver)
1602    {
1603
1604        if (count > fControlDriver->fMcFilters)
1605        {
1606            fControlDriver->fPacketFilter |= kPACKET_TYPE_ALL_MULTICAST;
1607        }
1608        else
1609        {
1610            fControlDriver->fPacketFilter &= ~kPACKET_TYPE_ALL_MULTICAST;
1611
1612        }
1613
1614        fControlDriver->USBSetPacketFilter();
1615
1616        uStat = fControlDriver->USBSetMulticastFilter(addrs, count);
1617        if (!uStat)
1618        {
1619            return kIOReturnIOError;
1620        }
1621
1622        return kIOReturnSuccess;
1623    }
1624
1625    return kIOReturnIOError;
1626
1627}/* end setMulticastList */
1628
1629/****************************************************************************************************/
1630//
1631//		Method:		AppleUSBCDCECMData::setPromiscuousMode
1632//
1633//		Inputs:		active - true (set it), false (don't)
1634//
1635//		Outputs:	Return code - kIOReturnSuccess
1636//
1637//		Desc:		Sets promiscuous mode
1638//
1639/****************************************************************************************************/
1640
1641IOReturn AppleUSBCDCECMData::setPromiscuousMode(IOEnetPromiscuousMode active)
1642{
1643
1644    XTRACE(this, 0, active, "setPromiscuousMode");
1645
1646    if (!fReady)
1647    {
1648        return kIOReturnSuccess;
1649    }
1650
1651    if (fControlDriver)
1652    {
1653        if (active)
1654        {
1655            fControlDriver->fPacketFilter |= kPACKET_TYPE_PROMISCUOUS;
1656        } else {
1657            fControlDriver->fPacketFilter &= ~kPACKET_TYPE_PROMISCUOUS;
1658        }
1659
1660        fControlDriver->USBSetPacketFilter();
1661
1662        return kIOReturnSuccess;
1663    }
1664
1665    return kIOReturnIOError;
1666
1667}/* end setPromiscuousMode */
1668
1669/****************************************************************************************************/
1670//
1671//		Method:		AppleUSBCDCECMData::createOutputQueue
1672//
1673//		Inputs:
1674//
1675//		Outputs:	Return code - the output queue
1676//
1677//		Desc:		Creates the output queue
1678//
1679/****************************************************************************************************/
1680
1681IOOutputQueue* AppleUSBCDCECMData::createOutputQueue()
1682{
1683
1684    XTRACE(this, 0, 0, "createOutputQueue");
1685
1686    if (!fWorkLoop)
1687	{
1688		fWorkLoop = getWorkLoop();
1689		if (!fWorkLoop)
1690		{
1691			ALERT(0, 0, "createOutputQueue - getWorkLoop failed");
1692			return NULL;
1693		}
1694	}
1695
1696	return IOGatedOutputQueue::withTarget(this, fWorkLoop, TRANSMIT_QUEUE_SIZE);
1697
1698}/* end createOutputQueue */
1699
1700/****************************************************************************************************/
1701//
1702//		Method:		AppleUSBCDCECMData::outputPacket
1703//
1704//		Inputs:		mbuf - the packet
1705//				param - optional parameter
1706//
1707//		Outputs:	Return code - kIOReturnOutputSuccess or kIOReturnOutputStall
1708//
1709//		Desc:		Packet transmission. The BSD mbuf needs to be formatted correctly
1710//				and transmitted
1711//
1712/****************************************************************************************************/
1713
1714UInt32 AppleUSBCDCECMData::outputPacket(mbuf_t pkt, void *param)
1715{
1716    UInt32	ior = kIOReturnSuccess;
1717
1718    XTRACEP(this, pkt, 0, "outputPacket");
1719
1720    if (!fControlDriver)
1721    {
1722        XTRACE(this, 0, 0, "outputPacket - Control driver has gone");
1723        freePacket(pkt);
1724        return kIOReturnOutputDropped;
1725    }
1726
1727    if (fLinkStatus == kLinkDown)
1728    {
1729        XTRACEP(this, pkt, 0, "outputPacket - link is down");
1730        if (fControlDriver->fOutputErrsOK)
1731            fpNetStats->outputErrors++;
1732        freePacket(pkt);
1733        return kIOReturnOutputDropped;
1734    }
1735
1736	if (fResetState != kResetNormal)
1737	{
1738		XTRACEP(this, pkt, 0, "outputPacket - deferred reset");
1739        if (fControlDriver->fOutputErrsOK)
1740            fpNetStats->outputErrors++;
1741        freePacket(pkt);
1742		if (fResetState == kResetNeeded)
1743		{
1744			fResetState = kResetDone;
1745			fDataInterface->GetDevice()->ReEnumerateDevice(0);
1746		}
1747        return kIOReturnOutputDropped;
1748	}
1749
1750    ior = USBTransmitPacket(pkt);
1751    if (ior != kIOReturnSuccess)
1752    {
1753        if (ior == kIOReturnOutputStall)
1754        {
1755            fTxStalled = true;
1756        } else {
1757            freePacket(pkt);
1758            ior = kIOReturnOutputDropped;
1759        }
1760    }
1761
1762    return ior;
1763
1764}/* end outputPacket */
1765
1766/****************************************************************************************************/
1767//
1768//		Method:		AppleUSBCDCECMData::configureInterface
1769//
1770//		Inputs:		netif - the interface being configured
1771//
1772//		Outputs:	Return code - true (configured ok), false (not)
1773//
1774//		Desc:		Finish the network interface configuration
1775//
1776/****************************************************************************************************/
1777
1778bool AppleUSBCDCECMData::configureInterface(IONetworkInterface *netif)
1779{
1780    IONetworkData	*nd;
1781
1782    XTRACEP(this, IOThreadSelf(), netif, "configureInterface");
1783
1784    if (super::configureInterface(netif) == false)
1785    {
1786        ALERT(0, 0, "configureInterface - super failed");
1787        return false;
1788    }
1789
1790        // Get a pointer to the statistics structure in the interface
1791
1792    nd = netif->getNetworkData(kIONetworkStatsKey);
1793    if (!nd || !(fpNetStats = (IONetworkStats *)nd->getBuffer()))
1794    {
1795        ALERT(0, 0, "configureInterface - Invalid network statistics");
1796        return false;
1797    }
1798
1799        // Get the Ethernet statistics structure
1800
1801    nd = netif->getParameter(kIOEthernetStatsKey);
1802    if (!nd || !(fpEtherStats = (IOEthernetStats*)nd->getBuffer()))
1803    {
1804        ALERT(0, 0, "configureInterface - Invalid ethernet statistics\n");
1805        return false;
1806    }
1807
1808    return true;
1809
1810}/* end configureInterface */
1811
1812/****************************************************************************************************/
1813//
1814//		Method:		AppleUSBCDCECMData::wakeUp
1815//
1816//		Inputs:
1817//
1818//		Outputs:	Return Code - true(we're awake), false(failed)
1819//
1820//		Desc:		Resumes the device it it was suspended and then gets all the data
1821//				structures sorted out and all the pipes ready.
1822//
1823/****************************************************************************************************/
1824
1825bool AppleUSBCDCECMData::wakeUp()
1826{
1827    IOReturn 	rtn = kIOReturnSuccess;
1828    UInt32	i;
1829    bool	readOK = false;
1830
1831    XTRACE(this, 0, 0, "wakeUp");
1832
1833	if (fEnumOnWake)
1834    {
1835        if ((fSleeping) && (fDataInterface))
1836        {
1837            fDataInterface->GetDevice()->ReEnumerateDevice(0);
1838            return false;
1839        }
1840    }
1841
1842    fDataInterface->GetDevice()->SuspendDevice(false);
1843
1844    fReady = false;
1845
1846    if (fTimerSource)
1847    {
1848        fTimerSource->cancelTimeout();
1849    }
1850
1851    if (!allocateResources())
1852    {
1853        ALERT(0, 0, "wakeUp - allocateResources failed");
1854    	return false;
1855    }
1856
1857        // Kick off the data-in bulk pipe reads
1858
1859    for (i=0; i<fInBufPool; i++)
1860    {
1861        if (fPipeInBuff[i].pipeInMDP)
1862        {
1863//            fPipeInBuff[i].readCompletionInfo.parameter = (void *)i;
1864			fPipeInBuff[i].readCompletionInfo.parameter = (void *)&fPipeInBuff[i];
1865            rtn = fInPipe->Read(fPipeInBuff[i].pipeInMDP, &fPipeInBuff[i].readCompletionInfo, NULL);
1866            if (rtn == kIOReturnSuccess)
1867            {
1868                readOK = true;
1869            } else {
1870                XTRACE(this, i, rtn, "wakeUp - Read failed");
1871            }
1872        }
1873    }
1874
1875    if (!readOK)
1876    {
1877
1878    	// We failed for some reason
1879
1880        ALERT(0, 0, "wakeUp - Starting the input pipe read(s) failed");
1881        return false;
1882    } else {
1883        if (!fMediumDict)
1884        {
1885            if (!createMediumTables())
1886            {
1887                ALERT(0, 0, "wakeUp - createMediumTables failed");
1888                return false;
1889            }
1890        }
1891
1892		if (fTimerSource)
1893		{
1894			fTimerSource->setTimeoutMS(WATCHDOG_TIMER_MS);
1895		}
1896        fReady = true;
1897    }
1898
1899	fSleeping = false;
1900
1901    return true;
1902
1903}/* end wakeUp */
1904
1905/****************************************************************************************************/
1906//
1907//		Method:		AppleUSBCDCECMData::putToSleep
1908//
1909//		Inputs:
1910//
1911//		Outputs:	Return Code - true(we're asleep), false(failed)
1912//
1913//		Desc:		Do clean up and suspend the device.
1914//
1915/****************************************************************************************************/
1916
1917void AppleUSBCDCECMData::putToSleep()
1918{
1919    XTRACE(this, 0, 0, "putToSleep >>>");
1920
1921	if ( (!fReady) || (fTerminate == true))							// We've been here before...
1922	{
1923		return;
1924	}
1925
1926    fReady = false;
1927
1928		// Abort any outstanding I/O
1929
1930	if (fInPipe)
1931		fInPipe->Abort();
1932	if (fOutPipe)
1933		fOutPipe->Abort();
1934
1935    if (fTimerSource)
1936    {
1937        fTimerSource->cancelTimeout();
1938    }
1939
1940    releaseResources();
1941    linkStatusChange(kLinkDown);
1942	fSleeping = true;
1943
1944}/* end putToSleep */
1945
1946/****************************************************************************************************/
1947//
1948//		Method:		AppleUSBCDCECMData::createMediumTables
1949//
1950//		Inputs:
1951//
1952//		Outputs:	Return code - true (tables created), false (not created)
1953//
1954//		Desc:		Creates the medium tables
1955//
1956/****************************************************************************************************/
1957
1958bool AppleUSBCDCECMData::createMediumTables()
1959{
1960    IONetworkMedium	*medium;
1961    UInt64		maxSpeed;
1962    UInt32		i;
1963
1964    XTRACE(this, 0, 0, "createMediumTables");
1965
1966    maxSpeed = 1000;
1967    fMediumDict = OSDictionary::withCapacity(sizeof(mediumTable) / sizeof(mediumTable[0]));
1968    if (fMediumDict == 0)
1969    {
1970        XTRACE(this, 0, 0, "createMediumTables - create dict. failed");
1971        return false;
1972    }
1973
1974    for (i = 0; i < sizeof(mediumTable) / sizeof(mediumTable[0]); i++)
1975    {
1976        medium = IONetworkMedium::medium(mediumTable[i].type, mediumTable[i].speed);
1977        if (medium && (medium->getSpeed() <= maxSpeed))
1978        {
1979            IONetworkMedium::addMedium(fMediumDict, medium);
1980            medium->release();
1981        }
1982    }
1983
1984    if (publishMediumDictionary(fMediumDict) != true)
1985    {
1986        XTRACE(this, 0, 0, "createMediumTables - publish dict. failed");
1987        return false;
1988    }
1989
1990    medium = IONetworkMedium::getMediumWithType(fMediumDict, kIOMediumEthernetAuto);
1991    setCurrentMedium(medium);
1992
1993    return true;
1994
1995}/* end createMediumTables */
1996
1997/****************************************************************************************************/
1998//
1999//		Method:		AppleUSBCDCECMData::allocateResources
2000//
2001//		Inputs:
2002//
2003//		Outputs:	return code - true (allocate was successful), false (it failed)
2004//
2005//		Desc:		Gets all the endpoints open and buffers allocated etc.
2006//
2007/****************************************************************************************************/
2008
2009bool AppleUSBCDCECMData::allocateResources()
2010{
2011    IOUSBFindEndpointRequest		epReq;
2012    UInt32				i;
2013
2014    XTRACE(this, 0, 0, "allocateResources.");
2015
2016		// Check things are still around (waking from sleep)
2017
2018	if (!fDataInterface)
2019	{
2020		XTRACE(this, 0, 0, "allocateResources - No data interface");
2021		return false;
2022	}
2023
2024	if (!fControlDriver)
2025	{
2026		XTRACE(this, 0, 0, "allocateResources - No control driver");
2027		return false;
2028	}
2029
2030        // Open all the end points
2031
2032    epReq.type = kUSBBulk;
2033    epReq.direction = kUSBIn;
2034    epReq.maxPacketSize	= 0;
2035    epReq.interval = 0;
2036    fInPipe = fDataInterface->FindNextPipe(0, &epReq);
2037    if (!fInPipe)
2038    {
2039        XTRACE(this, 0, 0, "allocateResources - no bulk input pipe.");
2040        return false;
2041    }
2042    XTRACE(this, epReq.maxPacketSize << 16 |epReq.interval, 0, "allocateResources - bulk input pipe.");
2043
2044    epReq.direction = kUSBOut;
2045    fOutPipe = fDataInterface->FindNextPipe(0, &epReq);
2046    if (!fOutPipe)
2047    {
2048        XTRACE(this, 0, 0, "allocateResources - no bulk output pipe.");
2049        return false;
2050    }
2051    fOutPacketSize = epReq.maxPacketSize;
2052    XTRACE(this, epReq.maxPacketSize << 16 |epReq.interval, 0, "allocateResources - bulk output pipe.");
2053
2054        // Allocate Memory Descriptor Pointer with memory for the data-in bulk pipe
2055
2056    for (i=0; i<fInBufPool; i++)
2057    {
2058//        fPipeInBuff[i].pipeInMDP = IOBufferMemoryDescriptor::withCapacity(fControlDriver->fMax_Block_Size, kIODirectionIn);
2059        fPipeInBuff[i].pipeInMDP = IOBufferMemoryDescriptor::withOptions(kIODirectionIn | kIOMemoryPhysicallyContiguous, fControlDriver->fMax_Block_Size, PAGE_SIZE);
2060        if (!fPipeInBuff[i].pipeInMDP)
2061        {
2062            XTRACE(this, 0, i, "allocateResources - Allocate input descriptor failed");
2063            return false;
2064        }
2065
2066        fPipeInBuff[i].pipeInMDP->setLength(fControlDriver->fMax_Block_Size);
2067        fPipeInBuff[i].pipeInBuffer = (UInt8*)fPipeInBuff[i].pipeInMDP->getBytesNoCopy();
2068        XTRACEP(this, fPipeInBuff[i].pipeInMDP, fPipeInBuff[i].pipeInBuffer, "allocateResources - input buffer");
2069        fPipeInBuff[i].dead = false;
2070        fPipeInBuff[i].readCompletionInfo.target = this;
2071        fPipeInBuff[i].readCompletionInfo.action = dataReadComplete;
2072        fPipeInBuff[i].readCompletionInfo.parameter = NULL;
2073    }
2074
2075        // Allocate Memory Descriptor Pointers with memory for the data-out bulk pipe pool
2076
2077    for (i=0; i<fOutBufPool; i++)
2078    {
2079//        fPipeOutBuff[i].pipeOutMDP = IOBufferMemoryDescriptor::withCapacity(fControlDriver->fMax_Block_Size, kIODirectionOut);
2080        fPipeOutBuff[i].pipeOutMDP = IOBufferMemoryDescriptor::withOptions(kIODirectionOut | kIOMemoryPhysicallyContiguous, fControlDriver->fMax_Block_Size, PAGE_SIZE);
2081        if (!fPipeOutBuff[i].pipeOutMDP)
2082        {
2083            XTRACE(this, 0, i, "allocateResources - Allocate output descriptor failed");
2084            return false;
2085        }
2086
2087        fPipeOutBuff[i].pipeOutMDP->setLength(fControlDriver->fMax_Block_Size);
2088        fPipeOutBuff[i].pipeOutBuffer = (UInt8*)fPipeOutBuff[i].pipeOutMDP->getBytesNoCopy();
2089        XTRACEP(this, fPipeOutBuff[i].pipeOutMDP, fPipeOutBuff[i].pipeOutBuffer, "allocateResources - output buffer");
2090        fPipeOutBuff[i].avail = true;
2091        fPipeOutBuff[i].writeCompletionInfo.target = this;
2092        fPipeOutBuff[i].writeCompletionInfo.action = dataWriteComplete;
2093        fPipeOutBuff[i].writeCompletionInfo.parameter = NULL;				// for now, filled in with pool index when sent
2094    }
2095
2096    return true;
2097
2098}/* end allocateResources */
2099
2100/****************************************************************************************************/
2101//
2102//		Method:		AppleUSBCDCECMData::releaseResources
2103//
2104//		Inputs:
2105//
2106//		Outputs:
2107//
2108//		Desc:		Frees up the resources allocated in allocateResources
2109//
2110/****************************************************************************************************/
2111
2112void AppleUSBCDCECMData::releaseResources()
2113{
2114    UInt32	i;
2115
2116    XTRACE(this, 0, 0, "releaseResources");
2117
2118    for (i=0; i<fOutBufPool; i++)
2119    {
2120        if (fPipeOutBuff[i].pipeOutMDP)
2121        {
2122            fPipeOutBuff[i].pipeOutMDP->release();
2123            fPipeOutBuff[i].pipeOutMDP = NULL;
2124            fPipeOutBuff[i].avail = false;
2125            fPipeOutBuff[i].writeCompletionInfo.target = NULL;
2126            fPipeOutBuff[i].writeCompletionInfo.action = NULL;
2127            fPipeOutBuff[i].writeCompletionInfo.parameter = NULL;
2128        }
2129    }
2130    fOutPoolIndex = 0;
2131
2132    for (i=0; i<fInBufPool; i++)
2133    {
2134        if (fPipeInBuff[i].pipeInMDP)
2135        {
2136            fPipeInBuff[i].pipeInMDP->release();
2137            fPipeInBuff[i].pipeInMDP = NULL;
2138            fPipeInBuff[i].dead = false;
2139            fPipeInBuff[i].readCompletionInfo.target = NULL;
2140            fPipeInBuff[i].readCompletionInfo.action = NULL;
2141            fPipeInBuff[i].readCompletionInfo.parameter = NULL;
2142        }
2143    }
2144
2145}/* end releaseResources */
2146
2147/****************************************************************************************************/
2148//
2149//		Method:		AppleUSBCDCECMData::getOutputBuffer
2150//
2151//		Inputs:		bufIndx - index of an available buffer
2152//
2153//		Outputs:	Return code - True (got one), False (none available)
2154//
2155//		Desc:		Get an available buffer from the output buffer pool
2156//
2157/****************************************************************************************************/
2158
2159bool AppleUSBCDCECMData::getOutputBuffer(UInt32 *bufIndx)
2160{
2161	bool	gotBuffer = false;
2162	UInt32	indx = 0;
2163
2164	XTRACE(this, 0, 0, "getOutputBuffer");
2165
2166		// Get an ouput buffer (use the hint first then if that's not available look for one and then create one...)
2167
2168	indx = fOutPoolIndex;
2169	if (!fPipeOutBuff[indx].avail)
2170	{
2171		for (indx=0; indx<fOutBufPool; indx++)
2172		{
2173			if (fPipeOutBuff[indx].avail)
2174			{
2175				fOutPoolIndex = indx;
2176				gotBuffer = true;
2177				break;
2178			}
2179		}
2180	} else {
2181		gotBuffer = true;
2182	}
2183
2184	if (gotBuffer)
2185	{
2186		fPipeOutBuff[indx].avail = false;
2187		fOutPoolIndex++;
2188		if (fOutPoolIndex >= fOutBufPool)
2189		{
2190			fOutPoolIndex = 0;
2191		}
2192	} else {
2193		if (fOutBufPool >= kMaxOutBufPool)
2194		{
2195			ALERT(kMaxOutBufPool, fOutBufPool, "getOutputBuffer - Output buffer pool empty");
2196			indx = 0;
2197			gotBuffer = false;
2198		} else {
2199			XTRACE(this, 0, fOutBufPool, "getOutputBuffer - Adding output buffer to pool");
2200
2201				// Create a new one (should never really get here - maybe very very heavy transmit traffic)
2202
2203			indx = fOutBufPool;
2204			fPipeOutBuff[indx].pipeOutMDP = IOBufferMemoryDescriptor::withCapacity(fControlDriver->fMax_Block_Size, kIODirectionOut);
2205			if (!fPipeOutBuff[indx].pipeOutMDP)
2206			{
2207				XTRACE(this, 0, indx, "getOutputBuffer - Allocate output descriptor failed");
2208				gotBuffer = false;
2209				indx = 0;
2210			} else {
2211				fPipeOutBuff[indx].pipeOutMDP->setLength(fControlDriver->fMax_Block_Size);
2212				fPipeOutBuff[indx].pipeOutBuffer = (UInt8*)fPipeOutBuff[indx].pipeOutMDP->getBytesNoCopy();
2213				XTRACEP(this, fPipeOutBuff[indx].pipeOutMDP, fPipeOutBuff[indx].pipeOutBuffer, "getOutputBuffer - output buffer");
2214				fPipeOutBuff[indx].avail = false;
2215				fPipeOutBuff[indx].writeCompletionInfo.target = this;
2216				fPipeOutBuff[indx].writeCompletionInfo.action = dataWriteComplete;
2217				fPipeOutBuff[indx].writeCompletionInfo.parameter = NULL;
2218				fPipeOutBuff[indx].indx = indx;
2219				fOutBufPool++;
2220				fOutPoolIndex = 0;
2221				gotBuffer = true;
2222			}
2223		}
2224	}
2225
2226	*bufIndx = indx;
2227
2228	return gotBuffer;
2229
2230}/* end getOutputBuffer */
2231
2232/****************************************************************************************************/
2233//
2234//		Method:		AppleUSBCDCECMData::USBTransmitPacket
2235//
2236//		Inputs:		packet - the packet
2237//
2238//		Outputs:	Return code - kIOReturnSuccess (transmit started), everything else (it didn't)
2239//
2240//		Desc:		Set up and then transmit the packet.
2241//
2242/****************************************************************************************************/
2243
2244IOReturn AppleUSBCDCECMData::USBTransmitPacket(mbuf_t packet)
2245{
2246    UInt32		numbufs = 0;			// number of mbufs for this packet
2247    mbuf_t		m;						// current mbuf
2248    UInt32		total_pkt_length = 0;
2249    UInt32		rTotal = 0;
2250    IOReturn	ior = kIOReturnSuccess;
2251    UInt32		indx;
2252
2253    XTRACEP(this, 0, packet, "USBTransmitPacket");
2254
2255	if (fDeferredClear)
2256	{
2257		ior = clearPipeStall(fOutPipe);
2258		if (ior != kIOReturnSuccess)
2259		{
2260			XTRACE(this, 0, ior, "USBTransmitPacket - clear stall failed (trying to continue)");
2261		}
2262		fDeferredClear = false;
2263	}
2264
2265		// Count the number of mbufs in this packet
2266
2267	m = packet;
2268    while (m)
2269	{
2270		if (mbuf_len(m) != 0)
2271		{
2272			total_pkt_length += mbuf_len(m);
2273			numbufs++;
2274		}
2275		m = mbuf_next(m);
2276    }
2277
2278    XTRACE(this, total_pkt_length, numbufs, "USBTransmitPacket - Total packet length and Number of mbufs");
2279
2280    if (total_pkt_length > fControlDriver->fMax_Block_Size)
2281    {
2282        XTRACE(this, 0, 0, "USBTransmitPacket - Bad packet size");	// Note for now and revisit later
2283        if (fControlDriver->fOutputErrsOK)
2284            fpNetStats->outputErrors++;
2285        return kIOReturnOutputDropped;
2286    }
2287
2288    if (!getOutputBuffer(&indx))
2289    {
2290        ALERT(fOutBufPool, fOutPoolIndex, "USBTransmitPacket - Output buffer unavailable");
2291        return kIOReturnOutputStall;
2292    }
2293
2294        // Start filling in the send buffer
2295
2296    m = packet;							// start with the first mbuf of the packet
2297    rTotal = 0;							// running total
2298    do
2299    {
2300        if (mbuf_len(m) == 0)			// Ignore zero length buffers
2301			continue;
2302
2303        bcopy(mbuf_data(m), &fPipeOutBuff[indx].pipeOutBuffer[rTotal], mbuf_len(m));
2304        rTotal += mbuf_len(m);
2305
2306    } while ((m = mbuf_next(m)) != 0);
2307
2308    LogData(kDataOut, rTotal, fPipeOutBuff[indx].pipeOutBuffer);
2309
2310    fPipeOutBuff[indx].m = packet;
2311	fPipeOutBuff[indx].writeCompletionInfo.parameter = (void *)&fPipeOutBuff[indx];
2312
2313	ior = fOutPipe->Write(fPipeOutBuff[indx].pipeOutMDP, 2000, 5000, rTotal, &fPipeOutBuff[indx].writeCompletionInfo);
2314    if (ior != kIOReturnSuccess)
2315    {
2316        XTRACE(this, 0, ior, "USBTransmitPacket - Write failed");
2317        if (ior == kIOUSBPipeStalled)
2318        {
2319//            fOutPipe->Reset();
2320            clearPipeStall(fOutPipe);
2321			ior = fOutPipe->Write(fPipeOutBuff[indx].pipeOutMDP, 2000, 5000, rTotal, &fPipeOutBuff[indx].writeCompletionInfo);
2322            if (ior != kIOReturnSuccess)
2323            {
2324                XTRACE(this, 0, ior, "USBTransmitPacket - Write really failed");
2325                if (fControlDriver->fOutputErrsOK)
2326                    fpNetStats->outputErrors++;
2327
2328				fPipeOutBuff[indx].avail = true;
2329                return ior;
2330            }
2331        } else {
2332			if (fControlDriver->fOutputErrsOK)
2333				fpNetStats->outputErrors++;
2334
2335			fPipeOutBuff[indx].avail = true;
2336			return ior;
2337		}
2338    }
2339
2340    if (fControlDriver->fOutputPktsOK)
2341        fpNetStats->outputPackets++;
2342
2343    return ior;
2344
2345}/* end USBTransmitPacket */
2346
2347/****************************************************************************************************/
2348//
2349//		Method:		AppleUSBCDCECMData::clearPipeStall
2350//
2351//		Inputs:		thePipe - the pipe
2352//
2353//		Outputs:
2354//
2355//		Desc:		Clear a stall on the specified pipe.
2356//
2357/****************************************************************************************************/
2358
2359IOReturn AppleUSBCDCECMData::clearPipeStall(IOUSBPipe *thePipe)
2360{
2361    IOReturn 	rtn = kIOReturnSuccess;
2362
2363    XTRACEP(this, 0, thePipe, "clearPipeStall");
2364
2365//    rtn = thePipe->GetPipeStatus();
2366//    if (rtn == kIOUSBPipeStalled)
2367//    {
2368        rtn = thePipe->ClearPipeStall(true);
2369        if (rtn == kIOReturnSuccess)
2370        {
2371            XTRACE(this, 0, 0, "clearPipeStall - Successful");
2372        } else {
2373            XTRACE(this, 0, rtn, "clearPipeStall - Failed");
2374        }
2375//    } else {
2376//        XTRACE(this, 0, 0, "clearPipeStall - Pipe not stalled");
2377 //   }
2378
2379    return rtn;
2380
2381}/* end clearPipeStall */
2382
2383/****************************************************************************************************/
2384//
2385//		Method:		AppleUSBCDCECMData::receivePacket
2386//
2387//		Inputs:		packet - the packet
2388//				size - Number of bytes in the packet
2389//
2390//		Outputs:
2391//
2392//		Desc:		Build the mbufs and then send to the network stack.
2393//
2394/****************************************************************************************************/
2395
2396void AppleUSBCDCECMData::receivePacket(UInt8 *packet, UInt32 size)
2397{
2398    mbuf_t		m;
2399    errno_t     err;
2400    UInt32		submit;
2401
2402    XTRACE(this, 0, size, "receivePacket");
2403
2404    if (!fControlDriver)
2405    {
2406        XTRACE(this, 0, 0, "receivePacket - Control driver has gone, packet dropped");
2407        return;
2408    }
2409
2410    if (size > fControlDriver->fMax_Block_Size)
2411    {
2412        XTRACE(this, 0, 0, "receivePacket - Packet size error, packet dropped");
2413        if (fControlDriver->fInputErrsOK)
2414            fpNetStats->inputErrors++;
2415        return;
2416    }
2417
2418    m = allocatePacket(size);
2419    if (m)
2420    {
2421        err = mbuf_copyback(m, 0, size, packet, MBUF_DONTWAIT);
2422        if (err)
2423        {
2424            XTRACE(this, 0, err, "receivePacket - Buffer copy failed, packet dropped");
2425            if (fControlDriver->fInputErrsOK)
2426                fpNetStats->inputErrors++;
2427            freePacket(m);
2428            return;
2429        }
2430//        bcopy(packet, mbuf_data(m), size);
2431        submit = fNetworkInterface->inputPacket(m, size);
2432        XTRACE(this, 0, submit, "receivePacket - Packets submitted");
2433        if (fControlDriver->fInputPktsOK)
2434            fpNetStats->inputPackets++;
2435    } else {
2436        XTRACE(this, 0, 0, "receivePacket - Buffer allocation failed, packet dropped");
2437        if (fControlDriver->fInputErrsOK)
2438            fpNetStats->inputErrors++;
2439    }
2440
2441}/* end receivePacket */
2442
2443/****************************************************************************************************/
2444//
2445//		Method:		AppleUSBCDCECMData::linkStatusChange
2446//
2447//		Inputs:		linkState - 0=down, 1=up
2448//
2449//		Outputs:
2450//
2451//		Desc:		Notification from the control driver (or wherever) of the link state
2452//
2453/****************************************************************************************************/
2454void AppleUSBCDCECMData::linkStatusChange(UInt8 linkState)
2455{
2456
2457	XTRACE(this, 0, linkState, "linkStatusChange");
2458
2459    // Check the state actually changed
2460
2461	if (fLinkStatus != linkState)
2462	{
2463		XTRACE(this, 0, linkState, "linkStatusChange - State has changed");
2464
2465        fLinkStatus = linkState;
2466
2467		if (linkState == kLinkUp)
2468		{
2469            setLinkStatusUp();
2470
2471            // Start our IOOutputQueue object if not already started
2472
2473			if (fTransmitQueue)
2474			{
2475                if (!fQueueStarted)
2476                {
2477                    fTransmitQueue->setCapacity(TRANSMIT_QUEUE_SIZE);
2478                    XTRACE(this, 0, TRANSMIT_QUEUE_SIZE, "linkStatusChange - capacity set");
2479
2480                    fTransmitQueue->start();
2481                    XTRACE(this, 0, 0, "linkStatusChange - transmit queue started");
2482
2483                    fQueueStarted = true;
2484                }
2485			}
2486		} else {
2487            if (fQueueStarted)
2488            {
2489                fTransmitQueue->stop();
2490
2491                // Flush all packets currently in the output queue
2492
2493                fTransmitQueue->setCapacity(0);
2494                fTransmitQueue->flush();
2495
2496                fQueueStarted = false;
2497            }
2498            setLinkStatusDown();
2499		}
2500	}
2501
2502}/* end linkStatusChange */
2503
2504/****************************************************************************************************/
2505//
2506//		Method:		AppleUSBCDCECMData::linkSpeedChange
2507//
2508//		Inputs:		upSpeed - in bits/second (already converted to host format)
2509//					downSpeed - in bits/second (already converted to host format)
2510//
2511//		Outputs:
2512//
2513//		Desc:		Notification from the control driver of the link speed
2514//
2515/****************************************************************************************************/
2516void AppleUSBCDCECMData::linkSpeedChange(UInt32 upSpeed, UInt32 downSpeed)
2517{
2518	UInt32			speed;
2519
2520	XTRACE(this, upSpeed, downSpeed, "linkSpeedChange");
2521
2522	fUpSpeed = upSpeed;
2523    fDownSpeed = downSpeed;
2524
2525	//IOEthernetController does not handle asymmetric speeds. So pick the min speed as worst case scenario for traffic shaping.
2526	 speed = min(fDownSpeed,fUpSpeed);
2527
2528    if ((fLinkStatus != kLinkUp) && (speed != 0))
2529    {
2530        linkStatusChange(kLinkUp); // force link up
2531    }
2532
2533}/* end linkSpeedChange */
2534
2535/****************************************************************************************************/
2536//
2537//		Method:		AppleUSBCDCECMData::setLinkStatusUp
2538//
2539//		Inputs:
2540//
2541//		Outputs:
2542//
2543//		Desc:		Set our link status to up
2544//
2545/****************************************************************************************************/
2546void AppleUSBCDCECMData::setLinkStatusUp()
2547{
2548    IONetworkMedium	*medium;
2549    IOMediumType	mediumType = 0;
2550	UInt64			speed;
2551    char            line[256];
2552    UInt32          linkSpeed;
2553    UInt16          regs[LinkUp_Phy_Count] = {0, 0, 0, 0, 0, 0};
2554    LinkUpFlow      flowState = kLinkUpFlow_None;
2555    bool            fullduplex;
2556    char            portNameBuffer[5];
2557    OSNumber        *usbPortNumber;
2558    char            *portName = NULL;
2559
2560    XTRACE(this, fUpSpeed, fDownSpeed, "setLinkStatusUp");
2561
2562    if (fLinkStatus != kLinkUp)
2563    {
2564        XTRACE(this, 0, 0, "setLinkStatusUp linkspeed is 0 +");
2565        return;
2566    }
2567
2568		// We'll default to FDX and use the higher speed
2569
2570	mediumType = kIOMediumOptionFullDuplex;
2571	fullduplex = true;
2572
2573    speed = max(fUpSpeed,fDownSpeed);
2574
2575    linkSpeed = speed/1000000;           // Need this in mbits
2576
2577    XTRACE(this, speed, linkSpeed, "speed, linkSpeed mbps+++");
2578
2579    switch (linkSpeed) {
2580
2581        case 0:
2582            mediumType |= kIOMediumEthernetNone;
2583            fLinkStatus = kLinkDown;
2584            XTRACE(this, speed, linkSpeed, "setLinkStatusUp linkspeed is 0 +");
2585            return;
2586
2587        case 10:
2588            mediumType |= kIOMediumEthernet10BaseT;
2589            break;
2590
2591        case 100:
2592            mediumType |= kIOMediumEthernet100BaseTX;
2593            break;
2594
2595        case 1000:
2596            mediumType |= kIOMediumEthernet1000BaseTX;
2597            break;
2598
2599        default:
2600            mediumType |= kIOMediumEthernet10BaseT;
2601            XTRACE(this, speed, linkSpeed, "default linkspeed+");
2602            linkSpeed = 10;                 //Force to 10 Mbps
2603            speed = linkSpeed*1000000;      //Corresponding value in bits per second
2604           break;
2605    }
2606
2607
2608    // Get the port number
2609
2610    usbPortNumber = OSDynamicCast(OSNumber, fDataInterface->GetDevice()->getProperty("PortNum"));
2611    if (usbPortNumber)
2612    {
2613        snprintf(portNameBuffer, sizeof(portNameBuffer), "%d", usbPortNumber->unsigned16BitValue());
2614        portName = portNameBuffer;
2615    }
2616
2617    // Get some debug info. (none at the moment)
2618
2619    regs[0] = 0;
2620    regs[1] = 0;
2621    regs[2] = 0;
2622    regs[3] = 0;
2623    regs[4] = 0;
2624    regs[5] = 0;
2625
2626    // Now print it
2627
2628    ::LinkUpMessage(line, sizeof(line),         // std link up msg to line buffer
2629                    NULL,                       // get kext name from kmodinfo
2630                    fNetworkInterface,			// where to get the en name
2631                    linkSpeed,                  // speed in mbits
2632                    fullduplex,					// boolean for full/half duplex
2633                    flowState,					// flow control type
2634                    portName,					// port name or NULL
2635                    regs,						// array of 6 useful registers to log
2636                    NULL);                      // string of loopback type or NULL
2637#if USE_ELG
2638        Log("%s\n", line);                          // Above goes to IOLog, send a copy to firewire if debug enabled
2639#endif
2640
2641
2642    medium = IONetworkMedium::getMediumWithType(fMediumDict, mediumType);
2643
2644    XTRACE(this, 0, mediumType, "setLinkStatusUp - LinkStatus set");
2645
2646    setLinkStatus(kIONetworkLinkActive | kIONetworkLinkValid, medium, speed);
2647
2648}/* end setLinkStatusUp */
2649
2650/****************************************************************************************************/
2651//
2652//		Method:		AppleUSBCDCECMData::setLinkStatusDown
2653//
2654//		Inputs:
2655//
2656//		Outputs:
2657//
2658//		Desc:		Set our link status to down
2659//
2660/****************************************************************************************************/
2661void AppleUSBCDCECMData::setLinkStatusDown()
2662{
2663
2664    XTRACE(this, 0, 0, "setLinkStatusDown");
2665
2666    // Set our status to inactive, with the current medium set to 'none'
2667
2668	setLinkStatus(kIONetworkLinkValid, IONetworkMedium::getMediumWithType(fMediumDict, kIOMediumEthernetNone));
2669
2670    // Log it if we need to
2671
2672    if (fNetworkInterface)
2673    {
2674        Log("Ethernet [%s]: Link down on %s%d\n", DEBUG_NAME, fNetworkInterface->getNamePrefix(), fNetworkInterface->getUnitNumber());
2675    } else {
2676        Log("Ethernet [%s]: Link down\n", DEBUG_NAME);
2677    }
2678
2679	fLinkStatus = kLinkDown;
2680    linkSpeedChange(0,0);                   //Force Link Speed to Zero
2681
2682}/* end setLinkStatusDown */
2683
2684/****************************************************************************************************/
2685//
2686//		Method:		AppleUSBCDCECMData::timerFired
2687//
2688//		Inputs:
2689//
2690//		Outputs:
2691//
2692//		Desc:		Static member function called when a timer event fires.
2693//
2694/****************************************************************************************************/
2695void AppleUSBCDCECMData::timerFired(OSObject *owner, IOTimerEventSource *sender)
2696{
2697
2698//    XTRACE(this, 0, 0, "timerFired");
2699
2700    if (owner)
2701    {
2702	AppleUSBCDCECMData* target = OSDynamicCast(AppleUSBCDCECMData, owner);
2703
2704	if (target)
2705	{
2706	    target->timeoutOccurred(sender);
2707	}
2708    }
2709
2710}/* end timerFired */
2711
2712/****************************************************************************************************/
2713//
2714//		Method:		AppleUSBCDCECMData::timeoutOccurred
2715//
2716//		Inputs:
2717//
2718//		Outputs:
2719//
2720//		Desc:		Timeout handler, used for stats gathering.
2721//
2722/****************************************************************************************************/
2723
2724void AppleUSBCDCECMData::timeoutOccurred(IOTimerEventSource * /*timer*/)
2725{
2726    bool		statsOK = false;
2727
2728//    XTRACE(this, 0, 0, "timeoutOccurred");
2729
2730    if (fControlDriver)
2731    {
2732        statsOK = fControlDriver->statsProcessing();
2733    }
2734
2735    if (statsOK)
2736    {
2737
2738            // Restart the watchdog timer
2739
2740        fTimerSource->setTimeoutMS(WATCHDOG_TIMER_MS);
2741    }
2742
2743}/* end timeoutOccurred */
2744
2745
2746
2747bool AppleUSBCDCECMData::willTerminate( IOService * provider, IOOptionBits options )
2748{
2749    bool result = true;
2750    Log(DEBUG_NAME ":willTerminate\n");
2751
2752    fTerminate = true;
2753    return result;
2754}
2755
2756
2757/****************************************************************************************************/
2758//
2759//		Method:		AppleUSBCDCECMData::message
2760//
2761//		Inputs:		type - message type
2762//				provider - my provider
2763//				argument - additional parameters
2764//
2765//		Outputs:	return Code - kIOReturnSuccess
2766//
2767//		Desc:		Handles IOKit messages.
2768//
2769/****************************************************************************************************/
2770
2771IOReturn AppleUSBCDCECMData::message(UInt32 type, IOService *provider, void *argument)
2772{
2773    UInt16	i;
2774    IOReturn	ior;
2775
2776    XTRACE(this, 0, type, "message");
2777
2778    switch (type)
2779    {
2780        case kIOMessageServiceIsTerminated:
2781            XTRACE(this, fReady, type, "message - kIOMessageServiceIsTerminated");
2782#if 0
2783				// As a precaution abort any outstanding I/O
2784
2785			if (fInPipe)
2786				fInPipe->Abort();
2787			if (fOutPipe)
2788				fOutPipe->Abort();
2789#endif
2790
2791            if (fReady)
2792            {
2793                if (!fTerminate)		// Check if we're already being terminated
2794                {
2795#if 0
2796		    // NOTE! This call below depends on the hard coded path of this KEXT. Make sure
2797		    // that if the KEXT moves, this path is changed!
2798		    KUNCUserNotificationDisplayNotice(
2799			10,		// Timeout in seconds
2800			0,		// Flags (for later usage)
2801			"",		// iconPath (not supported yet)
2802			"",		// soundPath (not supported yet)
2803			"/System/Library/Extensions/IOUSBFamily.kext/Contents/PlugIns/AppleUSBCDCECMData.kext",	// localizationPath
2804			"Unplug Header",		// the header
2805			"Unplug Notice",		// the notice - look in Localizable.strings
2806			"OK");
2807#endif
2808                }
2809            }
2810
2811			putToSleep();
2812
2813//            releaseResources();
2814
2815            if (fDataInterface)
2816            {
2817                fDataInterface->close(this);
2818                fDataInterface->release();
2819                fDataInterface = NULL;
2820            }
2821            fTerminate = true;              // we're being terminated (unplugged)
2822            linkStatusChange(kLinkDown);    // and of course we're offline
2823            return kIOReturnSuccess;
2824        case kIOMessageServiceIsSuspended:
2825            XTRACE(this, 0, type, "message - kIOMessageServiceIsSuspended");
2826            break;
2827        case kIOMessageServiceIsResumed:
2828            XTRACE(this, 0, type, "message - kIOMessageServiceIsResumed");
2829            break;
2830        case kIOMessageServiceIsRequestingClose:
2831            XTRACE(this, 0, type, "message - kIOMessageServiceIsRequestingClose");
2832            break;
2833        case kIOMessageServiceWasClosed:
2834            XTRACE(this, 0, type, "message - kIOMessageServiceWasClosed");
2835            break;
2836        case kIOMessageServiceBusyStateChange:
2837            XTRACE(this, 0, type, "message - kIOMessageServiceBusyStateChange");
2838            break;
2839        case kIOUSBMessagePortHasBeenResumed:
2840            XTRACE(this, 0, type, "message - kIOUSBMessagePortHasBeenResumed");
2841
2842            ior = fDataInterface->SetAlternateInterface(this, fAltInterface);
2843            if (ior != kIOReturnSuccess)
2844            {
2845                ALERT(0, 0, "AppleUSBCDCECMData::enable - SetAlternateInterface  failed");
2846                XTRACE(this, 0, 0, "enable - SetAlternateInterface  failed");
2847            }
2848
2849            for (i=0; i<fInBufPool; i++)
2850            {
2851                if (fPipeInBuff[i].dead)			// If it's dead try and resurrect it
2852                {
2853                    ior = fInPipe->Read(fPipeInBuff[i].pipeInMDP, &fPipeInBuff[i].readCompletionInfo, NULL);
2854                    if (ior != kIOReturnSuccess)
2855                    {
2856                        XTRACE(this, 0, ior, "message - Read io error");
2857                    } else {
2858                        fPipeInBuff[i].dead = false;
2859                    }
2860                }
2861            }
2862            return kIOReturnSuccess;
2863        case kIOUSBMessageHubResumePort:
2864            XTRACE(this, 0, type, "message - kIOUSBMessageHubResumePort");
2865            break;
2866		case kIOMessageServiceIsAttemptingOpen:
2867			XTRACE(this, 0, type, "message - kIOMessageServiceIsAttemptingOpen");
2868			break;
2869        default:
2870            XTRACE(this, 0, type, "message - unknown message");
2871            break;
2872    }
2873
2874    return super::message(type, provider, argument);
2875
2876}/* end message */
2877
2878/****************************************************************************************************/
2879//
2880//	Method:		AppleUSBCDCECMData::registerWithPolicyMaker
2881//
2882//	Inputs:		provider - my provider
2883//
2884//	Outputs:	return code - From policy maker
2885//
2886//	Desc:		Initialize the driver for power management and register ourselves with policy-maker.
2887//				Called by superclass - not by Power Management.
2888//
2889/****************************************************************************************************/
2890
2891IOReturn AppleUSBCDCECMData::registerWithPolicyMaker(IOService *policyMaker)
2892{
2893	IOReturn	ior;
2894
2895	XTRACE(this, 0, 0, "registerWithPolicyMaker");
2896
2897	ior = policyMaker->registerPowerDriver(this, gOurPowerStates, kNumCDCStates);
2898
2899	return ior;
2900
2901}/* end registerWithPolicyMaker */
2902