]> git.saurik.com Git - apple/xnu.git/blame - iokit/Drivers/platform/drvAppleCuda/AppleCuda.cpp
xnu-201.tar.gz
[apple/xnu.git] / iokit / Drivers / platform / drvAppleCuda / AppleCuda.cpp
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
24 * All Rights Reserved
25 *
26 * Permission to use, copy, modify, and distribute this software and
27 * its documentation for any purpose and without fee is hereby granted,
28 * provided that the above copyright notice appears in all copies and
29 * that both the copyright notice and this permission notice appear in
30 * supporting documentation.
31 *
32 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
33 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
34 * FOR A PARTICULAR PURPOSE.
35 *
36 * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
37 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
38 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
39 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
40 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
41 *
42 */
43/*
44 * Copyright 1996 1995 by Apple Computer, Inc. 1997 1996 1995 1994 1993 1992 1991
45 * All Rights Reserved
46 *
47 * Permission to use, copy, modify, and distribute this software and
48 * its documentation for any purpose and without fee is hereby granted,
49 * provided that the above copyright notice appears in all copies and
50 * that both the copyright notice and this permission notice appear in
51 * supporting documentation.
52 *
53 * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
54 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
55 * FOR A PARTICULAR PURPOSE.
56 *
57 * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
58 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
59 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
60 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
61 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
62 */
63/*
64 * MKLINUX-1.0DR2
65 */
66
67/* 1 April 1997 Simon Douglas:
68 * Stolen wholesale from MkLinux.
69 * Added nonblocking adb poll from interrupt level for the debugger.
70 * Acknowledge before response so polled mode can work from inside the adb handler.
71 *
72 * 18 June 1998 sdouglas
73 * Start IOKit version. Fix errors from kCudaSRQAssertMask. Use ool cmd & reply buffers,
74 * not fixed len in packet. Does queueing here.
75 *
76 * 20 Nov 1998 suurballe
77 * Port to C++
78 */
79
80
81#include "AppleCuda.h"
0b4e3aa0 82#include "AppleCudaUserClient.h"
1c79356b
A
83#include "IOCudaADBController.h"
84#include <IOKit/IOLib.h>
85#include <IOKit/IOSyncer.h>
86#include <IOKit/IOWorkLoop.h>
87#include <IOKit/IOInterruptEventSource.h>
88#include <IOKit/IODeviceMemory.h>
89#include <IOKit/IOPlatformExpert.h>
90#include <IOKit/pwr_mgt/IOPM.h>
91
92#include <IOKit/assert.h>
93
94#define super IOService
95OSDefineMetaClassAndStructors(AppleCuda,IOService)
96
97static void cuda_interrupt ( AppleCuda * self );
98
99static void cuda_process_response(AppleCuda * self);
100static void cuda_transmit_data(AppleCuda * self);
101static void cuda_expected_attention(AppleCuda * self);
102static void cuda_unexpected_attention(AppleCuda * self);
103static void cuda_receive_data(AppleCuda * self);
104static void cuda_receive_last_byte(AppleCuda * self);
105static void cuda_collision(AppleCuda * self);
106static void cuda_idle(AppleCuda * self);
107
108static void cuda_poll(AppleCuda * self);
109static void cuda_error(AppleCuda * self);
110static void cuda_send_request(AppleCuda * self);
111static IOReturn cuda_do_sync_request( AppleCuda * self,
112 cuda_request_t * request, bool polled);
113static void cuda_do_state_transition_delay(AppleCuda * self);
114
115static int Cuda_PE_poll_input(unsigned int options, char * c);
116static int Cuda_PE_read_write_time_of_day(unsigned int options, long * secs);
117static int Cuda_PE_halt_restart(unsigned int type);
118static int Cuda_PE_write_IIC(unsigned char addr, unsigned char reg,
119 unsigned char data);
120
121static void
122autopollArrived ( OSObject *inCuda, IOInterruptEventSource *, int );
123
124static int set_cuda_power_message ( int command );
125static int set_cuda_file_server_mode ( int command );
0b4e3aa0 126static int set_cuda_poweruptime(long secs);
1c79356b
A
127static void cuda_async_set_power_message_enable( thread_call_param_t param, thread_call_param_t );
128static void cuda_async_set_file_server_mode( thread_call_param_t param, thread_call_param_t ) ;
129
130bool CudahasRoot( OSObject * us, void *, IOService * yourDevice );
131
132
133//
134// inline functions
135//
136
137static __inline__ unsigned char cuda_read_data(AppleCuda * self)
138{
139 volatile unsigned char val;
140
141 val = *self->cuda_via_regs.shift; eieio();
142 return val;
143}
144
145static __inline__ int cuda_get_result(cuda_request_t *request)
146{
147 int status = ADB_RET_OK;
148 int theStatus = request->a_reply.a_header[1];
149
150 if ( theStatus & kCudaTimeOutMask ) {
151 status = ADB_RET_TIMEOUT;
152#if 0
153 // these are expected before autopoll mask is set
154 } else if ( theStatus & kCudaSRQAssertMask ) {
155 status = ADB_RET_UNEXPECTED_RESULT;
156#endif
157 } else if ( theStatus & kCudaSRQErrorMask ) {
158 status = ADB_RET_REQUEST_ERROR;
159 } else if ( theStatus & kCudaBusErrorMask ) {
160 status = ADB_RET_BUS_ERROR;
161 }
162
163 return status;
164}
165
166static __inline__ void cuda_lock(AppleCuda * self)
167{
168 if( !self->cuda_polled_mode)
169 IOSimpleLockLock(self->cuda_request_lock);
170}
171
172static __inline__ void cuda_unlock(AppleCuda * self)
173{
174 if( !self->cuda_polled_mode)
175 IOSimpleLockUnlock(self->cuda_request_lock);
176}
177
178//
179//
180//
181
182
183static AppleCuda * gCuda;
184// **********************************************************************************
185// init
186//
187// **********************************************************************************
188bool AppleCuda::init ( OSDictionary * properties = 0 )
189{
190return super::init(properties);
191}
192
193
194// **********************************************************************************
195// start
196//
197// **********************************************************************************
198bool AppleCuda::start ( IOService * nub )
199{
200int i;
201IOMemoryMap * viaMap;
202unsigned char * cuda_base;
203
204if( !super::start(nub))
205 return false;
206
207gCuda = this;
208 // callPlatformFunction symbols
209 cuda_check_any_interrupt = OSSymbol::withCString("cuda_check_any_interrupt");
210
211workLoop = NULL;
212eventSrc = NULL;
213ourADBinterface = NULL;
214_rootDomain = 0;
0b4e3aa0 215_wakeup_from_sleep = false;
1c79356b
A
216
217workLoop = IOWorkLoop::workLoop();
218if ( !workLoop ) {
219 kprintf("Start is bailing\n");
220 return false;
221}
222
223eventSrc = IOInterruptEventSource::interruptEventSource(this, autopollArrived);
224if (!eventSrc ||
225 kIOReturnSuccess != workLoop->addEventSource(eventSrc) ) {
226 kprintf("Start is bailing\n");
227 return false;
228}
229
230if( 0 == (viaMap = nub->mapDeviceMemoryWithIndex( 0 )) ) {
231 IOLog("%s: no via memory\n", getName());
232 kprintf("Start is bailing\n");
233 return false;
234}
235cuda_base = (unsigned char *)viaMap->getVirtualAddress();
236
237kprintf("VIA base = %08x\n", (UInt32)cuda_base);
238ourADBinterface = new IOCudaADBController;
239if ( !ourADBinterface ) {
240 kprintf("Start is bailing\n");
241 return false;
242}
243if ( !ourADBinterface->init(0,this) ) {
244 kprintf("Start is bailing\n");
245 return false;
246}
247
248if ( !ourADBinterface->attach( this) ) {
249 kprintf("Start is bailing\n");
250 return false;
251}
252
253cuda_request_lock = IOSimpleLockAlloc();
254IOSimpleLockInit(cuda_request_lock);
255
256cuda_via_regs.dataB = cuda_base;
257cuda_via_regs.handshakeDataA = cuda_base+0x0200;
258cuda_via_regs.dataDirectionB = cuda_base+0x0400;
259cuda_via_regs.dataDirectionA = cuda_base+0x0600;
260cuda_via_regs.timer1CounterLow = cuda_base+0x0800;
261cuda_via_regs.timer1CounterHigh = cuda_base+0x0A00;
262cuda_via_regs.timer1LatchLow = cuda_base+0x0C00;
263cuda_via_regs.timer1LatchHigh = cuda_base+0x0E00;
264cuda_via_regs.timer2CounterLow = cuda_base+0x1000;
265cuda_via_regs.timer2CounterHigh = cuda_base+0x1200;
266cuda_via_regs.shift = cuda_base+0x1400;
267cuda_via_regs.auxillaryControl = cuda_base+0x1600;
268cuda_via_regs.peripheralControl = cuda_base+0x1800;
269cuda_via_regs.interruptFlag = cuda_base+0x1A00;
270cuda_via_regs.interruptEnable = cuda_base+0x1C00;
271cuda_via_regs.dataA = cuda_base+0x1E00;
272
273// we require delays of this duration between certain state transitions
274clock_interval_to_absolutetime_interval(200, 1, &cuda_state_transition_delay);
275
276// Set the direction of the cuda signals. ByteACk and TIP are output and
277// TREQ is an input
278
279*cuda_via_regs.dataDirectionB |= (kCudaByteAcknowledgeMask | kCudaTransferInProgressMask);
280*cuda_via_regs.dataDirectionB &= ~kCudaTransferRequestMask;
281
282// Set the clock control. Set to shift data in by external clock CB1.
283
284*cuda_via_regs.auxillaryControl = (*cuda_via_regs.auxillaryControl | kCudaTransferMode) &
285 kCudaSystemRecieve;
286
287// Clear any posible cuda interupt.
288
289if ( *cuda_via_regs.shift );
290
291// Initialize the internal data.
292
293cuda_interrupt_state = CUDA_STATE_IDLE;
294cuda_transaction_state = CUDA_TS_NO_REQUEST;
295cuda_is_header_transfer = false;
296cuda_is_packet_type = false;
297cuda_transfer_count = 0;
298cuda_current_response = NULL;
299for( i = 0; i < NUM_AP_BUFFERS; i++ ) {
300 cuda_unsolicited[ i ].a_buffer = cuda_autopoll_buffers[ i ];
301}
302
303// Terminate transaction and set idle state
304
305cuda_neg_tip_and_byteack(this);
306
307// we want to delay 4 mS for ADB reset to complete
308
309IOSleep( 4 );
310
311// Clear pending interrupt if any...
312
313(void)cuda_read_data(this);
314
315// Issue a Sync Transaction, ByteAck asserted while TIP is negated.
316
317cuda_assert_byte_ack(this);
318
319// Wait for the Sync acknowledgement, cuda to assert TREQ
320
321cuda_wait_for_transfer_request_assert(this);
322
323// Wait for the Sync acknowledgement interrupt.
324
325cuda_wait_for_interrupt(this);
326
327// Clear pending interrupt
328
329(void)cuda_read_data(this);
330
331// Terminate the sync cycle by Negating ByteAck
332
333cuda_neg_byte_ack(this);
334
335// Wait for the Sync termination acknowledgement, cuda negates TREQ.
336
337cuda_wait_for_transfer_request_neg(this);
338
339// Wait for the Sync termination acknowledgement interrupt.
340
341cuda_wait_for_interrupt(this);
342
343// Terminate transaction and set idle state, TIP negate and ByteAck negate.
344cuda_neg_transfer_in_progress(this);
345
346// Clear pending interrupt, if there is one...
347(void)cuda_read_data(this);
348
349#if 0
350 cuda_polled_mode = true;
351#else
352#define VIA_DEV_CUDA 2
353nub->registerInterrupt(VIA_DEV_CUDA,
354 this, (IOInterruptAction) cuda_interrupt);
355nub->enableInterrupt(VIA_DEV_CUDA);
356#endif
357
358PE_poll_input = Cuda_PE_poll_input;
359PE_read_write_time_of_day = Cuda_PE_read_write_time_of_day;
360PE_halt_restart = Cuda_PE_halt_restart;
361PE_write_IIC = Cuda_PE_write_IIC;
362publishResource( "IOiic0", this );
363publishResource( "IORTC", this );
364
365
366//set_cuda_power_message(kADB_powermsg_enable); //won't work on beige G3
367thread_call_func(cuda_async_set_power_message_enable, (thread_call_param_t)this, true);
368thread_call_func(cuda_async_set_file_server_mode, (thread_call_param_t)this, true);
369
370 registerService(); //Gossamer needs to find this driver for waking up G3
371
372 _cuda_power_state = 1; //default is wake state
373 //We want to know when sleep is about to occur
374 addNotification( gIOPublishNotification,serviceMatching("IOPMrootDomain"),
375 (IOServiceNotificationHandler)CudahasRoot, this, 0 );
376
377ourADBinterface->start( this );
378
379return true;
380}
381
382/* Here are some power management functions so we can tell when system is
383 going to sleep. */
384bool CudahasRoot( OSObject * us, void *, IOService * yourDevice )
385{
386 if (( yourDevice != NULL ) && ((AppleCuda *)us)->_rootDomain == 0)
387 {
388 ((AppleCuda *)us)->_rootDomain = (IOPMrootDomain *) yourDevice;
389 ((IOPMrootDomain *)yourDevice)->registerInterestedDriver((IOService *) us);
390 }
391 return true;
392}
393
394IOReturn AppleCuda::powerStateWillChangeTo ( IOPMPowerFlags theFlags, unsigned long unused1,
395 IOService* unused2)
396{
1c79356b
A
397 if ( ! (theFlags & IOPMPowerOn) )
398 {
399 _cuda_power_state = 0; //0 means sleeping
400 }
401 return IOPMAckImplied;
402}
403
404IOReturn AppleCuda::powerStateDidChangeTo ( IOPMPowerFlags theFlags, unsigned long unused1,
405 IOService* unused2)
406{
1c79356b
A
407 if (theFlags & IOPMPowerOn)
408 {
409 _cuda_power_state = 1; //1 means awake
0b4e3aa0 410 _wakeup_from_sleep = false; //normally it is false
1c79356b
A
411 }
412 return IOPMAckImplied;
413}
414
415
416
417// *****************************************************************************
418// getWorkLoop
419//
420// Return the cuda's workloop.
421//
422// *****************************************************************************
423IOWorkLoop *AppleCuda::getWorkLoop() const
424{
425 return workLoop;
426}
427
428// *****************************************************************************
429// free
430//
431// Release everything we may have allocated.
432//
433// *****************************************************************************
434void AppleCuda::free ( void )
435{
436if ( workLoop ) {
437 workLoop->release();
438}
439if ( eventSrc ) {
440 eventSrc->release();
441}
442if ( ourADBinterface ) {
443 ourADBinterface->release();
444}
445 if (_rootDomain)
446 {
447 _rootDomain->deRegisterInterestedDriver((IOService *) this);
448 _rootDomain = 0;
449 }
450super::free();
451}
452
453
454// **********************************************************************************
455// registerForADBInterrupts
456//
457// Some driver is calling to say it is prepared to receive "unsolicited" adb
458// interrupts (e.g. autopoll keyboard and trackpad data). The parameters identify
459// who to call when we get one.
460// **********************************************************************************
461void AppleCuda::registerForADBInterrupts ( ADB_callback_func handler, IOService * caller )
462{
463autopoll_handler = handler;
464ADBid = caller;
465}
466
467
468// **********************************************************************************
469// autopollArrived
470//
471// **********************************************************************************
472static void autopollArrived ( OSObject * CudaDriver, IOInterruptEventSource *, int )
473{
474((AppleCuda *)CudaDriver)->serviceAutopolls();
475}
476
477#define RB_BOOT 1 /* Causes reboot, not halt. Is in xnu/bsd/sys/reboot.h */
478extern "C" {
479 void boot(int paniced, int howto, char * command);
480}
481
482
483static void cuda_async_set_power_message_enable( thread_call_param_t param, thread_call_param_t )
484{
485 //AppleCuda * me = (AppleCuda *) param;
486
487 set_cuda_power_message(kADB_powermsg_enable);
488}
489
490static void cuda_async_set_file_server_mode( thread_call_param_t param, thread_call_param_t )
491{
492 set_cuda_file_server_mode(1);
493}
494
495// **********************************************************************************
496// serviceAutopolls
497// We get here just before calling autopollHandler() in IOADBController.cpp
498// **********************************************************************************
499void AppleCuda::serviceAutopolls ( void )
500{
501cuda_packet_t * response;
502
503 while( inIndex != outIndex ) {
1c79356b
A
504 response = &cuda_unsolicited[ outIndex ];
505
506 //Check for power messages, which are handled differently from regular
507 // autopoll data coming from mouse or keyboard.
508 if (response->a_header[0] == ADB_PACKET_POWER)
509 {
510 unsigned char flag, cmd;
511
512 flag = response->a_header[1];
513 cmd = response->a_header[2];
514
515 if ((flag == kADB_powermsg_flag_chassis)
516 && (cmd == kADB_powermsg_cmd_chassis_off))
517 {
518 thread_call_func(cuda_async_set_power_message_enable,
519 (thread_call_param_t)this, true);
520
521 if (_rootDomain)
522 {
523 if (_cuda_power_state)
524 {
525 //Put system to sleep now
526 _rootDomain->receivePowerNotification (kIOPMSleepNow);
527 }
528 else //If asleep, wake up the system
529 {
530 //Tickle activity timer in root domain. This will not
531 // wake up machine that is in demand-sleep, but it will
532 // wake up an inactive system that dozed
533 _rootDomain->activityTickle(0,0);
534 }
535 }
536 }
537 else if ((flag == kADB_powermsg_flag_keyboardpwr)
538 && (cmd == kADB_powermsg_cmd_keyboardoff))
539 {
540 //set_cuda_power_message(kADB_powermsg_continue);
541 //This needs to by async so Beige G3 ADB won't lock up
542 thread_call_func(cuda_async_set_power_message_enable,
543 (thread_call_param_t)this, true);
544 }
545
546 }
1c79356b
A
547 if ( ADBid != NULL ) {
548 (*autopoll_handler)(ADBid,response->a_header[2],response->a_bcount,response->a_buffer);
549 }
550
551 outIndex = (outIndex + 1) & (NUM_AP_BUFFERS - 1);
552
553 } //end of while loop
554
555}
556
557
558// **********************************************************************************
559// doSyncRequest
560//
561// **********************************************************************************
562IOReturn AppleCuda::doSyncRequest ( cuda_request_t * request )
563{
564return(cuda_do_sync_request(this, request, false));
565}
566
567
568IOReturn AppleCuda::callPlatformFunction(const OSSymbol *functionName,
569 bool waitForFunction,
570 void *param1, void *param2,
571 void *param3, void *param4)
572{
573 if (functionName == cuda_check_any_interrupt)
574 {
575 bool *hasint;
576
577 hasint = (bool *)param1;
578 *hasint = false;
579
580 if (inIndex != outIndex)
581 {
582 *hasint = true;
583 }
0b4e3aa0
A
584
585 if (_wakeup_from_sleep)
586 {
587 *hasint = true;
588 }
1c79356b
A
589 return kIOReturnSuccess;
590 }
591
592 return kIOReturnBadArgument;
593}
594
595
0b4e3aa0
A
596void
597AppleCuda::setWakeTime(UInt32 waketime)
598{
599 //Call this function with waketime=0 in order to allow normal sleep again
600 _wakeup_from_sleep = false;
601 if (waketime != 0) {
602 timerSrc = IOTimerEventSource::timerEventSource((OSObject*)this, WakeupTimeoutHandler);
603
604 if (!timerSrc || (workLoop->addEventSource(timerSrc) != kIOReturnSuccess))
605 {
606 IOLog("Cuda can not register timeout event\n");
607 return;
608 }
609
610 timerSrc->setTimeoutMS(waketime);
611 }
612}
613
614static void
615AppleCuda::WakeupTimeoutHandler(OSObject *object, IOTimerEventSource *timer)
616{
617 gCuda->_wakeup_from_sleep = true;
618 if (gCuda->_rootDomain)
619 {
620 gCuda->_rootDomain->activityTickle(0,0);
621 }
622}
623
624
625void
626AppleCuda::setPowerOnTime(UInt32 newTime)
627{
628 long long_secs;
629
630 if (newTime != 0) {
631 Cuda_PE_read_write_time_of_day(kPEReadTOD, &long_secs);
632 set_cuda_poweruptime((long)newTime + long_secs);
633 }
634}
635
636void
637AppleCuda::setFileServerMode(bool fileServerModeON)
638{
639 set_cuda_file_server_mode((int) fileServerModeON);
640}
641
642void AppleCuda::demandSleepNow(void)
643{
644 if (_rootDomain)
645 {
646 _rootDomain->receivePowerNotification (kIOPMSleepNow);
647 }
648}
649
650// --------------------------------------------------------------------------
651//
652// Method: newUserClient
653//
654// Purpose:
655// newUserClient is called by the IOKit manager to create the
656// kernel receiver of a user request. The "type" is a qualifier
657// shared between the kernel and user client class instances..
658
659#define kAppleCudaUserClientMagicCookie 0x0C00DA
660
661IOReturn
662AppleCuda::newUserClient(task_t owningTask,
663 void *securityToken,
664 UInt32 magicCookie,
665 IOUserClient **handler)
666{
667 IOReturn ioReturn = kIOReturnSuccess;
668 AppleCudaUserClient *client = NULL;
669
670 IOLog("AppleCuda::newUserClient\n");
671
672 if (IOUserClient::clientHasPrivilege(securityToken, "root") != kIOReturnSuccess) {
673 IOLog("AppleCuda::newUserClient: Can't create user client, not privileged\n");
674 return kIOReturnNotPrivileged;
675 }
676
677 // Check that this is a user client type that we support.
678 // type is known only to this driver's user and kernel
679 // classes. It could be used, for example, to define
680 // read or write privileges. In this case, we look for
681 // a private value.
682 if (magicCookie == kAppleCudaUserClientMagicCookie) {
683 // Construct a new client instance for the requesting task.
684 // This is, essentially client = new AppleCudaUserClient;
685 // ... create metaclasses ...
686 // client->setTask(owningTask)
687 client = AppleCudaUserClient::withTask(owningTask);
688 if (client == NULL) {
689 ioReturn = kIOReturnNoResources;
690 IOLog("AppleCuda::newUserClient: Can't create user client\n");
691 }
692 }
693 else {
694 ioReturn = kIOReturnInvalid;
695 IOLog("AppleCuda::newUserClient: bad magic cookie.\n");
696 }
697
698 if (ioReturn == kIOReturnSuccess) {
699 // Attach ourself to the client so that this client instance
700 // can call us.
701 if (client->attach(this) == false) {
702 ioReturn = kIOReturnError;
703 IOLog("AppleCuda::newUserClient: Can't attach user client\n");
704 }
705 }
706
707 if (ioReturn == kIOReturnSuccess) {
708 // Start the client so it can accept requests.
709 if (client->start(this) == false) {
710 ioReturn = kIOReturnError;
711 IOLog("AppleCuda::newUserClientt: Can't start user client\n");
712 }
713 }
714
715 if (ioReturn != kIOReturnSuccess && client != NULL) {
716 client->detach(this);
717 client->release();
718 }
719
720 *handler = client;
721 return (ioReturn);
722}
723
1c79356b
A
724// **********************************************************************************
725// cuda_do_sync_request
726//
727// **********************************************************************************
728IOReturn cuda_do_sync_request ( AppleCuda * self, cuda_request_t * request, bool polled )
729{
730 bool wasPolled = false;
731 IOInterruptState ints;
732
733 if( !polled ) {
734 request->sync = IOSyncer::create();
735 request->needWake = true;
736 }
737
738 ints = IOSimpleLockLockDisableInterrupt(self->cuda_request_lock);
739
740 if( polled ) {
741 wasPolled = self->cuda_polled_mode;
742 self->cuda_polled_mode = polled;
743 }
744
745 if( self->cuda_last_request )
746 self->cuda_last_request->a_next = request;
747 else
748 self->cuda_request = request;
749
750 self->cuda_last_request = request;
751
752 if( self->cuda_interrupt_state == CUDA_STATE_IDLE )
753 cuda_send_request(self);
754
755 if( polled ) {
756 cuda_poll(self);
757 self->cuda_polled_mode = wasPolled;
758 assert( 0 == self->cuda_request );
759 assert( 0 == self->cuda_last_request );
760 }
761
762 IOSimpleLockUnlockEnableInterrupt(self->cuda_request_lock, ints);
763
764 if( !polled)
765 request->sync->wait();
766
767 return cuda_get_result(request);
768}
769
770
771// **********************************************************************************
772// Cuda_PE_read_write_time_of_day
773//
774// **********************************************************************************
775static int Cuda_PE_read_write_time_of_day ( unsigned int options, long * secs )
776{
777cuda_request_t cmd;
778
779adb_init_request(&cmd);
780
781cmd.a_cmd.a_hcount = 2;
782cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO;
783
784switch( options ) {
785
786 case kPEReadTOD:
787 cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_GET_REAL_TIME;
788 cmd.a_reply.a_buffer = (UInt8 *)secs;
789 cmd.a_reply.a_bcount = sizeof(*secs);
790 break;
791
792 case kPEWriteTOD:
793 cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_SET_REAL_TIME;
794 cmd.a_cmd.a_buffer = (UInt8 *)secs;
795 cmd.a_cmd.a_bcount = sizeof(*secs);
796 break;
797
798 default:
799 return 1;
800}
801
802return cuda_do_sync_request(gCuda, &cmd, true);
803}
804
805
806// **********************************************************************************
807// Cuda_PE_halt_restart
808//
809// **********************************************************************************
810static int Cuda_PE_halt_restart ( unsigned int type )
811{
812cuda_request_t cmd;
813
814adb_init_request(&cmd);
815
816cmd.a_cmd.a_hcount = 2;
817cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO;
818
819switch( type ) {
820
821 case kPERestartCPU:
822 cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_RESTART_SYSTEM;
823 break;
824
825 case kPEHaltCPU:
826 cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_POWER_DOWN;
827 break;
828
829 default:
830 return 1;
831 }
832
833return cuda_do_sync_request(gCuda, &cmd, true);
834}
835
0b4e3aa0
A
836// **********************************************************************************
837// Set the power-on time. 2001
838// **********************************************************************************
839static int set_cuda_poweruptime (long secs)
840{
841 cuda_request_t cmd;
842 long localsecs = secs;
843
844 adb_init_request(&cmd);
845
846 cmd.a_cmd.a_hcount = 2;
847 cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO;
848
849 cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_SET_POWER_UPTIME;
850 cmd.a_cmd.a_buffer = (UInt8 *)&localsecs;
851 cmd.a_cmd.a_bcount = 4;
852
853 return cuda_do_sync_request(gCuda, &cmd, true);
854}
855
1c79356b
A
856
857// **********************************************************************************
858// In case this machine loses power, it will automatically reboot when power is
859// restored. Only desktop machines have Cuda, so this feature will not affect
860// PowerBooks.
861// **********************************************************************************
862static int set_cuda_file_server_mode ( int command )
863{
864cuda_request_t cmd;
865
866adb_init_request(&cmd);
867
868cmd.a_cmd.a_hcount = 3;
869cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO;
870cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_FILE_SERVER_FLAG;
871cmd.a_cmd.a_header[2] = command;
872
873return cuda_do_sync_request(gCuda, &cmd, true);
874}
875
876// **********************************************************************************
877// Fix front panel power key (mostly on Yosemites) so that one press won't power
878// down the entire machine
879//
880// **********************************************************************************
881static int set_cuda_power_message ( int command )
882{
883cuda_request_t cmd;
884
885if (command >= kADB_powermsg_invalid)
886 return 0; //invalid Cuda power request
887
888adb_init_request(&cmd);
889
890cmd.a_cmd.a_hcount = 3;
891cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO;
892cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_SET_POWER_MESSAGES;
893cmd.a_cmd.a_header[2] = command;
894
895return cuda_do_sync_request(gCuda, &cmd, true);
896}
897
898
899// **********************************************************************************
900// Cuda_PE_write_IIC
901//
902// **********************************************************************************
903static int Cuda_PE_write_IIC ( unsigned char addr, unsigned char reg, unsigned char data )
904{
905cuda_request_t cmd;
906
907adb_init_request(&cmd);
908
909cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO;
910cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_GET_SET_IIC;
911cmd.a_cmd.a_header[2] = addr;
912cmd.a_cmd.a_header[3] = reg;
913cmd.a_cmd.a_header[4] = data;
914cmd.a_cmd.a_hcount = 5;
915
916return cuda_do_sync_request(gCuda, &cmd, true);
917}
918
919IOReturn
920AppleCudaWriteIIC( UInt8 address, const UInt8 * buffer, IOByteCount * count )
921{
922 IOReturn ret;
923 cuda_request_t cmd;
924
925 if( !gCuda)
926 return( kIOReturnUnsupported );
927
928 adb_init_request(&cmd);
929
930 cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO;
931 cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_GET_SET_IIC;
932 cmd.a_cmd.a_header[2] = address;
933 cmd.a_cmd.a_hcount = 3;
934 cmd.a_cmd.a_buffer = (UInt8 *) buffer;
935 cmd.a_cmd.a_bcount = *count;
936
937 ret = cuda_do_sync_request(gCuda, &cmd, true);
938
939 *count = cmd.a_cmd.a_bcount;
940
941 return( ret );
942}
943
944IOReturn
945AppleCudaReadIIC( UInt8 address, UInt8 * buffer, IOByteCount * count )
946{
947 IOReturn ret;
948 cuda_request_t cmd;
949
950 if( !gCuda)
951 return( kIOReturnUnsupported );
952
953 adb_init_request(&cmd);
954
955 cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO;
956 cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_GET_SET_IIC;
957 cmd.a_cmd.a_header[2] = address;
958 cmd.a_cmd.a_hcount = 3;
959 cmd.a_reply.a_buffer = buffer;
960 cmd.a_reply.a_bcount = *count;
961
962 ret = cuda_do_sync_request(gCuda, &cmd, true);
963 *count = cmd.a_reply.a_bcount;
964
965 return( ret );
966}
967
968
969// **********************************************************************************
970// Cuda_PE_poll_input
971//
972// **********************************************************************************
973static int Cuda_PE_poll_input ( unsigned int, char * c )
974{
975AppleCuda * self = gCuda;
976int interruptflag;
977UInt8 code;
978cuda_packet_t * response; //0123456789abcdef
979static char keycodes2ascii[] = "asdfhgzxcv_bqwer" //00
980 "yt123465=97-80]o" //10
981 "u[ip\nlj'k;_,/nm." //20
982 "\t_"; //30
983
984*c = 0xff;
985
986if( !self ) {
987 return 1;
988}
989
990self->cuda_polled_mode = true;
991interruptflag = *self->cuda_via_regs.interruptFlag & kCudaInterruptMask;
992eieio();
993if( interruptflag ) {
994 cuda_interrupt(self);
995}
996
997if( self->inIndex != self->outIndex ) {
998 response = &self->cuda_unsolicited[ self->outIndex ];
999 if( ((response->a_header[2] >> 4) == 2)
1000 && (response->a_bcount > 1) ) {
1001 code = response->a_buffer[0];
1002 if( code < sizeof(keycodes2ascii) ) {
1003 *c = keycodes2ascii[ code ];
1004 }
1005 }
1006 self->outIndex = self->inIndex;
1007}
1008
1009self->cuda_polled_mode = false;
1010return 0;
1011}
1012
1013
1014//
1015// internal
1016//
1017
1018
1019// **********************************************************************************
1020// cuda_send_request
1021//
1022// **********************************************************************************
1023static void cuda_send_request ( AppleCuda * self )
1024{
1025
1026 // The data register must written with the data byte 25uS
1027 // after examining TREQ or we run the risk of getting out of sync
1028 // with Cuda. So call with disabled interrupts and spinlock held.
1029
1030 // Check if we can commence with the packet transmission. First, check if
1031 // Cuda can service our request now. Second, check if Cuda wants to send
1032 // a response packet now.
1033
1034if( !cuda_is_transfer_in_progress(self) ) {
1035 // Set the shift register direction to output to Cuda by setting
1036 // the direction bit.
1037
1038 cuda_set_data_direction_to_output(self);
1039
1040 // Write the first byte to the shift register
1041 cuda_write_data(self, self->cuda_request->a_cmd.a_header[0]);
1042
1043 // Set up the transfer state info here.
1044
1045 self->cuda_is_header_transfer = true;
1046 self->cuda_transfer_count = 1;
1047
1048 // Make sure we're in idle state before transaction, and then
1049 // assert TIP to tell Cuda we're starting command
1050 cuda_neg_byte_ack(self);
1051 cuda_assert_transfer_in_progress(self);
1052
1053 // The next state is going to be a transmit state, if there is
1054 // no collision. This is a requested response but call it sync.
1055
1056 self->cuda_interrupt_state = CUDA_STATE_TRANSMIT_EXPECTED;
1057 self->cuda_transaction_state = CUDA_TS_SYNC_RESPONSE;
1058}
1059
1060#if 0
1061else {
1062 IOLog("Req = %x, state = %x, TIP = %x\n", self->cuda_request,
1063 self->cuda_interrupt_state, cuda_is_transfer_in_progress(self));
1064}
1065#endif
1066}
1067
1068
1069// **********************************************************************************
1070// cuda_poll
1071//
1072// **********************************************************************************
1073static void cuda_poll( AppleCuda * self )
1074{
1075 do {
1076 cuda_wait_for_interrupt(self);
1077 cuda_interrupt(self);
1078 } while( self->cuda_interrupt_state != CUDA_STATE_IDLE );
1079}
1080
1081//
1082// cuda_process_response
1083// Execute at secondary interrupt.
1084//
1085
1086
1087// **********************************************************************************
1088// cuda_process_response
1089//
1090// **********************************************************************************
1091static void cuda_process_response ( AppleCuda * self )
1092{
1093volatile cuda_request_t * request;
1094unsigned int newIndex;
1095
1096 // Almost ready for the next state, which should be a Idle state.
1097 // Just need to notifiy the client.
1098
1099if ( self->cuda_transaction_state == CUDA_TS_SYNC_RESPONSE ) {
1100
1101 // dequeue reqeuest
1102 cuda_lock(self);
1103 request = self->cuda_request;
1104 if( NULL == (self->cuda_request = request->a_next) ) {
1105 self->cuda_last_request = NULL;
1106 }
1107 cuda_unlock(self);
1108
1109 // wake the sync request thread
1110 if ( ((cuda_request_t *)request)->needWake ) {
1111 ((cuda_request_t *)request)->sync->signal();
1112 }
1113
1114}
1115else {
1116 if ( self->cuda_transaction_state == CUDA_TS_ASYNC_RESPONSE ) {
1117 newIndex = (self->inIndex + 1) & (NUM_AP_BUFFERS - 1);
1118 if( newIndex != self->outIndex ) {
1119 self->inIndex = newIndex;
1120 }
1121 else {
1122 // drop this packet, and reuse the buffer
1123 }
1124 if ( !self->cuda_polled_mode ) {
1125 // wake thread to service autopolls
1126 self->eventSrc->interruptOccurred(0, 0, 0);
1127 }
1128 }
1129}
1130return;
1131}
1132
1133
1134// **********************************************************************************
1135// cuda_interrupt
1136//
1137// **********************************************************************************
1138static void cuda_interrupt ( AppleCuda * self )
1139{
1140unsigned char interruptState;
1141
1142 // Get the relevant signal in determining the cause of the interrupt:
1143 // the shift direction, the transfer request line and the transfer
1144 // request line.
1145
1146interruptState = cuda_get_interrupt_state(self);
1147
1148//kprintf("%02x",interruptState);
1149
1150switch ( interruptState ) {
1151 case kCudaReceiveByte:
1152 cuda_receive_data(self);
1153 break;
1154
1155 case kCudaReceiveLastByte:
1156 cuda_receive_last_byte(self);
1157 break;
1158
1159 case kCudaTransmitByte:
1160 cuda_transmit_data(self);
1161 break;
1162
1163 case kCudaUnexpectedAttention:
1164 cuda_unexpected_attention(self);
1165 break;
1166
1167 case kCudaExpectedAttention:
1168 cuda_expected_attention(self);
1169 break;
1170
1171 case kCudaIdleState:
1172 cuda_idle(self);
1173 break;
1174
1175 case kCudaCollision:
1176 cuda_collision(self);
1177 break;
1178
1179 // Unknown interrupt, clear it and leave.
1180 default:
1181 cuda_error(self);
1182 break;
1183}
1184}
1185
1186//
1187// TransmitCudaData
1188// Executes at hardware interrupt level.
1189//
1190
1191// **********************************************************************************
1192// cuda_transmit_data
1193//
1194// **********************************************************************************
1195static void cuda_transmit_data ( AppleCuda * self )
1196{
1197 // Clear the pending interrupt by reading the shift register.
1198
1199if ( self->cuda_is_header_transfer ) {
1200 // There are more header bytes, write one out.
1201 cuda_write_data(self, self->cuda_request->a_cmd.a_header[self->cuda_transfer_count++]);
1202
1203 // Toggle the handshake line.
1204 if ( self->cuda_transfer_count >= self->cuda_request->a_cmd.a_hcount ) {
1205 self->cuda_is_header_transfer = FALSE;
1206 self->cuda_transfer_count = 0;
1207 }
1208
1209 cuda_toggle_byte_ack( self);
1210}
1211else {
1212 if ( self->cuda_transfer_count < self->cuda_request->a_cmd.a_bcount ) {
1213 // There are more command bytes, write one out and update the pointer
1214 cuda_write_data( self,
1215 *(self->cuda_request->a_cmd.a_buffer + self->cuda_transfer_count++));
1216 // Toggle the handshake line.
1217 cuda_toggle_byte_ack(self);
1218 }
1219 else {
1220 (void)cuda_read_data(self);
1221 // There is no more command bytes, terminate the send transaction.
1222 // Cuda should send a expected attention interrupt soon.
1223
1224 cuda_neg_tip_and_byteack(self);
1225
1226 // The next interrupt should be a expected attention interrupt.
1227
1228 self->cuda_interrupt_state = CUDA_STATE_ATTN_EXPECTED;
1229 }
1230}
1231}
1232
1233//
1234// cuda_expected_attention
1235// Executes at hardware interrupt level.
1236//
1237
1238
1239// **********************************************************************************
1240// cuda_expected_attention
1241//
1242// **********************************************************************************
1243static void cuda_expected_attention ( AppleCuda * self )
1244{
1245 // Clear the pending interrupt by reading the shift register.
1246
1247(void)cuda_read_data(self);
1248
1249 // Allow the VIA to settle directions.. else the possibility of
1250 // data corruption.
1251cuda_do_state_transition_delay(self);
1252
1253if ( self->cuda_transaction_state == CUDA_TS_SYNC_RESPONSE ) {
1254 self->cuda_current_response = (cuda_packet_t*)&self->cuda_request->a_reply;
1255}
1256else {
1257 self->cuda_current_response = &self->cuda_unsolicited[ self->inIndex ];
1258 self->cuda_current_response->a_hcount = 0;
1259 self->cuda_current_response->a_bcount = MAX_AP_RESPONSE;
1260}
1261
1262self->cuda_is_header_transfer = true;
1263self->cuda_is_packet_type = true;
1264self->cuda_transfer_count = 0;
1265
1266 // Set the shift register direction to input.
1267cuda_set_data_direction_to_input(self);
1268
1269 // Start the response packet transaction.
1270cuda_assert_transfer_in_progress(self);
1271
1272 // The next interrupt should be a receive data interrupt.
1273self->cuda_interrupt_state = CUDA_STATE_RECEIVE_EXPECTED;
1274}
1275
1276//
1277// cuda_unexpected_attention
1278// Executes at hardware interrupt level.
1279//
1280
1281
1282// **********************************************************************************
1283// cuda_expected_attention
1284//
1285// **********************************************************************************
1286static void cuda_unexpected_attention ( AppleCuda * self )
1287{
1288 // Clear the pending interrupt by reading the shift register.
1289(void)cuda_read_data(self);
1290
1291 // Get ready for a unsolicited response.
1292self->cuda_current_response = &self->cuda_unsolicited[ self->inIndex ];
1293self->cuda_current_response->a_hcount = 0;
1294self->cuda_current_response->a_bcount = MAX_AP_RESPONSE;
1295
1296self->cuda_is_header_transfer = TRUE;
1297self->cuda_is_packet_type = TRUE;
1298self->cuda_transfer_count = 0;
1299
1300 // Start the response packet transaction, Transaction In Progress
1301cuda_assert_transfer_in_progress(self);
1302
1303 // The next interrupt should be a receive data interrupt and the next
1304 // response should be an async response.
1305
1306self->cuda_interrupt_state = CUDA_STATE_RECEIVE_EXPECTED;
1307
1308self->cuda_transaction_state = CUDA_TS_ASYNC_RESPONSE;
1309}
1310
1311//
1312// cuda_receive_data
1313// Executes at hardware interrupt level.
1314//
1315
1316
1317// **********************************************************************************
1318// cuda_receive_data
1319//
1320// **********************************************************************************
1321static void cuda_receive_data ( AppleCuda * self )
1322{
1323if ( self->cuda_is_packet_type ) {
1324 unsigned char packetType;
1325
1326 packetType = cuda_read_data( self);
1327 self->cuda_current_response->a_header[self->cuda_transfer_count++] = packetType;
1328
1329 if ( packetType == ADB_PACKET_ERROR) {
1330 self->cuda_current_response->a_hcount = 4;
1331 }
1332 else {
1333 self->cuda_current_response->a_hcount = 3;
1334 }
1335
1336 self->cuda_is_packet_type = false;
1337
1338 cuda_toggle_byte_ack(self);
1339
1340}
1341else {
1342
1343
1344 if ( self->cuda_is_header_transfer ) {
1345
1346 self->cuda_current_response->a_header[self->cuda_transfer_count++] =
1347 cuda_read_data(self);
1348
1349 if (self->cuda_transfer_count >= self->cuda_current_response->a_hcount) {
1350 self->cuda_is_header_transfer = FALSE;
1351 self->cuda_transfer_count = 0;
1352 }
1353
1354 cuda_toggle_byte_ack(self);
1355 }
1356 else {
1357 if ( self->cuda_transfer_count < self->cuda_current_response->a_bcount ) {
1358 // Still room for more bytes. Get the byte and tell Cuda to continue.
1359 // Toggle the handshake line, ByteAck, to acknowledge receive.
1360
1361 *(self->cuda_current_response->a_buffer + self->cuda_transfer_count++) =
1362 cuda_read_data(self);
1363 cuda_toggle_byte_ack(self);
1364
1365 }
1366 else {
1367 // Cuda is still sending data but the buffer is full.
1368 // Normally should not get here. The only exceptions are open ended
1369 // request such as PRAM read... In any event time to exit.
1370
1371 self->cuda_current_response->a_bcount = self->cuda_transfer_count;
1372
1373 cuda_read_data(self);
1374
1375 cuda_process_response(self);
1376 cuda_neg_tip_and_byteack(self);
1377 }
1378 }
1379}
1380}
1381
1382
1383//
1384// cuda_receive_last_byte
1385// Executes at hardware interrupt level.
1386//
1387
1388
1389// **********************************************************************************
1390// cuda_receive_last_byte
1391//
1392// **********************************************************************************
1393static void cuda_receive_last_byte ( AppleCuda * self )
1394{
1395
1396if ( self->cuda_is_header_transfer ) {
1397 self->cuda_current_response->a_header[self->cuda_transfer_count++] =
1398 cuda_read_data(self);
1399
1400 self->cuda_transfer_count = 0;
1401 }
1402else {
1403 if ( self->cuda_transfer_count < self->cuda_current_response->a_bcount ) {
1404 *(self->cuda_current_response->a_buffer + self->cuda_transfer_count++) =
1405 cuda_read_data(self);
1406 }
1407 else {
1408 /* Overrun -- ignore data */
1409 (void) cuda_read_data(self);
1410 }
1411}
1412self->cuda_current_response->a_bcount = self->cuda_transfer_count;
1413 // acknowledge before response so polled mode can work
1414 // from inside the handler
1415cuda_neg_tip_and_byteack(self);
1416cuda_process_response(self);
1417}
1418
1419
1420//
1421// cuda_collision
1422// Executes at hardware interrupt level.
1423//
1424
1425
1426// **********************************************************************************
1427// cuda_collision
1428//
1429// **********************************************************************************
1430static void cuda_collision ( AppleCuda * self )
1431{
1432// Clear the pending interrupt by reading the shift register.
1433(void)cuda_read_data(self);
1434
1435// Negate TIP to abort the send. Cuda should send a second attention
1436// interrupt to acknowledge the abort cycle.
1437cuda_neg_transfer_in_progress(self);
1438
1439// The next interrupt should be an expected attention and the next
1440// response packet should be an async response.
1441
1442self->cuda_interrupt_state = CUDA_STATE_ATTN_EXPECTED;
1443self->cuda_transaction_state = CUDA_TS_ASYNC_RESPONSE;
1444
1445/* queue the request */
1446self->cuda_is_header_transfer = false;
1447self->cuda_transfer_count = 0;
1448}
1449
1450
1451//
1452//
1453// Executes at hardware interrupt level.
1454//
1455
1456
1457// **********************************************************************************
1458// cuda_idle
1459//
1460// **********************************************************************************
1461static void cuda_idle ( AppleCuda * self )
1462{
1463
1464// Clear the pending interrupt by reading the shift register.
1465(void)cuda_read_data(self);
1466
1467cuda_lock(self);
1468 // Set to the idle state.
1469self->cuda_interrupt_state = CUDA_STATE_IDLE;
1470 // See if there are any pending requests.
1471if( self->cuda_request ) {
1472 cuda_send_request(self);
1473}
1474cuda_unlock(self);
1475}
1476
1477
1478// **********************************************************************************
1479// cuda_error
1480//
1481// **********************************************************************************
1482static void cuda_error ( AppleCuda * self )
1483{
1484//printf("{Error %d}", self->cuda_transaction_state);
1485
1486// Was looking at cuda_transaction_state - doesn't seem right
1487
1488switch ( self->cuda_interrupt_state ) {
1489 case CUDA_STATE_IDLE:
1490 cuda_neg_tip_and_byteack(self);
1491 break;
1492
1493 case CUDA_STATE_TRANSMIT_EXPECTED:
1494 if ( self->cuda_is_header_transfer && self->cuda_transfer_count <= 1 ) {
1495 cuda_do_state_transition_delay(self);
1496 cuda_neg_transfer_in_progress(self);
1497 cuda_set_data_direction_to_input(self);
1498 panic ("CUDA - TODO FORCE COMMAND BACK UP!\n");
1499 }
1500 else {
1501 self->cuda_interrupt_state = CUDA_STATE_ATTN_EXPECTED;
1502 cuda_neg_tip_and_byteack(self);
1503 }
1504 break;
1505
1506 case CUDA_STATE_ATTN_EXPECTED:
1507 cuda_assert_transfer_in_progress(self);
1508
1509 cuda_do_state_transition_delay(self);
1510 cuda_set_data_direction_to_input(self);
1511 cuda_neg_transfer_in_progress(self);
1512 panic("CUDA - TODO CHECK FOR TRANSACTION TYPE AND ERROR");
1513 break;
1514
1515 case CUDA_STATE_RECEIVE_EXPECTED:
1516 cuda_neg_tip_and_byteack(self);
1517 panic("Cuda - todo check for transaction type and error");
1518 break;
1519
1520 default:
1521 cuda_set_data_direction_to_input(self);
1522 cuda_neg_tip_and_byteack(self);
1523 break;
1524}
1525}
1526
1527static void cuda_do_state_transition_delay( AppleCuda * self )
1528{
1529 AbsoluteTime deadline;
1530
1531 clock_absolutetime_interval_to_deadline(
1532 self->cuda_state_transition_delay, &deadline);
1533 clock_delay_until(deadline);
1534}