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    /* AppleUSBCDCACMData.cpp - MacOSX implementation of		*/
26    /* USB Communication Device Class (CDC) Driver, ACM Data Interface.	*/
27
28#include <machine/limits.h>			/* UINT_MAX */
29#include <libkern/OSByteOrder.h>
30
31#include <IOKit/assert.h>
32#include <IOKit/IOLib.h>
33#include <IOKit/IOService.h>
34#include <IOKit/IOBufferMemoryDescriptor.h>
35#include <IOKit/IOMessage.h>
36
37#include <IOKit/pwr_mgt/RootDomain.h>
38
39#if !TARGET_OS_IPHONE
40#include <IOKit/usb/IOUSBBus.h>
41#endif /* TARGET_OS_IPHONE */
42
43#include <IOKit/usb/IOUSBNub.h>
44#include <IOKit/usb/IOUSBDevice.h>
45#include <IOKit/usb/IOUSBLog.h>
46#include <IOKit/usb/IOUSBPipe.h>
47#include <IOKit/usb/USB.h>
48#include <IOKit/usb/IOUSBInterface.h>
49
50#include <IOKit/serial/IOSerialKeys.h>
51#include <IOKit/serial/IOSerialDriverSync.h>
52#include <IOKit/serial/IOModemSerialStreamSync.h>
53#include <IOKit/serial/IORS232SerialStreamSync.h>
54
55#include <UserNotification/KUNCUserNotifications.h>
56
57#define DEBUG_NAME "AppleUSBCDCACMData"
58
59#include "AppleUSBCDCACM.h"
60#include "AppleUSBCDCACMData.h"
61
62#define MIN_BAUD (50 << 1)
63
64//AppleUSBCDCACMControl		*gControlDriver = NULL;			// Our Control driver
65
66static const OSSymbol *gPMWakeOnRingSymbol = NULL;
67
68#define super IOSerialDriverSync
69
70OSDefineMetaClassAndStructors(AppleUSBCDCACMData, IOSerialDriverSync);
71
72/****************************************************************************************************/
73//
74//		Function:	findCDCDriverAD
75//
76//		Inputs:		dataAddr - my address
77//				dataInterfaceNum - the data interface number
78//
79//		Outputs:	Pointer to the CDC driver
80//
81//		Desc:		Finds the initiating CDC driver and confirms the interface number
82//
83/****************************************************************************************************/
84
85AppleUSBCDC *findCDCDriverAD(void *dataAddr, UInt8 dataInterfaceNum, IOReturn *retCode)
86{
87    AppleUSBCDCACMData	*me = (AppleUSBCDCACMData *)dataAddr;
88    AppleUSBCDC		*CDCDriver = NULL;
89    bool		driverOK = false;
90    OSIterator		*iterator = NULL;
91    OSDictionary	*matchingDictionary = NULL;
92
93    XTRACE(me, 0, 0, "findCDCDriverAD");
94
95        // Get matching dictionary
96
97    matchingDictionary = IOService::serviceMatching("AppleUSBCDC");
98    if (!matchingDictionary)
99    {
100        XTRACE(me, 0, 0, "findCDCDriverAD - Couldn't create a matching dictionary");
101		*retCode = kIOReturnError;
102        return NULL;
103    }
104
105	// Get an iterator
106
107    iterator = IOService::getMatchingServices(matchingDictionary);
108    if (!iterator)
109    {
110        XTRACE(me, 0, 0, "findCDCDriverAD - No AppleUSBCDC driver found!");
111        matchingDictionary->release();
112		*retCode = kIOReturnError;
113        return NULL;
114    }
115
116    	// Iterate until we find our matching CDC driver
117
118    CDCDriver = (AppleUSBCDC *)iterator->getNextObject();
119    while (CDCDriver)
120    {
121        XTRACEP(me, 0, CDCDriver, "findCDCDriverAD - CDC driver candidate");
122
123        if (me->fDataInterface->GetDevice() == CDCDriver->getCDCDevice())
124        {
125            XTRACEP(me, 0, CDCDriver, "findCDCDriverAD - Found our CDC driver");
126            driverOK = CDCDriver->confirmDriver(kUSBAbstractControlModel, dataInterfaceNum);
127            break;
128        }
129        CDCDriver = (AppleUSBCDC *)iterator->getNextObject();
130    }
131
132    matchingDictionary->release();
133    iterator->release();
134
135    if (!CDCDriver)
136    {
137        XTRACE(me, 0, 0, "findCDCDriverAD - CDC driver not found");
138		*retCode = kIOReturnNotReady;
139        return NULL;
140    }
141
142    if (!driverOK)
143    {
144        XTRACE(me, kUSBAbstractControlModel, dataInterfaceNum, "findCDCDriverAD - Not my interface");
145		*retCode = kIOReturnError;
146        return NULL;
147    }
148
149    me->fConfigAttributes = CDCDriver->fbmAttributes;
150
151	*retCode = kIOReturnSuccess;
152
153    return CDCDriver;
154
155}/* end findCDCDriverAD */
156
157/****************************************************************************************************/
158//
159//		Function:	findControlDriverAD
160//
161//		Inputs:		me - my address
162//
163//		Outputs:	AppleUSBCDCACMControl
164//
165//		Desc:		Finds our matching control driver
166//
167/****************************************************************************************************/
168
169AppleUSBCDCACMControl *findControlDriverAD(void *me)
170{
171    Boolean                      worked             = false;
172    AppleUSBCDCACMControl	*tempDriver         = NULL;
173    OSIterator			*iterator           = NULL;
174    OSDictionary		*matchingDictionary = NULL;
175
176    XTRACE(me, 0, 0, "findControlDriverAD");
177
178        // Get matching dictionary
179
180    matchingDictionary = IOService::serviceMatching("AppleUSBCDCACMControl");
181    if (!matchingDictionary)
182    {
183        XTRACE(me, 0, 0, "findControlDriverAD - Couldn't create a matching dictionary");
184        return NULL;
185    }
186
187	// Get an iterator
188
189    iterator = IOService::getMatchingServices(matchingDictionary);
190    if (!iterator)
191    {
192        XTRACE(me, 0, 0, "findControlDriverAD - No AppleUSBCDCACMControl drivers found (iterator)");
193        matchingDictionary->release();
194        return NULL;
195    }
196
197	// Iterate until we find our matching driver
198
199    tempDriver = (AppleUSBCDCACMControl *)iterator->getNextObject();
200    while (tempDriver)
201    {
202        XTRACEP(me, 0, tempDriver, "findControlDriverAD - Data driver candidate");
203        if (tempDriver->checkInterfaceNumber((AppleUSBCDCACMData *)me))
204        {
205            XTRACEP(me, 0, tempDriver, "findControlDriverAD - Found our data driver");
206            worked = true;
207            break;
208        }
209        tempDriver = (AppleUSBCDCACMControl *)iterator->getNextObject();
210    }
211
212    matchingDictionary->release();
213    iterator->release();
214
215    if (!worked)
216    {
217        XTRACE(me, 0, 0, "findControlDriverAD - Failed");
218        return NULL;
219    }
220
221	return tempDriver;
222
223}/* end findControlDriverAD */
224
225#if LOG_DATA
226#define dumplen		32		// Set this to the number of bytes to dump and the rest should work out correct
227
228#define buflen		((dumplen*2)+dumplen)+3
229#define Asciistart	(dumplen*2)+3
230
231/****************************************************************************************************/
232//
233//		Function:	USBLogData
234//
235//		Inputs:		Dir - direction
236//				Count - number of bytes
237//				buf - the data
238//
239//		Outputs:
240//
241//		Desc:		Puts the data in the log.
242//
243/****************************************************************************************************/
244
245void AppleUSBCDCACMData::USBLogData(UInt8 Dir, SInt32 Count, char *buf)
246{
247    SInt32	wlen;
248    SInt32	llen, rlen;
249    SInt16	i, Aspnt, Hxpnt;
250    UInt8	wchr;
251    UInt8	LocBuf[buflen+1];
252
253    switch (Dir)
254    {
255        case kDataIn:
256            Log( "AppleUSBCDCACMData: USBLogData - Read Complete, address = %8p, size = %8d\n", (void *)buf, (UInt)Count );
257            break;
258        case kDataOut:
259            Log( "AppleUSBCDCACMData: USBLogData - Write, address = %8p, size = %8d\n", (void *)buf, (UInt)Count );
260            break;
261        case kDataOther:
262            Log( "AppleUSBCDCACMData: USBLogData - Other, address = %8p, size = %8d\n", (void *)buf, (UInt)Count );
263            break;
264    }
265
266    if (Count > dumplen)
267    {
268        wlen = dumplen;
269    } else {
270        wlen = Count;
271    }
272
273    if (wlen == 0)
274    {
275        Log( "AppleUSBCDCACMData: USBLogData - No data, Count=0\n" );
276        return;
277    }
278
279    rlen = 0;
280    do
281    {
282		memset(LocBuf, 0x20, buflen);
283
284        if (wlen > dumplen)
285        {
286            llen = dumplen;
287            wlen -= dumplen;
288        } else {
289            llen = wlen;
290            wlen = 0;
291        }
292        Aspnt = Asciistart;
293        Hxpnt = 0;
294        for (i=1; i<=llen; i++)
295        {
296            wchr = buf[i-1];
297            LocBuf[Hxpnt++] = Asciify(wchr >> 4);
298            LocBuf[Hxpnt++] = Asciify(wchr);
299            if ((wchr < 0x20) || (wchr > 0x7F)) 		// Non printable characters
300            {
301                LocBuf[Aspnt++] = 0x2E;				// Replace with a period
302            } else {
303                LocBuf[Aspnt++] = wchr;
304            }
305        }
306        LocBuf[Aspnt] = 0x00;
307
308        Log("%s\n", LocBuf);
309#if USE_IOL
310        IOSleep(Sleep_Time);					// Try and keep the log from overflowing
311#endif
312        rlen += llen;
313        buf = &buf[rlen];
314    } while (wlen != 0);
315
316}/* end USBLogData */
317
318/****************************************************************************************************/
319//
320//		Function:	AppleUSBCDCACMData::dumpData
321//
322//		Inputs:		Dir - direction
323//					buf - the data
324//					size - number of bytes
325//
326//		Outputs:	None
327//
328//		Desc:		Creates formatted data for the log
329//
330/****************************************************************************************************/
331
332void AppleUSBCDCACMData::dumpData(UInt8 Dir, char *buf, SInt32 Count)
333{
334    SInt32	curr, len, dlen;
335
336	switch (Dir)
337    {
338        case kDataIn:
339            Log( "AppleUSBCDCACMData: dumpData - Read Complete, address = %8p, size = %8d\n", (void *)buf, (UInt)Count );
340            break;
341        case kDataOut:
342            Log( "AppleUSBCDCACMData: dumpData - Write, address = %8p, size = %8d\n", (void *)buf, (UInt)Count );
343            break;
344        case kDataOther:
345            Log( "AppleUSBCDCACMData: dumpData - Other, address = %8p, size = %8d\n", (void *)buf, (UInt)Count );
346            break;
347    }
348
349    dlen = 0;
350    len = Count;
351
352    for (curr=0; curr<Count; curr+=dumplen)
353    {
354        if (len > dumplen)
355        {
356            dlen = dumplen;
357        } else {
358            dlen = len;
359        }
360        Log("%8p ", (void *)&buf[curr]);
361        USBLogData(kDataNone, dlen, &buf[curr]);
362        len -= dlen;
363    }
364
365}/* end dumpData */
366#endif
367
368/****************************************************************************************************/
369//
370//		Method:		AddBytetoQueue
371//
372//		Inputs:		Queue - the queue to be added to
373//				Value - Byte to be added
374//
375//		Outputs:	Queue status - full or no error
376//
377//		Desc:		Add a byte to the circular queue.
378//				Check to see if there is space by comparing the next pointer,
379//				with the last, If they match we are either Empty or full, so
380//				check InQueue for zero.
381//
382/****************************************************************************************************/
383
384QueueStatus AppleUSBCDCACMData::AddBytetoQueue(CirQueue *Queue, char Value)
385{
386
387    if ((Queue->NextChar == Queue->LastChar) && Queue->InQueue)
388    {
389        return queueFull;
390    }
391
392    *Queue->NextChar++ = Value;
393    Queue->InQueue++;
394
395        // Check to see if we need to wrap the pointer.
396
397    if (Queue->NextChar >= Queue->End)
398        Queue->NextChar =  Queue->Start;
399
400    return queueNoError;
401
402}/* end AddBytetoQueue */
403
404/****************************************************************************************************/
405//
406//		Method:		GetBytetoQueue
407//
408//		Inputs:		Queue - the queue to be removed from
409//
410//		Outputs:	Value - where to put the byte
411//				QueueStatus - empty or no error
412//
413//		Desc:		Remove a byte from the circular queue.
414//
415/****************************************************************************************************/
416
417QueueStatus AppleUSBCDCACMData::GetBytetoQueue(CirQueue *Queue, UInt8 *Value)
418{
419
420    if ((Queue->NextChar == Queue->LastChar) && !Queue->InQueue)
421    {
422        return queueEmpty;
423    }
424
425    *Value = *Queue->LastChar++;
426    Queue->InQueue--;
427
428        // Check to see if we need to wrap the pointer.
429
430    if (Queue->LastChar >= Queue->End)
431        Queue->LastChar =  Queue->Start;
432
433    return queueNoError;
434
435}/* end GetBytetoQueue */
436
437/****************************************************************************************************/
438//
439//		Method:		InitQueue
440//
441//		Inputs:		Queue - the queue to be initialized
442//				Buffer - the buffer
443//				size - length of buffer
444//
445//		Outputs:	QueueStatus - queueNoError.
446//
447//		Desc:		Pass a buffer of memory and this routine will set up the internal data structures.
448//
449/****************************************************************************************************/
450
451QueueStatus AppleUSBCDCACMData::InitQueue(CirQueue *Queue, UInt8 *Buffer, size_t Size)
452{
453    Queue->Start	= Buffer;
454    Queue->End		= (UInt8*)((size_t)Buffer + Size);
455    Queue->Size		= Size;
456    Queue->NextChar	= Buffer;
457    Queue->LastChar	= Buffer;
458    Queue->InQueue	= 0;
459
460//    IOSleep(1);
461
462    return queueNoError ;
463
464}/* end InitQueue */
465
466/****************************************************************************************************/
467//
468//		Method:		CloseQueue
469//
470//		Inputs:		Queue - the queue to be closed
471//
472//		Outputs:	QueueStatus - queueNoError.
473//
474//		Desc:		Clear out all of the data structures.
475//
476/****************************************************************************************************/
477
478QueueStatus AppleUSBCDCACMData::CloseQueue(CirQueue *Queue)
479{
480
481    Queue->Start	= 0;
482    Queue->End		= 0;
483    Queue->NextChar	= 0;
484    Queue->LastChar	= 0;
485    Queue->Size		= 0;
486
487    return queueNoError;
488
489}/* end CloseQueue */
490
491/****************************************************************************************************/
492//
493//		Function:	AppleUSBCDCACMData::AddtoRXQueue
494//
495//		Inputs:		Queue - the queue to be added to
496//					buffs - data to add
497//					Size - length of data
498//
499//		Outputs:	BytesWritten - Number of bytes actually put in the queue.
500//
501//		Desc:		Add an entire buffer to the queue.
502//
503/****************************************************************************************************/
504
505size_t AppleUSBCDCACMData::AddtoRXQueue(CirQueue *Queue, inPipeBuffers *buffs, size_t Size)
506{
507	UInt8	*Buffer = buffs->pipeBuffer;
508    size_t	BytesWritten = 0;
509	size_t	inQueue = 0;
510
511	inQueue = FreeSpaceinQueue(Queue);
512	if (inQueue < Size)
513	{
514		XTRACE(this, inQueue, Size, "AddtoRXQueue - Queue full, buffer will be held" );
515		return 0;
516	}
517
518    while (FreeSpaceinQueue(Queue) && (Size > BytesWritten))
519    {
520        AddBytetoQueue(Queue, *Buffer++);
521        BytesWritten++;
522    }
523
524	if (BytesWritten < Size)
525	{
526		ALERT(BytesWritten, Size, "AddtoRXQueue - Queue full, data has been dropped" );
527	}
528
529    return BytesWritten;
530
531}/* end AddtoRXQueue */
532
533/****************************************************************************************************/
534//
535//		Method:		AddtoQueue
536//
537//		Inputs:		Queue - the queue to be added to
538//				Buffer - data to add
539//				Size - length of data
540//
541//		Outputs:	BytesWritten - Number of bytes actually put in the queue.
542//
543//		Desc:		Add an entire buffer to the queue.
544//
545/****************************************************************************************************/
546
547size_t AppleUSBCDCACMData::AddtoQueue(CirQueue *Queue, UInt8 *Buffer, size_t Size)
548{
549    size_t	BytesWritten = 0;
550
551    while (FreeSpaceinQueue(Queue) && (Size > BytesWritten))
552    {
553        AddBytetoQueue(Queue, *Buffer++);
554        BytesWritten++;
555    }
556
557    return BytesWritten;
558
559}/* end AddtoQueue */
560
561/****************************************************************************************************/
562//
563//		Method:		RemovefromQueue
564//
565//		Inputs:		Queue - the queue to be removed from
566//				Size - size of buffer
567//
568//		Outputs:	Buffer - Where to put the data
569//				BytesReceived - Number of bytes actually put in Buffer.
570//
571//		Desc:		Get a buffers worth of data from the queue.
572//
573/****************************************************************************************************/
574
575size_t AppleUSBCDCACMData::RemovefromQueue(CirQueue *Queue, UInt8 *Buffer, size_t MaxSize)
576{
577    size_t	BytesReceived = 0;
578    UInt8	Value;
579
580    //  while((GetBytetoQueue(Queue, &Value) == queueNoError) && (MaxSize >= BytesReceived))
581    while((MaxSize > BytesReceived) && (GetBytetoQueue(Queue, &Value) == queueNoError))
582    {
583        *Buffer++ = Value;
584        BytesReceived++;
585    }/* end while */
586
587    return BytesReceived;
588
589}/* end RemovefromQueue */
590
591/****************************************************************************************************/
592//
593//		Method:		FreeSpaceinQueue
594//
595//		Inputs:		Queue - the queue to be queried
596//
597//		Outputs:	Return Value - Free space left
598//
599//		Desc:		Return the amount of free space left in this buffer.
600//
601/****************************************************************************************************/
602
603size_t AppleUSBCDCACMData::FreeSpaceinQueue(CirQueue *Queue)
604{
605    size_t	retVal = 0;
606
607    retVal = Queue->Size - Queue->InQueue;
608
609    return retVal;
610
611}/* end FreeSpaceinQueue */
612
613/****************************************************************************************************/
614//
615//		Method:		UsedSpaceinQueue
616//
617//		Inputs:		Queue - the queue to be queried
618//
619//		Outputs:	UsedSpace - Amount of data in buffer
620//
621//		Desc:		Return the amount of data in this buffer.
622//
623/****************************************************************************************************/
624
625size_t AppleUSBCDCACMData::UsedSpaceinQueue(CirQueue *Queue)
626{
627    return Queue->InQueue;
628
629}/* end UsedSpaceinQueue */
630
631/****************************************************************************************************/
632//
633//		Method:		GetQueueSize
634//
635//		Inputs:		Queue - the queue to be queried
636//
637//		Outputs:	QueueSize - The size of the queue.
638//
639//		Desc:		Return the total size of the queue.
640//
641/****************************************************************************************************/
642
643size_t AppleUSBCDCACMData::GetQueueSize(CirQueue *Queue)
644{
645    return Queue->Size;
646
647}/* end GetQueueSize */
648
649/****************************************************************************************************/
650//
651//		Method:		GetQueueStatus
652//
653//		Inputs:		Queue - the queue to be queried
654//
655//		Outputs:	Queue status - full, empty or no error
656//
657//		Desc:		Returns the status of the circular queue.
658//
659/****************************************************************************************************/
660
661QueueStatus AppleUSBCDCACMData::GetQueueStatus(CirQueue *Queue)
662{
663    if ((Queue->NextChar == Queue->LastChar) && Queue->InQueue)
664        return queueFull;
665    else if ((Queue->NextChar == Queue->LastChar) && !Queue->InQueue)
666        return queueEmpty;
667
668    return queueNoError ;
669
670}/* end GetQueueStatus */
671
672/****************************************************************************************************/
673//
674//		Method:		CheckQueues
675//
676//		Inputs:
677//
678//		Outputs:
679//
680//		Desc:		Checks the various queue's etc and manipulates the state(s) accordingly
681//				Must be called from a gated method or completion routine.
682//
683/****************************************************************************************************/
684
685void AppleUSBCDCACMData::CheckQueues()
686{
687    UInt32	Used;
688    UInt32	Free;
689    UInt32	QueuingState;
690    UInt32	DeltaState;
691
692	// Initialise the QueueState with the current state.
693
694    QueuingState = fPort.State;
695
696        // Check to see if there is anything in the Transmit buffer.
697
698    Used = UsedSpaceinQueue(&fPort.TX);
699    Free = FreeSpaceinQueue(&fPort.TX);
700
701    XTRACE(this, Free, Used, "CheckQueues");
702
703    if (Free == 0)
704    {
705        QueuingState |=  PD_S_TXQ_FULL;
706        QueuingState &= ~PD_S_TXQ_EMPTY;
707    } else {
708        if (Used == 0)
709	{
710            QueuingState &= ~PD_S_TXQ_FULL;
711            QueuingState |=  PD_S_TXQ_EMPTY;
712        } else {
713            QueuingState &= ~PD_S_TXQ_FULL;
714            QueuingState &= ~PD_S_TXQ_EMPTY;
715        }
716    }
717
718    	// Check to see if we are below the low water mark.
719
720    if (Used < fPort.TXStats.LowWater)
721         QueuingState |=  PD_S_TXQ_LOW_WATER;
722    else QueuingState &= ~PD_S_TXQ_LOW_WATER;
723
724    if (Used > fPort.TXStats.HighWater)
725         QueuingState |= PD_S_TXQ_HIGH_WATER;
726    else QueuingState &= ~PD_S_TXQ_HIGH_WATER;
727
728
729        // Check to see if there is anything in the Receive buffer.
730
731    Used = UsedSpaceinQueue(&fPort.RX);
732    Free = FreeSpaceinQueue(&fPort.RX);
733
734    if (Free == 0)
735    {
736        QueuingState |= PD_S_RXQ_FULL;
737        QueuingState &= ~PD_S_RXQ_EMPTY;
738    } else {
739        if (Used == 0)
740	{
741            QueuingState &= ~PD_S_RXQ_FULL;
742            QueuingState |= PD_S_RXQ_EMPTY;
743        } else {
744            QueuingState &= ~PD_S_RXQ_FULL;
745            QueuingState &= ~PD_S_RXQ_EMPTY;
746        }
747    }
748
749        // Check to see if we are below the low water mark.
750
751    if (Used < fPort.RXStats.LowWater)
752         QueuingState |= PD_S_RXQ_LOW_WATER;
753    else QueuingState &= ~PD_S_RXQ_LOW_WATER;
754
755    if (Used > fPort.RXStats.HighWater)
756         QueuingState |= PD_S_RXQ_HIGH_WATER;
757    else QueuingState &= ~PD_S_RXQ_HIGH_WATER;
758
759        // Figure out what has changed to get mask.
760
761    DeltaState = QueuingState ^ fPort.State;
762    setStateGated(&QueuingState, &DeltaState);
763
764}/* end CheckQueues */
765
766/****************************************************************************************************/
767//
768//		Method:		CheckHold
769//
770//		Inputs:
771//
772//		Outputs:
773//
774//		Desc:		Checks to see if there's any held buffers
775//
776/****************************************************************************************************/
777
778void AppleUSBCDCACMData::CheckHold()
779{
780	SInt32			size;
781	inPipeBuffers	*buffs;
782	IOReturn		ior = kIOReturnSuccess;
783
784	XTRACE(this, fPort.holdQueueIndxIn, fPort.holdQueueIndxOut, "CheckHold");
785
786	while (1)
787	{
788		if (fPort.holdQueue[fPort.holdQueueIndxOut] != 0)
789		{
790			buffs = fPort.holdQueue[fPort.holdQueueIndxOut];
791			size = AddtoRXQueue(&fPort.RX, buffs, buffs->count);
792			if (size == 0)
793			{
794				XTRACE(this, fPort.holdQueueIndxIn, fPort.holdQueueIndxOut, "CheckHold - Still holding");
795				break;
796			} else {
797				buffs->count = 0;
798				buffs->held = false;
799				XTRACE(this, fPort.holdQueueIndxIn, fPort.holdQueueIndxOut, "CheckHold - Read issued");
800				ior = fPort.InPipe->Read(buffs->pipeMDP, &buffs->completionInfo, NULL);
801				if (ior != kIOReturnSuccess)
802				{
803					XTRACE(this, fPort.holdQueueIndxOut, ior, "CheckHold - Read io err");
804					buffs->dead = true;
805				}
806				fPort.holdQueue[fPort.holdQueueIndxOut] = 0;
807				fPort.holdQueueIndxOut++;
808				if (fPort.holdQueueIndxOut >= kMaxInBufPool)
809				{
810					fPort.holdQueueIndxOut = 0;
811				}
812			}
813		} else {
814			break;
815		}
816	}
817
818	CheckQueues();
819
820	XTRACE(this, fPort.holdQueueIndxIn, fPort.holdQueueIndxOut, "CheckHold - Exit");
821
822}/* end CheckHold */
823
824/****************************************************************************************************/
825//
826//		Method:		AppleUSBCDCACMData::dataReadComplete
827//
828//		Inputs:		obj - me
829//				param - the buffer pool pointer
830//				rc - return code
831//				remaining - what's left
832//
833//		Outputs:	None
834//
835//		Desc:		BulkIn pipe read completion routine
836//
837/****************************************************************************************************/
838
839void AppleUSBCDCACMData::dataReadComplete(void *obj, void *param, IOReturn rc, UInt32 remaining)
840{
841    AppleUSBCDCACMData	*me = (AppleUSBCDCACMData*)obj;
842    inPipeBuffers		*buffs = (inPipeBuffers *)param;
843    IOReturn		ior;
844    size_t			length;
845	SInt32			putInQueue = 0;
846
847    XTRACE(me, rc, 0, "dataReadComplete");
848
849    if (me->fStopping)
850        return;
851
852    if (rc == kIOReturnSuccess)				// If operation returned ok
853    {
854        length = DATA_BUFF_SIZE - remaining;
855        XTRACE(me, me->fPort.State, length, "dataReadComplete - data length");
856
857		if (length > 0)
858		{
859//			me->LogData(kDataIn, length, buffs->pipeBuffer);
860
861				// Move the incoming bytes to the ring buffer, if we can
862
863//			me->AddtoQueue(&me->fPort.RX, buffs->pipeBuffer, length);
864
865				// If the indices are not equal then there's something in the hold queue
866
867			if (me->fPort.holdQueueIndxIn != me->fPort.holdQueueIndxOut)
868			{
869				putInQueue = 0;
870			} else {
871				putInQueue = me->AddtoRXQueue(&me->fPort.RX, buffs, length);
872			}
873			if (putInQueue == 0)
874			{
875				XTRACE(me, 0, me->fPort.holdQueueIndxIn, "dataReadComplete - Buffer held");
876				buffs->held = true;
877				buffs->count = length;
878				me->fPort.holdQueue[me->fPort.holdQueueIndxIn++] = buffs;
879				if (me->fPort.holdQueueIndxIn >= kMaxInBufPool)
880				{
881					me->fPort.holdQueueIndxIn = 0;
882				}
883			}
884		}
885    } else {
886        XTRACE(me, 0, rc, "dataReadComplete - error");
887		if (rc != kIOReturnAborted)
888        {
889			if ((rc == kIOUSBPipeStalled) || (rc == kIOUSBHighSpeedSplitError))
890			{
891				rc = me->checkPipe(me->fPort.InPipe, true);
892			} else {
893				rc = me->checkPipe(me->fPort.InPipe, false);
894			}
895            if (rc != kIOReturnSuccess)
896            {
897                XTRACE(me, 0, rc, "dataReadComplete - clear stall failed (trying to continue)");
898            }
899        }
900    }
901
902        // Queue the read only if not aborted and the buffer is not held
903
904    if (rc != kIOReturnAborted)
905    {
906		if (!buffs->held)
907		{
908			XTRACE(me, 0, me->fPort.holdQueueIndxIn, "dataReadComplete - Read issued");
909			ior = me->fPort.InPipe->Read(buffs->pipeMDP, &buffs->completionInfo, NULL);
910			if (ior != kIOReturnSuccess)
911			{
912				XTRACEP(me, buffs, ior, "dataReadComplete - Read io err");
913				buffs->dead = true;
914			} else {
915				XTRACEP(me, buffs, me->fPort.InPipe, "dataReadComplete - Read posted");
916			}
917		}
918        me->CheckQueues();
919	} else {
920		XTRACEP(me, buffs, me->fPort.InPipe, "dataReadComplete - Read aborted");
921	}
922
923}/* end dataReadComplete */
924
925/****************************************************************************************************/
926//
927//		Method:		AppleUSBCDCACMData::dataWriteComplete
928//
929//		Inputs:		obj - me
930//				param - the buffer pool pointer
931//				rc - return code
932//				remaining - what's left
933//
934//		Outputs:	None
935//
936//		Desc:		BulkOut pipe write completion routine
937//
938/****************************************************************************************************/
939
940void AppleUSBCDCACMData::dataWriteComplete(void *obj, void *param, IOReturn rc, UInt32 remaining)
941{
942    AppleUSBCDCACMData	*me = (AppleUSBCDCACMData *)obj;
943    outPipeBuffers		*buffs = (outPipeBuffers *)param;
944    SInt32		dLen;
945    UInt16		i;
946    bool		busy = false;
947	UInt32		state;
948	UInt32		mask;
949
950    XTRACE(me, rc, 0, "dataWriteComplete");
951
952    if (me->fStopping)
953        return;
954
955    if (rc == kIOReturnSuccess)
956    {
957        dLen = buffs->count - remaining;
958        XTRACE(me, 0, dLen, "dataWriteComplete - data length");
959        if (dLen > 0)						// Check if it was a zero length write
960        {
961            if ((dLen % me->fPort.OutPacketSize) == 0)		// If it was a multiple of max packet size then we need to do a zero length write
962            {
963                XTRACE(me, rc, dLen, "dataWriteComplete - writing zero length packet");
964                buffs->count = 0;
965                buffs->pipeMDP->setLength(0);
966
967                me->fPort.OutPipe->Write(buffs->pipeMDP, &buffs->completionInfo);
968                return;
969            } else {
970                buffs->avail = true;
971            }
972        } else {
973            buffs->avail = true;
974        }
975
976        me->CheckQueues();
977
978            // If any of the buffers are unavailable then we're still busy
979
980        for (i=0; i<me->fOutBufPool; i++)
981        {
982            if (!me->fPort.outPool[i].avail)
983            {
984                busy = true;
985                break;
986            }
987        }
988
989        if (!busy)
990        {
991			state = 0;
992			mask = PD_S_TX_BUSY;
993            me->setStateGated(&state, &mask);	// Clear the busy state
994        }
995
996        me->setUpTransmit();						// just to keep it going??
997
998    } else {
999        XTRACE(me, 0, rc, "dataWriteComplete - io error");
1000		if (rc != kIOReturnAborted)
1001        {
1002			if ((rc == kIOUSBPipeStalled) || (rc == kIOUSBHighSpeedSplitError))
1003			{
1004				rc = me->checkPipe(me->fPort.InPipe, true);
1005			} else {
1006				rc = me->checkPipe(me->fPort.InPipe, false);
1007			}
1008            if (rc != kIOReturnSuccess)
1009            {
1010                XTRACE(me, 0, rc, "dataWriteComplete - clear stall failed (trying to continue)");
1011            }
1012        }
1013
1014
1015        buffs->avail = true;
1016
1017             // If any of the buffers are unavailable then we're still busy
1018
1019        for (i=0; i<me->fOutBufPool; i++)
1020        {
1021            if (!me->fPort.outPool[i].avail)
1022            {
1023                busy = true;
1024                break;
1025            }
1026        }
1027
1028        if (!busy)
1029        {
1030			state = 0;
1031			mask = PD_S_TX_BUSY;
1032            me->setStateGated(&state, &mask);
1033        }
1034    }
1035
1036}/* end dataWriteComplete */
1037
1038/****************************************************************************************************/
1039//
1040//		Method:		AppleUSBCDCACMData::probe
1041//
1042//		Inputs:		provider - my provider
1043//
1044//		Outputs:	IOService - from super::probe, score - probe score
1045//
1046//		Desc:		Modify the probe score if necessary (we don't  at the moment)
1047//
1048/****************************************************************************************************/
1049
1050IOService* AppleUSBCDCACMData::probe( IOService *provider, SInt32 *score )
1051{
1052    IOService   *res;
1053
1054		// If our IOUSBInterface has a "do not match" property, it means that we should not match and need
1055		// to bail.  See rdar://3716623
1056
1057    OSBoolean *boolObj = OSDynamicCast(OSBoolean, provider->getProperty("kDoNotClassMatchThisInterface"));
1058    if (boolObj && boolObj->isTrue())
1059    {
1060        XTRACE(this, 0, 0, "probe - Provider doesn't want us to match");
1061        return NULL;
1062    }
1063
1064    res = super::probe(provider, score);
1065
1066    return res;
1067
1068}/* end probe */
1069
1070/****************************************************************************************************/
1071//
1072//		Method:		AppleUSBCDCACMData::start
1073//
1074//		Inputs:		provider - my provider
1075//
1076//		Outputs:	Return code - true (it's me), false (sorry it probably was me, but I can't configure it)
1077//
1078//		Desc:		This is called once it has been determined I'm probably the best
1079//				driver for this device.
1080//
1081/****************************************************************************************************/
1082
1083bool AppleUSBCDCACMData::start(IOService *provider)
1084{
1085	IOReturn	rtn;
1086	UInt16		devDriverCount = 0;
1087    OSNumber	*bufNumber = NULL;
1088    UInt16		bufValue = 0;
1089	IOUSBDevice *usbDevice;
1090
1091	XTRACE(this, 0, 0, "start");
1092
1093    fSessions = 0;
1094    fTerminate = false;
1095	fSuppressWarning = false;
1096	fEnumOnWake = false;
1097    fStopping = false;
1098	fCDCDriver = NULL;
1099	fControlDriver = NULL;
1100	fWorkLoop = NULL;
1101	fPMRootDomain = NULL;
1102	fWoR = false;
1103	fWakeSettingControllerHandle = NULL;
1104	fWanDevice = kOSBooleanFalse;
1105    fThreadSleepCount = 0;
1106    fReady = false;
1107
1108    initStructure();
1109
1110    if(!super::start(provider))
1111    {
1112        ALERT(0, 0, "start - super failed");
1113        return false;
1114    }
1115
1116	// Get my USB provider - the interface
1117
1118    fDataInterface = OSDynamicCast(IOUSBInterface, provider);
1119    if(!fDataInterface)
1120    {
1121        ALERT(0, 0, "start - provider invalid");
1122        return false;
1123    }
1124
1125	usbDevice = OSDynamicCast (IOUSBDevice, fDataInterface->GetDevice());
1126 	fWanDevice = (OSBoolean *) usbDevice->getProperty("WWAN");
1127	fInterfaceMappings = (OSDictionary *) usbDevice->getProperty("InterfaceMapping");
1128	if (fInterfaceMappings == NULL)
1129	{
1130
1131		fWanDevice = kOSBooleanFalse;
1132	}
1133	else
1134		fWanDevice = kOSBooleanTrue;
1135
1136
1137    fPort.DataInterfaceNumber = fDataInterface->GetInterfaceNumber();
1138
1139		// See if we can find/wait for the CDC driver
1140
1141	while (!fCDCDriver)
1142	{
1143		rtn = kIOReturnSuccess;
1144		fCDCDriver = findCDCDriverAD(this, fPort.DataInterfaceNumber, &rtn);
1145		if (fCDCDriver)
1146		{
1147			XTRACE (this, 0, 0, "start: Found the CDC device driver");
1148			break;
1149		} else {
1150			if (rtn == kIOReturnNotReady)
1151			{
1152				devDriverCount++;
1153				XTRACE(this, devDriverCount, fPort.DataInterfaceNumber, "start - Waiting for CDC device driver...");
1154				if (devDriverCount > 9)
1155				{
1156					break;
1157				}
1158				IOSleep(100);
1159			} else {
1160				break;
1161			}
1162		}
1163	}
1164
1165		// If we didn't find him then we have to bail
1166
1167	if (!fCDCDriver)
1168	{
1169		ALERT(0, fPort.DataInterfaceNumber, "start - Find CDC driver for ACM data interface failed");
1170		return false;
1171	}
1172
1173        // get workloop
1174
1175    fWorkLoop = getWorkLoop();
1176    if (!fWorkLoop)
1177    {
1178        ALERT(0, 0, "start - getWorkLoop failed");
1179        return false;
1180    }
1181
1182    fCommandGate = IOCommandGate::commandGate(this);
1183    if (!fCommandGate)
1184    {
1185        ALERT(0, 0, "start - commandGate failed");
1186        return false;
1187    }
1188
1189    if (fWorkLoop->addEventSource(fCommandGate) != kIOReturnSuccess)
1190    {
1191        ALERT(0, 0, "start - addEventSource(commandGate) failed");
1192        return false;
1193    }
1194
1195		// Check for an input buffer pool override first
1196
1197	fInBufPool = 0;
1198	fOutBufPool = 0;
1199
1200	bufNumber = (OSNumber *)provider->getProperty(inputTag);
1201    if (bufNumber)
1202    {
1203		bufValue = bufNumber->unsigned16BitValue();
1204		XTRACE(this, 0, bufValue, "start - Number of input buffers override value");
1205        if (bufValue <= kMaxInBufPool)
1206        {
1207            fInBufPool = bufValue;
1208        } else {
1209            fInBufPool = kMaxInBufPool;
1210        }
1211	} else {
1212		fInBufPool = 0;
1213	}
1214
1215		// Now set up the real input buffer pool values (only if not overridden)
1216
1217	if (fInBufPool == 0)
1218	{
1219		bufNumber = NULL;
1220		bufNumber = (OSNumber *)getProperty(inputTag);
1221		if (bufNumber)
1222		{
1223			bufValue = bufNumber->unsigned16BitValue();
1224			XTRACE(this, 0, bufValue, "start - Number of input buffers requested");
1225			if (bufValue <= kMaxInBufPool)
1226			{
1227				fInBufPool = bufValue;
1228			} else {
1229				fInBufPool = kMaxInBufPool;
1230			}
1231		} else {
1232			fInBufPool = kInBufPool;
1233		}
1234    }
1235
1236		// Check for an output buffer pool override
1237
1238	bufNumber = NULL;
1239	bufNumber = (OSNumber *)provider->getProperty(outputTag);
1240    if (bufNumber)
1241    {
1242		bufValue = bufNumber->unsigned16BitValue();
1243		XTRACE(this, 0, bufValue, "start - Number of output buffers override value");
1244        if (bufValue <= kMaxOutBufPool)
1245        {
1246            fOutBufPool = bufValue;
1247        } else {
1248            fOutBufPool = kMaxOutBufPool;
1249        }
1250	} else {
1251		fOutBufPool = 0;
1252	}
1253
1254        // Now set up the real output buffer pool values (only if not overridden)
1255
1256	if (fOutBufPool == 0)
1257	{
1258		bufNumber = NULL;
1259		bufNumber = (OSNumber *)getProperty(outputTag);
1260		if (bufNumber)
1261		{
1262			bufValue = bufNumber->unsigned16BitValue();
1263			XTRACE(this, 0, bufValue, "start - Number of output buffers requested");
1264			if (bufValue <= kMaxOutBufPool)
1265			{
1266				fOutBufPool = bufValue;
1267			} else {
1268				fOutBufPool = kMaxOutBufPool;
1269			}
1270		} else {
1271			fOutBufPool = kOutBufPool;
1272		}
1273	}
1274
1275    XTRACE(this, fInBufPool, fOutBufPool, "start - Buffer pools (input, output)");
1276
1277		// Check Reset on Close
1278
1279	OSBoolean *boolObj = OSDynamicCast(OSBoolean, provider->getProperty("ResetOnClose"));
1280    if (boolObj && boolObj->isTrue())
1281    {
1282		fResetOnClose = TRUE;
1283        XTRACE(this, 0, 0, "start - Reset on close is on");
1284    } else {
1285		fResetOnClose = FALSE;
1286	}
1287
1288		// Check Suppress Warning
1289
1290	OSBoolean *boolObj1 = OSDynamicCast(OSBoolean, provider->getProperty("SuppressWarning"));
1291    if (boolObj1 && boolObj1->isTrue())
1292    {
1293		fSuppressWarning = TRUE;
1294        XTRACE(this, 0, 0, "start - Suppress Warning is on");
1295    } else {
1296		fSuppressWarning = FALSE;
1297	}
1298
1299		// Check Enumerate on wake
1300
1301	OSBoolean *boolObj2 = OSDynamicCast(OSBoolean, provider->getProperty("EnumerateOnWake"));
1302    if (boolObj2 && boolObj2->isTrue())
1303    {
1304		fEnumOnWake = TRUE;
1305        XTRACE(this, 0, 0, "start - Enumerate on wake is on");
1306    } else {
1307		fEnumOnWake = FALSE;
1308	}
1309
1310    if (!createSerialStream())					// Publish SerialStream services
1311    {
1312        ALERT(0, 0, "start - createSerialStream failed");
1313        return false;
1314    }
1315
1316    if (!allocateResources())
1317    {
1318        ALERT(0, 0, "start - allocateResources failed");
1319        return false;
1320    }
1321
1322        // Looks like we're ok
1323
1324    fDataInterface->retain();
1325    fWorkLoop->retain();
1326    fCommandGate->enable();
1327
1328	gPMWakeOnRingSymbol = OSSymbol::withCString(kIOPMSettingWakeOnRingKey);
1329
1330	if (fConfigAttributes & kUSBAtrRemoteWakeup)
1331    {
1332		XTRACE(this, 0, 0, "start - Remote wake up is supported");
1333		WakeonRing();
1334		setWakeFeature();
1335		if (!setupWakeOnRingPMCallback())
1336		{
1337			XTRACE(this, 0, 0, "start - Setting the Wake on Ring callback failed");
1338		}
1339	} else {
1340        XTRACE(this, 0, 0, "start - Remote wake up not supported");
1341    }
1342
1343		// Save the ID's
1344
1345    fVendorID = fDataInterface->GetDevice()->GetVendorID();
1346    fProductID = fDataInterface->GetDevice()->GetProductID();
1347
1348    char vendorString[20];
1349    char productString[20];
1350    snprintf(vendorString, sizeof(vendorString), "0x%X", fVendorID);
1351    snprintf(productString, sizeof(productString), "0x%X", fProductID);
1352
1353    cdc_LogToMessageTracer(CDC_ASL_DOMAIN, "AppleUSBCDCACMData", vendorString, productString, 0, 0);
1354
1355    fReady = true;
1356
1357	IOLog(DEBUG_NAME ": Version number - %s, Input buffers %d, Output buffers %d\n", VersionNumber, fInBufPool, fOutBufPool);
1358
1359    return true;
1360
1361}/* end start */
1362
1363/****************************************************************************************************/
1364//
1365//		Method:		AppleUSBCDCACMData::stop
1366//
1367//		Inputs:		provider - my provider
1368//
1369//		Outputs:	None
1370//
1371//		Desc:		Stops the driver
1372//
1373/****************************************************************************************************/
1374
1375void AppleUSBCDCACMData::stop(IOService *provider)
1376{
1377    IOReturn	ret;
1378
1379    XTRACE(this, 0, 0, "stop");
1380
1381    fStopping = true;
1382    fReady = false;
1383
1384    retain();
1385    ret = fCommandGate->runAction(stopAction);
1386    release();
1387
1388	if (fWakeSettingControllerHandle)
1389	{
1390		fWakeSettingControllerHandle->release();
1391	}
1392
1393	if (fPMRootDomain)
1394	{
1395		fPMRootDomain->deRegisterInterestedDriver(this);
1396	}
1397
1398    removeProperty((const char *)propertyTag);
1399
1400    super::stop(provider);
1401
1402}/* end stop */
1403
1404/****************************************************************************************************/
1405//
1406//		Method:		AppleUSBCDCACMData::stopAction
1407//
1408//		Desc:		Dummy pass through for stopGated.
1409//
1410/****************************************************************************************************/
1411
1412IOReturn AppleUSBCDCACMData::stopAction(OSObject *owner, void *, void *, void *, void *)
1413{
1414
1415    ((AppleUSBCDCACMData *)owner)->stopGated();
1416
1417    return kIOReturnSuccess;
1418
1419}/* end stopAction */
1420
1421/****************************************************************************************************/
1422//
1423//		Method:		AppleUSBCDCACMData::stopGated
1424//
1425//		Inputs:
1426//
1427//		Outputs:
1428//
1429//		Desc:		Releases the resources
1430//
1431/****************************************************************************************************/
1432
1433void AppleUSBCDCACMData::stopGated()
1434{
1435
1436    XTRACE(this, 0, 0, "stopGated");
1437
1438    releaseResources();
1439
1440}/* end stopGated */
1441
1442/****************************************************************************************************/
1443//
1444//		Method:		AppleUSBCDCACMData::createSuffix
1445//
1446//		Inputs:
1447//
1448//		Outputs:	return Code - true (suffix created), false (suffix not create)
1449//				sufKey - the key
1450//
1451//		Desc:		Creates the suffix key. It attempts to use the serial number string from the device
1452//				if it's reasonable i.e. less than 8 bytes ascii. Remember it's stored in unicode
1453//				format. If it's not present or not reasonable it will generate the suffix based
1454//				on the location property tag. At least this remains the same across boots if the
1455//				device is plugged into the same physical location. In the latter case trailing
1456//				zeros are removed.
1457//				The interface number is also added to make it unique for
1458//				multiple CDC configuration devices.
1459//
1460/****************************************************************************************************/
1461
1462bool AppleUSBCDCACMData::createSuffix(unsigned char *sufKey)
1463{
1464
1465    IOReturn	rc;
1466    UInt8	serBuf[12];		// arbitrary size > 8
1467    OSNumber	*location;
1468    UInt32	locVal;
1469    SInt16	i, sig = 0;
1470    UInt8	indx;
1471    bool	keyOK = false;
1472
1473    XTRACE(this, 0, 0, "createSuffix");
1474
1475    indx = fDataInterface->GetDevice()->GetSerialNumberStringIndex();
1476    if (indx != 0)
1477    {
1478            // Generate suffix key based on the serial number string (if reasonable <= 8 and > 0)
1479
1480        rc = fDataInterface->GetDevice()->GetStringDescriptor(indx, (char *)&serBuf, sizeof(serBuf));
1481        if (!rc)
1482        {
1483            if ((strlen((char *)&serBuf) < 9) && (strlen((char *)&serBuf) > 0))
1484            {
1485				strlcpy((char *)sufKey, (const char *)&serBuf, strlen((char *)&serBuf));
1486//                strcpy((char *)sufKey, (const char *)&serBuf);
1487                sig = strlen((char *)sufKey);
1488                keyOK = true;
1489            }
1490        } else {
1491            XTRACE(this, 0, rc, "createSuffix error reading serial number string");
1492        }
1493    }
1494
1495    if (!keyOK)
1496    {
1497            // Generate suffix key based on the location property tag
1498
1499        location = (OSNumber *)fDataInterface->GetDevice()->getProperty(kUSBDevicePropertyLocationID);
1500        if (location)
1501        {
1502            locVal = location->unsigned32BitValue();
1503			snprintf((char *)sufKey, (sizeof(locVal)*2)+1, "%x", (unsigned int)locVal);
1504			sig = strlen((const char *)sufKey)-1;
1505			for (i=sig; i>=0; i--)
1506			{
1507				if (sufKey[i] != '0')
1508				{
1509					break;
1510				}
1511			}
1512			sig = i + 1;
1513            keyOK = true;
1514        }
1515    }
1516
1517        // Make it unique just in case there's more than one CDC configuration on this device
1518
1519    if (keyOK)
1520    {
1521        sufKey[sig] = Asciify((UInt8)fPort.DataInterfaceNumber >> 4);
1522		if (sufKey[sig] != '0')
1523            sig++;
1524        sufKey[sig++] = Asciify((UInt8)fPort.DataInterfaceNumber);
1525        sufKey[sig] = 0x00;
1526    }
1527
1528    return keyOK;
1529
1530}/* end createSuffix */
1531
1532
1533
1534
1535
1536bool AppleUSBCDCACMData::findSerialBSDClient (IOModemSerialStreamSync *nub)
1537{
1538	IOReturn							resultCode = kIOReturnError;
1539
1540	bsdClientState = 0;
1541
1542	XTRACE (this, 0, 0,"findSerialBSDClient Adding notification with custom matching dictionary");
1543	bsdClientAddedNotifier = addMatchingNotification (gIOFirstPublishNotification,
1544													  serviceMatching("IOSerialBSDClient"),
1545													  (IOServiceMatchingNotificationHandler)&bsdClientPublished,
1546													  this,
1547													  nub);
1548
1549	resultCode = fCommandGate->runAction(waitForBSDClienAction);
1550	XTRACE (this, 0, resultCode, "findSerialBSDClient Exiting....");
1551	if (resultCode == kIOReturnSuccess)
1552		return TRUE;
1553	else
1554		return FALSE;
1555}
1556
1557/****************************************************************************************************/
1558//
1559//		Method:		AppleUSBCDCACMData::waitForBSDClienAction
1560//
1561//		Desc:		Dummy pass through for sendDeviceRequestGated
1562//
1563/****************************************************************************************************/
1564
1565IOReturn AppleUSBCDCACMData::waitForBSDClienAction(OSObject *owner, void *, void *, void *, void *)
1566{
1567    return ((AppleUSBCDCACMData *)owner)->waitForBSDClientGated();
1568}   // end sendDeviceRequestAction
1569
1570
1571/****************************************************************************************************/
1572//
1573//		Method:		AppleUSBCDCACMData::waitForBSDClientGated
1574//
1575//		Inputs:
1576//
1577//		Outputs:	return Code - true that the device object appeared
1578//
1579//		Desc:		wait for the BSDClient object to be ready
1580//
1581/****************************************************************************************************/
1582
1583IOReturn AppleUSBCDCACMData::waitForBSDClientGated()
1584{
1585    IOReturn	result = kIOReturnSuccess;
1586
1587	AbsoluteTime	when;
1588	AbsoluteTime	offset;
1589	uint64_t		now;
1590
1591	now = mach_absolute_time();
1592	nanoseconds_to_absolutetime (9000000000ULL, &offset);	//rcs We will wait for up to 9 Seconds before timing out..
1593	ADD_ABSOLUTETIME (&now, &offset);	//when we timeout
1594	nanoseconds_to_absolutetime (now, &when);	//rcs We will wait for up to 9 Seconds before timing out..
1595
1596	if (bsdClientState == 1)
1597	{
1598		XTRACE(this, 0, 0, "waitForBSDClientGated - bsdClientState is already 1 no need to wait..."); //Sometimes the match callback gets called before this...
1599		return result; //no Need it was already published....
1600	}
1601
1602	result = fCommandGate->commandSleep((void *) &bsdClientState,when, THREAD_INTERRUPTIBLE);
1603	//	result = fCommandGate->commandSleep((void *) &bsdClientState);
1604
1605	if (result == THREAD_TIMED_OUT)
1606	{
1607		result = kIOReturnTimeout;
1608		XTRACE(this, 0, 0, "waitForBSDClientGated - fCommandGate returned THREAD_TIMED_OUT");
1609		return result;
1610	}
1611	else if (result == THREAD_INTERRUPTED)
1612	{
1613		result = kIOReturnAborted;
1614		XTRACE(this, 0, 0, "waitForBSDClientGated - fCommandGate returned THREAD_INTERRUPTED");
1615		return result;
1616	}
1617
1618	XTRACE(this, 0, 0, "waitForBSDClientGated - Exit");
1619    return result;
1620}
1621
1622bool AppleUSBCDCACMData::bsdClientPublished (AppleUSBCDCACMData * target, void * ref, IOService * newService, IONotifier * notifier)
1623{
1624	bool	resultCode = TRUE;
1625
1626	resultCode = FALSE;	// Assume failure
1627
1628	XTRACE(target, 0, 0, "bsdClientPublished");
1629
1630	if (ref == newService->getProvider()) //is the bsdclient that was just published the one we created (since they can be multiple IOBSDClient objects on any given Sunday)
1631	{
1632		XTRACE (target, 0, 0, "bsdClientPublished - waking up command gate + removing Notifier");
1633		notifier->remove();
1634		resultCode = TRUE;
1635		target->bsdClientState = 1;
1636		target->fCommandGate->commandWakeup((void *) &target->bsdClientState);
1637	}
1638	return resultCode;
1639}
1640
1641
1642/****************************************************************************************************/
1643//
1644//		Method:		AppleUSBCDCACMData::createSerialStream
1645//
1646//		Inputs:
1647//
1648//		Outputs:	return Code - true (created and initialilzed ok), false (it failed)
1649//
1650//		Desc:		Creates and initializes the nub
1651//
1652/****************************************************************************************************/
1653
1654bool AppleUSBCDCACMData::createSerialStream()
1655{
1656    IOModemSerialStreamSync	*pNub = new IOModemSerialStreamSync;
1657    bool			ret;
1658    UInt8			indx;
1659    IOReturn			rc;
1660    unsigned char		rname[20];
1661	OSString			*portName;
1662    const char			*suffix = (const char *)&rname;
1663//	OSBoolean			*hideProp = NULL;
1664
1665	OSString *portSuffixString = NULL;
1666	OSDictionary *fInfoCommands = NULL;
1667	OSDictionary *hiddenProperties = NULL;
1668	UInt32		ttyNameSize = 0;
1669	char		*ttyName = NULL;
1670	OSString	*ttyNameStr = NULL;
1671
1672    XTRACEP(this, 0, pNub, "createSerialStream");
1673    if (!pNub)
1674    {
1675		XTRACEP(this, 0, pNub, "createSerialStream - Could not create serial stream");
1676        return false;
1677    }
1678
1679    	// Either we attached and should get rid of our reference
1680    	// or we failed in which case we should get rid our reference as well.
1681        // This just makes sure the reference count is correct.
1682
1683    ret = (pNub->init(0, 0) && pNub->attach(this));
1684
1685    pNub->release();
1686    if (!ret)
1687    {
1688        XTRACE(this, ret, 0, "createSerialStream - Failed to attach to the nub");
1689        return false;
1690    }
1691
1692	if (fWanDevice == kOSBooleanTrue)
1693		pNub->setProperty("WWAN", true);
1694	else
1695	{
1696		XTRACE(this, 0, 0, "createSerialStream - NON WAN CDC Device");
1697	}
1698
1699
1700		// Get the name from the InterfaceMapping dictionary.
1701
1702	portName = getPortNameForInterface(fDataInterface->GetInterfaceNumber());
1703	if (portName != NULL)
1704	{
1705		pNub->setProperty(kIOTTYBaseNameKey, portName->getCStringNoCopy());
1706		if (!(portName->isEqualTo("wwan")))
1707		{
1708				pNub->setProperty((const char *)hiddenTag, true);
1709				pNub->setProperty((const char *)WWANTag, true);
1710		}
1711	} else {
1712			// Report the base name to be used for generating device nodes
1713
1714		pNub->setProperty(kIOTTYBaseNameKey, baseName);
1715		XTRACE(this, 0, fDataInterface->GetInterfaceNumber(), "createSerialStream - using default naming and suffix...");
1716
1717			// Create suffix key and set it
1718
1719		if (createSuffix((unsigned char *)suffix))
1720		{
1721			pNub->setProperty(kIOTTYSuffixKey, suffix);
1722		}
1723	}
1724
1725    pNub->registerService(kIOServiceSynchronous);
1726
1727	XTRACE(this, 0, 0, "createSerialStream with kIOServiceSynchronous - wait for a sec...");
1728	if (!findSerialBSDClient(pNub))
1729	{
1730		XTRACE (this, 0, 0, "createSerialStream - findSerialBSDClient failed terminating nub");
1731        if (pNub != NULL)
1732            pNub->close(this);
1733		XTRACE (this, 0, 0, "createSerialStream - findSerialBSDClient returning false");
1734		return false;
1735	}
1736
1737//	IOSleep(500);
1738
1739	fInfoCommands = (OSDictionary *) fDataInterface->GetDevice()->getProperty("InfoCommands");
1740
1741	if ( (fInfoCommands != NULL) && (portName != NULL) )
1742	{
1743		hiddenProperties = (OSDictionary *) fInfoCommands->getObject("HiddenProperties");
1744		if (hiddenProperties)
1745		{
1746			portSuffixString = (OSSymbol *) pNub->copyProperty(kIOTTYSuffixKey);
1747
1748			if (portSuffixString != NULL)
1749			{
1750				if ( (portSuffixString->getCStringNoCopy() != NULL) )
1751				{
1752						OSCollectionIterator *propertyIterator;
1753						propertyIterator = OSCollectionIterator::withCollection( hiddenProperties);
1754
1755						if ( propertyIterator != NULL )
1756						{
1757							OSString *key;
1758							propertyIterator->reset();
1759
1760							while( key = (OSString *)propertyIterator->getNextObject())
1761							{
1762								OSString *value;
1763								value = (OSString *) hiddenProperties->getObject(key);
1764
1765								if (value->isEqualTo(portName))
1766								{
1767									ttyNameSize = (portSuffixString->getLength() + portName->getLength() );
1768									ttyName = (char *)IOMallocAligned(ttyNameSize+4, sizeof (char));
1769									bzero(ttyName,ttyNameSize+4);
1770									strncpy(ttyName, value->getCStringNoCopy(), value->getLength());
1771									strncat(ttyName, portSuffixString->getCStringNoCopy(), portSuffixString->getLength());
1772
1773									ttyNameStr = OSString::withCString(ttyName);
1774									if ( ttyNameStr != NULL )
1775									{
1776										//OSString *foo;
1777										XTRACE(this, 0, 0, "createSerialStream - hiddenProperties: collision");
1778										fDataInterface->GetDevice()->setProperty(key->getCStringNoCopy(),ttyNameStr);
1779										//hiddenProperties->setObject(key->getCStringNoCopy(),ttyNameStr);
1780
1781										//foo = (OSString *)hiddenProperties->getObject(key->getCStringNoCopy());
1782										//hiddenProperties->setObject(foo,ttyNameStr);
1783									}
1784									}
1785							}
1786							propertyIterator->release();
1787						}	else { XTRACE(this, 0, 0, "createSerialStream - propertyIterator is NULL...");}
1788				} else { XTRACE(this, 0, 0, "createSerialStream - portSuffixString->getCStringNoCopy is NULL...");}
1789			} else { XTRACE(this, 0, 0, "createSerialStream - portSuffixString is NULL...");}
1790		} else { XTRACE(this, 0, 0, "createSerialStream - hiddenProperties is NULL...");}
1791	} else { XTRACE(this, 0, fDataInterface->GetInterfaceNumber(), "createSerialStream - fInfoCommands or portname is NULL...");}
1792
1793		// Save the Product String (at least the first productNameLength's worth).
1794
1795    indx = fDataInterface->GetDevice()->GetProductStringIndex();
1796    if (indx != 0)
1797    {
1798        rc = fDataInterface->GetDevice()->GetStringDescriptor(indx, (char *)&fProductName, sizeof(fProductName));
1799        if (!rc)
1800        {
1801            if (strlen((char *)fProductName) == 0)		// Believe it or not this sometimes happens - null string with an index defined???
1802            {
1803				strlcpy((char *)fProductName, defaultName, sizeof(defaultName));
1804//                strcpy((char *)fProductName, defaultName);
1805            }
1806            pNub->setProperty((const char *)propertyTag, (const char *)fProductName);
1807        }
1808    }
1809
1810    return true;
1811
1812}/* end createSerialStream */
1813
1814/****************************************************************************************************/
1815//
1816//		Method:		AppleUSBCDCACMData::acquirePort
1817//
1818//		Inputs:		sleep - true (wait for it), false (don't)
1819//				refCon - unused
1820//
1821//		Outputs:	Return Code - kIOReturnSuccess, kIOReturnExclusiveAccess, kIOReturnIOError and various others
1822//
1823//		Desc:		Set up for gated acquirePort call.
1824//
1825/****************************************************************************************************/
1826
1827IOReturn AppleUSBCDCACMData::acquirePort(bool sleep, void *refCon)
1828{
1829    IOReturn                ret;
1830
1831    XTRACEP(this, refCon, 0, "acquirePort");
1832
1833		// Check for being acquired after stop has been issued and before start
1834
1835	if (fTerminate || fStopping)
1836	{
1837		XTRACE(this, 0, 0, "acquirePort - Offline");
1838		return kIOReturnOffline;
1839	}
1840
1841		// Make sure we have a valid workloop
1842
1843	if (!fWorkLoop)
1844    {
1845        XTRACE(this, 0, 0, "acquirePort - No workLoop");
1846        return kIOReturnOffline;
1847    }
1848
1849        // Make sure start has finished (could be different threads)
1850
1851    if (!fReady)
1852    {
1853        XTRACE(this, 0, 0, "acquirePort - Not ready");
1854		return kIOReturnNotReady;
1855    }
1856
1857        // Find the matching control driver first (we're obviously not ready if he hasn't arrived)
1858
1859    if (!fControlDriver)
1860    {
1861        fControlDriver = findControlDriverAD(this);
1862        if (fControlDriver == NULL)
1863        {
1864            XTRACE(this, 0, 0, "acquirePort - Cannot find control driver");
1865            return kIOReturnNotReady;
1866        }
1867    }
1868
1869    retain();
1870    ret = fCommandGate->runAction(acquirePortAction, (void *)sleep);
1871    release();
1872
1873    return ret;
1874
1875}/* end acquirePort */
1876
1877/****************************************************************************************************/
1878//
1879//		Method:		AppleUSBCDCACMData::acquirePortAction
1880//
1881//		Desc:		Dummy pass through for acquirePortGated.
1882//
1883/****************************************************************************************************/
1884
1885IOReturn AppleUSBCDCACMData::acquirePortAction(OSObject *owner, void *arg0, void *, void *, void *)
1886{
1887
1888    return ((AppleUSBCDCACMData *)owner)->acquirePortGated((bool)arg0);
1889
1890}/* end acquirePortAction */
1891
1892/****************************************************************************************************/
1893//
1894//		Method:		AppleUSBCDCACMData::acquirePortGated
1895//
1896//		Inputs:		sleep - true (wait for it), false (don't)
1897//
1898//		Outputs:	Return Code - kIOReturnSuccess, kIOReturnExclusiveAccess, kIOReturnIOError and various others
1899//
1900//		Desc:		acquirePort tests and sets the state of the port object.  If the port was
1901// 				available, then the state is set to busy, and kIOReturnSuccess is returned.
1902// 				If the port was already busy and sleep is YES, then the thread will sleep
1903// 				until the port is freed, then re-attempts the acquire.  If the port was
1904// 				already busy and sleep is NO, then kIOReturnExclusiveAccess is returned.
1905//
1906/****************************************************************************************************/
1907
1908IOReturn AppleUSBCDCACMData::acquirePortGated(bool sleep)
1909{
1910    UInt32 	busyState = 0;
1911    IOReturn 	rtn = kIOReturnSuccess;
1912    UInt16	i;
1913	UInt32	state;
1914	UInt32	mask;
1915
1916    XTRACE(this, 0, sleep, "acquirePortGated");
1917
1918    retain(); 							// Hold reference till releasePortGated, unless we fail to acquire
1919    while (true)
1920    {
1921        busyState = fPort.State & PD_S_ACQUIRED;
1922        if (!busyState)
1923        {
1924                // Set busy bit (acquired), and clear everything else
1925
1926			state = PD_S_ACQUIRED | DEFAULT_STATE;
1927			mask = STATE_ALL;
1928            setStateGated(&state, &mask);
1929            break;
1930        } else {
1931            if (!sleep)
1932            {
1933                XTRACE(this, 0, 0, "acquirePortGated - Busy exclusive access");
1934                release();
1935            	return kIOReturnExclusiveAccess;
1936            } else {
1937            	busyState = 0;
1938				mask = PD_S_ACQUIRED;
1939            	rtn = watchStateGated(&busyState, &mask);
1940            	if ((rtn == kIOReturnIOError) || (rtn == kIOReturnSuccess))
1941                {
1942                    continue;
1943            	} else {
1944                    XTRACE(this, 0, 0, "acquirePortGated - Interrupted!");
1945                    release();
1946                    return rtn;
1947                }
1948            }
1949        }
1950    }
1951
1952    do
1953    {
1954        setStructureDefaults();				// Set the default values
1955
1956            // Set up and read the data-in bulk pipe
1957
1958        for (i=0; i<fInBufPool; i++)
1959        {
1960            if (fPort.inPool[i].pipeMDP)
1961            {
1962                fPort.inPool[i].completionInfo.target = this;
1963                fPort.inPool[i].completionInfo.action = dataReadComplete;
1964                fPort.inPool[i].completionInfo.parameter = (void *)&fPort.inPool[i];
1965                rtn = fPort.InPipe->Read(fPort.inPool[i].pipeMDP, &fPort.inPool[i].completionInfo, NULL);
1966                if (rtn != kIOReturnSuccess)
1967                {
1968                    XTRACE(this, i, rtn, "acquirePortGated - Read for bulk-in pipe failed");
1969					fPort.inPool[i].dead = true;
1970                    break;
1971                }
1972				XTRACEP(this, &fPort.inPool[i], fPort.InPipe, "acquirePortGated - Read posted");
1973            }
1974        }
1975        if (rtn == kIOReturnSuccess)
1976        {
1977
1978                // Set up the data-out bulk pipe
1979
1980            for (i=0; i<fOutBufPool; i++)
1981            {
1982                if (fPort.outPool[i].pipeMDP)
1983                {
1984                    fPort.outPool[i].completionInfo.target = this;
1985                    fPort.outPool[i].completionInfo.action = dataWriteComplete;
1986                    fPort.outPool[i].completionInfo.parameter = (void *)&fPort.outPool[i];
1987                }
1988            }
1989        } else {
1990            break;
1991        }
1992
1993        fSessions++;					// Bump number of active sessions and turn on clear to send
1994		state = PD_RS232_S_CTS;
1995		mask = PD_RS232_S_CTS;
1996		setStateGated(&state, &mask);
1997
1998            // Tell the Control driver we're good to go
1999
2000		if (fControlDriver)
2001		{
2002			if (!fControlDriver->dataAcquired())
2003			{
2004				XTRACE(this, 0, 0, "acquirePortGated - dataAcquired to Control failed");
2005				break;
2006			}
2007		}
2008
2009        return kIOReturnSuccess;
2010
2011    } while (0);
2012
2013    	// We failed for some reason
2014
2015	state = 0;
2016	mask = STATE_ALL;
2017	setStateGated(&state, &mask);			// Clear the entire state
2018
2019    release();
2020
2021    return rtn;
2022
2023}/* end acquirePortGated */
2024
2025/****************************************************************************************************/
2026//
2027//		Method:		AppleUSBCDCACMData::releasePort
2028//
2029//		Inputs:		refCon - unused
2030//
2031//		Outputs:	Return Code - kIOReturnSuccess or kIOReturnNotOpen
2032//
2033//		Desc:		Set up for gated releasePort call.
2034//
2035/****************************************************************************************************/
2036
2037IOReturn AppleUSBCDCACMData::releasePort(void *refCon)
2038{
2039    IOReturn	ret = kIOReturnSuccess;
2040
2041    XTRACE(this, 0, 0, "releasePort");
2042
2043        // Abort any outstanding I/O (only if we're not terminated)
2044
2045	if (!fTerminate)
2046	{
2047		if (fPort.InPipe)
2048			fPort.InPipe->Abort();
2049		if (fPort.OutPipe)
2050			fPort.OutPipe->Abort();
2051	}
2052
2053//	IOSleep(10);
2054
2055    retain();
2056    ret = fCommandGate->runAction(releasePortAction);
2057    release();
2058
2059        // Check the pipes before we leave (only if we're not terminated)
2060		// and Reset on Close is true. This resets the data toggle on both ends
2061
2062    if (!fTerminate)
2063    {
2064		if (fResetOnClose)
2065		{
2066			if (fPort.InPipe)
2067				checkPipe(fPort.InPipe, true);
2068
2069			if (fPort.OutPipe)
2070				checkPipe(fPort.OutPipe, true);
2071
2072			if (fDataInterface)
2073			{
2074				ret = fDataInterface->GetDevice()->ResetDevice();
2075				if (ret != kIOReturnSuccess)
2076				{
2077					XTRACE(this, 0, ret, "releasePort - ResetDevice failed");
2078				}
2079			}
2080		}
2081    } else {
2082        clearSleepingThreads();
2083    }
2084
2085    return ret;
2086
2087}/* end releasePort */
2088
2089/****************************************************************************************************/
2090//
2091//		Method:		AppleUSBCDCACMData::releasePortAction
2092//
2093//		Desc:		Dummy pass through for releasePortGated.
2094//
2095/****************************************************************************************************/
2096
2097IOReturn AppleUSBCDCACMData::releasePortAction(OSObject *owner, void *, void *, void *, void *)
2098{
2099
2100    return ((AppleUSBCDCACMData *)owner)->releasePortGated();
2101
2102}/* end releasePortAction */
2103
2104/****************************************************************************************************/
2105//
2106//		Method:		AppleUSBCDCACMData::releasePortGated
2107//
2108//		Inputs:
2109//
2110//		Outputs:	Return Code - kIOReturnSuccess or kIOReturnNotOpen
2111//
2112//		Desc:		releasePort returns all the resources and does clean up.
2113//
2114/****************************************************************************************************/
2115
2116IOReturn AppleUSBCDCACMData::releasePortGated()
2117{
2118    UInt32 	busyState;
2119	UInt32	state;
2120	UInt32	mask;
2121
2122    XTRACE(this, 0, 0, "releasePortGated");
2123
2124    busyState = (fPort.State & PD_S_ACQUIRED);
2125    if (!busyState)
2126    {
2127        if (fTerminate || fStopping)
2128        {
2129            XTRACE(this, 0, 0, "releasePortGated - Offline");
2130            return kIOReturnOffline;
2131        }
2132
2133        XTRACE(this, 0, 0, "releasePortGated - Not open");
2134        return kIOReturnNotOpen;
2135    }
2136
2137    if (!fTerminate)
2138        setControlLineState(false, false);		// clear RTS and clear DTR only if not terminated
2139
2140	state = 0;
2141	mask = STATE_ALL;
2142	setStateGated(&state, &mask);				// Clear the entire state word - which also deactivates the port
2143
2144#if 0
2145        // Abort any outstanding I/O
2146
2147    if (fPort.InPipe)
2148        fPort.InPipe->Abort();
2149    if (fPort.OutPipe)
2150        fPort.OutPipe->Abort();
2151#endif
2152
2153        // Tell the Control driver the port's been released, only when not terminated (control driver may already be gone)
2154
2155	if (!fTerminate)
2156	{
2157		if (fControlDriver)
2158		{
2159			fControlDriver->dataReleased();
2160		}
2161	}
2162
2163    fSessions--;					// reduce number of active sessions
2164
2165    release(); 						// Dispose of the self-reference we took in acquirePortGated()
2166
2167    XTRACE(this, 0, 0, "releasePort - Exit");
2168
2169    return kIOReturnSuccess;
2170
2171}/* end releasePortGated */
2172
2173/****************************************************************************************************/
2174//
2175//		Method:		AppleUSBCDCACMData::getState
2176//
2177//		Inputs:		refCon - unused
2178//
2179//		Outputs:	Return value - port state
2180//
2181//		Desc:		Set up for gated getState call.
2182//
2183/****************************************************************************************************/
2184
2185UInt32 AppleUSBCDCACMData::getState(void *refCon)
2186{
2187    UInt32	currState;
2188
2189    XTRACE(this, 0, 0, "getState");
2190
2191    if (fTerminate || fStopping)
2192    {
2193        XTRACE(this, 0, kIOReturnOffline, "getState - Offline");
2194        return 0;
2195    }
2196
2197    retain();
2198    currState = fCommandGate->runAction(getStateAction);
2199    release();
2200
2201    return currState;
2202
2203}/* end getState */
2204
2205/****************************************************************************************************/
2206//
2207//		Method:		AppleUSBCDCACMData::getStateAction
2208//
2209//		Desc:		Dummy pass through for getStateGated.
2210//
2211/****************************************************************************************************/
2212
2213IOReturn AppleUSBCDCACMData::getStateAction(OSObject *owner, void *, void *, void *, void *)
2214{
2215    UInt32	newState;
2216
2217    newState = ((AppleUSBCDCACMData *)owner)->getStateGated();
2218
2219    return newState;
2220
2221}/* end getStateAction */
2222
2223/****************************************************************************************************/
2224//
2225//		Method:		AppleUSBCDCACMData::getStateGated
2226//
2227//		Inputs:		port - unused
2228//
2229//		Outputs:	return value - port state
2230//
2231//		Desc:		Get the state for the port.
2232//
2233/****************************************************************************************************/
2234
2235UInt32 AppleUSBCDCACMData::getStateGated()
2236{
2237    UInt32 	state;
2238
2239    XTRACE(this, 0, 0, "getStateGated");
2240
2241    if (fTerminate || fStopping)
2242        return 0;
2243
2244    CheckQueues();
2245
2246    state = fPort.State & EXTERNAL_MASK;
2247
2248    XTRACE(this, state, EXTERNAL_MASK, "getStateGated - Exit");
2249
2250    return state;
2251
2252}/* end getStateGated */
2253
2254/****************************************************************************************************/
2255//
2256//		Method:		AppleUSBCDCACMData::setState
2257//
2258//		Inputs:		state - the state
2259//				mask - the mask
2260//				refCon - unused
2261//
2262//		Outputs:	Return code - kIOReturnSuccess or kIOReturnBadArgument
2263//
2264//		Desc:		Set up for gated setState call.
2265//
2266/****************************************************************************************************/
2267
2268IOReturn AppleUSBCDCACMData::setState(UInt32 state, UInt32 mask, void *refCon)
2269{
2270    IOReturn	ret = kIOReturnSuccess;
2271
2272    XTRACE(this, 0, 0, "setState");
2273
2274    if (fTerminate || fStopping)
2275    {
2276        XTRACE(this, 0, kIOReturnOffline, "setState - Offline");
2277        return 0;
2278    }
2279
2280        // Cannot acquire or activate via setState
2281
2282    if (mask & (PD_S_ACQUIRED | PD_S_ACTIVE | (~EXTERNAL_MASK)))
2283    {
2284        ret = kIOReturnBadArgument;
2285    } else {
2286
2287            // ignore any bits that are read-only
2288
2289        mask &= (~fPort.FlowControl & PD_RS232_A_MASK) | PD_S_MASK;
2290        if (mask)
2291        {
2292            retain();
2293            ret = fCommandGate->runAction(setStateAction, (void *)&state, (void *)&mask);
2294            release();
2295        }
2296    }
2297
2298    return ret;
2299
2300}/* end setState */
2301
2302/****************************************************************************************************/
2303//
2304//		Method:		AppleUSBCDCACMData::setStateAction
2305//
2306//		Desc:		Dummy pass through for setStateGated.
2307//
2308/****************************************************************************************************/
2309
2310IOReturn AppleUSBCDCACMData::setStateAction(OSObject *owner, void *arg0, void *arg1, void *, void *)
2311{
2312
2313    return ((AppleUSBCDCACMData *)owner)->setStateGated((UInt32 *)arg0, (UInt32 *)arg1);
2314
2315}/* end setStateAction */
2316
2317/****************************************************************************************************/
2318//
2319//		Method:		AppleUSBCDCACMData::setStateGated
2320//
2321//		Inputs:		state - state to set
2322//				mask - state mask
2323//
2324//		Outputs:	Return Code - kIOReturnSuccess or kIOReturnBadArgument
2325//
2326//		Desc:		Set the state for the port device.  The lower 16 bits are used to set the
2327//				state of various flow control bits (this can also be done by enqueueing a
2328//				PD_E_FLOW_CONTROL event).  If any of the flow control bits have been set
2329//				for automatic control, then they can't be changed by setState.  For flow
2330//				control bits set to manual (that are implemented in hardware), the lines
2331//				will be changed before this method returns.  The one weird case is if RXO
2332//				is set for manual, then an XON or XOFF character may be placed at the end
2333//				of the TXQ and transmitted later.
2334//
2335/****************************************************************************************************/
2336
2337IOReturn AppleUSBCDCACMData::setStateGated(UInt32 *pState, UInt32 *pMask)
2338{
2339	UInt32	state = *pState;
2340	UInt32	mask = *pMask;
2341    UInt32	delta;
2342	bool	controlUpdate = false;
2343	UInt32	DTRstate;
2344	UInt32	RTSstate;
2345	bool	DTRnew = false;
2346	bool	RTSnew = false;
2347
2348    XTRACE(this, state, mask, "setStateGated");
2349
2350    if (fStopping)
2351        return kIOReturnOffline;
2352
2353        // Check if it's being acquired or already acquired
2354
2355    if ((state & PD_S_ACQUIRED) || (fPort.State & PD_S_ACQUIRED))
2356    {
2357		XTRACE(this, state, mask, "setState - Requested state and mask");
2358		XTRACE(this, 0, fPort.State, "setState - Current state");
2359		DTRstate = fPort.State & PD_RS232_S_DTR;
2360		RTSstate = fPort.State & PD_RS232_S_RTS;
2361		XTRACE(this, DTRstate, RTSstate, "setState - DTRstate and RTSstate");
2362
2363			// Set the new state based on the current setting
2364
2365		if (fPort.State & PD_RS232_S_DTR)
2366		{
2367			DTRnew = true;
2368		}
2369		if (fPort.State & PD_RS232_S_RTS)
2370		{
2371			RTSnew = true;
2372		}
2373		XTRACE(this, DTRnew, RTSnew, "setState - DTRstate and RTSstate");
2374
2375			// Handle DTR and RTS changes for the modem
2376
2377        if (mask & PD_RS232_S_DTR)
2378        {
2379            if ((state & PD_RS232_S_DTR) != (fPort.State & PD_RS232_S_DTR))
2380            {
2381				controlUpdate = true;
2382                if (state & PD_RS232_S_DTR)
2383                {
2384                    XTRACE(this, 0, 0, "setState - Changing DTR to ON");
2385					DTRnew = true;
2386                } else {
2387					XTRACE(this, 0, 0, "setState - Changing DTR to OFF");
2388					DTRnew = false;
2389                }
2390            } else {
2391				XTRACE(this, 0, DTRstate, "setState - DTR state unchanged");
2392			}
2393        }
2394		if (mask & PD_RS232_S_RTS)
2395		{
2396			if ((state & PD_RS232_S_RTS) != (fPort.State & PD_RS232_S_RTS))
2397            {
2398				controlUpdate = true;
2399                if (state & PD_RS232_S_RTS)
2400                {
2401                    XTRACE(this, 0, 0, "setState - Changing RTS to ON");
2402					RTSnew = true;
2403                } else {
2404					XTRACE(this, 0, 0, "setState - Changing RTS to OFF");
2405					RTSnew = false;
2406                }
2407            } else {
2408				XTRACE(this, 0, RTSstate, "setState - RTS state unchanged");
2409			}
2410		}
2411
2412		XTRACE(this, DTRnew, RTSnew, "setState - DTRnew and RTSnew");
2413
2414		if ((!fTerminate) && (controlUpdate))
2415		{
2416			setControlLineState(RTSnew, DTRnew);
2417		}
2418
2419        state = (fPort.State & ~mask) | (state & mask); 		// compute the new state
2420        delta = state ^ fPort.State;		    			// keep a copy of the diffs
2421        fPort.State = state;
2422
2423	    // Wake up all threads asleep on WatchStateMask
2424
2425        if (delta & fPort.WatchStateMask)
2426        {
2427            fCommandGate->commandWakeup((void *)&fPort.State);
2428        }
2429
2430        return kIOReturnSuccess;
2431
2432    } else {
2433        XTRACE(this, fPort.State, 0, "setStateGated - Not Acquired");
2434    }
2435
2436    return kIOReturnNotOpen;
2437
2438}/* end setStateGated */
2439
2440/****************************************************************************************************/
2441//
2442//		Method:		AppleUSBCDCACMData::watchState
2443//
2444//		Inputs:		state - state to watch for
2445//				mask - state mask bits
2446//				refCon - unused
2447//
2448//		Outputs:	Return Code - kIOReturnSuccess or value returned from ::watchState
2449//
2450//		Desc:		Set up for gated watchState call.
2451//
2452/****************************************************************************************************/
2453
2454IOReturn AppleUSBCDCACMData::watchState(UInt32 *state, UInt32 mask, void *refCon)
2455{
2456    IOReturn 	ret;
2457
2458    XTRACE(this, *state, mask, "watchState");
2459
2460    if (fTerminate || fStopping)
2461    {
2462        XTRACE(this, 0, kIOReturnOffline, "watchState - Offline");
2463        return kIOReturnOffline;
2464    }
2465
2466    if (!state)
2467        return kIOReturnBadArgument;
2468
2469    if (!mask)
2470        return kIOReturnSuccess;
2471
2472    retain();
2473    ret = fCommandGate->runAction(watchStateAction, (void *)state, (void *)&mask);
2474    release();
2475
2476    return ret;
2477
2478}/* end watchState */
2479
2480/****************************************************************************************************/
2481//
2482//		Method:		AppleUSBCDCACMData::watchStateAction
2483//
2484//		Desc:		Dummy pass through for watchStateGated.
2485//
2486/****************************************************************************************************/
2487
2488IOReturn AppleUSBCDCACMData::watchStateAction(OSObject *owner, void *arg0, void *arg1, void *, void *)
2489{
2490
2491    return ((AppleUSBCDCACMData *)owner)->watchStateGated((UInt32 *)arg0, (UInt32 *)arg1);
2492
2493}/* end watchStateAction */
2494
2495/****************************************************************************************************/
2496//
2497//		Method:		AppleUSBCDCACMData::watchStateGated
2498//
2499//		Inputs:		state - state to watch for
2500//				mask - state mask bits
2501//
2502//		Outputs:	Return Code - kIOReturnSuccess or value returned from privateWatchState
2503//
2504//		Desc:		Wait for the at least one of the state bits defined in mask to be equal
2505//				to the value defined in state. Check on entry then sleep until necessary,
2506//				A return value of kIOReturnSuccess means that at least one of the port state
2507//				bits specified by mask is equal to the value passed in by state.  A return
2508//				value of kIOReturnIOError indicates that the port went inactive.  A return
2509//				value of kIOReturnIPCError indicates sleep was interrupted by a signal.
2510//
2511/****************************************************************************************************/
2512
2513IOReturn AppleUSBCDCACMData::watchStateGated(UInt32 *pState, UInt32 *pMask)
2514{
2515	UInt32		mask = *pMask;
2516    UInt32		watchState, foundStates;
2517    bool		autoActiveBit = false;
2518    IOReturn	ret = kIOReturnNotOpen;
2519
2520    XTRACE(this, *pState, mask, "watchStateGated");
2521
2522    if (fTerminate || fStopping)
2523        return kIOReturnOffline;
2524
2525    if (fPort.State & PD_S_ACQUIRED)
2526    {
2527        ret = kIOReturnSuccess;
2528        mask &= EXTERNAL_MASK;
2529
2530        watchState = *pState;
2531        if (!(mask & (PD_S_ACQUIRED | PD_S_ACTIVE)))
2532        {
2533            watchState &= ~PD_S_ACTIVE;				// Check for low PD_S_ACTIVE
2534            mask |=  PD_S_ACTIVE;				// Register interest in PD_S_ACTIVE bit
2535            autoActiveBit = true;
2536        }
2537
2538        while (true)
2539        {
2540                // Check port state for any interesting bits with watchState value
2541                // NB. the '^ ~' is a XNOR and tests for equality of bits.
2542
2543            foundStates = (watchState ^ ~fPort.State) & mask;
2544
2545            if (foundStates)
2546            {
2547                *pState = fPort.State;
2548                if (autoActiveBit && (foundStates & PD_S_ACTIVE))
2549                {
2550                    ret = kIOReturnIOError;
2551                } else {
2552                    ret = kIOReturnSuccess;
2553                }
2554                break;
2555            }
2556
2557                // Everytime we go around the loop we have to reset the watch mask.
2558                // This means any event that could affect the WatchStateMask must
2559                // wakeup all watch state threads.  The two events are an interrupt
2560                // or one of the bits in the WatchStateMask changing.
2561
2562            fPort.WatchStateMask |= mask;
2563
2564            XTRACE(this, fPort.State, fPort.WatchStateMask, "watchStateGated - Thread sleeping");
2565
2566            retain();								// Just to make sure all threads are awake
2567            fCommandGate->retain();					// before we're released
2568
2569            fThreadSleepCount++;
2570
2571            ret = fCommandGate->commandSleep((void *)&fPort.State);
2572
2573            fThreadSleepCount--;
2574
2575            fCommandGate->release();
2576
2577            XTRACE(this, fPort.State, ret, "watchStateGated - Thread restart");
2578
2579            if (ret == THREAD_TIMED_OUT)
2580            {
2581                ret = kIOReturnTimeout;
2582				release();
2583                break;
2584            } else {
2585                if (ret == THREAD_INTERRUPTED)
2586                {
2587                    ret = kIOReturnAborted;
2588					release();
2589                    break;
2590                } else {
2591					if (fTerminate || fStopping)	// Make sure we not terminated or stopping
2592					{
2593						ret = kIOReturnOffline;
2594						release();
2595						break;
2596					}
2597				}
2598            }
2599            release();
2600        }
2601
2602            // As it is impossible to undo the masking used by this
2603            // thread, we clear down the watch state mask and wakeup
2604            // every sleeping thread to reinitialize the mask before exiting.
2605
2606        fPort.WatchStateMask = 0;
2607        XTRACE(this, *pState, 0, "watchStateGated - Thread wakeing others");
2608        fCommandGate->commandWakeup((void *)&fPort.State);
2609
2610        *pState &= EXTERNAL_MASK;
2611    }
2612
2613    XTRACE(this, ret, 0, "watchState - Exit");
2614
2615    return ret;
2616
2617}/* end watchStateGated */
2618
2619/****************************************************************************************************/
2620//
2621//		Method:		AppleUSBCDCACMData::nextEvent
2622//
2623//		Inputs:		refCon - unused
2624//
2625//		Outputs:	Return Code - kIOReturnSuccess or kIOReturnOffline
2626//
2627//		Desc:		Not used by this driver.
2628//
2629/****************************************************************************************************/
2630
2631UInt32 AppleUSBCDCACMData::nextEvent(void *refCon)
2632{
2633
2634    XTRACE(this, 0, 0, "nextEvent");
2635
2636    if (fTerminate || fStopping)
2637        return kIOReturnOffline;
2638
2639    if (getState(&fPort) & PD_S_ACTIVE)
2640    {
2641        return kIOReturnSuccess;
2642    }
2643
2644    return kIOReturnNotOpen;
2645
2646}/* end nextEvent */
2647
2648/****************************************************************************************************/
2649//
2650//		Method:		AppleUSBCDCACMData::executeEvent
2651//
2652//		Inputs:		event - The event
2653//				data - any data associated with the event
2654//				refCon - unused
2655//
2656//		Outputs:	Return Code - kIOReturnSuccess, kIOReturnNotOpen or kIOReturnBadArgument
2657//
2658//		Desc:		Set up for gated executeEvent call.
2659//
2660/****************************************************************************************************/
2661
2662IOReturn AppleUSBCDCACMData::executeEvent(UInt32 event, UInt32 data, void *refCon)
2663{
2664    IOReturn 	ret;
2665
2666    XTRACE(this, data, event, "executeEvent");
2667
2668    if (fTerminate || fStopping)
2669    {
2670        XTRACE(this, 0, kIOReturnOffline, "executeEvent - Offline");
2671        return kIOReturnOffline;
2672    }
2673
2674    retain();
2675    ret = fCommandGate->runAction(executeEventAction, (void *)&event, (void *)&data);
2676    release();
2677
2678    return ret;
2679
2680}/* end executeEvent */
2681
2682/****************************************************************************************************/
2683//
2684//		Method:		AppleUSBCDCACMData::executeEventAction
2685//
2686//		Desc:		Dummy pass through for executeEventGated.
2687//
2688/****************************************************************************************************/
2689
2690IOReturn AppleUSBCDCACMData::executeEventAction(OSObject *owner, void *arg0, void *arg1, void *, void *)
2691{
2692
2693    return ((AppleUSBCDCACMData *)owner)->executeEventGated((UInt32 *)arg0, (UInt32 *)arg1);
2694
2695}/* end executeEventAction */
2696
2697/****************************************************************************************************/
2698//
2699//		Method:		AppleUSBCDCACMData::executeEventGated
2700//
2701//		Inputs:		event - The event
2702//				data - any data associated with the event
2703//
2704//		Outputs:	Return Code - kIOReturnSuccess, kIOReturnNotOpen or kIOReturnBadArgument
2705//
2706//		Desc:		executeEvent causes the specified event to be processed immediately.
2707//				This is primarily used for channel control commands like START & STOP
2708//
2709/****************************************************************************************************/
2710
2711IOReturn AppleUSBCDCACMData::executeEventGated(UInt32 *pEvent, UInt32 *pData)
2712{
2713	UInt32		event = *pEvent;
2714	UInt32		data = *pData;
2715    IOReturn	ret = kIOReturnSuccess;
2716    UInt32		state, delta;
2717	UInt32		nState;
2718	UInt32		mask;
2719
2720    if (fTerminate || fStopping)
2721        return kIOReturnOffline;
2722
2723    delta = 0;
2724    state = fPort.State;
2725    XTRACE(this, state, event, "executeEventGated");
2726
2727    if ((state & PD_S_ACQUIRED) == 0)
2728        return kIOReturnNotOpen;
2729
2730    switch (event)
2731    {
2732	case PD_RS232_E_XON_BYTE:
2733            XTRACE(this, data, event, "executeEventGated - PD_RS232_E_XON_BYTE");
2734            fPort.XONchar = data;
2735            break;
2736	case PD_RS232_E_XOFF_BYTE:
2737            XTRACE(this, data, event, "executeEventGated - PD_RS232_E_XOFF_BYTE");
2738            fPort.XOFFchar = data;
2739            break;
2740	case PD_E_SPECIAL_BYTE:
2741            XTRACE(this, data, event, "executeEventGated - PD_E_SPECIAL_BYTE");
2742            fPort.SWspecial[ data >> SPECIAL_SHIFT ] |= (1 << (data & SPECIAL_MASK));
2743            break;
2744	case PD_E_VALID_DATA_BYTE:
2745            XTRACE(this, data, event, "executeEventGated - PD_E_VALID_DATA_BYTE");
2746            fPort.SWspecial[ data >> SPECIAL_SHIFT ] &= ~(1 << (data & SPECIAL_MASK));
2747            break;
2748	case PD_E_FLOW_CONTROL:
2749            XTRACE(this, data, event, "executeEventGated - PD_E_FLOW_CONTROL");
2750            break;
2751	case PD_E_ACTIVE:
2752            XTRACE(this, data, event, "executeEventGated - PD_E_ACTIVE");
2753            if ((bool)data)
2754            {
2755                if (!(state & PD_S_ACTIVE))
2756                {
2757                    setStructureDefaults();
2758					nState = PD_S_ACTIVE;
2759					mask = PD_S_ACTIVE;
2760                    setStateGated(&nState, &mask); 			// activate port
2761
2762					nState = PD_RS232_S_RTS;
2763					mask = PD_RS232_S_RTS;
2764					setStateGated(&nState, &mask);
2765
2766					nState = PD_RS232_S_DTR;
2767					mask = PD_RS232_S_DTR;
2768					setStateGated(&nState, &mask);
2769
2770 //                   setControlLineState(true, true);						// set RTS and set DTR
2771                }
2772            } else {
2773                if ((state & PD_S_ACTIVE))
2774                {
2775					nState = 0;
2776					mask = PD_S_ACTIVE;
2777                    setStateGated(&nState, &mask);					// deactivate port
2778
2779                    setControlLineState(false, false);						// clear RTS and clear DTR
2780                }
2781            }
2782            break;
2783	case PD_E_DATA_LATENCY:
2784            XTRACE(this, data, event, "executeEventGated - PD_E_DATA_LATENCY");
2785            fPort.DataLatInterval = long2tval(data * 1000);
2786            break;
2787	case PD_RS232_E_MIN_LATENCY:
2788            XTRACE(this, data, event, "executeEventGated - PD_RS232_E_MIN_LATENCY");
2789            fPort.MinLatency = bool(data);
2790            break;
2791	case PD_E_DATA_INTEGRITY:
2792            XTRACE(this, data, event, "executeEventGated - PD_E_DATA_INTEGRITY");
2793            if ((data < PD_RS232_PARITY_NONE) || (data > PD_RS232_PARITY_SPACE))
2794            {
2795                ret = kIOReturnBadArgument;
2796            } else {
2797                fPort.TX_Parity = data;
2798                fPort.RX_Parity = PD_RS232_PARITY_DEFAULT;
2799
2800                setLineCoding();
2801            }
2802            break;
2803	case PD_E_DATA_RATE:
2804            XTRACE(this, data, event, "executeEventGated - PD_E_DATA_RATE");
2805
2806                // For API compatiblilty with Intel.
2807
2808            data >>= 1;
2809            XTRACE(this, data, 0, "executeEventGated - actual data rate");
2810            if ((data < MIN_BAUD) || (data > kMaxBaudRate))
2811            {
2812                ret = kIOReturnBadArgument;
2813            } else {
2814                fPort.BaudRate = data;
2815
2816                setLineCoding();
2817            }
2818            break;
2819	case PD_E_DATA_SIZE:
2820            XTRACE(this, data, event, "executeEventGated - PD_E_DATA_SIZE");
2821
2822                // For API compatiblilty with Intel.
2823
2824            data >>= 1;
2825            XTRACE(this, data, 0, "executeEventGated - actual data size");
2826            if ((data < 5) || (data > 8))
2827            {
2828                ret = kIOReturnBadArgument;
2829            } else {
2830                fPort.CharLength = data;
2831
2832                setLineCoding();
2833            }
2834            break;
2835	case PD_RS232_E_STOP_BITS:
2836            XTRACE(this, data, event, "executeEventGated - PD_RS232_E_STOP_BITS");
2837            if ((data < 0) || (data > 20))
2838            {
2839                ret = kIOReturnBadArgument;
2840            } else {
2841                fPort.StopBits = data;
2842
2843                setLineCoding();
2844            }
2845            break;
2846	case PD_E_RXQ_FLUSH:
2847            XTRACE(this, data, event, "executeEventGated - PD_E_RXQ_FLUSH");
2848            break;
2849	case PD_E_RX_DATA_INTEGRITY:
2850            XTRACE(this, data, event, "executeEventGated - PD_E_RX_DATA_INTEGRITY");
2851            if ((data != PD_RS232_PARITY_DEFAULT) &&  (data != PD_RS232_PARITY_ANY))
2852            {
2853                ret = kIOReturnBadArgument;
2854            } else {
2855                fPort.RX_Parity = data;
2856            }
2857            break;
2858	case PD_E_RX_DATA_RATE:
2859            XTRACE(this, data, event, "executeEventGated - PD_E_RX_DATA_RATE");
2860            if (data)
2861            {
2862                ret = kIOReturnBadArgument;
2863            }
2864            break;
2865	case PD_E_RX_DATA_SIZE:
2866            XTRACE(this, data, event, "executeEventGated - PD_E_RX_DATA_SIZE");
2867            if (data)
2868            {
2869                ret = kIOReturnBadArgument;
2870            }
2871            break;
2872	case PD_RS232_E_RX_STOP_BITS:
2873            XTRACE(this, data, event, "executeEventGated - PD_RS232_E_RX_STOP_BITS");
2874            if (data)
2875            {
2876                ret = kIOReturnBadArgument;
2877            }
2878            break;
2879	case PD_E_TXQ_FLUSH:
2880            XTRACE(this, data, event, "executeEventGated - PD_E_TXQ_FLUSH");
2881            break;
2882	case PD_RS232_E_LINE_BREAK:
2883            XTRACE(this, data, event, "executeEventGated - PD_RS232_E_LINE_BREAK");
2884            state &= ~PD_RS232_S_BRK;
2885            delta |= PD_RS232_S_BRK;
2886            setStateGated(&state, &delta);
2887			if (!fTerminate)
2888			{
2889				sendBreak((bool)data);
2890			}
2891            break;
2892	case PD_E_DELAY:
2893            XTRACE(this, data, event, "executeEventGated - PD_E_DELAY");
2894            fPort.CharLatInterval = long2tval(data * 1000);
2895            break;
2896	case PD_E_RXQ_SIZE:
2897            XTRACE(this, data, event, "executeEventGated - PD_E_RXQ_SIZE");
2898            break;
2899	case PD_E_TXQ_SIZE:
2900            XTRACE(this, data, event, "executeEventGated - PD_E_TXQ_SIZE");
2901            break;
2902	case PD_E_RXQ_HIGH_WATER:
2903            XTRACE(this, data, event, "executeEventGated - PD_E_RXQ_HIGH_WATER");
2904            break;
2905	case PD_E_RXQ_LOW_WATER:
2906            XTRACE(this, data, event, "executeEventGated - PD_E_RXQ_LOW_WATER");
2907            break;
2908	case PD_E_TXQ_HIGH_WATER:
2909            XTRACE(this, data, event, "executeEventGated - PD_E_TXQ_HIGH_WATER");
2910            break;
2911	case PD_E_TXQ_LOW_WATER:
2912            XTRACE(this, data, event, "executeEventGated - PD_E_TXQ_LOW_WATER");
2913            break;
2914	default:
2915            XTRACE(this, data, event, "executeEventGated - unrecognized event");
2916            ret = kIOReturnBadArgument;
2917            break;
2918    }
2919
2920    return ret;
2921
2922}/* end executeEventGated */
2923
2924/****************************************************************************************************/
2925//
2926//		Method:		AppleUSBCDCACMData::requestEvent
2927//
2928//		Inputs:		event - The event
2929//				refCon - unused
2930//
2931//		Outputs:	Return Code - kIOReturnSuccess, kIOReturnBadArgument
2932//				data - any data associated with the event
2933//
2934//		Desc:		requestEvent processes the specified event as an immediate request and
2935//				returns the results in data.  This is primarily used for getting link
2936//				status information and verifying baud rate etc.
2937//				For the most part this can be done immediately without being gated.
2938//
2939/****************************************************************************************************/
2940
2941IOReturn AppleUSBCDCACMData::requestEvent(UInt32 event, UInt32 *data, void *refCon)
2942{
2943    IOReturn	returnValue = kIOReturnSuccess;
2944
2945    XTRACE(this, 0, event, "requestEvent");
2946
2947    if (fTerminate || fStopping)
2948    {
2949        XTRACE(this, 0, kIOReturnOffline, "requestEvent - Offline");
2950        return kIOReturnOffline;
2951    }
2952
2953    if (data == NULL)
2954    {
2955        XTRACE(this, 0, event, "requestEvent - data is null");
2956        returnValue = kIOReturnBadArgument;
2957    } else {
2958        switch (event)
2959        {
2960            case PD_E_ACTIVE:
2961                XTRACE(this, 0, event, "requestEvent - PD_E_ACTIVE");
2962                *data = bool(getState(&fPort) & PD_S_ACTIVE);			// Just to be safe put this through the gate
2963                break;
2964            case PD_E_FLOW_CONTROL:
2965                XTRACE(this, fPort.FlowControl, event, "requestEvent - PD_E_FLOW_CONTROL");
2966                *data = fPort.FlowControl;
2967                break;
2968            case PD_E_DELAY:
2969                XTRACE(this, 0, event, "requestEvent - PD_E_DELAY");
2970                *data = tval2long(fPort.CharLatInterval)/ 1000;
2971                break;
2972            case PD_E_DATA_LATENCY:
2973                XTRACE(this, 0, event, "requestEvent - PD_E_DATA_LATENCY");
2974                *data = tval2long(fPort.DataLatInterval)/ 1000;
2975                break;
2976            case PD_E_TXQ_SIZE:
2977                XTRACE(this, 0, event, "requestEvent - PD_E_TXQ_SIZE");
2978                *data = GetQueueSize(&fPort.TX);
2979                break;
2980            case PD_E_RXQ_SIZE:
2981                XTRACE(this, 0, event, "requestEvent - PD_E_RXQ_SIZE");
2982                *data = GetQueueSize(&fPort.RX);
2983                break;
2984            case PD_E_TXQ_LOW_WATER:
2985                XTRACE(this, 0, event, "requestEvent - PD_E_TXQ_LOW_WATER");
2986                *data = 0;
2987                returnValue = kIOReturnBadArgument;
2988                break;
2989            case PD_E_RXQ_LOW_WATER:
2990                XTRACE(this, 0, event, "requestEvent - PD_E_RXQ_LOW_WATER");
2991                *data = 0;
2992                returnValue = kIOReturnBadArgument;
2993                break;
2994            case PD_E_TXQ_HIGH_WATER:
2995                XTRACE(this, 0, event, "requestEvent - PD_E_TXQ_HIGH_WATER");
2996                *data = 0;
2997                returnValue = kIOReturnBadArgument;
2998                break;
2999            case PD_E_RXQ_HIGH_WATER:
3000                XTRACE(this, 0, event, "requestEvent - PD_E_RXQ_HIGH_WATER");
3001                *data = 0;
3002                returnValue = kIOReturnBadArgument;
3003                break;
3004            case PD_E_TXQ_AVAILABLE:
3005                XTRACE(this, 0, event, "requestEvent - PD_E_TXQ_AVAILABLE");
3006                *data = FreeSpaceinQueue(&fPort.TX);
3007                break;
3008            case PD_E_RXQ_AVAILABLE:
3009                XTRACE(this, 0, event, "requestEvent - PD_E_RXQ_AVAILABLE");
3010                *data = UsedSpaceinQueue(&fPort.RX);
3011                break;
3012            case PD_E_DATA_RATE:
3013                XTRACE(this, 0, event, "requestEvent - PD_E_DATA_RATE");
3014                *data = fPort.BaudRate << 1;
3015                break;
3016            case PD_E_RX_DATA_RATE:
3017                XTRACE(this, 0, event, "requestEvent - PD_E_RX_DATA_RATE");
3018                *data = 0x00;
3019                break;
3020            case PD_E_DATA_SIZE:
3021                XTRACE(this, 0, event, "requestEvent - PD_E_DATA_SIZE");
3022                *data = fPort.CharLength << 1;
3023                break;
3024            case PD_E_RX_DATA_SIZE:
3025                XTRACE(this, 0, event, "requestEvent - PD_E_RX_DATA_SIZE");
3026                *data = 0x00;
3027                break;
3028            case PD_E_DATA_INTEGRITY:
3029                XTRACE(this, 0, event, "requestEvent - PD_E_DATA_INTEGRITY");
3030                *data = fPort.TX_Parity;
3031                break;
3032            case PD_E_RX_DATA_INTEGRITY:
3033                XTRACE(this, 0, event, "requestEvent - PD_E_RX_DATA_INTEGRITY");
3034                *data = fPort.RX_Parity;
3035                break;
3036            case PD_RS232_E_STOP_BITS:
3037                XTRACE(this, 0, event, "requestEvent - PD_RS232_E_STOP_BITS");
3038                *data = fPort.StopBits << 1;
3039                break;
3040            case PD_RS232_E_RX_STOP_BITS:
3041                XTRACE(this, 0, event, "requestEvent - PD_RS232_E_RX_STOP_BITS");
3042                *data = 0x00;
3043                break;
3044            case PD_RS232_E_XON_BYTE:
3045                XTRACE(this, 0, event, "requestEvent - PD_RS232_E_XON_BYTE");
3046                *data = fPort.XONchar;
3047                break;
3048            case PD_RS232_E_XOFF_BYTE:
3049                XTRACE(this, 0, event, "requestEvent - PD_RS232_E_XOFF_BYTE");
3050                *data = fPort.XOFFchar;
3051                break;
3052            case PD_RS232_E_LINE_BREAK:
3053                XTRACE(this, 0, event, "requestEvent - PD_RS232_E_LINE_BREAK");
3054                *data = bool(getState(&fPort) & PD_RS232_S_BRK);			// This should be gated too
3055                break;
3056            case PD_RS232_E_MIN_LATENCY:
3057                XTRACE(this, 0, event, "requestEvent - PD_RS232_E_MIN_LATENCY");
3058                *data = bool(fPort.MinLatency);
3059                break;
3060            default:
3061                XTRACE(this, 0, event, "requestEvent - unrecognized event");
3062                returnValue = kIOReturnBadArgument;
3063                break;
3064        }
3065    }
3066
3067    return kIOReturnSuccess;
3068
3069}/* end requestEvent */
3070
3071/****************************************************************************************************/
3072//
3073//		Method:		AppleUSBCDCACMData::enqueueEvent
3074//
3075//		Inputs:		event - The event
3076//				data - any data associated with the event,
3077//				sleep - true (wait for it), false (don't)
3078//				refCon - unused
3079//
3080//		Outputs:	Return Code - kIOReturnSuccess or kIOReturnNotOpen
3081//
3082//		Desc:		Not used by this driver.
3083//				Events are passed on to executeEvent for immediate action.
3084//
3085/****************************************************************************************************/
3086
3087IOReturn AppleUSBCDCACMData::enqueueEvent(UInt32 event, UInt32 data, bool sleep, void *refCon)
3088{
3089    IOReturn 	ret;
3090
3091    XTRACE(this, data, event, "enqueueEvent");
3092
3093    if (fTerminate || fStopping)
3094    {
3095        XTRACE(this, 0, kIOReturnOffline, "enqueueEvent - Offline");
3096        return kIOReturnOffline;
3097    }
3098
3099    retain();
3100    ret = fCommandGate->runAction(executeEventAction, (void *)&event, (void *)&data);
3101    release();
3102
3103    return ret;
3104
3105}/* end enqueueEvent */
3106
3107/****************************************************************************************************/
3108//
3109//		Method:		AppleUSBCDCACMData::dequeueEvent
3110//
3111//		Inputs:		sleep - true (wait for it), false (don't)
3112//				refCon - unused
3113//
3114//		Outputs:	Return Code - kIOReturnSuccess, kIOReturnNotOpen
3115//
3116//		Desc:		Not used by this driver.
3117//
3118/****************************************************************************************************/
3119
3120IOReturn AppleUSBCDCACMData::dequeueEvent(UInt32 *event, UInt32 *data, bool sleep, void *refCon)
3121{
3122
3123    XTRACE(this, 0, 0, "dequeueEvent");
3124
3125    if (fTerminate || fStopping)
3126    {
3127        XTRACE(this, 0, kIOReturnOffline, "dequeueEvent - Offline");
3128        return kIOReturnOffline;
3129    }
3130
3131    if ((event == NULL) || (data == NULL))
3132        return kIOReturnBadArgument;
3133
3134    if (getState(&fPort) & PD_S_ACTIVE)
3135    {
3136        return kIOReturnSuccess;
3137    }
3138
3139    return kIOReturnNotOpen;
3140
3141}/* end dequeueEvent */
3142
3143/****************************************************************************************************/
3144//
3145//		Method:		AppleUSBCDCACMData::enqueueData
3146//
3147//		Inputs:		buffer - the data
3148//				size - number of bytes
3149//				sleep - true (wait for it), false (don't)
3150//				refCon - unused
3151//
3152//		Outputs:	Return Code - kIOReturnSuccess, kIOReturnBadArgument or value returned from watchState
3153//				count - bytes transferred
3154//
3155//		Desc:		set up for enqueueDataGated call.
3156//
3157/****************************************************************************************************/
3158
3159IOReturn AppleUSBCDCACMData::enqueueData(UInt8 *buffer, UInt32 size, UInt32 *count, bool sleep, void *refCon)
3160{
3161    IOReturn 	ret;
3162
3163    XTRACE(this, size, sleep, "enqueueData");
3164
3165    if (fTerminate || fStopping)
3166    {
3167        XTRACE(this, 0, kIOReturnOffline, "enqueueData - Offline");
3168        return kIOReturnOffline;
3169    }
3170
3171    if (count == NULL || buffer == NULL)
3172        return kIOReturnBadArgument;
3173
3174    retain();
3175    ret = fCommandGate->runAction(enqueueDataAction, (void *)buffer, (void *)&size, (void *)count, (void *)&sleep);
3176    release();
3177
3178    return ret;
3179
3180}/* end enqueueData */
3181
3182/****************************************************************************************************/
3183//
3184//		Method:		AppleUSBCDCACMData::enqueueDatatAction
3185//
3186//		Desc:		Dummy pass through for enqueueDataGated.
3187//
3188/****************************************************************************************************/
3189
3190IOReturn AppleUSBCDCACMData::enqueueDataAction(OSObject *owner, void *arg0, void *arg1, void *arg2, void *arg3)
3191{
3192
3193    return ((AppleUSBCDCACMData *)owner)->enqueueDataGated((UInt8 *)arg0, (UInt32 *)arg1, (UInt32 *)arg2, (bool *)arg3);
3194
3195}/* end enqueueDataAction */
3196
3197/****************************************************************************************************/
3198//
3199//		Method:		AppleUSBCDCACMData::enqueueDataGated
3200//
3201//		Inputs:		buffer - the data
3202//				size - number of bytes
3203//				sleep - true (wait for it), false (don't)
3204//
3205//		Outputs:	Return Code - kIOReturnSuccess or value returned from watchState
3206//				count - bytes transferred,
3207//
3208//		Desc:		enqueueData will attempt to copy data from the specified buffer to
3209//				the TX queue as a sequence of VALID_DATA events.  The argument
3210//				bufferSize specifies the number of bytes to be sent.  The actual
3211//				number of bytes transferred is returned in count.
3212//				If sleep is true, then this method will sleep until all bytes can be
3213//				transferred.  If sleep is false, then as many bytes as possible
3214//				will be copied to the TX queue.
3215//				Note that the caller should ALWAYS check the transferCount unless
3216//				the return value was kIOReturnBadArgument, indicating one or more
3217//				arguments were not valid.  Other possible return values are
3218//				kIOReturnSuccess if all requirements were met or kIOReturnOffline
3219//				if the device was unplugged.
3220//
3221/****************************************************************************************************/
3222
3223IOReturn AppleUSBCDCACMData::enqueueDataGated(UInt8 *buffer, UInt32 *pSize, UInt32 *count, bool *pSleep)
3224{
3225	UInt32		size = *pSize;
3226	bool		sleep = *pSleep;
3227    UInt32		state = PD_S_TXQ_LOW_WATER;
3228	UInt32		mask;
3229    IOReturn 	rtn = kIOReturnSuccess;
3230
3231    XTRACE(this, size, sleep, "enqueueDataGated");
3232
3233    if (fTerminate || fStopping)
3234        return kIOReturnOffline;
3235
3236    *count = 0;
3237
3238    if (!(fPort.State & PD_S_ACTIVE))
3239        return kIOReturnNotOpen;
3240
3241    XTRACE(this, fPort.State, size, "enqueueDataGated - current State");
3242//    LogData(kDataOther, size, buffer);
3243
3244        // Go ahead and try to add something to the buffer
3245
3246    *count = AddtoQueue(&fPort.TX, buffer, size);
3247    CheckQueues();
3248
3249        // Let the tranmitter know that we have something ready to go
3250
3251    setUpTransmit();
3252
3253        // If we could not queue up all of the data on the first pass and
3254        // the user wants us to sleep until it's all out then sleep
3255
3256    while ((*count < size) && sleep)
3257    {
3258        state = PD_S_TXQ_LOW_WATER;
3259		mask = PD_S_TXQ_LOW_WATER;
3260        rtn = watchStateGated(&state, &mask);
3261        if (rtn != kIOReturnSuccess)
3262        {
3263            XTRACE(this, 0, rtn, "enqueueDataGated - interrupted");
3264            return rtn;
3265        }
3266
3267        *count += AddtoQueue(&fPort.TX, buffer + *count, size - *count);
3268        CheckQueues();
3269
3270            // Let the tranmitter know that we have something ready to go.
3271
3272        setUpTransmit();
3273    }
3274
3275    XTRACE(this, *count, size, "enqueueDataGated - Exit");
3276
3277    return kIOReturnSuccess;
3278
3279}/* end enqueueDataGated */
3280
3281/****************************************************************************************************/
3282//
3283//		Method:		AppleUSBCDCACMData::dequeueData
3284//
3285//		Inputs:		size - buffer size
3286//				min - minimum bytes required
3287//				refCon - the Port
3288//
3289//		Outputs:	buffer - data returned
3290//				min - number of bytes
3291//				Return Code - kIOReturnSuccess, kIOReturnBadArgument, kIOReturnNotOpen, or value returned from watchState
3292//
3293//		Desc:		set up for dequeueDataGated call.
3294//
3295/****************************************************************************************************/
3296
3297IOReturn AppleUSBCDCACMData::dequeueData(UInt8 *buffer, UInt32 size, UInt32 *count, UInt32 min, void *refCon)
3298{
3299    IOReturn 	ret;
3300
3301    XTRACE(this, size, min, "dequeueData");
3302
3303    if (fTerminate || fStopping)
3304    {
3305        XTRACE(this, 0, kIOReturnOffline, "dequeueData - Offline");
3306        return kIOReturnOffline;
3307    }
3308
3309    if ((count == NULL) || (buffer == NULL) || (min > size))
3310        return kIOReturnBadArgument;
3311
3312    retain();
3313    ret = fCommandGate->runAction(dequeueDataAction, (void *)buffer, (void *)&size, (void *)count, (void *)&min);
3314    release();
3315
3316    return ret;
3317
3318}/* end dequeueData */
3319
3320/****************************************************************************************************/
3321//
3322//		Method:		AppleUSBCDCACMData::dequeueDatatAction
3323//
3324//		Desc:		Dummy pass through for dequeueDataGated.
3325//
3326/****************************************************************************************************/
3327
3328IOReturn AppleUSBCDCACMData::dequeueDataAction(OSObject *owner, void *arg0, void *arg1, void *arg2, void *arg3)
3329{
3330
3331    return ((AppleUSBCDCACMData *)owner)->dequeueDataGated((UInt8 *)arg0, (UInt32 *)arg1, (UInt32 *)arg2, (UInt32 *)arg3);
3332
3333}/* end dequeueDataAction */
3334
3335/****************************************************************************************************/
3336//
3337//		Method:		AppleUSBCDCACMData::dequeueDataGated
3338//
3339//		Inputs:		size - buffer size
3340//				min - minimum bytes required
3341//
3342//		Outputs:	buffer - data returned
3343//				min - number of bytes
3344//				Return Code - kIOReturnSuccess, kIOReturnBadArgument, kIOReturnNotOpen, or value returned from watchState
3345//
3346//		Desc:		dequeueData will attempt to copy data from the RX queue to the
3347//				specified buffer.  No more than bufferSize VALID_DATA events
3348//				will be transferred. In other words, copying will continue until
3349//				either a non-data event is encountered or the transfer buffer
3350//				is full.  The actual number of bytes transferred is returned
3351//				in count.
3352//				The sleep semantics of this method are slightly more complicated
3353//				than other methods in this API. Basically, this method will
3354//				continue to sleep until either min characters have been
3355//				received or a non data event is next in the RX queue.  If
3356//				min is zero, then this method never sleeps and will return
3357//				immediately if the queue is empty.
3358//				Note that the caller should ALWAYS check the transferCount
3359//				unless the return value was kIOReturnBadArgument, indicating one or
3360//				more arguments were not valid.
3361//
3362/****************************************************************************************************/
3363
3364IOReturn AppleUSBCDCACMData::dequeueDataGated(UInt8 *buffer, UInt32 *pSize, UInt32 *count, UInt32 *pMin)
3365{
3366	UInt32		size = *pSize;
3367	UInt32		min = *pMin;
3368    IOReturn 	rtn = kIOReturnSuccess;
3369    UInt32		state = 0;
3370	UInt32		mask;
3371    bool		goXOIdle;
3372	UInt32		savCount;
3373	uintptr_t	addr;
3374
3375    XTRACE(this, size, min, "dequeueDataGated");
3376
3377    if (fTerminate || fStopping)
3378        return kIOReturnOffline;
3379
3380        // If the port is not active then there should not be any chars.
3381
3382    *count = 0;
3383    if (!(fPort.State & PD_S_ACTIVE))
3384        return kIOReturnNotOpen;
3385
3386        // Get any data living in the queue.
3387
3388    *count = RemovefromQueue(&fPort.RX, buffer, size);
3389	if (*count > 0)
3390	{
3391		addr = (uintptr_t)buffer;
3392		XTRACE(this, size, addr, "dequeueDataGated - Removed from Queue (first)");
3393		LogData(kDataOther, *count, buffer);
3394		CheckHold();
3395	}
3396    CheckQueues();
3397
3398    while ((min > 0) && (*count < min))
3399    {
3400            // Figure out how many bytes we have left to queue up
3401
3402        state = 0;
3403		mask = PD_S_RXQ_EMPTY;
3404        rtn = watchStateGated(&state, &mask);
3405
3406        if (rtn != kIOReturnSuccess)
3407        {
3408            XTRACE(this, 0, rtn, "dequeueDataGated - Interrupted!");
3409            return rtn;
3410        }
3411
3412            // Try and get more data starting from where we left off
3413
3414//		*count += RemovefromQueue(&fPort.RX, buffer + *count, (size - *count));
3415
3416		savCount = *count;
3417		*count += RemovefromQueue(&fPort.RX, &buffer[*count], (size - *count));
3418		addr = (uintptr_t)buffer;
3419		XTRACE(this, *count, addr, "dequeueDataGated - Removed from Queue (next)");
3420		LogData(kDataOther, *count, &buffer[savCount]);
3421		if (*count > 0)
3422		{
3423			CheckHold();
3424		}
3425        CheckQueues();
3426    }
3427
3428        // Now let's check our receive buffer to see if we need to stop
3429
3430    goXOIdle = (UsedSpaceinQueue(&fPort.RX) < fPort.RXStats.LowWater) && (fPort.RXOstate == SENT_XOFF);
3431
3432    if (goXOIdle)
3433    {
3434        fPort.RXOstate = IDLE_XO;
3435        AddBytetoQueue(&fPort.TX, fPort.XOFFchar);
3436        setUpTransmit();
3437    }
3438
3439    XTRACE(this, *count, size, "dequeueData - Exit");
3440
3441    return rtn;
3442
3443}/* end dequeueDataGated */
3444
3445/****************************************************************************************************/
3446//
3447//		Method:		AppleUSBCDCACMData::setUpTransmit
3448//
3449//		Inputs:
3450//
3451//		Outputs:	return code - true (transmit started), false (transmission already in progress)
3452//
3453//		Desc:		Setup and then start transmisson
3454//
3455/****************************************************************************************************/
3456
3457bool AppleUSBCDCACMData::setUpTransmit()
3458{
3459
3460    XTRACE(this, 0, 0, "setUpTransmit");
3461
3462        // As a precaution just check we've not been terminated (maybe a woken thread)
3463
3464    if (fTerminate || fStopping)
3465    {
3466        XTRACE(this, 0, 0, "setUpTransmit - terminated");
3467        return false;
3468    }
3469
3470    if (UsedSpaceinQueue(&fPort.TX) > 0)
3471    {
3472        startTransmission();
3473    }
3474
3475    return TRUE;
3476
3477}/* end setUpTransmit */
3478
3479/****************************************************************************************************/
3480//
3481//		Method:		AppleUSBCDCACMData::startTransmission
3482//
3483//		Inputs:
3484//
3485//		Outputs:
3486//
3487//		Desc:		Start the transmisson
3488//				Must be called from a gated method
3489//
3490/****************************************************************************************************/
3491
3492void AppleUSBCDCACMData::startTransmission()
3493{
3494    size_t		count;
3495    IOReturn	ior;
3496    UInt16		indx;
3497	bool		gotBuffer = false;
3498	UInt32		state;
3499	UInt32		mask;
3500
3501    XTRACE(this, 0, 0, "startTransmission");
3502
3503        // Get an output buffer
3504
3505	indx = fPort.outPoolIndex;
3506	if (!fPort.outPool[indx].avail)
3507	{
3508		for (indx=0; indx<fPort.outPoolIndex; indx++)
3509		{
3510			if (fPort.outPool[indx].avail)
3511			{
3512				fPort.outPoolIndex = indx;
3513				gotBuffer = true;
3514				break;
3515			}
3516		}
3517	} else {
3518		gotBuffer = true;
3519	}
3520	if (gotBuffer)
3521	{
3522		fPort.outPool[indx].avail = false;
3523		fPort.outPoolIndex++;
3524		if (fPort.outPoolIndex >= fOutBufPool)
3525		{
3526			fPort.outPoolIndex = 0;
3527		}
3528	} else {
3529		XTRACE(this, fOutBufPool, indx, "startTransmission - Output buffer unavailable");
3530        return;
3531	}
3532
3533        // Fill up the buffer with characters from the queue
3534
3535    count = RemovefromQueue(&fPort.TX, fPort.outPool[indx].pipeBuffer, MAX_BLOCK_SIZE);
3536
3537        // If there are no bytes to send just exit:
3538
3539    if (count <= 0)
3540    {
3541            // Updates all the status flags:
3542
3543        CheckQueues();
3544		fPort.outPool[indx].avail = true;
3545        return;
3546    }
3547
3548	state = PD_S_TX_BUSY;
3549	mask = PD_S_TX_BUSY;
3550    setStateGated(&state, &mask);
3551
3552    XTRACE(this, fPort.State, count, "startTransmission - Bytes to write");
3553    LogData(kDataOut, count, fPort.outPool[indx].pipeBuffer);
3554
3555    fPort.outPool[indx].count = count;
3556    fPort.outPool[indx].completionInfo.parameter = (void *)&fPort.outPool[indx];
3557    fPort.outPool[indx].pipeMDP->setLength(count);
3558
3559    ior = fPort.OutPipe->Write(fPort.outPool[indx].pipeMDP, &fPort.outPool[indx].completionInfo);
3560    if (ior != kIOReturnSuccess)
3561    {
3562        XTRACE(this, 0, ior, "startTransmission - Write failed");
3563    }
3564
3565        // We just removed a bunch of stuff from the
3566        // queue, so see if we can free some thread(s)
3567        // to enqueue more stuff.
3568
3569    CheckQueues();
3570
3571}/* end startTransmission */
3572
3573/****************************************************************************************************/
3574//
3575//		Method:		AppleUSBCDCACMData::setLineCoding
3576//
3577//		Inputs:
3578//
3579//		Outputs:
3580//
3581//		Desc:		Set up and send SetLineCoding Management Element Request(MER) for all settings.
3582//
3583/****************************************************************************************************/
3584
3585void AppleUSBCDCACMData::setLineCoding()
3586{
3587
3588    XTRACE(this, 0, 0, "setLineCoding");
3589
3590    	// Check for changes and only do it if something's changed
3591
3592    if ((fPort.BaudRate == fPort.LastBaudRate) && (fPort.StopBits == fPort.LastStopBits) &&
3593        (fPort.TX_Parity == fPort.LastTX_Parity) && (fPort.CharLength == fPort.LastCharLength))
3594    {
3595        return;
3596    }
3597
3598        // Now send it to the control driver
3599
3600	if (fControlDriver)
3601	{
3602		fControlDriver->USBSendSetLineCoding(fPort.BaudRate, fPort.StopBits, fPort.TX_Parity, fPort.CharLength);
3603	}
3604
3605	fPort.LastBaudRate = fPort.BaudRate;
3606	fPort.LastStopBits = fPort.StopBits;
3607	fPort.LastTX_Parity = fPort.TX_Parity;
3608	fPort.LastCharLength = fPort.CharLength;
3609
3610}/* end setLineCoding */
3611
3612/****************************************************************************************************/
3613//
3614//		Method:		AppleUSBCDCACMData::setControlLineState
3615//
3616//		Inputs:		RTS - true(set RTS), false(clear RTS)
3617//				DTR - true(set DTR), false(clear DTR)
3618//
3619//		Outputs:
3620//
3621//		Desc:		Set up and send SetControlLineState Management Element Request(MER).
3622//
3623/****************************************************************************************************/
3624
3625void AppleUSBCDCACMData::setControlLineState(bool RTS, bool DTR)
3626{
3627
3628    XTRACE(this, 0, 0, "setControlLineState");
3629
3630    if (fControlDriver)
3631    {
3632        fControlDriver->USBSendSetControlLineState(RTS, DTR);
3633    }
3634
3635}/* end setControlLineState */
3636
3637/****************************************************************************************************/
3638//
3639//		Method:		AppleUSBCDCACMData::sendBreak
3640//
3641//		Inputs:		sBreak - true(set Break), false(clear Break)
3642//
3643//		Outputs:
3644//
3645//		Desc:		Set up and send SendBreak Management Element Request(MER).
3646//
3647/****************************************************************************************************/
3648
3649void AppleUSBCDCACMData::sendBreak(bool sBreak)
3650{
3651
3652    XTRACE(this, 0, 0, "sendBreak");
3653
3654    if (fControlDriver)
3655    {
3656        fControlDriver->USBSendBreak(sBreak);
3657    }
3658
3659}/* end sendBreak */
3660
3661/****************************************************************************************************/
3662//
3663//		Method:		AppleUSBCDCACMData::checkPipe
3664//
3665//		Inputs:		thePipe - the pipe
3666//				devReq - true(send CLEAR_FEATURE), false(only if status returns stalled)
3667//
3668//		Outputs:
3669//
3670//		Desc:		Clear a stall on the specified pipe. If ClearPipeStall is issued
3671//				all outstanding I/O is returned with kIOUSBTransactionReturned and
3672//				a CLEAR_FEATURE Endpoint stall is sent.
3673//
3674/****************************************************************************************************/
3675
3676IOReturn AppleUSBCDCACMData::checkPipe(IOUSBPipe *thePipe, bool devReq)
3677{
3678    IOReturn 	rtn = kIOReturnSuccess;
3679
3680    XTRACEP(this, 0, thePipe, "checkPipe");
3681
3682    if (!devReq)
3683    {
3684        rtn = thePipe->GetPipeStatus();
3685        if (rtn != kIOUSBPipeStalled)
3686        {
3687            XTRACE(this, 0, rtn, "checkPipe - Pipe not stalled");
3688            return rtn;
3689        }
3690    }
3691
3692    rtn = thePipe->ClearPipeStall(true);
3693    if (rtn == kIOReturnSuccess)
3694    {
3695        XTRACE(this, 0, 0, "checkPipe - ClearPipeStall Successful");
3696    } else {
3697        XTRACE(this, 0, rtn, "checkPipe - ClearPipeStall Failed");
3698    }
3699
3700    return rtn;
3701
3702}/* end checkPipe */
3703
3704/****************************************************************************************************/
3705//
3706//		Method:		AppleUSBCDCACMData::initStructure
3707//
3708//		Inputs:
3709//
3710//		Outputs:
3711//
3712//		Desc:		Initialize the port structure
3713//
3714/****************************************************************************************************/
3715
3716void AppleUSBCDCACMData::initStructure()
3717{
3718    UInt16	i;
3719
3720    XTRACE(this, 0, 0, "initStructure");
3721
3722        // These are set up at start and should not be reset during execution.
3723
3724    fPort.FCRimage = 0x00;
3725    fPort.IERmask = 0x00;
3726
3727    fPort.State = (PD_S_TXQ_EMPTY | PD_S_TXQ_LOW_WATER | PD_S_RXQ_EMPTY | PD_S_RXQ_LOW_WATER);
3728    fPort.WatchStateMask = 0x00000000;
3729    fPort.InPipe = NULL;
3730    fPort.OutPipe = NULL;
3731    for (i=0; i<kMaxInBufPool; i++)
3732    {
3733        fPort.inPool[i].pipeMDP = NULL;
3734        fPort.inPool[i].pipeBuffer = NULL;
3735        fPort.inPool[i].dead = false;
3736		fPort.inPool[i].count = -1;
3737		fPort.inPool[i].held = false;
3738
3739		fPort.holdQueue[i] = 0;
3740    }
3741	fPort.holdQueueIndxIn = 0;
3742	fPort.holdQueueIndxOut = 0;
3743
3744    for (i=0; i<kMaxOutBufPool; i++)
3745    {
3746        fPort.outPool[i].pipeMDP = NULL;
3747        fPort.outPool[i].pipeBuffer = NULL;
3748        fPort.outPool[i].count = -1;
3749        fPort.outPool[i].avail = false;
3750    }
3751    fPort.outPoolIndex = 0;
3752
3753}/* end initStructure */
3754
3755/****************************************************************************************************/
3756//
3757//		Method:		AppleUSBCDCACMData::setStructureDefaults
3758//
3759//		Inputs:
3760//
3761//		Outputs:
3762//
3763//		Desc:		Sets the defaults for the specified port structure
3764//
3765/****************************************************************************************************/
3766
3767void AppleUSBCDCACMData::setStructureDefaults()
3768{
3769    UInt32	tmp;
3770
3771    XTRACE(this, 0, 0, "setStructureDefaults");
3772
3773    fPort.BaudRate = kDefaultBaudRate;			// 9600 bps
3774    fPort.LastBaudRate = 0;
3775    fPort.CharLength = 8;				// 8 Data bits
3776    fPort.LastCharLength = 0;
3777    fPort.StopBits = 2;					// 1 Stop bit
3778    fPort.LastStopBits = 0;
3779    fPort.TX_Parity = 1;				// No Parity
3780    fPort.LastTX_Parity	= 0;
3781    fPort.RX_Parity = 1;				// --ditto--
3782    fPort.MinLatency = false;
3783    fPort.XONchar = '\x11';
3784    fPort.XOFFchar = '\x13';
3785    fPort.FlowControl = 0x00000000;
3786    fPort.RXOstate = IDLE_XO;
3787    fPort.TXOstate = IDLE_XO;
3788    fPort.FrameTOEntry = NULL;
3789
3790    fPort.RXStats.BufferSize = kMaxCirBufferSize;
3791    fPort.RXStats.HighWater = (fPort.RXStats.BufferSize << 1) / 3;
3792    fPort.RXStats.LowWater = fPort.RXStats.HighWater >> 1;
3793    fPort.TXStats.BufferSize = kMaxCirBufferSize;
3794    fPort.TXStats.HighWater = (fPort.RXStats.BufferSize << 1) / 3;
3795    fPort.TXStats.LowWater = fPort.RXStats.HighWater >> 1;
3796
3797    fPort.FlowControl = (DEFAULT_AUTO | DEFAULT_NOTIFY);
3798
3799    for (tmp=0; tmp < (256 >> SPECIAL_SHIFT); tmp++)
3800        fPort.SWspecial[ tmp ] = 0;
3801
3802}/* end setStructureDefaults */
3803
3804/****************************************************************************************************/
3805//
3806//		Method:		AppleUSBCDCACMData::allocateResources
3807//
3808//		Inputs:
3809//
3810//		Outputs:	return code - true (allocate was successful), false (it failed)
3811//
3812//		Desc:		Finishes up the rest of the configuration and gets all the endpoints open etc.
3813//
3814/****************************************************************************************************/
3815
3816bool AppleUSBCDCACMData::allocateResources()
3817{
3818    IOUSBFindEndpointRequest	epReq;
3819    UInt16			i;
3820
3821    XTRACE(this, 0, 0, "allocateResources.");
3822
3823        // Open all the end points and get the buffers
3824
3825    if (!fDataInterface->open(this))
3826    {
3827        XTRACE(this, 0, 0, "allocateResources - open data interface failed.");
3828        return false;
3829    }
3830
3831        // Bulk In pipe
3832
3833    epReq.type = kUSBBulk;
3834    epReq.direction = kUSBIn;
3835    epReq.maxPacketSize	= 0;
3836    epReq.interval = 0;
3837    fPort.InPipe = fDataInterface->FindNextPipe(0, &epReq);
3838    if (!fPort.InPipe)
3839    {
3840        XTRACE(this, 0, 0, "allocateResources - no bulk input pipe.");
3841        return false;
3842    }
3843    fPort.InPacketSize = epReq.maxPacketSize;
3844    XTRACE(this, epReq.maxPacketSize << 16 |epReq.interval, 0, "allocateResources - bulk input pipe.");
3845
3846        // Allocate Memory Descriptor Pointer with memory for the bulk in pipe
3847
3848    for (i=0; i<fInBufPool; i++)
3849    {
3850//        fPort.inPool[i].pipeMDP = IOBufferMemoryDescriptor::withCapacity(DATA_BUFF_SIZE, kIODirectionIn);
3851        fPort.inPool[i].pipeMDP = IOBufferMemoryDescriptor::withOptions(kIODirectionIn | kIOMemoryPhysicallyContiguous, DATA_BUFF_SIZE, PAGE_SIZE);
3852        if (!fPort.inPool[i].pipeMDP)
3853        {
3854            XTRACE(this, 0, i, "allocateResources - Allocate input MDP failed");
3855            return false;
3856        }
3857        fPort.inPool[i].pipeBuffer = (UInt8*)fPort.inPool[i].pipeMDP->getBytesNoCopy();
3858        XTRACEP(this, fPort.inPool[i].pipeMDP, fPort.inPool[i].pipeBuffer, "allocateResources - input buffer");
3859        fPort.inPool[i].dead = false;
3860    }
3861
3862        // Bulk Out pipe
3863
3864    epReq.direction = kUSBOut;
3865    fPort.OutPipe = fDataInterface->FindNextPipe(0, &epReq);
3866    if (!fPort.OutPipe)
3867    {
3868        XTRACE(this, 0, 0, "allocateResources - no bulk output pipe.");
3869        return false;
3870    }
3871    fPort.OutPacketSize = epReq.maxPacketSize;
3872    XTRACE(this, epReq.maxPacketSize << 16 |epReq.interval, 0, "allocateResources - bulk output pipe.");
3873
3874        // Allocate Memory Descriptor Pointer with memory for the bulk out pipe
3875
3876    for (i=0; i<fOutBufPool; i++)
3877    {
3878//        fPort.outPool[i].pipeMDP = IOBufferMemoryDescriptor::withCapacity(MAX_BLOCK_SIZE, kIODirectionOut);
3879        fPort.outPool[i].pipeMDP = IOBufferMemoryDescriptor::withOptions(kIODirectionOut | kIOMemoryPhysicallyContiguous, MAX_BLOCK_SIZE, PAGE_SIZE);
3880        if (!fPort.outPool[i].pipeMDP)
3881        {
3882            XTRACE(this, 0, i, "allocateResources - Allocate output MDP failed");
3883            return false;
3884        }
3885        fPort.outPool[i].pipeBuffer = (UInt8*)fPort.outPool[i].pipeMDP->getBytesNoCopy();
3886        XTRACEP(this, fPort.outPool[i].pipeMDP, fPort.outPool[i].pipeBuffer, "allocateResources - output buffer");
3887        fPort.outPool[i].avail = true;
3888    }
3889
3890        // Now the ring buffers
3891
3892    if (!allocateRingBuffer(&fPort.TX, fPort.TXStats.BufferSize))
3893    {
3894        XTRACE(this, 0, 0, "allocateResources - Couldn't allocate TX ring buffer");
3895        return false;
3896    }
3897
3898    XTRACEP(this, 0, fPort.TX.Start, "allocateResources - TX ring buffer");
3899
3900    if (!allocateRingBuffer(&fPort.RX, fPort.RXStats.BufferSize))
3901    {
3902        XTRACE(this, 0, 0, "allocateResources - Couldn't allocate RX ring buffer");
3903        return false;
3904    }
3905
3906    XTRACEP(this, 0, fPort.RX.Start, "allocateResources - RX ring buffer");
3907
3908    return true;
3909
3910}/* end allocateResources */
3911
3912/****************************************************************************************************/
3913//
3914//		Method:		AppleUSBCDCACMData::releaseResources
3915//
3916//		Inputs:
3917//
3918//		Outputs:
3919//
3920//		Desc:		Frees up the resources allocated in allocateResources
3921//
3922/****************************************************************************************************/
3923
3924void AppleUSBCDCACMData::releaseResources()
3925{
3926    UInt16	i;
3927
3928    XTRACE(this, 0, 0, "releaseResources");
3929
3930	if (fDataInterface)
3931    {
3932        fDataInterface->close(this);
3933        fDataInterface->release();
3934        fDataInterface = NULL;
3935    }
3936
3937    for (i=0; i<fInBufPool; i++)
3938    {
3939        if (fPort.inPool[i].pipeMDP)
3940        {
3941            fPort.inPool[i].pipeMDP->release();
3942            fPort.inPool[i].pipeMDP = NULL;
3943            fPort.inPool[i].dead = false;
3944        }
3945    }
3946
3947    for (i=0; i<fOutBufPool; i++)
3948    {
3949        if (fPort.outPool[i].pipeMDP)
3950        {
3951            fPort.outPool[i].pipeMDP->release();
3952            fPort.outPool[i].pipeMDP = NULL;
3953            fPort.outPool[i].count = -1;
3954            fPort.outPool[i].avail = false;
3955        }
3956    }
3957    fPort.outPoolIndex = 0;
3958
3959    if (fWorkLoop)
3960    {
3961        fWorkLoop->release();
3962        fWorkLoop = NULL;
3963    }
3964
3965    freeRingBuffer(&fPort.TX);
3966    freeRingBuffer(&fPort.RX);
3967
3968}/* end releaseResources */
3969
3970/****************************************************************************************************/
3971//
3972//		Method:		AppleUSBCDCACMData::freeRingBuffer
3973//
3974//		Inputs:		Queue - the specified queue to free
3975//
3976//		Outputs:
3977//
3978//		Desc:		Frees all resources assocated with the queue, then sets all queue parameters
3979//				to safe values.
3980//
3981/****************************************************************************************************/
3982
3983void AppleUSBCDCACMData::freeRingBuffer(CirQueue *Queue)
3984{
3985    XTRACEP(this, 0, Queue, "freeRingBuffer");
3986
3987    if (Queue)
3988    {
3989        if (Queue->Start)
3990        {
3991            IOFree(Queue->Start, Queue->Size);
3992        }
3993        CloseQueue(Queue);
3994    }
3995
3996}/* end freeRingBuffer */
3997
3998/****************************************************************************************************/
3999//
4000//		Method:		AppleUSBCDCACMData::allocateRingBuffer
4001//
4002//		Inputs:		Queue - the specified queue to allocate
4003//				BufferSize - size to allocate
4004//
4005//		Outputs:	return Code - true (buffer allocated), false (it failed)
4006//
4007//		Desc:		Allocates resources needed by the queue, then sets up all queue parameters.
4008//
4009/****************************************************************************************************/
4010
4011bool AppleUSBCDCACMData::allocateRingBuffer(CirQueue *Queue, size_t BufferSize)
4012{
4013    UInt8	*Buffer;
4014
4015        // Size is ignored and kMaxCirBufferSize, which is 4096, is used.
4016
4017    XTRACE(this, 0, BufferSize, "allocateRingBuffer");
4018    Buffer = (UInt8*)IOMalloc(kMaxCirBufferSize);
4019
4020    InitQueue(Queue, Buffer, kMaxCirBufferSize);
4021
4022    if (Buffer)
4023        return true;
4024
4025    return false;
4026
4027}/* end allocateRingBuffer */
4028
4029/****************************************************************************************************/
4030//
4031//		Function:	AppleUSBCDCACMData::handleSettingCallback
4032//
4033//		Inputs:
4034//
4035//		Outputs:	none
4036//
4037//		Desc:		Handles the async Wake on Ring setting
4038//
4039/****************************************************************************************************/
4040
4041void AppleUSBCDCACMData::handleSettingCallback(const OSSymbol *arg_type, OSObject *arg_val, uintptr_t refcon)
4042{
4043    UInt32				WoR;
4044
4045	XTRACE(this, 0, 0, "handleSettingCallback");
4046
4047    WoR = ((OSNumber *)arg_val)->unsigned32BitValue();
4048
4049	if (arg_type == gPMWakeOnRingSymbol)
4050	{
4051		if (WoR != fWoR)
4052		{
4053			fWoR = WoR;
4054			if (fTerminate || fStopping)
4055			{
4056				XTRACE(this, 0, 0, "handleSettingCallback - Offline");
4057				return;
4058			}
4059			setWakeFeature();
4060		} else {
4061			XTRACE(this, 0, 0, "handleSettingCallback - Wake on Ring unchanged");
4062		}
4063    }
4064
4065}/* end handleSettingCallback */
4066
4067/****************************************************************************************************/
4068//
4069//		Function:	AppleUSBCDCACMData::setupWakeOnRingPMCallback
4070//
4071//		Inputs:		none
4072//
4073//		Outputs:	return code - true( callback enabled), false(disabled)
4074//
4075//		Desc:		Set up the PM callback for Wake on Ring
4076//
4077/****************************************************************************************************/
4078
4079bool AppleUSBCDCACMData::setupWakeOnRingPMCallback()
4080{
4081	IOReturn		ior;
4082	bool			worOK = false;
4083    const OSSymbol	*settings_arr[] = {gPMWakeOnRingSymbol, (const OSSymbol *)NULL};
4084
4085	XTRACE(this, 0, 0, "setupWakeOnRingPMCallback");
4086
4087	if (fPMRootDomain)
4088	{
4089		fPMRootDomain->publishFeature("WakeOnRing");
4090
4091		ior = fPMRootDomain->registerPMSettingController(settings_arr,
4092														 OSMemberFunctionCast(IOPMSettingControllerCallback,
4093														 (OSObject*)this,
4094														 &AppleUSBCDCACMData::handleSettingCallback),
4095														 (OSObject *)this,
4096														 (uintptr_t)NULL,
4097														 (OSObject **)&fWakeSettingControllerHandle);
4098		if (ior == kIOReturnSuccess)
4099		{
4100			XTRACE(this, 0, 0, "setupWakeOnRingPMCallback - Setting PM callback successful");
4101			worOK = true;
4102		} else {
4103			XTRACE(this, 0, 0, "setupWakeOnRingPMCallback - Setting PM callback failed, wake-on-ring set at start only");
4104		}
4105	} else {
4106		XTRACE(this, 0, 0, "setupWakeOnRingPMCallback - PM root domain is invalid, wake-on-ring set at start only");
4107	}
4108
4109    return worOK;
4110
4111}/* end setupWakeOnRingPMCallback */
4112
4113/****************************************************************************************************/
4114//
4115//		Function:	AppleUSBCDCACMData::WakeonRing
4116//
4117//		Inputs:		none
4118//
4119//		Outputs:	return code - true(always at the moment...)
4120//
4121//		Desc:		Get the current Wake on Ring setting
4122//
4123/****************************************************************************************************/
4124
4125bool AppleUSBCDCACMData::WakeonRing(void)
4126{
4127    OSObject	*initWORValue = NULL;
4128	UInt32		worVal;
4129
4130    XTRACE(this, 0, 0, "WakeonRing");
4131
4132    fPMRootDomain = getPMRootDomain();
4133	if (fPMRootDomain)
4134	{
4135		fPMRootDomain->registerInterestedDriver(this);
4136		initWORValue = fPMRootDomain->copyPMSetting((OSSymbol *)gPMWakeOnRingSymbol);
4137		if (initWORValue)
4138		{
4139			worVal = ((OSNumber *)initWORValue)->unsigned32BitValue();
4140			if (worVal)
4141			{
4142				XTRACE(this, 0, worVal, "WakeonRing - Wake on Ring Enabled");
4143				fWoR = true;
4144			} else {
4145				XTRACE(this, 0, 0, "WakeonRing - Wake on Ring Disabled");
4146			}
4147		} else {
4148			XTRACE(this, 0, 0, "WakeonRing - Initial Wake on Ring unavailable, now disabled...");
4149		}
4150	} else {
4151		XTRACE(this, 0, 0, "WakeonRing - Remote wake up is disabled");
4152	}
4153
4154    return true;
4155
4156}/* end WakeonRing */
4157
4158/****************************************************************************************************/
4159//
4160//		Function:	AppleUSBCDCACMData::setWakeFeature
4161//
4162//		Inputs:		none
4163//
4164//		Outputs:	none
4165//
4166//		Desc:		Check the wake-on-ring feature and send the device request
4167//
4168/****************************************************************************************************/
4169
4170void AppleUSBCDCACMData::setWakeFeature(void)
4171{
4172	IOUSBDevRequest devreq;
4173	IOReturn		ior;
4174
4175    XTRACE(this, 0, 0, "setWakeFeature");
4176
4177		// Set/Clear the Device Remote Wake feature depending upon wake-on-ring
4178
4179	devreq.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBStandard, kUSBDevice);
4180	if (!fWoR)
4181	{
4182		devreq.bRequest = kUSBRqClearFeature;
4183	} else {
4184		devreq.bRequest = kUSBRqSetFeature;
4185	}
4186	devreq.wValue = kUSBFeatureDeviceRemoteWakeup;
4187	devreq.wIndex = 0;
4188	devreq.wLength = 0;
4189	devreq.pData = 0;
4190
4191	ior = fDataInterface->GetDevice()->DeviceRequest(&devreq);
4192	if (ior == kIOReturnSuccess)
4193	{
4194		XTRACE(this, fWoR, ior, "setWakeFeature - Set/Clear remote wake up feature successful");
4195	} else {
4196		XTRACE(this, fWoR, ior, "setWakeFeature - Set/Clear remote wake up feature failed");
4197	}
4198
4199}/* end setWakeFeature */
4200
4201/****************************************************************************************************/
4202//
4203//		Method:		AppleUSBCDCACMData::clearSleepingThreads
4204//
4205//		Inputs:
4206//
4207//		Outputs:
4208//
4209//		Desc:		Try to clear any threads asleep on the command gate
4210//
4211/****************************************************************************************************/
4212
4213void AppleUSBCDCACMData::clearSleepingThreads()
4214{
4215
4216	XTRACE(this, 0, fThreadSleepCount, "clearSleepingThreads");
4217
4218        // If we still have a command gate clean up anything sleeping on it
4219
4220    if (fCommandGate)
4221    {
4222        if (fThreadSleepCount > 0)
4223        {
4224            fPort.WatchStateMask = 0;
4225            fCommandGate->commandWakeup((void *)&fPort.State);
4226        }
4227    }
4228
4229}/* end clearSleepingThreads */
4230
4231/****************************************************************************************************/
4232//
4233//		Method:		AppleUSBCDCACMData::resurrectRead
4234//
4235//		Inputs:
4236//
4237//		Outputs:
4238//
4239//		Desc:		Try and resurrect any dead reads
4240//
4241/****************************************************************************************************/
4242
4243void AppleUSBCDCACMData::resurrectRead()
4244{
4245    UInt16		i;
4246	IOReturn	rtn;
4247
4248	XTRACE(this, 0, 0, "resurrectRead");
4249
4250		// Let's check the pipes first
4251
4252	if (fPort.InPipe)
4253	{
4254		checkPipe(fPort.InPipe, false);
4255	}
4256
4257	if (fPort.OutPipe)
4258	{
4259		checkPipe(fPort.OutPipe, false);
4260	}
4261
4262	for (i=0; i<fInBufPool; i++)
4263	{
4264		if (fPort.inPool[i].pipeMDP)
4265		{
4266			if (fPort.inPool[i].dead)
4267			{
4268				rtn = fPort.InPipe->Read(fPort.inPool[i].pipeMDP, &fPort.inPool[i].completionInfo, NULL);
4269				if (rtn != kIOReturnSuccess)
4270				{
4271					XTRACE(this, i, rtn, "resurrectRead - Read for bulk-in pipe failed, still dead");
4272				} else {
4273					XTRACEP(this, &fPort.inPool[i], fPort.InPipe, "resurrectRead - Read posted");
4274					fPort.inPool[i].dead = false;
4275				}
4276			}
4277		}
4278	}
4279
4280}/* end resurrectRead */
4281
4282/****************************************************************************************************/
4283//
4284//		Method:		AppleUSBCDCACMData::didTerminate
4285//
4286//		Inputs:		type - provider - my provider
4287//					options - additional parameters
4288//					defer - defer flag
4289//
4290//		Outputs:	return Code
4291//
4292//		Desc:		Handle did termination notification
4293//
4294/****************************************************************************************************/
4295
4296bool AppleUSBCDCACMData::didTerminate(IOService *provider, IOOptionBits options, bool *defer)
4297{
4298	bool	result = false;
4299
4300	XTRACE(this, 0, fThreadSleepCount, "didTerminate");
4301
4302    fTerminate = true;                  // Just to make sure
4303
4304    clearSleepingThreads();             // All the threads should be gone by now but make sure
4305
4306	result = super::didTerminate(provider, options, defer);
4307
4308	return result;
4309
4310}/* end didTerminate */
4311
4312/****************************************************************************************************/
4313//
4314//		Method:		AppleUSBCDCACMData::message
4315//
4316//		Inputs:		type - message type
4317//                  provider - my provider
4318//                  argument - additional parameters
4319//
4320//		Outputs:	return Code - kIOReturnSuccess
4321//
4322//		Desc:		Handles IOKit messages.
4323//
4324/****************************************************************************************************/
4325
4326IOReturn AppleUSBCDCACMData::message(UInt32 type, IOService *provider, void *argument)
4327{
4328
4329    XTRACE(this, 0, type, "message");
4330
4331    switch (type)
4332    {
4333        case kIOMessageServiceIsTerminated:
4334            XTRACE(this, fSessions, type, "message - kIOMessageServiceIsTerminated");
4335
4336			if (!fSuppressWarning)
4337			{
4338				if (fSessions)
4339				{
4340					if (!fTerminate)		// Check if we're already being terminated
4341					{
4342#if 0
4343							// NOTE! This call below depends on the hard coded path of this KEXT. Make sure
4344							// that if the KEXT moves, this path is changed!
4345						KUNCUserNotificationDisplayNotice(
4346						10,		// Timeout in seconds
4347						0,		// Flags (for later usage)
4348						"",		// iconPath (not supported yet)
4349						"",		// soundPath (not supported yet)
4350						"/System/Library/Extensions/IOUSBFamily.kext/Contents/PlugIns/AppleUSBCDCACMData.kext",		// localizationPath
4351						"Unplug Header",		// the header
4352						"Unplug Notice",		// the notice - look in Localizable.strings
4353						"OK");
4354#endif
4355					}
4356				}
4357			}
4358
4359            fTerminate = true;		// We're being terminated (unplugged) let's see if we can clean up some threads and release some stuff
4360
4361            releaseResources();
4362            return kIOReturnSuccess;
4363
4364        case kIOMessageServiceIsSuspended:
4365            XTRACE(this, 0, type, "message - kIOMessageServiceIsSuspended");
4366            break;
4367        case kIOMessageServiceIsResumed:
4368            XTRACE(this, 0, type, "message - kIOMessageServiceIsResumed");
4369            break;
4370        case kIOMessageServiceIsRequestingClose:
4371            XTRACE(this, 0, type, "message - kIOMessageServiceIsRequestingClose");
4372            break;
4373        case kIOMessageServiceWasClosed:
4374            XTRACE(this, 0, type, "message - kIOMessageServiceWasClosed");
4375            break;
4376        case kIOMessageServiceBusyStateChange:
4377            XTRACE(this, 0, type, "message - kIOMessageServiceBusyStateChange");
4378            break;
4379        case kIOUSBMessagePortHasBeenResumed:
4380            XTRACE(this, 0, type, "message - kIOUSBMessagePortHasBeenResumed");
4381            resurrectRead();
4382            return kIOReturnSuccess;
4383        case kIOUSBMessageHubResumePort:
4384            XTRACE(this, 0, type, "message - kIOUSBMessageHubResumePort");
4385            break;
4386        case kIOUSBMessagePortHasBeenReset:
4387            XTRACE(this, 0, type, "message - kIOUSBMessagePortHasBeenReset");
4388			resurrectRead();
4389			if (fConfigAttributes & kUSBAtrRemoteWakeup)
4390			{
4391				setWakeFeature();
4392			}
4393            return kIOReturnSuccess;
4394        default:
4395            XTRACE(this, 0, type, "message - unknown message");
4396            break;
4397    }
4398
4399    return super::message(type, provider, argument);
4400
4401}/* end message */
4402
4403/****************************************************************************************************/
4404//
4405//		Method:		AppleUSBCDCACMData::getPortNameForInterface
4406//
4407//		Inputs:		interfaceNumber - the number of the interface we're interested in
4408//
4409//		Outputs:	return Code - NULL (not found) or the name
4410//
4411//		Desc:		Gets the name from the mapping
4412//
4413/****************************************************************************************************/
4414
4415OSString *AppleUSBCDCACMData::getPortNameForInterface(UInt8 interfaceNumber)
4416{
4417	OSSymbol *ttyName = NULL;
4418	char	 endPointAddrStr[16];
4419
4420	XTRACE(this, 0, interfaceNumber, "getPortNameForInterface");
4421
4422	if (fInterfaceMappings)
4423	{
4424		snprintf(endPointAddrStr,sizeof(endPointAddrStr),"%d",interfaceNumber);
4425		ttyName = (OSSymbol *)fInterfaceMappings->getObject(endPointAddrStr);
4426	 }
4427
4428	return ttyName;
4429
4430}/* end getPortNameForInterface */
4431
4432#undef  super
4433#define super IOUserClient
4434
4435OSDefineMetaClassAndStructors(AppleUSBCDCACMDataUserClient, IOUserClient);
4436
4437/****************************************************************************************************/
4438//
4439//		Method:		AppleUSBCDCACMDataUserClient::getTargetAndMethodForIndex
4440//
4441//		Inputs:
4442//
4443//		Outputs:	return code - method index
4444//
4445//		Desc:		Get the method index.
4446//
4447/****************************************************************************************************/
4448
4449//IOExternalMethod *AppleUSBCDCACMDataUserClient::getExternalMethodForIndex(UInt32 index)
4450IOExternalMethod *AppleUSBCDCACMDataUserClient::getTargetAndMethodForIndex(IOService **targetP, UInt32 index)
4451{
4452    IOExternalMethod	*result = NULL;
4453
4454    XTRACE(this, 0, index, "getTargetAndMethodForIndex");
4455
4456    if (index == 0)
4457    {
4458        result = &fMethods[0];
4459		*targetP = this;
4460    }
4461
4462    return result;
4463
4464}/* end getTargetAndMethodForIndex */
4465
4466/****************************************************************************************************/
4467//
4468//		Method:		AppleUSBCDCACMDataUserClient::initWithTask
4469//
4470//		Inputs:		owningTask - the owner
4471//					security_id - Security ID
4472//					type - Client code (lucky number)
4473//
4474//		Outputs:	true - it worked, false - it didn't
4475//
4476//		Desc:		Set up the user client task.
4477//
4478/****************************************************************************************************/
4479
4480bool AppleUSBCDCACMDataUserClient::initWithTask(task_t owningTask, void *security_id , UInt32 type)
4481{
4482
4483    XTRACE(this, 0, 0, "initWithTask");
4484
4485    if (!super::initWithTask(owningTask, security_id, type))
4486    {
4487        XTRACE(this, 0, 0, "initWithTask - super failed");
4488        return false;
4489    }
4490
4491    if (!owningTask)
4492    {
4493        XTRACE(this, 0, 0, "initWithTask - No owning task");
4494		return false;
4495    }
4496
4497    fTask = owningTask;
4498    fProvider = NULL;
4499
4500    return true;
4501
4502}/* end initWithTask */
4503
4504/****************************************************************************************************/
4505//
4506//		Method:		AppleUSBCDCACMDataUserClient::start
4507//
4508//		Inputs:		provider - my provider
4509//
4510//		Outputs:	return code - true(it worked), false (it didn't)
4511//
4512//		Desc:		Start the user client task.
4513//
4514/****************************************************************************************************/
4515
4516bool AppleUSBCDCACMDataUserClient::start(IOService *provider)
4517{
4518
4519    XTRACE(this, 0, 0, "start");
4520
4521    if (super::start(provider) == false)
4522    {
4523        XTRACE(this, 0, 0, "start - Provider start failed");
4524        return false;
4525    }
4526
4527    fProvider = OSDynamicCast(AppleUSBCDCACMData, provider);
4528    if (!fProvider)
4529    {
4530        XTRACE(this, 0, 0, "start - Provider invalid");
4531		return false;
4532    }
4533
4534        // Initialize the call structure
4535
4536    fMethods[0].object = this;
4537    fMethods[0].func   = (IOMethod)&AppleUSBCDCACMDataUserClient::doRequest;
4538    fMethods[0].count0 = 0xFFFFFFFF;			/* One input  as big as I need */
4539    fMethods[0].count1 = 0xFFFFFFFF;			/* One output as big as I need */
4540    fMethods[0].flags  = kIOUCStructIStructO;
4541
4542    return true;
4543
4544}/* end start */
4545
4546/****************************************************************************************************/
4547//
4548//		Method:		AppleUSBCDCACMDataUserClient::clientClose
4549//
4550//		Inputs:
4551//
4552//		Outputs:	return code - kIOReturnSuccess
4553//
4554//		Desc:		Close things down.
4555//
4556/****************************************************************************************************/
4557
4558IOReturn AppleUSBCDCACMDataUserClient::clientClose()
4559{
4560
4561    XTRACE(this, 0, 0, "clientClose");
4562
4563    if (!fProvider)
4564    {
4565        XTRACE(this, 0, 0, "clientClose - Not attached");
4566        return kIOReturnNotAttached;
4567    }
4568
4569        // Make sure it's open before we close it.
4570
4571    if (fProvider->isOpen(this))
4572        fProvider->close(this);
4573
4574    fTask = NULL;
4575    fProvider = NULL;
4576
4577    return kIOReturnSuccess;
4578
4579}/* end clientClose */
4580
4581/****************************************************************************************************/
4582//
4583//		Method:		AppleUSBCDCACMDataUserClient::clientDied
4584//
4585//		Inputs:
4586//
4587//		Outputs:	return code - kIOReturnSuccess
4588//
4589//		Desc:		Close it down now.
4590//
4591/****************************************************************************************************/
4592
4593IOReturn AppleUSBCDCACMDataUserClient::clientDied()
4594{
4595
4596    XTRACE(this, 0, 0, "clientDied");
4597
4598    return clientClose();
4599
4600}/* end clientDied */
4601
4602/****************************************************************************************************/
4603//
4604//		Method:		AppleUSBCDCACMDataUserClient::doRequest
4605//
4606//		Inputs:		pIn - the input buffer
4607//					pOut - the output buffer
4608//					inputSize - Size of input buffer
4609//					pOutPutSize - Size of output buffer
4610//
4611//		Outputs:	pOutSize - Number of bytes returned
4612//					return code - kIOReturnSuccess or kIOReturnBadArgument
4613//
4614//		Desc:		Execute the client request.
4615//
4616/****************************************************************************************************/
4617
4618IOReturn AppleUSBCDCACMDataUserClient::doRequest(void *pIn, void *pOut, IOByteCount inputSize, IOByteCount *pOutPutSize)
4619{
4620    UInt8	*input;
4621
4622    XTRACE(this, 0, 0, "doRequest");
4623
4624        // Make sure we actually have a provider
4625
4626    if (!fProvider)
4627    {
4628        XTRACE(this, 0, 0, "doRequest - Not attached");
4629        return kIOReturnNotAttached;
4630    }
4631
4632	// check first byte of input data for a command code
4633
4634    if (pIn && (inputSize > 0))
4635    {
4636        input = (UInt8 *)pIn;
4637
4638            // 1st byte of input has request ID
4639
4640        switch (*input)
4641        {
4642            case cmdACMData_Message:
4643                return ACMDataMessage(pIn, pOut, inputSize, pOutPutSize);
4644
4645            default:
4646               XTRACE(this, 0, *input, "doRequest - Invalid command");
4647               break;
4648        }
4649    } else {
4650        XTRACE(this, 0, inputSize, "doRequest - pIn/pOut or size error");
4651    }
4652
4653    return kIOReturnBadArgument;
4654
4655}/* end doRequest */
4656
4657/****************************************************************************************************/
4658//
4659//		Method:		AppleUSBCDCACMDataUserClient::ACMDataMessage
4660//
4661//		Inputs:		pIn - the input structure
4662//					pOut - the output structure
4663//					inputSize - Size of the input structure
4664//					pOutSize - Size of the output structure
4665//
4666//		Outputs:	return code - kIOReturnSuccess
4667//
4668//		Desc:		Process the message
4669//
4670/****************************************************************************************************/
4671
4672IOReturn AppleUSBCDCACMDataUserClient::ACMDataMessage(void *pIn, void *pOut, IOByteCount inputSize, IOByteCount *pOutPutSize)
4673{
4674	dataParms	*input = (dataParms *)pIn;
4675    statusData	*output = (statusData *)pOut;
4676
4677    XTRACE(this, 0, 0, "ACMDataMessage");
4678
4679	switch (input->message)
4680    {
4681		case noWarning:
4682			XTRACE(this, 0, 0, "ACMDataMessage - noWarning");
4683			if ((input->vendor == fProvider->fVendorID) && (input->product == fProvider->fProductID))
4684			{
4685				XTRACE(this, fProvider->fVendorID, fProvider->fProductID, "ACMDataMessage - Unplug warning dialog is being suppressed");
4686				fProvider->fSuppressWarning = true;
4687				output->status = kSuccess;
4688			} else {
4689				XTRACE(this, 0, 0, "ACMDataMessage - noWarning, not my device");
4690				output->status = kError;
4691			}
4692			break;
4693		case warning:
4694			XTRACE(this, 0, 0, "ACMDataMessage - warning");
4695			if ((input->vendor == fProvider->fVendorID) && (input->product == fProvider->fProductID))
4696			{
4697				XTRACE(this, fProvider->fVendorID, fProvider->fProductID, "ACMDataMessage - Unplug warning dialog is being re-instated");
4698				fProvider->fSuppressWarning = false;
4699				output->status = kSuccess;
4700			} else {
4701				XTRACE(this, 0, 0, "ACMDataMessage - warning, not my device");
4702				output->status = kError;
4703			}
4704			break;
4705		default:
4706			XTRACE(this, 0, 0, "ACMDataMessage - Invalid message");
4707			output->status = kError;
4708			break;
4709	}
4710
4711    return kIOReturnSuccess;
4712
4713}/* end ACMDataMessage */