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