#include "AppleCuda.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 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 );
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
} 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;
bool AppleCuda::init ( OSDictionary * properties = 0 )
{
return super::init(properties);
}
bool AppleCuda::start ( IOService * nub )
{
int i;
IOMemoryMap * viaMap;
unsigned char * cuda_base;
if( !super::start(nub))
return false;
gCuda = this;
cuda_check_any_interrupt = OSSymbol::withCString("cuda_check_any_interrupt");
workLoop = NULL;
eventSrc = NULL;
ourADBinterface = NULL;
_rootDomain = 0;
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;
clock_interval_to_absolutetime_interval(200, 1, &cuda_state_transition_delay);
*cuda_via_regs.dataDirectionB |= (kCudaByteAcknowledgeMask | kCudaTransferInProgressMask);
*cuda_via_regs.dataDirectionB &= ~kCudaTransferRequestMask;
*cuda_via_regs.auxillaryControl = (*cuda_via_regs.auxillaryControl | kCudaTransferMode) &
kCudaSystemRecieve;
if ( *cuda_via_regs.shift );
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 ];
}
cuda_neg_tip_and_byteack(this);
IOSleep( 4 );
(void)cuda_read_data(this);
cuda_assert_byte_ack(this);
cuda_wait_for_transfer_request_assert(this);
cuda_wait_for_interrupt(this);
(void)cuda_read_data(this);
cuda_neg_byte_ack(this);
cuda_wait_for_transfer_request_neg(this);
cuda_wait_for_interrupt(this);
cuda_neg_transfer_in_progress(this);
(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 );
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();
_cuda_power_state = 1; addNotification( gIOPublishNotification,serviceMatching("IOPMrootDomain"),
(IOServiceNotificationHandler)CudahasRoot, this, 0 );
ourADBinterface->start( this );
return true;
}
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; }
return IOPMAckImplied;
}
IOReturn AppleCuda::powerStateDidChangeTo ( IOPMPowerFlags theFlags, unsigned long unused1,
IOService* unused2)
{
if (theFlags & IOPMPowerOn)
{
_cuda_power_state = 1; }
return IOPMAckImplied;
}
IOWorkLoop *AppleCuda::getWorkLoop() const
{
return workLoop;
}
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();
}
void AppleCuda::registerForADBInterrupts ( ADB_callback_func handler, IOService * caller )
{
autopoll_handler = handler;
ADBid = caller;
}
static void autopollArrived ( OSObject * CudaDriver, IOInterruptEventSource *, int )
{
((AppleCuda *)CudaDriver)->serviceAutopolls();
}
#define RB_BOOT 1
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 )
{
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);
}
void AppleCuda::serviceAutopolls ( void )
{
cuda_packet_t * response;
while( inIndex != outIndex ) {
response = &cuda_unsolicited[ outIndex ];
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)
{
_rootDomain->receivePowerNotification (kIOPMSleepNow);
}
else {
_rootDomain->activityTickle(0,0);
}
}
}
else if ((flag == kADB_powermsg_flag_keyboardpwr)
&& (cmd == kADB_powermsg_cmd_keyboardoff))
{
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);
}
}
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;
}
return kIOReturnSuccess;
}
return kIOReturnBadArgument;
}
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);
}
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);
}
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);
}
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);
}
static int set_cuda_power_message ( int command )
{
cuda_request_t cmd;
if (command >= kADB_powermsg_invalid)
return 0;
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);
}
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 );
}
static int Cuda_PE_poll_input ( unsigned int, char * c )
{
AppleCuda * self = gCuda;
int interruptflag;
UInt8 code;
cuda_packet_t * response; static char keycodes2ascii[] = "asdfhgzxcv_bqwer" "yt123465=97-80]o" "u[ip\nlj'k;_,/nm." "\t_";
*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;
}
static void cuda_send_request ( AppleCuda * self )
{
if( !cuda_is_transfer_in_progress(self) ) {
cuda_set_data_direction_to_output(self);
cuda_write_data(self, self->cuda_request->a_cmd.a_header[0]);
self->cuda_is_header_transfer = true;
self->cuda_transfer_count = 1;
cuda_neg_byte_ack(self);
cuda_assert_transfer_in_progress(self);
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
}
static void cuda_poll( AppleCuda * self )
{
do {
cuda_wait_for_interrupt(self);
cuda_interrupt(self);
} while( self->cuda_interrupt_state != CUDA_STATE_IDLE );
}
static void cuda_process_response ( AppleCuda * self )
{
volatile cuda_request_t * request;
unsigned int newIndex;
if ( self->cuda_transaction_state == CUDA_TS_SYNC_RESPONSE ) {
cuda_lock(self);
request = self->cuda_request;
if( NULL == (self->cuda_request = request->a_next) ) {
self->cuda_last_request = NULL;
}
cuda_unlock(self);
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 {
}
if ( !self->cuda_polled_mode ) {
self->eventSrc->interruptOccurred(0, 0, 0);
}
}
}
return;
}
static void cuda_interrupt ( AppleCuda * self )
{
unsigned char interruptState;
interruptState = cuda_get_interrupt_state(self);
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;
default:
cuda_error(self);
break;
}
}
static void cuda_transmit_data ( AppleCuda * self )
{
if ( self->cuda_is_header_transfer ) {
cuda_write_data(self, self->cuda_request->a_cmd.a_header[self->cuda_transfer_count++]);
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 ) {
cuda_write_data( self,
*(self->cuda_request->a_cmd.a_buffer + self->cuda_transfer_count++));
cuda_toggle_byte_ack(self);
}
else {
(void)cuda_read_data(self);
cuda_neg_tip_and_byteack(self);
self->cuda_interrupt_state = CUDA_STATE_ATTN_EXPECTED;
}
}
}
static void cuda_expected_attention ( AppleCuda * self )
{
(void)cuda_read_data(self);
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;
cuda_set_data_direction_to_input(self);
cuda_assert_transfer_in_progress(self);
self->cuda_interrupt_state = CUDA_STATE_RECEIVE_EXPECTED;
}
static void cuda_unexpected_attention ( AppleCuda * self )
{
(void)cuda_read_data(self);
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;
cuda_assert_transfer_in_progress(self);
self->cuda_interrupt_state = CUDA_STATE_RECEIVE_EXPECTED;
self->cuda_transaction_state = CUDA_TS_ASYNC_RESPONSE;
}
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 ) {
*(self->cuda_current_response->a_buffer + self->cuda_transfer_count++) =
cuda_read_data(self);
cuda_toggle_byte_ack(self);
}
else {
self->cuda_current_response->a_bcount = self->cuda_transfer_count;
cuda_read_data(self);
cuda_process_response(self);
cuda_neg_tip_and_byteack(self);
}
}
}
}
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 {
(void) cuda_read_data(self);
}
}
self->cuda_current_response->a_bcount = self->cuda_transfer_count;
cuda_neg_tip_and_byteack(self);
cuda_process_response(self);
}
static void cuda_collision ( AppleCuda * self )
{
(void)cuda_read_data(self);
cuda_neg_transfer_in_progress(self);
self->cuda_interrupt_state = CUDA_STATE_ATTN_EXPECTED;
self->cuda_transaction_state = CUDA_TS_ASYNC_RESPONSE;
self->cuda_is_header_transfer = false;
self->cuda_transfer_count = 0;
}
static void cuda_idle ( AppleCuda * self )
{
(void)cuda_read_data(self);
cuda_lock(self);
self->cuda_interrupt_state = CUDA_STATE_IDLE;
if( self->cuda_request ) {
cuda_send_request(self);
}
cuda_unlock(self);
}
static void cuda_error ( AppleCuda * self )
{
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);
}