1/*
2 *
3 * @APPLE_LICENSE_HEADER_START@
4 *
5 * Copyright (c) 1998-2004 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    /* AppleUSBCDCDMM.cpp - MacOSX implementation of		*/
26    /* USB Communication Device Class (CDC) Driver, DMM 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 "AppleUSBCDCDMM"
58
59#include "AppleUSBCDCDMM.h"
60
61#define MIN_BAUD (50 << 1)
62
63    // Globals
64
65#define super IOSerialDriverSync
66
67OSDefineMetaClassAndStructors(AppleUSBCDCDMM, IOSerialDriverSync);
68
69#if LOG_DATA
70#define dumplen		32		// Set this to the number of bytes to dump and the rest should work out correct
71
72#define buflen		((dumplen*2)+dumplen)+3
73#define Asciistart	(dumplen*2)+3
74
75/****************************************************************************************************/
76//
77//		Function:	USBLogData
78//
79//		Inputs:		Dir - direction
80//				Count - number of bytes
81//				buf - the data
82//
83//		Outputs:
84//
85//		Desc:		Puts the data in the log.
86//
87/****************************************************************************************************/
88
89void AppleUSBCDCDMM::USBLogData(UInt8 Dir, SInt32 Count, char *buf)
90{
91    SInt32	wlen;
92    SInt32	llen, rlen;
93    SInt16	i, Aspnt, Hxpnt;
94    UInt8	wchr;
95    char	LocBuf[buflen+1];
96
97    switch (Dir)
98    {
99        case kDataIn:
100            Log( "AppleUSBCDCDMM: USBLogData - Read Complete, address = %8p, size = %8d\n", (void *)buf, (UInt)Count );
101            break;
102        case kDataOut:
103            Log( "AppleUSBCDCDMM: USBLogData - Write, address = %8p, size = %8d\n", (void *)buf, (UInt)Count );
104            break;
105        case kDataOther:
106            Log( "AppleUSBCDCDMM: USBLogData - Other, address = %8p, size = %8d\n", (void *)buf, (UInt)Count );
107            break;
108    }
109
110#if DUMPALL
111    wlen = Count;
112#else
113    if (Count > dumplen)
114    {
115        wlen = dumplen;
116    } else {
117        wlen = Count;
118    }
119#endif
120
121    if (wlen == 0)
122    {
123        Log( "AppleUSBCDCDMM: USBLogData - No data, Count=0\n" );
124        return;
125    }
126
127    rlen = 0;
128    do
129    {
130        memset(LocBuf, 0x20, buflen);
131
132        if (wlen > dumplen)
133        {
134            llen = dumplen;
135            wlen -= dumplen;
136        } else {
137            llen = wlen;
138            wlen = 0;
139        }
140        Aspnt = Asciistart;
141        Hxpnt = 0;
142        for (i=1; i<=llen; i++)
143        {
144            wchr = buf[i-1];
145            LocBuf[Hxpnt++] = Asciify(wchr >> 4);
146            LocBuf[Hxpnt++] = Asciify(wchr);
147            if ((wchr < 0x20) || (wchr > 0x7F)) 		// Non printable characters
148            {
149                LocBuf[Aspnt++] = 0x2E;				// Replace with a period
150            } else {
151                LocBuf[Aspnt++] = wchr;
152            }
153        }
154        LocBuf[Aspnt] = 0x00;
155
156		Log("%s\n", LocBuf);
157#if USE_IOL
158        IOSleep(Sleep_Time);					// Try and keep the log from overflowing
159#endif
160        rlen += llen;
161        buf = &buf[rlen];
162    } while (wlen != 0);
163
164}/* end USBLogData */
165#endif
166
167/****************************************************************************************************/
168//
169//		Method:		AddBytetoQueue
170//
171//		Inputs:		Queue - the queue to be added to
172//				Value - Byte to be added
173//
174//		Outputs:	Queue status - full or no error
175//
176//		Desc:		Add a byte to the circular queue.
177//				Check to see if there is space by comparing the next pointer,
178//				with the last, If they match we are either Empty or full, so
179//				check InQueue for zero.
180//
181/****************************************************************************************************/
182
183QueueStatus AppleUSBCDCDMM::AddBytetoQueue(CirQueue *Queue, char Value)
184{
185
186    if ((Queue->NextChar == Queue->LastChar) && Queue->InQueue)
187    {
188        return queueFull;
189    }
190
191    *Queue->NextChar++ = Value;
192    Queue->InQueue++;
193
194        // Check to see if we need to wrap the pointer.
195
196    if (Queue->NextChar >= Queue->End)
197        Queue->NextChar =  Queue->Start;
198
199    return queueNoError;
200
201}/* end AddBytetoQueue */
202
203/****************************************************************************************************/
204//
205//		Method:		GetBytetoQueue
206//
207//		Inputs:		Queue - the queue to be removed from
208//
209//		Outputs:	Value - where to put the byte
210//				QueueStatus - empty or no error
211//
212//		Desc:		Remove a byte from the circular queue.
213//
214/****************************************************************************************************/
215
216QueueStatus AppleUSBCDCDMM::GetBytetoQueue(CirQueue *Queue, UInt8 *Value)
217{
218
219    if ((Queue->NextChar == Queue->LastChar) && !Queue->InQueue)
220    {
221        return queueEmpty;
222    }
223
224    *Value = *Queue->LastChar++;
225    Queue->InQueue--;
226
227        // Check to see if we need to wrap the pointer.
228
229    if (Queue->LastChar >= Queue->End)
230        Queue->LastChar =  Queue->Start;
231
232    return queueNoError;
233
234}/* end GetBytetoQueue */
235
236/****************************************************************************************************/
237//
238//		Method:		InitQueue
239//
240//		Inputs:		Queue - the queue to be initialized
241//				Buffer - the buffer
242//				size - length of buffer
243//
244//		Outputs:	QueueStatus - queueNoError.
245//
246//		Desc:		Pass a buffer of memory and this routine will set up the internal data structures.
247//
248/****************************************************************************************************/
249
250QueueStatus AppleUSBCDCDMM::InitQueue(CirQueue *Queue, UInt8 *Buffer, size_t Size)
251{
252    Queue->Start	= Buffer;
253    Queue->End		= (UInt8*)((size_t)Buffer + Size);
254    Queue->Size		= Size;
255    Queue->NextChar	= Buffer;
256    Queue->LastChar	= Buffer;
257    Queue->InQueue	= 0;
258
259//    IOSleep(1);
260
261    return queueNoError ;
262
263}/* end InitQueue */
264
265/****************************************************************************************************/
266//
267//		Method:		CloseQueue
268//
269//		Inputs:		Queue - the queue to be closed
270//
271//		Outputs:	QueueStatus - queueNoError.
272//
273//		Desc:		Clear out all of the data structures.
274//
275/****************************************************************************************************/
276
277QueueStatus AppleUSBCDCDMM::CloseQueue(CirQueue *Queue)
278{
279
280    Queue->Start	= 0;
281    Queue->End		= 0;
282    Queue->NextChar	= 0;
283    Queue->LastChar	= 0;
284    Queue->Size		= 0;
285
286    return queueNoError;
287
288}/* end CloseQueue */
289
290/****************************************************************************************************/
291//
292//		Method:		AddtoQueue
293//
294//		Inputs:		Queue - the queue to be added to
295//				Buffer - data to add
296//				Size - length of data
297//
298//		Outputs:	BytesWritten - Number of bytes actually put in the queue.
299//
300//		Desc:		Add an entire buffer to the queue.
301//
302/****************************************************************************************************/
303
304size_t AppleUSBCDCDMM::AddtoQueue(CirQueue *Queue, UInt8 *Buffer, size_t Size)
305{
306    size_t	BytesWritten = 0;
307
308    while (FreeSpaceinQueue(Queue) && (Size > BytesWritten))
309    {
310        AddBytetoQueue(Queue, *Buffer++);
311        BytesWritten++;
312    }
313
314    return BytesWritten;
315
316}/* end AddtoQueue */
317
318/****************************************************************************************************/
319//
320//		Method:		RemovefromQueue
321//
322//		Inputs:		Queue - the queue to be removed from
323//				Size - size of buffer
324//
325//		Outputs:	Buffer - Where to put the data
326//				BytesReceived - Number of bytes actually put in Buffer.
327//
328//		Desc:		Get a buffers worth of data from the queue.
329//
330/****************************************************************************************************/
331
332size_t AppleUSBCDCDMM::RemovefromQueue(CirQueue *Queue, UInt8 *Buffer, size_t MaxSize)
333{
334    size_t	BytesReceived = 0;
335    UInt8	Value;
336
337    //  while((GetBytetoQueue(Queue, &Value) == queueNoError) && (MaxSize >= BytesReceived))
338    while((MaxSize > BytesReceived) && (GetBytetoQueue(Queue, &Value) == queueNoError))
339    {
340        *Buffer++ = Value;
341        BytesReceived++;
342    }/* end while */
343
344    return BytesReceived;
345
346}/* end RemovefromQueue */
347
348/****************************************************************************************************/
349//
350//		Method:		FreeSpaceinQueue
351//
352//		Inputs:		Queue - the queue to be queried
353//
354//		Outputs:	Return Value - Free space left
355//
356//		Desc:		Return the amount of free space left in this buffer.
357//
358/****************************************************************************************************/
359
360size_t AppleUSBCDCDMM::FreeSpaceinQueue(CirQueue *Queue)
361{
362    size_t	retVal = 0;
363
364    retVal = Queue->Size - Queue->InQueue;
365
366    return retVal;
367
368}/* end FreeSpaceinQueue */
369
370/****************************************************************************************************/
371//
372//		Method:		UsedSpaceinQueue
373//
374//		Inputs:		Queue - the queue to be queried
375//
376//		Outputs:	UsedSpace - Amount of data in buffer
377//
378//		Desc:		Return the amount of data in this buffer.
379//
380/****************************************************************************************************/
381
382size_t AppleUSBCDCDMM::UsedSpaceinQueue(CirQueue *Queue)
383{
384    return Queue->InQueue;
385
386}/* end UsedSpaceinQueue */
387
388/****************************************************************************************************/
389//
390//		Method:		GetQueueSize
391//
392//		Inputs:		Queue - the queue to be queried
393//
394//		Outputs:	QueueSize - The size of the queue.
395//
396//		Desc:		Return the total size of the queue.
397//
398/****************************************************************************************************/
399
400size_t AppleUSBCDCDMM::GetQueueSize(CirQueue *Queue)
401{
402    return Queue->Size;
403
404}/* end GetQueueSize */
405
406/****************************************************************************************************/
407//
408//		Method:		GetQueueStatus
409//
410//		Inputs:		Queue - the queue to be queried
411//
412//		Outputs:	Queue status - full, empty or no error
413//
414//		Desc:		Returns the status of the circular queue.
415//
416/****************************************************************************************************/
417
418QueueStatus AppleUSBCDCDMM::GetQueueStatus(CirQueue *Queue)
419{
420    if ((Queue->NextChar == Queue->LastChar) && Queue->InQueue)
421        return queueFull;
422    else if ((Queue->NextChar == Queue->LastChar) && !Queue->InQueue)
423        return queueEmpty;
424
425    return queueNoError ;
426
427}/* end GetQueueStatus */
428
429/****************************************************************************************************/
430//
431//		Method:		isCRinQueue
432//
433//		Inputs:		Queue - the queue to be looked at
434//
435//		Outputs:	return code - number of bytes
436//
437//		Desc:		Is there a cr in the queue.
438//
439/****************************************************************************************************/
440
441UInt16 AppleUSBCDCDMM::isCRinQueue(CirQueue *Queue)
442{
443    UInt8	*last;
444	bool	done = false;
445	UInt16  i = 1;
446
447	if ((Queue->NextChar == Queue->LastChar) && !Queue->InQueue)
448    {
449        return 0;
450    }
451
452	last = Queue->LastChar;
453
454	while (!done)
455	{
456		if (*last == 0x0D)
457		{
458			done = true;
459		} else {
460			last++;
461			i++;
462			if (last >= Queue->End)
463			{
464				last = Queue->Start;
465			}
466			if (last == Queue->NextChar)
467			{
468				i = 0;
469				done = true;
470			}
471		}
472	}
473
474    return i;
475
476}/* end isCRinQueue */
477
478/****************************************************************************************************/
479//
480//		Method:		CheckQueues
481//
482//		Inputs:
483//
484//		Outputs:
485//
486//		Desc:		Checks the various queue's etc and manipulates the state(s) accordingly
487//				Must be called from a gated method or completion routine.
488//
489/****************************************************************************************************/
490
491void AppleUSBCDCDMM::CheckQueues()
492{
493    UInt32	Used;
494    UInt32	Free;
495    UInt32	QueuingState;
496    UInt32	DeltaState;
497
498	// Initialise the QueueState with the current state.
499
500    QueuingState = fPort.State;
501
502        // Check to see if there is anything in the Transmit buffer.
503
504    Used = UsedSpaceinQueue(&fPort.TX);
505    Free = FreeSpaceinQueue(&fPort.TX);
506
507    XTRACE(this, Free, Used, "CheckQueues");
508
509    if (Free == 0)
510    {
511        QueuingState |=  PD_S_TXQ_FULL;
512        QueuingState &= ~PD_S_TXQ_EMPTY;
513    } else {
514        if (Used == 0)
515	{
516            QueuingState &= ~PD_S_TXQ_FULL;
517            QueuingState |=  PD_S_TXQ_EMPTY;
518        } else {
519            QueuingState &= ~PD_S_TXQ_FULL;
520            QueuingState &= ~PD_S_TXQ_EMPTY;
521        }
522    }
523
524    	// Check to see if we are below the low water mark.
525
526    if (Used < fPort.TXStats.LowWater)
527         QueuingState |=  PD_S_TXQ_LOW_WATER;
528    else QueuingState &= ~PD_S_TXQ_LOW_WATER;
529
530    if (Used > fPort.TXStats.HighWater)
531         QueuingState |= PD_S_TXQ_HIGH_WATER;
532    else QueuingState &= ~PD_S_TXQ_HIGH_WATER;
533
534
535        // Check to see if there is anything in the Receive buffer.
536
537    Used = UsedSpaceinQueue(&fPort.RX);
538    Free = FreeSpaceinQueue(&fPort.RX);
539
540    if (Free == 0)
541    {
542        QueuingState |= PD_S_RXQ_FULL;
543        QueuingState &= ~PD_S_RXQ_EMPTY;
544    } else {
545        if (Used == 0)
546	{
547            QueuingState &= ~PD_S_RXQ_FULL;
548            QueuingState |= PD_S_RXQ_EMPTY;
549        } else {
550            QueuingState &= ~PD_S_RXQ_FULL;
551            QueuingState &= ~PD_S_RXQ_EMPTY;
552        }
553    }
554
555        // Check to see if we are below the low water mark.
556
557    if (Used < fPort.RXStats.LowWater)
558         QueuingState |= PD_S_RXQ_LOW_WATER;
559    else QueuingState &= ~PD_S_RXQ_LOW_WATER;
560
561    if (Used > fPort.RXStats.HighWater)
562         QueuingState |= PD_S_RXQ_HIGH_WATER;
563    else QueuingState &= ~PD_S_RXQ_HIGH_WATER;
564
565        // Figure out what has changed to get mask.
566
567    DeltaState = QueuingState ^ fPort.State;
568    setStateGated(&QueuingState, &DeltaState);
569
570}/* end CheckQueues */
571
572/****************************************************************************************************/
573//
574//		Method:		AppleUSBCDCDMM::intReadComplete
575//
576//		Inputs:		obj - me
577//				rc - return code
578//				remaining - what's left
579//
580//		Outputs:	None
581//
582//		Desc:		Interrupt pipe (DMM interface) read completion routine
583//
584/****************************************************************************************************/
585
586void AppleUSBCDCDMM::intReadComplete(void *obj, void *param, IOReturn rc, UInt32 remaining)
587{
588    AppleUSBCDCDMM	*me = (AppleUSBCDCDMM*)obj;
589    IOReturn			ior;
590    UInt32			dLen;
591
592    XTRACE(me, rc, 0, "intReadComplete");
593
594    if (me->fStopping)
595        return;
596
597    if (rc == kIOReturnSuccess)					// If operation returned ok
598    {
599        dLen = me->fIntBufferSize - remaining;
600        XTRACE(me, me->fIntPipeBuffer[1], dLen, "intReadComplete - Notification and length");
601
602            // Now look at the notification
603
604        if (me->fIntPipeBuffer[1] == kUSBRESPONSE_AVAILABLE)
605        {
606			rc = me->sendMERRequest(kUSBGET_ENCAPSULATED_RESPONSE, 0, me->fMax_Command, me->fInBuffer, &me->fRspCompletionInfo);
607			if (rc != kIOReturnSuccess)
608			{
609				XTRACE(me, 0, rc, "intReadComplete - sendMERRequest failed");
610			}
611		}
612    } else {
613        XTRACE(me, 0, rc, "intReadComplete - error");
614	}
615
616        // Queue the next read only if not aborted
617
618    if (rc != kIOReturnAborted)
619    {
620        ior = me->fIntPipe->Read(me->fIntPipeMDP, &me->fIntCompletionInfo, NULL);
621        if (ior != kIOReturnSuccess)
622        {
623            XTRACE(me, 0, rc, "intReadComplete - Read io error");
624			me->fReadDead = true;
625        }
626    } else {
627		me->fReadDead = true;
628	}
629
630}/* end intReadComplete */
631
632/****************************************************************************************************/
633//
634//		Method:		AppleUSBCDCDMM::merWriteComplete
635//
636//		Inputs:		obj - me
637//				param - MER
638//				rc - return code
639//				remaining - what's left
640//
641//		Outputs:	None
642//
643//		Desc:		Management Element Request write completion routine
644//
645/****************************************************************************************************/
646
647void AppleUSBCDCDMM::merWriteComplete(void *obj, void *param, IOReturn rc, UInt32 remaining)
648{
649#if LDEBUG
650	AppleUSBCDCDMM	*me = (AppleUSBCDCDMM*)obj;
651#endif
652    IOUSBDevRequest		*MER = (IOUSBDevRequest *)param;
653    UInt16			dataLen;
654
655    XTRACE(0, 0, remaining, "merWriteComplete");
656
657    if (MER)
658    {
659        if (rc == kIOReturnSuccess)
660        {
661            XTRACE(me, MER->bRequest, remaining, "merWriteComplete - request");
662        } else {
663            XTRACE(me, MER->bRequest, rc, "merWriteComplete - io err");
664        }
665
666        dataLen = MER->wLength;
667        XTRACE(me, 0, dataLen, "merWriteComplete - data length");
668        if ((dataLen != 0) && (MER->pData))
669        {
670            IOFree(MER->pData, dataLen);
671        }
672        IOFree(MER, sizeof(IOUSBDevRequest));
673
674    } else {
675        if (rc == kIOReturnSuccess)
676        {
677            XTRACE(me, 0, remaining, "merWriteComplete (request unknown)");
678        } else {
679            XTRACE(me, 0, rc, "merWriteComplete (request unknown) - io err");
680        }
681    }
682
683}/* end merWriteComplete */
684
685/****************************************************************************************************/
686//
687//		Method:		AppleUSBCDCDMM::rspComplete
688//
689//		Inputs:		obj - me
690//				param - MER
691//				rc - return code
692//				remaining - what's left
693//
694//		Outputs:	None
695//
696//		Desc:		Encapsulated response (MER) completion routine
697//
698/****************************************************************************************************/
699
700void AppleUSBCDCDMM::rspComplete(void *obj, void *param, IOReturn rc, UInt32 remaining)
701{
702	AppleUSBCDCDMM  *me = (AppleUSBCDCDMM*)obj;
703    IOUSBDevRequest *MER = (IOUSBDevRequest *)param;
704    UInt16			dataLen;
705
706    XTRACE(me, 0, remaining, "rspComplete");
707
708    if (MER)
709    {
710		dataLen = MER->wLength;
711        if (rc == kIOReturnSuccess)
712        {
713			XTRACE(me, MER->bRequest, dataLen, "rspComplete - request and data length");
714			if ((MER->bRequest == kUSBGET_ENCAPSULATED_RESPONSE) && (dataLen > 0))
715			{
716				meLogData(kDataIn, dataLen, MER->pData);
717
718					// Move the incoming bytes to the ring buffer
719
720				me->AddtoQueue(&me->fPort.RX, (UInt8 *)MER->pData, dataLen);
721
722				me->CheckQueues();
723			}
724        } else {
725            XTRACE(me, MER->bRequest, rc, "rspComplete - io err");
726        }
727
728        if ((dataLen != 0) && (MER->pData))
729        {
730            IOFree(MER->pData, dataLen);
731        }
732        IOFree(MER, sizeof(IOUSBDevRequest));
733
734    } else {
735        if (rc == kIOReturnSuccess)
736        {
737            XTRACE(me, 0, remaining, "rspComplete (request unknown)");
738        } else {
739            XTRACE(me, 0, rc, "rspComplete (request unknown) - io err");
740        }
741    }
742
743}/* end rspComplete */
744
745/****************************************************************************************************/
746//
747//		Method:		AppleUSBCDCDMM::probe
748//
749//		Inputs:		provider - my provider
750//
751//		Outputs:	IOService - from super::probe, score - probe score
752//
753//		Desc:		Modify the probe score if necessary (we don't  at the moment)
754//
755/****************************************************************************************************/
756
757IOService* AppleUSBCDCDMM::probe( IOService *provider, SInt32 *score )
758{
759    IOService   *res;
760
761		// If our IOUSBInterface has a "do not match" property, it means that we should not match and need
762		// to bail.  See rdar://3716623
763
764    OSBoolean *boolObj = OSDynamicCast(OSBoolean, provider->getProperty("kDoNotClassMatchThisInterface"));
765    if (boolObj && boolObj->isTrue())
766    {
767        XTRACE(this, 0, 0, "probe - provider doesn't want us to match");
768        return NULL;
769    }
770
771    res = super::probe(provider, score);
772
773    return res;
774
775}/* end probe */
776
777/****************************************************************************************************/
778//
779//		Method:		AppleUSBCDCDMM::start
780//
781//		Inputs:		provider - my provider
782//
783//		Outputs:	Return code - true (it's me), false (sorry it probably was me, but I can't configure it)
784//
785//		Desc:		This is called once it has been determined I'm probably the best
786//				driver for this device.
787//
788/****************************************************************************************************/
789
790bool AppleUSBCDCDMM::start(IOService *provider)
791{
792
793    fSessions = 0;
794    fTerminate = false;
795    fStopping = false;
796    fWorkLoop = NULL;
797	fMax_Command = 256;
798	fIntBufferSize = INT_BUFF_SIZE;
799
800    initStructure();
801
802    XTRACE(this, 0, 0, "start");
803
804    if(!super::start(provider))
805    {
806        ALERT(0, 0, "start - super failed");
807        return false;
808    }
809
810	// Get my USB provider - the interface
811
812    fInterface = OSDynamicCast(IOUSBInterface, provider);
813    if(!fInterface)
814    {
815        ALERT(0, 0, "start - provider invalid");
816        return false;
817    }
818
819        // get workloop
820
821    fWorkLoop = getWorkLoop();
822    if (!fWorkLoop)
823    {
824        ALERT(0, 0, "start - getWorkLoop failed");
825        return false;
826    }
827
828    fCommandGate = IOCommandGate::commandGate(this);
829    if (!fCommandGate)
830    {
831        ALERT(0, 0, "start - commandGate failed");
832        return false;
833    }
834
835    if (fWorkLoop->addEventSource(fCommandGate) != kIOReturnSuccess)
836    {
837        ALERT(0, 0, "start - addEventSource(commandGate) failed");
838        return false;
839    }
840
841	if (!configureDMM())
842    {
843        ALERT(0, 0, "start - configureDMM failed");
844        return false;
845    }
846
847    if (!allocateResources())
848    {
849        ALERT(0, 0, "start - allocateResources failed");
850        return false;
851    }
852
853	if (!createSerialStream())					// Publish SerialStream services
854    {
855        ALERT(0, 0, "start - createSerialStream failed");
856        return false;
857    }
858
859        // Looks like we're ok
860
861    fInterface->retain();
862    fWorkLoop->retain();
863    fCommandGate->enable();
864
865    XTRACE(this, 0, 0, "start - successful and IOModemSerialStreamSync created");
866	Log(DEBUG_NAME ": Version number - %s\n", VersionNumber);
867
868    return true;
869
870}/* end start */
871
872/****************************************************************************************************/
873//
874//		Method:		AppleUSBCDCDMM::stop
875//
876//		Inputs:		provider - my provider
877//
878//		Outputs:	None
879//
880//		Desc:		Stops the driver
881//
882/****************************************************************************************************/
883
884void AppleUSBCDCDMM::stop(IOService *provider)
885{
886    IOReturn	ret;
887
888    XTRACE(this, 0, 0, "stop");
889
890    fStopping = true;
891
892    retain();
893    ret = fCommandGate->runAction(stopAction);
894    release();
895
896    removeProperty((const char *)propertyTag);
897
898    super::stop(provider);
899
900}/* end stop */
901
902/****************************************************************************************************/
903//
904//		Method:		AppleUSBCDCDMM::stopAction
905//
906//		Desc:		Dummy pass through for stopGated.
907//
908/****************************************************************************************************/
909
910IOReturn AppleUSBCDCDMM::stopAction(OSObject *owner, void *, void *, void *, void *)
911{
912
913    ((AppleUSBCDCDMM *)owner)->stopGated();
914
915    return kIOReturnSuccess;
916
917}/* end stopAction */
918
919/****************************************************************************************************/
920//
921//		Method:		AppleUSBCDCDMM::stopGated
922//
923//		Inputs:
924//
925//		Outputs:
926//
927//		Desc:		Releases the resources
928//
929/****************************************************************************************************/
930
931void AppleUSBCDCDMM::stopGated()
932{
933
934    XTRACE(this, 0, 0, "stopGated");
935
936    releaseResources();
937
938}/* end stopGated */
939
940/****************************************************************************************************/
941//
942//		Method:		AppleUSBCDCDMM::configureDMM
943//
944//		Inputs:
945//
946//		Outputs:	return Code - true (configured), false (not configured)
947//
948//		Desc:		Configures the Device Management Model interface etc.
949//
950/****************************************************************************************************/
951
952bool AppleUSBCDCDMM::configureDMM()
953{
954
955    XTRACE(this, 0, 0, "configureDMM");
956
957    fInterfaceNumber = fInterface->GetInterfaceNumber();
958    XTRACE(this, 0, fInterfaceNumber, "configureDMM - Interface number.");
959
960    if (!getFunctionalDescriptors())
961    {
962        XTRACE(this, 0, 0, "configureDMM - getFunctionalDescriptors failed");
963        return false;
964    }
965
966    return true;
967
968}/* end configureDMM */
969
970/****************************************************************************************************/
971//
972//		Method:		AppleUSBCDCDMM::getFunctionalDescriptors
973//
974//		Inputs:
975//
976//		Outputs:	return - true (descriptors ok), false (somethings not right or not supported)
977//
978//		Desc:		Finds all the functional descriptors for the specific interface
979//
980/****************************************************************************************************/
981
982bool AppleUSBCDCDMM::getFunctionalDescriptors()
983{
984    bool				gotDescriptors = false;
985    UInt16				vers;
986    UInt16				*hdrVers;
987    const FunctionalDescriptorHeader 	*funcDesc = NULL;
988    HDRFunctionalDescriptor		*HDRFDesc;		// hearder functional descriptor
989    DMMFunctionalDescriptor		*DMMFDesc;		// device management functional descriptor
990
991    XTRACE(this, 0, 0, "getFunctionalDescriptors");
992
993        // Get the associated functional descriptors
994
995    do
996    {
997        funcDesc = (const FunctionalDescriptorHeader *)fInterface->FindNextAssociatedDescriptor((void*)funcDesc, CS_INTERFACE);
998        if (!funcDesc)
999        {
1000            gotDescriptors = true;				// We're done
1001        } else {
1002            switch (funcDesc->bDescriptorSubtype)
1003            {
1004                case Header_FunctionalDescriptor:
1005                    HDRFDesc = (HDRFunctionalDescriptor *)funcDesc;
1006                    XTRACE(this, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - Header Functional Descriptor");
1007                    hdrVers = (UInt16 *)&HDRFDesc->bcdCDC1;
1008                    vers = USBToHostWord(*hdrVers);
1009                    if (vers > kUSBRel11)
1010                    {
1011                        XTRACE(this, vers, kUSBRel11, "getFunctionalDescriptors - Header descriptor version number is incorrect");
1012                    }
1013                    break;
1014				case DMM_FunctionalDescriptor:
1015                    DMMFDesc = (DMMFunctionalDescriptor *)funcDesc;
1016                    XTRACE(this, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - ACM Functional Descriptor");
1017                    fMax_Command = USBToHostWord(DMMFDesc->wMaxCommand);
1018                    break;
1019                case Union_FunctionalDescriptor:
1020                    XTRACE(this, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - Union Functional Descriptor");
1021					break;
1022                case CS_FunctionalDescriptor:
1023                    XTRACE(this, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - CS Functional Descriptor");
1024                    break;
1025                default:
1026                    XTRACE(this, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - unknown Functional Descriptor");
1027                    break;
1028            }
1029        }
1030    } while (!gotDescriptors);
1031
1032    return true;
1033
1034}/* end getFunctionalDescriptors */
1035
1036/****************************************************************************************************/
1037//
1038//		Method:		AppleUSBCDCDMM::createSuffix
1039//
1040//		Inputs:
1041//
1042//		Outputs:	return Code - true (suffix created), false (suffix not create)
1043//				sufKey - the key
1044//
1045//		Desc:		Creates the suffix key. It attempts to use the serial number string from the device
1046//				if it's reasonable i.e. less than 8 bytes ascii. Remember it's stored in unicode
1047//				format. If it's not present or not reasonable it will generate the suffix based
1048//				on the location property tag. At least this remains the same across boots if the
1049//				device is plugged into the same physical location. In the latter case trailing
1050//				zeros are removed.
1051//				The interface number is also added to make it unique for
1052//				multiple CDC configuration devices.
1053//
1054/****************************************************************************************************/
1055
1056bool AppleUSBCDCDMM::createSuffix(unsigned char *sufKey)
1057{
1058
1059    IOReturn	rc;
1060    UInt8	serBuf[12];		// arbitrary size > 8
1061    OSNumber	*location;
1062    UInt32	locVal;
1063    SInt16	i, sig = 0;
1064    UInt8	indx;
1065    bool	keyOK = false;
1066
1067    XTRACE(this, 0, 0, "createSuffix");
1068
1069    indx = fInterface->GetDevice()->GetSerialNumberStringIndex();
1070    if (indx != 0)
1071    {
1072            // Generate suffix key based on the serial number string (if reasonable <= 8 and > 0)
1073
1074        rc = fInterface->GetDevice()->GetStringDescriptor(indx, (char *)&serBuf, sizeof(serBuf));
1075        if (!rc)
1076        {
1077            if ((strlen((char *)&serBuf) < 9) && (strlen((char *)&serBuf) > 0))
1078            {
1079				strlcpy((char *)sufKey, (const char *)&serBuf, strlen((char *)&serBuf));
1080//                strcpy((char *)sufKey, (const char *)&serBuf);
1081                sig = strlen((char *)sufKey);
1082                keyOK = true;
1083            }
1084        } else {
1085            XTRACE(this, 0, rc, "createSuffix error reading serial number string");
1086        }
1087    }
1088
1089    if (!keyOK)
1090    {
1091            // Generate suffix key based on the location property tag
1092
1093        location = (OSNumber *)fInterface->GetDevice()->getProperty(kUSBDevicePropertyLocationID);
1094        if (location)
1095        {
1096            locVal = location->unsigned32BitValue();
1097            snprintf((char *)sufKey, (sizeof(locVal)*2)+1, "%x", (unsigned int)locVal);
1098			sig = strlen((const char *)sufKey)-1;
1099			for (i=sig; i>=0; i--)
1100			{
1101				if (sufKey[i] != '0')
1102				{
1103					break;
1104				}
1105			}
1106			sig = i + 1;
1107            keyOK = true;
1108        }
1109    }
1110
1111        // Make it unique just in case there's more than one configuration on this device
1112
1113    if (keyOK)
1114    {
1115        sufKey[sig] = Asciify((UInt8)fInterfaceNumber >> 4);
1116        if (sufKey[sig] != '0')
1117            sig++;
1118        sufKey[sig++] = Asciify((UInt8)fInterfaceNumber);
1119        sufKey[sig] = 0x00;
1120    }
1121
1122    return keyOK;
1123
1124}/* end createSuffix */
1125
1126/****************************************************************************************************/
1127//
1128//		Method:		AppleUSBCDCDMM::createSerialStream
1129//
1130//		Inputs:
1131//
1132//		Outputs:	return Code - true (created and initialilzed ok), false (it failed)
1133//
1134//		Desc:		Creates and initializes the nub
1135//
1136/****************************************************************************************************/
1137
1138bool AppleUSBCDCDMM::createSerialStream()
1139{
1140    IOModemSerialStreamSync	*pNub = new IOModemSerialStreamSync;
1141    bool			ret;
1142    unsigned char		rname[20];
1143    const char			*suffix = (const char *)&rname;
1144
1145    XTRACEP(this, 0, pNub, "createSerialStream");
1146    if (!pNub)
1147    {
1148        return false;
1149    }
1150
1151    	// Either we attached and should get rid of our reference
1152    	// or we failed in which case we should get rid our reference as well.
1153        // This just makes sure the reference count is correct.
1154
1155    ret = (pNub->init(0, 0) && pNub->attach(this));
1156
1157    pNub->release();
1158    if (!ret)
1159    {
1160        XTRACE(this, ret, 0, "createSerialStream - Failed to attach to the nub");
1161        return false;
1162    }
1163
1164        // Report the base name to be used for generating device nodes
1165
1166    pNub->setProperty(kIOTTYBaseNameKey, baseName);
1167
1168        // Create suffix key and set it
1169
1170    if (createSuffix((unsigned char *)suffix))
1171    {
1172        pNub->setProperty(kIOTTYSuffixKey, suffix);
1173    }
1174
1175	pNub->setProperty((const char *)hiddenTag, true);
1176
1177    pNub->registerService();
1178
1179    return true;
1180
1181}/* end createSerialStream */
1182
1183/****************************************************************************************************/
1184//
1185//		Method:		AppleUSBCDCDMM::acquirePort
1186//
1187//		Inputs:		sleep - true (wait for it), false (don't)
1188//				refCon - unused
1189//
1190//		Outputs:	Return Code - kIOReturnSuccess, kIOReturnExclusiveAccess, kIOReturnIOError and various others
1191//
1192//		Desc:		Set up for gated acquirePort call.
1193//
1194/****************************************************************************************************/
1195
1196IOReturn AppleUSBCDCDMM::acquirePort(bool sleep, void *refCon)
1197{
1198    IOReturn                ret;
1199
1200    XTRACEP(this, refCon, 0, "acquirePort");
1201
1202		// Check for being acquired after stop has been issued and before start
1203
1204	if (fTerminate || fStopping)
1205	{
1206		XTRACE(this, 0, 0, "acquirePort - Offline");
1207		return kIOReturnOffline;
1208	}
1209
1210		// Make sure we have a valid workloop
1211
1212	if (!fWorkLoop)
1213    {
1214        XTRACE(this, 0, 0, "acquirePort - No workLoop");
1215        return kIOReturnOffline;
1216    }
1217
1218    retain();
1219    ret = fCommandGate->runAction(acquirePortAction, (void *)sleep);
1220    release();
1221
1222    return ret;
1223
1224}/* end acquirePort */
1225
1226/****************************************************************************************************/
1227//
1228//		Method:		AppleUSBCDCDMM::acquirePortAction
1229//
1230//		Desc:		Dummy pass through for acquirePortGated.
1231//
1232/****************************************************************************************************/
1233
1234IOReturn AppleUSBCDCDMM::acquirePortAction(OSObject *owner, void *arg0, void *, void *, void *)
1235{
1236
1237    return ((AppleUSBCDCDMM *)owner)->acquirePortGated((bool)arg0);
1238
1239}/* end acquirePortAction */
1240
1241/****************************************************************************************************/
1242//
1243//		Method:		AppleUSBCDCDMM::acquirePortGated
1244//
1245//		Inputs:		sleep - true (wait for it), false (don't)
1246//
1247//		Outputs:	Return Code - kIOReturnSuccess, kIOReturnExclusiveAccess, kIOReturnIOError and various others
1248//
1249//		Desc:		acquirePort tests and sets the state of the port object.  If the port was
1250// 				available, then the state is set to busy, and kIOReturnSuccess is returned.
1251// 				If the port was already busy and sleep is YES, then the thread will sleep
1252// 				until the port is freed, then re-attempts the acquire.  If the port was
1253// 				already busy and sleep is NO, then kIOReturnExclusiveAccess is returned.
1254//
1255/****************************************************************************************************/
1256
1257IOReturn AppleUSBCDCDMM::acquirePortGated(bool sleep)
1258{
1259    UInt32 	busyState = 0;
1260	UInt32	state;
1261	UInt32	mask;
1262    IOReturn 	rtn = kIOReturnSuccess;
1263
1264    XTRACE(this, 0, sleep, "acquirePortGated");
1265
1266    retain(); 							// Hold reference till releasePortGated, unless we fail to acquire
1267    while (true)
1268    {
1269        busyState = fPort.State & PD_S_ACQUIRED;
1270        if (!busyState)
1271        {
1272                // Set busy bit (acquired), and clear everything else
1273
1274			state = PD_S_ACQUIRED | DEFAULT_STATE;
1275			mask = STATE_ALL;
1276            setStateGated(&state, &mask);
1277            break;
1278        } else {
1279            if (!sleep)
1280            {
1281                XTRACE(this, 0, 0, "acquirePortGated - Busy exclusive access");
1282                release();
1283            	return kIOReturnExclusiveAccess;
1284            } else {
1285            	busyState = 0;
1286				mask = PD_S_ACQUIRED;
1287            	rtn = watchStateGated(&busyState, &mask);
1288            	if ((rtn == kIOReturnIOError) || (rtn == kIOReturnSuccess))
1289                {
1290                    continue;
1291            	} else {
1292                    XTRACE(this, 0, 0, "acquirePortGated - Interrupted!");
1293                    release();
1294                    return rtn;
1295                }
1296            }
1297        }
1298    }
1299
1300    setStructureDefaults();				// Set the default values
1301
1302    fSessions++;					// Bump number of active sessions and turn on clear to send
1303	state = PD_RS232_S_CTS;
1304	mask = PD_RS232_S_CTS;
1305    setStateGated(&state, &mask);
1306
1307    return kIOReturnSuccess;
1308
1309}/* end acquirePortGated */
1310
1311/****************************************************************************************************/
1312//
1313//		Method:		AppleUSBCDCDMM::releasePort
1314//
1315//		Inputs:		refCon - unused
1316//
1317//		Outputs:	Return Code - kIOReturnSuccess or kIOReturnNotOpen
1318//
1319//		Desc:		Set up for gated releasePort call.
1320//
1321/****************************************************************************************************/
1322
1323IOReturn AppleUSBCDCDMM::releasePort(void *refCon)
1324{
1325    IOReturn	ret = kIOReturnSuccess;
1326
1327    XTRACE(this, 0, 0, "releasePort");
1328
1329    retain();
1330    ret = fCommandGate->runAction(releasePortAction);
1331    release();
1332
1333        // Clear any sleeping threads
1334
1335    fPort.WatchStateMask = 0;
1336    fCommandGate->commandWakeup((void *)&fPort.State);
1337
1338    return ret;
1339
1340}/* end releasePort */
1341
1342/****************************************************************************************************/
1343//
1344//		Method:		AppleUSBCDCDMM::releasePortAction
1345//
1346//		Desc:		Dummy pass through for releasePortGated.
1347//
1348/****************************************************************************************************/
1349
1350IOReturn AppleUSBCDCDMM::releasePortAction(OSObject *owner, void *, void *, void *, void *)
1351{
1352
1353    return ((AppleUSBCDCDMM *)owner)->releasePortGated();
1354
1355}/* end releasePortAction */
1356
1357/****************************************************************************************************/
1358//
1359//		Method:		AppleUSBCDCDMM::releasePortGated
1360//
1361//		Inputs:
1362//
1363//		Outputs:	Return Code - kIOReturnSuccess or kIOReturnNotOpen
1364//
1365//		Desc:		releasePort returns all the resources and does clean up.
1366//
1367/****************************************************************************************************/
1368
1369IOReturn AppleUSBCDCDMM::releasePortGated()
1370{
1371    UInt32 	busyState;
1372	UInt32	state;
1373	UInt32	mask;
1374
1375    XTRACE(this, 0, 0, "releasePortGated");
1376
1377    busyState = (fPort.State & PD_S_ACQUIRED);
1378    if (!busyState)
1379    {
1380        if (fTerminate || fStopping)
1381        {
1382            XTRACE(this, 0, 0, "releasePortGated - Offline");
1383            return kIOReturnOffline;
1384        }
1385
1386        XTRACE(this, 0, 0, "releasePortGated - Not open");
1387        return kIOReturnNotOpen;
1388    }
1389
1390    if (!fTerminate)
1391        setControlLineState(false, false);		// clear RTS and clear DTR only if not terminated
1392
1393	state = 0;
1394	mask = STATE_ALL;
1395    setStateGated(&state, &mask);			// Clear the entire state word - which also deactivates the port
1396
1397    fSessions--;					// reduce number of active sessions
1398
1399    release(); 						// Dispose of the self-reference we took in acquirePortGated()
1400
1401    XTRACE(this, 0, 0, "releasePort - Exit");
1402
1403    return kIOReturnSuccess;
1404
1405}/* end releasePortGated */
1406
1407/****************************************************************************************************/
1408//
1409//		Method:		AppleUSBCDCDMM::getState
1410//
1411//		Inputs:		refCon - unused
1412//
1413//		Outputs:	Return value - port state
1414//
1415//		Desc:		Set up for gated getState call.
1416//
1417/****************************************************************************************************/
1418
1419UInt32 AppleUSBCDCDMM::getState(void *refCon)
1420{
1421    UInt32	currState;
1422
1423    XTRACE(this, 0, 0, "getState");
1424
1425    if (fTerminate || fStopping)
1426    {
1427        XTRACE(this, 0, kIOReturnOffline, "getState - Offline");
1428        return 0;
1429    }
1430
1431    retain();
1432    currState = fCommandGate->runAction(getStateAction);
1433    release();
1434
1435    return currState;
1436
1437}/* end getState */
1438
1439/****************************************************************************************************/
1440//
1441//		Method:		AppleUSBCDCDMM::getStateAction
1442//
1443//		Desc:		Dummy pass through for getStateGated.
1444//
1445/****************************************************************************************************/
1446
1447IOReturn AppleUSBCDCDMM::getStateAction(OSObject *owner, void *, void *, void *, void *)
1448{
1449    UInt32	newState;
1450
1451    newState = ((AppleUSBCDCDMM *)owner)->getStateGated();
1452
1453    return newState;
1454
1455}/* end getStateAction */
1456
1457/****************************************************************************************************/
1458//
1459//		Method:		AppleUSBCDCDMM::getStateGated
1460//
1461//		Inputs:		port - unused
1462//
1463//		Outputs:	return value - port state
1464//
1465//		Desc:		Get the state for the port.
1466//
1467/****************************************************************************************************/
1468
1469UInt32 AppleUSBCDCDMM::getStateGated()
1470{
1471    UInt32 	state;
1472
1473    XTRACE(this, 0, 0, "getStateGated");
1474
1475    if (fTerminate || fStopping)
1476        return 0;
1477
1478    CheckQueues();
1479
1480    state = fPort.State & EXTERNAL_MASK;
1481
1482    XTRACE(this, state, EXTERNAL_MASK, "getStateGated - Exit");
1483
1484    return state;
1485
1486}/* end getStateGated */
1487
1488/****************************************************************************************************/
1489//
1490//		Method:		AppleUSBCDCDMM::setState
1491//
1492//		Inputs:		state - the state
1493//				mask - the mask
1494//				refCon - unused
1495//
1496//		Outputs:	Return code - kIOReturnSuccess or kIOReturnBadArgument
1497//
1498//		Desc:		Set up for gated setState call.
1499//
1500/****************************************************************************************************/
1501
1502IOReturn AppleUSBCDCDMM::setState(UInt32 state, UInt32 mask, void *refCon)
1503{
1504    IOReturn	ret = kIOReturnSuccess;
1505
1506    XTRACE(this, 0, 0, "setState");
1507
1508    if (fTerminate || fStopping)
1509    {
1510        XTRACE(this, 0, kIOReturnOffline, "setState - Offline");
1511        return 0;
1512    }
1513
1514        // Cannot acquire or activate via setState
1515
1516    if (mask & (PD_S_ACQUIRED | PD_S_ACTIVE | (~EXTERNAL_MASK)))
1517    {
1518        ret = kIOReturnBadArgument;
1519    } else {
1520
1521            // ignore any bits that are read-only
1522
1523        mask &= (~fPort.FlowControl & PD_RS232_A_MASK) | PD_S_MASK;
1524        if (mask)
1525        {
1526            retain();
1527            ret = fCommandGate->runAction(setStateAction, (void *)&state, (void *)&mask);
1528            release();
1529        }
1530    }
1531
1532    return ret;
1533
1534}/* end setState */
1535
1536/****************************************************************************************************/
1537//
1538//		Method:		AppleUSBCDCDMM::setStateAction
1539//
1540//		Desc:		Dummy pass through for setStateGated.
1541//
1542/****************************************************************************************************/
1543
1544IOReturn AppleUSBCDCDMM::setStateAction(OSObject *owner, void *arg0, void *arg1, void *, void *)
1545{
1546
1547    return ((AppleUSBCDCDMM *)owner)->setStateGated((UInt32 *)arg0, (UInt32 *)arg1);
1548
1549}/* end setStateAction */
1550
1551/****************************************************************************************************/
1552//
1553//		Method:		AppleUSBCDCDMM::setStateGated
1554//
1555//		Inputs:		state - state to set
1556//				mask - state mask
1557//
1558//		Outputs:	Return Code - kIOReturnSuccess or kIOReturnBadArgument
1559//
1560//		Desc:		Set the state for the port device.  The lower 16 bits are used to set the
1561//				state of various flow control bits (this can also be done by enqueueing a
1562//				PD_E_FLOW_CONTROL event).  If any of the flow control bits have been set
1563//				for automatic control, then they can't be changed by setState.  For flow
1564//				control bits set to manual (that are implemented in hardware), the lines
1565//				will be changed before this method returns.  The one weird case is if RXO
1566//				is set for manual, then an XON or XOFF character may be placed at the end
1567//				of the TXQ and transmitted later.
1568//
1569/****************************************************************************************************/
1570
1571IOReturn AppleUSBCDCDMM::setStateGated(UInt32 *pState, UInt32 *pMask)
1572{
1573	UInt32	state = *pMask;
1574	UInt32	mask = *pMask;
1575    UInt32	delta;
1576
1577    XTRACE(this, state, mask, "setStateGated");
1578
1579    if (fStopping)
1580        return kIOReturnOffline;
1581
1582        // Check if it's being acquired or already acquired
1583
1584    if ((state & PD_S_ACQUIRED) || (fPort.State & PD_S_ACQUIRED))
1585    {
1586        if (mask & PD_RS232_S_DTR)
1587        {
1588            if ((state & PD_RS232_S_DTR) != (fPort.State & PD_RS232_S_DTR))
1589            {
1590                if (state & PD_RS232_S_DTR)
1591                {
1592                    XTRACE(this, 0, 0, "setState - DTR TRUE");
1593                    setControlLineState(false, true);
1594                } else {
1595                    if (!fTerminate)
1596                    {
1597                        XTRACE(this, 0, 0, "setState - DTR FALSE");
1598                        setControlLineState(false, false);
1599                    }
1600                }
1601            }
1602        }
1603
1604        state = (fPort.State & ~mask) | (state & mask); 		// compute the new state
1605        delta = state ^ fPort.State;		    			// keep a copy of the diffs
1606        fPort.State = state;
1607
1608	    // Wake up all threads asleep on WatchStateMask
1609
1610        if (delta & fPort.WatchStateMask)
1611        {
1612            fCommandGate->commandWakeup((void *)&fPort.State);
1613        }
1614
1615        return kIOReturnSuccess;
1616
1617    } else {
1618        XTRACE(this, fPort.State, 0, "setStateGated - Not Acquired");
1619    }
1620
1621    return kIOReturnNotOpen;
1622
1623}/* end setStateGated */
1624
1625/****************************************************************************************************/
1626//
1627//		Method:		AppleUSBCDCDMM::watchState
1628//
1629//		Inputs:		state - state to watch for
1630//				mask - state mask bits
1631//				refCon - unused
1632//
1633//		Outputs:	Return Code - kIOReturnSuccess or value returned from ::watchState
1634//
1635//		Desc:		Set up for gated watchState call.
1636//
1637/****************************************************************************************************/
1638
1639IOReturn AppleUSBCDCDMM::watchState(UInt32 *state, UInt32 mask, void *refCon)
1640{
1641    IOReturn 	ret;
1642
1643    XTRACE(this, *state, mask, "watchState");
1644
1645    if (fTerminate || fStopping)
1646    {
1647        XTRACE(this, 0, kIOReturnOffline, "watchState - Offline");
1648        return kIOReturnOffline;
1649    }
1650
1651    if (!state)
1652        return kIOReturnBadArgument;
1653
1654    if (!mask)
1655        return kIOReturnSuccess;
1656
1657    retain();
1658    ret = fCommandGate->runAction(watchStateAction, (void *)state, (void *)&mask);
1659    release();
1660
1661    return ret;
1662
1663}/* end watchState */
1664
1665/****************************************************************************************************/
1666//
1667//		Method:		AppleUSBCDCDMM::watchStateAction
1668//
1669//		Desc:		Dummy pass through for watchStateGated.
1670//
1671/****************************************************************************************************/
1672
1673IOReturn AppleUSBCDCDMM::watchStateAction(OSObject *owner, void *arg0, void *arg1, void *, void *)
1674{
1675
1676    return ((AppleUSBCDCDMM *)owner)->watchStateGated((UInt32 *)arg0, (UInt32 *)arg1);
1677
1678}/* end watchStateAction */
1679
1680/****************************************************************************************************/
1681//
1682//		Method:		AppleUSBCDCDMM::watchStateGated
1683//
1684//		Inputs:		state - state to watch for
1685//				mask - state mask bits
1686//
1687//		Outputs:	Return Code - kIOReturnSuccess or value returned from privateWatchState
1688//
1689//		Desc:		Wait for the at least one of the state bits defined in mask to be equal
1690//				to the value defined in state. Check on entry then sleep until necessary,
1691//				A return value of kIOReturnSuccess means that at least one of the port state
1692//				bits specified by mask is equal to the value passed in by state.  A return
1693//				value of kIOReturnIOError indicates that the port went inactive.  A return
1694//				value of kIOReturnIPCError indicates sleep was interrupted by a signal.
1695//
1696/****************************************************************************************************/
1697
1698IOReturn AppleUSBCDCDMM::watchStateGated(UInt32 *state, UInt32 *pMask)
1699{
1700	UInt32		mask = *pMask;
1701    unsigned 	watchState, foundStates;
1702    bool 	autoActiveBit = false;
1703    IOReturn 	ret = kIOReturnNotOpen;
1704
1705    XTRACE(this, *state, mask, "watchStateGated");
1706
1707    if (fTerminate || fStopping)
1708        return kIOReturnOffline;
1709
1710    if (fPort.State & PD_S_ACQUIRED)
1711    {
1712        ret = kIOReturnSuccess;
1713        mask &= EXTERNAL_MASK;
1714
1715        watchState = *state;
1716        if (!(mask & (PD_S_ACQUIRED | PD_S_ACTIVE)))
1717        {
1718            watchState &= ~PD_S_ACTIVE;				// Check for low PD_S_ACTIVE
1719            mask |=  PD_S_ACTIVE;				// Register interest in PD_S_ACTIVE bit
1720            autoActiveBit = true;
1721        }
1722
1723        while (true)
1724        {
1725                // Check port state for any interesting bits with watchState value
1726                // NB. the '^ ~' is a XNOR and tests for equality of bits.
1727
1728            foundStates = (watchState ^ ~fPort.State) & mask;
1729
1730            if (foundStates)
1731            {
1732                *state = fPort.State;
1733                if (autoActiveBit && (foundStates & PD_S_ACTIVE))
1734                {
1735                    ret = kIOReturnIOError;
1736                } else {
1737                    ret = kIOReturnSuccess;
1738                }
1739                break;
1740            }
1741
1742                // Everytime we go around the loop we have to reset the watch mask.
1743                // This means any event that could affect the WatchStateMask must
1744                // wakeup all watch state threads.  The two events are an interrupt
1745                // or one of the bits in the WatchStateMask changing.
1746
1747            fPort.WatchStateMask |= mask;
1748
1749            XTRACE(this, fPort.State, fPort.WatchStateMask, "watchStateGated - Thread sleeping");
1750
1751            retain();								// Just to make sure all threads are awake
1752            fCommandGate->retain();					// before we're released
1753
1754            ret = fCommandGate->commandSleep((void *)&fPort.State);
1755
1756            fCommandGate->release();
1757
1758            XTRACE(this, fPort.State, ret, "watchStateGated - Thread restart");
1759
1760            if (ret == THREAD_TIMED_OUT)
1761            {
1762                ret = kIOReturnTimeout;
1763                release();
1764                break;
1765            } else {
1766                if (ret == THREAD_INTERRUPTED)
1767                {
1768                    ret = kIOReturnAborted;
1769                    release();
1770                    break;
1771                } else {
1772                    if (fTerminate || fStopping)	// Make sure we not terminated or stopping
1773					{
1774						ret = kIOReturnOffline;
1775						release();
1776						break;
1777					}
1778                }
1779            }
1780            release();
1781        }
1782
1783            // As it is impossible to undo the masking used by this
1784            // thread, we clear down the watch state mask and wakeup
1785            // every sleeping thread to reinitialize the mask before exiting.
1786
1787        fPort.WatchStateMask = 0;
1788        XTRACE(this, *state, 0, "watchStateGated - Thread wakeing others");
1789        fCommandGate->commandWakeup((void *)&fPort.State);
1790
1791        *state &= EXTERNAL_MASK;
1792    }
1793
1794    XTRACE(this, ret, 0, "watchStateGated - Exit");
1795
1796    return ret;
1797
1798}/* end watchStateGated */
1799
1800/****************************************************************************************************/
1801//
1802//		Method:		AppleUSBCDCDMM::nextEvent
1803//
1804//		Inputs:		refCon - unused
1805//
1806//		Outputs:	Return Code - kIOReturnSuccess or kIOReturnOffline
1807//
1808//		Desc:		Not used by this driver.
1809//
1810/****************************************************************************************************/
1811
1812UInt32 AppleUSBCDCDMM::nextEvent(void *refCon)
1813{
1814
1815    XTRACE(this, 0, 0, "nextEvent");
1816
1817    if (fTerminate || fStopping)
1818        return kIOReturnOffline;
1819
1820    if (getState(&fPort) & PD_S_ACTIVE)
1821    {
1822        return kIOReturnSuccess;
1823    }
1824
1825    return kIOReturnNotOpen;
1826
1827}/* end nextEvent */
1828
1829/****************************************************************************************************/
1830//
1831//		Method:		AppleUSBCDCDMM::executeEvent
1832//
1833//		Inputs:		event - The event
1834//				data - any data associated with the event
1835//				refCon - unused
1836//
1837//		Outputs:	Return Code - kIOReturnSuccess, kIOReturnNotOpen or kIOReturnBadArgument
1838//
1839//		Desc:		Set up for gated executeEvent call.
1840//
1841/****************************************************************************************************/
1842
1843IOReturn AppleUSBCDCDMM::executeEvent(UInt32 event, UInt32 data, void *refCon)
1844{
1845    IOReturn 	ret;
1846
1847    XTRACE(this, data, event, "executeEvent");
1848
1849    if (fTerminate || fStopping)
1850    {
1851        XTRACE(this, 0, kIOReturnOffline, "executeEvent - Offline");
1852        return kIOReturnOffline;
1853    }
1854
1855    retain();
1856    ret = fCommandGate->runAction(executeEventAction, (void *)&event, (void *)&data);
1857    release();
1858
1859    return ret;
1860
1861}/* end executeEvent */
1862
1863/****************************************************************************************************/
1864//
1865//		Method:		AppleUSBCDCDMM::executeEventAction
1866//
1867//		Desc:		Dummy pass through for executeEventGated.
1868//
1869/****************************************************************************************************/
1870
1871IOReturn AppleUSBCDCDMM::executeEventAction(OSObject *owner, void *arg0, void *arg1, void *, void *)
1872{
1873
1874    return ((AppleUSBCDCDMM *)owner)->executeEventGated((UInt32 *)arg0, (UInt32 *)arg1);
1875
1876}/* end executeEventAction */
1877
1878/****************************************************************************************************/
1879//
1880//		Method:		AppleUSBCDCDMM::executeEventGated
1881//
1882//		Inputs:		event - The event
1883//				data - any data associated with the event
1884//
1885//		Outputs:	Return Code - kIOReturnSuccess, kIOReturnNotOpen or kIOReturnBadArgument
1886//
1887//		Desc:		executeEvent causes the specified event to be processed immediately.
1888//				This is primarily used for channel control commands like START & STOP
1889//
1890/****************************************************************************************************/
1891
1892IOReturn AppleUSBCDCDMM::executeEventGated(UInt32 *pEvent, UInt32 *pData)
1893{
1894	UInt32		event = *pEvent;
1895	UInt32		data = *pData;
1896    IOReturn	ret = kIOReturnSuccess;
1897    UInt32		state, delta;
1898	UInt32		mask;
1899
1900    if (fTerminate || fStopping)
1901        return kIOReturnOffline;
1902
1903    delta = 0;
1904    state = fPort.State;
1905    XTRACE(this, state, event, "executeEventGated");
1906
1907    if ((state & PD_S_ACQUIRED) == 0)
1908        return kIOReturnNotOpen;
1909
1910    switch (event)
1911    {
1912	case PD_RS232_E_XON_BYTE:
1913            XTRACE(this, data, event, "executeEventGated - PD_RS232_E_XON_BYTE");
1914            fPort.XONchar = data;
1915            break;
1916	case PD_RS232_E_XOFF_BYTE:
1917            XTRACE(this, data, event, "executeEventGated - PD_RS232_E_XOFF_BYTE");
1918            fPort.XOFFchar = data;
1919            break;
1920	case PD_E_SPECIAL_BYTE:
1921            XTRACE(this, data, event, "executeEventGated - PD_E_SPECIAL_BYTE");
1922            fPort.SWspecial[ data >> SPECIAL_SHIFT ] |= (1 << (data & SPECIAL_MASK));
1923            break;
1924	case PD_E_VALID_DATA_BYTE:
1925            XTRACE(this, data, event, "executeEventGated - PD_E_VALID_DATA_BYTE");
1926            fPort.SWspecial[ data >> SPECIAL_SHIFT ] &= ~(1 << (data & SPECIAL_MASK));
1927            break;
1928	case PD_E_FLOW_CONTROL:
1929            XTRACE(this, data, event, "executeEventGated - PD_E_FLOW_CONTROL");
1930            break;
1931	case PD_E_ACTIVE:
1932            XTRACE(this, data, event, "executeEventGated - PD_E_ACTIVE");
1933            if ((bool)data)
1934            {
1935                if (!(state & PD_S_ACTIVE))
1936                {
1937                    setStructureDefaults();
1938					state = PD_S_ACTIVE;
1939					mask = PD_S_ACTIVE;
1940                    setStateGated(&state, &mask); 			// activate port
1941
1942                    setControlLineState(true, true);						// set RTS and set DTR
1943                }
1944            } else {
1945                if ((state & PD_S_ACTIVE))
1946                {
1947					state = 0;
1948					mask = PD_S_ACTIVE;
1949                    setStateGated(&state, &mask);					// deactivate port
1950
1951                    setControlLineState(false, false);						// clear RTS and clear DTR
1952                }
1953            }
1954            break;
1955	case PD_E_DATA_LATENCY:
1956            XTRACE(this, data, event, "executeEventGated - PD_E_DATA_LATENCY");
1957            fPort.DataLatInterval = long2tval(data * 1000);
1958            break;
1959	case PD_RS232_E_MIN_LATENCY:
1960            XTRACE(this, data, event, "executeEventGated - PD_RS232_E_MIN_LATENCY");
1961            fPort.MinLatency = bool(data);
1962            break;
1963	case PD_E_DATA_INTEGRITY:
1964            XTRACE(this, data, event, "executeEventGated - PD_E_DATA_INTEGRITY");
1965            if ((data < PD_RS232_PARITY_NONE) || (data > PD_RS232_PARITY_SPACE))
1966            {
1967                ret = kIOReturnBadArgument;
1968            } else {
1969                fPort.TX_Parity = data;
1970                fPort.RX_Parity = PD_RS232_PARITY_DEFAULT;
1971
1972                setLineCoding();
1973            }
1974            break;
1975	case PD_E_DATA_RATE:
1976            XTRACE(this, data, event, "executeEventGated - PD_E_DATA_RATE");
1977
1978                // For API compatiblilty with Intel.
1979
1980            data >>= 1;
1981            XTRACE(this, data, 0, "executeEventGated - actual data rate");
1982            if ((data < MIN_BAUD) || (data > kMaxBaudRate))
1983            {
1984                ret = kIOReturnBadArgument;
1985            } else {
1986                fPort.BaudRate = data;
1987
1988                setLineCoding();
1989            }
1990            break;
1991	case PD_E_DATA_SIZE:
1992            XTRACE(this, data, event, "executeEventGated - PD_E_DATA_SIZE");
1993
1994                // For API compatiblilty with Intel.
1995
1996            data >>= 1;
1997            XTRACE(this, data, 0, "executeEventGated - actual data size");
1998            if ((data < 5) || (data > 8))
1999            {
2000                ret = kIOReturnBadArgument;
2001            } else {
2002                fPort.CharLength = data;
2003
2004                setLineCoding();
2005            }
2006            break;
2007	case PD_RS232_E_STOP_BITS:
2008            XTRACE(this, data, event, "executeEventGated - PD_RS232_E_STOP_BITS");
2009            if ((data < 0) || (data > 20))
2010            {
2011                ret = kIOReturnBadArgument;
2012            } else {
2013                fPort.StopBits = data;
2014
2015                setLineCoding();
2016            }
2017            break;
2018	case PD_E_RXQ_FLUSH:
2019            XTRACE(this, data, event, "executeEventGated - PD_E_RXQ_FLUSH");
2020            break;
2021	case PD_E_RX_DATA_INTEGRITY:
2022            XTRACE(this, data, event, "executeEventGated - PD_E_RX_DATA_INTEGRITY");
2023            if ((data != PD_RS232_PARITY_DEFAULT) &&  (data != PD_RS232_PARITY_ANY))
2024            {
2025                ret = kIOReturnBadArgument;
2026            } else {
2027                fPort.RX_Parity = data;
2028            }
2029            break;
2030	case PD_E_RX_DATA_RATE:
2031            XTRACE(this, data, event, "executeEventGated - PD_E_RX_DATA_RATE");
2032            if (data)
2033            {
2034                ret = kIOReturnBadArgument;
2035            }
2036            break;
2037	case PD_E_RX_DATA_SIZE:
2038            XTRACE(this, data, event, "executeEventGated - PD_E_RX_DATA_SIZE");
2039            if (data)
2040            {
2041                ret = kIOReturnBadArgument;
2042            }
2043            break;
2044	case PD_RS232_E_RX_STOP_BITS:
2045            XTRACE(this, data, event, "executeEventGated - PD_RS232_E_RX_STOP_BITS");
2046            if (data)
2047            {
2048                ret = kIOReturnBadArgument;
2049            }
2050            break;
2051	case PD_E_TXQ_FLUSH:
2052            XTRACE(this, data, event, "executeEventGated - PD_E_TXQ_FLUSH");
2053            break;
2054	case PD_RS232_E_LINE_BREAK:
2055            XTRACE(this, data, event, "executeEventGated - PD_RS232_E_LINE_BREAK");
2056            state &= ~PD_RS232_S_BRK;
2057            delta |= PD_RS232_S_BRK;
2058            setStateGated(&state, &delta);
2059            break;
2060	case PD_E_DELAY:
2061            XTRACE(this, data, event, "executeEventGated - PD_E_DELAY");
2062            fPort.CharLatInterval = long2tval(data * 1000);
2063            break;
2064	case PD_E_RXQ_SIZE:
2065            XTRACE(this, data, event, "executeEventGated - PD_E_RXQ_SIZE");
2066            break;
2067	case PD_E_TXQ_SIZE:
2068            XTRACE(this, data, event, "executeEventGated - PD_E_TXQ_SIZE");
2069            break;
2070	case PD_E_RXQ_HIGH_WATER:
2071            XTRACE(this, data, event, "executeEventGated - PD_E_RXQ_HIGH_WATER");
2072            break;
2073	case PD_E_RXQ_LOW_WATER:
2074            XTRACE(this, data, event, "executeEventGated - PD_E_RXQ_LOW_WATER");
2075            break;
2076	case PD_E_TXQ_HIGH_WATER:
2077            XTRACE(this, data, event, "executeEventGated - PD_E_TXQ_HIGH_WATER");
2078            break;
2079	case PD_E_TXQ_LOW_WATER:
2080            XTRACE(this, data, event, "executeEventGated - PD_E_TXQ_LOW_WATER");
2081            break;
2082	default:
2083            XTRACE(this, data, event, "executeEventGated - unrecognized event");
2084            ret = kIOReturnBadArgument;
2085            break;
2086    }
2087
2088    return ret;
2089
2090}/* end executeEventGated */
2091
2092/****************************************************************************************************/
2093//
2094//		Method:		AppleUSBCDCDMM::requestEvent
2095//
2096//		Inputs:		event - The event
2097//				refCon - unused
2098//
2099//		Outputs:	Return Code - kIOReturnSuccess, kIOReturnBadArgument
2100//				data - any data associated with the event
2101//
2102//		Desc:		requestEvent processes the specified event as an immediate request and
2103//				returns the results in data.  This is primarily used for getting link
2104//				status information and verifying baud rate etc.
2105//				For the most part this can be done immediately without being gated.
2106//
2107/****************************************************************************************************/
2108
2109IOReturn AppleUSBCDCDMM::requestEvent(UInt32 event, UInt32 *data, void *refCon)
2110{
2111    IOReturn	returnValue = kIOReturnSuccess;
2112
2113    XTRACE(this, 0, event, "requestEvent");
2114
2115    if (fTerminate || fStopping)
2116    {
2117        XTRACE(this, 0, kIOReturnOffline, "requestEvent - Offline");
2118        return kIOReturnOffline;
2119    }
2120
2121    if (data == NULL)
2122    {
2123        XTRACE(this, 0, event, "requestEvent - data is null");
2124        returnValue = kIOReturnBadArgument;
2125    } else {
2126        switch (event)
2127        {
2128            case PD_E_ACTIVE:
2129                XTRACE(this, 0, event, "requestEvent - PD_E_ACTIVE");
2130                *data = bool(getState(&fPort) & PD_S_ACTIVE);			// Just to be safe put this through the gate
2131                break;
2132            case PD_E_FLOW_CONTROL:
2133                XTRACE(this, fPort.FlowControl, event, "requestEvent - PD_E_FLOW_CONTROL");
2134                *data = fPort.FlowControl;
2135                break;
2136            case PD_E_DELAY:
2137                XTRACE(this, 0, event, "requestEvent - PD_E_DELAY");
2138                *data = tval2long(fPort.CharLatInterval)/ 1000;
2139                break;
2140            case PD_E_DATA_LATENCY:
2141                XTRACE(this, 0, event, "requestEvent - PD_E_DATA_LATENCY");
2142                *data = tval2long(fPort.DataLatInterval)/ 1000;
2143                break;
2144            case PD_E_TXQ_SIZE:
2145                XTRACE(this, 0, event, "requestEvent - PD_E_TXQ_SIZE");
2146                *data = GetQueueSize(&fPort.TX);
2147                break;
2148            case PD_E_RXQ_SIZE:
2149                XTRACE(this, 0, event, "requestEvent - PD_E_RXQ_SIZE");
2150                *data = GetQueueSize(&fPort.RX);
2151                break;
2152            case PD_E_TXQ_LOW_WATER:
2153                XTRACE(this, 0, event, "requestEvent - PD_E_TXQ_LOW_WATER");
2154                *data = 0;
2155                returnValue = kIOReturnBadArgument;
2156                break;
2157            case PD_E_RXQ_LOW_WATER:
2158                XTRACE(this, 0, event, "requestEvent - PD_E_RXQ_LOW_WATER");
2159                *data = 0;
2160                returnValue = kIOReturnBadArgument;
2161                break;
2162            case PD_E_TXQ_HIGH_WATER:
2163                XTRACE(this, 0, event, "requestEvent - PD_E_TXQ_HIGH_WATER");
2164                *data = 0;
2165                returnValue = kIOReturnBadArgument;
2166                break;
2167            case PD_E_RXQ_HIGH_WATER:
2168                XTRACE(this, 0, event, "requestEvent - PD_E_RXQ_HIGH_WATER");
2169                *data = 0;
2170                returnValue = kIOReturnBadArgument;
2171                break;
2172            case PD_E_TXQ_AVAILABLE:
2173                XTRACE(this, 0, event, "requestEvent - PD_E_TXQ_AVAILABLE");
2174                *data = FreeSpaceinQueue(&fPort.TX);
2175                break;
2176            case PD_E_RXQ_AVAILABLE:
2177                XTRACE(this, 0, event, "requestEvent - PD_E_RXQ_AVAILABLE");
2178                *data = UsedSpaceinQueue(&fPort.RX);
2179                break;
2180            case PD_E_DATA_RATE:
2181                XTRACE(this, 0, event, "requestEvent - PD_E_DATA_RATE");
2182                *data = fPort.BaudRate << 1;
2183                break;
2184            case PD_E_RX_DATA_RATE:
2185                XTRACE(this, 0, event, "requestEvent - PD_E_RX_DATA_RATE");
2186                *data = 0x00;
2187                break;
2188            case PD_E_DATA_SIZE:
2189                XTRACE(this, 0, event, "requestEvent - PD_E_DATA_SIZE");
2190                *data = fPort.CharLength << 1;
2191                break;
2192            case PD_E_RX_DATA_SIZE:
2193                XTRACE(this, 0, event, "requestEvent - PD_E_RX_DATA_SIZE");
2194                *data = 0x00;
2195                break;
2196            case PD_E_DATA_INTEGRITY:
2197                XTRACE(this, 0, event, "requestEvent - PD_E_DATA_INTEGRITY");
2198                *data = fPort.TX_Parity;
2199                break;
2200            case PD_E_RX_DATA_INTEGRITY:
2201                XTRACE(this, 0, event, "requestEvent - PD_E_RX_DATA_INTEGRITY");
2202                *data = fPort.RX_Parity;
2203                break;
2204            case PD_RS232_E_STOP_BITS:
2205                XTRACE(this, 0, event, "requestEvent - PD_RS232_E_STOP_BITS");
2206                *data = fPort.StopBits << 1;
2207                break;
2208            case PD_RS232_E_RX_STOP_BITS:
2209                XTRACE(this, 0, event, "requestEvent - PD_RS232_E_RX_STOP_BITS");
2210                *data = 0x00;
2211                break;
2212            case PD_RS232_E_XON_BYTE:
2213                XTRACE(this, 0, event, "requestEvent - PD_RS232_E_XON_BYTE");
2214                *data = fPort.XONchar;
2215                break;
2216            case PD_RS232_E_XOFF_BYTE:
2217                XTRACE(this, 0, event, "requestEvent - PD_RS232_E_XOFF_BYTE");
2218                *data = fPort.XOFFchar;
2219                break;
2220            case PD_RS232_E_LINE_BREAK:
2221                XTRACE(this, 0, event, "requestEvent - PD_RS232_E_LINE_BREAK");
2222                *data = bool(getState(&fPort) & PD_RS232_S_BRK);			// This should be gated too
2223                break;
2224            case PD_RS232_E_MIN_LATENCY:
2225                XTRACE(this, 0, event, "requestEvent - PD_RS232_E_MIN_LATENCY");
2226                *data = bool(fPort.MinLatency);
2227                break;
2228            default:
2229                XTRACE(this, 0, event, "requestEvent - unrecognized event");
2230                returnValue = kIOReturnBadArgument;
2231                break;
2232        }
2233    }
2234
2235    return kIOReturnSuccess;
2236
2237}/* end requestEvent */
2238
2239/****************************************************************************************************/
2240//
2241//		Method:		AppleUSBCDCDMM::enqueueEvent
2242//
2243//		Inputs:		event - The event
2244//				data - any data associated with the event,
2245//				sleep - true (wait for it), false (don't)
2246//				refCon - unused
2247//
2248//		Outputs:	Return Code - kIOReturnSuccess or kIOReturnNotOpen
2249//
2250//		Desc:		Not used by this driver.
2251//				Events are passed on to executeEvent for immediate action.
2252//
2253/****************************************************************************************************/
2254
2255IOReturn AppleUSBCDCDMM::enqueueEvent(UInt32 event, UInt32 data, bool sleep, void *refCon)
2256{
2257    IOReturn 	ret;
2258
2259    XTRACE(this, data, event, "enqueueEvent");
2260
2261    if (fTerminate || fStopping)
2262    {
2263        XTRACE(this, 0, kIOReturnOffline, "enqueueEvent - Offline");
2264        return kIOReturnOffline;
2265    }
2266
2267    retain();
2268    ret = fCommandGate->runAction(executeEventAction, (void *)&event, (void *)&data);
2269    release();
2270
2271    return ret;
2272
2273}/* end enqueueEvent */
2274
2275/****************************************************************************************************/
2276//
2277//		Method:		AppleUSBCDCDMM::dequeueEvent
2278//
2279//		Inputs:		sleep - true (wait for it), false (don't)
2280//				refCon - unused
2281//
2282//		Outputs:	Return Code - kIOReturnSuccess, kIOReturnNotOpen
2283//
2284//		Desc:		Not used by this driver.
2285//
2286/****************************************************************************************************/
2287
2288IOReturn AppleUSBCDCDMM::dequeueEvent(UInt32 *event, UInt32 *data, bool sleep, void *refCon)
2289{
2290
2291    XTRACE(this, 0, 0, "dequeueEvent");
2292
2293    if (fTerminate || fStopping)
2294    {
2295        XTRACE(this, 0, kIOReturnOffline, "dequeueEvent - Offline");
2296        return kIOReturnOffline;
2297    }
2298
2299    if ((event == NULL) || (data == NULL))
2300        return kIOReturnBadArgument;
2301
2302    if (getState(&fPort) & PD_S_ACTIVE)
2303    {
2304        return kIOReturnSuccess;
2305    }
2306
2307    return kIOReturnNotOpen;
2308
2309}/* end dequeueEvent */
2310
2311/****************************************************************************************************/
2312//
2313//		Method:		AppleUSBCDCDMM::enqueueData
2314//
2315//		Inputs:		buffer - the data
2316//				size - number of bytes
2317//				sleep - true (wait for it), false (don't)
2318//				refCon - unused
2319//
2320//		Outputs:	Return Code - kIOReturnSuccess, kIOReturnBadArgument or value returned from watchState
2321//				count - bytes transferred
2322//
2323//		Desc:		set up for enqueueDataGated call.
2324//
2325/****************************************************************************************************/
2326
2327IOReturn AppleUSBCDCDMM::enqueueData(UInt8 *buffer, UInt32 size, UInt32 *count, bool sleep, void *refCon)
2328{
2329    IOReturn 	ret;
2330
2331    XTRACE(this, size, sleep, "enqueueData");
2332
2333    if (fTerminate || fStopping)
2334    {
2335        XTRACE(this, 0, kIOReturnOffline, "enqueueData - Offline");
2336        return kIOReturnOffline;
2337    }
2338
2339    if (count == NULL || buffer == NULL)
2340        return kIOReturnBadArgument;
2341
2342    retain();
2343    ret = fCommandGate->runAction(enqueueDataAction, (void *)buffer, (void *)&size, (void *)count, (void *)&sleep);
2344    release();
2345
2346    return ret;
2347
2348}/* end enqueueData */
2349
2350/****************************************************************************************************/
2351//
2352//		Method:		AppleUSBCDCDMM::enqueueDatatAction
2353//
2354//		Desc:		Dummy pass through for enqueueDataGated.
2355//
2356/****************************************************************************************************/
2357
2358IOReturn AppleUSBCDCDMM::enqueueDataAction(OSObject *owner, void *arg0, void *arg1, void *arg2, void *arg3)
2359{
2360
2361    return ((AppleUSBCDCDMM *)owner)->enqueueDataGated((UInt8 *)arg0, (UInt32 *)arg1, (UInt32 *)arg2, (bool *)arg3);
2362
2363}/* end enqueueDataAction */
2364
2365/****************************************************************************************************/
2366//
2367//		Method:		AppleUSBCDCDMM::enqueueDataGated
2368//
2369//		Inputs:		buffer - the data
2370//				size - number of bytes
2371//				sleep - true (wait for it), false (don't)
2372//
2373//		Outputs:	Return Code - kIOReturnSuccess or value returned from watchState
2374//				count - bytes transferred,
2375//
2376//		Desc:		enqueueData will attempt to copy data from the specified buffer to
2377//				the TX queue as a sequence of VALID_DATA events.  The argument
2378//				bufferSize specifies the number of bytes to be sent.  The actual
2379//				number of bytes transferred is returned in count.
2380//				If sleep is true, then this method will sleep until all bytes can be
2381//				transferred.  If sleep is false, then as many bytes as possible
2382//				will be copied to the TX queue.
2383//				Note that the caller should ALWAYS check the transferCount unless
2384//				the return value was kIOReturnBadArgument, indicating one or more
2385//				arguments were not valid.  Other possible return values are
2386//				kIOReturnSuccess if all requirements were met or kIOReturnOffline
2387//				if the device was unplugged.
2388//
2389/****************************************************************************************************/
2390
2391IOReturn AppleUSBCDCDMM::enqueueDataGated(UInt8 *buffer, UInt32 *pSize, UInt32 *count, bool *pSleep)
2392{
2393	UInt32		size = *pSize;
2394	bool		sleep = *pSleep;
2395    UInt32		state = PD_S_TXQ_LOW_WATER;
2396	UInt32		mask;
2397    IOReturn 	rtn = kIOReturnSuccess;
2398
2399    XTRACE(this, size, sleep, "enqueueDataGated");
2400
2401    if (fTerminate || fStopping)
2402        return kIOReturnOffline;
2403
2404    *count = 0;
2405
2406    if (!(fPort.State & PD_S_ACTIVE))
2407        return kIOReturnNotOpen;
2408
2409    XTRACE(this, fPort.State, size, "enqueueDataGated - current State");
2410//    LogData(kDataOther, size, buffer);
2411
2412        // Go ahead and try to add something to the buffer
2413
2414    *count = AddtoQueue(&fPort.TX, buffer, size);
2415    CheckQueues();
2416
2417        // Let the tranmitter know that we have something ready to go
2418
2419    setUpTransmit();
2420
2421        // If we could not queue up all of the data on the first pass and
2422        // the user wants us to sleep until it's all out then sleep
2423
2424    while ((*count < size) && sleep)
2425    {
2426        state = PD_S_TXQ_LOW_WATER;
2427		mask = PD_S_TXQ_LOW_WATER;
2428        rtn = watchStateGated(&state, &mask);
2429        if (rtn != kIOReturnSuccess)
2430        {
2431            XTRACE(this, 0, rtn, "enqueueDataGated - interrupted");
2432            return rtn;
2433        }
2434
2435        *count += AddtoQueue(&fPort.TX, buffer + *count, size - *count);
2436        CheckQueues();
2437
2438            // Let the tranmitter know that we have something ready to go.
2439
2440        setUpTransmit();
2441    }
2442
2443    XTRACE(this, *count, size, "enqueueDataGated - Exit");
2444
2445    return kIOReturnSuccess;
2446
2447}/* end enqueueDataGated */
2448
2449/****************************************************************************************************/
2450//
2451//		Method:		AppleUSBCDCDMM::dequeueData
2452//
2453//		Inputs:		size - buffer size
2454//				min - minimum bytes required
2455//				refCon - the Port
2456//
2457//		Outputs:	buffer - data returned
2458//				min - number of bytes
2459//				Return Code - kIOReturnSuccess, kIOReturnBadArgument, kIOReturnNotOpen, or value returned from watchState
2460//
2461//		Desc:		set up for dequeueDataGated call.
2462//
2463/****************************************************************************************************/
2464
2465IOReturn AppleUSBCDCDMM::dequeueData(UInt8 *buffer, UInt32 size, UInt32 *count, UInt32 min, void *refCon)
2466{
2467    IOReturn 	ret;
2468
2469    XTRACE(this, size, min, "dequeueData");
2470
2471    if (fTerminate || fStopping)
2472    {
2473        XTRACE(this, 0, kIOReturnOffline, "dequeueData - Offline");
2474        return kIOReturnOffline;
2475    }
2476
2477    if ((count == NULL) || (buffer == NULL) || (min > size))
2478        return kIOReturnBadArgument;
2479
2480    retain();
2481    ret = fCommandGate->runAction(dequeueDataAction, (void *)buffer, (void *)&size, (void *)count, (void *)&min);
2482    release();
2483
2484    return ret;
2485
2486}/* end dequeueData */
2487
2488/****************************************************************************************************/
2489//
2490//		Method:		AppleUSBCDCDMM::dequeueDatatAction
2491//
2492//		Desc:		Dummy pass through for dequeueDataGated.
2493//
2494/****************************************************************************************************/
2495
2496IOReturn AppleUSBCDCDMM::dequeueDataAction(OSObject *owner, void *arg0, void *arg1, void *arg2, void *arg3)
2497{
2498
2499    return ((AppleUSBCDCDMM *)owner)->dequeueDataGated((UInt8 *)arg0, (UInt32 *)arg1, (UInt32 *)arg2, (UInt32 *)arg3);
2500
2501}/* end dequeueDataAction */
2502
2503/****************************************************************************************************/
2504//
2505//		Method:		AppleUSBCDCDMM::dequeueDataGated
2506//
2507//		Inputs:		size - buffer size
2508//				min - minimum bytes required
2509//
2510//		Outputs:	buffer - data returned
2511//				min - number of bytes
2512//				Return Code - kIOReturnSuccess, kIOReturnBadArgument, kIOReturnNotOpen, or value returned from watchState
2513//
2514//		Desc:		dequeueData will attempt to copy data from the RX queue to the
2515//				specified buffer.  No more than bufferSize VALID_DATA events
2516//				will be transferred. In other words, copying will continue until
2517//				either a non-data event is encountered or the transfer buffer
2518//				is full.  The actual number of bytes transferred is returned
2519//				in count.
2520//				The sleep semantics of this method are slightly more complicated
2521//				than other methods in this API. Basically, this method will
2522//				continue to sleep until either min characters have been
2523//				received or a non data event is next in the RX queue.  If
2524//				min is zero, then this method never sleeps and will return
2525//				immediately if the queue is empty.
2526//				Note that the caller should ALWAYS check the transferCount
2527//				unless the return value was kIOReturnBadArgument, indicating one or
2528//				more arguments were not valid.
2529//
2530/****************************************************************************************************/
2531
2532IOReturn AppleUSBCDCDMM::dequeueDataGated(UInt8 *buffer, UInt32 *pSize, UInt32 *count, UInt32 *pMin)
2533{
2534	UInt32		size = *pSize;
2535	UInt32		min = *pMin;
2536    IOReturn 	rtn = kIOReturnSuccess;
2537    UInt32		state = 0;
2538	UInt32		mask;
2539    bool		goXOIdle;
2540
2541    XTRACE(this, size, min, "dequeueDataGated");
2542
2543    if (fTerminate || fStopping)
2544        return kIOReturnOffline;
2545
2546        // If the port is not active then there should not be any chars.
2547
2548    *count = 0;
2549    if (!(fPort.State & PD_S_ACTIVE))
2550        return kIOReturnNotOpen;
2551
2552        // Get any data living in the queue.
2553
2554    *count = RemovefromQueue(&fPort.RX, buffer, size);
2555    CheckQueues();
2556
2557    while ((min > 0) && (*count < min))
2558    {
2559            // Figure out how many bytes we have left to queue up
2560
2561        state = 0;
2562		mask = PD_S_RXQ_EMPTY;
2563        rtn = watchStateGated(&state, &mask);
2564
2565        if (rtn != kIOReturnSuccess)
2566        {
2567            XTRACE(this, 0, rtn, "dequeueDataGated - Interrupted!");
2568            return rtn;
2569        }
2570
2571            // Try and get more data starting from where we left off
2572
2573        *count += RemovefromQueue(&fPort.RX, buffer + *count, (size - *count));
2574        CheckQueues();
2575
2576    }
2577
2578        // Now let's check our receive buffer to see if we need to stop
2579
2580    goXOIdle = (UsedSpaceinQueue(&fPort.RX) < fPort.RXStats.LowWater) && (fPort.RXOstate == SENT_XOFF);
2581
2582    if (goXOIdle)
2583    {
2584        fPort.RXOstate = IDLE_XO;
2585        AddBytetoQueue(&fPort.TX, fPort.XOFFchar);
2586        setUpTransmit();
2587    }
2588
2589    XTRACE(this, *count, size, "dequeueData - Exit");
2590
2591    return rtn;
2592
2593}/* end dequeueDataGated */
2594
2595/****************************************************************************************************/
2596//
2597//		Method:		AppleUSBCDCDMM::setUpTransmit
2598//
2599//		Inputs:
2600//
2601//		Outputs:	return code - true (transmit started), false (transmission already in progress)
2602//
2603//		Desc:		Setup and then start transmisson
2604//
2605/****************************************************************************************************/
2606
2607bool AppleUSBCDCDMM::setUpTransmit()
2608{
2609
2610    XTRACE(this, 0, 0, "setUpTransmit");
2611
2612            // As a precaution just check we've not been terminated (maybe a woken thread)
2613
2614    if (fTerminate || fStopping)
2615    {
2616        XTRACE(this, 0, 0, "setUpTransmit - terminated");
2617        return false;
2618    }
2619
2620    if (UsedSpaceinQueue(&fPort.TX) > 0)
2621    {
2622        startTransmission();
2623    }
2624
2625    return TRUE;
2626
2627}/* end setUpTransmit */
2628
2629/****************************************************************************************************/
2630//
2631//		Method:		AppleUSBCDCDMM::startTransmission
2632//
2633//		Inputs:
2634//
2635//		Outputs:
2636//
2637//		Desc:		Start the transmisson
2638//				Must be called from a gated method
2639//
2640/****************************************************************************************************/
2641
2642void AppleUSBCDCDMM::startTransmission()
2643{
2644	UInt32		state;
2645	UInt32		mask;
2646    size_t		count;
2647    IOReturn	ior;
2648
2649    XTRACE(this, 0, 0, "startTransmission");
2650
2651		// Check if we have a cr, if not just exit
2652
2653	count = isCRinQueue(&fPort.TX);
2654
2655	if (count <= 0)
2656    {
2657            // Updates all the status flags
2658
2659        CheckQueues();
2660        return;
2661    }
2662
2663        // Fill up the buffer with characters from the queue
2664
2665    count = RemovefromQueue(&fPort.TX, fOutBuffer, count);
2666
2667	state = PD_S_TX_BUSY;
2668	mask = PD_S_TX_BUSY;
2669    setStateGated(&state, &mask);
2670
2671    XTRACE(this, fPort.State, count, "startTransmission - Bytes to write");
2672    LogData(kDataOut, count, fOutBuffer);
2673
2674    ior = sendMERRequest(kUSBSEND_ENCAPSULATED_COMMAND, 0, count, fOutBuffer, &fMERCompletionInfo);
2675    if (ior != kIOReturnSuccess)
2676    {
2677        XTRACE(this, 0, ior, "startTransmission - sendMERRequest failed");
2678    }
2679
2680        // We just removed a bunch of stuff from the
2681        // queue, so see if we can free some thread(s)
2682        // to enqueue more stuff.
2683
2684    CheckQueues();
2685
2686}/* end startTransmission */
2687
2688/****************************************************************************************************/
2689//
2690//		Method:		AppleUSBCDCDMM::sendMERRequest
2691//
2692//		Inputs:
2693//
2694//		Outputs:
2695//
2696//		Desc:		Set up and send a Management Element Request(MER).
2697//
2698/****************************************************************************************************/
2699
2700IOReturn AppleUSBCDCDMM::sendMERRequest(UInt8 request, UInt16 val, UInt16 len, UInt8 *buff, IOUSBCompletion *Comp)
2701{
2702	IOUSBDevRequest	*MER;
2703    IOReturn		rc = kIOReturnSuccess;
2704
2705    XTRACE(this, 0, 0, "sendMERRequest");
2706
2707	MER = (IOUSBDevRequest*)IOMalloc(sizeof(IOUSBDevRequest));
2708    if (!MER)
2709    {
2710        XTRACE(this, 0, 0, "sendMERRequest - allocate MER failed");
2711        return kIOReturnError;
2712    }
2713    bzero(MER, sizeof(IOUSBDevRequest));
2714
2715        // now build the Management Element Request
2716
2717    MER->bmRequestType = USBmakebmRequestType(kUSBOut, kUSBClass, kUSBInterface);
2718    MER->bRequest = request;
2719    MER->wValue = val;
2720    MER->wIndex = fInterfaceNumber;
2721	if (len > 0)
2722	{
2723		MER->wLength = len;
2724		MER->pData = buff;
2725	} else {
2726		MER->wLength = 0;
2727		MER->pData = NULL;
2728	}
2729
2730    Comp->parameter = MER;
2731
2732    rc = fInterface->GetDevice()->DeviceRequest(MER, Comp);
2733    if (rc != kIOReturnSuccess)
2734    {
2735        XTRACE(this, MER->bRequest, rc, "sendMERRequest - error issueing DeviceRequest");
2736        IOFree(MER, sizeof(IOUSBDevRequest));
2737    }
2738
2739	return rc;
2740
2741}
2742
2743/* end sendMERRequest */
2744
2745/****************************************************************************************************/
2746//
2747//		Method:		AppleUSBCDCDMM::setLineCoding
2748//
2749//		Inputs:
2750//
2751//		Outputs:
2752//
2753//		Desc:		Set up and send SetLineCoding Management Element Request(MER) for all settings.
2754//
2755/****************************************************************************************************/
2756
2757void AppleUSBCDCDMM::setLineCoding()
2758{
2759	IOReturn	ior;
2760	LineCoding  *lineParms;
2761    UInt16		lcLen = sizeof(LineCoding)-1;
2762
2763    XTRACE(this, 0, 0, "setLineCoding");
2764
2765	return;
2766
2767    	// Check for changes and only do it if something's changed
2768
2769    if ((fPort.BaudRate == fPort.LastBaudRate) && (fPort.StopBits == fPort.LastStopBits) &&
2770        (fPort.TX_Parity == fPort.LastTX_Parity) && (fPort.CharLength == fPort.LastCharLength))
2771    {
2772        return;
2773    }
2774
2775	lineParms = (LineCoding *)IOMalloc(lcLen);
2776    if (!lineParms)
2777    {
2778        XTRACE(this, 0, 0, "setLineCoding - allocate lineParms failed");
2779        return;
2780    }
2781    bzero(lineParms, lcLen);
2782
2783        // Convert BaudRate - intel format doubleword (32 bits)
2784
2785    OSWriteLittleInt32(lineParms, dwDTERateOffset, fPort.BaudRate);
2786    lineParms->bCharFormat = fPort.StopBits - 2;
2787    lineParms->bParityType = fPort.TX_Parity - 1;
2788    lineParms->bDataBits = fPort.CharLength;
2789
2790        // Now send it
2791
2792	ior = sendMERRequest(kUSBSET_LINE_CODING, 0, lcLen, (UInt8 *)lineParms, &fMERCompletionInfo);
2793	if (ior != kIOReturnSuccess)
2794	{
2795		XTRACE(this, 0, ior, "setLineCoding - sendMERRequest failed");
2796		IOFree(lineParms, lcLen);
2797	}
2798
2799}/* end setLineCoding */
2800
2801/****************************************************************************************************/
2802//
2803//		Method:		AppleUSBCDCDMM::setControlLineState
2804//
2805//		Inputs:		RTS - true(set RTS), false(clear RTS)
2806//				DTR - true(set DTR), false(clear DTR)
2807//
2808//		Outputs:
2809//
2810//		Desc:		Set up and send SetControlLineState Management Element Request(MER).
2811//
2812/****************************************************************************************************/
2813
2814void AppleUSBCDCDMM::setControlLineState(bool RTS, bool DTR)
2815{
2816	IOReturn	ior;
2817    UInt16		CSBitmap = 0;
2818
2819    XTRACE(this, 0, 0, "setControlLineState");
2820
2821	return;
2822
2823	if (RTS)
2824        CSBitmap |= kRTSOn;
2825    if (DTR)
2826        CSBitmap |= kDTROn;
2827
2828		// Now send it
2829
2830	ior = sendMERRequest(kUSBSET_CONTROL_LINE_STATE, CSBitmap, 0, NULL, &fMERCompletionInfo);
2831	if (ior != kIOReturnSuccess)
2832	{
2833		XTRACE(this, 0, ior, "setControlLineState - sendMERRequest failed");
2834	}
2835
2836}/* end setControlLineState */
2837
2838/****************************************************************************************************/
2839//
2840//		Method:		AppleUSBCDCDMM::sendBreak
2841//
2842//		Inputs:		sBreak - true(set Break), false(clear Break)
2843//
2844//		Outputs:
2845//
2846//		Desc:		Set up and send SendBreak Management Element Request(MER).
2847//
2848/****************************************************************************************************/
2849
2850void AppleUSBCDCDMM::sendBreak(bool sBreak)
2851{
2852	IOReturn	ior;
2853    UInt16		breakVal = 0;
2854
2855    XTRACE(this, 0, 0, "sendBreak");
2856
2857	return;
2858
2859	if (sBreak)
2860    {
2861        breakVal = 0xFFFF;
2862    }
2863
2864		// Now send it
2865
2866	ior = sendMERRequest(kUSBSEND_BREAK, breakVal, 0, NULL, &fMERCompletionInfo);
2867	if (ior != kIOReturnSuccess)
2868	{
2869		XTRACE(this, 0, ior, "sendBreak - sendMERRequest failed");
2870	}
2871
2872}/* end sendBreak */
2873
2874/****************************************************************************************************/
2875//
2876//		Method:		AppleUSBCDCDMM::initStructure
2877//
2878//		Inputs:
2879//
2880//		Outputs:
2881//
2882//		Desc:		Initialize the port structure
2883//
2884/****************************************************************************************************/
2885
2886void AppleUSBCDCDMM::initStructure()
2887{
2888
2889    XTRACE(this, 0, 0, "initStructure");
2890
2891        // These are set up at start and should not be reset during execution.
2892
2893    fPort.FCRimage = 0x00;
2894    fPort.IERmask = 0x00;
2895
2896    fPort.State = (PD_S_TXQ_EMPTY | PD_S_TXQ_LOW_WATER | PD_S_RXQ_EMPTY | PD_S_RXQ_LOW_WATER);
2897    fPort.WatchStateMask = 0x00000000;
2898
2899}/* end initStructure */
2900
2901/****************************************************************************************************/
2902//
2903//		Method:		AppleUSBCDCDMM::setStructureDefaults
2904//
2905//		Inputs:
2906//
2907//		Outputs:
2908//
2909//		Desc:		Sets the defaults for the specified port structure
2910//
2911/****************************************************************************************************/
2912
2913void AppleUSBCDCDMM::setStructureDefaults()
2914{
2915    UInt32	tmp;
2916
2917    XTRACE(this, 0, 0, "setStructureDefaults");
2918
2919    fPort.BaudRate = kDefaultBaudRate;			// 9600 bps
2920    fPort.LastBaudRate = 0;
2921    fPort.CharLength = 8;				// 8 Data bits
2922    fPort.LastCharLength = 0;
2923    fPort.StopBits = 2;					// 1 Stop bit
2924    fPort.LastStopBits = 0;
2925    fPort.TX_Parity = 1;				// No Parity
2926    fPort.LastTX_Parity	= 0;
2927    fPort.RX_Parity = 1;				// --ditto--
2928    fPort.MinLatency = false;
2929    fPort.XONchar = '\x11';
2930    fPort.XOFFchar = '\x13';
2931    fPort.FlowControl = 0x00000000;
2932    fPort.RXOstate = IDLE_XO;
2933    fPort.TXOstate = IDLE_XO;
2934    fPort.FrameTOEntry = NULL;
2935
2936    fPort.RXStats.BufferSize = kMaxCirBufferSize;
2937    fPort.RXStats.HighWater = (fPort.RXStats.BufferSize << 1) / 3;
2938    fPort.RXStats.LowWater = fPort.RXStats.HighWater >> 1;
2939    fPort.TXStats.BufferSize = kMaxCirBufferSize;
2940    fPort.TXStats.HighWater = (fPort.RXStats.BufferSize << 1) / 3;
2941    fPort.TXStats.LowWater = fPort.RXStats.HighWater >> 1;
2942
2943    fPort.FlowControl = (DEFAULT_AUTO | DEFAULT_NOTIFY);
2944
2945    for (tmp=0; tmp < (256 >> SPECIAL_SHIFT); tmp++)
2946        fPort.SWspecial[ tmp ] = 0;
2947
2948}/* end setStructureDefaults */
2949
2950/****************************************************************************************************/
2951//
2952//		Method:		AppleUSBCDCDMM::allocateResources
2953//
2954//		Inputs:
2955//
2956//		Outputs:	return code - true (allocate was successful), false (it failed)
2957//
2958//		Desc:		Finishes up the rest of the configuration and gets all the endpoints open etc.
2959//
2960/****************************************************************************************************/
2961
2962bool AppleUSBCDCDMM::allocateResources()
2963{
2964    IOUSBFindEndpointRequest	epReq;
2965	IOReturn					rtn;
2966
2967    XTRACE(this, 0, 0, "allocateResources.");
2968
2969        // Open all the end points and get the buffers
2970
2971    if (!fInterface->open(this))
2972    {
2973        XTRACE(this, 0, 0, "allocateResources - open data interface failed.");
2974        return false;
2975    }
2976
2977           // Interrupt pipe
2978
2979    epReq.type = kUSBInterrupt;
2980    epReq.direction = kUSBIn;
2981    fIntPipe = fInterface->FindNextPipe(0, &epReq);
2982    if (!fIntPipe)
2983    {
2984        XTRACE(this, 0, 0, "allocateResources - no interrrupt pipe.");
2985        return false;
2986    }
2987    XTRACEP(this, epReq.maxPacketSize << 16 |epReq.interval, 0, "allocateResources - interrupt pipe.");
2988	fIntBufferSize = epReq.maxPacketSize;
2989
2990        // Allocate Memory Descriptor Pointer with memory for the Interrupt pipe:
2991
2992    fIntPipeMDP = IOBufferMemoryDescriptor::withCapacity(fIntBufferSize, kIODirectionIn);
2993    if (!fIntPipeMDP)
2994    {
2995        XTRACE(this, 0, 0, "allocateResources - Couldn't allocate MDP for interrupt pipe");
2996        return false;
2997    }
2998
2999    fIntPipeBuffer = (UInt8*)fIntPipeMDP->getBytesNoCopy();
3000    XTRACEP(this, 0, fIntPipeBuffer, "allocateResources - comm buffer");
3001
3002		// Now the input and output buffers
3003
3004	fInBuffer = (UInt8 *)IOMalloc(fMax_Command);
3005    if (!fInBuffer)
3006    {
3007        XTRACE(this, 0, 0, "allocateResources - allocate input buffer failed");
3008        return false;
3009    }
3010    bzero(fInBuffer, fMax_Command);
3011
3012	fOutBuffer = (UInt8 *)IOMalloc(fMax_Command);
3013    if (!fOutBuffer)
3014    {
3015        XTRACE(this, 0, 0, "allocateResources - allocate output buffer failed");
3016        return false;
3017    }
3018    bzero(fOutBuffer, fMax_Command);
3019
3020		// Now the ring buffers
3021
3022    if (!allocateRingBuffer(&fPort.TX, fPort.TXStats.BufferSize))
3023    {
3024        XTRACE(this, 0, 0, "allocateResources - Couldn't allocate TX ring buffer");
3025        return false;
3026    }
3027
3028    XTRACEP(this, 0, fPort.TX.Start, "allocateResources - TX ring buffer");
3029
3030    if (!allocateRingBuffer(&fPort.RX, fPort.RXStats.BufferSize))
3031    {
3032        XTRACE(this, 0, 0, "allocateResources - Couldn't allocate RX ring buffer");
3033        return false;
3034    }
3035
3036    XTRACEP(this, 0, fPort.RX.Start, "allocateResources - RX ring buffer");
3037
3038		// Read the interrupt pipe
3039
3040    fIntCompletionInfo.target = this;
3041    fIntCompletionInfo.action = intReadComplete;
3042    fIntCompletionInfo.parameter = NULL;
3043
3044    rtn = fIntPipe->Read(fIntPipeMDP, &fIntCompletionInfo, NULL);
3045    if (rtn != kIOReturnSuccess)
3046    {
3047		XTRACE(this, rtn, 0, "allocateResources - Read for interrupt pipe failed");
3048		return false;
3049	}
3050
3051		// Set up the MER completion routine
3052
3053    fMERCompletionInfo.target = this;
3054    fMERCompletionInfo.action = merWriteComplete;
3055    fMERCompletionInfo.parameter = NULL;
3056
3057		// Set up the response completion routine
3058
3059    fRspCompletionInfo.target = this;
3060    fRspCompletionInfo.action = rspComplete;
3061    fRspCompletionInfo.parameter = NULL;
3062
3063    return true;
3064
3065}/* end allocateResources */
3066
3067/****************************************************************************************************/
3068//
3069//		Method:		AppleUSBCDCDMM::releaseResources
3070//
3071//		Inputs:
3072//
3073//		Outputs:
3074//
3075//		Desc:		Frees up the resources allocated in allocateResources
3076//
3077/****************************************************************************************************/
3078
3079void AppleUSBCDCDMM::releaseResources()
3080{
3081
3082    XTRACE(this, 0, 0, "releaseResources");
3083
3084	if (fIntPipe)
3085	{
3086		fIntPipe->Abort();
3087	}
3088
3089	if (fInterface)
3090    {
3091        fInterface->close(this);
3092        fInterface->release();
3093        fInterface = NULL;
3094    }
3095
3096    if (fIntPipeMDP)
3097    {
3098        fIntPipeMDP->release();
3099        fIntPipeMDP = 0;
3100    }
3101
3102#if 0
3103	if (fInBuffer)
3104	{
3105		IOFree(fInBuffer, fMax_Command);
3106		fInBuffer = 0;
3107	}
3108#endif
3109
3110    if (fWorkLoop)
3111    {
3112        fWorkLoop->release();
3113        fWorkLoop = NULL;
3114    }
3115
3116    freeRingBuffer(&fPort.TX);
3117    freeRingBuffer(&fPort.RX);
3118
3119}/* end releaseResources */
3120
3121/****************************************************************************************************/
3122//
3123//		Method:		AppleUSBCDCDMM::freeRingBuffer
3124//
3125//		Inputs:		Queue - the specified queue to free
3126//
3127//		Outputs:
3128//
3129//		Desc:		Frees all resources assocated with the queue, then sets all queue parameters
3130//				to safe values.
3131//
3132/****************************************************************************************************/
3133
3134void AppleUSBCDCDMM::freeRingBuffer(CirQueue *Queue)
3135{
3136    XTRACEP(this, 0, Queue, "freeRingBuffer");
3137
3138    if (Queue)
3139    {
3140        if (Queue->Start)
3141        {
3142            IOFree(Queue->Start, Queue->Size);
3143        }
3144        CloseQueue(Queue);
3145    }
3146
3147}/* end freeRingBuffer */
3148
3149/****************************************************************************************************/
3150//
3151//		Method:		AppleUSBCDCDMM::allocateRingBuffer
3152//
3153//		Inputs:		Queue - the specified queue to allocate
3154//				BufferSize - size to allocate
3155//
3156//		Outputs:	return Code - true (buffer allocated), false (it failed)
3157//
3158//		Desc:		Allocates resources needed by the queue, then sets up all queue parameters.
3159//
3160/****************************************************************************************************/
3161
3162bool AppleUSBCDCDMM::allocateRingBuffer(CirQueue *Queue, size_t BufferSize)
3163{
3164    UInt8	*Buffer;
3165
3166        // Size is ignored and kMaxCirBufferSize, which is 4096, is used.
3167
3168    XTRACE(this, 0, BufferSize, "allocateRingBuffer");
3169    Buffer = (UInt8*)IOMalloc(kMaxCirBufferSize);
3170
3171    InitQueue(Queue, Buffer, kMaxCirBufferSize);
3172
3173    if (Buffer)
3174        return true;
3175
3176    return false;
3177
3178}/* end allocateRingBuffer */
3179
3180/****************************************************************************************************/
3181//
3182//		Method:		AppleUSBCDCDMM::message
3183//
3184//		Inputs:		type - message type
3185//				provider - my provider
3186//				argument - additional parameters
3187//
3188//		Outputs:	return Code - kIOReturnSuccess
3189//
3190//		Desc:		Handles IOKit messages.
3191//
3192/****************************************************************************************************/
3193
3194IOReturn AppleUSBCDCDMM::message(UInt32 type, IOService *provider, void *argument)
3195{
3196	IOReturn	rtn;
3197
3198    XTRACE(this, 0, type, "message");
3199
3200    switch (type)
3201    {
3202        case kIOMessageServiceIsTerminated:
3203            XTRACE(this, fSessions, type, "message - kIOMessageServiceIsTerminated");
3204            fTerminate = true;		// We're being terminated (unplugged)
3205            releaseResources();
3206            return kIOReturnSuccess;
3207        case kIOMessageServiceIsSuspended:
3208            XTRACE(this, 0, type, "message - kIOMessageServiceIsSuspended");
3209            break;
3210        case kIOMessageServiceIsResumed:
3211            XTRACE(this, 0, type, "message - kIOMessageServiceIsResumed");
3212            break;
3213        case kIOMessageServiceIsRequestingClose:
3214            XTRACE(this, 0, type, "message - kIOMessageServiceIsRequestingClose");
3215            break;
3216        case kIOMessageServiceWasClosed:
3217            XTRACE(this, 0, type, "message - kIOMessageServiceWasClosed");
3218            break;
3219        case kIOMessageServiceBusyStateChange:
3220            XTRACE(this, 0, type, "message - kIOMessageServiceBusyStateChange");
3221            break;
3222        case kIOUSBMessagePortHasBeenResumed:
3223            XTRACE(this, 0, type, "message - kIOUSBMessagePortHasBeenResumed");
3224            if (fReadDead)
3225			{
3226				rtn = fIntPipe->Read(fIntPipeMDP, &fIntCompletionInfo, NULL);
3227				if (rtn != kIOReturnSuccess)
3228				{
3229					XTRACE(this, 0, rtn, "message - Read for interrupt-in pipe failed, still dead");
3230				} else {
3231					fReadDead = false;
3232				}
3233			}
3234            return kIOReturnSuccess;
3235        case kIOUSBMessageHubResumePort:
3236            XTRACE(this, 0, type, "message - kIOUSBMessageHubResumePort");
3237            break;
3238        case kIOUSBMessagePortHasBeenReset:
3239            XTRACE(this, 0, type, "message - kIOUSBMessagePortHasBeenReset");
3240			if (fReadDead)
3241			{
3242				rtn = fIntPipe->Read(fIntPipeMDP, &fIntCompletionInfo, NULL);
3243				if (rtn != kIOReturnSuccess)
3244				{
3245					XTRACE(this, 0, rtn, "message - Read for interrupt-in pipe failed, still dead");
3246				} else {
3247					fReadDead = false;
3248				}
3249			}
3250            return kIOReturnSuccess;
3251        default:
3252            XTRACE(this, 0, type, "message - unknown message");
3253            break;
3254    }
3255
3256    return super::message(type, provider, argument);
3257
3258}/* end message */