+++ /dev/null
-/*
- * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License"). You may not use this file except in compliance with the
- * License. Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
- *
- * This 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 OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-/*
- * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
- * All Rights Reserved
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby granted,
- * provided that the above copyright notice appears in all copies and
- * that both the copyright notice and this permission notice appear in
- * supporting documentation.
- *
- * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE.
- *
- * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
- * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-/*
- * Copyright 1996 1995 by Apple Computer, Inc. 1997 1996 1995 1994 1993 1992 1991
- * All Rights Reserved
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby granted,
- * provided that the above copyright notice appears in all copies and
- * that both the copyright notice and this permission notice appear in
- * supporting documentation.
- *
- * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE.
- *
- * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
- * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-/*
- * MKLINUX-1.0DR2
- */
-
-/* 1 April 1997 Simon Douglas:
- * Stolen wholesale from MkLinux.
- * Added nonblocking adb poll from interrupt level for the debugger.
- * Acknowledge before response so polled mode can work from inside the adb handler.
- *
- * 18 June 1998 sdouglas
- * Start IOKit version. Fix errors from kCudaSRQAssertMask. Use ool cmd & reply buffers,
- * not fixed len in packet. Does queueing here.
- *
- * 20 Nov 1998 suurballe
- * Port to C++
- */
-
-
-#include "AppleCuda.h"
-#include "AppleCudaUserClient.h"
-#include "IOCudaADBController.h"
-#include <IOKit/IOLib.h>
-#include <IOKit/IOSyncer.h>
-#include <IOKit/IOWorkLoop.h>
-#include <IOKit/IOInterruptEventSource.h>
-#include <IOKit/IODeviceMemory.h>
-#include <IOKit/IOPlatformExpert.h>
-#include <IOKit/pwr_mgt/IOPM.h>
-
-#include <IOKit/assert.h>
-
-#define super IOService
-OSDefineMetaClassAndStructors(AppleCuda,IOService)
-
-static void cuda_interrupt ( AppleCuda * self );
-
-static void cuda_process_response(AppleCuda * self);
-static void cuda_transmit_data(AppleCuda * self);
-static void cuda_expected_attention(AppleCuda * self);
-static void cuda_unexpected_attention(AppleCuda * self);
-static void cuda_receive_data(AppleCuda * self);
-static void cuda_receive_last_byte(AppleCuda * self);
-static void cuda_collision(AppleCuda * self);
-static void cuda_idle(AppleCuda * self);
-
-static void cuda_poll(AppleCuda * self);
-static void cuda_error(AppleCuda * self);
-static void cuda_send_request(AppleCuda * self);
-static IOReturn cuda_do_sync_request( AppleCuda * self,
- cuda_request_t * request, bool polled);
-static void cuda_do_state_transition_delay(AppleCuda * self);
-
-static int Cuda_PE_poll_input(unsigned int options, char * c);
-static int Cuda_PE_read_write_time_of_day(unsigned int options, long * secs);
-static int Cuda_PE_halt_restart(unsigned int type);
-static int Cuda_PE_write_IIC(unsigned char addr, unsigned char reg,
- unsigned char data);
-
-static void
-autopollArrived ( OSObject *inCuda, IOInterruptEventSource *, int );
-
-static int set_cuda_power_message ( int command );
-static int set_cuda_file_server_mode ( int command );
-static int set_cuda_poweruptime(long secs);
-static void cuda_async_set_power_message_enable( thread_call_param_t param, thread_call_param_t );
-static void cuda_async_set_file_server_mode( thread_call_param_t param, thread_call_param_t ) ;
-
-bool CudahasRoot( OSObject * us, void *, IOService * yourDevice );
-
-
-//
-// inline functions
-//
-
-static __inline__ unsigned char cuda_read_data(AppleCuda * self)
-{
- volatile unsigned char val;
-
- val = *self->cuda_via_regs.shift; eieio();
- return val;
-}
-
-static __inline__ int cuda_get_result(cuda_request_t *request)
-{
- int status = ADB_RET_OK;
- int theStatus = request->a_reply.a_header[1];
-
- if ( theStatus & kCudaTimeOutMask ) {
- status = ADB_RET_TIMEOUT;
-#if 0
- // these are expected before autopoll mask is set
- } else if ( theStatus & kCudaSRQAssertMask ) {
- status = ADB_RET_UNEXPECTED_RESULT;
-#endif
- } else if ( theStatus & kCudaSRQErrorMask ) {
- status = ADB_RET_REQUEST_ERROR;
- } else if ( theStatus & kCudaBusErrorMask ) {
- status = ADB_RET_BUS_ERROR;
- }
-
- return status;
-}
-
-static __inline__ void cuda_lock(AppleCuda * self)
-{
- if( !self->cuda_polled_mode)
- IOSimpleLockLock(self->cuda_request_lock);
-}
-
-static __inline__ void cuda_unlock(AppleCuda * self)
-{
- if( !self->cuda_polled_mode)
- IOSimpleLockUnlock(self->cuda_request_lock);
-}
-
-//
-//
-//
-
-
-static AppleCuda * gCuda;
-// **********************************************************************************
-// init
-//
-// **********************************************************************************
-bool AppleCuda::init ( OSDictionary * properties = 0 )
-{
-return super::init(properties);
-}
-
-
-// **********************************************************************************
-// start
-//
-// **********************************************************************************
-bool AppleCuda::start ( IOService * nub )
-{
-int i;
-IOMemoryMap * viaMap;
-unsigned char * cuda_base;
-
-if( !super::start(nub))
- return false;
-
-gCuda = this;
- // callPlatformFunction symbols
- cuda_check_any_interrupt = OSSymbol::withCString("cuda_check_any_interrupt");
-
-workLoop = NULL;
-eventSrc = NULL;
-ourADBinterface = NULL;
-_rootDomain = 0;
-_wakeup_from_sleep = false;
-
-workLoop = IOWorkLoop::workLoop();
-if ( !workLoop ) {
- kprintf("Start is bailing\n");
- return false;
-}
-
-eventSrc = IOInterruptEventSource::interruptEventSource(this, autopollArrived);
-if (!eventSrc ||
- kIOReturnSuccess != workLoop->addEventSource(eventSrc) ) {
- kprintf("Start is bailing\n");
- return false;
-}
-
-if( 0 == (viaMap = nub->mapDeviceMemoryWithIndex( 0 )) ) {
- IOLog("%s: no via memory\n", getName());
- kprintf("Start is bailing\n");
- return false;
-}
-cuda_base = (unsigned char *)viaMap->getVirtualAddress();
-
-kprintf("VIA base = %08x\n", (UInt32)cuda_base);
-ourADBinterface = new IOCudaADBController;
-if ( !ourADBinterface ) {
- kprintf("Start is bailing\n");
- return false;
-}
-if ( !ourADBinterface->init(0,this) ) {
- kprintf("Start is bailing\n");
- return false;
-}
-
-if ( !ourADBinterface->attach( this) ) {
- kprintf("Start is bailing\n");
- return false;
-}
-
-cuda_request_lock = IOSimpleLockAlloc();
-IOSimpleLockInit(cuda_request_lock);
-
-cuda_via_regs.dataB = cuda_base;
-cuda_via_regs.handshakeDataA = cuda_base+0x0200;
-cuda_via_regs.dataDirectionB = cuda_base+0x0400;
-cuda_via_regs.dataDirectionA = cuda_base+0x0600;
-cuda_via_regs.timer1CounterLow = cuda_base+0x0800;
-cuda_via_regs.timer1CounterHigh = cuda_base+0x0A00;
-cuda_via_regs.timer1LatchLow = cuda_base+0x0C00;
-cuda_via_regs.timer1LatchHigh = cuda_base+0x0E00;
-cuda_via_regs.timer2CounterLow = cuda_base+0x1000;
-cuda_via_regs.timer2CounterHigh = cuda_base+0x1200;
-cuda_via_regs.shift = cuda_base+0x1400;
-cuda_via_regs.auxillaryControl = cuda_base+0x1600;
-cuda_via_regs.peripheralControl = cuda_base+0x1800;
-cuda_via_regs.interruptFlag = cuda_base+0x1A00;
-cuda_via_regs.interruptEnable = cuda_base+0x1C00;
-cuda_via_regs.dataA = cuda_base+0x1E00;
-
-// we require delays of this duration between certain state transitions
-clock_interval_to_absolutetime_interval(200, 1, &cuda_state_transition_delay);
-
-// Set the direction of the cuda signals. ByteACk and TIP are output and
-// TREQ is an input
-
-*cuda_via_regs.dataDirectionB |= (kCudaByteAcknowledgeMask | kCudaTransferInProgressMask);
-*cuda_via_regs.dataDirectionB &= ~kCudaTransferRequestMask;
-
-// Set the clock control. Set to shift data in by external clock CB1.
-
-*cuda_via_regs.auxillaryControl = (*cuda_via_regs.auxillaryControl | kCudaTransferMode) &
- kCudaSystemRecieve;
-
-// Clear any posible cuda interupt.
-
-if ( *cuda_via_regs.shift );
-
-// Initialize the internal data.
-
-cuda_interrupt_state = CUDA_STATE_IDLE;
-cuda_transaction_state = CUDA_TS_NO_REQUEST;
-cuda_is_header_transfer = false;
-cuda_is_packet_type = false;
-cuda_transfer_count = 0;
-cuda_current_response = NULL;
-for( i = 0; i < NUM_AP_BUFFERS; i++ ) {
- cuda_unsolicited[ i ].a_buffer = cuda_autopoll_buffers[ i ];
-}
-
-// Terminate transaction and set idle state
-
-cuda_neg_tip_and_byteack(this);
-
-// we want to delay 4 mS for ADB reset to complete
-
-IOSleep( 4 );
-
-// Clear pending interrupt if any...
-
-(void)cuda_read_data(this);
-
-// Issue a Sync Transaction, ByteAck asserted while TIP is negated.
-
-cuda_assert_byte_ack(this);
-
-// Wait for the Sync acknowledgement, cuda to assert TREQ
-
-cuda_wait_for_transfer_request_assert(this);
-
-// Wait for the Sync acknowledgement interrupt.
-
-cuda_wait_for_interrupt(this);
-
-// Clear pending interrupt
-
-(void)cuda_read_data(this);
-
-// Terminate the sync cycle by Negating ByteAck
-
-cuda_neg_byte_ack(this);
-
-// Wait for the Sync termination acknowledgement, cuda negates TREQ.
-
-cuda_wait_for_transfer_request_neg(this);
-
-// Wait for the Sync termination acknowledgement interrupt.
-
-cuda_wait_for_interrupt(this);
-
-// Terminate transaction and set idle state, TIP negate and ByteAck negate.
-cuda_neg_transfer_in_progress(this);
-
-// Clear pending interrupt, if there is one...
-(void)cuda_read_data(this);
-
-#if 0
- cuda_polled_mode = true;
-#else
-#define VIA_DEV_CUDA 2
-nub->registerInterrupt(VIA_DEV_CUDA,
- this, (IOInterruptAction) cuda_interrupt);
-nub->enableInterrupt(VIA_DEV_CUDA);
-#endif
-
-PE_poll_input = Cuda_PE_poll_input;
-PE_read_write_time_of_day = Cuda_PE_read_write_time_of_day;
-PE_halt_restart = Cuda_PE_halt_restart;
-PE_write_IIC = Cuda_PE_write_IIC;
-publishResource( "IOiic0", this );
-publishResource( "IORTC", this );
-
-
-//set_cuda_power_message(kADB_powermsg_enable); //won't work on beige G3
-thread_call_func(cuda_async_set_power_message_enable, (thread_call_param_t)this, true);
-thread_call_func(cuda_async_set_file_server_mode, (thread_call_param_t)this, true);
-
- registerService(); //Gossamer needs to find this driver for waking up G3
-
- _cuda_power_state = 1; //default is wake state
- //We want to know when sleep is about to occur
- addNotification( gIOPublishNotification,serviceMatching("IOPMrootDomain"),
- (IOServiceNotificationHandler)CudahasRoot, this, 0 );
-
-ourADBinterface->start( this );
-
-return true;
-}
-
-/* Here are some power management functions so we can tell when system is
- going to sleep. */
-bool CudahasRoot( OSObject * us, void *, IOService * yourDevice )
-{
- if (( yourDevice != NULL ) && ((AppleCuda *)us)->_rootDomain == 0)
- {
- ((AppleCuda *)us)->_rootDomain = (IOPMrootDomain *) yourDevice;
- ((IOPMrootDomain *)yourDevice)->registerInterestedDriver((IOService *) us);
- }
- return true;
-}
-
-IOReturn AppleCuda::powerStateWillChangeTo ( IOPMPowerFlags theFlags, unsigned long unused1,
- IOService* unused2)
-{
- if ( ! (theFlags & IOPMPowerOn) )
- {
- _cuda_power_state = 0; //0 means sleeping
- }
- return IOPMAckImplied;
-}
-
-IOReturn AppleCuda::powerStateDidChangeTo ( IOPMPowerFlags theFlags, unsigned long unused1,
- IOService* unused2)
-{
- if (theFlags & IOPMPowerOn)
- {
- _cuda_power_state = 1; //1 means awake
- _wakeup_from_sleep = false; //normally it is false
- }
- return IOPMAckImplied;
-}
-
-
-
-// *****************************************************************************
-// getWorkLoop
-//
-// Return the cuda's workloop.
-//
-// *****************************************************************************
-IOWorkLoop *AppleCuda::getWorkLoop() const
-{
- return workLoop;
-}
-
-// *****************************************************************************
-// free
-//
-// Release everything we may have allocated.
-//
-// *****************************************************************************
-void AppleCuda::free ( void )
-{
-if ( workLoop ) {
- workLoop->release();
-}
-if ( eventSrc ) {
- eventSrc->release();
-}
-if ( ourADBinterface ) {
- ourADBinterface->release();
-}
- if (_rootDomain)
- {
- _rootDomain->deRegisterInterestedDriver((IOService *) this);
- _rootDomain = 0;
- }
-super::free();
-}
-
-
-// **********************************************************************************
-// registerForADBInterrupts
-//
-// Some driver is calling to say it is prepared to receive "unsolicited" adb
-// interrupts (e.g. autopoll keyboard and trackpad data). The parameters identify
-// who to call when we get one.
-// **********************************************************************************
-void AppleCuda::registerForADBInterrupts ( ADB_callback_func handler, IOService * caller )
-{
-autopoll_handler = handler;
-ADBid = caller;
-}
-
-
-// **********************************************************************************
-// autopollArrived
-//
-// **********************************************************************************
-static void autopollArrived ( OSObject * CudaDriver, IOInterruptEventSource *, int )
-{
-((AppleCuda *)CudaDriver)->serviceAutopolls();
-}
-
-#define RB_BOOT 1 /* Causes reboot, not halt. Is in xnu/bsd/sys/reboot.h */
-extern "C" {
- void boot(int paniced, int howto, char * command);
-}
-
-
-static void cuda_async_set_power_message_enable( thread_call_param_t param, thread_call_param_t )
-{
- //AppleCuda * me = (AppleCuda *) param;
-
- set_cuda_power_message(kADB_powermsg_enable);
-}
-
-static void cuda_async_set_file_server_mode( thread_call_param_t param, thread_call_param_t )
-{
- set_cuda_file_server_mode(1);
-}
-
-// **********************************************************************************
-// serviceAutopolls
-// We get here just before calling autopollHandler() in IOADBController.cpp
-// **********************************************************************************
-void AppleCuda::serviceAutopolls ( void )
-{
-cuda_packet_t * response;
-
- while( inIndex != outIndex ) {
- response = &cuda_unsolicited[ outIndex ];
-
- //Check for power messages, which are handled differently from regular
- // autopoll data coming from mouse or keyboard.
- if (response->a_header[0] == ADB_PACKET_POWER)
- {
- unsigned char flag, cmd;
-
- flag = response->a_header[1];
- cmd = response->a_header[2];
-
- if ((flag == kADB_powermsg_flag_chassis)
- && (cmd == kADB_powermsg_cmd_chassis_off))
- {
- thread_call_func(cuda_async_set_power_message_enable,
- (thread_call_param_t)this, true);
-
- if (_rootDomain)
- {
- if (_cuda_power_state)
- {
- //Put system to sleep now
- _rootDomain->receivePowerNotification (kIOPMSleepNow);
- }
- else //If asleep, wake up the system
- {
- //Tickle activity timer in root domain. This will not
- // wake up machine that is in demand-sleep, but it will
- // wake up an inactive system that dozed
- _rootDomain->activityTickle(0,0);
- }
- }
- }
- else if ((flag == kADB_powermsg_flag_keyboardpwr)
- && (cmd == kADB_powermsg_cmd_keyboardoff))
- {
- //set_cuda_power_message(kADB_powermsg_continue);
- //This needs to by async so Beige G3 ADB won't lock up
- thread_call_func(cuda_async_set_power_message_enable,
- (thread_call_param_t)this, true);
- }
-
- }
- if ( ADBid != NULL ) {
- (*autopoll_handler)(ADBid,response->a_header[2],response->a_bcount,response->a_buffer);
- }
-
- outIndex = (outIndex + 1) & (NUM_AP_BUFFERS - 1);
-
- } //end of while loop
-
-}
-
-
-// **********************************************************************************
-// doSyncRequest
-//
-// **********************************************************************************
-IOReturn AppleCuda::doSyncRequest ( cuda_request_t * request )
-{
-return(cuda_do_sync_request(this, request, false));
-}
-
-
-IOReturn AppleCuda::callPlatformFunction(const OSSymbol *functionName,
- bool waitForFunction,
- void *param1, void *param2,
- void *param3, void *param4)
-{
- if (functionName == cuda_check_any_interrupt)
- {
- bool *hasint;
-
- hasint = (bool *)param1;
- *hasint = false;
-
- if (inIndex != outIndex)
- {
- *hasint = true;
- }
-
- if (_wakeup_from_sleep)
- {
- *hasint = true;
- }
- return kIOReturnSuccess;
- }
-
- return kIOReturnBadArgument;
-}
-
-
-void
-AppleCuda::setWakeTime(UInt32 waketime)
-{
- //Call this function with waketime=0 in order to allow normal sleep again
- _wakeup_from_sleep = false;
- if (waketime != 0) {
- timerSrc = IOTimerEventSource::timerEventSource((OSObject*)this, WakeupTimeoutHandler);
-
- if (!timerSrc || (workLoop->addEventSource(timerSrc) != kIOReturnSuccess))
- {
- IOLog("Cuda can not register timeout event\n");
- return;
- }
-
- timerSrc->setTimeoutMS(waketime);
- }
-}
-
-static void
-AppleCuda::WakeupTimeoutHandler(OSObject *object, IOTimerEventSource *timer)
-{
- gCuda->_wakeup_from_sleep = true;
- if (gCuda->_rootDomain)
- {
- gCuda->_rootDomain->activityTickle(0,0);
- }
-}
-
-
-void
-AppleCuda::setPowerOnTime(UInt32 newTime)
-{
- long long_secs;
-
- if (newTime != 0) {
- Cuda_PE_read_write_time_of_day(kPEReadTOD, &long_secs);
- set_cuda_poweruptime((long)newTime + long_secs);
- }
-}
-
-void
-AppleCuda::setFileServerMode(bool fileServerModeON)
-{
- set_cuda_file_server_mode((int) fileServerModeON);
-}
-
-void AppleCuda::demandSleepNow(void)
-{
- if (_rootDomain)
- {
- _rootDomain->receivePowerNotification (kIOPMSleepNow);
- }
-}
-
-// --------------------------------------------------------------------------
-//
-// Method: newUserClient
-//
-// Purpose:
-// newUserClient is called by the IOKit manager to create the
-// kernel receiver of a user request. The "type" is a qualifier
-// shared between the kernel and user client class instances..
-
-#define kAppleCudaUserClientMagicCookie 0x0C00DA
-
-IOReturn
-AppleCuda::newUserClient(task_t owningTask,
- void *securityToken,
- UInt32 magicCookie,
- IOUserClient **handler)
-{
- IOReturn ioReturn = kIOReturnSuccess;
- AppleCudaUserClient *client = NULL;
-
- IOLog("AppleCuda::newUserClient\n");
-
- if (IOUserClient::clientHasPrivilege(securityToken, "root") != kIOReturnSuccess) {
- IOLog("AppleCuda::newUserClient: Can't create user client, not privileged\n");
- return kIOReturnNotPrivileged;
- }
-
- // Check that this is a user client type that we support.
- // type is known only to this driver's user and kernel
- // classes. It could be used, for example, to define
- // read or write privileges. In this case, we look for
- // a private value.
- if (magicCookie == kAppleCudaUserClientMagicCookie) {
- // Construct a new client instance for the requesting task.
- // This is, essentially client = new AppleCudaUserClient;
- // ... create metaclasses ...
- // client->setTask(owningTask)
- client = AppleCudaUserClient::withTask(owningTask);
- if (client == NULL) {
- ioReturn = kIOReturnNoResources;
- IOLog("AppleCuda::newUserClient: Can't create user client\n");
- }
- }
- else {
- ioReturn = kIOReturnInvalid;
- IOLog("AppleCuda::newUserClient: bad magic cookie.\n");
- }
-
- if (ioReturn == kIOReturnSuccess) {
- // Attach ourself to the client so that this client instance
- // can call us.
- if (client->attach(this) == false) {
- ioReturn = kIOReturnError;
- IOLog("AppleCuda::newUserClient: Can't attach user client\n");
- }
- }
-
- if (ioReturn == kIOReturnSuccess) {
- // Start the client so it can accept requests.
- if (client->start(this) == false) {
- ioReturn = kIOReturnError;
- IOLog("AppleCuda::newUserClientt: Can't start user client\n");
- }
- }
-
- if (ioReturn != kIOReturnSuccess && client != NULL) {
- client->detach(this);
- client->release();
- }
-
- *handler = client;
- return (ioReturn);
-}
-
-// **********************************************************************************
-// cuda_do_sync_request
-//
-// **********************************************************************************
-IOReturn cuda_do_sync_request ( AppleCuda * self, cuda_request_t * request, bool polled )
-{
- bool wasPolled = false;
- IOInterruptState ints;
-
- if( !polled ) {
- request->sync = IOSyncer::create();
- request->needWake = true;
- }
-
- ints = IOSimpleLockLockDisableInterrupt(self->cuda_request_lock);
-
- if( polled ) {
- wasPolled = self->cuda_polled_mode;
- self->cuda_polled_mode = polled;
- }
-
- if( self->cuda_last_request )
- self->cuda_last_request->a_next = request;
- else
- self->cuda_request = request;
-
- self->cuda_last_request = request;
-
- if( self->cuda_interrupt_state == CUDA_STATE_IDLE )
- cuda_send_request(self);
-
- if( polled ) {
- cuda_poll(self);
- self->cuda_polled_mode = wasPolled;
- assert( 0 == self->cuda_request );
- assert( 0 == self->cuda_last_request );
- }
-
- IOSimpleLockUnlockEnableInterrupt(self->cuda_request_lock, ints);
-
- if( !polled)
- request->sync->wait();
-
- return cuda_get_result(request);
-}
-
-
-// **********************************************************************************
-// Cuda_PE_read_write_time_of_day
-//
-// **********************************************************************************
-static int Cuda_PE_read_write_time_of_day ( unsigned int options, long * secs )
-{
-cuda_request_t cmd;
-
-adb_init_request(&cmd);
-
-cmd.a_cmd.a_hcount = 2;
-cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO;
-
-switch( options ) {
-
- case kPEReadTOD:
- cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_GET_REAL_TIME;
- cmd.a_reply.a_buffer = (UInt8 *)secs;
- cmd.a_reply.a_bcount = sizeof(*secs);
- break;
-
- case kPEWriteTOD:
- cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_SET_REAL_TIME;
- cmd.a_cmd.a_buffer = (UInt8 *)secs;
- cmd.a_cmd.a_bcount = sizeof(*secs);
- break;
-
- default:
- return 1;
-}
-
-return cuda_do_sync_request(gCuda, &cmd, true);
-}
-
-
-// **********************************************************************************
-// Cuda_PE_halt_restart
-//
-// **********************************************************************************
-static int Cuda_PE_halt_restart ( unsigned int type )
-{
-cuda_request_t cmd;
-
-adb_init_request(&cmd);
-
-cmd.a_cmd.a_hcount = 2;
-cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO;
-
-switch( type ) {
-
- case kPERestartCPU:
- cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_RESTART_SYSTEM;
- break;
-
- case kPEHaltCPU:
- cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_POWER_DOWN;
- break;
-
- default:
- return 1;
- }
-
-return cuda_do_sync_request(gCuda, &cmd, true);
-}
-
-// **********************************************************************************
-// Set the power-on time. 2001
-// **********************************************************************************
-static int set_cuda_poweruptime (long secs)
-{
- cuda_request_t cmd;
- long localsecs = secs;
-
- adb_init_request(&cmd);
-
- cmd.a_cmd.a_hcount = 2;
- cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO;
-
- cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_SET_POWER_UPTIME;
- cmd.a_cmd.a_buffer = (UInt8 *)&localsecs;
- cmd.a_cmd.a_bcount = 4;
-
- return cuda_do_sync_request(gCuda, &cmd, true);
-}
-
-
-// **********************************************************************************
-// In case this machine loses power, it will automatically reboot when power is
-// restored. Only desktop machines have Cuda, so this feature will not affect
-// PowerBooks.
-// **********************************************************************************
-static int set_cuda_file_server_mode ( int command )
-{
-cuda_request_t cmd;
-
-adb_init_request(&cmd);
-
-cmd.a_cmd.a_hcount = 3;
-cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO;
-cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_FILE_SERVER_FLAG;
-cmd.a_cmd.a_header[2] = command;
-
-return cuda_do_sync_request(gCuda, &cmd, true);
-}
-
-// **********************************************************************************
-// Fix front panel power key (mostly on Yosemites) so that one press won't power
-// down the entire machine
-//
-// **********************************************************************************
-static int set_cuda_power_message ( int command )
-{
-cuda_request_t cmd;
-
-if (command >= kADB_powermsg_invalid)
- return 0; //invalid Cuda power request
-
-adb_init_request(&cmd);
-
-cmd.a_cmd.a_hcount = 3;
-cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO;
-cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_SET_POWER_MESSAGES;
-cmd.a_cmd.a_header[2] = command;
-
-return cuda_do_sync_request(gCuda, &cmd, true);
-}
-
-
-// **********************************************************************************
-// Cuda_PE_write_IIC
-//
-// **********************************************************************************
-static int Cuda_PE_write_IIC ( unsigned char addr, unsigned char reg, unsigned char data )
-{
-cuda_request_t cmd;
-
-adb_init_request(&cmd);
-
-cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO;
-cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_GET_SET_IIC;
-cmd.a_cmd.a_header[2] = addr;
-cmd.a_cmd.a_header[3] = reg;
-cmd.a_cmd.a_header[4] = data;
-cmd.a_cmd.a_hcount = 5;
-
-return cuda_do_sync_request(gCuda, &cmd, true);
-}
-
-IOReturn
-AppleCudaWriteIIC( UInt8 address, const UInt8 * buffer, IOByteCount * count )
-{
- IOReturn ret;
- cuda_request_t cmd;
-
- if( !gCuda)
- return( kIOReturnUnsupported );
-
- adb_init_request(&cmd);
-
- cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO;
- cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_GET_SET_IIC;
- cmd.a_cmd.a_header[2] = address;
- cmd.a_cmd.a_hcount = 3;
- cmd.a_cmd.a_buffer = (UInt8 *) buffer;
- cmd.a_cmd.a_bcount = *count;
-
- ret = cuda_do_sync_request(gCuda, &cmd, true);
-
- *count = cmd.a_cmd.a_bcount;
-
- return( ret );
-}
-
-IOReturn
-AppleCudaReadIIC( UInt8 address, UInt8 * buffer, IOByteCount * count )
-{
- IOReturn ret;
- cuda_request_t cmd;
-
- if( !gCuda)
- return( kIOReturnUnsupported );
-
- adb_init_request(&cmd);
-
- cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO;
- cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_GET_SET_IIC;
- cmd.a_cmd.a_header[2] = address;
- cmd.a_cmd.a_hcount = 3;
- cmd.a_reply.a_buffer = buffer;
- cmd.a_reply.a_bcount = *count;
-
- ret = cuda_do_sync_request(gCuda, &cmd, true);
- *count = cmd.a_reply.a_bcount;
-
- return( ret );
-}
-
-
-// **********************************************************************************
-// Cuda_PE_poll_input
-//
-// **********************************************************************************
-static int Cuda_PE_poll_input ( unsigned int, char * c )
-{
-AppleCuda * self = gCuda;
-int interruptflag;
-UInt8 code;
-cuda_packet_t * response; //0123456789abcdef
-static char keycodes2ascii[] = "asdfhgzxcv_bqwer" //00
- "yt123465=97-80]o" //10
- "u[ip\nlj'k;_,/nm." //20
- "\t_"; //30
-
-*c = 0xff;
-
-if( !self ) {
- return 1;
-}
-
-self->cuda_polled_mode = true;
-interruptflag = *self->cuda_via_regs.interruptFlag & kCudaInterruptMask;
-eieio();
-if( interruptflag ) {
- cuda_interrupt(self);
-}
-
-if( self->inIndex != self->outIndex ) {
- response = &self->cuda_unsolicited[ self->outIndex ];
- if( ((response->a_header[2] >> 4) == 2)
- && (response->a_bcount > 1) ) {
- code = response->a_buffer[0];
- if( code < sizeof(keycodes2ascii) ) {
- *c = keycodes2ascii[ code ];
- }
- }
- self->outIndex = self->inIndex;
-}
-
-self->cuda_polled_mode = false;
-return 0;
-}
-
-
-//
-// internal
-//
-
-
-// **********************************************************************************
-// cuda_send_request
-//
-// **********************************************************************************
-static void cuda_send_request ( AppleCuda * self )
-{
-
- // The data register must written with the data byte 25uS
- // after examining TREQ or we run the risk of getting out of sync
- // with Cuda. So call with disabled interrupts and spinlock held.
-
- // Check if we can commence with the packet transmission. First, check if
- // Cuda can service our request now. Second, check if Cuda wants to send
- // a response packet now.
-
-if( !cuda_is_transfer_in_progress(self) ) {
- // Set the shift register direction to output to Cuda by setting
- // the direction bit.
-
- cuda_set_data_direction_to_output(self);
-
- // Write the first byte to the shift register
- cuda_write_data(self, self->cuda_request->a_cmd.a_header[0]);
-
- // Set up the transfer state info here.
-
- self->cuda_is_header_transfer = true;
- self->cuda_transfer_count = 1;
-
- // Make sure we're in idle state before transaction, and then
- // assert TIP to tell Cuda we're starting command
- cuda_neg_byte_ack(self);
- cuda_assert_transfer_in_progress(self);
-
- // The next state is going to be a transmit state, if there is
- // no collision. This is a requested response but call it sync.
-
- self->cuda_interrupt_state = CUDA_STATE_TRANSMIT_EXPECTED;
- self->cuda_transaction_state = CUDA_TS_SYNC_RESPONSE;
-}
-
-#if 0
-else {
- IOLog("Req = %x, state = %x, TIP = %x\n", self->cuda_request,
- self->cuda_interrupt_state, cuda_is_transfer_in_progress(self));
-}
-#endif
-}
-
-
-// **********************************************************************************
-// cuda_poll
-//
-// **********************************************************************************
-static void cuda_poll( AppleCuda * self )
-{
- do {
- cuda_wait_for_interrupt(self);
- cuda_interrupt(self);
- } while( self->cuda_interrupt_state != CUDA_STATE_IDLE );
-}
-
-//
-// cuda_process_response
-// Execute at secondary interrupt.
-//
-
-
-// **********************************************************************************
-// cuda_process_response
-//
-// **********************************************************************************
-static void cuda_process_response ( AppleCuda * self )
-{
-volatile cuda_request_t * request;
-unsigned int newIndex;
-
- // Almost ready for the next state, which should be a Idle state.
- // Just need to notifiy the client.
-
-if ( self->cuda_transaction_state == CUDA_TS_SYNC_RESPONSE ) {
-
- // dequeue reqeuest
- cuda_lock(self);
- request = self->cuda_request;
- if( NULL == (self->cuda_request = request->a_next) ) {
- self->cuda_last_request = NULL;
- }
- cuda_unlock(self);
-
- // wake the sync request thread
- if ( ((cuda_request_t *)request)->needWake ) {
- ((cuda_request_t *)request)->sync->signal();
- }
-
-}
-else {
- if ( self->cuda_transaction_state == CUDA_TS_ASYNC_RESPONSE ) {
- newIndex = (self->inIndex + 1) & (NUM_AP_BUFFERS - 1);
- if( newIndex != self->outIndex ) {
- self->inIndex = newIndex;
- }
- else {
- // drop this packet, and reuse the buffer
- }
- if ( !self->cuda_polled_mode ) {
- // wake thread to service autopolls
- self->eventSrc->interruptOccurred(0, 0, 0);
- }
- }
-}
-return;
-}
-
-
-// **********************************************************************************
-// cuda_interrupt
-//
-// **********************************************************************************
-static void cuda_interrupt ( AppleCuda * self )
-{
-unsigned char interruptState;
-
- // Get the relevant signal in determining the cause of the interrupt:
- // the shift direction, the transfer request line and the transfer
- // request line.
-
-interruptState = cuda_get_interrupt_state(self);
-
-//kprintf("%02x",interruptState);
-
-switch ( interruptState ) {
- case kCudaReceiveByte:
- cuda_receive_data(self);
- break;
-
- case kCudaReceiveLastByte:
- cuda_receive_last_byte(self);
- break;
-
- case kCudaTransmitByte:
- cuda_transmit_data(self);
- break;
-
- case kCudaUnexpectedAttention:
- cuda_unexpected_attention(self);
- break;
-
- case kCudaExpectedAttention:
- cuda_expected_attention(self);
- break;
-
- case kCudaIdleState:
- cuda_idle(self);
- break;
-
- case kCudaCollision:
- cuda_collision(self);
- break;
-
- // Unknown interrupt, clear it and leave.
- default:
- cuda_error(self);
- break;
-}
-}
-
-//
-// TransmitCudaData
-// Executes at hardware interrupt level.
-//
-
-// **********************************************************************************
-// cuda_transmit_data
-//
-// **********************************************************************************
-static void cuda_transmit_data ( AppleCuda * self )
-{
- // Clear the pending interrupt by reading the shift register.
-
-if ( self->cuda_is_header_transfer ) {
- // There are more header bytes, write one out.
- cuda_write_data(self, self->cuda_request->a_cmd.a_header[self->cuda_transfer_count++]);
-
- // Toggle the handshake line.
- if ( self->cuda_transfer_count >= self->cuda_request->a_cmd.a_hcount ) {
- self->cuda_is_header_transfer = FALSE;
- self->cuda_transfer_count = 0;
- }
-
- cuda_toggle_byte_ack( self);
-}
-else {
- if ( self->cuda_transfer_count < self->cuda_request->a_cmd.a_bcount ) {
- // There are more command bytes, write one out and update the pointer
- cuda_write_data( self,
- *(self->cuda_request->a_cmd.a_buffer + self->cuda_transfer_count++));
- // Toggle the handshake line.
- cuda_toggle_byte_ack(self);
- }
- else {
- (void)cuda_read_data(self);
- // There is no more command bytes, terminate the send transaction.
- // Cuda should send a expected attention interrupt soon.
-
- cuda_neg_tip_and_byteack(self);
-
- // The next interrupt should be a expected attention interrupt.
-
- self->cuda_interrupt_state = CUDA_STATE_ATTN_EXPECTED;
- }
-}
-}
-
-//
-// cuda_expected_attention
-// Executes at hardware interrupt level.
-//
-
-
-// **********************************************************************************
-// cuda_expected_attention
-//
-// **********************************************************************************
-static void cuda_expected_attention ( AppleCuda * self )
-{
- // Clear the pending interrupt by reading the shift register.
-
-(void)cuda_read_data(self);
-
- // Allow the VIA to settle directions.. else the possibility of
- // data corruption.
-cuda_do_state_transition_delay(self);
-
-if ( self->cuda_transaction_state == CUDA_TS_SYNC_RESPONSE ) {
- self->cuda_current_response = (cuda_packet_t*)&self->cuda_request->a_reply;
-}
-else {
- self->cuda_current_response = &self->cuda_unsolicited[ self->inIndex ];
- self->cuda_current_response->a_hcount = 0;
- self->cuda_current_response->a_bcount = MAX_AP_RESPONSE;
-}
-
-self->cuda_is_header_transfer = true;
-self->cuda_is_packet_type = true;
-self->cuda_transfer_count = 0;
-
- // Set the shift register direction to input.
-cuda_set_data_direction_to_input(self);
-
- // Start the response packet transaction.
-cuda_assert_transfer_in_progress(self);
-
- // The next interrupt should be a receive data interrupt.
-self->cuda_interrupt_state = CUDA_STATE_RECEIVE_EXPECTED;
-}
-
-//
-// cuda_unexpected_attention
-// Executes at hardware interrupt level.
-//
-
-
-// **********************************************************************************
-// cuda_expected_attention
-//
-// **********************************************************************************
-static void cuda_unexpected_attention ( AppleCuda * self )
-{
- // Clear the pending interrupt by reading the shift register.
-(void)cuda_read_data(self);
-
- // Get ready for a unsolicited response.
-self->cuda_current_response = &self->cuda_unsolicited[ self->inIndex ];
-self->cuda_current_response->a_hcount = 0;
-self->cuda_current_response->a_bcount = MAX_AP_RESPONSE;
-
-self->cuda_is_header_transfer = TRUE;
-self->cuda_is_packet_type = TRUE;
-self->cuda_transfer_count = 0;
-
- // Start the response packet transaction, Transaction In Progress
-cuda_assert_transfer_in_progress(self);
-
- // The next interrupt should be a receive data interrupt and the next
- // response should be an async response.
-
-self->cuda_interrupt_state = CUDA_STATE_RECEIVE_EXPECTED;
-
-self->cuda_transaction_state = CUDA_TS_ASYNC_RESPONSE;
-}
-
-//
-// cuda_receive_data
-// Executes at hardware interrupt level.
-//
-
-
-// **********************************************************************************
-// cuda_receive_data
-//
-// **********************************************************************************
-static void cuda_receive_data ( AppleCuda * self )
-{
-if ( self->cuda_is_packet_type ) {
- unsigned char packetType;
-
- packetType = cuda_read_data( self);
- self->cuda_current_response->a_header[self->cuda_transfer_count++] = packetType;
-
- if ( packetType == ADB_PACKET_ERROR) {
- self->cuda_current_response->a_hcount = 4;
- }
- else {
- self->cuda_current_response->a_hcount = 3;
- }
-
- self->cuda_is_packet_type = false;
-
- cuda_toggle_byte_ack(self);
-
-}
-else {
-
-
- if ( self->cuda_is_header_transfer ) {
-
- self->cuda_current_response->a_header[self->cuda_transfer_count++] =
- cuda_read_data(self);
-
- if (self->cuda_transfer_count >= self->cuda_current_response->a_hcount) {
- self->cuda_is_header_transfer = FALSE;
- self->cuda_transfer_count = 0;
- }
-
- cuda_toggle_byte_ack(self);
- }
- else {
- if ( self->cuda_transfer_count < self->cuda_current_response->a_bcount ) {
- // Still room for more bytes. Get the byte and tell Cuda to continue.
- // Toggle the handshake line, ByteAck, to acknowledge receive.
-
- *(self->cuda_current_response->a_buffer + self->cuda_transfer_count++) =
- cuda_read_data(self);
- cuda_toggle_byte_ack(self);
-
- }
- else {
- // Cuda is still sending data but the buffer is full.
- // Normally should not get here. The only exceptions are open ended
- // request such as PRAM read... In any event time to exit.
-
- self->cuda_current_response->a_bcount = self->cuda_transfer_count;
-
- cuda_read_data(self);
-
- cuda_process_response(self);
- cuda_neg_tip_and_byteack(self);
- }
- }
-}
-}
-
-
-//
-// cuda_receive_last_byte
-// Executes at hardware interrupt level.
-//
-
-
-// **********************************************************************************
-// cuda_receive_last_byte
-//
-// **********************************************************************************
-static void cuda_receive_last_byte ( AppleCuda * self )
-{
-
-if ( self->cuda_is_header_transfer ) {
- self->cuda_current_response->a_header[self->cuda_transfer_count++] =
- cuda_read_data(self);
-
- self->cuda_transfer_count = 0;
- }
-else {
- if ( self->cuda_transfer_count < self->cuda_current_response->a_bcount ) {
- *(self->cuda_current_response->a_buffer + self->cuda_transfer_count++) =
- cuda_read_data(self);
- }
- else {
- /* Overrun -- ignore data */
- (void) cuda_read_data(self);
- }
-}
-self->cuda_current_response->a_bcount = self->cuda_transfer_count;
- // acknowledge before response so polled mode can work
- // from inside the handler
-cuda_neg_tip_and_byteack(self);
-cuda_process_response(self);
-}
-
-
-//
-// cuda_collision
-// Executes at hardware interrupt level.
-//
-
-
-// **********************************************************************************
-// cuda_collision
-//
-// **********************************************************************************
-static void cuda_collision ( AppleCuda * self )
-{
-// Clear the pending interrupt by reading the shift register.
-(void)cuda_read_data(self);
-
-// Negate TIP to abort the send. Cuda should send a second attention
-// interrupt to acknowledge the abort cycle.
-cuda_neg_transfer_in_progress(self);
-
-// The next interrupt should be an expected attention and the next
-// response packet should be an async response.
-
-self->cuda_interrupt_state = CUDA_STATE_ATTN_EXPECTED;
-self->cuda_transaction_state = CUDA_TS_ASYNC_RESPONSE;
-
-/* queue the request */
-self->cuda_is_header_transfer = false;
-self->cuda_transfer_count = 0;
-}
-
-
-//
-//
-// Executes at hardware interrupt level.
-//
-
-
-// **********************************************************************************
-// cuda_idle
-//
-// **********************************************************************************
-static void cuda_idle ( AppleCuda * self )
-{
-
-// Clear the pending interrupt by reading the shift register.
-(void)cuda_read_data(self);
-
-cuda_lock(self);
- // Set to the idle state.
-self->cuda_interrupt_state = CUDA_STATE_IDLE;
- // See if there are any pending requests.
-if( self->cuda_request ) {
- cuda_send_request(self);
-}
-cuda_unlock(self);
-}
-
-
-// **********************************************************************************
-// cuda_error
-//
-// **********************************************************************************
-static void cuda_error ( AppleCuda * self )
-{
-//printf("{Error %d}", self->cuda_transaction_state);
-
-// Was looking at cuda_transaction_state - doesn't seem right
-
-switch ( self->cuda_interrupt_state ) {
- case CUDA_STATE_IDLE:
- cuda_neg_tip_and_byteack(self);
- break;
-
- case CUDA_STATE_TRANSMIT_EXPECTED:
- if ( self->cuda_is_header_transfer && self->cuda_transfer_count <= 1 ) {
- cuda_do_state_transition_delay(self);
- cuda_neg_transfer_in_progress(self);
- cuda_set_data_direction_to_input(self);
- panic ("CUDA - TODO FORCE COMMAND BACK UP!\n");
- }
- else {
- self->cuda_interrupt_state = CUDA_STATE_ATTN_EXPECTED;
- cuda_neg_tip_and_byteack(self);
- }
- break;
-
- case CUDA_STATE_ATTN_EXPECTED:
- cuda_assert_transfer_in_progress(self);
-
- cuda_do_state_transition_delay(self);
- cuda_set_data_direction_to_input(self);
- cuda_neg_transfer_in_progress(self);
- panic("CUDA - TODO CHECK FOR TRANSACTION TYPE AND ERROR");
- break;
-
- case CUDA_STATE_RECEIVE_EXPECTED:
- cuda_neg_tip_and_byteack(self);
- panic("Cuda - todo check for transaction type and error");
- break;
-
- default:
- cuda_set_data_direction_to_input(self);
- cuda_neg_tip_and_byteack(self);
- break;
-}
-}
-
-static void cuda_do_state_transition_delay( AppleCuda * self )
-{
- AbsoluteTime deadline;
-
- clock_absolutetime_interval_to_deadline(
- self->cuda_state_transition_delay, &deadline);
- clock_delay_until(deadline);
-}