/* Copyright (c) 2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* AppleSCCIrDA.cpp - MacOSX implementation of SCC IrDA Port Driver. */ #include /* UINT_MAX */ #include #include #include #include #include #include #include #include #include #include #include #include #include "AppleSCCIrDA.h" #include "IrDAComm.h" #include "IrDAUser.h" #include "IrDALog.h" #include "IrDADebugging.h" static IrDAglobals g; /**** Instantiate the globals ****/ #ifdef Trace_SCCSerial // running w/debug AppleSCCSerial driver #define IRDLOG_HACK (PD_DATA_LONG | PD_OP(100)) // send irdalog to SCCSerial driver #endif #if (hasTracing > 0 && hasAppleSCCIrDATracing > 0) enum tracecodes { kLoginit = 1, kLogprob, kLogatch, kLogdtch, kLogstrt, kLogfree, kLogstop, kLogAdRB, kLogSbof, kLogStSp, kLogSSpminus, kLogSSsplus, kLogGIrS, kLogSICS, kLogCIrS, kLogSIrS, kLogstcn, kLogstrminus, kLogstbr, kLogstar, kLogeSCC, kLogeSCH, kLogeSCminus, kLogeSCK, kLogdSCC, kLogdSCH, kLogdSCminus, kLogdSCK, kLogsnBd, kLogsnBminus, kLogsnCd, kLogsCeminus, kLogsCtC, kLogsCnminus, kLogsCnplus, kLogsCdminus, kLoggFWV, kLoggFdplus, kLogrDTR, kLogklIO, kLogklRd, kLogklTd, kLogcrRX, kLogcREminus, kLogcrRplus, kLogcrRminus, kLogcrTX, kLogcTEminus, kLogcrTplus, kLogcrTminus, kLogsuDv, kLogsDpminus, kLogsDeminus, kLogsDdminus, kLogsDiminus, kLogsDsminus, kLogsDaminus, kLogcDev, kLogcDiminus, kLogcDominus, kLogcDuminus, kLogcDaminus, kLogcDIminus, kLogcDFminus, kLogcDvplus, kLogcDvminus, kLogcSSt, kLogacqP, kLogacqS, kLogacqplus, kLogacqminus, kLogrelP, kLogstSt, kLogstSm, kLogstsa, kLogstma, kLoggtSt, kLogexEv, kLogee01, kLogee02, kLogee03, kLogee04, kLogee05, kLogee06, kLogee07, kLogee08, kLogee09, kLogee10, kLogee11, kLogee12, kLogee13, kLogee14, kLogee15, kLogee16, kLogee17, kLogee18, kLogee19, kLogee20, kLogee21, kLogee22, kLogee23, kLogee24, kLogee25, kLogee26, kLogeexminus, kLogreEv, kLogre01, kLogre02, kLogre03, kLogre04, kLogre05, kLogre06, kLogre07, kLogre08, kLogre09, kLogre10, kLogre11, kLogre12, kLogre13, kLogre14, kLogre15, kLogre16, kLogre17, kLogre18, kLogre19, kLogre20, kLogre21, kLogre22, kLogre23, kLogre24, kLogreeminus, kLogeqDt, kLogeDWminus, kLogeDWplus, kLogeDfminus, kLogeDdminus, kLogdqDt, kLogdDpminus, kLogdqRt, kLogdqDplus, kLogSUTm, kLogSIWminus, kLogSIWplus, kLogstTx, kLogStTn, kLogfrRB, kLogalRB, kLogmess, kLogms01, kLogms02, kLogms03, kLogms04, kLogms05, kLogms06, kLogmesminus, kLogpIpB, kLogpImminus, kLogpISR, kLogpStI, kLogpStB, kLogpStd, kLogpSIminus, kLogpSCminus, kLogpSEminus, kLogpStp, kLogpSte, kLogpIFR, kLogpIRt, kLogPBFT, kLogrxLp, kLogrxok, kLogrxDminus, kLogrxLminus, kLogrxKl, kLogtxLp, kLogtxRs, kLogtxDt, kLogtxSE, kLogtxLminus, kLogtxKl, kLogXmitCount, kLogSpeedChangeThread, kLogTxThread, kLogTxThreadDeferred, kLogTxThreadResumed, kLogRxThread, kLogRxThreadResumed, kLogRxThreadSleeping, kLogRxThreadGotData, kLogSetStructureDefaults, kLogAcquirePort, kLogReleasePort, kLogSetState1, kLogSetState2, kLogGetState, kLogWatchState, kLogWatchState1, kLogWatchState2, kLogExecEvent, kLogExecEventData, kLogReqEvent, kLogReqEventData, kLogChangeStateBits, kLogChangeStateMask, kLogChangeStateDelta, kLogChangeStateNew, kLogInitForPM, kLogInitialPowerState, kLogSetPowerState }; static EventTraceCauseDesc gTraceEvents[] = { {kLoginit, "AppleSCCIrDA: init"}, {kLogprob, "AppleSCCIrDA: probe"}, {kLogatch, "AppleSCCIrDA: attach"}, {kLogdtch, "AppleSCCIrDA: detach"}, {kLogstrt, "AppleSCCIrDA: start"}, {kLogfree, "AppleSCCIrDA: free"}, {kLogstop, "AppleSCCIrDA: stop"}, {kLogAdRB, "AppleSCCIrDA: Add_RXBytes"}, {kLogSbof, "AppleSCCIrDA: SetBofCount"}, {kLogStSp, "AppleSCCIrDA: SetSpeed"}, {kLogSSpminus, "AppleSCCIrDA: SetSpeed - Unsupported baud rate"}, {kLogSSsplus, "AppleSCCIrDA: SetSpeed - sendCommand successful"}, {kLogGIrS, "AppleSCCIrDA: GetIrDAStatus"}, {kLogSICS, "AppleSCCIrDA: SetIrDAUserClientState"}, {kLogCIrS, "AppleSCCIrDA: CheckIrDAState"}, {kLogSIrS, "AppleSCCIrDA: SetIrDAState"}, {kLogstcn, "AppleSCCIrDA: SetIrDAState - successful (IrDA On)"}, {kLogstrminus, "AppleSCCIrDA: SetIrDAState - configureDevice failed"}, {kLogstbr, "AppleSCCIrDA: SetIrDAState - before releasePort"}, {kLogstar, "AppleSCCIrDA: SetIrDAState - after releasePort"}, {kLogeSCC, "AppleSCCIrDA: enableSCC"}, {kLogeSCH, "AppleSCCIrDA: enableSCC - Heathrow"}, {kLogeSCminus, "AppleSCCIrDA: enableSCC - no Heathrow or Keylargo"}, {kLogeSCK, "AppleSCCIrDA: enableSCC - Keylargo"}, {kLogdSCC, "AppleSCCIrDA: disable SCC"}, {kLogdSCH, "AppleSCCIrDA: disable SCC - heathrow"}, {kLogdSCminus, "AppleSCCIrDA: disable SCC - no heathrow or keylargo"}, {kLogdSCK, "AppleSCCIrDA: disable SCC - keylargo"}, {kLogsnBd, "AppleSCCIrDA: sendBaud"}, {kLogsnBminus, "AppleSCCIrDA: sendBaud - execute event (baud rate) failed"}, {kLogsnCd, "AppleSCCIrDA: sendCommand"}, {kLogsCeminus, "AppleSCCIrDA: sendCommand - enqueue data failed"}, {kLogsCtC, "AppleSCCIrDA: sendCommand - dequeue data"}, {kLogsCnminus, "AppleSCCIrDA: sendCommand - dequeue data, no data returned"}, {kLogsCnplus, "AppleSCCIrDA: sendCommand - dequeue data, successful"}, {kLogsCdminus, "AppleSCCIrDA: sendCommand - dequeue data failed"}, {kLoggFWV, "AppleSCCIrDA: getFIReWorksVersion"}, {kLoggFdplus, "AppleSCCIrDA: getFIReWorksVersion - dequeue data (getversion) successful"}, {kLogrDTR, "AppleSCCIrDA: resetDTR"}, {kLogklIO, "AppleSCCIrDA: killIO"}, {kLogklRd, "AppleSCCIrDA: killIO - RX saved by deadman"}, {kLogklTd, "AppleSCCIrDA: killIO - TX saved by deadman"}, {kLogcrRX, "AppleSCCIrDA: createRX"}, {kLogcREminus, "AppleSCCIrDA: createRX - timerEventSource failed"}, {kLogcrRplus, "AppleSCCIrDA: createRX - successful"}, {kLogcrRminus, "AppleSCCIrDA: createRX - failed"}, {kLogcrTX, "AppleSCCIrDA: createTX"}, {kLogcTEminus, "AppleSCCIrDA: createTX - timerEventSource failed"}, {kLogcrTplus, "AppleSCCIrDA: createTX - successful"}, {kLogcrTminus, "AppleSCCIrDA: createTX - failed"}, {kLogsuDv, "AppleSCCIrDA: setupDevice"}, {kLogsDpminus, "AppleSCCIrDA: setupDevice - acquirePort failed"}, {kLogsDeminus, "AppleSCCIrDA: setupDevice - enableSCC failed"}, {kLogsDdminus, "AppleSCCIrDA: setupDevice - execute event (data size) failed"}, {kLogsDiminus, "AppleSCCIrDA: setupDevice - execute event (data integrity) failed"}, {kLogsDsminus, "AppleSCCIrDA: setupDevice - execute event (stop bits) failed"}, {kLogsDaminus, "AppleSCCIrDA: setupDevice - execute event (active) failed"}, {kLogcDev, "AppleSCCIrDA: configureDevice"}, {kLogcDiminus, "AppleSCCIrDA: configureDevice - input buffer allocation failed"}, {kLogcDominus, "AppleSCCIrDA: configureDevice - output buffer allocation failed"}, {kLogcDuminus, "AppleSCCIrDA: configureDevice - in use buffer allocation failed"}, {kLogcDaminus, "AppleSCCIrDA: configureDevice - allocate ring buffer failed"}, {kLogcDIminus, "AppleSCCIrDA: configureDevice - IrDA initialize failed"}, {kLogcDFminus, "AppleSCCIrDA: configureDevice - getFIReWorksVersion failed"}, {kLogcDvplus, "AppleSCCIrDA: configureDevice - successful"}, {kLogcDvminus, "AppleSCCIrDA: configureDevice - failed"}, {kLogcSSt, "AppleSCCIrDA: createSerialStream"}, {kLogacqP, "AppleSCCIrDA: acquirePort"}, {kLogacqS, "AppleSCCIrDA: acquirePort - returned kIOReturnExclusiveAccess"}, {kLogacqplus, "AppleSCCIrDA: acquirePort - successful"}, {kLogacqminus, "AppleSCCIrDA: acquirePort - failed"}, {kLogrelP, "AppleSCCIrDA: releasePort"}, {kLogstSt, "AppleSCCIrDA: setState - state="}, {kLogstSm, "AppleSCCIrDA: setState - mask="}, {kLogstsa, "AppleSCCIrDA: setState - after change, state="}, {kLogstma, "AppleSCCIrDA: setState - after change, mask="}, {kLoggtSt, "AppleSCCIrDA: getState - state="}, {kLogexEv, "AppleSCCIrDA: executeEvent"}, {kLogee01, "AppleSCCIrDA: executeEvent - PD_RS232_E_XON_BYTE, data="}, {kLogee02, "AppleSCCIrDA: executeEvent - PD_RS232_E_XOFF_BYTE, data="}, {kLogee03, "AppleSCCIrDA: executeEvent - PD_E_SPECIAL_BYTE, data="}, {kLogee04, "AppleSCCIrDA: executeEvent - PD_E_VALID_DATA_BYTE, data="}, {kLogee05, "AppleSCCIrDA: executeEvent - PD_E_FLOW_CONTROL, data="}, {kLogee06, "AppleSCCIrDA: executeEvent - PD_E_ACTIVE, data="}, {kLogee07, "AppleSCCIrDA: executeEvent - PD_E_DATA_LATENCY, data="}, {kLogee08, "AppleSCCIrDA: executeEvent - PD_RS232_E_MIN_LATENCY, data="}, {kLogee09, "AppleSCCIrDA: executeEvent - PD_E_DATA_INTEGRITY, data="}, {kLogee10, "AppleSCCIrDA: executeEvent - PD_E_DATA_RATE, data="}, {kLogee11, "AppleSCCIrDA: executeEvent - PD_E_DATA_SIZE, data="}, {kLogee12, "AppleSCCIrDA: executeEvent - PD_RS232_E_STOP_BITS, data="}, {kLogee13, "AppleSCCIrDA: executeEvent - PD_E_RXQ_FLUSH, data="}, {kLogee14, "AppleSCCIrDA: executeEvent - PD_E_RX_DATA_INTEGRITY, data="}, {kLogee15, "AppleSCCIrDA: executeEvent - PD_E_RX_DATA_RATE, data="}, {kLogee16, "AppleSCCIrDA: executeEvent - PD_E_RX_DATA_SIZE, data="}, {kLogee17, "AppleSCCIrDA: executeEvent - PD_RS232_E_RX_STOP_BITS, data="}, {kLogee18, "AppleSCCIrDA: executeEvent - PD_E_TXQ_FLUSH, data="}, {kLogee19, "AppleSCCIrDA: executeEvent - PD_RS232_E_LINE_BREAK, data="}, {kLogee20, "AppleSCCIrDA: executeEvent - PD_E_DELAY, data="}, {kLogee21, "AppleSCCIrDA: executeEvent - PD_E_RXQ_SIZE, data="}, {kLogee22, "AppleSCCIrDA: executeEvent - PD_E_TXQ_SIZE, data="}, {kLogee23, "AppleSCCIrDA: executeEvent - PD_E_RXQ_HIGH_WATER, data="}, {kLogee24, "AppleSCCIrDA: executeEvent - PD_E_RXQ_LOW_WATER, data="}, {kLogee25, "AppleSCCIrDA: executeEvent - PD_E_TXQ_HIGH_WATER, data="}, {kLogee26, "AppleSCCIrDA: executeEvent - PD_E_TXQ_LOW_WATER, data="}, {kLogeexminus, "AppleSCCIrDA: executeEvent - unrecognized event, data="}, {kLogreEv, "AppleSCCIrDA: requestEvent"}, {kLogre01, "AppleSCCIrDA: requestEvent - PD_E_ACTIVE, data="}, {kLogre02, "AppleSCCIrDA: requestEvent - PD_E_FLOW_CONTROL, data="}, {kLogre03, "AppleSCCIrDA: requestEvent - PD_E_DELAY, data="}, {kLogre04, "AppleSCCIrDA: requestEvent - PD_E_DATA_LATENCY, data="}, {kLogre05, "AppleSCCIrDA: requestEvent - PD_E_TXQ_SIZE, data="}, {kLogre06, "AppleSCCIrDA: requestEvent - PD_E_RXQ_SIZE, data="}, {kLogre07, "AppleSCCIrDA: requestEvent - PD_E_TXQ_LOW_WATER, data="}, {kLogre08, "AppleSCCIrDA: requestEvent - PD_E_RXQ_LOW_WATER, data="}, {kLogre09, "AppleSCCIrDA: requestEvent - PD_E_TXQ_HIGH_WATER, data="}, {kLogre10, "AppleSCCIrDA: requestEvent - PD_E_RXQ_HIGH_WATER, data="}, {kLogre11, "AppleSCCIrDA: requestEvent - PD_E_TXQ_AVAILABLE, data="}, {kLogre12, "AppleSCCIrDA: requestEvent - PD_E_RXQ_AVAILABLE, data="}, {kLogre13, "AppleSCCIrDA: requestEvent - PD_E_DATA_RATE, data="}, {kLogre14, "AppleSCCIrDA: requestEvent - PD_E_RX_DATA_RATE, data="}, {kLogre15, "AppleSCCIrDA: requestEvent - PD_E_DATA_SIZE, data="}, {kLogre16, "AppleSCCIrDA: requestEvent - PD_E_RX_DATA_SIZE, data="}, {kLogre17, "AppleSCCIrDA: requestEvent - PD_E_DATA_INTEGRITY, data="}, {kLogre18, "AppleSCCIrDA: requestEvent - PD_E_RX_DATA_INTEGRITY, data="}, {kLogre19, "AppleSCCIrDA: requestEvent - PD_RS232_E_STOP_BITS, data="}, {kLogre20, "AppleSCCIrDA: requestEvent - PD_RS232_E_RX_STOP_BITS, data="}, {kLogre21, "AppleSCCIrDA: requestEvent - PD_RS232_E_XON_BYTE, data="}, {kLogre22, "AppleSCCIrDA: requestEvent - PD_RS232_E_XOFF_BYTE, data="}, {kLogre23, "AppleSCCIrDA: requestEvent - PD_RS232_E_LINE_BREAK, data="}, {kLogre24, "AppleSCCIrDA: requestEvent - PD_RS232_E_MIN_LATENCY, data="}, {kLogreeminus, "AppleSCCIrDA: requestEvent - unrecognized event, data="}, {kLogeqDt, "AppleSCCIrDA: enqueData"}, {kLogeDWminus, "AppleSCCIrDA: enqueueData - IrDA write problem, data has been dropped"}, {kLogeDWplus, "AppleSCCIrDA: enqueueData - data successfully handed to IrDA"}, {kLogeDfminus, "AppleSCCIrDA: enqueueData - frame allocation failed"}, {kLogeDdminus, "AppleSCCIrDA: enqueueData - buffer allocation failed"}, {kLogdqDt, "AppleSCCIrDA: dequeueData"}, {kLogdDpminus, "AppleSCCIrDA: dequeueData - parameter error"}, {kLogdqRt, "AppleSCCIrDA: dequeueData - read interrupted"}, {kLogdqDplus, "AppleSCCIrDA: dequeueData - successful"}, {kLogSUTm, "AppleSCCIrDA: SetUpTransmit"}, {kLogSIWminus, "AppleSCCIrDA: SetUpTransmit - IrDA write problem, data has been dropped"}, {kLogSIWplus, "AppleSCCIrDA: SetUpTransmit - data successfully handed to IrDA"}, {kLogstTx, "AppleSCCIrDA: StartTransmit"}, {kLogStTn, "AppleSCCIrDA: StartTransmit - no data (count = 0)"}, {kLogfrRB, "AppleSCCIrDA: freeRingBuffer"}, {kLogalRB, "AppleSCCIrDA: allocateRingBuffer"}, {kLogmess, "AppleSCCIrDA: message"}, {kLogms01, "AppleSCCIrDA: message - kIOMessageServiceIsTerminated"}, {kLogms02, "AppleSCCIrDA: message - kIOMessageServiceIsSuspended"}, {kLogms03, "AppleSCCIrDA: message - kIOMessageServiceIsResumed"}, {kLogms04, "AppleSCCIrDA: message - kIOMessageServiceIsRequestingClose"}, {kLogms05, "AppleSCCIrDA: message - kIOMessageServiceWasClosed"}, {kLogms06, "AppleSCCIrDA: message - kIOMessageServiceBusyStateChange"}, {kLogmesminus, "AppleSCCIrDA: message - unknown message"}, {kLogpIpB, "AppleSCCIrDA: parseInputBuffer"}, {kLogpImminus, "AppleSCCIrDA: parseInputBuffer - incorrect mode, data dropped"}, {kLogpISR, "AppleSCCIrDA: parseInputSIR"}, {kLogpStI, "AppleSCCIrDA: parseInputSIR - parse idle state, byte="}, {kLogpStB, "AppleSCCIrDA: parseInputSIR - parse BOF statef, byte="}, {kLogpStd, "AppleSCCIrDA: parseInputSIR - parse data state, byte="}, {kLogpSIminus, "AppleSCCIrDA: parseInputSIR - IrDA ReadComplete problem"}, {kLogpSCminus, "AppleSCCIrDA: parseInputSIR - CRC error"}, {kLogpSEminus, "AppleSCCIrDA: parseInputSIR - EOF early < 2 bytes of data"}, {kLogpStp, "AppleSCCIrDA: parseInputSIR - parse pad state, byte="}, {kLogpSte, "AppleSCCIrDA: parseInputSIR - state error"}, {kLogpIFR, "AppleSCCIrDA: parseInputFIR - Currently not supported"}, {kLogpIRt, "AppleSCCIrDA: parseInputReset"}, {kLogPBFT, "AppleSCCIrDA: Prepare_Buffer_For_Transmit"}, {kLogrxLp, "AppleSCCIrDA: rxLoop"}, {kLogrxok, "AppleSCCIrDA: rxLoop - read bytes, count="}, {kLogrxDminus, "AppleSCCIrDA: rxLoop - dequeueData (read) failed, err="}, {kLogrxLminus, "AppleSCCIrDA: rxLoop - Timer problem (SCC read has stopped)"}, {kLogrxKl, "AppleSCCIrDA: rxLoop - RX stopped (kill)"}, {kLogtxLp, "AppleSCCIrDA: txLoop"}, {kLogtxRs, "AppleSCCIrDA: txLoop - kTX_Reset"}, {kLogtxDt, "AppleSCCIrDA: txLoop - kTX_Data"}, {kLogtxSE, "AppleSCCIrDA: txLoop - State Error"}, {kLogtxLminus, "AppleSCCIrDA: txLoop - Timer problem (SCC write has stopped)"}, {kLogtxKl, "AppleSCCIrDA: txLoop - TX stopped (kill)"}, {kLogXmitCount, "AppleSCCIrDA - start transmit, queue count="}, {kLogSpeedChangeThread, "AppleSCCIrDA: - speed change thread"}, {kLogTxThread, "AppleSCCIrDA: tx thread"}, {kLogTxThreadDeferred, "AppleSCCIrDA: tx thread deferred"}, {kLogTxThreadResumed, "AppleSCCIrDA: tx thread resumed"}, {kLogRxThread, "AppleSCCIrDA: rx thread"}, {kLogRxThreadResumed, "AppleSCCIrDA: rx thread resumed"}, {kLogRxThreadSleeping, "AppleSCCIrDA: rx thread waiting for sendcommand"}, {kLogRxThreadGotData, "AppleSCCIrDA: rx thread has data"}, {kLogSetStructureDefaults, "AppleSCCIrDA: set port structure defaults, init="}, {kLogAcquirePort, "AppleSCCIrDA: acquire port"}, {kLogReleasePort, "AppleSCCIrDA: release port"}, {kLogSetState1, "AppleSCCIrDA: set state, state="}, {kLogSetState2, "AppleSCCIrDA: set state, mask="}, {kLogGetState, "AppleSCCIrDA; get state, state="}, {kLogWatchState, "AppleSCCIrDA: watch state"}, {kLogWatchState1, "AppleSCCIrDA: watch state, state="}, {kLogWatchState2, "AppleSCCIrDA: watch state, mask="}, {kLogExecEvent, "AppleSCCIrDA: exec event"}, {kLogExecEventData, "AppleSCCIrDA: exec event, data="}, {kLogReqEvent, "AppleSCCIrDA: request event"}, {kLogReqEventData, "AppleSCCIrDA: request event data"}, {kLogChangeStateBits, "AppleSCCIrDA: change state, new bits="}, {kLogChangeStateMask, "AppleSCCIrDA: change state, mask="}, {kLogChangeStateDelta, "AppleSCCIrDA: change state, delta="}, {kLogChangeStateNew, "AppleSCCIrDA: change state, new state="}, {kLogInitForPM, "AppleSCCIrDA: init power management"}, {kLogInitialPowerState, "AppleSCCIrDA: get initial power state, flags="}, {kLogSetPowerState, "AppleSCCIrDA: set power state, ordinal="} }; #define XTRACE(x, y, z) IrDALogAdd ( x, (UInt32)y, (UInt16)z, gTraceEvents, true) #else #define XTRACE(x, y, z) ((void)0) #endif enum { kIrDAPowerOffState = 0, kIrDAPowerOnState = 1, kNumIrDAStates = 2 }; static IOPMPowerState gOurPowerStates[kNumIrDAStates] = { {1,0,0,0,0,0,0,0,0,0,0,0}, {1,IOPMDeviceUsable,IOPMPowerOn,IOPMPowerOn,0,0,0,0,0,0,0,0} }; #define super AppleIrDASerial OSDefineMetaClassAndStructors( AppleSCCIrDA, AppleIrDASerial ); /****************************************************************************************************/ // CRC checking and generation (both 16 bit and 32 bit) /****************************************************************************************************/ #define POLYNOMIAL 0xedb88320 // 32-bit CRC polynomial, with lsb bits first #define P 0x8408 // The HDLC 16 bit polynomial: x**0 + x**5 + x**12 + x**16 (0x8408) #define VALID_CRC 0xDEBB20E3 // The 32 bit result after running over the CRC #define INITIAL_CRC 0xFFFFFFFF // Init 32 bit crc to this before starting static unsigned long crc_table[256]; // 32 bit table static UInt16 crc16_table[256]; // 16 bit table /****************************************************************************************************/ // // Function: gen_crc32_table // // Inputs: // // Outputs: // // Desc: Generate the table of CRC remainders for all possible bytes // /****************************************************************************************************/ void gen_crc32_table() { register int i, j; register unsigned long crc_accum; for ( i = 0; i < 256; i++ ) { crc_accum = ( (unsigned long) i ); for ( j = 0; j < 8; j++ ) { if ( crc_accum & 1 ) crc_accum = ( crc_accum >> 1 ) ^ POLYNOMIAL; else crc_accum = ( crc_accum >> 1 ); } crc_table[i] = crc_accum; } return; }/* end gen_crc32_table */ /****************************************************************************************************/ // // Function: gen_crc16_table // // Inputs: // // Outputs: // // Desc: Generate the CRC16 table // /****************************************************************************************************/ void gen_crc16_table() { register unsigned int b, v; register int i; for (b = 0; b < 256; b++) { v = b; for (i = 8; i--; ) v = v & 1 ? (v >> 1) ^ P : v >> 1; crc16_table[b] = v; } }/* end gen_crc16_table */ /****************************************************************************************************/ // // Function: update_crc32 // // Inputs: crc - the current crc value // cp - new data // len - length of the new data // // Outputs: crc - the new crc // // Desc: Update the CRC on the data block one byte at a time // /****************************************************************************************************/ UInt32 update_crc32( UInt32 crc, unsigned char *cp, int len ) { register int i, j; for ( j = 0; j < len; j++ ) { i = ( (int) ( crc ^ *cp++ ) & 0xff ); crc = ( crc >> 8 ) ^ crc_table[i]; } return crc; }/* end update_crc32 */ /****************************************************************************************************/ // // Function: update_crc16 // // Inputs: crc - the current crc value // cp - new data // len - length of the new data // // Outputs: crc - the new crc // // Desc: Update the CRC on the data block one byte at a time // /****************************************************************************************************/ UInt16 update_crc16( UInt16 crc, unsigned char *cp, int len ) { while (len--) crc = (crc >> 8) ^ crc16_table[(crc ^ *cp++) & 0xff]; return (crc); }/* end update_crc16 */ /****************************************************************************************************/ // // Function: check_crc32 // // Inputs: buf - the data // len - length of the data // // Outputs: bool - true (good), false (not so good) // // Desc: Call this to see if the crc-32 at the end of the block is valid // /****************************************************************************************************/ bool check_crc32( unsigned char *buf, int len ) { unsigned long crc = INITIAL_CRC; crc = update_crc32(crc, buf, len); return (crc == VALID_CRC); }/* end check_crc32 */ /****************************************************************************************************/ // // Function: check_crc16 // // Inputs: buf - the data // len - length of the data // // Outputs: bool - true (good), false (not so good) // // Desc: Call this to see if the crc-16 at the end of the block is valid // /****************************************************************************************************/ bool check_crc16( unsigned char *buf, int len ) { UInt16 crc; if (len < 2) return false; // sanity check crc = 0xffff; // init crc crc = update_crc16(crc, buf, len-2); // run over the data bytes crc = ~crc; // finalize it return ( ((crc & 0xff) == buf[len-2]) && ((crc >> 8) == buf[len-1]) ); }/* end check_crc16 */ #if LOG_DATA /****************************************************************************************************/ // // Function: Asciify // // Inputs: i - the nibble // // Outputs: return byte - ascii byte // // Desc: Converts to ascii. // /****************************************************************************************************/ static UInt8 Asciify(UInt8 i) { i &= 0xF; if ( i < 10 ) return( '0' + i ); else return( 55 + i ); }/* end Asciify */ #endif // LOG_DATA #if USE_ELG /****************************************************************************************************/ // // Function: AllocateEventLog // // Inputs: size - amount of memory to allocate // // Outputs: None // // Desc: Allocates the event log buffer // /****************************************************************************************************/ void AllocateEventLog( UInt32 size ) { if ( g.evLogBuf ) return; g.evLogFlag = 0; /* assume insufficient memory */ g.evLogBuf = (UInt8*)IOMalloc( size ); if ( !g.evLogBuf ) { IOLog( "AppleSCCIrDA: evLog allocation failed" ); return; } bzero( g.evLogBuf, size ); g.evLogBufp = g.evLogBuf; g.evLogBufe = g.evLogBufp + kEvLogSize - 0x20; // ??? overran buffer? g.evLogFlag = 0xFEEDBEEF; // continuous wraparound // g.evLogFlag = 'step'; // stop at each ELG // g.evLogFlag = 0x0333; // any nonzero - don't wrap - stop logging at buffer end IOLog( "AppleSCCIrDA: AllocateEventLog - &globals=%8x buffer=%8x", (unsigned int)&g, (unsigned int)g.evLogBuf ); return; }/* end AllocateEventLog */ /****************************************************************************************************/ // // Function: EvLog // // Inputs: a - anything // b - anything // ascii - 4 charater tag // str - any info string // // Outputs: None // // Desc: Writes the various inputs to the event log buffer // /****************************************************************************************************/ void EvLog( UInt32 a, UInt32 b, UInt32 ascii, char* str ) { register UInt32 *lp; /* Long pointer */ mach_timespec_t time; if ( g.evLogFlag == 0 ) return; IOGetTime( &time ); lp = (UInt32*)g.evLogBufp; g.evLogBufp += 0x10; if ( g.evLogBufp >= g.evLogBufe ) /* handle buffer wrap around if any */ { g.evLogBufp = g.evLogBuf; if ( g.evLogFlag != 0xFEEDBEEF ) // make 0xFEEDBEEF a symbolic ??? g.evLogFlag = 0; /* stop tracing if wrap undesired */ } /* compose interrupt level with 3 byte time stamp: */ *lp++ = (g.intLevel << 24) | ((time.tv_nsec >> 10) & 0x003FFFFF); // ~ 1 microsec resolution *lp++ = a; *lp++ = b; *lp = ascii; if( g.evLogFlag == 'step' ) { static char code[ 5 ] = {0,0,0,0,0}; *(UInt32*)&code = ascii; IOLog( "AppleSCCIrDA: %8x %8x %8x %s\n", time.tv_nsec>>10, (unsigned int)a, (unsigned int)b, code ); } return; }/* end EvLog */ #endif // USE_ELG #if LOG_DATA #define dumplen 32 // Set this to the number of bytes to dump and the rest should work out correct #define buflen ((dumplen*2)+dumplen)+3 #define Asciistart (dumplen*2)+3 /****************************************************************************************************/ // // Function: DEVLogData // // Inputs: Dir - direction // Count - number of bytes // buf - the data // // Outputs: None // // Desc: Puts the data in the log. // /****************************************************************************************************/ void DEVLogData(UInt8 Dir, UInt32 Count, char *buf) { UInt8 wlen, i, Aspnt, Hxpnt; UInt8 wchr; char LocBuf[buflen+1]; for ( i=0; i<=buflen; i++ ) { LocBuf[i] = 0x20; } LocBuf[i] = 0x00; switch (Dir) { case kDriverIn: IOLog( "AppleSCCIrDA: SCCLogData - from SCC, size = %8lx\n", Count ); break; case kAppIn: IOLog( "AppleSCCIrDA: SCCLogData - to Application, size = %8lx\n", Count ); break; case kDriverOut: IOLog( "AppleSCCIrDA: SCCLogData - to SCC, size = %8lx\n", Count ); break; case kAppOut: IOLog( "AppleSCCIrDA: SCCLogData - from Application, size = %8lx\n", Count ); break; case kAny: IOLog( "AppleSCCIrDA: SCCLogData - Other, size = %8lx\n", Count ); break; default: IOLog( "AppleSCCIrDA: SCCLogData - Unknown, size = %8lx\n", Count ); break; } if ( Count > dumplen ) { wlen = dumplen; } else { wlen = Count; } if ( wlen > 0 ) { Aspnt = Asciistart; Hxpnt = 0; for ( i=1; i<=wlen; i++ ) { wchr = buf[i-1]; LocBuf[Hxpnt++] = Asciify( wchr >> 4 ); LocBuf[Hxpnt++] = Asciify( wchr ); if (( wchr < 0x20) || (wchr > 0x7F )) // Non printable characters { LocBuf[Aspnt++] = 0x2E; // Replace with a period } else { LocBuf[Aspnt++] = wchr; } } LocBuf[(wlen + Asciistart) + 1] = 0x00; IOLog( LocBuf ); IOLog( "\n" ); } else { IOLog( "AppleSCCIrDA: SCCLogData - No data, Count = 0\n" ); } }/* end DEVLogData */ #endif // LOG_DATA /****************************************************************************************************/ // // Method: AppleSCCIrDA::AddBytetoQueue // // Inputs: Queue - the queue to be added to // // Outputs: Value - Byte to be added, Queue status - full or no error // // Desc: Add a byte to the circular queue. // /****************************************************************************************************/ QueueStatus AppleSCCIrDA::AddBytetoQueue( CirQueue *Queue, char Value ) { /* Check to see if there is space by comparing the next pointer, */ /* with the last, If they match we are either Empty or full, so */ /* check the InQueue of being zero. */ require(fPort && fPort->serialRequestLock, Fail); IOLockLock( fPort->serialRequestLock ); if ( (Queue->NextChar == Queue->LastChar) && Queue->InQueue ) { IOLockUnlock( fPort->serialRequestLock); return queueFull; } *Queue->NextChar++ = Value; Queue->InQueue++; /* Check to see if we need to wrap the pointer. */ if ( Queue->NextChar >= Queue->End ) Queue->NextChar = Queue->Start; IOLockUnlock( fPort->serialRequestLock); return queueNoError; Fail: return queueFull; // for lack of a better error }/* end AddBytetoQueue */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::GetBytetoQueue // // Inputs: Queue - the queue to be removed from // // Outputs: Value - where to put the byte, Queue status - empty or no error // // Desc: Remove a byte from the circular queue. // /****************************************************************************************************/ QueueStatus AppleSCCIrDA::GetBytetoQueue( CirQueue *Queue, UInt8 *Value ) { require(fPort && fPort->serialRequestLock, Fail); IOLockLock( fPort->serialRequestLock ); /* Check to see if the queue has something in it. */ if ( (Queue->NextChar == Queue->LastChar) && !Queue->InQueue ) { IOLockUnlock(fPort->serialRequestLock); return queueEmpty; } *Value = *Queue->LastChar++; Queue->InQueue--; /* Check to see if we need to wrap the pointer. */ if ( Queue->LastChar >= Queue->End ) Queue->LastChar = Queue->Start; IOLockUnlock(fPort->serialRequestLock); return queueNoError; Fail: return queueEmpty; // can't get to it, pretend it's empty }/* end GetBytetoQueue */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::InitQueue // // Inputs: Queue - the queue to be initialized, Buffer - the buffer, size - length of buffer // // Outputs: Queue status - queueNoError. // // Desc: Pass a buffer of memory and this routine will set up the internal data structures. // /****************************************************************************************************/ QueueStatus AppleSCCIrDA::InitQueue( CirQueue *Queue, UInt8 *Buffer, size_t Size ) { Queue->Start = Buffer; Queue->End = (UInt8*)((size_t)Buffer + Size); Queue->Size = Size; Queue->NextChar = Buffer; Queue->LastChar = Buffer; Queue->InQueue = 0; IOSleep( 1 ); return queueNoError ; }/* end InitQueue */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::CloseQueue // // Inputs: Queue - the queue to be closed // // Outputs: Queue status - queueNoError. // // Desc: Clear out all of the data structures. // /****************************************************************************************************/ QueueStatus AppleSCCIrDA::CloseQueue( CirQueue *Queue ) { Queue->Start = 0; Queue->End = 0; Queue->NextChar = 0; Queue->LastChar = 0; Queue->Size = 0; return queueNoError; }/* end CloseQueue */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::AddtoQueue // // Inputs: Queue - the queue to be added to, Buffer - data to add, Size - length of data // // Outputs: BytesWritten - Number of bytes actually put in the queue. // // Desc: Add an entire buffer to the queue. // /****************************************************************************************************/ size_t AppleSCCIrDA::AddtoQueue( CirQueue *Queue, UInt8 *Buffer, size_t Size ) { size_t BytesWritten = 0; while ( FreeSpaceinQueue( Queue ) && (Size > BytesWritten) ) { AddBytetoQueue( Queue, *Buffer++ ); BytesWritten++; } return BytesWritten; }/* end AddtoQueue */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::RemovefromQueue // // Inputs: Queue - the queue to be removed from, Size - size of buffer // // Outputs: Buffer - Where to put the data, BytesReceived - Number of bytes actually put in Buffer. // // Desc: Get a buffers worth of data from the queue. // /****************************************************************************************************/ size_t AppleSCCIrDA::RemovefromQueue( CirQueue *Queue, UInt8 *Buffer, size_t MaxSize ) { size_t BytesReceived = 0; UInt8 Value; while( (MaxSize > BytesReceived) && (GetBytetoQueue(Queue, &Value) == queueNoError) ) { *Buffer++ = Value; BytesReceived++; } return BytesReceived; }/* end RemovefromQueue */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::FreeSpaceinQueue // // Inputs: Queue - the queue to be queried // // Outputs: Return Value - Free space left // // Desc: Return the amount of free space left in this buffer. // /****************************************************************************************************/ size_t AppleSCCIrDA::FreeSpaceinQueue( CirQueue *Queue ) { size_t retVal = 0; require(fPort && fPort->serialRequestLock, Fail); IOLockLock( fPort->serialRequestLock ); retVal = Queue->Size - Queue->InQueue; IOLockUnlock(fPort->serialRequestLock); Fail: return retVal; }/* end FreeSpaceinQueue */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::UsedSpaceinQueue // // Inputs: Queue - the queue to be queried // // Outputs: UsedSpace - Amount of data in buffer // // Desc: Return the amount of data in this buffer. // /****************************************************************************************************/ size_t AppleSCCIrDA::UsedSpaceinQueue( CirQueue *Queue ) { return Queue->InQueue; }/* end UsedSpaceinQueue */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::GetQueueSize // // Inputs: Queue - the queue to be queried // // Outputs: QueueSize - The size of the queue. // // Desc: Return the total size of the queue. // /****************************************************************************************************/ size_t AppleSCCIrDA::GetQueueSize( CirQueue *Queue ) { return Queue->Size; }/* end GetQueueSize */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::GetQueueStatus // // Inputs: Queue - the queue to be queried // // Outputs: Queue status - full, empty or no error // // Desc: Returns the status of the circular queue. // /****************************************************************************************************/ /* QueueStatus AppleSCCIrDA::GetQueueStatus( CirQueue *Queue ) { QueueStatus retval = queueFull; require(fPort && fPort->serialRequestLock, Fail); IOLockLock( fPort->serialRequestLock ); if ( (Queue->NextChar == Queue->LastChar) && Queue->InQueue ) retval = queueFull; else if ( (Queue->NextChar == Queue->LastChar) && !Queue->InQueue ) retval = queueEmpty; else retval = queueNoError; IOLockUnlock(fPort->serialRequestLock); Fail: return retval; } */ /* end GetQueueStatus */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::CheckQueues // // Inputs: port - the port to check // // Outputs: None // // Desc: Checks the various queue's etc and manipulates the state(s) accordingly // /****************************************************************************************************/ void AppleSCCIrDA::CheckQueues( PortInfo_t *port ) { unsigned long Used; unsigned long Free; unsigned long QueuingState; unsigned long DeltaState; // Initialise the QueueState with the current state. QueuingState = readPortState( port ); /* Check to see if there is anything in the Transmit buffer. */ Used = UsedSpaceinQueue( &port->TX ); Free = FreeSpaceinQueue( &port->TX ); // ELG( Free, Used, 'CkQs', "CheckQueues" ); if ( Free == 0 ) { QueuingState |= PD_S_TXQ_FULL; QueuingState &= ~PD_S_TXQ_EMPTY; } else if ( Used == 0 ) { QueuingState &= ~PD_S_TXQ_FULL; QueuingState |= PD_S_TXQ_EMPTY; } else { QueuingState &= ~PD_S_TXQ_FULL; QueuingState &= ~PD_S_TXQ_EMPTY; } /* Check to see if we are below the low water mark. */ if ( Used < port->TXStats.LowWater ) QueuingState |= PD_S_TXQ_LOW_WATER; else QueuingState &= ~PD_S_TXQ_LOW_WATER; if ( Used > port->TXStats.HighWater ) QueuingState |= PD_S_TXQ_HIGH_WATER; else QueuingState &= ~PD_S_TXQ_HIGH_WATER; /* Check to see if there is anything in the Receive buffer. */ Used = UsedSpaceinQueue( &port->RX ); Free = FreeSpaceinQueue( &port->RX ); if ( Free == 0 ) { QueuingState |= PD_S_RXQ_FULL; QueuingState &= ~PD_S_RXQ_EMPTY; } else if ( Used == 0 ) { QueuingState &= ~PD_S_RXQ_FULL; QueuingState |= PD_S_RXQ_EMPTY; } else { QueuingState &= ~PD_S_RXQ_FULL; QueuingState &= ~PD_S_RXQ_EMPTY; } /* Check to see if we are below the low water mark. */ if ( Used < port->RXStats.LowWater ) QueuingState |= PD_S_RXQ_LOW_WATER; else QueuingState &= ~PD_S_RXQ_LOW_WATER; if ( Used > port->RXStats.HighWater ) QueuingState |= PD_S_RXQ_HIGH_WATER; else QueuingState &= ~PD_S_RXQ_HIGH_WATER; /* Figure out what has changed to get mask.*/ DeltaState = QueuingState ^ readPortState( port ); changeState( port, QueuingState, DeltaState ); return; }/* end CheckQueues */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::Add_RXBytes // // Inputs: Buffer - the raw input data // Size - the length // // Outputs: // // Desc: Adds data to the circular receive queue // /****************************************************************************************************/ void AppleSCCIrDA::Add_RXBytes( UInt8 *Buffer, size_t Size ) { XTRACE(kLogAdRB, 0, Size); ELG( 0, Size, 'AdRB', "Add_RXBytes" ); AddtoQueue( &fPort->RX, Buffer, Size ); CheckQueues( fPort ); }/* end Add_RXBytes */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::SetBofCount // // Inputs: bof_count - the requested number of Beginning Of Frames // // Outputs: return word - the actual count (not bofs) // // Desc: Encode the requested number of BOF bytes to the first value that's big enough // /****************************************************************************************************/ SInt16 AppleSCCIrDA::SetBofCount( SInt16 bof_count ) { ELG( 0, bof_count, 'Sbof', "SetBofCount" ); XTRACE(kLogSbof, 0, bof_count); fBofsCode = bof_count; return fBofsCode; }/* end SetBofCount */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::SetSpeed // // Inputs: brate - the requested baud rate // // Outputs: return word - baud coding // // Desc: Set the baudrate for the device // /****************************************************************************************************/ UInt16 AppleSCCIrDA::SetSpeed( UInt32 brate ) { UInt8 command = 0; ELG( 0, brate, 'StSp', "SetSpeed" ); XTRACE(kLogStSp, brate >> 16, brate); require(fSpeedChanging == false, Fail); // sanity check switch (brate) { default: ELG( 0, brate, 'SSp-', "SetSpeed - Unsupported baud rate"); XTRACE(kLogSSpminus, brate >> 16, brate); //break; // fall through and set to 9600 case 9600: fBaudCode = brate; fModeFlag = kMode_SIR; command = kSetModeHP9600_1_6; break; case 19200: fBaudCode = brate; fModeFlag = kMode_SIR; command = kSetModeHP19200_1_6; break; case 38400: fBaudCode = brate; fModeFlag = kMode_SIR; command = kSetModeHP38400_1_6; break; case 57600: fBaudCode = brate; fModeFlag = kMode_SIR; command = kSetModeHP57600_1_6; break; case 115200: fBaudCode = brate; fModeFlag = kMode_SIR; command = kSetModeHP115200_1_6; break; case 576000: fBaudCode = brate; fModeFlag = kMode_MIR; break; case 1152000: fBaudCode = brate; fModeFlag = kMode_FIR; break; case 4000000: fBaudCode = brate; fModeFlag = kMode_FIR; break; } if (command) { bool rc; fSpeedChanging = true; rc = thread_call_enter1(speed_change_thread_call, (thread_call_param_t)command); check(rc == false); // true here meant it was already running } return fBaudCode; Fail: return (short)-1; }/* end SetSpeed */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::GetIrDAComm // // Inputs: // // Outputs: IrDAComm - Address of the IrDA object // // Desc: Returns the address of the IrDA object // /****************************************************************************************************/ IrDAComm* AppleSCCIrDA::GetIrDAComm( void ) { return fIrDA; }/* end GetIrDAComm */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::GetIrDAQoS // // Inputs: // // Outputs: USBIrDAQoS - Address of the QoS structure // // Desc: Returns the address of the Quality of Service structure // /****************************************************************************************************/ USBIrDAQoS* AppleSCCIrDA::GetIrDAQoS( void ) { return &fQoS; }/* end GetIrDAQoS */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::GetIrDAStatus // // Inputs: status - status structure // // Outputs: // // Desc: Sets the connection state and CRC errors of the status structure // /****************************************************************************************************/ void AppleSCCIrDA::GetIrDAStatus( IrDAStatus *status ) { ELG( 0, 0, 'GIrS', "GetIrDAStatus" ); XTRACE(kLogGIrS, 0, 0); if ( !fIrDAOn ) { //bzero( status, sizeof(IrDAStatus) ); status->connectionState = kIrDAStatusOff; } else { if ( status->connectionState == kIrDAStatusOff ) { status->connectionState = kIrDAStatusIdle; } status->crcErrors = fICRCError; } }/* end GetIrDAStatus */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::SetIrDAUserClientState // // Inputs: state - true = IrDA on, false = IrDA off // // Outputs: // // Desc: User client stub to change the state of IrDA // /****************************************************************************************************/ IOReturn AppleSCCIrDA::SetIrDAUserClientState( bool IrDAOn ) { ELG( 0, IrDAOn, 'SICS', "SetIrDAUserClientState" ); XTRACE(kLogSICS, 0, IrDAOn); fUserClientStarted = IrDAOn; return CheckIrDAState(); }/* SetIrDAUserClientState */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::CheckIrDAState // // Inputs: // // Outputs: // // Desc: Turns IrDA on or off if needed // /****************************************************************************************************/ IOReturn AppleSCCIrDA::CheckIrDAState() { IOReturn ior = kIOReturnSuccess; bool newState; // new irda on/off state newState = fSCCStarted && // we have to be started (and not stopped) for irda to run, and (fPowerState == kIrDAPowerOnState) && // powered on by the power manager, and (fUserClientStarted | (fSessions > 0)); // Either the user client or a real app must be started ELG( 0, newState, 'CIrS', "CheckIrDAState" ); ELG( fUserClientStarted, fSessions, 'CIrS', "CheckIrDAState *" ); XTRACE(kLogCIrS, 0, newState); if (newState != fIrDAOn) // if desired state not the current state ior = SetIrDAState(newState); // then change it return ior; }/* end CheckIrDAState */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::SetIrDAState // // Inputs: state - true = IrDA on, false = IrDA off // // Outputs: // // Desc: Turns IrDA on or off // /****************************************************************************************************/ IOReturn AppleSCCIrDA::SetIrDAState( bool IrDAOn ) { IOReturn ior = kIOReturnSuccess; ELG( 0, IrDAOn, 'SIrS', "SetIrDAState" ); XTRACE(kLogSIrS, 0, IrDAOn); if ( IrDAOn && !fIrDAOn) // if want on, but we're off, then turn IrDA on { fIrDAOn = true; fTerminate = false; if ( configureDevice() ) { ELG( 0, 0, 'stcn', "SetIrDAState - successful (IrDA On)" ); XTRACE(kLogstcn, 0, 0); fICRCError = 0; } else { ELG( 0, 0, 'str-', "SetIrDAState - configureDevice failed" ); XTRACE(kLogstrminus, 0, 0); //fpDevice->close(this); -- jdg, ths is done in stop // let's stop irda if we've failed to start SetIrDAState(false); // recurse to turn off irda ior = kIOReturnIOError; } } else { if ( !IrDAOn && fIrDAOn ) // if want off, but currently on, turn it off { if (fIrDA) { fIrDA->Stop(); fIrDA->release(); fIrDA = NULL; } fpDevice->executeEvent( PD_E_ACTIVE, false ); IOSleep(100); // give completed reads time to finish up if ( fInBuffer ) { IOFree( fInBuffer, SCCLapPayLoad ); fInBuffer = NULL; } if ( fOutBuffer ) { IOFree( fOutBuffer, SCCLapPayLoad ); fOutBuffer = NULL; } if ( fInUseBuffer ) { IOFree( fInUseBuffer, SCCLapPayLoad ); fInUseBuffer = NULL; } ELG( 0, 0, 'stbr', "SetIrDAState - before releasePort" ); XTRACE(kLogstbr, 0, 0); fpDevice->releasePort(); ELG( 0, 0, 'star', "SetIrDAState - after releasePort" ); XTRACE(kLogstar, 0, 0); freeRingBuffer( &fPort->TX ); freeRingBuffer( &fPort->RX ); fIrDAOn = false; fTerminate = true; // Make it look like we've been terminated disableSCC(); // and turn off the power to the scc } } return ior; }/* end SetIrDAState */ /****************************************************************************************************/ // // Function: AppleSCCIrDA::init // // Inputs: dict - Dictionary // // Outputs: Return code - from IOService::init // // Desc: Driver initialization // /****************************************************************************************************/ bool AppleSCCIrDA::init( OSDictionary *dict ) { bool rc; ELG( 0, 0, 'init', "init" ); XTRACE(kLoginit, 0, 0); #if (hasTracing > 0) IOLog("AppleSCCIrDA: irdalog info at 0x%lx\n", (UInt32)IrDALogGetInfo()); #endif // Skip the IORS232SerialStreamSync's super classes, they aren't 'driver side' rc = IOService::init( dict ); IOLogIt( 0, rc, 'init', "init" ); return rc; }/* end init */ /****************************************************************************************************/ // // Function: AppleSCCIrDA::probe // // Inputs: provider - my provider // // Outputs: IOService - me (successful), 0 (failed) // score - probe score // // Desc: Check to see if we match correctly // /****************************************************************************************************/ IOService* AppleSCCIrDA::probe( IOService *provider, SInt32 *score ) { OSString *matchEntry = 0; OSData *ssn; UInt32 *nWords; char *tmpPtr, *tmpName; ELG( 0, 0, 'prob', "probe" ); XTRACE(kLogprob, 0, 0); if (1) { // limit to machines we've tested IOService *iter = provider; while (iter != NULL) { //#if (hasTracing > 0) if (strcmp(iter->getName(), "PowerBook3,1") == 0) break; if (strcmp(iter->getName(), "PowerBook3,2") == 0) break; //#endif if (strcmp(iter->getName(), "PowerBook3,3") == 0) break; iter = iter->getProvider(); } if (iter == NULL) return 0; // fail if didn't match } matchEntry = OSDynamicCast (OSString, getProperty (kIONameMatchedKey)); if ( (matchEntry == 0) || (matchEntry->isEqualTo("chrp,es3") == false) ) { IOLogIt( matchEntry, 0, 'prm-', "probe - failed, name match incorrect" ); return 0; } ssn = OSDynamicCast( OSData, provider->getProperty("slot-names") ); if ( !ssn ) { IOLogIt( ssn, 0, 'prs-', "probe - failed, retrieving slot-name error" ); return 0; } nWords = (UInt32*)ssn->getBytesNoCopy(); if ( *nWords < 1 ) { IOLogIt( 0, 0, 'pns-', "probe - failed, no slot-name" ); return 0; } // Get the slot-name tmpName = (char *)ssn->getBytesNoCopy() + sizeof(UInt32); // To make parsing easy set the sting to lower case for ( tmpPtr = tmpName; *tmpPtr != 0; tmpPtr++ ) { *tmpPtr |= 32; } LogData( kAny, 4, (char *)tmpName ); if ( strncmp (tmpName, "irda", 4) == 0 ) { IOLogIt( 0, 0, 'prs+', "probe - successful" ); *score = 10000; return this; } else { IOLogIt( 0, 0, 'prb-', "probe - failed, did not match with slot-name(irda)" ); return 0; } }/* end probe */ /****************************************************************************************************/ // // Function: AppleSCCIrDA::attach // // Inputs: provider - my provider // // Outputs: Return code - from IOService::attach // // Desc: Attach with our provider // /****************************************************************************************************/ bool AppleSCCIrDA::attach(IOService *provider) { ELG( 0, 0, 'atch', "attach" ); XTRACE(kLogatch, 0, 0); // Skip the IORS232SerialStreamSync's super classes, they aren't 'driver side' return IOService::attach(provider); }/* end attach */ /****************************************************************************************************/ // // Function: AppleSCCIrDA::detach // // Inputs: provider - my provider // // Outputs: // // Desc: detach from our provider // /****************************************************************************************************/ void AppleSCCIrDA::detach(IOService *provider) { ELG( 0, 0, 'dtch', "detach" ); XTRACE(kLogdtch, 0, 0); // Skip the IORS232SerialStreamSync's super classes, they aren't 'driver side' IOService::detach(provider); }/* detach */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::start // // Inputs: provider - my provider // // Outputs: Return code - true (it's me), false (sorry it probably was me, but I can't configure it) // // Desc: This is called once it has beed determined I'm probably the best driver. // /****************************************************************************************************/ bool AppleSCCIrDA::start( IOService *provider ) { XTRACE(kLogstrt, provider >> 16, provider); g.evLogBufp = NULL; fUserClientNub = NULL; fPort = NULL; fIrDAOn = false; fTerminate = false; // Make sure we don't think we're being terminated fKillRead = false; rx_thread_call = NULL; tx_thread_call = NULL; speed_change_thread_call = NULL; fUserClientStarted = false; // user/client has not started us yet fSCCStarted = false; fSessions = 0; fSendingCommand = false; fSpeedChanging = false; fPowerState = kIrDAPowerOffState; // set to on when we're registered with the power mgr fProvider = provider; // Remember that masked man disableSCC(); // turn off the scc clocks until we start irda stack #if USE_ELG AllocateEventLog( kEvLogSize ); ELG( &g, g.evLogBufp, 'SCCM', "start - event logging set up." ); waitForService( resourceMatching( "kdp" ) ); #endif /* USE_ELG */ ELG( this, provider, 'strt', "start - this, provider." ); // Skip the IORS232SerialStreamSync's super classes, they aren't 'driver side' if( !IOService::start( provider ) ) { IOLogIt( 0, 0, 'SS--', "start - IOService failed" ); return false; } /* Get my device - RS232 device */ fpDevice = OSDynamicCast( IORS232SerialStreamSync, provider ); if( !fpDevice ) { IOLogIt( 0, 0, 'Dev-', "start - device invalid" ); IOService::stop( provider ); return false; } rx_thread_call = thread_call_allocate(rx_thread, this); tx_thread_call = thread_call_allocate(tx_thread, this); speed_change_thread_call = thread_call_allocate(speed_change_thread, this); check(rx_thread_call && tx_thread_call && speed_change_thread_call); if (!rx_thread_call || !tx_thread_call || !speed_change_thread_call) return false; /* Now take control of the device and configure it */ if (!fpDevice->open(this)) { IOLogIt( 0, 0, 'Opn-', "start - unable to open device" ); IOService::stop( provider ); return false; } // build a nub to make user-client name easy fUserClientNub = AppleIrDA::withNub(this); if (fUserClientNub) { fUserClientNub->attach(this); } if (fPort == NULL) { fPort = (PortInfo_t*)IOMalloc( sizeof(PortInfo_t) ); } if (fPort) bzero(fPort, sizeof(PortInfo_t)); else return false; SetStructureDefaults(fPort, true); // init the port fPort->serialRequestLock = IOLockAlloc(); // init lock used to protect code on MP if ( !fPort->serialRequestLock ) return false; if (!createSerialStream() ) // Publish Serial Stream (bsd) services { IOLogIt( 0, 0, 'cSS-', "start - createSerialStream failed" ); IOService::stop( provider ); return false; } if (!initForPM(fProvider)) return false; fSCCStarted = true; // we can start up irda next time IOLogIt( 0, fProvider, 'stcf', "start - successful (IrDA Off)" ); return true; }/* end start */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::free // // Inputs: // // Outputs: // // Desc: Clean up and free the log // /****************************************************************************************************/ void AppleSCCIrDA::free() { ELG( 0, 0, 'free', "free" ); XTRACE(kLogfree, 0, 0); if ( fIrDA ) fIrDA->release(); // we don't do delete's in the kernal I suppose ... #if USE_ELG if ( g.evLogBuf ) IOFree( g.evLogBuf, kEvLogSize ); #endif /* USE_ELG */ // Skip the IORS232SerialStreamSync's super classes, they aren't 'driver side' IOService::free(); return; }/* end free */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::stop // // Inputs: provider - my provider // // Outputs: // // Desc: Stops // /****************************************************************************************************/ void AppleSCCIrDA::stop( IOService *provider ) { ELG( 0, 0, 'stop', "stop" ); XTRACE(kLogstop, provider >> 16, provider); fSCCStarted = false; CheckIrDAState(); // stop the irda stack if (fPort) { if (fPort->serialRequestLock) { IOLockFree(fPort->serialRequestLock); // free the Serial Request Lock fPort->serialRequestLock = NULL; } IOFree( fPort, sizeof(PortInfo_t)); fPort = NULL; } if (fUserClientNub) { fUserClientNub->detach(this); fUserClientNub->release(); fUserClientNub = NULL; } check(fIrDA == NULL); // sanity check(fInBuffer == NULL); // eludes us check(fOutBuffer == NULL); check(fInUseBuffer == NULL); fpDevice->executeEvent( PD_E_ACTIVE, false ); IOSleep(100); // give completed reads time to finish up fpDevice->releasePort(); #ifdef Trace_SCCSerial (void) fpDevice->executeEvent(IRDLOG_HACK, 0); // don't let scc call irdalog anymore #endif fpDevice->close(this); #define THREAD_FREE(x) do { if (x) { \ thread_call_cancel(x); \ thread_call_free(x); \ x = NULL; } } while(0) THREAD_FREE(rx_thread_call); THREAD_FREE(tx_thread_call); THREAD_FREE(speed_change_thread_call); #undef THREAD_FREE // release our power manager state PMstop(); // Skip the IORS232SerialStreamSync's super classes, they aren't 'driver side' IOService::stop( provider ); return; }/* end stop */ /** #define RevertEndianness32(X) ((X & 0x000000FF) << 24) | \ ((X & 0x0000FF00) << 16) | \ ((X & 0x00FF0000) >> 16) | \ ((X & 0xFF000000) >> 24) **/ /****************************************************************************************************/ // // Function: AppleSCCIrDA::enableSCC // // Inputs: None // // Outputs: return code - true (did it), false (didn't) // // Desc: Enables the SCC cell for IrDA on channel B // /****************************************************************************************************/ enum { kFcr0Offset = 0x38 }; bool AppleSCCIrDA::enableSCC( void ) { IOService *topProvider = NULL; IOService *provider = NULL; bool isCore99 = false; bool isHeathrow = false; UInt8 *comp; ELG( 0, 0, 'eSCC', "enableSCC" ); XTRACE(kLogeSCC, 0, 0); // See if we can find the top of the tree (with the machine type) // iterating all the way up: provider = fProvider; while (provider != NULL) { // Check if we are at the IOService mac-io registry entry OSData *s = OSDynamicCast( OSData, provider->getProperty("name") ); if ( (s != NULL) && s->isEqualTo("mac-io", 6) ) { // Look to see if we have keylargo or Heathrow OSData *kl = OSDynamicCast( OSData, provider->getProperty("compatible") ); if ( kl != NULL ) { (const void *)comp = kl->getBytesNoCopy(); LogData( kAny, 20, (char *)comp ); if ( kl->isEqualTo("Keylargo", 8) ) { isCore99 = true; } else { if ( (kl->isEqualTo("paddington", 10)) || (kl->isEqualTo("heathrow", 8)) ) { isHeathrow = true; } } } } // remember who is the topmost provider and iterate again topProvider = provider; provider = topProvider->getProvider(); } if ( isHeathrow ) { ELG( 0, 0, 'eSCH', "enableSCC - Heathrow" ); XTRACE(kLogeSCH, 0, 0); callPlatformFunction("EnableSCC", false, (void *)true, 0, 0, 0); return true; } if ( !isCore99 ) { ELG( 0, 0, 'eSC-', "enableSCC - no Heathrow or Keylargo" ); XTRACE(kLogeSCminus, 0, 0); return false; }; /** this code is now part of the keylargo platform expert -- we just need to pass a few undocumented parameters to EnableSCC ***/ /** UInt32 bitsON; UInt32 bitsOFF; UInt32 bitValues, bitMask; ELG( 0, 0, 'eSCK', "enableSCC - Keylargo" ); XTRACE(kLogeSCK, 0, 0); // Enables the SCCb (irda) cell: bitsON = bitsOFF = 0; bitsON |= (1 << 17); // irda 19.584 MHz clock bitsON |= (1 << 16); // irda 32 mhz clock on bitsON |= (1 << 15); // IrDA Enable bitsOFF|= (1 << 14); // fast connect bitsOFF|= (1 << 13); // default0 bitsOFF|= (1 << 12); // default1 // 11 IrDA software reset bitsON |= (1 << 10); // use ir source 1 bitsOFF|= (1 << 9); // do not use ir source 2 bitsOFF|= (1 << 8); // high band for 1mbit. 0 for low speed? // 7 VIA bitsON |= (1 << 6); // SccEnable. Enables SCC bitsON |= (1 << 5); // SccBEnable. Enables SCC B // bitsON |= (1 << 4); // SccAEnable. Enables SCC A // 3 software reset of scc bitsOFF|= (1 << 2); // SlowPCLK. 0 for SCCPCLK at 24.576 MHZ, 1 for 15.6672 MHz // bitsON |= (1 << 1); // ChooseSCCA. 0 for I2S1, 1 for SCCA bitsOFF|= (1 << 0); // ChooseSCCB. 0 for IrDA hardware, 1 for SCC interface pins bitValues = bitsON; bitMask = bitsON | bitsOFF; callPlatformFunction("keyLargo_safeWriteRegUInt32", true, (void *)kFcr0Offset, (void *)bitMask, (void *)bitValues, 0); if (1) // Now reset the SCC { bitMask = (1 << 3); // Resets the SCC callPlatformFunction("keyLargo_safeWriteRegUInt32", true, (void *)kFcr0Offset, (void *)bitMask, (void *)bitMask, 0); IOSleep(15); callPlatformFunction("keyLargo_safeWriteRegUInt32", true, (void *)kFcr0Offset, (void *)bitMask, 0, 0); } if (1) // And finally reset the IrDA cell { bitMask = (1 << 11); // Resets FIReworks callPlatformFunction("keyLargo_safeWriteRegUInt32", true, (void *)kFcr0Offset, (void *)bitMask, (void *)bitMask, 0); IOSleep(15); callPlatformFunction("keyLargo_safeWriteRegUInt32", true, (void *)kFcr0Offset, (void *)bitMask, 0, 0); } ***/ // keylargo enablescc call // param1 == enable/disable // param2 == 1 if sccb, else scca // param3 == 1 if irda, else sccb serial port // parma4 == unused callPlatformFunction("EnableSCC", false, (void *)true, (void *)1, (void *)1, 0); return true; }/* end enableSCC */ /****************************************************************************************************/ // // Function: AppleSCCIrDA::disableSCC // // Inputs: None // // Outputs: return code - true (did it), false (didn't) // // Desc: Enables the SCC cell for IrDA on channel B // /****************************************************************************************************/ bool AppleSCCIrDA::disableSCC( void ) { IOService *topProvider = NULL; IOService *provider = NULL; //IOMemoryMap *macIOBase; //UInt8 *ioPhisicalBaseAddress = NULL; bool isCore99 = false; bool isHeathrow = false; UInt8 *comp; ELG( 0, 0, 'dSCC', "disableSCC" ); XTRACE(kLogdSCC, 0, 0); // See if we can find the top of the tree (with the machine type) // iterating all the way up: provider = fProvider; while (provider != NULL) { // Check if we are at the IOService mac-io registry entry OSData *s = OSDynamicCast( OSData, provider->getProperty("name") ); if ( (s != NULL) && s->isEqualTo("mac-io", 6) ) { //if ( (macIOBase = provider->mapDeviceMemoryWithIndex( 0 )) ) //{ // ioPhisicalBaseAddress = (UInt8*)macIOBase->getPhysicalAddress(); //} // Look to see if we have keylargo or Heathrow OSData *kl = OSDynamicCast( OSData, provider->getProperty("compatible") ); if ( kl != NULL ) { (const void *)comp = kl->getBytesNoCopy(); LogData( kAny, 20, (char *)comp ); if ( kl->isEqualTo("Keylargo", 8) ) { isCore99 = true; } else { if ( (kl->isEqualTo("paddington", 10)) || (kl->isEqualTo("heathrow", 8)) ) { isHeathrow = true; } } } } // remember who is the topmost provider and iterate again topProvider = provider; provider = topProvider->getProvider(); } if ( isHeathrow ) { ELG( 0, 0, 'dSCH', "disableSCC - Heathrow" ); XTRACE(kLogdSCH, 0, 0); // disable scc -- this is a big, fat, nop! and if it // wasn't, then it'd tread on the modem's toes callPlatformFunction("EnableSCC", false, (void *)false, 0, 0, 0); return true; } if ( !isCore99 ) { ELG( 0, 0, 'dSC-', "disableSCC - no Heathrow or Keylargo" ); XTRACE(kLogdSCminus, 0, 0); return false; }; /**** moved to platform expert UInt32 bitsON, bitsOFF; UInt32 bitValues, bitMask; ELG( 0, 0, 'dSCK', "disableSCC - Keylargo" ); XTRACE(kLogdSCK, 0, 0); // disables the SCC cell: bitsON = bitsOFF = 0; bitsOFF |= (1 << 17); // irda 19.584 MHz clock bitsOFF |= (1 << 16); // irda 32 mhz clock on bitsOFF |= (1 << 15); // IrDA Enable bitsOFF |= (1 << 14); // fast connect bitsOFF |= (1 << 13); // default0 bitsOFF |= (1 << 12); // default1 // 11 IrDA software reset bitsOFF |= (1 << 10); // use ir source 1 bitsOFF |= (1 << 9); // do not use ir source 2 bitsOFF |= (1 << 8); // high band for 1mbit. 0 for low speed? // 7 VIA // bitsON |= (1 << 6); // SccEnable. Enables SCC bitsOFF |= (1 << 5); // SccBEnable. Enables SCC B // bitsON |= (1 << 4); // SccAEnable. Enables SCC A // 3 software reset of scc bitsOFF |= (1 << 2); // SlowPCLK. 0 for SCCPCLK at 24.576 MHZ, 1 for 15.6672 MHz // bitsON |= (1 << 1); // ChooseSCCA. 0 for I2S1, 1 for SCCA // bitsOFF|= (1 << 0); // ChooseSCCB. 0 for IrDA hardware, 1 for SCC interface pins bitValues = bitsON; bitMask = bitsON | bitsOFF; callPlatformFunction("keyLargo_safeWriteRegUInt32", true, (void *)kFcr0Offset, (void *)bitMask, (void *)bitValues, 0); ****/ // keylargo enablescc call // param1 == enable/disable // param2 == 1 if sccb, else scca // param3 == 1 if irda, else sccb serial port // parma4 == unused callPlatformFunction("EnableSCC", false, (void *)false, (void *)1, (void *)1, 0); return true; }/* end disableSCC */ // // initForPM // // Add ourselves to the power management tree so we // can do the right thing on sleep/wakeup. // bool AppleSCCIrDA::initForPM(IOService * provider) { XTRACE(kLogInitForPM, 0, 0); fPowerState = kIrDAPowerOnState; // init our power state to be 'on' PMinit(); // init power manager instance variables provider->joinPMtree(this); // add us to the power management tree require(pm_vars != NULL, Fail); // register ourselves with ourself as policy-maker registerPowerDriver(this, gOurPowerStates, kNumIrDAStates); return true; Fail: return false; } // // request for our initial power state // unsigned long AppleSCCIrDA::initialPowerStateForDomainState ( IOPMPowerFlags flags) { XTRACE(kLogInitialPowerState, flags >> 16, (short)flags); return fPowerState; } // // request to turn device on or off // IOReturn AppleSCCIrDA::setPowerState(unsigned long powerStateOrdinal, IOService * whatDevice) { XTRACE(kLogSetPowerState, 0, powerStateOrdinal); require(powerStateOrdinal == kIrDAPowerOffState || powerStateOrdinal == kIrDAPowerOnState, Fail); if (powerStateOrdinal == fPowerState) return IOPMAckImplied; fPowerState = powerStateOrdinal; CheckIrDAState(); return IOPMNoErr; Fail: return IOPMNoSuchState; } /****************************************************************************************************/ // // Method: AppleSCCIrDA::sendBaud // // Inputs: brate - the requested baud rate // // Outputs: return code - kIOReturnSuccess and others // // Desc: Send the baudrate to the SCC driver // /****************************************************************************************************/ IOReturn AppleSCCIrDA::sendBaud( UInt32 baud ) { IOReturn rtn = kIOReturnSuccess; ELG( 0, baud, 'snBd', "sendBaud" ); XTRACE(kLogsnBd, baud >> 16, baud); if (baud < 115200) { rtn = fpDevice->executeEvent( PD_E_DATA_RATE, (baud << 1) ); } else { rtn = fpDevice->executeEvent( PD_E_EXTERNAL_CLOCK_MODE, 0); } if ( rtn != kIOReturnSuccess ) { ELG( baud, rtn, 'snB-', "sendBaud - execute event (baud rate) failed" ); XTRACE(kLogsnBminus, rtn >> 16, rtn); } return rtn; }/* end sendBaud */ /****************************************************************************************************/ // // Function: AppleSCCIrDA::sendCommand // // Inputs: command - the command to be sent // // Outputs: result - result returned from the cell // return code - kIOReturnSuccess, kIOReturnIOError and others // // Desc: Set up and send the command to the FIReworks cell // /****************************************************************************************************/ IOReturn AppleSCCIrDA::sendCommand( UInt8 command, UInt8* result ) { IOReturn rtn = kIOReturnSuccess; UInt32 tCount = 0; UInt8 tbuff[8]; ELG( 0, 0, 'snCd', "sendCommand" ); XTRACE(kLogsnCd, 0, command); fSendingCommand = true; // flag to rx thread to *not* consume data if (result) *result = 0; // init return zero fpDevice->setState( PD_RS232_S_DTR, PD_RS232_S_DTR ); sendBaud( kDefaultRawBaudRate ); rtn = fpDevice->enqueueData( &command, 1, &tCount, false ); if ( rtn != kIOReturnSuccess ) { ELG( command, rtn, 'sCe-', "sendCommand - enqueue data failed" ); XTRACE(kLogsCeminus, rtn >> 16, rtn); } else { // could do a watchState here, but we want to make sure we drain // the fifo and not just get the first byte of noise IOSleep( 50 ); // fine tune timer? rtn = fpDevice->dequeueData( tbuff, sizeof(tbuff), &tCount, 0 ); if ( rtn == kIOReturnSuccess ) { XTRACE(kLogsCtC, tCount, tbuff[tCount-1]); ELG( tCount, tbuff[tCount-1], 'sCtC', "sendCommand - dequeue data" ); if ( tCount == 0 ) { XTRACE(kLogsCnminus, 0, 0); ELG( command, 0, 'sCn-', "sendCommand - dequeue data, no data returned" ); rtn = kIOReturnIOError; } else { if (result) *result = tbuff[tCount-1]; // Could have leading garbage because of the DTR wiggle so we take the last byte read XTRACE(kLogsCnplus, 0, *result); ELG( command, *result, 'sCn+', "sendCommand - dequeue data, successful" ); } } else { ELG( command, rtn, 'sCd-', "sendCommand - dequeue data failed" ); XTRACE(kLogsCdminus, rtn >> 16, rtn); } } fpDevice->setState( 0, PD_RS232_S_DTR ); sendBaud( fBaudCode ); fSendingCommand = false; // let rcv thread consume data again return rtn; }/* end sendCommand */ /****************************************************************************************************/ // // Function: AppleSCCIrDA::getFIReWorksVersion // // Inputs: None // // Outputs: return code - kIOReturnSuccess, kIOReturnIOError and others // // Desc: Gets the version of the FIReworks cell in the SCC // (part of initialization) // /****************************************************************************************************/ IOReturn AppleSCCIrDA::getFIReWorksVersion( void ) { UInt8 getversion = 0x01; IOReturn rtn = kIOReturnSuccess; ELG( 0, 0, 'gFWV', "getFIReWorksVersion" ); XTRACE(kLoggFWV, 0, 0); rtn = sendCommand( getversion, fInBuffer ); if ( rtn == kIOReturnSuccess ) { ELG( 0, fInBuffer[0], 'gFd+', "getFIReWorksVersion - dequeue data (getversion) successful" ); XTRACE(kLoggFdplus, 0, fInBuffer[0]); } return rtn; }/* end getFIReWorksVersion */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::resetDTR // // Inputs: // // Outputs: // // Desc: Reset and wiggle the DTR line // Holding DTR high over 100ms resets the FIReworks chip // /****************************************************************************************************/ void AppleSCCIrDA::resetDTR() { ELG( 0, 0, 'rDTR', "resetDTR" ); XTRACE(kLogrDTR, 0, 0); sendBaud( kDefaultRawBaudRate ); fpDevice->setState( PD_RS232_S_DTR, PD_RS232_S_DTR ); IOSleep(101); // Actually 100 for the reset +1 for fudge fpDevice->setState( 0, PD_RS232_S_DTR ); sendBaud( fBaudCode ); }/* end resetDTR */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::setupDevice // // Inputs: // // Outputs: IOReturn - kIOReturnSuccess, various others // // Desc: Set up and open the port // /****************************************************************************************************/ IOReturn AppleSCCIrDA::setupDevice() { IOReturn rtn = kIOReturnSuccess; ELG( 0, 0, 'suDv', "setupDevice" ); XTRACE(kLogsuDv, 0, 0); rtn = fpDevice->acquirePort( false ); // Get the port on behalf of IrDA (so we can do the discovers) if ( rtn != kIOReturnSuccess ) { ELG( 0, rtn, 'sDp-', "setupDevice - acquirePort failed" ); XTRACE(kLogsDpminus, rtn >> 16, rtn); } else { #ifdef Trace_SCCSerial rtn = fpDevice->executeEvent(IRDLOG_HACK, (UInt32)IrDALogAdd); if (rtn == kIOReturnSuccess) { IOLog("told serial of irdalog %d\n", rtn); } else { IOLog("scc serial didn't know of irdalog hack\n"); } #endif if ( !enableSCC() ) { ELG( 0, 0, 'sDe-', "setupDevice - enableSCC failed" ); XTRACE(kLogsDeminus, 0, 0); rtn = kIOReturnIOError; } else { // Set some defaults //SetSpeed( kDefaultBaudRate ); // too soon for this fBaudCode = 9600; // but set line speed for SendCommand to revert back to rtn = fpDevice->executeEvent( PD_E_DATA_SIZE, (kDefaultDataSize << 1) ); if ( rtn != kIOReturnSuccess ) { ELG( kDefaultDataSize, rtn, 'sDd-', "setupDevice - execute event (data size) failed" ); XTRACE(kLogsDdminus, rtn >> 16, rtn); } else { rtn = fpDevice->executeEvent( PD_E_DATA_INTEGRITY, PD_RS232_PARITY_NONE ); if ( rtn != kIOReturnSuccess ) { ELG( PD_RS232_PARITY_NONE, rtn, 'sDi-', "setupDevice - execute event (data integrity) failed" ); XTRACE(kLogsDiminus, rtn >> 16, rtn); } else { rtn = fpDevice->executeEvent( PD_RS232_E_STOP_BITS, (kDefaultStopBits << 1) ); if ( rtn != kIOReturnSuccess ) { ELG( kDefaultStopBits, rtn, 'sDs-', "setupDevice - execute event (stop bits) failed" ); XTRACE(kLogsDsminus, rtn >> 16, rtn); } else { rtn = fpDevice->executeEvent( PD_E_ACTIVE, true ); if ( rtn != kIOReturnSuccess ) { ELG( true, rtn, 'sDa-', "setupDevice - execute event (active) failed" ); XTRACE(kLogsDaminus, rtn >> 16, rtn); } else { // notes: both calling acquirePort and executing PD_E_ACTIVE in // the current implementation will reset this back to the default. // see speed_change_thread for where this is really set rtn = fpDevice->executeEvent(PD_E_DATA_LATENCY, 1); check(rtn == kIOReturnSuccess); } } } } } } if ( rtn != kIOReturnSuccess ) { fpDevice->releasePort(); } return rtn; }/* end setupDevice */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::configureDevice // // Inputs: // // Outputs: return Code - true (device configured), false (device not configured) // // Desc: Sets up and configure the SCC // /****************************************************************************************************/ bool AppleSCCIrDA::configureDevice( void ) { IOReturn rtn = kIOReturnSuccess; ELG( 0, 0, 'cDev', "configureDevice" ); XTRACE(kLogcDev, 0, 0); /* Set some defaults - qos values need tuning of course */ fQoS.version = 0x100; fQoS.datasize = 0x3f; // 1k = 1f, 2k = 3f fQoS.windowsize = 1; fQoS.minturn = 2; // review & tune. fQoS.baud1 = 0x00; // 4mbit no mir, all sir fQoS.baud2 = 0x3e; // 3e for 115k thru 9600 fQoS.bofs = 4; // review and tune. fQoS.sniff = 0; fQoS.unicast = 0; SetBofCount(10); // start with about 10 bofs (sets fBofsCode) ::gen_crc16_table(); // Initialize the crc 16 table (for SIR mode) ::gen_crc32_table(); // Initialize the crc 32 table (for FIR mode) if ( !fInBuffer ) { fInBuffer = (UInt8 *)IOMalloc( SCCLapPayLoad ); if ( !fInBuffer ) { ELG( 0, 0, 'cDi-', "configureDevice - input buffer allocation failed" ); XTRACE(kLogcDiminus, 0, 0); return false; } bzero( fInBuffer, SCCLapPayLoad ); } if ( !fOutBuffer ) { fOutBuffer = (UInt8 *)IOMalloc( SCCLapPayLoad ); if ( !fOutBuffer ) { ELG( 0, 0, 'cDo-', "configureDevice - output buffer allocation failed" ); XTRACE(kLogcDominus, 0, 0); IOFree( fInBuffer, SCCLapPayLoad ); fInBuffer = NULL; return false; } bzero( fOutBuffer, SCCLapPayLoad ); } if ( !fInUseBuffer ) { fInUseBuffer = (UInt8 *)IOMalloc( SCCLapPayLoad ); if ( !fInUseBuffer ) { ELG( 0, 0, 'cDu-', "configureDevice - in use buffer allocation failed" ); XTRACE(kLogcDuminus, 0, 0); IOFree( fInBuffer, SCCLapPayLoad ); IOFree( fOutBuffer, SCCLapPayLoad ); fInBuffer = NULL; fOutBuffer = NULL; return false; } bzero( fInUseBuffer, SCCLapPayLoad ); } fDataLength = 0; if (!allocateRingBuffer(&(fPort->TX), kMaxCirBufferSize) || !allocateRingBuffer(&(fPort->RX), kMaxCirBufferSize)) { ELG( 0, 0, 'cDa-', "configureDevice - allocate ring buffer failed" ); XTRACE(kLogcDaminus, 0, 0); IOFree( fInBuffer, SCCLapPayLoad ); IOFree( fOutBuffer, SCCLapPayLoad ); IOFree( fInUseBuffer, SCCLapPayLoad ); fInBuffer = NULL; fOutBuffer = NULL; fInUseBuffer = NULL; return false; } rtn = setupDevice(); if ( rtn == kIOReturnSuccess ) { // verify that we can talk to the hardware by reading the // FIReworks version number resetDTR(); // really reset the FIR cell //rtn = getFIReWorksVersion(); // won't work with workloops if ( rtn != kIOReturnSuccess ) { ELG( 0, rtn, 'cDF-', "configureDevice - getFIReWorksVersion failed" ); XTRACE(kLogcDFminus, rtn >> 16, rtn); } else { // Now initialze IrDA and set the name for this port fIrDA = IrDAComm::irDAComm( this, fUserClientNub); // create and init in one call if ( !fIrDA ) { ELG( 0, 0, 'cDI-', "configureDevice - IrDA initialize failed" ); XTRACE(kLogcDIminus, 0, 0); fpDevice->releasePort(); rtn = kIOReturnIOError; } else { bool rc; rc = thread_call_enter(rx_thread_call); // start the read loop check(rc == false); return true; } } } //killIO(); IOFree( fInBuffer, SCCLapPayLoad ); IOFree( fOutBuffer, SCCLapPayLoad ); IOFree( fInUseBuffer, SCCLapPayLoad ); fInBuffer = NULL; fOutBuffer = NULL; fInUseBuffer = NULL; freeRingBuffer( &fPort->TX ); freeRingBuffer( &fPort->RX ); ELG( 0, rtn, 'cDv-', "configureDevice - failed" ); XTRACE(kLogcDvminus, rtn >> 16, rtn); return false; }/* end configureDevice */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::createSerialStream // // Inputs: // // Outputs: return Code - true (created and initialilzed ok), false (it failed) // // Desc: Sets the name and registers the service // /****************************************************************************************************/ bool AppleSCCIrDA::createSerialStream() { ELG( 0, 0, 'cSSt', "createSerialStream" ); XTRACE(kLogcSSt, 0, 0); // Report the base name to be used for generating device nodes setProperty( kIOTTYBaseNameKey, baseName ); setProperty( kIOTTYSuffixKey, SCCsuffix ); // Need to chnage this registerService(); return true; }/* end createSerialStream */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::acquirePort // // Inputs: sleep - true (wait for it), false (don't) // // Outputs: Return Code - from provider acquirePort // // Desc: Acquires the IrDA port // The first aquirePort is done on behalf of IrDA (and sent to the SCC driver). // The first real (application) aquirePort is not sent on to the SCC driver, // all subsequent ones are returned with kIOReturnExclusiveAccess for the moment. // /****************************************************************************************************/ IOReturn AppleSCCIrDA::acquirePort(bool sleep) { PortInfo_t *port = fPort; UInt32 busyState = 0; IOReturn rtn = kIOReturnSuccess; ELG( port, sleep, 'acqP', "acquirePort" ); XTRACE(kLogAcquirePort, 0, 0); if ( fTerminate ) { int review_fTerminate; //return kIOReturnOffline; } SetStructureDefaults( port, FALSE ); /* Initialize all the structures */ for (;;) { XTRACE(kLogAcquirePort, 1, 1); busyState = readPortState( port ) & PD_S_ACQUIRED; if ( !busyState ) { // Set busy bit, and clear everything else XTRACE(kLogAcquirePort, 2, 2); changeState( port, (UInt32)PD_S_ACQUIRED | DEFAULT_STATE, (UInt32)STATE_ALL); break; } else { if ( !sleep ) { XTRACE(kLogAcquirePort, 3, 3); ELG( 0, 0, 'busy', "acquirePort - Busy exclusive access" ); return kIOReturnExclusiveAccess; } else { XTRACE(kLogAcquirePort, 4, 4); busyState = 0; rtn = watchState( &busyState, PD_S_ACQUIRED); XTRACE(kLogAcquirePort, 5, 5); if ( (rtn == kIOReturnIOError) || (rtn == kIOReturnSuccess) ) { continue; } else { ELG( 0, 0, 'int-', "acquirePort - Interrupted!" ); return rtn; } } } } /* end for */ fSessions++; //bump number of active sessions and turn on clear to send XTRACE(kLogAcquirePort, 6, 6); //changeState( port, PD_RS232_S_CTS, PD_RS232_S_CTS); changeState( port, PD_RS232_S_CTS | PD_RS232_S_CAR, PD_RS232_S_CTS | PD_RS232_S_CAR); CheckIrDAState(); // turn irda on/off if appropriate XTRACE(kLogAcquirePort,7, 7); if (1) { // wait for initial connect int counter = 0; while (fIrDA && fIrDA->Starting()) { counter++; // debugging IOSleep(100); XTRACE(kLogAcquirePort, 8, counter); if (counter > (10*10)) { // 10 second max on hanging open //IOLog("sccirda: open timed out\n"); break; } } //IOLog("AppleUSBIrDA: acquire port paused %d ms for initial connection\n", counter*100); } XTRACE(kLogAcquirePort, 0xffff, 0xffff); return rtn; }/* end acquirePort */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::releasePort // // Inputs: // // Outputs: Return Code - kIOReturnSuccess and various others // // Desc: Releases the IrDA port and does clean up. // /****************************************************************************************************/ IOReturn AppleSCCIrDA::releasePort() { PortInfo_t *port = fPort; UInt32 busyState; ELG( 0, port, 'relP', "releasePort" ); XTRACE(kLogReleasePort, 0, 0); busyState = (readPortState( port ) & PD_S_ACQUIRED); if ( !busyState ) { ELG( 0, 0, 'rlP-', "releasePort - NOT OPEN" ); return kIOReturnNotOpen; } changeState( port, 0, (UInt32)STATE_ALL ); // Clear the entire state word which also deactivates the port fSessions--; // reduce number of active sessions CheckIrDAState(); // turn irda off if appropriate ELG( 0, 0, 'RlP+', "releasePort - OK" ); return kIOReturnSuccess; }/* end releasePort */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::setState // // Inputs: state - state to set // mask - state mask // // Outputs: Return Code - from provider setState // // Desc: Sets the state for the port device. // /****************************************************************************************************/ IOReturn AppleSCCIrDA::setState( UInt32 state, UInt32 mask ) { PortInfo_t *port = fPort; ELG( state, mask, 'stSt', "setState" ); XTRACE(kLogSetState1, state >> 16, (short)state); XTRACE(kLogSetState2, mask >> 16, (short)mask); if ( mask & (PD_S_ACQUIRED | PD_S_ACTIVE | (~EXTERNAL_MASK)) ) return kIOReturnBadArgument; if ( readPortState( port ) & PD_S_ACQUIRED ) { // ignore any bits that are read-only mask &= (~port->FlowControl & PD_RS232_A_MASK) | PD_S_MASK; if ( mask) changeState( port, state, mask ); return kIOReturnSuccess; } return kIOReturnNotOpen; }/* end setState */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::getState // // Inputs: // // Outputs: state - port state // // Desc: Get the state for the port. // /****************************************************************************************************/ UInt32 AppleSCCIrDA::getState() { PortInfo_t *port = fPort; UInt32 state; ELG( 0, port, 'gtSt', "getState" ); CheckQueues(port); state = readPortState(port) & EXTERNAL_MASK; ELG( state, EXTERNAL_MASK, 'gtS-', "getState-->State" ); XTRACE(kLogGetState, state >> 16, (short)state); return state; }/* end getState */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::watchState // // Inputs: state - state to watch for // mask - state mask bits // // Outputs: Return Code - from provider watchState // // Desc: Wait for state bit changes // /****************************************************************************************************/ IOReturn AppleSCCIrDA::watchState( UInt32 *state, UInt32 mask ) { PortInfo_t *port = fPort; IOReturn ret = kIOReturnNotOpen; ELG( *state, mask, 'WatS', "watchState" ); XTRACE(kLogWatchState1, state >> 16, (short)state); XTRACE(kLogWatchState2, mask >> 16, (short)mask); if ( readPortState( port ) & PD_S_ACQUIRED ) { ret = kIOReturnSuccess; mask &= EXTERNAL_MASK; ret = privateWatchState( port, state, mask ); *state &= EXTERNAL_MASK; } ELG( ret, 0, 'WatS', "watchState --> watchState" ); XTRACE(kLogWatchState, 0xffff, 0xffff); return ret; }/* end watchState */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::nextEvent // // Inputs: // // Outputs: Return Code - from provider nextEvent // // Desc: Get the next event // /****************************************************************************************************/ UInt32 AppleSCCIrDA::nextEvent() { UInt32 rtn = kIOReturnSuccess; ELG( 0, 0, 'NxtE', "nextEvent" ); return rtn; }/* end nextEvent */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::executeEvent // // Inputs: event - The event // data - any data associated with the event // // Outputs: Return Code - from provider executeEvent // // Desc: executeEvent causes the specified event to be processed immediately. // This is primarily used for channel control commands like START & STOP // /****************************************************************************************************/ IOReturn AppleSCCIrDA::executeEvent( UInt32 event, UInt32 data ) { PortInfo_t *port = fPort; IOReturn ret = kIOReturnSuccess; UInt32 state, delta; delta = 0; state = readPortState( port ); ELG( port, state, 'ExIm', "executeEvent" ); XTRACE(kLogExecEvent, event >> 16, (short)event); XTRACE(kLogExecEventData, data >> 16, (short)data); if ( (state & PD_S_ACQUIRED) == 0 ) return kIOReturnNotOpen; switch ( event ) { case PD_RS232_E_XON_BYTE: ELG( data, event, 'ExIm', "executeEvent - PD_RS232_E_XON_BYTE" ); port->XONchar = data; break; case PD_RS232_E_XOFF_BYTE: ELG( data, event, 'ExIm', "executeEvent - PD_RS232_E_XOFF_BYTE" ); port->XOFFchar = data; break; case PD_E_SPECIAL_BYTE: ELG( data, event, 'ExIm', "executeEvent - PD_E_SPECIAL_BYTE" ); port->SWspecial[ data >> SPECIAL_SHIFT ] |= (1 << (data & SPECIAL_MASK)); break; case PD_E_VALID_DATA_BYTE: ELG( data, event, 'ExIm', "executeEvent - PD_E_VALID_DATA_BYTE" ); port->SWspecial[ data >> SPECIAL_SHIFT ] &= ~(1 << (data & SPECIAL_MASK)); break; case PD_E_FLOW_CONTROL: ELG( data, event, 'ExIm', "executeEvent - PD_E_FLOW_CONTROL" ); break; case PD_E_ACTIVE: ELG( data, event, 'Exlm', "executeEvent - PD_E_ACTIVE" ); if ( (bool)data ) { if ( !(state & PD_S_ACTIVE) ) { SetStructureDefaults( port, FALSE ); changeState( port, (UInt32)PD_S_ACTIVE, (UInt32)PD_S_ACTIVE ); // activate port } } else { if ( (state & PD_S_ACTIVE) ) { changeState( port, 0, (UInt32)PD_S_ACTIVE ); } } break; case PD_E_DATA_LATENCY: ELG( data, event, 'ExIm', "executeEvent - PD_E_DATA_LATENCY" ); port->DataLatInterval = long2tval( data * 1000 ); break; case PD_RS232_E_MIN_LATENCY: ELG( data, event, 'ExIm', "executeEvent - PD_RS232_E_MIN_LATENCY" ); port->MinLatency = bool( data ); break; case PD_E_DATA_INTEGRITY: ELG( data, event, 'Exlm', "executeEvent - PD_E_DATA_INTEGRITY" ); if ( (data < PD_RS232_PARITY_NONE) || (data > PD_RS232_PARITY_SPACE)) { ret = kIOReturnBadArgument; } else { port->TX_Parity = data; port->RX_Parity = PD_RS232_PARITY_DEFAULT; } break; case PD_E_DATA_RATE: ELG( data, event, 'Exlm', "executeEvent - PD_E_DATA_RATE" ); /* For API compatiblilty with Intel. */ data >>= 1; ELG( 0, data, 'Exlm', "executeEvent - actual data rate" ); if ( (data < kMinBaudRate) || (data > kMaxBaudRate) ) // Do we really care ret = kIOReturnBadArgument; else { port->BaudRate = data; } break; case PD_E_DATA_SIZE: ELG( data, event, 'Exlm', "executeEvent - PD_E_DATA_SIZE" ); /* For API compatiblilty with Intel. */ data >>= 1; ELG( 0, data, 'Exlm', "executeEvent - actual data size" ); if ( (data < 5) || (data > 8) ) ret = kIOReturnBadArgument; else { port->CharLength = data; } break; case PD_RS232_E_STOP_BITS: ELG( data, event, 'Exlm', "executeEvent - PD_RS232_E_STOP_BITS" ); if ( (data < 0) || (data > 20) ) ret = kIOReturnBadArgument; else { port->StopBits = data; } break; case PD_E_RXQ_FLUSH: ELG( data, event, 'Exlm', "executeEvent - PD_E_RXQ_FLUSH" ); break; case PD_E_RX_DATA_INTEGRITY: ELG( data, event, 'Exlm', "executeEvent - PD_E_RX_DATA_INTEGRITY" ); if ( (data != PD_RS232_PARITY_DEFAULT) && (data != PD_RS232_PARITY_ANY) ) ret = kIOReturnBadArgument; else port->RX_Parity = data; break; case PD_E_RX_DATA_RATE: ELG( data, event, 'Exlm', "executeEvent - PD_E_RX_DATA_RATE" ); if ( data ) ret = kIOReturnBadArgument; break; case PD_E_RX_DATA_SIZE: ELG( data, event, 'Exlm', "executeEvent - PD_E_RX_DATA_SIZE" ); if ( data ) ret = kIOReturnBadArgument; break; case PD_RS232_E_RX_STOP_BITS: ELG( data, event, 'Exlm', "executeEvent - PD_RS232_E_RX_STOP_BITS" ); if ( data ) ret = kIOReturnBadArgument; break; case PD_E_TXQ_FLUSH: ELG( data, event, 'Exlm', "executeEvent - PD_E_TXQ_FLUSH" ); break; case PD_RS232_E_LINE_BREAK: ELG( data, event, 'Exlm', "executeEvent - PD_RS232_E_LINE_BREAK" ); state &= ~PD_RS232_S_BRK; delta |= PD_RS232_S_BRK; break; case PD_E_DELAY: ELG( data, event, 'Exlm', "executeEvent - PD_E_DELAY" ); port->CharLatInterval = long2tval(data * 1000); break; case PD_E_RXQ_SIZE: ELG( 0, event, 'Exlm', "executeEvent - PD_E_RXQ_SIZE" ); break; case PD_E_TXQ_SIZE: ELG( 0, event, 'Exlm', "executeEvent - PD_E_TXQ_SIZE" ); break; case PD_E_RXQ_HIGH_WATER: ELG( data, event, 'Exlm', "executeEvent - PD_E_RXQ_HIGH_WATER" ); break; case PD_E_RXQ_LOW_WATER: ELG( data, event, 'Exlm', "executeEvent - PD_E_RXQ_LOW_WATER" ); break; case PD_E_TXQ_HIGH_WATER: ELG( data, event, 'Exlm', "executeEvent - PD_E_TXQ_HIGH_WATER" ); break; case PD_E_TXQ_LOW_WATER: ELG( data, event, 'Exlm', "executeEvent - PD_E_TXQ_LOW_WATER" ); break; default: ELG( data, event, 'Exlm', "executeEvent - unrecognized event" ); ret = kIOReturnBadArgument; break; } state |= state;/* ejk for compiler warnings. ?? */ changeState( port, state, delta ); return ret; }/* end executeEvent */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::requestEvent // // Inputs: event - The event // // Outputs: Return Code - from provider requestEvent // data - any data associated with the event // // Desc: requestEvent processes the specified event as an immediate request and // returns the results in data. This is primarily used for getting link // status information and verifying baud rate and such. // /****************************************************************************************************/ IOReturn AppleSCCIrDA::requestEvent( UInt32 event, UInt32 *data ) { PortInfo_t *port = fPort; IOReturn returnValue = kIOReturnSuccess; ELG( 0, readPortState( port ), 'ReqE', "requestEvent" ); XTRACE(kLogReqEvent, event >> 16, (short)event); if ( data == NULL ) { ELG( 0, event, 'ReqE', "requestEvent - data is null" ); returnValue = kIOReturnBadArgument; } else { XTRACE(kLogReqEventData, (*data) >> 16, (short)*data); switch ( event ) { case PD_E_ACTIVE: ELG( 0, event, 'ReqE', "requestEvent - PD_E_ACTIVE" ); *data = bool(readPortState( port ) & PD_S_ACTIVE); break; case PD_E_FLOW_CONTROL: ELG( port->FlowControl, event, 'ReqE', "requestEvent - PD_E_FLOW_CONTROL" ); *data = port->FlowControl; break; case PD_E_DELAY: ELG( 0, event, 'ReqE', "requestEvent - PD_E_DELAY" ); *data = tval2long( port->CharLatInterval )/ 1000; break; case PD_E_DATA_LATENCY: ELG( 0, event, 'ReqE', "requestEvent - PD_E_DATA_LATENCY" ); *data = tval2long( port->DataLatInterval )/ 1000; break; case PD_E_TXQ_SIZE: ELG( 0, event, 'ReqE', "requestEvent - PD_E_TXQ_SIZE" ); *data = GetQueueSize( &port->TX ); break; case PD_E_RXQ_SIZE: ELG( 0, event, 'ReqE', "requestEvent - PD_E_RXQ_SIZE" ); *data = GetQueueSize( &port->RX ); break; case PD_E_TXQ_LOW_WATER: ELG( 0, event, 'ReqE', "requestEvent - PD_E_TXQ_LOW_WATER" ); *data = 0; returnValue = kIOReturnBadArgument; break; case PD_E_RXQ_LOW_WATER: ELG( 0, event, 'ReqE', "requestEvent - PD_E_RXQ_LOW_WATER" ); *data = 0; returnValue = kIOReturnBadArgument; break; case PD_E_TXQ_HIGH_WATER: ELG( 0, event, 'ReqE', "requestEvent - PD_E_TXQ_HIGH_WATER" ); *data = 0; returnValue = kIOReturnBadArgument; break; case PD_E_RXQ_HIGH_WATER: ELG( 0, event, 'ReqE', "requestEvent - PD_E_RXQ_HIGH_WATER" ); *data = 0; returnValue = kIOReturnBadArgument; break; case PD_E_TXQ_AVAILABLE: ELG( 0, event, 'ReqE', "requestEvent - PD_E_TXQ_AVAILABLE" ); *data = FreeSpaceinQueue( &port->TX ); break; case PD_E_RXQ_AVAILABLE: ELG( 0, event, 'ReqE', "requestEvent - PD_E_RXQ_AVAILABLE" ); *data = UsedSpaceinQueue( &port->RX ); break; case PD_E_DATA_RATE: ELG( 0, event, 'ReqE', "requestEvent - PD_E_DATA_RATE" ); *data = port->BaudRate << 1; break; case PD_E_RX_DATA_RATE: ELG( 0, event, 'ReqE', "requestEvent - PD_E_RX_DATA_RATE" ); *data = 0x00; break; case PD_E_DATA_SIZE: ELG( 0, event, 'ReqE', "requestEvent - PD_E_DATA_SIZE" ); *data = port->CharLength << 1; break; case PD_E_RX_DATA_SIZE: ELG( 0, event, 'ReqE', "requestEvent - PD_E_RX_DATA_SIZE" ); *data = 0x00; break; case PD_E_DATA_INTEGRITY: ELG( 0, event, 'ReqE', "requestEvent - PD_E_DATA_INTEGRITY" ); *data = port->TX_Parity; break; case PD_E_RX_DATA_INTEGRITY: ELG( 0, event, 'ReqE', "requestEvent - PD_E_RX_DATA_INTEGRITY" ); *data = port->RX_Parity; break; case PD_RS232_E_STOP_BITS: ELG( 0, event, 'ReqE', "requestEvent - PD_RS232_E_STOP_BITS" ); *data = port->StopBits << 1; break; case PD_RS232_E_RX_STOP_BITS: ELG( 0, event, 'ReqE', "requestEvent - PD_RS232_E_RX_STOP_BITS" ); *data = 0x00; break; case PD_RS232_E_XON_BYTE: ELG( 0, event, 'ReqE', "requestEvent - PD_RS232_E_XON_BYTE" ); *data = port->XONchar; break; case PD_RS232_E_XOFF_BYTE: ELG( 0, event, 'ReqE', "requestEvent - PD_RS232_E_XOFF_BYTE" ); *data = port->XOFFchar; break; case PD_RS232_E_LINE_BREAK: ELG( 0, event, 'ReqE', "requestEvent - PD_RS232_E_LINE_BREAK" ); *data = bool(readPortState( port ) & PD_RS232_S_BRK); break; case PD_RS232_E_MIN_LATENCY: ELG( 0, event, 'ReqE', "requestEvent - PD_RS232_E_MIN_LATENCY" ); *data = bool( port->MinLatency ); break; default: ELG( 0, event, 'ReqE', "requestEvent - unrecognized event" ); returnValue = kIOReturnBadArgument; break; } } return kIOReturnSuccess; }/* end requestEvent */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::enqueueEvent // // Inputs: event - The event, data - any data associated with the event, // sleep - true (wait for it), false (don't) // // Outputs: Return Code - provider enqueueEvent // // Desc: Enqueue the event. // /****************************************************************************************************/ IOReturn AppleSCCIrDA::enqueueEvent( UInt32 event, UInt32 data, bool sleep ) { PortInfo_t *port = fPort; ELG( data, event, 'EnqE', "enqueueEvent" ); if ( readPortState( port ) & PD_S_ACTIVE ) { return kIOReturnSuccess; } return kIOReturnNotOpen; }/* end enqueueEvent */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::dequeueEvent // // Inputs: sleep - true (wait for it), false (don't) // // Outputs: Return Code - from provider dequeueEvent // event - the event // data - any associated data // // Desc: Dequeue next event. // /****************************************************************************************************/ IOReturn AppleSCCIrDA::dequeueEvent( UInt32 *event, UInt32 *data, bool sleep ) { PortInfo_t *port = fPort; ELG( 0, 0, 'DeqE', "dequeueEvent" ); if ( (event == NULL) || (data == NULL) ) return kIOReturnBadArgument; if ( readPortState( port ) & PD_S_ACTIVE ) { return kIOReturnSuccess; } return kIOReturnNotOpen; }/* end dequeueEvent */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::enqueueData // // Inputs: buffer - the data // size - number of bytes // sleep - true (wait for it), false (don't), // // Outputs: Return Code - kIOReturnSuccess, kIOReturnIOError, kIOReturnBadArgument or kIOReturnNotOpen // count - bytes transferred, // // Desc: Enqueue data to be sent to IrDA // /****************************************************************************************************/ IOReturn AppleSCCIrDA::enqueueData( UInt8 *buffer, UInt32 size, UInt32 *count, bool sleep ) { PortInfo_t *port = fPort; UInt32 state = PD_S_TXQ_LOW_WATER; IOReturn rtn = kIOReturnSuccess; ELG( 0, sleep, 'eqDt', "enqueData" ); if ( fTerminate ) return kIOReturnOffline; if ( count == NULL || buffer == NULL ) return kIOReturnBadArgument; *count = 0; if ( !(readPortState( port ) & PD_S_ACTIVE) ) return kIOReturnNotOpen; ELG( port->State, size, 'eqDt', "enqueData State" ); LogData( kUSBOut, size, buffer ); /* OK, go ahead and try to add something to the buffer */ *count = AddtoQueue( &port->TX, buffer, size ); CheckQueues( port ); /* Let the tranmitter know that we have something ready to go */ SetUpTransmit( ); /* If we could not queue up all of the data on the first pass and */ /* the user wants us to sleep until it's all out then sleep */ while ( (*count < size) && sleep ) { state = PD_S_TXQ_LOW_WATER; rtn = watchState( &state, PD_S_TXQ_LOW_WATER ); if ( rtn != kIOReturnSuccess ) { ELG( 0, rtn, 'EqD-', "enqueueData - interrupted" ); return rtn; } *count += AddtoQueue( &port->TX, buffer + *count, size - *count ); CheckQueues( port ); /* Let the tranmitter know that we have something ready to go. */ SetUpTransmit( ); }/* end while */ ELG( *count, size, 'enqd', "enqueueData - Enqueue" ); return kIOReturnSuccess; }/* end enqueueData */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::dequeueData // // Inputs: size - buffer size // min - minimum bytes required // // Outputs: buffer - data returned // Return Code - from provider dequeueData // // Desc: dequeueData will attempt to copy data from the RX queue to the // specified buffer. // /****************************************************************************************************/ IOReturn AppleSCCIrDA::dequeueData( UInt8 *buffer, UInt32 size, UInt32 *count, UInt32 min ) { PortInfo_t *port = fPort; IOReturn rtn = kIOReturnSuccess; UInt32 state = 0; ELG( size, min, 'dqDt', "dequeueData" ); /* Check to make sure we have good arguments. */ if ( (count == NULL) || (buffer == NULL) || (min > size) ) return kIOReturnBadArgument; /* If the port is not active then there should not be any chars. */ *count = 0; if ( !(readPortState( port ) & PD_S_ACTIVE) ) return kIOReturnNotOpen; /* Get any data living in the queue. */ *count = RemovefromQueue( &port->RX, buffer, size ); if (fIrDA) fIrDA->ReturnCredit( *count ); // return credit when room in the queue CheckQueues( port ); while ( (min > 0) && (*count < min) ) { int count_read; /* Figure out how many bytes we have left to queue up */ state = 0; rtn = watchState( &state, PD_S_RXQ_EMPTY ); if ( rtn != kIOReturnSuccess ) { ELG( 0, rtn, 'DqD-', "dequeueData - Interrupted!" ); LogData( kUSBIn, *count, buffer ); return rtn; } /* Try and get more data starting from where we left off */ count_read = RemovefromQueue( &port->RX, buffer + *count, (size - *count) ); if (fIrDA) fIrDA->ReturnCredit(count_read); // return credit when room in the queue *count += count_read; CheckQueues( port ); }/* end while */ LogData( kUSBIn, *count, buffer ); ELG( *count, size, 'deqd', "dequeueData -->Out Dequeue" ); return rtn; }/* end dequeueData */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::SetUpTransmit // // Inputs: // // Outputs: return code - true (transmit started), false (transmission already in progress or error) // // Desc: Setup and then start transmisson // /****************************************************************************************************/ bool AppleSCCIrDA::SetUpTransmit( void ) { size_t count = 0; size_t data_Length, tCount; UInt8 *TempOutBuffer; ELG( fPort, fPort->AreTransmitting, 'upTx', "SetUpTransmit" ); XTRACE(kLogSUTm, 0, fPort->AreTransmitting); // If we are already in the cycle of transmitting characters, // then we do not need to do anything. if ( fPort->AreTransmitting == TRUE ) return false; // First check if we can actually do anything, also if IrDA has no room we're done for now //if ( GetQueueStatus( &fPort->TX ) != queueEmpty ) if (UsedSpaceinQueue(&fPort->TX) > 0) { data_Length = fIrDA->TXBufferAvailable(); if ( data_Length == 0 ) { return false; } if ( data_Length > MAX_BLOCK_SIZE ) { data_Length = MAX_BLOCK_SIZE; } TempOutBuffer = (UInt8*)IOMalloc( data_Length ); if ( !TempOutBuffer ) { ELG( 0, 0, 'STA-', "SetUpTransmit - buffer allocation problem" ); return false; } bzero( TempOutBuffer, data_Length ); // Fill up the buffer with characters from the queue count = RemovefromQueue( &fPort->TX, TempOutBuffer, data_Length ); XTRACE(kLogSIWplus, fPort->State, count); ELG( fPort->State, count, ' Tx+', "SetUpTransmit - Sending to IrDA" ); fPort->AreTransmitting = TRUE; changeState( fPort, PD_S_TX_BUSY, PD_S_TX_BUSY ); tCount = fIrDA->Write( TempOutBuffer, count ); // do the "transmit" -- send to IrCOMM changeState( fPort, 0, PD_S_TX_BUSY ); fPort->AreTransmitting = false; IOFree( TempOutBuffer, data_Length ); if ( tCount != count ) { XTRACE(kLogSIWminus, tCount, count); ELG( tCount, count, 'IrW-', "SetUpTransmit - IrDA write problem, data has been dropped" ); return false; } // We potentially removed a bunch of stuff from the // queue, so see if we can free some thread(s) // to enqueue more stuff. CheckQueues( fPort ); } return true; }/* SetUpTransmit */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::StartTransmit // // Inputs: control_length - Length of control data // control_buffer - Control data // data_length - Length of raw data // data_buffer - raw data // // Outputs: Return code - kIOReturnSuccess and others // // Desc: Start the transmisson // /****************************************************************************************************/ IOReturn AppleSCCIrDA::StartTransmit( UInt32 control_length, UInt8 *control_buffer, UInt32 data_length, UInt8 *data_buffer ) { IOReturn rtn = kIOReturnSuccess; UInt32 count = 0; ELG( control_length, data_length, 'StTx', "StartTransmit" ); XTRACE(kLogstTx, control_length, data_length); parseInputReset(); // discard any partial input packet require(control_length + data_length > 0, Fail); // sanity check count = Prepare_Buffer_For_Transmit(fOutBuffer, control_length, control_buffer, data_length, data_buffer); LogData( kDriverOut, count, fOutBuffer ); XTRACE(kLogXmitCount, 0, count); thread_call_enter1(tx_thread_call, (thread_call_param_t)count); // send it out and wait for it in another workloop return rtn; Fail: return -1; }/* end StartTransmit */ /****************************************************************************************************/ // // Method: AppleUSBIrDADriver::SetStructureDefaults // // Inputs: port - the port to set the defaults, Init - Probe time or not // // Outputs: None // // Desc: Sets the defaults for the specified port structure // /****************************************************************************************************/ void AppleSCCIrDA::SetStructureDefaults( PortInfo_t *port, bool Init ) { UInt32 tmp; ELG( 0, 0, 'StSD', "SetStructureDefaults" ); XTRACE(kLogSetStructureDefaults, 0, Init); /* These are initialized when the port is created and shouldn't be reinitialized. */ if ( Init ) { port->FCRimage = 0x00; port->IERmask = 0x00; port->State = ( PD_S_TXQ_EMPTY | PD_S_TXQ_LOW_WATER | PD_S_RXQ_EMPTY | PD_S_RXQ_LOW_WATER ); port->WatchStateMask = 0x00000000; // port->serialRequestLock = 0; // port->readActive = false; } port->BaudRate = kDefaultBaudRate; // 9600 bps port->CharLength = 8; // 8 Data bits port->StopBits = 2; // 1 Stop bit port->TX_Parity = 1; // No Parity port->RX_Parity = 1; // --ditto-- port->MinLatency = false; port->XONchar = '\x11'; port->XOFFchar = '\x13'; port->FlowControl = 0x00000000; port->RXOstate = IDLE_XO; port->TXOstate = IDLE_XO; //port->FrameTOEntry = NULL; port->RXStats.BufferSize = kMaxCirBufferSize; port->RXStats.HighWater = (port->RXStats.BufferSize << 1) / 3; port->RXStats.LowWater = port->RXStats.HighWater >> 1; port->TXStats.BufferSize = kMaxCirBufferSize; port->TXStats.HighWater = (port->RXStats.BufferSize << 1) / 3; port->TXStats.LowWater = port->RXStats.HighWater >> 1; port->FlowControl = (DEFAULT_AUTO | DEFAULT_NOTIFY); // port->FlowControl = DEFAULT_NOTIFY; port->AreTransmitting = FALSE; for ( tmp=0; tmp < (256 >> SPECIAL_SHIFT); tmp++ ) port->SWspecial[ tmp ] = 0; return; }/* end SetStructureDefaults */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::freeRingBuffer // // Inputs: Queue - the specified queue to free // // Outputs: // // Desc: Frees all resources assocated with the queue, then sets all queue parameters // to safe values. // /****************************************************************************************************/ void AppleSCCIrDA::freeRingBuffer( CirQueue *Queue ) { ELG( 0, Queue, 'frRB', "freeRingBuffer" ); XTRACE(kLogfrRB, 0, 0); if ( Queue->Start ) { IOFree( Queue->Start, Queue->Size ); CloseQueue( Queue ); } return; }/* end freeRingBuffer */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::allocateRingBuffer // // Inputs: Queue - the specified queue to allocate, BufferSize - size to allocate // // Outputs: return Code - true (buffer allocated), false (it failed) // // Desc: Allocates resources needed by the queue, then sets up all queue parameters. // /****************************************************************************************************/ bool AppleSCCIrDA::allocateRingBuffer( CirQueue *Queue, size_t BufferSize ) { UInt8 *Buffer; ELG( 0, BufferSize, 'alRB', "allocateRingBuffer" ); XTRACE(kLogalRB, 0, 0); if ( !Queue->Start ) { Buffer = (UInt8*)IOMalloc( BufferSize ); InitQueue( Queue, Buffer, BufferSize ); } if ( Queue->Start ) return true; return false; }/* end allocateRingBuffer */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::readPortState // // Inputs: port - the specified port // // Outputs: returnState - current state of the port // // Desc: Reads the current Port->State. // /****************************************************************************************************/ UInt32 AppleSCCIrDA::readPortState( PortInfo_t *port ) { UInt32 returnState; // ELG( 0, port, 'rPSt', "readPortState" ); IOLockLock( port->serialRequestLock ); returnState = port->State; IOLockUnlock( port->serialRequestLock); // ELG( returnState, 0, 'rPS-', "readPortState" ); return returnState; }/* end readPortState */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::changeState // // Inputs: port - the specified port, state - new state, mask - state mask (the specific bits) // // Outputs: None // // Desc: Change the current Port->State to state using the mask bits. // if mask = 0 nothing is changed. // delta contains the difference between the new and old state taking the // mask into account and it's used to wake any waiting threads as appropriate. // /****************************************************************************************************/ void AppleSCCIrDA::changeState( PortInfo_t *port, UInt32 state, UInt32 mask ) { UInt32 delta; // ELG( state, mask, 'chSt', "changeState" ); XTRACE(kLogChangeStateBits, state >> 16, (short)state); XTRACE(kLogChangeStateMask, mask >> 16, (short)mask); IOLockLock( port->serialRequestLock ); state = (port->State & ~mask) | (state & mask); // compute the new state delta = state ^ port->State; // keep a copy of the diffs port->State = state; XTRACE(kLogChangeStateDelta, delta >> 16, (short)delta); XTRACE(kLogChangeStateNew, port->State >> 16, (short)port->State); // Wake up all threads asleep on WatchStateMask if ( delta & port->WatchStateMask ) { thread_wakeup_with_result( &port->WatchStateMask, THREAD_RESTART ); } IOLockUnlock( port->serialRequestLock ); ELG( port->State, delta, 'chSt', "changeState - exit" ); return; }/* end changeState */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::privateWatchState // // Inputs: port - the specified port, state - state watching for, mask - state mask (the specific bits) // // Outputs: IOReturn - kIOReturnSuccess, kIOReturnIOError or kIOReturnIPCError // // Desc: Wait for the at least one of the state bits defined in mask to be equal // to the value defined in state. Check on entry then sleep until necessary. // A return value of kIOReturnSuccess means that at least one of the port state // bits specified by mask is equal to the value passed in by state. A return // value of kIOReturnIOError indicates that the port went inactive. A return // value of kIOReturnIPCError indicates sleep was interrupted by a signal. // /****************************************************************************************************/ IOReturn AppleSCCIrDA::privateWatchState( PortInfo_t *port, UInt32 *state, UInt32 mask ) { unsigned watchState, foundStates; bool autoActiveBit = false; IOReturn rtn = kIOReturnSuccess; // ELG( mask, *state, 'wsta', "privateWatchState" ); watchState = *state; IOLockLock( port->serialRequestLock ); // hack to get around problem with carrier detection if ( *state | 0x40 ) // never wait on dsr going high or low { port->State |= 0x40; } if ( !(mask & (PD_S_ACQUIRED | PD_S_ACTIVE)) ) { watchState &= ~PD_S_ACTIVE; // Check for low PD_S_ACTIVE mask |= PD_S_ACTIVE; // Register interest in PD_S_ACTIVE bit autoActiveBit = true; } for (;;) { // Check port state for any interesting bits with watchState value // NB. the '^ ~' is a XNOR and tests for equality of bits. foundStates = (watchState ^ ~port->State) & mask; if ( foundStates ) { *state = port->State; if ( autoActiveBit && (foundStates & PD_S_ACTIVE) ) { rtn = kIOReturnIOError; } else { rtn = kIOReturnSuccess; } // ELG( rtn, foundStates, 'FndS', "privateWatchState - foundStates" ); break; } // Everytime we go around the loop we have to reset the watch mask. // This means any event that could affect the WatchStateMask must // wakeup all watch state threads. The two events are an interrupt // or one of the bits in the WatchStateMask changing. port->WatchStateMask |= mask; // note: Interrupts need to be locked out completely here, // since as assertwait is called other threads waiting on // &port->WatchStateMask will be woken up and spun through the loop. // If an interrupt occurs at this point then the current thread // will end up waiting with a different port state than assumed // -- this problem was causing dequeueData to wait for a change in // PD_E_RXQ_EMPTY to 0 after an interrupt had already changed it to 0. assert_wait( &port->WatchStateMask, true ); /* assert event */ IOLockUnlock( port->serialRequestLock ); rtn = thread_block( (void(*)(void))0 ); /* block ourselves */ IOLockLock( port->serialRequestLock ); if ( rtn == THREAD_RESTART ) { continue; } else { rtn = kIOReturnIPCError; break; } }/* end for */ // As it is impossible to undo the masking used by this // thread, we clear down the watch state mask and wakeup // every sleeping thread to reinitialize the mask before exiting. port->WatchStateMask = 0; thread_wakeup_with_result( &port->WatchStateMask, THREAD_RESTART ); IOLockUnlock( port->serialRequestLock); // ELG( rtn, *state, 'wEnd', "privateWatchState end" ); return rtn; }/* end privateWatchState */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::message // // Inputs: type - message type // provider - my provider // argument - additional parameters // // Outputs: return Code - kIOReturnSuccess // // Desc: Handles IOKit messages. // /****************************************************************************************************/ IOReturn AppleSCCIrDA::message( UInt32 type, IOService *provider, void *argument ) { ELG( 0, type, 'mess', "message" ); XTRACE(kLogmess, type >> 16, type); switch ( type ) { case kIOMessageServiceIsTerminated: ELG( 0, type, 'ms01', "message - kIOMessageServiceIsTerminated" ); XTRACE(kLogms01, 0, 0); fTerminate = true; // we're being terminated break; case kIOMessageServiceIsSuspended: ELG( 0, type, 'ms02', "message - kIOMessageServiceIsSuspended" ); XTRACE(kLogms02, 0, 0); break; case kIOMessageServiceIsResumed: ELG( 0, type, 'ms03', "message - kIOMessageServiceIsResumed" ); XTRACE(kLogms03, 0, 0); break; case kIOMessageServiceIsRequestingClose: ELG( 0, type, 'ms04', "message - kIOMessageServiceIsRequestingClose" ); XTRACE(kLogms04, 0, 0); break; case kIOMessageServiceWasClosed: ELG( 0, type, 'ms05', "message - kIOMessageServiceWasClosed" ); XTRACE(kLogms05, 0, 0); break; case kIOMessageServiceBusyStateChange: ELG( 0, type, 'ms06', "message - kIOMessageServiceBusyStateChange" ); XTRACE(kLogms06, 0, 0); break; default: ELG( 0, type, 'mes-', "message - unknown message" ); XTRACE(kLogmesminus, 0, 0); break; } return kIOReturnSuccess; }/* end message */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::parseInputBuffer // // Inputs: length - length of data // data - data received // // Outputs: // // Desc: Kick off the real parse engine // /****************************************************************************************************/ void AppleSCCIrDA::parseInputBuffer( UInt32 length, UInt8 *data ) { // ELG( 0, length, 'pIpB', "parseInputBuffer" ); XTRACE(kLogpIpB, 0, length); if ( fModeFlag == kMode_SIR ) { parseInputSIR( length, data ); } else { if ( fModeFlag == kMode_FIR ) { parseInputFIR( length, data ); } else { ELG( 0, fModeFlag, 'pIm-', "parseInputBuffer - incorrect mode, data dropped" ); XTRACE(kLogpImminus, 0, fModeFlag); } } }/* end parseInputBuffer */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::parseInputSIR // // Inputs: length - length of data // data - data received // // Outputs: // // Desc: Parse the input buffer in SIR mode // /****************************************************************************************************/ void AppleSCCIrDA::parseInputSIR( UInt32 length, UInt8 *data ) { IOReturn rtn = kIOReturnSuccess; UInt8 byte; // ELG( 0, 0, 'pISR', "parseInputSIR" ); XTRACE(kLogpISR, 0, 0); // Loop over newly received data while (length-- > 0) { byte = *data++; switch ( fParseState ) { case kParseStateIdle: XTRACE(kLogpStI, 0, byte); // ELG( fParseState, byte, 'pStI', "parseInputSIR - parse idle state" ); if (byte == 0xC0) // Idle State - discard everything but BOF { fParseState = kParseStateBOF; } break; case kParseStateBOF: XTRACE(kLogpStB, 0, byte); // ELG( fParseState, byte, 'pStB', "parseInputSIR - parse BOF state" ); switch (byte) { case 0xC0: // BOF State - multiple BOFs are ignored break; case 0xC1: // BOF State - EOF is invalid fParseState = kParseStateIdle; fDataLength = 0; break; case 0x7D: // BOF State - ESCAPE, starts with a pad byte fParseState = kParseStatePad; break; default: // BOF State - data, starts with a normal byte fInUseBuffer[fDataLength++] = byte; fParseState = kParseStateData; break; } break; case kParseStateData: XTRACE(kLogpStd, 0, byte); // ELG( fParseState, byte, 'pStd', "parseInputSIR - parse data state" ); switch (byte) { case 0xC0: // Data State - BOF is invalid in the data section of a packet fParseState = kParseStateIdle; fDataLength = 0; break; case 0xC1: // Data State - EOF, done with the packet, check the CRC if ( fDataLength > 2 ) { if ( ::check_crc16(fInUseBuffer, fDataLength) ) // Check CRC is valid { fDataLength -= 2; // Don't pass back the CRC if ( fIrDA ) { LogData( kDriverIn, fDataLength, fInUseBuffer ); rtn = fIrDA->ReadComplete( fInUseBuffer, fDataLength ); if ( rtn != kIOReturnSuccess ) { ELG( 0, rtn, 'pSI-', "parseInputSIR - IrDA ReadComplete problem" ); XTRACE(kLogpSIminus, rtn >> 16, rtn); } } } else { ELG( 0, 0, 'pSC-', "parseInputSIR - CRC error" ); XTRACE(kLogpSCminus, 0, 0); fICRCError++; } } else { ELG( 0, 0, 'pSE-', "parseInputSIR - EOF early < 2 bytes of data" ); XTRACE(kLogpSEminus, fParseState, 0); } fParseState = kParseStateIdle; fDataLength = 0; break; case 0x7D: // Data State - pad byte, switch to pad state fParseState = kParseStatePad; break; default: // Data State - by golly it's data fInUseBuffer[fDataLength++] = byte; break; } break; case kParseStatePad: XTRACE(kLogpStp, 0, byte); // ELG( fParseState, byte, 'pStp', "parseInputSIR - parse pad state" ); fInUseBuffer[fDataLength++] = byte ^ 0x20; fParseState = kParseStateData; break; default: ELG( fParseState, byte, 'pSte', "parseInputSIR - state error" ); XTRACE(kLogpSte, fParseState, byte); break; } } }/* end parseInputSIR */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::parseInputFIR // // Inputs: length - length of data // data - data received // // Outputs: // // Desc: Parse the input buffer in FIR mode // /****************************************************************************************************/ void AppleSCCIrDA::parseInputFIR( UInt32 length, UInt8 *data ) { ELG( 0, 0, 'pIFR', "parseInputFIR - Currently not supported" ); XTRACE(kLogpIFR, 0, 0); }/* end parseInputFIR */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::parseInputReset // // Inputs: none // // Outputs: fParseState and fDataLength get reset // // Desc: initialize input parse engine (on each packet transmit) // /****************************************************************************************************/ void AppleSCCIrDA::parseInputReset( void ) { ELG( 0, 0, 'pIRt', "parseInputReset" ); XTRACE(kLogpIRt, 0, 0); fParseState = kParseStateIdle; fDataLength = 0; }/* end parseInputReset */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::Prepare_Buffer_For_Transmit // // Inputs: fOutBuffer - the transmit buffer // control_length - Length of control data // control_buffer - Control data // data_length - Length of raw data // data_buffer - raw data // // Outputs: length - actual length to transmit // // Desc: Sets up the transmit buffer as follows: // first N-1 bytes of XBOF characters // then the BOF byte // then the IrLAP frame // then the CRC16 // then the EOF // /****************************************************************************************************/ UInt32 AppleSCCIrDA::Prepare_Buffer_For_Transmit( UInt8 *fOutBuffer, UInt32 control_length, UInt8 *control_buffer, UInt32 data_length, UInt8 *data_buffer ) { UInt32 length; // length of xmit buffer (not including 4 byte header) UInt8 *dest; // pointer into constructed xmit buffer UInt8 *src; // pointer into input xmit packet int src_length; // original write length from user (irlap length) int i; UInt16 crc16; // sir crc ELG( 0, 0, 'PBFT', "Prepare_Buffer_For_Transmit" ); XTRACE(kLogPBFT, 0, 0); dest = fOutBuffer; // where to start building the xmit // Start off with a few BOF bytes. The old irda spec (1.0) says to start with C0 bytes, // but the 1.1 spec says to use 0xFF and a single 0xC0 as a BOF flag. for (i = 0; i < fBofsCode; i++) // N-1 pad bytes of 0xFF { *dest++ = 0xFF; // change these to 0xC0 to match old spec (for testing) } *dest++ = 0xC0; // one BOF byte after the 0xFF pad bytes length = fBofsCode+1; // review // Now copy the irlap packet, doing byte stuffing as needed src = control_buffer; // start of client's irlap packet src_length = control_length; // grab count of client's bytes while (src_length-- > 0) // copy over the user bytes { SIRStuff(*src++, &dest, &length); // byte stuffing along the way } src = data_buffer; // and again for the non-control portion src_length = data_length; while (src_length-- > 0) // copy over the user bytes { SIRStuff(*src++, &dest, &length); // byte stuffing along the way } // now we append the CRC16. Make it from the original buffer, non-escape byte crc16 = 0xffff; // initialize the crc crc16 = ::update_crc16(crc16, control_buffer, control_length); // update w/the packet crc16 = ::update_crc16(crc16, data_buffer, data_length); // update w/the packet crc16 = ~crc16; // finalize the crc SIRStuff(crc16 >> 0, &dest, &length); // add in the crc16, lsb then msb SIRStuff(crc16 >> 8, &dest, &length); // crc bytes are byte-stuffed too // and finally end with EOF *dest++ = 0xC1; length++; // length is now what we want to actually transmit return length; }/* end Prepare_Buffer_For_Transmit */ /****************************************************************************************************/ // // Method: AppleSCCIrDA::SIRStuff // // Inputs: byte - data to be stuffed // destptr - where to put it // // Outputs: lengthPtr - updated lenth // // Desc: Stuff byte into the output buffer in SIR mode // /****************************************************************************************************/ void AppleSCCIrDA::SIRStuff(UInt8 byte, UInt8 **destPtr, UInt32 *lengthPtr) { UInt8 *dest = *destPtr; UInt32 length = *lengthPtr; switch (byte) { case 0xC0: case 0xC1: case 0x7D: *dest++ = 0x7D; // the escape byte followed by ... *dest++ = byte ^ 0x20; // c0 to e0, c1 to e1, 7d to 5d length += 2; break; default: *dest++ = byte; // the usual case, non-escaped byte to copy length++; break; } *destPtr = dest; *lengthPtr = length; return; }/* end SIRStuff */ /* static */ void AppleSCCIrDA::tx_thread(thread_call_param_t param0, thread_call_param_t param1) { AppleSCCIrDA *obj; UInt32 count = (UInt32)param1; UInt32 tCount; UInt32 waitBits; IOReturn rtn; XTRACE(kLogTxThread, 0, (short)param1); require(param0, Fail); obj = OSDynamicCast(AppleSCCIrDA, (OSObject *)param0); require(obj, Fail); require(obj->fpDevice, Fail); // now that we have SetSpeedComplete, this nonsense is not // needed anymore ... /**if (obj->fSpeedChanging == true) { // doing a write, but speed still changing AbsoluteTime deadline; bool rc; XTRACE(kLogTxThreadDeferred, 0, 0); clock_interval_to_deadline(1000, kMicrosecondScale, &deadline); // wait a ms? rc = thread_call_enter1_delayed(obj->tx_thread_call, param1, deadline); IOLog("AppleSCCIrDA: tx thread called self w/delay, rc %d\n", rc); return; } ***/ // do normal xmit now rtn = obj->fpDevice->enqueueData(obj->fOutBuffer, count, &tCount, true); require(rtn == kIOReturnSuccess && tCount == count, Fail); waitBits = 0; // want tx busy to go to zero rtn = obj->fpDevice->watchState(&waitBits, PD_S_TX_BUSY); check(rtn == kIOReturnSuccess); XTRACE(kLogTxThreadResumed, 0, 0); if (obj->fIrDA) obj->fIrDA->Transmit_Complete(rtn == kIOReturnSuccess); Fail: XTRACE(kLogTxThread, 0xffff, 0xffff); return; } /* static */ void AppleSCCIrDA::rx_thread(thread_call_param_t param0, thread_call_param_t param1) { IOReturn rtn; UInt32 count; AppleSCCIrDA *obj; XTRACE(kLogRxThread, 0, 0); require(param0, Fail); obj = OSDynamicCast(AppleSCCIrDA, (OSObject *)param0); require(obj, Fail); while (obj->fpDevice) { UInt32 want; want = 0; // want empty bit to be zero rtn = obj->fpDevice->watchState(&want, PD_S_RXQ_EMPTY); XTRACE(kLogRxThreadResumed, rtn >> 16, (short)rtn); // this returns an error when we stop irda and inactivate the scc if (rtn != kIOReturnSuccess) { break; } if (obj->fSendingCommand) { // if sending a command, then it's hands-off for me XTRACE(kLogRxThreadSleeping, 0, 0); IOSleep(25); // so just sleep and do it again } else { // else, I can grab the data require(obj->fpDevice && obj->fInBuffer, Fail); rtn = obj->fpDevice->dequeueData(obj->fInBuffer, SCCLapPayLoad, &count, false); require(rtn == kIOReturnSuccess, Fail); if (count > 0) { XTRACE(kLogRxThreadGotData, 0, count); obj->parseInputBuffer(count, obj->fInBuffer); } } } Fail: return; }/* end rxLoop */ /* static */ void AppleSCCIrDA::speed_change_thread(thread_call_param_t param0, thread_call_param_t param1) { AppleSCCIrDA *obj; IOReturn rtn; int command = (int)param1; UInt32 delay; XTRACE(kLogSpeedChangeThread, 0, (short)param1); require(param0, Fail); obj = OSDynamicCast(AppleSCCIrDA, (OSObject *)param0); require(obj, Fail); require(obj->fSpeedChanging == true, Fail); require(obj->fpDevice, Fail); // Hack #824 // The write complete gets called when all of the data is transferred to the SCC cell's xmit fifo. // Not when the bytes have actually made it out of the SCC to the IR hardware. // Changing the speed before the transmit fifo is empty, will flush the fifo (or xmit at new speed?). // This is initially a problem when sending the UA packet, just before switching from 9600 baud // to the newly negotiated speed, but can also truncate the last packet sent at a higher speed // before switching back to 9600. Trial and error came up with 20ms as a reasonable delay. if (1) { // if xmit complete isn't to be trusted XTRACE(kLogSpeedChangeThread, 1, 20); IOSleep(20); } rtn = obj->fpDevice->executeEvent(PD_E_DATA_LATENCY, 1); // set to no delay for command echo require(rtn == kIOReturnSuccess, Fail); rtn = obj->sendCommand(command, obj->fInBuffer); // sets scc baud to fBaudCode after command runs if ( rtn == kIOReturnSuccess ) { ELG( 0, fInBuffer[0], 'SSs+', "SetSpeed - sendCommand successful" ); XTRACE(kLogSSsplus, 0, obj->fInBuffer[0]); } // compute the delay (in nanoseconds) for about 5 bytes at the current speed // the math is done this way so that the numbers all fit in a UInt32 w/out // have to use floating point. Should get about 5 million nanoseconds for // 9600 baud, down to about 400,000 nanoseconds for 115k. // should be 50 million / baud delay = ( 50000000 / obj->fBaudCode); rtn = obj->fpDevice->executeEvent(PD_E_DATA_LATENCY, delay); require(rtn == kIOReturnSuccess, Fail); obj->fSpeedChanging = false; if (obj->fIrDA) obj->fIrDA->SetSpeedComplete(true); Fail: XTRACE(kLogSpeedChangeThread, 0xffff, 0xffff); return; }