2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
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.
32 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
33 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
34 * FOR A PARTICULAR PURPOSE.
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.
44 * Copyright 1996 1995 by Apple Computer, Inc. 1997 1996 1995 1994 1993 1992 1991
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.
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.
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.
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.
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.
76 * 20 Nov 1998 suurballe
81 #include "AppleCuda.h"
82 #include "AppleCudaUserClient.h"
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>
92 #include <IOKit/assert.h>
94 #define super IOService
95 OSDefineMetaClassAndStructors(AppleCuda
,IOService
)
97 static void cuda_interrupt ( AppleCuda
* self
);
99 static void cuda_process_response(AppleCuda
* self
);
100 static void cuda_transmit_data(AppleCuda
* self
);
101 static void cuda_expected_attention(AppleCuda
* self
);
102 static void cuda_unexpected_attention(AppleCuda
* self
);
103 static void cuda_receive_data(AppleCuda
* self
);
104 static void cuda_receive_last_byte(AppleCuda
* self
);
105 static void cuda_collision(AppleCuda
* self
);
106 static void cuda_idle(AppleCuda
* self
);
108 static void cuda_poll(AppleCuda
* self
);
109 static void cuda_error(AppleCuda
* self
);
110 static void cuda_send_request(AppleCuda
* self
);
111 static IOReturn
cuda_do_sync_request( AppleCuda
* self
,
112 cuda_request_t
* request
, bool polled
);
113 static void cuda_do_state_transition_delay(AppleCuda
* self
);
115 static int Cuda_PE_poll_input(unsigned int options
, char * c
);
116 static int Cuda_PE_read_write_time_of_day(unsigned int options
, long * secs
);
117 static int Cuda_PE_halt_restart(unsigned int type
);
118 static int Cuda_PE_write_IIC(unsigned char addr
, unsigned char reg
,
122 autopollArrived ( OSObject
*inCuda
, IOInterruptEventSource
*, int );
124 static int set_cuda_power_message ( int command
);
125 static int set_cuda_file_server_mode ( int command
);
126 static int set_cuda_poweruptime(long secs
);
127 static void cuda_async_set_power_message_enable( thread_call_param_t param
, thread_call_param_t
);
128 static void cuda_async_set_file_server_mode( thread_call_param_t param
, thread_call_param_t
) ;
130 bool CudahasRoot( OSObject
* us
, void *, IOService
* yourDevice
);
137 static __inline__
unsigned char cuda_read_data(AppleCuda
* self
)
139 volatile unsigned char val
;
141 val
= *self
->cuda_via_regs
.shift
; eieio();
145 static __inline__
int cuda_get_result(cuda_request_t
*request
)
147 int status
= ADB_RET_OK
;
148 int theStatus
= request
->a_reply
.a_header
[1];
150 if ( theStatus
& kCudaTimeOutMask
) {
151 status
= ADB_RET_TIMEOUT
;
153 // these are expected before autopoll mask is set
154 } else if ( theStatus
& kCudaSRQAssertMask
) {
155 status
= ADB_RET_UNEXPECTED_RESULT
;
157 } else if ( theStatus
& kCudaSRQErrorMask
) {
158 status
= ADB_RET_REQUEST_ERROR
;
159 } else if ( theStatus
& kCudaBusErrorMask
) {
160 status
= ADB_RET_BUS_ERROR
;
166 static __inline__
void cuda_lock(AppleCuda
* self
)
168 if( !self
->cuda_polled_mode
)
169 IOSimpleLockLock(self
->cuda_request_lock
);
172 static __inline__
void cuda_unlock(AppleCuda
* self
)
174 if( !self
->cuda_polled_mode
)
175 IOSimpleLockUnlock(self
->cuda_request_lock
);
183 static AppleCuda
* gCuda
;
184 // **********************************************************************************
187 // **********************************************************************************
188 bool AppleCuda::init ( OSDictionary
* properties
= 0 )
190 return super::init(properties
);
194 // **********************************************************************************
197 // **********************************************************************************
198 bool AppleCuda::start ( IOService
* nub
)
201 IOMemoryMap
* viaMap
;
202 unsigned char * cuda_base
;
204 if( !super::start(nub
))
208 // callPlatformFunction symbols
209 cuda_check_any_interrupt
= OSSymbol::withCString("cuda_check_any_interrupt");
213 ourADBinterface
= NULL
;
215 _wakeup_from_sleep
= false;
217 workLoop
= IOWorkLoop::workLoop();
219 kprintf("Start is bailing\n");
223 eventSrc
= IOInterruptEventSource::interruptEventSource(this, autopollArrived
);
225 kIOReturnSuccess
!= workLoop
->addEventSource(eventSrc
) ) {
226 kprintf("Start is bailing\n");
230 if( 0 == (viaMap
= nub
->mapDeviceMemoryWithIndex( 0 )) ) {
231 IOLog("%s: no via memory\n", getName());
232 kprintf("Start is bailing\n");
235 cuda_base
= (unsigned char *)viaMap
->getVirtualAddress();
237 kprintf("VIA base = %08x\n", (UInt32
)cuda_base
);
238 ourADBinterface
= new IOCudaADBController
;
239 if ( !ourADBinterface
) {
240 kprintf("Start is bailing\n");
243 if ( !ourADBinterface
->init(0,this) ) {
244 kprintf("Start is bailing\n");
248 if ( !ourADBinterface
->attach( this) ) {
249 kprintf("Start is bailing\n");
253 cuda_request_lock
= IOSimpleLockAlloc();
254 IOSimpleLockInit(cuda_request_lock
);
256 cuda_via_regs
.dataB
= cuda_base
;
257 cuda_via_regs
.handshakeDataA
= cuda_base
+0x0200;
258 cuda_via_regs
.dataDirectionB
= cuda_base
+0x0400;
259 cuda_via_regs
.dataDirectionA
= cuda_base
+0x0600;
260 cuda_via_regs
.timer1CounterLow
= cuda_base
+0x0800;
261 cuda_via_regs
.timer1CounterHigh
= cuda_base
+0x0A00;
262 cuda_via_regs
.timer1LatchLow
= cuda_base
+0x0C00;
263 cuda_via_regs
.timer1LatchHigh
= cuda_base
+0x0E00;
264 cuda_via_regs
.timer2CounterLow
= cuda_base
+0x1000;
265 cuda_via_regs
.timer2CounterHigh
= cuda_base
+0x1200;
266 cuda_via_regs
.shift
= cuda_base
+0x1400;
267 cuda_via_regs
.auxillaryControl
= cuda_base
+0x1600;
268 cuda_via_regs
.peripheralControl
= cuda_base
+0x1800;
269 cuda_via_regs
.interruptFlag
= cuda_base
+0x1A00;
270 cuda_via_regs
.interruptEnable
= cuda_base
+0x1C00;
271 cuda_via_regs
.dataA
= cuda_base
+0x1E00;
273 // we require delays of this duration between certain state transitions
274 clock_interval_to_absolutetime_interval(200, 1, &cuda_state_transition_delay
);
276 // Set the direction of the cuda signals. ByteACk and TIP are output and
279 *cuda_via_regs
.dataDirectionB
|= (kCudaByteAcknowledgeMask
| kCudaTransferInProgressMask
);
280 *cuda_via_regs
.dataDirectionB
&= ~kCudaTransferRequestMask
;
282 // Set the clock control. Set to shift data in by external clock CB1.
284 *cuda_via_regs
.auxillaryControl
= (*cuda_via_regs
.auxillaryControl
| kCudaTransferMode
) &
287 // Clear any posible cuda interupt.
289 if ( *cuda_via_regs
.shift
);
291 // Initialize the internal data.
293 cuda_interrupt_state
= CUDA_STATE_IDLE
;
294 cuda_transaction_state
= CUDA_TS_NO_REQUEST
;
295 cuda_is_header_transfer
= false;
296 cuda_is_packet_type
= false;
297 cuda_transfer_count
= 0;
298 cuda_current_response
= NULL
;
299 for( i
= 0; i
< NUM_AP_BUFFERS
; i
++ ) {
300 cuda_unsolicited
[ i
].a_buffer
= cuda_autopoll_buffers
[ i
];
303 // Terminate transaction and set idle state
305 cuda_neg_tip_and_byteack(this);
307 // we want to delay 4 mS for ADB reset to complete
311 // Clear pending interrupt if any...
313 (void)cuda_read_data(this);
315 // Issue a Sync Transaction, ByteAck asserted while TIP is negated.
317 cuda_assert_byte_ack(this);
319 // Wait for the Sync acknowledgement, cuda to assert TREQ
321 cuda_wait_for_transfer_request_assert(this);
323 // Wait for the Sync acknowledgement interrupt.
325 cuda_wait_for_interrupt(this);
327 // Clear pending interrupt
329 (void)cuda_read_data(this);
331 // Terminate the sync cycle by Negating ByteAck
333 cuda_neg_byte_ack(this);
335 // Wait for the Sync termination acknowledgement, cuda negates TREQ.
337 cuda_wait_for_transfer_request_neg(this);
339 // Wait for the Sync termination acknowledgement interrupt.
341 cuda_wait_for_interrupt(this);
343 // Terminate transaction and set idle state, TIP negate and ByteAck negate.
344 cuda_neg_transfer_in_progress(this);
346 // Clear pending interrupt, if there is one...
347 (void)cuda_read_data(this);
350 cuda_polled_mode
= true;
352 #define VIA_DEV_CUDA 2
353 nub
->registerInterrupt(VIA_DEV_CUDA
,
354 this, (IOInterruptAction
) cuda_interrupt
);
355 nub
->enableInterrupt(VIA_DEV_CUDA
);
358 PE_poll_input
= Cuda_PE_poll_input
;
359 PE_read_write_time_of_day
= Cuda_PE_read_write_time_of_day
;
360 PE_halt_restart
= Cuda_PE_halt_restart
;
361 PE_write_IIC
= Cuda_PE_write_IIC
;
362 publishResource( "IOiic0", this );
363 publishResource( "IORTC", this );
366 //set_cuda_power_message(kADB_powermsg_enable); //won't work on beige G3
367 thread_call_func(cuda_async_set_power_message_enable
, (thread_call_param_t
)this, true);
368 thread_call_func(cuda_async_set_file_server_mode
, (thread_call_param_t
)this, true);
370 registerService(); //Gossamer needs to find this driver for waking up G3
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 );
377 ourADBinterface
->start( this );
382 /* Here are some power management functions so we can tell when system is
384 bool CudahasRoot( OSObject
* us
, void *, IOService
* yourDevice
)
386 if (( yourDevice
!= NULL
) && ((AppleCuda
*)us
)->_rootDomain
== 0)
388 ((AppleCuda
*)us
)->_rootDomain
= (IOPMrootDomain
*) yourDevice
;
389 ((IOPMrootDomain
*)yourDevice
)->registerInterestedDriver((IOService
*) us
);
394 IOReturn
AppleCuda::powerStateWillChangeTo ( IOPMPowerFlags theFlags
, unsigned long unused1
,
397 if ( ! (theFlags
& IOPMPowerOn
) )
399 _cuda_power_state
= 0; //0 means sleeping
401 return IOPMAckImplied
;
404 IOReturn
AppleCuda::powerStateDidChangeTo ( IOPMPowerFlags theFlags
, unsigned long unused1
,
407 if (theFlags
& IOPMPowerOn
)
409 _cuda_power_state
= 1; //1 means awake
410 _wakeup_from_sleep
= false; //normally it is false
412 return IOPMAckImplied
;
417 // *****************************************************************************
420 // Return the cuda's workloop.
422 // *****************************************************************************
423 IOWorkLoop
*AppleCuda::getWorkLoop() const
428 // *****************************************************************************
431 // Release everything we may have allocated.
433 // *****************************************************************************
434 void AppleCuda::free ( void )
442 if ( ourADBinterface
) {
443 ourADBinterface
->release();
447 _rootDomain
->deRegisterInterestedDriver((IOService
*) this);
454 // **********************************************************************************
455 // registerForADBInterrupts
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 // **********************************************************************************
461 void AppleCuda::registerForADBInterrupts ( ADB_callback_func handler
, IOService
* caller
)
463 autopoll_handler
= handler
;
468 // **********************************************************************************
471 // **********************************************************************************
472 static void autopollArrived ( OSObject
* CudaDriver
, IOInterruptEventSource
*, int )
474 ((AppleCuda
*)CudaDriver
)->serviceAutopolls();
477 #define RB_BOOT 1 /* Causes reboot, not halt. Is in xnu/bsd/sys/reboot.h */
479 void boot(int paniced
, int howto
, char * command
);
483 static void cuda_async_set_power_message_enable( thread_call_param_t param
, thread_call_param_t
)
485 //AppleCuda * me = (AppleCuda *) param;
487 set_cuda_power_message(kADB_powermsg_enable
);
490 static void cuda_async_set_file_server_mode( thread_call_param_t param
, thread_call_param_t
)
492 set_cuda_file_server_mode(1);
495 // **********************************************************************************
497 // We get here just before calling autopollHandler() in IOADBController.cpp
498 // **********************************************************************************
499 void AppleCuda::serviceAutopolls ( void )
501 cuda_packet_t
* response
;
503 while( inIndex
!= outIndex
) {
504 response
= &cuda_unsolicited
[ outIndex
];
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
)
510 unsigned char flag
, cmd
;
512 flag
= response
->a_header
[1];
513 cmd
= response
->a_header
[2];
515 if ((flag
== kADB_powermsg_flag_chassis
)
516 && (cmd
== kADB_powermsg_cmd_chassis_off
))
518 thread_call_func(cuda_async_set_power_message_enable
,
519 (thread_call_param_t
)this, true);
523 if (_cuda_power_state
)
525 //Put system to sleep now
526 _rootDomain
->receivePowerNotification (kIOPMSleepNow
);
528 else //If asleep, wake up the system
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);
537 else if ((flag
== kADB_powermsg_flag_keyboardpwr
)
538 && (cmd
== kADB_powermsg_cmd_keyboardoff
))
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);
547 if ( ADBid
!= NULL
) {
548 (*autopoll_handler
)(ADBid
,response
->a_header
[2],response
->a_bcount
,response
->a_buffer
);
551 outIndex
= (outIndex
+ 1) & (NUM_AP_BUFFERS
- 1);
553 } //end of while loop
558 // **********************************************************************************
561 // **********************************************************************************
562 IOReturn
AppleCuda::doSyncRequest ( cuda_request_t
* request
)
564 return(cuda_do_sync_request(this, request
, false));
568 IOReturn
AppleCuda::callPlatformFunction(const OSSymbol
*functionName
,
569 bool waitForFunction
,
570 void *param1
, void *param2
,
571 void *param3
, void *param4
)
573 if (functionName
== cuda_check_any_interrupt
)
577 hasint
= (bool *)param1
;
580 if (inIndex
!= outIndex
)
585 if (_wakeup_from_sleep
)
589 return kIOReturnSuccess
;
592 return kIOReturnBadArgument
;
597 AppleCuda::setWakeTime(UInt32 waketime
)
599 //Call this function with waketime=0 in order to allow normal sleep again
600 _wakeup_from_sleep
= false;
602 timerSrc
= IOTimerEventSource::timerEventSource((OSObject
*)this, WakeupTimeoutHandler
);
604 if (!timerSrc
|| (workLoop
->addEventSource(timerSrc
) != kIOReturnSuccess
))
606 IOLog("Cuda can not register timeout event\n");
610 timerSrc
->setTimeoutMS(waketime
);
615 AppleCuda::WakeupTimeoutHandler(OSObject
*object
, IOTimerEventSource
*timer
)
617 gCuda
->_wakeup_from_sleep
= true;
618 if (gCuda
->_rootDomain
)
620 gCuda
->_rootDomain
->activityTickle(0,0);
626 AppleCuda::setPowerOnTime(UInt32 newTime
)
631 Cuda_PE_read_write_time_of_day(kPEReadTOD
, &long_secs
);
632 set_cuda_poweruptime((long)newTime
+ long_secs
);
637 AppleCuda::setFileServerMode(bool fileServerModeON
)
639 set_cuda_file_server_mode((int) fileServerModeON
);
642 void AppleCuda::demandSleepNow(void)
646 _rootDomain
->receivePowerNotification (kIOPMSleepNow
);
650 // --------------------------------------------------------------------------
652 // Method: newUserClient
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..
659 #define kAppleCudaUserClientMagicCookie 0x0C00DA
662 AppleCuda::newUserClient(task_t owningTask
,
665 IOUserClient
**handler
)
667 IOReturn ioReturn
= kIOReturnSuccess
;
668 AppleCudaUserClient
*client
= NULL
;
670 IOLog("AppleCuda::newUserClient\n");
672 if (IOUserClient::clientHasPrivilege(securityToken
, "root") != kIOReturnSuccess
) {
673 IOLog("AppleCuda::newUserClient: Can't create user client, not privileged\n");
674 return kIOReturnNotPrivileged
;
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
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");
694 ioReturn
= kIOReturnInvalid
;
695 IOLog("AppleCuda::newUserClient: bad magic cookie.\n");
698 if (ioReturn
== kIOReturnSuccess
) {
699 // Attach ourself to the client so that this client instance
701 if (client
->attach(this) == false) {
702 ioReturn
= kIOReturnError
;
703 IOLog("AppleCuda::newUserClient: Can't attach user client\n");
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");
715 if (ioReturn
!= kIOReturnSuccess
&& client
!= NULL
) {
716 client
->detach(this);
724 // **********************************************************************************
725 // cuda_do_sync_request
727 // **********************************************************************************
728 IOReturn
cuda_do_sync_request ( AppleCuda
* self
, cuda_request_t
* request
, bool polled
)
730 bool wasPolled
= false;
731 IOInterruptState ints
;
734 request
->sync
= IOSyncer::create();
735 request
->needWake
= true;
738 ints
= IOSimpleLockLockDisableInterrupt(self
->cuda_request_lock
);
741 wasPolled
= self
->cuda_polled_mode
;
742 self
->cuda_polled_mode
= polled
;
745 if( self
->cuda_last_request
)
746 self
->cuda_last_request
->a_next
= request
;
748 self
->cuda_request
= request
;
750 self
->cuda_last_request
= request
;
752 if( self
->cuda_interrupt_state
== CUDA_STATE_IDLE
)
753 cuda_send_request(self
);
757 self
->cuda_polled_mode
= wasPolled
;
758 assert( 0 == self
->cuda_request
);
759 assert( 0 == self
->cuda_last_request
);
762 IOSimpleLockUnlockEnableInterrupt(self
->cuda_request_lock
, ints
);
765 request
->sync
->wait();
767 return cuda_get_result(request
);
771 // **********************************************************************************
772 // Cuda_PE_read_write_time_of_day
774 // **********************************************************************************
775 static int Cuda_PE_read_write_time_of_day ( unsigned int options
, long * secs
)
779 adb_init_request(&cmd
);
781 cmd
.a_cmd
.a_hcount
= 2;
782 cmd
.a_cmd
.a_header
[0] = ADB_PACKET_PSEUDO
;
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
);
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
);
802 return cuda_do_sync_request(gCuda
, &cmd
, true);
806 // **********************************************************************************
807 // Cuda_PE_halt_restart
809 // **********************************************************************************
810 static int Cuda_PE_halt_restart ( unsigned int type
)
814 adb_init_request(&cmd
);
816 cmd
.a_cmd
.a_hcount
= 2;
817 cmd
.a_cmd
.a_header
[0] = ADB_PACKET_PSEUDO
;
822 cmd
.a_cmd
.a_header
[1] = ADB_PSEUDOCMD_RESTART_SYSTEM
;
826 cmd
.a_cmd
.a_header
[1] = ADB_PSEUDOCMD_POWER_DOWN
;
833 return cuda_do_sync_request(gCuda
, &cmd
, true);
836 // **********************************************************************************
837 // Set the power-on time. 2001
838 // **********************************************************************************
839 static int set_cuda_poweruptime (long secs
)
842 long localsecs
= secs
;
844 adb_init_request(&cmd
);
846 cmd
.a_cmd
.a_hcount
= 2;
847 cmd
.a_cmd
.a_header
[0] = ADB_PACKET_PSEUDO
;
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;
853 return cuda_do_sync_request(gCuda
, &cmd
, true);
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
861 // **********************************************************************************
862 static int set_cuda_file_server_mode ( int command
)
866 adb_init_request(&cmd
);
868 cmd
.a_cmd
.a_hcount
= 3;
869 cmd
.a_cmd
.a_header
[0] = ADB_PACKET_PSEUDO
;
870 cmd
.a_cmd
.a_header
[1] = ADB_PSEUDOCMD_FILE_SERVER_FLAG
;
871 cmd
.a_cmd
.a_header
[2] = command
;
873 return cuda_do_sync_request(gCuda
, &cmd
, true);
876 // **********************************************************************************
877 // Fix front panel power key (mostly on Yosemites) so that one press won't power
878 // down the entire machine
880 // **********************************************************************************
881 static int set_cuda_power_message ( int command
)
885 if (command
>= kADB_powermsg_invalid
)
886 return 0; //invalid Cuda power request
888 adb_init_request(&cmd
);
890 cmd
.a_cmd
.a_hcount
= 3;
891 cmd
.a_cmd
.a_header
[0] = ADB_PACKET_PSEUDO
;
892 cmd
.a_cmd
.a_header
[1] = ADB_PSEUDOCMD_SET_POWER_MESSAGES
;
893 cmd
.a_cmd
.a_header
[2] = command
;
895 return cuda_do_sync_request(gCuda
, &cmd
, true);
899 // **********************************************************************************
902 // **********************************************************************************
903 static int Cuda_PE_write_IIC ( unsigned char addr
, unsigned char reg
, unsigned char data
)
907 adb_init_request(&cmd
);
909 cmd
.a_cmd
.a_header
[0] = ADB_PACKET_PSEUDO
;
910 cmd
.a_cmd
.a_header
[1] = ADB_PSEUDOCMD_GET_SET_IIC
;
911 cmd
.a_cmd
.a_header
[2] = addr
;
912 cmd
.a_cmd
.a_header
[3] = reg
;
913 cmd
.a_cmd
.a_header
[4] = data
;
914 cmd
.a_cmd
.a_hcount
= 5;
916 return cuda_do_sync_request(gCuda
, &cmd
, true);
920 AppleCudaWriteIIC( UInt8 address
, const UInt8
* buffer
, IOByteCount
* count
)
926 return( kIOReturnUnsupported
);
928 adb_init_request(&cmd
);
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
;
937 ret
= cuda_do_sync_request(gCuda
, &cmd
, true);
939 *count
= cmd
.a_cmd
.a_bcount
;
945 AppleCudaReadIIC( UInt8 address
, UInt8
* buffer
, IOByteCount
* count
)
951 return( kIOReturnUnsupported
);
953 adb_init_request(&cmd
);
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
;
962 ret
= cuda_do_sync_request(gCuda
, &cmd
, true);
963 *count
= cmd
.a_reply
.a_bcount
;
969 // **********************************************************************************
970 // Cuda_PE_poll_input
972 // **********************************************************************************
973 static int Cuda_PE_poll_input ( unsigned int, char * c
)
975 AppleCuda
* self
= gCuda
;
978 cuda_packet_t
* response
; //0123456789abcdef
979 static char keycodes2ascii
[] = "asdfhgzxcv_bqwer" //00
980 "yt123465=97-80]o" //10
981 "u[ip\nlj'k;_,/nm." //20
990 self
->cuda_polled_mode
= true;
991 interruptflag
= *self
->cuda_via_regs
.interruptFlag
& kCudaInterruptMask
;
993 if( interruptflag
) {
994 cuda_interrupt(self
);
997 if( 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
];
1006 self
->outIndex
= self
->inIndex
;
1009 self
->cuda_polled_mode
= false;
1019 // **********************************************************************************
1020 // cuda_send_request
1022 // **********************************************************************************
1023 static void cuda_send_request ( AppleCuda
* self
)
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.
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.
1034 if( !cuda_is_transfer_in_progress(self
) ) {
1035 // Set the shift register direction to output to Cuda by setting
1036 // the direction bit.
1038 cuda_set_data_direction_to_output(self
);
1040 // Write the first byte to the shift register
1041 cuda_write_data(self
, self
->cuda_request
->a_cmd
.a_header
[0]);
1043 // Set up the transfer state info here.
1045 self
->cuda_is_header_transfer
= true;
1046 self
->cuda_transfer_count
= 1;
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
);
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.
1056 self
->cuda_interrupt_state
= CUDA_STATE_TRANSMIT_EXPECTED
;
1057 self
->cuda_transaction_state
= CUDA_TS_SYNC_RESPONSE
;
1062 IOLog("Req = %x, state = %x, TIP = %x\n", self
->cuda_request
,
1063 self
->cuda_interrupt_state
, cuda_is_transfer_in_progress(self
));
1069 // **********************************************************************************
1072 // **********************************************************************************
1073 static void cuda_poll( AppleCuda
* self
)
1076 cuda_wait_for_interrupt(self
);
1077 cuda_interrupt(self
);
1078 } while( self
->cuda_interrupt_state
!= CUDA_STATE_IDLE
);
1082 // cuda_process_response
1083 // Execute at secondary interrupt.
1087 // **********************************************************************************
1088 // cuda_process_response
1090 // **********************************************************************************
1091 static void cuda_process_response ( AppleCuda
* self
)
1093 volatile cuda_request_t
* request
;
1094 unsigned int newIndex
;
1096 // Almost ready for the next state, which should be a Idle state.
1097 // Just need to notifiy the client.
1099 if ( self
->cuda_transaction_state
== CUDA_TS_SYNC_RESPONSE
) {
1103 request
= self
->cuda_request
;
1104 if( NULL
== (self
->cuda_request
= request
->a_next
) ) {
1105 self
->cuda_last_request
= NULL
;
1109 // wake the sync request thread
1110 if ( ((cuda_request_t
*)request
)->needWake
) {
1111 ((cuda_request_t
*)request
)->sync
->signal();
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
;
1122 // drop this packet, and reuse the buffer
1124 if ( !self
->cuda_polled_mode
) {
1125 // wake thread to service autopolls
1126 self
->eventSrc
->interruptOccurred(0, 0, 0);
1134 // **********************************************************************************
1137 // **********************************************************************************
1138 static void cuda_interrupt ( AppleCuda
* self
)
1140 unsigned char interruptState
;
1142 // Get the relevant signal in determining the cause of the interrupt:
1143 // the shift direction, the transfer request line and the transfer
1146 interruptState
= cuda_get_interrupt_state(self
);
1148 //kprintf("%02x",interruptState);
1150 switch ( interruptState
) {
1151 case kCudaReceiveByte
:
1152 cuda_receive_data(self
);
1155 case kCudaReceiveLastByte
:
1156 cuda_receive_last_byte(self
);
1159 case kCudaTransmitByte
:
1160 cuda_transmit_data(self
);
1163 case kCudaUnexpectedAttention
:
1164 cuda_unexpected_attention(self
);
1167 case kCudaExpectedAttention
:
1168 cuda_expected_attention(self
);
1171 case kCudaIdleState
:
1175 case kCudaCollision
:
1176 cuda_collision(self
);
1179 // Unknown interrupt, clear it and leave.
1188 // Executes at hardware interrupt level.
1191 // **********************************************************************************
1192 // cuda_transmit_data
1194 // **********************************************************************************
1195 static void cuda_transmit_data ( AppleCuda
* self
)
1197 // Clear the pending interrupt by reading the shift register.
1199 if ( 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
++]);
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;
1209 cuda_toggle_byte_ack( self
);
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
);
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.
1224 cuda_neg_tip_and_byteack(self
);
1226 // The next interrupt should be a expected attention interrupt.
1228 self
->cuda_interrupt_state
= CUDA_STATE_ATTN_EXPECTED
;
1234 // cuda_expected_attention
1235 // Executes at hardware interrupt level.
1239 // **********************************************************************************
1240 // cuda_expected_attention
1242 // **********************************************************************************
1243 static void cuda_expected_attention ( AppleCuda
* self
)
1245 // Clear the pending interrupt by reading the shift register.
1247 (void)cuda_read_data(self
);
1249 // Allow the VIA to settle directions.. else the possibility of
1251 cuda_do_state_transition_delay(self
);
1253 if ( self
->cuda_transaction_state
== CUDA_TS_SYNC_RESPONSE
) {
1254 self
->cuda_current_response
= (cuda_packet_t
*)&self
->cuda_request
->a_reply
;
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
;
1262 self
->cuda_is_header_transfer
= true;
1263 self
->cuda_is_packet_type
= true;
1264 self
->cuda_transfer_count
= 0;
1266 // Set the shift register direction to input.
1267 cuda_set_data_direction_to_input(self
);
1269 // Start the response packet transaction.
1270 cuda_assert_transfer_in_progress(self
);
1272 // The next interrupt should be a receive data interrupt.
1273 self
->cuda_interrupt_state
= CUDA_STATE_RECEIVE_EXPECTED
;
1277 // cuda_unexpected_attention
1278 // Executes at hardware interrupt level.
1282 // **********************************************************************************
1283 // cuda_expected_attention
1285 // **********************************************************************************
1286 static void cuda_unexpected_attention ( AppleCuda
* self
)
1288 // Clear the pending interrupt by reading the shift register.
1289 (void)cuda_read_data(self
);
1291 // Get ready for a unsolicited response.
1292 self
->cuda_current_response
= &self
->cuda_unsolicited
[ self
->inIndex
];
1293 self
->cuda_current_response
->a_hcount
= 0;
1294 self
->cuda_current_response
->a_bcount
= MAX_AP_RESPONSE
;
1296 self
->cuda_is_header_transfer
= TRUE
;
1297 self
->cuda_is_packet_type
= TRUE
;
1298 self
->cuda_transfer_count
= 0;
1300 // Start the response packet transaction, Transaction In Progress
1301 cuda_assert_transfer_in_progress(self
);
1303 // The next interrupt should be a receive data interrupt and the next
1304 // response should be an async response.
1306 self
->cuda_interrupt_state
= CUDA_STATE_RECEIVE_EXPECTED
;
1308 self
->cuda_transaction_state
= CUDA_TS_ASYNC_RESPONSE
;
1312 // cuda_receive_data
1313 // Executes at hardware interrupt level.
1317 // **********************************************************************************
1318 // cuda_receive_data
1320 // **********************************************************************************
1321 static void cuda_receive_data ( AppleCuda
* self
)
1323 if ( self
->cuda_is_packet_type
) {
1324 unsigned char packetType
;
1326 packetType
= cuda_read_data( self
);
1327 self
->cuda_current_response
->a_header
[self
->cuda_transfer_count
++] = packetType
;
1329 if ( packetType
== ADB_PACKET_ERROR
) {
1330 self
->cuda_current_response
->a_hcount
= 4;
1333 self
->cuda_current_response
->a_hcount
= 3;
1336 self
->cuda_is_packet_type
= false;
1338 cuda_toggle_byte_ack(self
);
1344 if ( self
->cuda_is_header_transfer
) {
1346 self
->cuda_current_response
->a_header
[self
->cuda_transfer_count
++] =
1347 cuda_read_data(self
);
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;
1354 cuda_toggle_byte_ack(self
);
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.
1361 *(self
->cuda_current_response
->a_buffer
+ self
->cuda_transfer_count
++) =
1362 cuda_read_data(self
);
1363 cuda_toggle_byte_ack(self
);
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.
1371 self
->cuda_current_response
->a_bcount
= self
->cuda_transfer_count
;
1373 cuda_read_data(self
);
1375 cuda_process_response(self
);
1376 cuda_neg_tip_and_byteack(self
);
1384 // cuda_receive_last_byte
1385 // Executes at hardware interrupt level.
1389 // **********************************************************************************
1390 // cuda_receive_last_byte
1392 // **********************************************************************************
1393 static void cuda_receive_last_byte ( AppleCuda
* self
)
1396 if ( self
->cuda_is_header_transfer
) {
1397 self
->cuda_current_response
->a_header
[self
->cuda_transfer_count
++] =
1398 cuda_read_data(self
);
1400 self
->cuda_transfer_count
= 0;
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
);
1408 /* Overrun -- ignore data */
1409 (void) cuda_read_data(self
);
1412 self
->cuda_current_response
->a_bcount
= self
->cuda_transfer_count
;
1413 // acknowledge before response so polled mode can work
1414 // from inside the handler
1415 cuda_neg_tip_and_byteack(self
);
1416 cuda_process_response(self
);
1422 // Executes at hardware interrupt level.
1426 // **********************************************************************************
1429 // **********************************************************************************
1430 static void cuda_collision ( AppleCuda
* self
)
1432 // Clear the pending interrupt by reading the shift register.
1433 (void)cuda_read_data(self
);
1435 // Negate TIP to abort the send. Cuda should send a second attention
1436 // interrupt to acknowledge the abort cycle.
1437 cuda_neg_transfer_in_progress(self
);
1439 // The next interrupt should be an expected attention and the next
1440 // response packet should be an async response.
1442 self
->cuda_interrupt_state
= CUDA_STATE_ATTN_EXPECTED
;
1443 self
->cuda_transaction_state
= CUDA_TS_ASYNC_RESPONSE
;
1445 /* queue the request */
1446 self
->cuda_is_header_transfer
= false;
1447 self
->cuda_transfer_count
= 0;
1453 // Executes at hardware interrupt level.
1457 // **********************************************************************************
1460 // **********************************************************************************
1461 static void cuda_idle ( AppleCuda
* self
)
1464 // Clear the pending interrupt by reading the shift register.
1465 (void)cuda_read_data(self
);
1468 // Set to the idle state.
1469 self
->cuda_interrupt_state
= CUDA_STATE_IDLE
;
1470 // See if there are any pending requests.
1471 if( self
->cuda_request
) {
1472 cuda_send_request(self
);
1478 // **********************************************************************************
1481 // **********************************************************************************
1482 static void cuda_error ( AppleCuda
* self
)
1484 //printf("{Error %d}", self->cuda_transaction_state);
1486 // Was looking at cuda_transaction_state - doesn't seem right
1488 switch ( self
->cuda_interrupt_state
) {
1489 case CUDA_STATE_IDLE
:
1490 cuda_neg_tip_and_byteack(self
);
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");
1501 self
->cuda_interrupt_state
= CUDA_STATE_ATTN_EXPECTED
;
1502 cuda_neg_tip_and_byteack(self
);
1506 case CUDA_STATE_ATTN_EXPECTED
:
1507 cuda_assert_transfer_in_progress(self
);
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");
1515 case CUDA_STATE_RECEIVE_EXPECTED
:
1516 cuda_neg_tip_and_byteack(self
);
1517 panic("Cuda - todo check for transaction type and error");
1521 cuda_set_data_direction_to_input(self
);
1522 cuda_neg_tip_and_byteack(self
);
1527 static void cuda_do_state_transition_delay( AppleCuda
* self
)
1529 AbsoluteTime deadline
;
1531 clock_absolutetime_interval_to_deadline(
1532 self
->cuda_state_transition_delay
, &deadline
);
1533 clock_delay_until(deadline
);