1
2    /* Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3     *
4     * @APPLE_LICENSE_HEADER_START@
5     *
6     * The contents of this file constitute Original Code as defined in and
7     * are subject to the Apple Public Source License Version 1.1 (the
8     * "License").  You may not use this file except in compliance with the
9     * License.  Please obtain a copy of the License at
10     * http://www.apple.com/publicsource and read it before using this file.
11     *
12     * This Original Code and all software distributed under the License are
13     * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14     * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15     * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16     * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
17     * License for the specific language governing rights and limitations
18     * under the License.
19     *
20     * @APPLE_LICENSE_HEADER_END@
21     */
22
23    /* AppleUSBIrDA.cpp - MacOSX implementation of USB IrDA Driver. */
24
25#include <machine/limits.h>         /* UINT_MAX */
26#include <libkern/OSByteOrder.h>
27
28#include <IOKit/assert.h>
29#include <IOKit/IOLib.h>
30#include <IOKit/IOService.h>
31#include <IOKit/IOBufferMemoryDescriptor.h>
32#include <IOKit/IOMessage.h>
33
34#include <IOKit/usb/IOUSBBus.h>
35#include <IOKit/usb/IOUSBNub.h>
36#include <IOKit/usb/IOUSBPipe.h>
37#include <IOKit/usb/USB.h>
38#include <IOKit/usb/IOUSBInterface.h>
39
40#include <IOKit/serial/IOSerialKeys.h>
41#include <IOKit/serial/IOModemSerialStreamSync.h>
42#include <IOKit/serial/IORS232SerialStreamSync.h>
43
44#include <UserNotification/KUNCUserNotifications.h>
45
46#include "AppleUSBIrDA.h"
47#include "IrDAComm.h"
48#include "IrDAUser.h"
49#include "IrDALog.h"
50#include "IrDADebugging.h"
51
52
53#if (hasTracing > 0 && hasAppleUSBIrDATracing > 0)
54
55enum tracecodes
56{
57    kLogInit = 1,
58    kLogFree,
59    kLogProbe,
60    kLogStart,
61    kLogStop,
62
63    kLogNewNub,
64    kLogNewPort,
65    kLogDestroyNub,
66
67    kLogSetSpeed,
68    kLogGetState,
69    kLogXmitLen,
70    kLogXmitData,
71
72    kLogAddRxBytes,
73    kLogSetBofCount,
74    kLogGetIrDAStatus,
75
76    kLogSetIrDAState,
77    kLogInterruptRead,
78    kLogDataReadComplete,
79
80    kLogInputData,
81    kLogDataWriteComplete,
82    kLogDataWriteCompleteZero,
83
84    kLogAllocateResources,
85    kLogReleaseResources,
86    kLogConfigureDevice,
87    kLogCreateSerialStream,
88
89    kLogAcquirePort,
90    kLogReleasePort,
91    kLogSetState,
92    kLogWatchState,
93
94    kLogExecEvent,
95    kLogExecEventData,
96    kLogReqEvent,
97    kLogReqEventData,
98
99    kLogSetupTransmit,
100    kLogSetStructureDefaults,
101    kLogMessage,
102
103    kLogWorkAround,
104    kLogWorkAroundComplete,
105
106    kLogInitForPM,
107    kLogInitialPowerState,
108    kLogSetPowerState
109};
110
111static
112EventTraceCauseDesc gTraceEvents[] = {
113    {kLogInit,          "AppleUSBIrDADriver: init"},
114    {kLogFree,          "AppleUSBIrDADriver: free"},
115    {kLogProbe,         "AppleUSBIrDADriver: probe, provider="},
116    {kLogStart,         "AppleUSBIrDADriver: start, provider="},
117    {kLogStop,          "AppleUSBIrDADriver: stop"},
118
119    {kLogNewNub,        "AppleUSBIrDADriver: new nub"},
120    {kLogNewPort,       "AppleUSBIrDADriver: new port"},
121    {kLogDestroyNub,    "AppleUSBIrDADriver: destroy nub"},
122
123    {kLogSetSpeed,      "AppleUSBIrDADriver: set irda speed"},
124    {kLogGetState,      "AppleUSBIrDADriver: get state"},
125    {kLogXmitLen,       "AppleUSBIrDADriver: xmit length"},
126    {kLogXmitData,      "AppleUSBIrDADriver: xmit data"},
127
128    {kLogAddRxBytes,    "AppleUSBIrDADriver: add rx bytes, count="},
129    {kLogSetBofCount,   "AppleUSBIrDADriver: set bof count, input="},
130    {kLogGetIrDAStatus, "AppleUSBIrDADriver: get irda status, on="},
131
132    {kLogSetIrDAState,          "AppleUSBIrDADriver: set irda state, current=, want="},
133    {kLogInterruptRead,         "AppleUSBIrDADriver: interrupt read complete"},
134    {kLogDataReadComplete,      "AppleUSBIrDADriver: data read complete, rc, len="},
135
136    {kLogInputData,             "AppleUSBIrDADriver: data read buffer"},
137    {kLogDataWriteComplete,     "AppleUSBIrDADriver: data write complete, rc, len="},
138    {kLogDataWriteCompleteZero, "AppleUSBIrDADriver: data write complete sending zero length packet"},
139
140    {kLogAllocateResources,     "AppleUSBIrDADriver: allocate resources"},
141    {kLogReleaseResources,      "AppleUSBIrDADriver: release resources"},
142    {kLogConfigureDevice,       "AppleUSBIrDADriver: configure device"},
143    {kLogCreateSerialStream,    "AppleUSBIrDADriver: create serial stream"},
144
145    {kLogAcquirePort,       "AppleUSBIrDADriver: acquire port"},
146    {kLogReleasePort,       "AppleUSBIrDADriver: release port"},
147    {kLogSetState,          "AppleUSBIrDADriver: set state"},
148    {kLogWatchState,        "AppleUSBIrDADriver: watch state"},
149
150    {kLogExecEvent,         "AppleUSBIrDADriver: execute event"},
151    {kLogExecEventData,     "AppleUSBIrDADriver: execute event, data="},
152    {kLogReqEvent,          "AppleUSBIrDADriver: request event"},
153    {kLogReqEventData,      "AppleUSBIrDADriver: request event, data="},
154
155    {kLogSetupTransmit,         "AppleUSBIrDADriver: setup transmit"},
156    {kLogSetStructureDefaults,  "AppleUSBIrDADriver: set structure defaults"},
157    {kLogMessage,               "AppleUSBIrDADriver: message"},
158
159    {kLogWorkAround,            "AppleUSBIrDADriver: workaround called"},
160    {kLogWorkAroundComplete,    "AppleUSBIrDADriver: workaround complete"},
161
162    {kLogInitForPM,             "AppleUSBIrDADriver: init power management"},
163    {kLogInitialPowerState,     "AppleUSBIrDADriver: get initial power state, flags="},
164    {kLogSetPowerState,         "AppleUSBIrDADriver: set power state, ordinal="}
165
166};
167
168
169#define XTRACE(x, y, z) IrDALogAdd ( x, y, ((uintptr_t)z & 0xffff), gTraceEvents, true)
170#else
171#define XTRACE(x, y, z) ((void)0)
172#endif
173
174
175enum {
176    kUseInterruptsForRead   = true
177};
178
179enum {
180    kIrDAPowerOffState  = 0,
181    kIrDAPowerOnState   = 1,
182    kNumIrDAStates = 2
183};
184
185static IOPMPowerState gOurPowerStates[kNumIrDAStates] = {
186    {1,0,0,0,0,0,0,0,0,0,0,0},
187    {1,IOPMDeviceUsable,IOPMPowerOn,IOPMPowerOn,0,0,0,0,0,0,0,0}
188};
189
190
191    static IrDAglobals      g;  /**** Instantiate the globals ****/
192
193#define super IOSerialDriverSync
194
195    OSDefineMetaClassAndStructors( AppleUSBIrDADriver, IOSerialDriverSync );
196
197/****************************************************************************************************/
198//
199//      Function:   Asciify
200//
201//      Inputs:     i - the nibble
202//
203//      Outputs:    return byte - ascii byte
204//
205//      Desc:       Converts to ascii.
206//
207/****************************************************************************************************/
208
209static UInt8 Asciify(UInt8 i)
210{
211
212    i &= 0xF;
213    if ( i < 10 )
214	 return( '0' + i );
215    else return( 55  + i );
216
217}/* end Asciify */
218
219#if USE_ELG
220/****************************************************************************************************/
221//
222//      Function:   AllocateEventLog
223//
224//      Inputs:     size - amount of memory to allocate
225//
226//      Outputs:    None
227//
228//      Desc:       Allocates the event log buffer
229//
230/****************************************************************************************************/
231
232void AllocateEventLog( UInt32 size )
233{
234    if ( g.evLogBuf )
235	return;
236
237    g.evLogFlag = 0;            /* assume insufficient memory   */
238    g.evLogBuf = (UInt8*)IOMalloc( size );
239    if ( !g.evLogBuf )
240    {
241	kprintf( "AppleUSBIrDA: evLog allocation failed" );
242	return;
243    }
244
245    bzero( g.evLogBuf, size );
246    g.evLogBufp = g.evLogBuf;
247    g.evLogBufe = g.evLogBufp + kEvLogSize - 0x20; // ??? overran buffer?
248    g.evLogFlag  = 0xFEEDBEEF;  // continuous wraparound
249//  g.evLogFlag  = 'step';      // stop at each ELG
250//  g.evLogFlag  = 0x0333;      // any nonzero - don't wrap - stop logging at buffer end
251
252    IOLog( "AppleUSBIrDA: AllocateEventLog - &USBglobals=%p buffer=%p", &g, (uintptr_t)g.evLogBuf );
253
254    return;
255
256}/* end AllocateEventLog */
257
258/****************************************************************************************************/
259//
260//      Function:   EvLog
261//
262//      Inputs:     a - anything, b - anything, ascii - 4 charater tag, str - any info string
263//
264//      Outputs:    None
265//
266//      Desc:       Writes the various inputs to the event log buffer
267//
268/****************************************************************************************************/
269
270void EvLog( UInt32 a, UInt32 b, UInt32 ascii, char* str )
271{
272    register UInt32     *lp;           /* Long pointer      */
273    mach_timespec_t     time;
274
275    if ( g.evLogFlag == 0 )
276	return;
277
278    IOGetTime( &time );
279
280    lp = (UInt32*)g.evLogBufp;
281    g.evLogBufp += 0x10;
282
283    if ( g.evLogBufp >= g.evLogBufe )       /* handle buffer wrap around if any */
284    {    g.evLogBufp  = g.evLogBuf;
285	if ( g.evLogFlag != 0xFEEDBEEF )    // make 0xFEEDBEEF a symbolic ???
286	    g.evLogFlag = 0;                /* stop tracing if wrap undesired   */
287    }
288
289	/* compose interrupt level with 3 byte time stamp:  */
290
291    *lp++ = (g.intLevel << 24) | ((time.tv_nsec >> 10) & 0x003FFFFF);   // ~ 1 microsec resolution
292    *lp++ = a;
293    *lp++ = b;
294    *lp   = ascii;
295
296    if( g.evLogFlag == 'step' )
297    {   static char code[ 5 ] = {0,0,0,0,0};
298	*(UInt32*)&code = ascii;
299	IOLog( "AppleUSBIrDA: %8x %8x %8x %s\n", time.tv_nsec>>10, (unsigned int)a, (unsigned int)b, code );
300    }
301
302    return;
303
304}/* end EvLog */
305#endif // USE_ELG
306
307#if LOG_DATA
308#define dumplen     32      // Set this to the number of bytes to dump and the rest should work out correct
309
310#define buflen      ((dumplen*2)+dumplen)+3
311#define Asciistart  (dumplen*2)+3
312
313/****************************************************************************************************/
314//
315//      Function:   DEVLogData
316//
317//      Inputs:     Dir - direction, Count - number of bytes, buf - the data
318//
319//      Outputs:    None
320//
321//      Desc:       Puts the data in the log.
322//
323/****************************************************************************************************/
324
325void DEVLogData(UInt8 Dir, UInt32 Count, char *buf)
326{
327    UInt8       wlen, i, Aspnt, Hxpnt;
328    UInt8       wchr;
329    char        LocBuf[buflen+1];
330
331    for ( i=0; i<=buflen; i++ )
332    {
333	LocBuf[i] = 0x20;
334    }
335    LocBuf[i] = 0x00;
336
337    if ( Dir == kUSBIn )
338    {
339	IOLog( "AppleUSBIrDA: USBLogData - Received, size = %8lx\n", (long unsigned int)Count );
340    } else {
341	if ( Dir == kUSBOut )
342	{
343	    IOLog( "AppleUSBIrDA: USBLogData - Write, size = %8lx\n", (long unsigned int)Count );
344	} else {
345	    if ( Dir == kUSBAnyDirn )
346	    {
347		IOLog( "AppleUSBIrDA: USBLogData - Other, size = %8lx\n", (long unsigned int)Count );
348	    }
349	}
350    }
351
352    if ( Count > dumplen )
353    {
354	wlen = dumplen;
355    } else {
356	wlen = Count;
357    }
358
359    if ( wlen > 0 )
360    {
361	Aspnt = Asciistart;
362	Hxpnt = 0;
363	for ( i=1; i<=wlen; i++ )
364	{
365	    wchr = buf[i-1];
366	    LocBuf[Hxpnt++] = Asciify( wchr >> 4 );
367	    LocBuf[Hxpnt++] = Asciify( wchr );
368	    if (( wchr < 0x20) || (wchr > 0x7F ))       // Non printable characters
369	    {
370		LocBuf[Aspnt++] = 0x2E;                 // Replace with a period
371	    } else {
372		LocBuf[Aspnt++] = wchr;
373	    }
374	}
375	LocBuf[(wlen + Asciistart) + 1] = 0x00;
376	IOLog( "%s\n", LocBuf );
377    } else {
378	IOLog( "AppleUSBIrDA: USBLogData - No data, Count = 0\n" );
379    }
380
381}/* end DEVLogData */
382#endif // LOG_DATA
383
384/* QueuePrimatives  */
385
386/****************************************************************************************************/
387//
388//      Method:     AppleUSBIrDADriver::AddBytetoQueue
389//
390//      Inputs:     Queue - the queue to be added to
391//
392//      Outputs:    Value - Byte to be added, Queue status - full or no error
393//
394//      Desc:       Add a byte to the circular queue.
395//
396/****************************************************************************************************/
397
398QueueStatus AppleUSBIrDADriver::AddBytetoQueue( CirQueue *Queue, char Value )
399{
400    /* Check to see if there is space by comparing the next pointer,    */
401    /* with the last, If they match we are either Empty or full, so     */
402    /* check the InQueue of being zero.                 */
403
404    require(fPort && fPort->serialRequestLock, Fail);
405    IOLockLock( fPort->serialRequestLock );
406
407    if ( (Queue->NextChar == Queue->LastChar) && Queue->InQueue ) {
408	IOLockUnlock( fPort->serialRequestLock);
409	return queueFull;
410    }
411
412    *Queue->NextChar++ = Value;
413    Queue->InQueue++;
414
415	/* Check to see if we need to wrap the pointer. */
416
417    if ( Queue->NextChar >= Queue->End )
418	Queue->NextChar =  Queue->Start;
419
420    IOLockUnlock( fPort->serialRequestLock);
421    return queueNoError;
422
423Fail:
424    return queueFull;       // for lack of a better error
425
426}/* end AddBytetoQueue */
427
428/****************************************************************************************************/
429//
430//      Method:     AppleUSBIrDADriver::GetBytetoQueue
431//
432//      Inputs:     Queue - the queue to be removed from
433//
434//      Outputs:    Value - where to put the byte, Queue status - empty or no error
435//
436//      Desc:       Remove a byte from the circular queue.
437//
438/****************************************************************************************************/
439
440QueueStatus AppleUSBIrDADriver::GetBytetoQueue( CirQueue *Queue, UInt8 *Value )
441{
442
443    require(fPort && fPort->serialRequestLock, Fail);
444    IOLockLock( fPort->serialRequestLock );
445
446	/* Check to see if the queue has something in it.   */
447
448    if ( (Queue->NextChar == Queue->LastChar) && !Queue->InQueue ) {
449	IOLockUnlock(fPort->serialRequestLock);
450	return queueEmpty;
451    }
452
453    *Value = *Queue->LastChar++;
454    Queue->InQueue--;
455
456	/* Check to see if we need to wrap the pointer. */
457
458    if ( Queue->LastChar >= Queue->End )
459	Queue->LastChar =  Queue->Start;
460
461    IOLockUnlock(fPort->serialRequestLock);
462    return queueNoError;
463
464Fail:
465    return queueEmpty;          // can't get to it, pretend it's empty
466
467}/* end GetBytetoQueue */
468
469/****************************************************************************************************/
470//
471//      Method:     AppleUSBIrDADriver::InitQueue
472//
473//      Inputs:     Queue - the queue to be initialized, Buffer - the buffer, size - length of buffer
474//
475//      Outputs:    Queue status - queueNoError.
476//
477//      Desc:       Pass a buffer of memory and this routine will set up the internal data structures.
478//
479/****************************************************************************************************/
480
481QueueStatus AppleUSBIrDADriver::InitQueue( CirQueue *Queue, UInt8 *Buffer, size_t Size )
482{
483    Queue->Start    = Buffer;
484    Queue->End      = (UInt8*)((size_t)Buffer + Size);
485    Queue->Size     = Size;
486    Queue->NextChar = Buffer;
487    Queue->LastChar = Buffer;
488    Queue->InQueue  = 0;
489
490    IOSleep( 1 );
491
492    return queueNoError ;
493
494}/* end InitQueue */
495
496/****************************************************************************************************/
497//
498//      Method:     AppleUSBIrDADriver::CloseQueue
499//
500//      Inputs:     Queue - the queue to be closed
501//
502//      Outputs:    Queue status - queueNoError.
503//
504//      Desc:       Clear out all of the data structures.
505//
506/****************************************************************************************************/
507
508QueueStatus AppleUSBIrDADriver::CloseQueue( CirQueue *Queue )
509{
510
511    Queue->Start    = 0;
512    Queue->End      = 0;
513    Queue->NextChar = 0;
514    Queue->LastChar = 0;
515    Queue->Size     = 0;
516
517    return queueNoError;
518
519}/* end CloseQueue */
520
521/****************************************************************************************************/
522//
523//      Method:     AppleUSBIrDADriver::AddtoQueue
524//
525//      Inputs:     Queue - the queue to be added to, Buffer - data to add, Size - length of data
526//
527//      Outputs:    BytesWritten - Number of bytes actually put in the queue.
528//
529//      Desc:       Add an entire buffer to the queue.
530//
531/****************************************************************************************************/
532
533size_t AppleUSBIrDADriver::AddtoQueue( CirQueue *Queue, UInt8 *Buffer, size_t Size )
534{
535    size_t      BytesWritten = 0;
536
537    while ( FreeSpaceinQueue( Queue ) && (Size > BytesWritten) )
538    {
539	AddBytetoQueue( Queue, *Buffer++ );
540	BytesWritten++;
541    }
542
543    return BytesWritten;
544
545}/* end AddtoQueue */
546
547/****************************************************************************************************/
548//
549//      Method:     AppleUSBIrDADriver::RemovefromQueue
550//
551//      Inputs:     Queue - the queue to be removed from, Size - size of buffer
552//
553//      Outputs:    Buffer - Where to put the data, BytesReceived - Number of bytes actually put in Buffer.
554//
555//      Desc:       Get a buffers worth of data from the queue.
556//
557/****************************************************************************************************/
558
559size_t AppleUSBIrDADriver::RemovefromQueue( CirQueue *Queue, UInt8 *Buffer, size_t MaxSize )
560{
561    size_t      BytesReceived = 0;
562    UInt8       Value;
563
564    while( (MaxSize > BytesReceived) && (GetBytetoQueue(Queue, &Value) == queueNoError) )
565    {
566	*Buffer++ = Value;
567	BytesReceived++;
568    }/* end while */
569
570    return BytesReceived;
571
572}/* end RemovefromQueue */
573
574/****************************************************************************************************/
575//
576//      Method:     AppleUSBIrDADriver::FreeSpaceinQueue
577//
578//      Inputs:     Queue - the queue to be queried
579//
580//      Outputs:    Return Value - Free space left
581//
582//      Desc:       Return the amount of free space left in this buffer.
583//
584/****************************************************************************************************/
585
586size_t AppleUSBIrDADriver::FreeSpaceinQueue( CirQueue *Queue )
587{
588    size_t  retVal = 0;
589
590    require(fPort && fPort->serialRequestLock, Fail);
591    IOLockLock( fPort->serialRequestLock );
592
593    retVal = Queue->Size - Queue->InQueue;
594
595    IOLockUnlock(fPort->serialRequestLock);
596
597Fail:
598    return retVal;
599
600}/* end FreeSpaceinQueue */
601
602/****************************************************************************************************/
603//
604//      Method:     AppleUSBIrDADriver::UsedSpaceinQueue
605//
606//      Inputs:     Queue - the queue to be queried
607//
608//      Outputs:    UsedSpace - Amount of data in buffer
609//
610//      Desc:       Return the amount of data in this buffer.
611//
612/****************************************************************************************************/
613
614size_t AppleUSBIrDADriver::UsedSpaceinQueue( CirQueue *Queue )
615{
616    return Queue->InQueue;
617
618}/* end UsedSpaceinQueue */
619
620/****************************************************************************************************/
621//
622//      Method:     AppleUSBIrDADriver::GetQueueSize
623//
624//      Inputs:     Queue - the queue to be queried
625//
626//      Outputs:    QueueSize - The size of the queue.
627//
628//      Desc:       Return the total size of the queue.
629//
630/****************************************************************************************************/
631
632size_t AppleUSBIrDADriver::GetQueueSize( CirQueue *Queue )
633{
634    return Queue->Size;
635
636}/* end GetQueueSize */
637
638/****************************************************************************************************/
639//
640//      Method:     AppleUSBIrDADriver::GetQueueStatus
641//
642//      Inputs:     Queue - the queue to be queried
643//
644//      Outputs:    Queue status - full, empty or no error
645//
646//      Desc:       Returns the status of the circular queue.
647//
648/****************************************************************************************************/
649/*
650QueueStatus AppleUSBIrDADriver::GetQueueStatus( CirQueue *Queue )
651{
652    if ( (Queue->NextChar == Queue->LastChar) && Queue->InQueue )
653	return queueFull;
654    else if ( (Queue->NextChar == Queue->LastChar) && !Queue->InQueue )
655	return queueEmpty;
656
657    return queueNoError ;
658
659}*/ /* end GetQueueStatus */
660
661/****************************************************************************************************/
662//
663//      Method:     AppleUSBIrDADriver::CheckQueues
664//
665//      Inputs:     port - the port to check
666//
667//      Outputs:    None
668//
669//      Desc:       Checks the various queue's etc and manipulates the state(s) accordingly
670//
671/****************************************************************************************************/
672
673void AppleUSBIrDADriver::CheckQueues( PortInfo_t *port )
674{
675    unsigned long   Used;
676    unsigned long   Free;
677    unsigned long   QueuingState;
678    unsigned long   DeltaState;
679
680    // Initialise the QueueState with the current state.
681    QueuingState = readPortState( port );
682
683	/* Check to see if there is anything in the Transmit buffer. */
684    Used = UsedSpaceinQueue( &port->TX );
685    Free = FreeSpaceinQueue( &port->TX );
686//  ELG( Free, Used, 'CkQs', "CheckQueues" );
687    if ( Free == 0 )
688    {
689	QueuingState |=  PD_S_TXQ_FULL;
690	QueuingState &= ~PD_S_TXQ_EMPTY;
691    }
692    else if ( Used == 0 )
693    {
694	QueuingState &= ~PD_S_TXQ_FULL;
695	QueuingState |=  PD_S_TXQ_EMPTY;
696    }
697    else
698    {
699	QueuingState &= ~PD_S_TXQ_FULL;
700	QueuingState &= ~PD_S_TXQ_EMPTY;
701    }
702
703	/* Check to see if we are below the low water mark. */
704    if ( Used < port->TXStats.LowWater )
705	 QueuingState |=  PD_S_TXQ_LOW_WATER;
706    else QueuingState &= ~PD_S_TXQ_LOW_WATER;
707
708    if ( Used > port->TXStats.HighWater )
709	 QueuingState |= PD_S_TXQ_HIGH_WATER;
710    else QueuingState &= ~PD_S_TXQ_HIGH_WATER;
711
712
713	/* Check to see if there is anything in the Receive buffer. */
714    Used = UsedSpaceinQueue( &port->RX );
715    Free = FreeSpaceinQueue( &port->RX );
716
717    if ( Free == 0 )
718    {
719	QueuingState |= PD_S_RXQ_FULL;
720	QueuingState &= ~PD_S_RXQ_EMPTY;
721    }
722    else if ( Used == 0 )
723    {
724	QueuingState &= ~PD_S_RXQ_FULL;
725	QueuingState |= PD_S_RXQ_EMPTY;
726    }
727    else
728    {
729	QueuingState &= ~PD_S_RXQ_FULL;
730	QueuingState &= ~PD_S_RXQ_EMPTY;
731    }
732
733	/* Check to see if we are below the low water mark. */
734    if ( Used < port->RXStats.LowWater )
735	 QueuingState |= PD_S_RXQ_LOW_WATER;
736    else QueuingState &= ~PD_S_RXQ_LOW_WATER;
737
738    if ( Used > port->RXStats.HighWater )
739	 QueuingState |= PD_S_RXQ_HIGH_WATER;
740    else QueuingState &= ~PD_S_RXQ_HIGH_WATER;
741
742	/* Figure out what has changed to get mask.*/
743    DeltaState = QueuingState ^ readPortState( port );
744    changeState( port, QueuingState, DeltaState );
745
746    return;
747
748}/* end CheckQueues */
749
750/* end of QueuePrimatives */
751
752/****************************************************************************************************/
753//
754//      Method:     AppleUSBIrDADriver::Add_RXBytes
755//
756//      Inputs:     Buffer - the raw input data, Size - the length
757//
758//      Outputs:
759//
760//      Desc:       Adds data to the circular receive queue
761//
762/****************************************************************************************************/
763
764void AppleUSBIrDADriver::Add_RXBytes( UInt8 *Buffer, size_t Size )
765{
766    XTRACE(kLogAddRxBytes, 0, Size);
767    ELG( 0, Size, 'AdRB', "Add_RXBytes" );
768
769    AddtoQueue( &fPort->RX, Buffer, Size );
770    CheckQueues( fPort );
771}/* end Add_RXBytes */
772
773/****************************************************************************************************/
774//
775//      Method:     AppleUSBIrDADriver::SetBofCount
776//
777//      Inputs:     bof_count - the requested number of Beginning Of Frames
778//
779//      Outputs:    return word - the actual count (not bofs)
780//
781//      Desc:       Encode the requested number of BOF bytes to the first value that's big enough
782//
783/****************************************************************************************************/
784
785SInt16 AppleUSBIrDADriver::SetBofCount( SInt16 bof_count )
786{
787    SInt16 counts[] = { 0, 1, 2, 3, 6, 12, 24, 48, -1};     // the bof counts that are encoded below
788    SInt16  codes[] = { 8, 7, 6, 5, 4,  3,  2,  1,  1};     // could use an f(i), but this is easier to match to spec
789    int i, sz;
790
791    ELG( 0, bof_count, 'Sbof', "SetBofCount" );
792    XTRACE(kLogSetBofCount, 0, bof_count);
793
794    // input is desired bof count at the current speed, but the usb hardware wants the
795    // unadjusted bof count (i.e. xbofs at 115k bps), so we have to adjust back to 115k.
796
797    if (fCurrentBaud < 115200) {
798	bof_count = bof_count * (115200 / fCurrentBaud);
799	XTRACE(kLogSetBofCount, 1, bof_count);
800    }
801
802    sz = sizeof(counts) / sizeof(counts[0]);
803
804    // note that the input bof counts can be computed, so we do an 'at least' test instead
805    // of insisting upon an exact match to one of the supported bof counts.
806
807    for (i = 0 ; i < sz; i++)
808    {
809	if (counts[i] >= bof_count || counts[i] < 0)        // if table entry at least what's wanted (no smaller), or end-of-table
810	{
811	    fBofsCode = codes[i];                           // then save the encoded version
812	    return counts[i];                               // and return raw count used to caller
813	}
814    }
815
816    ELG( 0, i, 'Sbf-', "SetBofCount - logic error" );
817    return 0;
818}/* end SetBofCount */
819
820/****************************************************************************************************/
821//
822//      Method:     AppleUSBIrDADriver::SetSpeed
823//
824//      Inputs:     brate - the requested baud rate
825//
826//      Outputs:    return word - baud coding
827//
828//      Desc:       Set the baudrate for the device
829//
830/****************************************************************************************************/
831
832UInt16 AppleUSBIrDADriver::SetSpeed( UInt32 brate )
833{
834    XTRACE(kLogSetSpeed, brate >> 16, (short)brate);
835    ELG( 0, brate, 'Sbof', "SetSpeed" );
836
837    fCurrentBaud = brate;
838
839    switch (brate)
840    {
841	case 2400:
842	    fBaudCode = kLinkSpeed2400;     // 0x01
843	    break;
844
845	case 9600:
846	    fBaudCode = kLinkSpeed9600;     // 0x02
847	    break;
848
849	case 19200:
850	    fBaudCode = kLinkSpeed19200;    // 0x03
851	    break;
852
853	case 38400:
854	    fBaudCode = kLinkSpeed38400;    // 0x04
855	    break;
856
857	case 57600:
858	    fBaudCode = kLinkSpeed57600;    // 0x05
859	    break;
860
861	case 115200:
862	    fBaudCode = kLinkSpeed115200;   // 0x06
863	    break;
864
865	case 576000:
866	    fBaudCode = kLinkSpeed576000;   // 0x07
867	    break;
868
869	case 1152000:
870	    fBaudCode = kLinkSpeed1152000;  // 0x08
871	    break;
872
873	case 4000000:
874	    fBaudCode = kLinkSpeed4000000;  // 0x09
875	    break;
876
877	case 300:
878	case 600:
879	case 1200:
880	case 1800:
881	case 3600:
882	case 4800:
883	case 7200:
884	default:
885	    ELG( 0, brate, 'SSp-', "SetSpeed - Unsupported baud rate");
886	    fBaudCode = 0;
887	    break;
888    }
889
890    // start a one-byte transmit to set the speed in the device
891    StartTransmit(0, NULL, 0, NULL);            // no control or data bytes, just the mode byte please
892						// note SetSpeedComplete is called out of transmit complete
893    return fBaudCode;
894}/* end SetSpeed */
895
896/****************************************************************************************************/
897//
898//      Method:     AppleUSBIrDADriver::GetIrDAComm
899//
900//      Inputs:
901//
902//      Outputs:    IrDAComm - Address of the IrDA object
903//
904//      Desc:       Returns the address of the IrDA object
905//
906/****************************************************************************************************/
907
908IrDAComm* AppleUSBIrDADriver::GetIrDAComm( void )
909{
910    return fIrDA;
911}/* end GetIrDAComm */
912
913/****************************************************************************************************/
914//
915//      Method:     AppleUSBIrDADriver::GetIrDAQoS
916//
917//      Inputs:
918//
919//      Outputs:    USBIrDAQoS - Address of the QoS structure
920//
921//      Desc:       Returns the address of the Quality of Service structure
922//
923/****************************************************************************************************/
924
925USBIrDAQoS* AppleUSBIrDADriver::GetIrDAQoS( void )
926{
927    return &fQoS;
928}/* end GetIrDAQoS */
929
930/****************************************************************************************************/
931//
932//      Method:     AppleUSBIrDADriver::GetIrDAStatus
933//
934//      Inputs:     status - status structure
935//
936//      Outputs:
937//
938//      Desc:       Sets the connection state and CRC errors of the status structure
939//
940/****************************************************************************************************/
941
942void AppleUSBIrDADriver::GetIrDAStatus( IrDAStatus *status )
943{
944    //int review_get_irda_status;     // check w/irda on/off logic
945
946    ELG( 0, 0, 'GIrS', "GetIrDAStatus" );
947    XTRACE(kLogGetIrDAStatus, 0, fIrDAOn);
948
949    if ( !fIrDAOn )
950    {
951	    //bzero( status, sizeof(IrDAStatus) );
952	    status->connectionState = kIrDAStatusOff;
953    } else {
954	    if ( status->connectionState == kIrDAStatusOff )
955	    {
956		status->connectionState = kIrDAStatusIdle;
957	    }
958	    status->crcErrors = 0;                  // Unavailable
959	}
960
961}/* end GetIrDAStatus */
962
963/****************************************************************************************************/
964//
965//      Method:     AppleUSBIrDADriver::CheckIrDAState
966//
967//      Inputs:     open session count (fSessions)
968//                  user-client start request (fStartStopUserClient)
969//                  usb start/stop (fStartStopUSB) -- replace with fTerminate?
970//
971//      Outputs:
972//
973//      Desc:       Turns IrDA on or off if appropriate
974//
975/****************************************************************************************************/
976
977IOReturn AppleUSBIrDADriver::CheckIrDAState( void )
978{
979    IOReturn    ior = kIOReturnSuccess;
980    Boolean     newState = fUSBStarted &    // usb must have started, and
981			(fPowerState == kIrDAPowerOnState) &&   // powered on by the power manager, and
982			(fUserClientStarted | (fSessions > 0)); // one of the clients too
983
984    ELG( 0, 0, 'SIrS', "CheckIrDAState" );
985    XTRACE(kLogSetIrDAState, fIrDAOn, newState);
986
987    if ( newState && !fIrDAOn )         // Turn IrDA on if needed
988    {
989	fIrDAOn = true;
990	fTerminate = false;
991
992	if (!fSuspendFail) {            // if previous suspend worked, then
993					// resume it and startIrDA will run from message().
994	    ior = fpDevice->SuspendDevice( false );     // Ask to resume the device
995	    if ( ior != kIOReturnSuccess )
996	    {
997		ELG( 0, ior, 'SIR-', "SetIrDAState - Resume failed" );
998		IOLog("AppleUSBIrDA: failed to resume device\n");
999		fIrDAOn = false;            // We're basically dead at this point
1000		fTerminate = true;
1001	    }
1002	}
1003	else{                   // earlier suspend failed, just start irda here
1004	    if ( !startIrDA() )
1005	    {
1006		fIrDAOn = false;
1007		fTerminate = true;
1008		IOLog("AppleUSBIrDADriver: SetIrDAState - startIrDA failed" );
1009	    } else {
1010		ELG( 0, 0, 'msc+', "SetIrDAState - startIrDA successful" );
1011		//IOLog("AppleUSBIrDADriver: message - startIrDA successful\n" );
1012	    }
1013	}
1014    }
1015    else if (!newState && fIrDAOn)      // Turn IrDA off if needed
1016    {
1017	fIrDAOn = false;
1018	fTerminate = true;              // Make it look like we've been terminated
1019
1020	stopIrDA();                     // stop irda and stop pipe i/o
1021
1022	ior = fpDevice->SuspendDevice( true );  // Try to suspend the device
1023	if ( ior != kIOReturnSuccess )
1024	{
1025	    ELG( 0, 0, 'SIS-', "SetIrDAState - Suspend failed" );
1026	    IOLog("AppleUSBIrDA: failed to suspend device\n");
1027	}
1028    }
1029
1030    return ior;
1031}/* end CheckIrDAState */
1032
1033//
1034// User client has asked to start/stop irda.  do it if
1035// it's ok w/bsd open count and usb start/stop flag.
1036//
1037IOReturn AppleUSBIrDADriver::SetIrDAUserClientState( bool IrDAOn )
1038{
1039    fUserClientStarted = IrDAOn;
1040    return CheckIrDAState();
1041}
1042
1043/****************************************************************************************************/
1044//
1045//      Function:   AppleUSBIrDADriver::init
1046//
1047//      Inputs:     dict - Dictionary
1048//
1049//      Outputs:    Return code - from super::init
1050//
1051//      Desc:       Driver initialization
1052//
1053/****************************************************************************************************/
1054
1055bool AppleUSBIrDADriver::init( OSDictionary *dict )
1056{
1057    bool    rc;
1058
1059    rc = super::init( dict );
1060    IOLogIt( (uintptr_t)IrDALogGetInfo(), rc, 'init', "init" );
1061    XTRACE(kLogInit, 0, rc);
1062    return rc;
1063
1064}/* end init */
1065
1066/****************************************************************************************************/
1067//
1068//      Function:   AppleUSBIrDADriver::probe
1069//
1070//      Inputs:     provider - my provider
1071//
1072//      Outputs:    IOService - from super::probe, score - probe score
1073//
1074//      Desc:       Modify the probe score if necessary (we don't  at the moment)
1075//
1076/****************************************************************************************************/
1077
1078IOService* AppleUSBIrDADriver::probe( IOService *provider, SInt32 *score )
1079{
1080    IOService       *res;
1081
1082    res = super::probe( provider, score );
1083    IOLogIt( provider, res, 'prob', "probe" );
1084    XTRACE(kLogProbe, 0, provider);
1085    return res;
1086
1087}/* end probe */
1088
1089
1090/****************************************************************************************************/
1091//
1092//      Method:     AppleUSBIrDADriver::start
1093//
1094//      Inputs:     provider - my provider
1095//
1096//      Outputs:    Return code - true (it's me), false (sorry it probably was me, but I can't configure it)
1097//
1098//      Desc:       This is called once it has beed determined I'm probably the best
1099//                  driver for this device.
1100//
1101/****************************************************************************************************/
1102
1103bool AppleUSBIrDADriver::start( IOService *provider )
1104{
1105    UInt8   configs;    // number of device configurations
1106    bool    ok;
1107
1108    XTRACE(kLogStart, 0, provider);
1109
1110    g.evLogBufp = NULL;
1111
1112    fTerminate = false;     // Make sure we don't think we're being terminated
1113    fPort = NULL;
1114    fIrDA = NULL;
1115    fNub = NULL;
1116    fIrDAOn = false;
1117    fSuspendFail = false;
1118    fpInterface = NULL;
1119
1120    fpinterruptPipeBuffer = NULL;
1121    fPipeInBuffer = NULL;
1122    fPipeOutBuffer = NULL;
1123
1124    fpDevice = NULL;
1125    fpInPipe = NULL;
1126    fpOutPipe = NULL;
1127    fpInterruptPipe = NULL;
1128
1129    fUserClientStarted = false;     // user/client has not started us yet
1130    fUSBStarted = false;            // set to true when start finishes up ok
1131    fSessions = 0;
1132
1133    fReadActive = false;
1134
1135    fWriteActive = false;
1136
1137    fGate = IOCommandGate::commandGate(this, 0);    // create a new command gate for PM
1138    require(fGate, Fail);
1139    getWorkLoop()->addEventSource(fGate);           // add it to the usb workloop
1140
1141#if USE_ELG
1142    AllocateEventLog( kEvLogSize );
1143    ELG( &g, g.evLogBufp, 'USBM', "start - event logging set up." );
1144
1145    waitForService( resourceMatching( "kdp" ) );
1146#endif /* USE_ELG */
1147
1148    ELG( this, provider, 'strt', "start - this, provider." );
1149    if( !super::start( provider ) )
1150    {
1151	IOLogIt( 0, 0, 'SS--', "start - super failed" );
1152	return false;
1153    }
1154
1155    /* Get my USB provider - the interface and then get the device */
1156
1157    fpInterface = OSDynamicCast( IOUSBInterface, provider );
1158    require(fpInterface, Fail);
1159
1160    fpDevice = fpInterface->GetDevice();
1161    require(fpDevice, Fail);
1162
1163    /* Let's see if we have any configurations to play with */
1164
1165    configs = fpDevice->GetNumConfigurations();
1166    require(configs == 1, Fail);
1167
1168    // make our nub (and fPort) now
1169    ok = createNub();
1170    require(ok, Fail);
1171
1172    // Now configure it (leaves device suspended)
1173    ok = configureDevice(configs);
1174    require(ok, Fail);
1175
1176    // Finally create the bsd tty (serial stream) and leave it there until usb stop
1177
1178    ok = createSerialStream();
1179    require(ok, Fail);
1180
1181    ok = initForPM(provider);
1182    require(ok, Fail);
1183
1184    fUSBStarted = true;     // now pay attn to bsd open's and user client start-irda requests
1185
1186    return true;
1187
1188Fail:
1189
1190    IOLogIt( 0, 0, 'sts-', "start - failed" );
1191    stop( provider );
1192
1193    return false;
1194
1195}/* end start */
1196
1197//
1198// initForPM
1199//
1200// Add ourselves to the power management tree so we
1201// can do the right thing on sleep/wakeup.
1202//
1203bool AppleUSBIrDADriver::initForPM(IOService * provider)
1204{
1205    XTRACE(kLogInitForPM, 0, 0);
1206
1207    fPowerThreadCall = thread_call_allocate(handleSetPowerState, (thread_call_param_t) this );
1208    require(fPowerThreadCall != NULL, Fail);
1209
1210    fPowerState = kIrDAPowerOnState;        // init our power state to be 'on'
1211    PMinit();                               // init power manager instance variables
1212    provider->joinPMtree(this);             // add us to the power management tree
1213    require(pm_vars != NULL, Fail);
1214
1215    // register ourselves with ourself as policy-maker
1216    registerPowerDriver(this, gOurPowerStates, kNumIrDAStates);
1217    return true;
1218
1219Fail:
1220    return false;
1221}
1222
1223//
1224// request for our initial power state
1225//
1226unsigned long AppleUSBIrDADriver::initialPowerStateForDomainState ( IOPMPowerFlags flags)
1227{
1228    XTRACE(kLogInitialPowerState, flags >> 16, (short)flags);
1229    return fPowerState;
1230}
1231
1232//
1233// request to turn device on or off.  since PM doesn't call us on our workloop, we'll
1234// get it going on another thead and wait for it.
1235//
1236IOReturn AppleUSBIrDADriver::setPowerState(unsigned long powerStateOrdinal, IOService * whatDevice)
1237{
1238    //UInt32 counter = 0;
1239
1240    if (powerStateOrdinal == fPowerState) return kIOPMAckImplied;
1241
1242    if (fPowerThreadCall) {
1243	bool ok;
1244
1245	retain();				// paranoia is your friend, make sure we're not freed
1246
1247	fWaitForGatedCmd = true;
1248	ok = thread_call_enter1(fPowerThreadCall, (void *)powerStateOrdinal);     // invoke handleSetPowerState
1249
1250	while (fWaitForGatedCmd) {		// wait for it now
1251	    IOSleep(1);				// cycles to gated thread
1252	    //counter++;
1253	}
1254
1255        if (ok) {                               // if thread was already pending ...
1256            release();                          // don't need/want the retain, so undo it
1257        }					// normally released below
1258    }
1259    //IOLog("irda setPowerState %d, waited %d ms\n", (int)powerStateOrdinal, (int)counter);
1260    return kIOPMAckImplied;
1261}
1262
1263// handleSetPowerState()
1264//
1265// param0 - the object
1266// param1 - new power state ordinal
1267//static
1268void AppleUSBIrDADriver::handleSetPowerState(thread_call_param_t param0, thread_call_param_t param1 )
1269{
1270    AppleUSBIrDADriver *self = OSDynamicCast(AppleUSBIrDADriver, (const OSMetaClassBase *)param0);
1271    uintptr_t powerStateOrdinal = (uintptr_t)param1;
1272
1273    if (self && self->fGate) {
1274	self->fGate->runAction(&(self->setPowerStateGated), (void *)powerStateOrdinal, (void *)0, (void *)0, (void *)0);
1275	self->release();		// offset the retain in setPowerState()
1276    }
1277}
1278
1279// could cast Action directly to setPowerStateGatedPrivate, but not w/out a compiler warning
1280// static
1281IOReturn AppleUSBIrDADriver::setPowerStateGated(OSObject *owner, void *arg0, void *arg1, void *arg2, void *arg3)
1282{
1283    AppleUSBIrDADriver *self = OSDynamicCast(AppleUSBIrDADriver, (const OSMetaClassBase *)owner);
1284    uintptr_t powerStateOrdinal = (uintptr_t)arg0;
1285
1286    if (self) return self->setPowerStateGatedPrivate(powerStateOrdinal);
1287    else return -1;
1288}
1289
1290//
1291// setPowerStateGatedPrivate - do the work of setPowerState, now that we are on the workloop
1292//
1293IOReturn AppleUSBIrDADriver::setPowerStateGatedPrivate(uintptr_t powerStateOrdinal)
1294{
1295    fPowerState = powerStateOrdinal;
1296    CheckIrDAState();
1297    fWaitForGatedCmd = false;	    // release caller (power thread)
1298    return kIOReturnSuccess;
1299}
1300
1301
1302/****************************************************************************************************/
1303//
1304//      Method:     AppleUSBIrDADriver::interruptReadComplete
1305//
1306//      Inputs:     obj - me, param - parameter block(the Port), rc - return code, remaining - what's left
1307//                                                                                  (whose idea was that?)
1308//
1309//      Outputs:    None
1310//
1311//      Desc:       Interrupt pipe read completion routine
1312//
1313/****************************************************************************************************/
1314
1315void AppleUSBIrDADriver::interruptReadComplete( void *obj, void *param, IOReturn rc, UInt32 remaining )
1316{
1317    AppleUSBIrDADriver  *me = (AppleUSBIrDADriver*)obj;
1318    //PortInfo_t            *port = (PortInfo_t*)param;
1319    IOReturn    ior;
1320    UInt32      dLen;
1321
1322    XTRACE(kLogInterruptRead, me->fpinterruptPipeBuffer[0], rc);
1323    if (me->fIrDAOn) {                  // if we're still "up" and haven't been turned off
1324	check(INTERRUPT_BUFF_SIZE - remaining == 1);
1325	check(me->fpinterruptPipeBuffer[0] == 1);
1326    }
1327
1328    if ( rc == kIOReturnSuccess )   /* If operation returned ok:    */
1329    {
1330	dLen = INTERRUPT_BUFF_SIZE - remaining;
1331	ELG( rc, dLen, 'iRC+', "interruptReadComplete" );
1332	XTRACE(kLogInterruptRead, 1, dLen);
1333
1334	    /* Now look at the data */
1335//      LogData( kUSBAnyDirn, dLen, me->fpinterruptPipeBuffer );
1336
1337	if (dLen != 1)
1338	{
1339	    XTRACE(kLogInterruptRead, 0xdead, 0xbeef);
1340	    ELG( 0, dLen, 'iRC-', "interruptReadComplete - what was that?" );
1341	} else {
1342
1343	    if (kUseInterruptsForRead) {            // We're using interrupts to trigger reads ...
1344		check(me->fReadActive == false);
1345		if (me->fReadActive == false) {
1346		    ior = me->fpInPipe->Read( me->fpPipeInMDP, &me->fReadCompletionInfo, NULL );    // start a read
1347		    if (ior != kIOReturnSuccess)
1348		    {
1349			ELG( 0, ior, 'icf-', "interrupt complete failed to start read");
1350		    } else {
1351			me->fReadActive = true;
1352		    }
1353		}
1354	    }
1355	}
1356
1357	    /* Queue the next interrupt read:   */
1358
1359	ior = me->fpInterruptPipe->Read( me->fpinterruptPipeMDP, &me->finterruptCompletionInfo, NULL );
1360	if ( ior == kIOReturnSuccess ) {
1361	    XTRACE(kLogInterruptRead, 0xffff, 0xffff);
1362	    return;
1363	}
1364    }
1365
1366	/* Read returned with error OR next interrupt read failed to be queued: */
1367
1368    XTRACE(kLogInterruptRead, 0xdead, 2);
1369    ELG( 0, rc, 'iRC-', "interruptReadComplete - error" );
1370
1371    return;
1372
1373}/* end interruptReadComplete */
1374
1375/****************************************************************************************************/
1376//
1377//      Method:     AppleUSBIrDADriver::dataReadComplete
1378//
1379//      Inputs:     obj - me, param - parameter block(the Port), rc - return code, remaining - what's left
1380//
1381//      Outputs:    None
1382//
1383//      Desc:       BulkIn pipe (Data interface) read completion routine
1384//
1385/****************************************************************************************************/
1386
1387void AppleUSBIrDADriver::dataReadComplete( void *obj, void *param, IOReturn rc, UInt32 remaining )
1388{
1389    AppleUSBIrDADriver  *me = (AppleUSBIrDADriver*)obj;
1390    PortInfo_t      *port = (PortInfo_t*)param;
1391    UInt16          dtlength;
1392    IOReturn        ior = kIOReturnSuccess;
1393
1394    XTRACE(kLogDataReadComplete, rc, USBLapPayLoad - remaining);
1395
1396#if (hasTracing > 0 && hasAppleUSBIrDATracing > 1)
1397    if (1) {
1398	int len = USBLapPayLoad - remaining;
1399	UInt32 w;
1400	UInt8 *b = me->fPipeInBuffer;
1401	int i;
1402
1403	while (len > 0) {
1404	    w = 0;
1405	    for (i = 0 ; i < 4; i++) {
1406		w = w << 8;
1407		if (len > 0)            // don't run off end (pad w/zeros)
1408		    w = w | *b;
1409		b++;
1410		len--;
1411	    }
1412	    XTRACE(kLogInputData, w >> 16, (short)w);
1413	}
1414    }
1415#endif  // tracing high
1416
1417    check(me->fReadActive == true);
1418
1419    if ( rc == kIOReturnSuccess )   /* If operation returned ok:    */
1420    {
1421	me->fReadActive = false;
1422	dtlength = USBLapPayLoad - remaining;
1423	ELG( port->State, dtlength, 'dRC+', "dataReadComplete" );
1424
1425//      LogData( kUSBIn, dtlength, me->fPipeInBuffer );
1426
1427	if ( dtlength > 1 )
1428	{
1429	    if ( me->fIrDA )
1430	    {
1431		ior = me->fIrDA->ReadComplete( &me->fPipeInBuffer[1], dtlength-1 );
1432	    }
1433	    if ( ior != kIOReturnSuccess )
1434	    {
1435		ELG( 0, ior, 'IrR-', "dataReadComplete - IrDA ReadComplete problem" );
1436	    }
1437	}
1438
1439	/* Queue the next read if not using interrupts */
1440
1441	if (kUseInterruptsForRead == false) {
1442
1443	    ior = me->fpInPipe->Read( me->fpPipeInMDP, &me->fReadCompletionInfo, NULL );
1444
1445	    if ( ior == kIOReturnSuccess )
1446	    {
1447		me->fReadActive = true;
1448		me->CheckQueues( port );
1449		return;
1450	    } else {
1451		ELG( 0, ior, 'DtQ-', "dataReadComplete - queueing bulk read failed" );
1452	    }
1453	}
1454    } else {
1455
1456	/* Read returned with error */
1457	ELG( 0, rc, 'DtR-', "dataReadComplete - io err" );
1458    }
1459
1460    return;
1461
1462}/* end dataReadComplete */
1463
1464/****************************************************************************************************/
1465//
1466//      Method:     AppleUSBIrDADriver::dataWriteComplete
1467//
1468//      Inputs:     obj - me, param - parameter block(the Port), rc - return code, remaining - what's left
1469//
1470//      Outputs:    None
1471//
1472//      Desc:       BulkOut pipe (Data interface) write completion routine
1473//
1474/****************************************************************************************************/
1475
1476void AppleUSBIrDADriver::dataWriteComplete( void *obj, void *param, IOReturn rc, UInt32 remaining )
1477{
1478    AppleUSBIrDADriver  *me = (AppleUSBIrDADriver*)obj;
1479    Boolean done = true;                // write really finished?
1480
1481    ELG( rc, (me->fCount - remaining), 'dWCt', "dataWriteComplete" );
1482    XTRACE(kLogDataWriteComplete, rc, me->fCount - remaining);
1483
1484    check(me->fWriteActive);
1485    me->fWriteActive = false;
1486
1487    // first check for speed change, it's the only time we do a single-byte write
1488    if (me->fCount == 1) {
1489	if (me->fIrDA)
1490	    me->fIrDA->SetSpeedComplete(rc == kIOReturnSuccess);
1491	return;
1492    }
1493
1494    // in a transmit complete, but need to manually transmit a zero-length packet
1495    // if it's a multiple of the max usb packet size for the bulk-out pipe (64 bytes)
1496    if ( rc == kIOReturnSuccess )   /* If operation returned ok:    */
1497    {
1498	if ( me->fCount > 0 )                       // Check if it was not a zero length write
1499	{
1500	    if ( (me->fCount % 64) == 0 )               // If was a multiple of 64 bytes then we need to do a zero length write
1501	    {
1502		XTRACE(kLogDataWriteCompleteZero, 0, 0);
1503		LogData( kUSBOut, 0, me->fPipeOutBuffer );
1504		me->fWriteActive = true;
1505		me->fpPipeOutMDP->setLength( 0 );
1506		me->fCount = 0;
1507		me->fpOutPipe->Write( me->fpPipeOutMDP, &me->fWriteCompletionInfo );
1508		done = false;               // don't complete back to irda quite yet
1509	    }
1510	}
1511    }
1512
1513    if (done && me->fIrDA )     // if time to let irda know the write has finished
1514    {
1515	me->fIrDA->Transmit_Complete( rc == kIOReturnSuccess ); // let IrDA know how write finished
1516    }
1517    return;
1518
1519}/* end dataWriteComplete */
1520
1521/****************************************************************************************************/
1522//
1523//      Method:     AppleUSBIrDADriver::free
1524//
1525//      Inputs:     None
1526//
1527//      Outputs:    None
1528//
1529//      Desc:       Clean up and free the log
1530//
1531/****************************************************************************************************/
1532
1533void AppleUSBIrDADriver::free()
1534{
1535    XTRACE(kLogFree, 0, 0);
1536    ELG( 0, 0, 'free', "free" );
1537
1538    if (fIrDA) {
1539	fIrDA->release();   // we don't do delete's in the kernal I suppose ...
1540	fIrDA=NULL;
1541    }
1542
1543    if (fPowerThreadCall) {
1544	thread_call_free(fPowerThreadCall);
1545	fPowerThreadCall = NULL;
1546    }
1547
1548    if (fGate) {
1549	IOWorkLoop *work =  getWorkLoop();
1550	if (work) work->removeEventSource(fGate);
1551	fGate->release();
1552	fGate = NULL;
1553    }
1554
1555
1556#if USE_ELG
1557    if ( g.evLogBuf )
1558	IOFree( g.evLogBuf, kEvLogSize );
1559#endif /* USE_ELG */
1560
1561    super::free();
1562
1563    XTRACE(kLogFree, 0xffff, 0xffff);
1564    return;
1565
1566}/* end free */
1567
1568/****************************************************************************************************/
1569//
1570//      Method:     AppleUSBIrDADriver::stop
1571//
1572//      Inputs:     provider - my provider
1573//
1574//      Outputs:    None
1575//
1576//      Desc:       Stops
1577//
1578/****************************************************************************************************/
1579
1580void AppleUSBIrDADriver::stop( IOService *provider )
1581{
1582    XTRACE(kLogStop, 0, provider);
1583    ELG( 0, 0, 'stop', "stop" );
1584
1585    fUSBStarted = false;        // reset usb start/stop flag for CheckIrDAState
1586    CheckIrDAState();           // turn irda off, release resources
1587
1588    destroySerialStream();      // release the bsd tty
1589
1590    destroyNub();               // delete the nubs and fPort
1591
1592    if ( fpInterface )
1593    {
1594	fpInterface->release();     // retain done in ConfigureDevice
1595	fpInterface = NULL;
1596    }
1597
1598    // release our power manager state
1599    PMstop();
1600
1601    super::stop( provider );
1602    XTRACE(kLogStop, 0xffff, 0xffff);
1603    return;
1604
1605}/* end stop */
1606
1607/****************************************************************************************************/
1608//
1609//      Method:     AppleUSBIrDADriver::allocateResources
1610//
1611//      Inputs:
1612//
1613//      Outputs:    return code - true (allocate was successful), false (it failed)
1614//
1615//      Desc:       Finishes up the rest of the configuration and gets all the endpoints open
1616//
1617/****************************************************************************************************/
1618
1619bool AppleUSBIrDADriver::allocateResources( void )
1620{
1621    IOUSBFindEndpointRequest    epReq;      // endPoint request struct on stack
1622    bool                        goodCall;   // return flag fm Interface call
1623
1624    ELG( 0, 0, 'Allo', "allocateResources." );
1625    XTRACE(kLogAllocateResources, 0, 0);
1626
1627    // Open all the end points
1628    require(fpInterface, Fail);
1629
1630    goodCall = fpInterface->open( this );       // close done in releaseResources
1631    if ( !goodCall )
1632    {
1633	ELG( 0, 0, 'epD-', "allocateResources - open data interface failed." );
1634	fpInterface->release();
1635	fpInterface = NULL;
1636	return false;
1637    }
1638
1639    fpInterfaceNumber = fpInterface->GetInterfaceNumber();
1640
1641    epReq.type          = kUSBBulk;
1642    epReq.direction     = kUSBIn;
1643    epReq.maxPacketSize = 0;
1644    epReq.interval      = 0;
1645    fpInPipe = fpInterface->FindNextPipe( 0, &epReq );
1646    require(fpInPipe, Fail);
1647    ELG( epReq.maxPacketSize << 16 |epReq.interval, fpInPipe, 'i P+', "allocateResources - bulk input pipe." );
1648
1649    epReq.direction = kUSBOut;
1650    fpOutPipe = fpInterface->FindNextPipe( 0, &epReq );
1651    require(fpOutPipe, Fail);
1652    ELG( epReq.maxPacketSize << 16 |epReq.interval, fpOutPipe, 'o P+', "allocateResources - bulk output pipe." );
1653
1654    epReq.type          = kUSBInterrupt;
1655    epReq.direction     = kUSBIn;
1656    fpInterruptPipe = fpInterface->FindNextPipe( 0, &epReq );
1657    require(fpInterruptPipe, Fail);
1658    ELG( epReq.maxPacketSize << 16 |epReq.interval, fpInterruptPipe, 'irP+', "allocateResources - interrupt pipe." );
1659
1660    // Allocate Memory Descriptor Pointer with memory for the interrupt-in pipe:
1661
1662    fpinterruptPipeMDP = IOBufferMemoryDescriptor::withCapacity( INTERRUPT_BUFF_SIZE, kIODirectionIn );
1663    require(fpinterruptPipeMDP, Fail);
1664
1665    fpinterruptPipeMDP->setLength( INTERRUPT_BUFF_SIZE );
1666    fpinterruptPipeBuffer = (UInt8*)fpinterruptPipeMDP->getBytesNoCopy();
1667    ELG( 0, fpinterruptPipeBuffer, 'iBuf', "allocateResources - interrupt in buffer" );
1668
1669    // Allocate Memory Descriptor Pointer with memory for the data-in bulk pipe:
1670
1671    fpPipeInMDP = IOBufferMemoryDescriptor::withCapacity( USBLapPayLoad, kIODirectionIn );
1672    require(fpPipeInMDP, Fail);
1673
1674    fpPipeInMDP->setLength( USBLapPayLoad );
1675    fPipeInBuffer = (UInt8*)fpPipeInMDP->getBytesNoCopy();
1676    ELG( 0, fPipeInBuffer, 'iBuf', "allocateResources - input buffer" );
1677
1678    // Allocate Memory Descriptor Pointer with memory for the data-out bulk pipe:
1679
1680    fpPipeOutMDP = IOBufferMemoryDescriptor::withCapacity( MAX_BLOCK_SIZE, kIODirectionOut );
1681    require(fpPipeOutMDP, Fail);
1682
1683    fpPipeOutMDP->setLength( MAX_BLOCK_SIZE );
1684    fPipeOutBuffer = (UInt8*)fpPipeOutMDP->getBytesNoCopy();
1685    ELG( 0, fPipeOutBuffer, 'oBuf', "allocateResources - output buffer" );
1686
1687    // set up the completion info for all three pipes
1688
1689    require(fPort, Fail);
1690    finterruptCompletionInfo.target = this;
1691    finterruptCompletionInfo.action = interruptReadComplete;
1692    finterruptCompletionInfo.parameter  = fPort;
1693
1694    fReadCompletionInfo.target  = this;
1695    fReadCompletionInfo.action  = dataReadComplete;
1696    fReadCompletionInfo.parameter   = fPort;
1697
1698    fWriteCompletionInfo.target = this;
1699    fWriteCompletionInfo.action = dataWriteComplete;
1700    fWriteCompletionInfo.parameter  = fPort;
1701
1702
1703    ELG( 0, 0, 'aRs+', "allocateResources successful" );
1704    return true;
1705
1706Fail:
1707    return false;
1708
1709} // allocateResources
1710
1711
1712/****************************************************************************************************/
1713//
1714//      Method:     AppleUSBIrDADriver::releaseResources
1715//
1716//      Inputs:     port - the Port
1717//
1718//      Outputs:    None
1719//
1720//      Desc:       Frees up the pipe resources allocated in allocateResources
1721//
1722/****************************************************************************************************/
1723
1724void AppleUSBIrDADriver::releaseResources( void )
1725{
1726    ELG( 0, 0, 'rlRs', "releaseResources" );
1727    XTRACE(kLogReleaseResources, 0, 0);
1728
1729    if ( fpInterface )
1730    {
1731	fpInterface->close( this );
1732    }
1733
1734    if ( fpPipeOutMDP  )
1735    {
1736	fpPipeOutMDP->release();
1737	fpPipeOutMDP    = 0;
1738    }
1739
1740    if ( fpPipeInMDP   )
1741    {
1742	fpPipeInMDP->release();
1743	fpPipeInMDP     = 0;
1744    }
1745
1746    if ( fpinterruptPipeMDP )
1747    {
1748	fpinterruptPipeMDP->release();
1749	fpinterruptPipeMDP  = 0;
1750    }
1751
1752    return;
1753
1754}/* end releaseResources */
1755
1756//
1757// start reading on the pipes
1758//
1759bool AppleUSBIrDADriver::startPipes( void )
1760{
1761    IOReturn                    rtn;
1762
1763    require(fPort, Fail);
1764    require(fpinterruptPipeMDP, Fail);
1765    require(fpPipeInMDP, Fail);
1766    require(fpPipeOutMDP, Fail);
1767
1768
1769    if (kUseInterruptsForRead) {                // read on interrupt pipe if using interrupts
1770	rtn = fpInterruptPipe->Read(fpinterruptPipeMDP, &finterruptCompletionInfo, NULL );
1771    }
1772    else {                                      // Read the data-in bulk pipe if not using interrupts
1773	rtn = fpInPipe->Read(fpPipeInMDP, 1000, 1000, &fReadCompletionInfo, NULL );
1774    }
1775    require(rtn == kIOReturnSuccess, Fail);
1776
1777    // is this really referenced by anyone??
1778    fReadActive = (kUseInterruptsForRead == false);     // remember if we did a read
1779
1780    return true;
1781
1782Fail:
1783    return false;
1784}/* end startPipes */
1785
1786//
1787// stop i/o on the pipes
1788//
1789void AppleUSBIrDADriver::stopPipes()
1790{
1791    if (fpInPipe)           fpInPipe->Abort();
1792    if (fpOutPipe)          fpOutPipe->Abort();
1793    if (fpInterruptPipe)    fpInterruptPipe->Abort();
1794}
1795
1796
1797/****************************************************************************************************/
1798//
1799//      Method:     AppleUSBIrDADriver::configureDevice
1800//
1801//      Inputs:     numConfigs - number of configurations present
1802//
1803//      Outputs:    return Code - true (device configured), false (device not configured)
1804//
1805//      Desc:       Finds the configurations and then the appropriate interfaces etc.
1806//
1807/****************************************************************************************************/
1808
1809bool AppleUSBIrDADriver::configureDevice( UInt8 numConfigs )
1810{
1811    IOUSBFindInterfaceRequest           req;            // device request Class on stack
1812    const IOUSBConfigurationDescriptor  *cd = NULL;     // configuration descriptor
1813    IOUSBInterfaceDescriptor            *intf = NULL;   // interface descriptor
1814    IOReturn                            ior;
1815    UInt8                               cval;
1816    UInt8                               config = 0;
1817    USBIrDAQoS                          *qos;
1818
1819    ELG( 0, numConfigs, 'cDev', "configureDevice" );
1820    XTRACE(kLogConfigureDevice, 0, 0);
1821
1822    for (cval=0; cval<numConfigs; cval++)
1823    {
1824	ELG( 0, cval, 'CkCn', "configureDevice - Checking Configuration" );
1825
1826	cd = fpDevice->GetFullConfigurationDescriptor(cval);
1827	if ( !cd )
1828	{
1829	    ELG( 0, 0, 'GFC-', "configureDevice - Error getting the full configuration descriptor" );
1830	} else {
1831
1832		// Find the first one - there may be more to go on in the future
1833
1834	    req.bInterfaceClass = kIOUSBFindInterfaceDontCare;
1835	    req.bInterfaceSubClass  = kIOUSBFindInterfaceDontCare;
1836	    req.bInterfaceProtocol  = kIOUSBFindInterfaceDontCare;
1837	    req.bAlternateSetting   = kIOUSBFindInterfaceDontCare;
1838	    ior = fpDevice->FindNextInterfaceDescriptor(cd, intf, &req, &intf);
1839	    if ( ior == kIOReturnSuccess )
1840	    {
1841		if ( intf )
1842		{
1843		    config = cd->bConfigurationValue;
1844		    ELG( cd, config, 'FNI+', "configureDevice - Interface descriptor found" );
1845		    break;
1846		} else {
1847		    ELG( 0, config, 'FNI-', "configureDevice - That's weird the interface was null" );
1848		    cd = NULL;
1849		}
1850	    } else {
1851		ELG( 0, cval, 'FNID', "configureDevice - No CDC interface found this configuration" );
1852		cd = NULL;
1853	    }
1854	}
1855    }
1856
1857    if ( !cd )
1858    {
1859	return false;
1860    }
1861
1862	// Now lets do it for real
1863
1864    req.bInterfaceClass = kIOUSBFindInterfaceDontCare;
1865    req.bInterfaceSubClass  = kIOUSBFindInterfaceDontCare;
1866    req.bInterfaceProtocol  = kIOUSBFindInterfaceDontCare;
1867    req.bAlternateSetting   = kIOUSBFindInterfaceDontCare;
1868
1869    fpInterface = fpDevice->FindNextInterface( NULL, &req );
1870    if ( !fpInterface )
1871    {
1872	ELG( 0, 0, 'FIC-', "configureDevice - Find next interface failed" );
1873	return false;
1874    }
1875    fpInterface->retain();      // release done in stop()
1876
1877	// Get the QoS Functional Descriptor (it's the only one)
1878
1879    qos = (USBIrDAQoS *)fpInterface->FindNextAssociatedDescriptor(NULL, USBIrDAClassDescriptor);
1880    if (!qos)
1881    {
1882	ELG( 0, 0, 'OSF-', "configureDevice - No QOS descriptor" );
1883
1884	/* Set some defaults - qos values need tuning of course */
1885
1886	fQoS.bFunctionLength = 12;
1887	fQoS.bDescriptorType = USBIrDAClassDescriptor;
1888	fQoS.version = 0x100;
1889	fQoS.datasize = 0x1f;       // 1k = 1f, 2k = 3f
1890	fQoS.windowsize = 1;
1891	fQoS.minturn = 2;           // review & tune.
1892	fQoS.baud1 = 0x01;          // 4mbit no mir, all sir
1893	fQoS.baud2 = 0x3e;
1894	fQoS.bofs = 4;              // review and tune.
1895	fQoS.sniff = 0;
1896	fQoS.unicast = 0;
1897    } else {
1898	ELG( qos->bDescriptorType, qos, 'QSFD', "AppleUSBCDCDriver::configureDevice - Got QoS Functional Descriptor" );
1899
1900	/* Save the real values */
1901
1902	fQoS.bFunctionLength = qos->bFunctionLength;
1903	fQoS.bDescriptorType = qos->bDescriptorType;
1904	fQoS.version = USBToHostWord(qos->version);
1905	fQoS.datasize = qos->datasize;
1906	fQoS.windowsize = qos->windowsize;
1907	fQoS.minturn = qos->minturn;
1908	fQoS.baud1 = qos->baud2;        // flipped because of our good friends at you know who
1909	fQoS.baud2 = qos->baud1;
1910	fQoS.bofs = qos->bofs;
1911	fQoS.sniff = qos->sniff;
1912	fQoS.unicast = qos->unicast;
1913    }
1914
1915
1916    // irda starts up turned off so always try and suspend the hardware
1917    ior = fpDevice->SuspendDevice( true );         // Suspend the device
1918    require(ior == kIOReturnSuccess, Fail);
1919
1920    return true;
1921
1922Fail:
1923    return false;
1924
1925}/* end configureDevice */
1926
1927/****************************************************************************************************/
1928//
1929//      Method:     AppleUSBIrDADriver::createSuffix
1930//
1931//      Inputs:     None
1932//
1933//      Outputs:    return Code - true (suffix created), false (suffix not create), sufKey - the key
1934//
1935//      Desc:       Creates the suffix key. It attempts to use the serial number string from the device
1936//                  if it's reasonable i.e. less than 8 bytes ascii. Remember it's stored in unicode
1937//                  format. If it's not present or not reasonable it will generate the suffix based
1938//                  on the location property tag. At least this remains the same across boots if the
1939//                  device is plugged into the same physical location. In the latter case trailing
1940//                  zeros are removed.
1941//
1942/****************************************************************************************************/
1943
1944bool AppleUSBIrDADriver::createSuffix( unsigned char *sufKey, int sufMaxLen )
1945{
1946
1947    IOReturn                rc;
1948    UInt8                   serBuf[10];     // arbitrary size > 8
1949    OSNumber                *location;
1950    UInt32                  locVal;
1951    UInt8                   *rlocVal;
1952    UInt16                  offs, i, sig = 0;
1953    UInt8                   indx;
1954    bool                    keyOK = false;
1955
1956    ELG( 0, 0, 'cSuf', "createSuffix" );
1957
1958    indx = fpDevice->GetSerialNumberStringIndex();
1959    if (indx != 0 )
1960    {
1961	// Generate suffix key based on the serial number string (if reasonable <= 8 and > 0)
1962
1963	rc = fpDevice->GetStringDescriptor(indx, (char *)&serBuf, sizeof(serBuf));
1964	if ( !rc )
1965	{
1966	    if ( (strlen((char *)&serBuf) < 9) && (strlen((char *)&serBuf) > 0) )
1967	    {
1968		strlcpy( (char *)sufKey, (const char *)&serBuf, sufMaxLen);
1969		keyOK = true;
1970	    }
1971	} else {
1972	    ELG( 0, rc, 'Sdt-', "createSuffix error reading serial number string" );
1973	}
1974    }
1975
1976    if ( !keyOK )
1977    {
1978	// Generate suffix key based on the location property tag
1979
1980	location = (OSNumber *)fpDevice->getProperty(kUSBDevicePropertyLocationID);
1981	if ( location )
1982	{
1983	    locVal = location->unsigned32BitValue();
1984	    offs = 0;
1985	    rlocVal = (UInt8*)&locVal;
1986	    for (i=0; i<4; i++)
1987	    {
1988		sufKey[offs] = Asciify(rlocVal[i] >> 4);
1989		if ( sufKey[offs++] != '0')
1990		    sig = offs;
1991		sufKey[offs] = Asciify(rlocVal[i]);
1992		if ( sufKey[offs++] != '0')
1993		    sig = offs;
1994	    }
1995	    sufKey[sig] = 0x00;
1996	    keyOK = true;
1997	}
1998    }
1999
2000    return keyOK;
2001
2002}/* end createSuffix */
2003
2004/****************************************************************************************************/
2005//
2006//      Method:     AppleUSBIrDADriver::createSerialStream
2007//
2008//      Inputs:     None
2009//
2010//      Outputs:    return Code - true (created and initialilzed ok), false (it failed)
2011//
2012//      Desc:       Creates and initializes the nub and port structure
2013//
2014/****************************************************************************************************/
2015
2016bool AppleUSBIrDADriver::createSerialStream()
2017{
2018    UInt8           indx;
2019    IOReturn            rc;
2020    unsigned char suffix[10];
2021
2022    ELG( 0, fNub, '=Nub', "createSerialStream" );
2023    XTRACE(kLogCreateSerialStream, 0, 0);
2024
2025    check(fNub && fPort);
2026    if (!fNub || !fPort) return false;
2027
2028    SetStructureDefaults( fPort, true );            // init the Port structure
2029
2030    // Allocate the request lock
2031    fPort->serialRequestLock = IOLockAlloc();   // init lock used to protect code on MP
2032    if ( !fPort->serialRequestLock ) {
2033	return false;
2034    }
2035
2036    // now the ring buffers
2037    if (!allocateRingBuffer(&(fPort->TX), fPort->TXStats.BufferSize) ||
2038	!allocateRingBuffer(&(fPort->RX), fPort->RXStats.BufferSize))
2039    {
2040	return false;
2041    }
2042
2043
2044    if ( !fTerminate )
2045    {
2046	// Report the base name to be used for generating device nodes
2047
2048	fNub->setProperty( kIOTTYBaseNameKey, baseName );
2049
2050	// Create suffix key and set it
2051
2052	if ( createSuffix(suffix, sizeof(suffix) ) )
2053	{
2054	    fNub->setProperty( kIOTTYSuffixKey, (const char *)suffix );
2055	}
2056
2057
2058	// Save the Product String  (at least the first productNameLength's worth).
2059
2060	indx = fpDevice->GetProductStringIndex();
2061	if ( indx != 0 )
2062	{
2063	    rc = fpDevice->GetStringDescriptor( indx, (char *)&fProductName, sizeof(fProductName) );
2064	    if ( !rc )
2065	    {
2066		if ( strlen((char *)fProductName) == 0 )        // believe it or not this sometimes happens (null string with an index defined???)
2067		{
2068		    strlcpy( (char *)fProductName, defaultName, sizeof(fProductName));
2069		}
2070		fNub->setProperty( (const char *)propertyTag, (const char *)fProductName );
2071	    }
2072	}
2073
2074	fNub->registerService();
2075    }
2076
2077    return true;
2078
2079}/* end createSerialStream */
2080
2081//
2082// release things created in createSerialStream
2083//
2084void
2085AppleUSBIrDADriver::destroySerialStream(void)
2086{
2087    require(fPort, Fail);
2088
2089    if ( fPort->serialRequestLock )
2090    {
2091	IOLockFree( fPort->serialRequestLock ); // free the Serial Request Lock
2092	fPort->serialRequestLock = NULL;
2093    }
2094
2095    // Remove all the buffers.
2096
2097    freeRingBuffer( &fPort->TX );
2098    freeRingBuffer( &fPort->RX );
2099
2100    removeProperty( (const char *)propertyTag );    // unhook from BSD
2101
2102Fail:
2103    return;
2104}
2105
2106//
2107// startIrDA
2108//
2109// assumes createSerialStream is called once at usb start time
2110// calls allocateResources to open endpoints
2111//
2112bool
2113AppleUSBIrDADriver::startIrDA()
2114{
2115    bool ok;
2116
2117    require(fIrDA == NULL, Fail);
2118    require(fNub, Fail);
2119    require(fUserClientNub, Fail);
2120
2121    Workaround();                           // make chip as sane as can be
2122
2123    ok = allocateResources();               // open the pipe endpoints
2124    require(ok, Fail);
2125
2126    startPipes();                           // start reading on the usb pipes
2127
2128    fBaudCode = kLinkSpeed9600;             // the code for 9600 (see BaudRate above)
2129    fLastChangeByte = 0;                    // no known state of device, force mode to change on first i/o
2130    fCurrentBaud = 9600;
2131    SetBofCount(10);                        // start with about 10 bofs (sets fBofsCode)
2132
2133    fIrDA = IrDAComm::irDAComm(fNub, fUserClientNub);       // create and init and start IrDA
2134    require(fIrDA, Fail);
2135
2136    return true;
2137
2138Fail:
2139    return false;
2140}
2141
2142void
2143AppleUSBIrDADriver::stopIrDA()
2144{
2145    require(fIrDA, Fail);
2146
2147    fIrDA->Stop();
2148    fIrDA->release();
2149    fIrDA = NULL;
2150
2151    stopPipes();                            // stop reading on the usb pipes
2152
2153    if (fpPipeOutMDP != NULL)               // better test for releaseResources?
2154	releaseResources( );
2155
2156Fail:
2157    return;
2158}
2159
2160/****************************************************************************************************/
2161//
2162//      Method:     AppleUSBIrDADriver::createNub
2163//
2164//      Inputs:
2165//
2166//      Outputs:    fNub (an AppleUSBIrDA glue object) and fPort
2167//
2168//      Desc:       allocates and inits, but doesn't publish the BSD info on the nub yet
2169//              create serial stream finishes the job later.
2170//
2171/****************************************************************************************************/
2172bool
2173AppleUSBIrDADriver::createNub(void)
2174{
2175    bool ret;
2176
2177    if (fNub == NULL) {
2178	fNub = new AppleUSBIrDA;
2179    }
2180    require(fNub, Failed);
2181    check(fNub->getRetainCount() == 1);     // testing
2182
2183    if (fPort == NULL) {
2184	fPort = (PortInfo_t*)IOMalloc( sizeof(PortInfo_t) );
2185    }
2186    require(fPort, Failed);
2187    bzero(fPort, sizeof(PortInfo_t));
2188
2189    ret = fNub->init(0, fPort);
2190    require(ret == true, Failed);
2191
2192    ret = fNub->attach( this );
2193    require(ret == true, Failed);
2194    check(fNub->getRetainCount() == 2);     // testing
2195
2196    XTRACE(kLogNewNub, 0, fNub);
2197    XTRACE(kLogNewPort, 0, fPort);
2198
2199    // now make the nub to act as a communication point for user-client
2200    if (fUserClientNub == NULL)
2201	fUserClientNub = AppleIrDA::withNub(fNub);      // it talks to the serial nub ...
2202    require(fUserClientNub, Failed);
2203
2204    fUserClientNub->attach(this);
2205
2206    return true;
2207
2208Failed:
2209    IOLog("Create nub failed\n");
2210    // could try and clean up here, but let's start by just not crashing.
2211    return false;
2212}
2213
2214void AppleUSBIrDADriver::destroyNub()
2215{
2216    if (fPort != NULL) {
2217	IOFree( fPort, sizeof(PortInfo_t) );
2218	fPort = NULL;
2219    }
2220
2221    if (fUserClientNub) {
2222	XTRACE(kLogDestroyNub, 1, fUserClientNub->getRetainCount());
2223	fUserClientNub->detach(this);
2224	fUserClientNub->release();
2225	fUserClientNub = NULL;
2226    }
2227
2228    if (fNub) {
2229	XTRACE(kLogDestroyNub, 2, fNub->getRetainCount());
2230	fNub->detach(this);
2231	fNub->release();    // crash boom?
2232	fNub = NULL;
2233    }
2234}
2235
2236/****************************************************************************************************/
2237//
2238//      Method:     AppleUSBIrDADriver::acquirePort
2239//
2240//      Inputs:     sleep - true (wait for it), false (don't), refCon - the Port
2241//
2242//      Outputs:    Return Code - kIOReturnSuccess, kIOReturnExclusiveAccess, kIOReturnIOError and various others
2243//
2244//      Desc:       acquirePort tests and sets the state of the port object.  If the port was
2245//                  available, then the state is set to busy, and kIOReturnSuccess is returned.
2246//                  If the port was already busy and sleep is YES, then the thread will sleep
2247//                  until the port is freed, then re-attempts the acquire.  If the port was
2248//                  already busy and sleep is NO, then kIOReturnExclusiveAccess is returned.
2249//
2250/****************************************************************************************************/
2251
2252IOReturn AppleUSBIrDADriver::acquirePort( bool sleep, void *refCon )
2253{
2254    PortInfo_t          *port = (PortInfo_t *) refCon;
2255    UInt32              busyState = 0;
2256    IOReturn            rtn = kIOReturnSuccess;
2257
2258    ELG( port, sleep, 'acqP', "acquirePort" );
2259    XTRACE(kLogAcquirePort, 0, 0);
2260
2261    if ( fTerminate ) {
2262	//int review_fTerminate;
2263	//return kIOReturnOffline;
2264    }
2265    SetStructureDefaults( port, FALSE );    /* Initialize all the structures */
2266
2267    for (;;)
2268    {
2269	busyState = readPortState( port ) & PD_S_ACQUIRED;
2270	if ( !busyState )
2271	{
2272	    // Set busy bit, and clear everything else
2273	    changeState( port, (UInt32)PD_S_ACQUIRED | DEFAULT_STATE, (UInt32)STATE_ALL);
2274	    break;
2275	} else {
2276	    if ( !sleep )
2277	    {
2278		ELG( 0, 0, 'busy', "acquirePort - Busy exclusive access" );
2279		return kIOReturnExclusiveAccess;
2280	    } else {
2281		busyState = 0;
2282		rtn = watchState( &busyState, PD_S_ACQUIRED, refCon );
2283		if ( (rtn == kIOReturnIOError) || (rtn == kIOReturnSuccess) )
2284		{
2285		    continue;
2286		} else {
2287		    ELG( 0, 0, 'int-', "acquirePort - Interrupted!" );
2288		    return rtn;
2289		}
2290	    }
2291	}
2292    } /* end for */
2293
2294    fSessions++;    //bump number of active sessions and turn on clear to send
2295    changeState( port, PD_RS232_S_CTS, PD_RS232_S_CTS);
2296
2297    CheckIrDAState();       // turn irda on/off if appropriate
2298
2299    if (1) {                // wait for initial connect
2300	int counter = 0;
2301	//while (fIrDA && fIrDA->Starting()) {
2302	while (counter++ < (10 * 10)) {     // sanity check limit of 10 seconds
2303	    if (fIrDA && (fIrDA->Starting() == false)) break;
2304	    XTRACE(kLogAcquirePort, counter, 1);
2305	    IOSleep(100);                   // wait 1/10 of a second between polls and yield time
2306	}
2307	//IOLog("AppleUSBIrDA: acquire port paused %d ms for initial connection\n", counter*100);
2308    }
2309
2310    return rtn;
2311
2312}/* end acquirePort */
2313
2314/****************************************************************************************************/
2315//
2316//      Method:     AppleUSBIrDADriver::releasePort
2317//
2318//      Inputs:     refCon - the Port
2319//
2320//      Outputs:    Return Code - kIOReturnSuccess or kIOReturnNotOpen
2321//
2322//      Desc:       releasePort returns all the resources and does clean up.
2323//
2324/****************************************************************************************************/
2325
2326IOReturn AppleUSBIrDADriver::releasePort( void *refCon )
2327{
2328    PortInfo_t          *port = (PortInfo_t *) refCon;
2329    UInt32              busyState;
2330
2331    ELG( 0, port, 'relP', "releasePort" );
2332    XTRACE(kLogReleasePort, 0, 0);
2333
2334    busyState = (readPortState( port ) & PD_S_ACQUIRED);
2335    if ( !busyState )
2336    {
2337	ELG( 0, 0, 'rlP-', "releasePort - NOT OPEN" );
2338	return kIOReturnNotOpen;
2339    }
2340
2341    changeState( port, 0, (UInt32)STATE_ALL );  // Clear the entire state word which also deactivates the port
2342
2343    fSessions--;        // reduce number of active sessions
2344    CheckIrDAState();   // turn irda off if appropriate
2345
2346    if ((fTerminate) && (fSessions == 0))       // if it's the result of a terminate and session count is zero we also need to close things
2347    {
2348	if (0 && fpInterface )      // jdg - this was bogus
2349	{
2350	    fpInterface->close( this );
2351	    fpInterface->release();
2352	    fpInterface = NULL;
2353	}
2354       // else IOLog("appleusbirda - would have released fpInteface here\n");
2355    }
2356
2357    ELG( 0, 0, 'RlP+', "releasePort - OK" );
2358
2359    return kIOReturnSuccess;
2360
2361}/* end releasePort */
2362
2363/****************************************************************************************************/
2364//
2365//      Method:     AppleUSBIrDADriver::setState
2366//
2367//      Inputs:     state - state to set, mask - state mask, refCon - the Port
2368//
2369//      Outputs:    Return Code - kIOReturnSuccess or kIOReturnBadArgument
2370//
2371//      Desc:       Set the state for the port device.  The lower 16 bits are used to set the
2372//                  state of various flow control bits (this can also be done by enqueueing a
2373//                  PD_E_FLOW_CONTROL event).  If any of the flow control bits have been set
2374//                  for automatic control, then they can't be changed by setState.  For flow
2375//                  control bits set to manual (that are implemented in hardware), the lines
2376//                  will be changed before this method returns.  The one weird case is if RXO
2377//                  is set for manual, then an XON or XOFF character may be placed at the end
2378//                  of the TXQ and transmitted later.
2379//
2380/****************************************************************************************************/
2381
2382IOReturn AppleUSBIrDADriver::setState( UInt32 state, UInt32 mask, void *refCon )
2383{
2384    PortInfo_t *port = (PortInfo_t *) refCon;
2385
2386    ELG( state, mask, 'stSt', "setState" );
2387    XTRACE(kLogSetState, 0, 0);
2388
2389    if ( mask & (PD_S_ACQUIRED | PD_S_ACTIVE | (~EXTERNAL_MASK)) )
2390	return kIOReturnBadArgument;
2391
2392    if ( readPortState( port ) & PD_S_ACQUIRED )
2393    {
2394	    // ignore any bits that are read-only
2395	mask &= (~port->FlowControl & PD_RS232_A_MASK) | PD_S_MASK;
2396
2397	if ( mask)
2398	    changeState( port, state, mask );
2399
2400	return kIOReturnSuccess;
2401    }
2402
2403    return kIOReturnNotOpen;
2404
2405}/* end setState */
2406
2407/****************************************************************************************************/
2408//
2409//      Method:     AppleUSBIrDADriver::getState
2410//
2411//      Inputs:     refCon - the Port
2412//
2413//      Outputs:    state - port state
2414//
2415//      Desc:       Get the state for the port.
2416//
2417/****************************************************************************************************/
2418
2419UInt32 AppleUSBIrDADriver::getState( void *refCon )
2420{
2421    PortInfo_t  *port = (PortInfo_t *) refCon;
2422    UInt32      state;
2423
2424    ELG( 0, port, 'gtSt', "getState" );
2425
2426    CheckQueues( port );
2427
2428    state = readPortState( port ) & EXTERNAL_MASK;
2429
2430    ELG( state, EXTERNAL_MASK, 'gtS-', "getState-->State" );
2431	XTRACE(kLogGetState, state >> 16, (short)state);
2432
2433    return state;
2434
2435}/* end getState */
2436
2437/****************************************************************************************************/
2438//
2439//      Method:     AppleUSBIrDADriver::watchState
2440//
2441//      Inputs:     state - state to watch for, mask - state mask bits, refCon - the Port
2442//
2443//      Outputs:    Return Code - kIOReturnSuccess or value returned from ::watchState
2444//
2445//      Desc:       Wait for the at least one of the state bits defined in mask to be equal
2446//                  to the value defined in state. Check on entry then sleep until necessary,
2447//                  see watchState for more details.
2448//
2449/****************************************************************************************************/
2450
2451IOReturn AppleUSBIrDADriver::watchState( UInt32 *state, UInt32 mask, void *refCon)
2452{
2453    PortInfo_t  *port = (PortInfo_t *) refCon;
2454    IOReturn    ret = kIOReturnNotOpen;
2455
2456    ELG( *state, mask, 'WatS', "watchState" );
2457    XTRACE(kLogWatchState, 0, 0);
2458
2459    if ( readPortState( port ) & PD_S_ACQUIRED )
2460    {
2461	ret = kIOReturnSuccess;
2462	mask &= EXTERNAL_MASK;
2463	ret = privateWatchState( port, state, mask );
2464	*state &= EXTERNAL_MASK;
2465    }
2466
2467    ELG( ret, 0, 'WatS', "watchState --> watchState" );
2468    XTRACE(kLogWatchState, 0xffff, 0xffff);
2469    return ret;
2470
2471}/* end watchState */
2472
2473/****************************************************************************************************/
2474//
2475//      Method:     AppleUSBIrDADriver::nextEvent
2476//
2477//      Inputs:     refCon - the Port
2478//
2479//      Outputs:    Return Code - kIOReturnSuccess
2480//
2481//      Desc:       Not used by this driver.
2482//
2483/****************************************************************************************************/
2484
2485UInt32 AppleUSBIrDADriver::nextEvent( void *refCon )
2486{
2487    UInt32      ret = kIOReturnSuccess;
2488
2489    ELG( 0, 0, 'NxtE', "nextEvent" );
2490
2491    return ret;
2492
2493}/* end nextEvent */
2494
2495/****************************************************************************************************/
2496//
2497//      Method:     AppleUSBIrDADriver::executeEvent
2498//
2499//      Inputs:     event - The event, data - any data associated with the event, refCon - the Port
2500//
2501//      Outputs:    Return Code - kIOReturnSuccess, kIOReturnNotOpen or kIOReturnBadArgument
2502//
2503//      Desc:       executeEvent causes the specified event to be processed immediately.
2504//                  This is primarily used for channel control commands like START & STOP
2505//
2506/****************************************************************************************************/
2507
2508IOReturn AppleUSBIrDADriver::executeEvent( UInt32 event, UInt32 data, void *refCon )
2509{
2510    PortInfo_t  *port = (PortInfo_t *) refCon;
2511    IOReturn    ret = kIOReturnSuccess;
2512    UInt32      state, delta;
2513
2514    delta = 0;
2515    state = readPortState( port );
2516    ELG( port, state, 'ExIm', "executeEvent" );
2517    XTRACE(kLogExecEvent, event >> 16, (short)event);
2518    XTRACE(kLogExecEventData, data >> 16, (short)data);
2519
2520    if ( (state & PD_S_ACQUIRED) == 0 )
2521	return kIOReturnNotOpen;
2522
2523    switch ( event )
2524    {
2525    case PD_RS232_E_XON_BYTE:
2526	ELG( data, event, 'ExIm', "executeEvent - PD_RS232_E_XON_BYTE" );
2527	port->XONchar = data;
2528	break;
2529    case PD_RS232_E_XOFF_BYTE:
2530	ELG( data, event, 'ExIm', "executeEvent - PD_RS232_E_XOFF_BYTE" );
2531	port->XOFFchar = data;
2532	break;
2533    case PD_E_SPECIAL_BYTE:
2534	ELG( data, event, 'ExIm', "executeEvent - PD_E_SPECIAL_BYTE" );
2535	port->SWspecial[ data >> SPECIAL_SHIFT ] |= (1 << (data & SPECIAL_MASK));
2536	break;
2537
2538    case PD_E_VALID_DATA_BYTE:
2539	ELG( data, event, 'ExIm', "executeEvent - PD_E_VALID_DATA_BYTE" );
2540	port->SWspecial[ data >> SPECIAL_SHIFT ] &= ~(1 << (data & SPECIAL_MASK));
2541	break;
2542
2543    case PD_E_FLOW_CONTROL:
2544	ELG( data, event, 'ExIm', "executeEvent - PD_E_FLOW_CONTROL" );
2545	break;
2546
2547    case PD_E_ACTIVE:
2548	ELG( data, event, 'Exlm', "executeEvent - PD_E_ACTIVE" );
2549	if ( (bool)data )
2550	{
2551	    if ( !(state & PD_S_ACTIVE) )
2552	    {
2553		SetStructureDefaults( port, FALSE );
2554		changeState( port, (UInt32)PD_S_ACTIVE, (UInt32)PD_S_ACTIVE ); // activate port
2555	    }
2556	} else {
2557	    if ( (state & PD_S_ACTIVE) )
2558	    {
2559		changeState( port, 0, (UInt32)PD_S_ACTIVE );
2560	    }
2561	}
2562	break;
2563
2564    case PD_E_DATA_LATENCY:
2565	ELG( data, event, 'ExIm', "executeEvent - PD_E_DATA_LATENCY" );
2566	port->DataLatInterval = long2tval( data * 1000 );
2567	break;
2568
2569    case PD_RS232_E_MIN_LATENCY:
2570	ELG( data, event, 'ExIm', "executeEvent - PD_RS232_E_MIN_LATENCY" );
2571	port->MinLatency = bool( data );
2572	break;
2573
2574    case PD_E_DATA_INTEGRITY:
2575	ELG( data, event, 'Exlm', "executeEvent - PD_E_DATA_INTEGRITY" );
2576	if ( (data < PD_RS232_PARITY_NONE) || (data > PD_RS232_PARITY_SPACE))
2577	{
2578	    ret = kIOReturnBadArgument;
2579	}
2580	else
2581	{
2582	    port->TX_Parity = data;
2583	    port->RX_Parity = PD_RS232_PARITY_DEFAULT;
2584	}
2585	break;
2586
2587    case PD_E_DATA_RATE:
2588	ELG( data, event, 'Exlm', "executeEvent - PD_E_DATA_RATE" );
2589	    /* For API compatiblilty with Intel.    */
2590	data >>= 1;
2591	ELG( 0, data, 'Exlm', "executeEvent - actual data rate" );
2592	if ( (data < kMinBaudRate) || (data > kMaxBaudRate) )       // Do we really care
2593	    ret = kIOReturnBadArgument;
2594	else
2595	{
2596	    port->BaudRate = data;
2597	}
2598	break;
2599
2600    case PD_E_DATA_SIZE:
2601	ELG( data, event, 'Exlm', "executeEvent - PD_E_DATA_SIZE" );
2602	    /* For API compatiblilty with Intel.    */
2603	data >>= 1;
2604	ELG( 0, data, 'Exlm', "executeEvent - actual data size" );
2605	if ( (data < 5) || (data > 8) )
2606	    ret = kIOReturnBadArgument;
2607	else
2608	{
2609	    port->CharLength = data;
2610	}
2611	break;
2612
2613    case PD_RS232_E_STOP_BITS:
2614	ELG( data, event, 'Exlm', "executeEvent - PD_RS232_E_STOP_BITS" );
2615	if ( (data < 0) || (data > 20) )
2616	    ret = kIOReturnBadArgument;
2617	else
2618	{
2619	    port->StopBits = data;
2620	}
2621	break;
2622
2623    case PD_E_RXQ_FLUSH:
2624	ELG( data, event, 'Exlm', "executeEvent - PD_E_RXQ_FLUSH" );
2625	break;
2626
2627    case PD_E_RX_DATA_INTEGRITY:
2628	ELG( data, event, 'Exlm', "executeEvent - PD_E_RX_DATA_INTEGRITY" );
2629	if ( (data != PD_RS232_PARITY_DEFAULT) &&  (data != PD_RS232_PARITY_ANY) )
2630	    ret = kIOReturnBadArgument;
2631	else
2632	    port->RX_Parity = data;
2633	break;
2634
2635    case PD_E_RX_DATA_RATE:
2636	ELG( data, event, 'Exlm', "executeEvent - PD_E_RX_DATA_RATE" );
2637	if ( data )
2638	    ret = kIOReturnBadArgument;
2639	break;
2640
2641    case PD_E_RX_DATA_SIZE:
2642	ELG( data, event, 'Exlm', "executeEvent - PD_E_RX_DATA_SIZE" );
2643	if ( data )
2644	    ret = kIOReturnBadArgument;
2645	break;
2646
2647    case PD_RS232_E_RX_STOP_BITS:
2648	ELG( data, event, 'Exlm', "executeEvent - PD_RS232_E_RX_STOP_BITS" );
2649	if ( data )
2650	    ret = kIOReturnBadArgument;
2651	break;
2652
2653    case PD_E_TXQ_FLUSH:
2654	ELG( data, event, 'Exlm', "executeEvent - PD_E_TXQ_FLUSH" );
2655	break;
2656
2657    case PD_RS232_E_LINE_BREAK:
2658	ELG( data, event, 'Exlm', "executeEvent - PD_RS232_E_LINE_BREAK" );
2659	state &= ~PD_RS232_S_BRK;
2660	delta |= PD_RS232_S_BRK;
2661	break;
2662
2663    case PD_E_DELAY:
2664	ELG( data, event, 'Exlm', "executeEvent - PD_E_DELAY" );
2665	port->CharLatInterval = long2tval(data * 1000);
2666	break;
2667
2668    case PD_E_RXQ_SIZE:
2669	ELG( 0, event, 'Exlm', "executeEvent - PD_E_RXQ_SIZE" );
2670	break;
2671
2672    case PD_E_TXQ_SIZE:
2673	ELG( 0, event, 'Exlm', "executeEvent - PD_E_TXQ_SIZE" );
2674	break;
2675
2676    case PD_E_RXQ_HIGH_WATER:
2677	ELG( data, event, 'Exlm', "executeEvent - PD_E_RXQ_HIGH_WATER" );
2678	break;
2679
2680    case PD_E_RXQ_LOW_WATER:
2681	ELG( data, event, 'Exlm', "executeEvent - PD_E_RXQ_LOW_WATER" );
2682	break;
2683
2684    case PD_E_TXQ_HIGH_WATER:
2685	ELG( data, event, 'Exlm', "executeEvent - PD_E_TXQ_HIGH_WATER" );
2686	break;
2687
2688    case PD_E_TXQ_LOW_WATER:
2689	ELG( data, event, 'Exlm', "executeEvent - PD_E_TXQ_LOW_WATER" );
2690	break;
2691
2692    default:
2693	ELG( data, event, 'Exlm', "executeEvent - unrecognized event" );
2694	ret = kIOReturnBadArgument;
2695	break;
2696    }
2697
2698    state |= state;/* ejk for compiler warnings. ?? */
2699    changeState( port, state, delta );
2700
2701    return ret;
2702
2703}/* end executeEvent */
2704
2705/****************************************************************************************************/
2706//
2707//      Method:     AppleUSBIrDADriver::requestEvent
2708//
2709//      Inputs:     event - The event, refCon - the Port
2710//
2711//      Outputs:    Return Code - kIOReturnSuccess, kIOReturnBadArgument, data - any data associated with the event
2712//
2713//      Desc:       requestEvent processes the specified event as an immediate request and
2714//                  returns the results in data.  This is primarily used for getting link
2715//                  status information and verifying baud rate and such.
2716//
2717/****************************************************************************************************/
2718
2719IOReturn AppleUSBIrDADriver::requestEvent( UInt32 event, UInt32 *data, void *refCon )
2720{
2721    PortInfo_t  *port = (PortInfo_t *) refCon;
2722    IOReturn    returnValue = kIOReturnSuccess;
2723
2724    ELG( 0, readPortState( port ), 'ReqE', "requestEvent" );
2725    XTRACE(kLogReqEvent, event >> 16, (short)event);
2726
2727    if ( data == NULL ) {
2728	ELG( 0, event, 'ReqE', "requestEvent - data is null" );
2729	returnValue = kIOReturnBadArgument;
2730    }
2731    else
2732    {
2733	XTRACE(kLogReqEventData, (*data) >> 16, (short)*data);
2734	switch ( event )
2735	{
2736	    case PD_E_ACTIVE:
2737		ELG( 0, event, 'ReqE', "requestEvent - PD_E_ACTIVE" );
2738		*data = bool(readPortState( port ) & PD_S_ACTIVE);
2739		break;
2740
2741	    case PD_E_FLOW_CONTROL:
2742		ELG( port->FlowControl, event, 'ReqE', "requestEvent - PD_E_FLOW_CONTROL" );
2743		*data = port->FlowControl;
2744		break;
2745
2746	    case PD_E_DELAY:
2747		ELG( 0, event, 'ReqE', "requestEvent - PD_E_DELAY" );
2748		*data = tval2long( port->CharLatInterval )/ 1000;
2749		break;
2750
2751	    case PD_E_DATA_LATENCY:
2752		ELG( 0, event, 'ReqE', "requestEvent - PD_E_DATA_LATENCY" );
2753		*data = tval2long( port->DataLatInterval )/ 1000;
2754		break;
2755
2756	    case PD_E_TXQ_SIZE:
2757		ELG( 0, event, 'ReqE', "requestEvent - PD_E_TXQ_SIZE" );
2758		*data = GetQueueSize( &port->TX );
2759		break;
2760
2761	    case PD_E_RXQ_SIZE:
2762		ELG( 0, event, 'ReqE', "requestEvent - PD_E_RXQ_SIZE" );
2763		*data = GetQueueSize( &port->RX );
2764		break;
2765
2766	    case PD_E_TXQ_LOW_WATER:
2767		ELG( 0, event, 'ReqE', "requestEvent - PD_E_TXQ_LOW_WATER" );
2768		*data = 0;
2769		returnValue = kIOReturnBadArgument;
2770		break;
2771
2772	    case PD_E_RXQ_LOW_WATER:
2773		ELG( 0, event, 'ReqE', "requestEvent - PD_E_RXQ_LOW_WATER" );
2774		*data = 0;
2775		returnValue = kIOReturnBadArgument;
2776		break;
2777
2778	    case PD_E_TXQ_HIGH_WATER:
2779		ELG( 0, event, 'ReqE', "requestEvent - PD_E_TXQ_HIGH_WATER" );
2780		*data = 0;
2781		returnValue = kIOReturnBadArgument;
2782		break;
2783
2784	    case PD_E_RXQ_HIGH_WATER:
2785		ELG( 0, event, 'ReqE', "requestEvent - PD_E_RXQ_HIGH_WATER" );
2786		*data = 0;
2787		returnValue = kIOReturnBadArgument;
2788		break;
2789
2790	    case PD_E_TXQ_AVAILABLE:
2791		ELG( 0, event, 'ReqE', "requestEvent - PD_E_TXQ_AVAILABLE" );
2792		*data = FreeSpaceinQueue( &port->TX );
2793		break;
2794
2795	    case PD_E_RXQ_AVAILABLE:
2796		ELG( 0, event, 'ReqE', "requestEvent - PD_E_RXQ_AVAILABLE" );
2797		*data = UsedSpaceinQueue( &port->RX );
2798		break;
2799
2800	    case PD_E_DATA_RATE:
2801		ELG( 0, event, 'ReqE', "requestEvent - PD_E_DATA_RATE" );
2802		*data = port->BaudRate << 1;
2803		break;
2804
2805	    case PD_E_RX_DATA_RATE:
2806		ELG( 0, event, 'ReqE', "requestEvent - PD_E_RX_DATA_RATE" );
2807		*data = 0x00;
2808		break;
2809
2810	    case PD_E_DATA_SIZE:
2811		ELG( 0, event, 'ReqE', "requestEvent - PD_E_DATA_SIZE" );
2812		*data = port->CharLength << 1;
2813		break;
2814
2815	    case PD_E_RX_DATA_SIZE:
2816		ELG( 0, event, 'ReqE', "requestEvent - PD_E_RX_DATA_SIZE" );
2817		*data = 0x00;
2818		break;
2819
2820	    case PD_E_DATA_INTEGRITY:
2821		ELG( 0, event, 'ReqE', "requestEvent - PD_E_DATA_INTEGRITY" );
2822		*data = port->TX_Parity;
2823		break;
2824
2825	    case PD_E_RX_DATA_INTEGRITY:
2826		ELG( 0, event, 'ReqE', "requestEvent - PD_E_RX_DATA_INTEGRITY" );
2827		*data = port->RX_Parity;
2828		break;
2829
2830	    case PD_RS232_E_STOP_BITS:
2831		ELG( 0, event, 'ReqE', "requestEvent - PD_RS232_E_STOP_BITS" );
2832		*data = port->StopBits << 1;
2833		break;
2834
2835	    case PD_RS232_E_RX_STOP_BITS:
2836		ELG( 0, event, 'ReqE', "requestEvent - PD_RS232_E_RX_STOP_BITS" );
2837		*data = 0x00;
2838		break;
2839
2840	    case PD_RS232_E_XON_BYTE:
2841		ELG( 0, event, 'ReqE', "requestEvent - PD_RS232_E_XON_BYTE" );
2842		*data = port->XONchar;
2843		break;
2844
2845	    case PD_RS232_E_XOFF_BYTE:
2846		ELG( 0, event, 'ReqE', "requestEvent - PD_RS232_E_XOFF_BYTE" );
2847		*data = port->XOFFchar;
2848		break;
2849
2850	    case PD_RS232_E_LINE_BREAK:
2851		ELG( 0, event, 'ReqE', "requestEvent - PD_RS232_E_LINE_BREAK" );
2852		*data = bool(readPortState( port ) & PD_RS232_S_BRK);
2853		break;
2854
2855	    case PD_RS232_E_MIN_LATENCY:
2856		ELG( 0, event, 'ReqE', "requestEvent - PD_RS232_E_MIN_LATENCY" );
2857		*data = bool( port->MinLatency );
2858		break;
2859
2860	    default:
2861		ELG( 0, event, 'ReqE', "requestEvent - unrecognized event" );
2862		returnValue = kIOReturnBadArgument;
2863		break;
2864	}
2865    }
2866
2867    return kIOReturnSuccess;
2868
2869}/* end requestEvent */
2870
2871/****************************************************************************************************/
2872//
2873//      Method:     AppleUSBIrDADriver::enqueueEvent
2874//
2875//      Inputs:     event - The event, data - any data associated with the event,
2876//                                              sleep - true (wait for it), false (don't), refCon - the Port
2877//
2878//      Outputs:    Return Code - kIOReturnSuccess, kIOReturnNotOpen
2879//
2880//      Desc:       Not used by this driver.
2881//
2882/****************************************************************************************************/
2883
2884IOReturn AppleUSBIrDADriver::enqueueEvent( UInt32 event, UInt32 data, bool sleep, void *refCon)
2885{
2886    PortInfo_t *port = (PortInfo_t *) refCon;
2887
2888    ELG( data, event, 'EnqE', "enqueueEvent" );
2889
2890    if ( readPortState( port ) & PD_S_ACTIVE )
2891    {
2892	return kIOReturnSuccess;
2893    }
2894
2895    return kIOReturnNotOpen;
2896
2897}/* end enqueueEvent */
2898
2899/****************************************************************************************************/
2900//
2901//      Method:     AppleUSBIrDADriver::dequeueEvent
2902//
2903//      Inputs:     sleep - true (wait for it), false (don't), refCon - the Port
2904//
2905//      Outputs:    Return Code - kIOReturnSuccess, kIOReturnNotOpen
2906//
2907//      Desc:       Not used by this driver.
2908//
2909/****************************************************************************************************/
2910
2911IOReturn AppleUSBIrDADriver::dequeueEvent( UInt32 *event, UInt32 *data, bool sleep, void *refCon )
2912{
2913    PortInfo_t *port = (PortInfo_t *) refCon;
2914
2915    ELG( 0, 0, 'DeqE', "dequeueEvent" );
2916
2917    if ( (event == NULL) || (data == NULL) )
2918	return kIOReturnBadArgument;
2919
2920    if ( readPortState( port ) & PD_S_ACTIVE )
2921    {
2922	return kIOReturnSuccess;
2923    }
2924
2925    return kIOReturnNotOpen;
2926
2927}/* end dequeueEvent */
2928
2929/****************************************************************************************************/
2930//
2931//      Method:     AppleUSBIrDADriver::enqueueData
2932//
2933//      Inputs:     buffer - the data, size - number of bytes, sleep - true (wait for it), false (don't),
2934//                                                                                      refCon - the Port
2935//
2936//      Outputs:    Return Code - kIOReturnSuccess or value returned from watchState, count - bytes transferred,
2937//
2938//      Desc:       enqueueData will attempt to copy data from the specified buffer to
2939//                  the TX queue as a sequence of VALID_DATA events.  The argument
2940//                  bufferSize specifies the number of bytes to be sent.  The actual
2941//                  number of bytes transferred is returned in count.
2942//                  If sleep is true, then this method will sleep until all bytes can be
2943//                  transferred.  If sleep is false, then as many bytes as possible
2944//                  will be copied to the TX queue.
2945//                  Note that the caller should ALWAYS check the transferCount unless
2946//                  the return value was kIOReturnBadArgument, indicating one or more
2947//                  arguments were not valid.  Other possible return values are
2948//                  kIOReturnSuccess if all requirements were met.
2949//
2950/****************************************************************************************************/
2951
2952IOReturn AppleUSBIrDADriver::enqueueData( UInt8 *buffer, UInt32 size, UInt32 *count, bool sleep, void *refCon )
2953{
2954    PortInfo_t  *port = (PortInfo_t *) refCon;
2955    UInt32      state = PD_S_TXQ_LOW_WATER;
2956    IOReturn    rtn = kIOReturnSuccess;
2957
2958    ELG( 0, sleep, 'eqDt', "enqueData" );
2959
2960    if ( fTerminate )
2961	return kIOReturnOffline;
2962
2963    if ( count == NULL || buffer == NULL )
2964	return kIOReturnBadArgument;
2965
2966    *count = 0;
2967
2968    if ( !(readPortState( port ) & PD_S_ACTIVE) )
2969	return kIOReturnNotOpen;
2970
2971    ELG( port->State, size, 'eqDt', "enqueData State" );
2972    LogData( kUSBOut, size, buffer );
2973
2974	/* OK, go ahead and try to add something to the buffer  */
2975    *count = AddtoQueue( &port->TX, buffer, size );
2976    CheckQueues( port );
2977
2978	/* Let the tranmitter know that we have something ready to go   */
2979    SetUpTransmit( );
2980
2981	/* If we could not queue up all of the data on the first pass and   */
2982	/* the user wants us to sleep until it's all out then sleep */
2983
2984    while ( (*count < size) && sleep )
2985    {
2986	state = PD_S_TXQ_LOW_WATER;
2987	rtn = watchState( &state, PD_S_TXQ_LOW_WATER, refCon );
2988	if ( rtn != kIOReturnSuccess )
2989	{
2990	    ELG( 0, rtn, 'EqD-', "enqueueData - interrupted" );
2991	    return rtn;
2992	}
2993
2994	*count += AddtoQueue( &port->TX, buffer + *count, size - *count );
2995	CheckQueues( port );
2996
2997	/* Let the tranmitter know that we have something ready to go.  */
2998
2999	SetUpTransmit( );
3000    }/* end while */
3001
3002    ELG( *count, size, 'enqd', "enqueueData - Enqueue" );
3003
3004    return kIOReturnSuccess;
3005
3006}/* end enqueueData */
3007
3008/****************************************************************************************************/
3009//
3010//      Method:     AppleUSBIrDADriver::dequeueData
3011//
3012//      Inputs:     size - buffer size, min - minimum bytes required, refCon - the Port
3013//
3014//      Outputs:    buffer - data returned, min - number of bytes
3015//                  Return Code - kIOReturnSuccess, kIOReturnBadArgument, kIOReturnNotOpen, or value returned from watchState
3016//
3017//      Desc:       dequeueData will attempt to copy data from the RX queue to the
3018//                  specified buffer.  No more than bufferSize VALID_DATA events
3019//                  will be transferred. In other words, copying will continue until
3020//                  either a non-data event is encountered or the transfer buffer
3021//                  is full.  The actual number of bytes transferred is returned
3022//                  in count.
3023//                  The sleep semantics of this method are slightly more complicated
3024//                  than other methods in this API. Basically, this method will
3025//                  continue to sleep until either min characters have been
3026//                  received or a non data event is next in the RX queue.  If
3027//                  min is zero, then this method never sleeps and will return
3028//                  immediately if the queue is empty.
3029//                  Note that the caller should ALWAYS check the transferCount
3030//                  unless the return value was kIOReturnBadArgument, indicating one or
3031//                  more arguments were not valid.
3032//
3033/****************************************************************************************************/
3034
3035IOReturn AppleUSBIrDADriver::dequeueData( UInt8 *buffer, UInt32 size, UInt32 *count, UInt32 min, void *refCon )
3036{
3037    PortInfo_t  *port = (PortInfo_t *) refCon;
3038    IOReturn    rtn = kIOReturnSuccess;
3039    UInt32      state = 0;
3040
3041    ELG( size, min, 'dqDt', "dequeueData" );
3042
3043	/* Check to make sure we have good arguments.   */
3044    if ( (count == NULL) || (buffer == NULL) || (min > size) )
3045	return kIOReturnBadArgument;
3046
3047	/* If the port is not active then there should not be any chars.    */
3048    *count = 0;
3049    if ( !(readPortState( port ) & PD_S_ACTIVE) )
3050	return kIOReturnNotOpen;
3051
3052	/* Get any data living in the queue.    */
3053    *count = RemovefromQueue( &port->RX, buffer, size );
3054    if (fIrDA)
3055	fIrDA->ReturnCredit( *count );      // return credit when room in the queue
3056
3057    CheckQueues( port );
3058
3059    while ( (min > 0) && (*count < min) )
3060    {
3061	int count_read;
3062
3063	    /* Figure out how many bytes we have left to queue up */
3064	state = 0;
3065
3066	rtn = watchState( &state, PD_S_RXQ_EMPTY, refCon );
3067
3068	if ( rtn != kIOReturnSuccess )
3069	{
3070	    ELG( 0, rtn, 'DqD-', "dequeueData - Interrupted!" );
3071	    LogData( kUSBIn, *count, buffer );
3072	    return rtn;
3073	}
3074	/* Try and get more data starting from where we left off */
3075	count_read = RemovefromQueue( &port->RX, buffer + *count, (size - *count) );
3076	if (fIrDA)
3077	    fIrDA->ReturnCredit(count_read);        // return credit when room in the queue
3078
3079	*count += count_read;
3080	CheckQueues( port );
3081
3082    }/* end while */
3083
3084    LogData( kUSBIn, *count, buffer );
3085
3086    ELG( *count, size, 'deqd', "dequeueData -->Out Dequeue" );
3087
3088    return rtn;
3089
3090}/* end dequeueData */
3091
3092/****************************************************************************************************/
3093//
3094//      Method:     AppleUSBIrDADriver::SetUpTransmit
3095//
3096//      Inputs:
3097//
3098//      Outputs:    return code - true (transmit started), false (transmission already in progress)
3099//
3100//      Desc:       Setup and then start transmisson on the channel specified
3101//
3102/****************************************************************************************************/
3103
3104bool AppleUSBIrDADriver::SetUpTransmit( void )
3105{
3106
3107    size_t      count = 0;
3108    size_t      data_Length, tCount;
3109    UInt8       *TempOutBuffer;
3110
3111    ELG( fPort, fPort->AreTransmitting, 'upTx', "SetUpTransmit" );
3112    XTRACE(kLogSetupTransmit, 0, fPort->AreTransmitting);
3113
3114	//  If we are already in the cycle of transmitting characters,
3115	//  then we do not need to do anything.
3116
3117    if ( fPort->AreTransmitting == TRUE )
3118	return false;
3119
3120	// First check if we can actually do anything, also if IrDA has no room we're done for now
3121
3122    //if ( GetQueueStatus( &fPort->TX ) != queueEmpty )
3123    if (UsedSpaceinQueue(&fPort->TX) > 0)
3124    {
3125	data_Length = fIrDA->TXBufferAvailable();
3126	if ( data_Length == 0 )
3127	{
3128	    return false;
3129	}
3130
3131	if ( data_Length > MAX_BLOCK_SIZE )
3132	{
3133	    data_Length = MAX_BLOCK_SIZE;
3134	}
3135
3136	TempOutBuffer = (UInt8*)IOMalloc( data_Length );
3137	if ( !TempOutBuffer )
3138	{
3139	    ELG( 0, 0, 'STA-', "SetUpTransmit - buffer allocation problem" );
3140	    return false;
3141	}
3142	bzero( TempOutBuffer, data_Length );
3143
3144	// Fill up the buffer with characters from the queue
3145
3146	count = RemovefromQueue( &fPort->TX, TempOutBuffer, data_Length );
3147	ELG( fPort->State, count, ' Tx+', "SetUpTransmit - Sending to IrDA" );
3148
3149	fPort->AreTransmitting = TRUE;
3150	changeState( fPort, PD_S_TX_BUSY, PD_S_TX_BUSY );
3151
3152	tCount = fIrDA->Write( TempOutBuffer, count );      // do the "transmit" -- send to IrCOMM
3153
3154	changeState( fPort, 0, PD_S_TX_BUSY );
3155	fPort->AreTransmitting = false;
3156
3157	IOFree( TempOutBuffer, data_Length );
3158	if ( tCount != count )
3159	{
3160	    ELG( tCount, count, 'IrW-', "SetUpTransmit - IrDA write problem, data has been dropped" );
3161	    return false;
3162	}
3163
3164	// We potentially removed a bunch of stuff from the
3165	// queue, so see if we can free some thread(s)
3166	// to enqueue more stuff.
3167
3168	CheckQueues( fPort );
3169    }
3170
3171    return true;
3172
3173}/* end SetUpTransmit */
3174
3175/****************************************************************************************************/
3176//
3177//      Method:     AppleUSBIrDADriver::StartTransmission
3178//
3179//      Inputs:     control_length - Length of control data
3180//                  control_buffer - Control data
3181//                  data_length - Length of raw data
3182//                  data_buffer - raw data
3183//
3184//      Outputs:    Return code - kIOReturnSuccess
3185//
3186//      Desc:       Start the transmisson. If both control and data length is zero then only
3187//                  the change byte will be sent.
3188//
3189/****************************************************************************************************/
3190
3191IOReturn AppleUSBIrDADriver::StartTransmit(UInt32 control_length, UInt8 *control_buffer, UInt32 data_length, UInt8 *data_buffer)
3192{
3193    IOReturn    ior;
3194    UInt8       changeByte;
3195
3196    ELG( 0, fPort, 'StTx', "StartTransmission" );
3197    check(fWriteActive == false);                   // bail?
3198
3199    // Sending control and data
3200
3201    changeByte = (fBofsCode << 4) | fBaudCode;      // compute new mode byte
3202    fPipeOutBuffer[0] = (changeByte != fLastChangeByte) ? changeByte : 0;   // tell hardware new mode if changed
3203
3204    fLastChangeByte = changeByte;                   // save new mode for next time through
3205
3206    // append the control and data buffers after the mode byte
3207    if ( control_length != 0 )
3208    {
3209	bcopy(control_buffer, &fPipeOutBuffer[1], control_length);
3210	if ( data_length != 0 )
3211	{
3212	    bcopy(data_buffer, &fPipeOutBuffer[control_length+1], data_length);
3213	}
3214    }
3215
3216    // add up the total length to send off to the device
3217    fCount = control_length + data_length + 1;
3218    fpPipeOutMDP->setLength( fCount );
3219
3220//  LogData( kUSBOut, fCount, fPipeOutBuffer );
3221    XTRACE(kLogXmitLen, 0, fCount);
3222    fWriteActive = true;
3223    //ior = fpOutPipe->Write( fpPipeOutMDP, &fWriteCompletionInfo );
3224    ior = fpOutPipe->Write( fpPipeOutMDP, 1000, 1000, &fWriteCompletionInfo );  // 1 second timeouts
3225
3226    return ior;
3227
3228}/* end StartTransmission */
3229
3230/****************************************************************************************************/
3231//
3232//      Method:     AppleUSBIrDADriver::SetStructureDefaults
3233//
3234//      Inputs:     port - the port to set the defaults, Init - Probe time or not
3235//
3236//      Outputs:    None
3237//
3238//      Desc:       Sets the defaults for the specified port structure
3239//
3240/****************************************************************************************************/
3241
3242void AppleUSBIrDADriver::SetStructureDefaults( PortInfo_t *port, bool Init )
3243{
3244    UInt32  tmp;
3245
3246    ELG( 0, 0, 'StSD', "SetStructureDefaults" );
3247    XTRACE(kLogSetStructureDefaults, 0, Init);
3248
3249	/* These are initialized when the port is created and shouldn't be reinitialized. */
3250    if ( Init )
3251    {
3252	port->FCRimage          = 0x00;
3253	port->IERmask           = 0x00;
3254
3255	port->State             = ( PD_S_TXQ_EMPTY | PD_S_TXQ_LOW_WATER | PD_S_RXQ_EMPTY | PD_S_RXQ_LOW_WATER );
3256	port->WatchStateMask    = 0x00000000;
3257 //       port->serialRequestLock = 0;
3258//      port->readActive        = false;
3259    }
3260
3261    port->BaudRate          = kDefaultBaudRate;         // 9600 bps
3262    port->CharLength        = 8;                        // 8 Data bits
3263    port->StopBits          = 2;                        // 1 Stop bit
3264    port->TX_Parity         = 1;                        // No Parity
3265    port->RX_Parity         = 1;                        // --ditto--
3266    port->MinLatency        = false;
3267    port->XONchar           = '\x11';
3268    port->XOFFchar          = '\x13';
3269    port->FlowControl       = 0x00000000;
3270    port->RXOstate          = IDLE_XO;
3271    port->TXOstate          = IDLE_XO;
3272    port->FrameTOEntry      = NULL;
3273
3274//  port->RXStats.BufferSize    = BUFFER_SIZE_DEFAULT;
3275    port->RXStats.BufferSize    = kMaxCirBufferSize;
3276//  port->RXStats.HighWater     = port->RXStats.BufferSize - (DATA_BUFF_SIZE*2);
3277    port->RXStats.HighWater     = (port->RXStats.BufferSize << 1) / 3;
3278    port->RXStats.LowWater      = port->RXStats.HighWater >> 1;
3279
3280//  port->TXStats.BufferSize    = BUFFER_SIZE_DEFAULT;
3281    port->TXStats.BufferSize    = kMaxCirBufferSize;
3282    port->TXStats.HighWater     = (port->RXStats.BufferSize << 1) / 3;
3283    port->TXStats.LowWater      = port->RXStats.HighWater >> 1;
3284
3285    port->FlowControl           = (DEFAULT_AUTO | DEFAULT_NOTIFY);
3286//  port->FlowControl           = DEFAULT_NOTIFY;
3287
3288    port->AreTransmitting   = FALSE;
3289
3290    for ( tmp=0; tmp < (256 >> SPECIAL_SHIFT); tmp++ )
3291	port->SWspecial[ tmp ] = 0;
3292
3293    return;
3294
3295}/* end SetStructureDefaults */
3296
3297/****************************************************************************************************/
3298//
3299//      Method:     AppleUSBIrDADriver::freeRingBuffer
3300//
3301//      Inputs:     Queue - the specified queue to free
3302//
3303//      Outputs:    None
3304//
3305//      Desc:       Frees all resources assocated with the queue, then sets all queue parameters
3306//                  to safe values.
3307//
3308/****************************************************************************************************/
3309
3310void AppleUSBIrDADriver::freeRingBuffer( CirQueue *Queue )
3311{
3312    ELG( 0, Queue, 'f rb', "freeRingBuffer" );
3313    require(Queue->Start, Bogus);
3314
3315    IOFree( Queue->Start, Queue->Size );
3316    CloseQueue( Queue );
3317
3318Bogus:
3319    return;
3320
3321}/* end freeRingBuffer */
3322
3323/****************************************************************************************************/
3324//
3325//      Method:     AppleUSBIrDADriver::allocateRingBuffer
3326//
3327//      Inputs:     Queue - the specified queue to allocate, BufferSize - size to allocate
3328//
3329//      Outputs:    return Code - true (buffer allocated), false (it failed)
3330//
3331//      Desc:       Allocates resources needed by the queue, then sets up all queue parameters.
3332//
3333/****************************************************************************************************/
3334
3335bool AppleUSBIrDADriver::allocateRingBuffer( CirQueue *Queue, size_t BufferSize )
3336{
3337    UInt8       *Buffer;
3338
3339	// Size is ignored and kMaxCirBufferSize, which is 4096, is used.
3340
3341    ELG( 0, BufferSize, 'alrb', "allocateRingBuffer" );
3342    Buffer = (UInt8*)IOMalloc( kMaxCirBufferSize );
3343
3344    InitQueue( Queue, Buffer, kMaxCirBufferSize );
3345
3346    if ( Buffer )
3347	return true;
3348
3349    return false;
3350
3351}/* end allocateRingBuffer */
3352
3353/****************************************************************************************************/
3354//
3355//      Method:     AppleUSBIrDADriver::message
3356//
3357//      Inputs:     type - message type, provider - my provider, argument - additional parameters
3358//
3359//      Outputs:    return Code - kIOReturnSuccess
3360//
3361//      Desc:       Handles IOKit messages.
3362//
3363/****************************************************************************************************/
3364
3365IOReturn AppleUSBIrDADriver::message( UInt32 type, IOService *provider,  void *argument)
3366{
3367
3368    ELG( 0, type, 'mess', "message" );
3369    XTRACE(kLogMessage, type >> 16, (short)type);
3370
3371    switch ( type )
3372    {
3373	case kIOMessageServiceIsTerminated:
3374	    ELG( 0, type, 'mess', "message - kIOMessageServiceIsTerminated" );
3375
3376#ifdef old	// don't need to do stops, will be closed shortly
3377
3378	    if (fIrDA)
3379	    {
3380		int REVIEW_fTerminate;  // this isn't right yet.
3381		stopIrDA();         // stop irda now
3382	    }
3383
3384	    if ( fSessions )
3385	    {
3386		if ( (fPort != NULL) && (fPort->serialRequestLock != 0) )
3387		{
3388//                  changeState( fPort, 0, (UInt32)PD_S_ACTIVE );
3389		}
3390
3391		KUNCUserNotificationDisplayNotice(
3392		0,      // Timeout in seconds
3393		0,      // Flags (for later usage)
3394		"",     // iconPath (not supported yet)
3395		"",     // soundPath (not supported yet)
3396		"",     // localizationPath (not supported  yet)
3397		"USB IrDA Unplug Notice",       // the header
3398		"The USB IrDA Pod has been unplugged while an Application was still active. This can result in loss of data.",
3399		"OK");
3400	    } else {
3401		if ( fpInterface )
3402		{
3403		    fpInterface->close( this );
3404		    fpInterface->release();
3405		    fpInterface = NULL;
3406		}
3407	    }
3408
3409	    fTerminate = true;      // we're being terminated (unplugged)
3410#endif // old
3411
3412	    /* We need to disconnect the user client interface */
3413	    messageClients(kIrDACallBack_Unplug, 0, 1);
3414	    break;
3415
3416	case kIOMessageServiceIsSuspended:
3417	    ELG( 0, type, 'mess', "message - kIOMessageServiceIsSuspended" );
3418	    break;
3419
3420	case kIOMessageServiceIsResumed:
3421	    ELG( 0, type, 'mess', "message - kIOMessageServiceIsResumed" );
3422	    break;
3423
3424	case kIOMessageServiceIsRequestingClose:
3425	    ELG( 0, type, 'mess', "message - kIOMessageServiceIsRequestingClose" );
3426	    break;
3427
3428	case kIOMessageServiceWasClosed:
3429	    ELG( 0, type, 'mess', "message - kIOMessageServiceWasClosed" );
3430	    break;
3431
3432	case kIOMessageServiceBusyStateChange:
3433	    ELG( 0, type, 'mess', "message - kIOMessageServiceBusyStateChange" );
3434	    break;
3435
3436	case kIOUSBMessagePortHasBeenResumed:
3437	    ELG( 0, type, 'mess', "message - kIOUSBMessagePortHasBeenResumed" );
3438	    DebugLog("message = kIOUSBMessagePortHasBeenResumed" );
3439
3440	    if ( !fIrDAOn )         // We tried to suspend, but it failed
3441	    {
3442		fSuspendFail = true;
3443		ELG( 0, 0, 'msS-', "message - Suspend device really failed" );
3444	    }
3445	    else {                  // we're trying to resume, so start irda
3446		if ( !startIrDA() )
3447		{
3448		    fIrDAOn = false;
3449		    fTerminate = true;
3450		    IOLog("AppleUSBIrDADriver: message - startIrDA failed\n" );
3451		} else {
3452		    ELG( 0, 0, 'msc+', "message - startIrDA successful" );
3453		    //IOLog("AppleUSBIrDADriver: message - startIrDA successful\n" );
3454		}
3455	    }
3456	    break;
3457
3458	case kIOUSBMessageHubResumePort:
3459	    ELG( 0, type, 'mess', "message - kIOUSBMessageHubResumePort" );
3460	    DebugLog("message = kIOUSBMessageHubResumePort" );
3461
3462	    if ( !fIrDAOn )         // Means the suspend failed
3463	    {
3464		fSuspendFail = true;
3465	    }
3466	    else {                  // we're being asked to resume
3467		if ( !startIrDA() )
3468		{
3469		    ELG( 0, 0, 'msc-', "message - startIrDA failed" );
3470#if 0
3471		    KUNCUserNotificationDisplayNotice(
3472		    0,      // Timeout in seconds
3473		    0,      // Flags (for later usage)
3474		    "",     // iconPath (not supported yet)
3475		    "",     // soundPath (not supported yet)
3476		    "",     // localizationPath (not supported  yet)
3477		    "USB IrDA Problem Notice",      // the header
3478		    "The USB IrDA Pod has experienced difficulties. To continue either replug the device (if external) or restart the computer",
3479		    "OK");
3480#endif
3481
3482		    fIrDAOn = false;        // We're basically sol at this point
3483		    fTerminate = true;
3484		} else {
3485		    ELG( 0, 0, 'msc+', "message - createSerialStream successful" );
3486		    //IOLog("AppleUSBIrDADriver: message - createSerialStream successful\n" );
3487		}
3488	    }
3489
3490	default:
3491	    ELG( 0, type, 'mess', "message - unknown message" );
3492	    break;
3493    }
3494
3495    return kIOReturnSuccess;
3496}
3497
3498/****************************************************************************************************/
3499//
3500//      Method:     AppleUSBIrDADriver::readPortState
3501//
3502//      Inputs:     port - the specified port
3503//
3504//      Outputs:    returnState - current state of the port
3505//
3506//      Desc:       Reads the current Port->State.
3507//
3508/****************************************************************************************************/
3509
3510UInt32 AppleUSBIrDADriver::readPortState( PortInfo_t *port )
3511{
3512    UInt32              returnState;
3513
3514//  ELG( 0, port, 'rPSt', "readPortState" );
3515
3516    IOLockLock( port->serialRequestLock );
3517
3518    returnState = port->State;
3519
3520    IOLockUnlock( port->serialRequestLock);
3521
3522//  ELG( returnState, 0, 'rPS-', "readPortState" );
3523
3524    return returnState;
3525
3526}/* end readPortState */
3527
3528/****************************************************************************************************/
3529//
3530//      Method:     AppleUSBIrDADriver::changeState
3531//
3532//      Inputs:     port - the specified port, state - new state, mask - state mask (the specific bits)
3533//
3534//      Outputs:    None
3535//
3536//      Desc:       Change the current Port->State to state using the mask bits.
3537//                  if mask = 0 nothing is changed.
3538//                  delta contains the difference between the new and old state taking the
3539//                  mask into account and it's used to wake any waiting threads as appropriate.
3540//
3541/****************************************************************************************************/
3542
3543void AppleUSBIrDADriver::changeState( PortInfo_t *port, UInt32 state, UInt32 mask )
3544{
3545    UInt32              delta;
3546
3547//  ELG( state, mask, 'chSt', "changeState" );
3548
3549    IOLockLock( port->serialRequestLock );
3550    state = (port->State & ~mask) | (state & mask); // compute the new state
3551    delta = state ^ port->State;                    // keep a copy of the diffs
3552    port->State = state;
3553
3554	// Wake up all threads asleep on WatchStateMask
3555
3556    if ( delta & port->WatchStateMask )
3557    {
3558	thread_wakeup_with_result( &port->WatchStateMask, THREAD_RESTART );
3559    }
3560
3561    IOLockUnlock( port->serialRequestLock );
3562
3563    ELG( port->State, delta, 'chSt', "changeState - exit" );
3564    return;
3565
3566}/* end changeState */
3567
3568/****************************************************************************************************/
3569//
3570//      Method:     AppleUSBIrDADriver::privateWatchState
3571//
3572//      Inputs:     port - the specified port, state - state watching for, mask - state mask (the specific bits)
3573//
3574//      Outputs:    IOReturn - kIOReturnSuccess, kIOReturnIOError or kIOReturnIPCError
3575//
3576//      Desc:       Wait for the at least one of the state bits defined in mask to be equal
3577//                  to the value defined in state. Check on entry then sleep until necessary.
3578//                  A return value of kIOReturnSuccess means that at least one of the port state
3579//                  bits specified by mask is equal to the value passed in by state.  A return
3580//                  value of kIOReturnIOError indicates that the port went inactive.  A return
3581//                  value of kIOReturnIPCError indicates sleep was interrupted by a signal.
3582//
3583/****************************************************************************************************/
3584
3585IOReturn AppleUSBIrDADriver::privateWatchState( PortInfo_t *port, UInt32 *state, UInt32 mask )
3586{
3587    unsigned            watchState, foundStates;
3588    bool                autoActiveBit   = false;
3589    IOReturn            rtn             = kIOReturnSuccess;
3590
3591//    ELG( mask, *state, 'wsta', "privateWatchState" );
3592
3593    watchState              = *state;
3594    IOLockLock( port->serialRequestLock );
3595
3596	// hack to get around problem with carrier detection
3597
3598    if ( *state | 0x40 )    /// mlj ??? PD_S_RXQ_FULL?
3599    {
3600	port->State |= 0x40;
3601    }
3602
3603    if ( !(mask & (PD_S_ACQUIRED | PD_S_ACTIVE)) )
3604    {
3605	watchState &= ~PD_S_ACTIVE; // Check for low PD_S_ACTIVE
3606	mask       |=  PD_S_ACTIVE; // Register interest in PD_S_ACTIVE bit
3607	autoActiveBit = true;
3608    }
3609
3610    for (;;)
3611    {
3612	    // Check port state for any interesting bits with watchState value
3613	    // NB. the '^ ~' is a XNOR and tests for equality of bits.
3614
3615	foundStates = (watchState ^ ~port->State) & mask;
3616
3617	if ( foundStates )
3618	{
3619	    *state = port->State;
3620	    if ( autoActiveBit && (foundStates & PD_S_ACTIVE) )
3621	    {
3622		rtn = kIOReturnIOError;
3623	    } else {
3624		rtn = kIOReturnSuccess;
3625	    }
3626//          ELG( rtn, foundStates, 'FndS', "privateWatchState - foundStates" );
3627	    break;
3628	}
3629
3630	    // Everytime we go around the loop we have to reset the watch mask.
3631	    // This means any event that could affect the WatchStateMask must
3632	    // wakeup all watch state threads.  The two events are an interrupt
3633	    // or one of the bits in the WatchStateMask changing.
3634
3635	port->WatchStateMask |= mask;
3636
3637	    // note: Interrupts need to be locked out completely here,
3638	    // since as assertwait is called other threads waiting on
3639	    // &port->WatchStateMask will be woken up and spun through the loop.
3640	    // If an interrupt occurs at this point then the current thread
3641	    // will end up waiting with a different port state than assumed
3642	    //  -- this problem was causing dequeueData to wait for a change in
3643	    // PD_E_RXQ_EMPTY to 0 after an interrupt had already changed it to 0.
3644
3645	assert_wait( &port->WatchStateMask, true ); /* assert event */
3646
3647	IOLockUnlock( port->serialRequestLock );
3648	rtn = thread_block( 0 );         /* block ourselves */
3649	IOLockLock( port->serialRequestLock );
3650
3651	if ( rtn == THREAD_RESTART )
3652	{
3653	    continue;
3654	} else {
3655	    rtn = kIOReturnIPCError;
3656	    break;
3657	}
3658    }/* end for */
3659
3660	    // As it is impossible to undo the masking used by this
3661	    // thread, we clear down the watch state mask and wakeup
3662	    // every sleeping thread to reinitialize the mask before exiting.
3663
3664    port->WatchStateMask = 0;
3665
3666    thread_wakeup_with_result( &port->WatchStateMask, THREAD_RESTART );
3667    IOLockUnlock( port->serialRequestLock);
3668
3669    //    ELG( rtn, *state, 'wEnd', "privateWatchState end" );
3670
3671    return rtn;
3672
3673}/* end privateWatchState */
3674
3675#pragma mark -- hardware workaround
3676
3677/****************************************************************************************************/
3678//
3679// Workaround: (re)send the device configuration to put the KC hardware back into a known state
3680//
3681/****************************************************************************************************/
3682
3683void AppleUSBIrDADriver::Workaround(void)
3684{
3685    IOReturn        rc;
3686    IOUSBDevRequest *request;
3687
3688    XTRACE(kLogWorkAround, 0, 0);
3689    //DebugLog("AppleUSBIrDA: workaround called");
3690
3691    request = (IOUSBDevRequest*)IOMalloc( sizeof(IOUSBDevRequest) );
3692    require(request, Failed);
3693    bzero( request, sizeof(IOUSBDevRequest) );
3694    // allocate pData here if needed
3695
3696    //request->bmRequestType = USBmakebmRequestType(kUSBOut, kUSBClass, kUSBInterface);
3697
3698    request->bmRequestType = USBmakebmRequestType(kUSBOut, kUSBStandard, kUSBDevice);   // long macro for zero
3699    request->bRequest = kUSBRqSetConfig;        // 9 - set configuration
3700    request->wValue = 1;                        // new configuration #1
3701    request->wIndex = 0;
3702    request->wLength = 0;
3703
3704    check(request->bmRequestType == 0);
3705    check(request->bRequest == 9);      // sanity eludes
3706
3707    fRequestCompletionInfo.target = this;
3708    fRequestCompletionInfo.action = workAroundComplete;
3709    fRequestCompletionInfo.parameter = request;
3710
3711    rc = fpDevice->DeviceRequest(request, &fRequestCompletionInfo);
3712    check(rc == kIOReturnSuccess);
3713
3714Failed:
3715    return;
3716}/* end Workaround */
3717
3718
3719/****************************************************************************************************/
3720//
3721//      Function:   AppleUSBCDCDriver::workAroundComplete
3722//
3723//      Inputs:     obj - me, param - request block
3724//                  rc - return code, remaining - what's left
3725//
3726//      Outputs:    None
3727//
3728/****************************************************************************************************/
3729
3730void AppleUSBIrDADriver::workAroundComplete(void *obj, void *param, IOReturn rc, UInt32 remaining )
3731{
3732    //AppleUSBIrDADriver    *me = (AppleUSBIrDADriver*)obj;
3733    IOUSBDevRequest     *request = (IOUSBDevRequest*)param;
3734    UInt16              dataLen;
3735
3736    XTRACE(kLogWorkAroundComplete, 0, 0);
3737    require(request, Fail);
3738
3739    dataLen = request->wLength;
3740    if ((dataLen != 0) && (request->pData)) {   // doesn't happen here
3741	IOFree(request->pData, dataLen);
3742    }
3743    IOFree(request, sizeof(IOUSBDevRequest));
3744
3745Fail:
3746    return;
3747}   /* end workAroundComplete */
3748
3749
3750#pragma mark -- Glue
3751/****************************************************************************************************/
3752// Glue to call the actual USB driver over the IOSerialStreamSync hurdle
3753//
3754// todo: see if dynamic cast is slow, if so just check for AppleUSBIrDADriver
3755// once at attach time and maybe save a copy of it.
3756/****************************************************************************************************/
3757#undef super
3758#define super AppleIrDASerial
3759    OSDefineMetaClassAndStructors( AppleUSBIrDA, AppleIrDASerial );
3760
3761bool
3762AppleUSBIrDA::attach(AppleUSBIrDADriver *provider)
3763{
3764    // any reason not to do the type check for AppleUSBIrDADriver at compile time?
3765    return super::attach(provider);
3766}
3767
3768void
3769AppleUSBIrDA::Add_RXBytes( UInt8 *Buffer, size_t Size )
3770{
3771    AppleUSBIrDADriver *driver;
3772    driver = OSDynamicCast(AppleUSBIrDADriver, fProvider);
3773    if (driver)
3774	return driver->Add_RXBytes(Buffer, Size);
3775}
3776
3777SInt16
3778AppleUSBIrDA::SetBofCount(SInt16 bof_count)
3779{
3780    AppleUSBIrDADriver *driver;
3781    driver = OSDynamicCast(AppleUSBIrDADriver, fProvider);
3782    if (driver)
3783	return driver->SetBofCount(bof_count);
3784    else
3785	return -1;
3786}
3787
3788UInt16
3789AppleUSBIrDA::SetSpeed(UInt32 brate)
3790{
3791    AppleUSBIrDADriver *driver;
3792    driver = OSDynamicCast(AppleUSBIrDADriver, fProvider);
3793    if (driver)
3794	return driver->SetSpeed(brate);
3795    else
3796	return 0;
3797}
3798
3799bool
3800AppleUSBIrDA::SetUpTransmit( void )
3801{
3802    AppleUSBIrDADriver *driver;
3803    driver = OSDynamicCast(AppleUSBIrDADriver, fProvider);
3804    if (driver)
3805	return driver->SetUpTransmit();
3806    else
3807	return false;
3808}
3809
3810IOReturn
3811AppleUSBIrDA::StartTransmit( UInt32 control_length, UInt8 *control_buffer, UInt32 data_length, UInt8 *data_buffer )
3812{
3813    AppleUSBIrDADriver *driver;
3814    driver = OSDynamicCast(AppleUSBIrDADriver, fProvider);
3815    if (driver)
3816	return driver->StartTransmit(control_length, control_buffer, data_length, data_buffer);
3817    else
3818	return -1;
3819}
3820
3821USBIrDAQoS *
3822AppleUSBIrDA::GetIrDAQoS( void )
3823{
3824    AppleUSBIrDADriver *driver;
3825    driver = OSDynamicCast(AppleUSBIrDADriver, fProvider);
3826    if (driver)
3827	return driver->GetIrDAQoS();
3828    else
3829	return NULL;
3830}
3831
3832IrDAComm *
3833AppleUSBIrDA::GetIrDAComm( void )
3834{
3835    AppleUSBIrDADriver *driver;
3836    driver = OSDynamicCast(AppleUSBIrDADriver, fProvider);
3837    if (driver)
3838	return driver->GetIrDAComm();
3839    else
3840	return NULL;
3841}
3842
3843void
3844AppleUSBIrDA::GetIrDAStatus( IrDAStatus *status )
3845{
3846    AppleUSBIrDADriver *driver;
3847    driver = OSDynamicCast(AppleUSBIrDADriver, fProvider);
3848    if (driver)
3849	return driver->GetIrDAStatus(status);
3850}
3851
3852IOReturn
3853AppleUSBIrDA::SetIrDAUserClientState( bool IrDAOn )
3854{
3855    AppleUSBIrDADriver *driver;
3856    driver = OSDynamicCast(AppleUSBIrDADriver, fProvider);
3857    if (driver)
3858	return driver->SetIrDAUserClientState(IrDAOn);
3859    else
3860	return -1;
3861}
3862
3863