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 "IOCudaADBController.h"
83 #include <IOKit/IOLib.h>
84 #include <IOKit/IOSyncer.h>
85 #include <IOKit/IOWorkLoop.h>
86 #include <IOKit/IOInterruptEventSource.h>
87 #include <IOKit/IODeviceMemory.h>
88 #include <IOKit/IOPlatformExpert.h>
89 #include <IOKit/pwr_mgt/IOPM.h>
91 #include <IOKit/assert.h>
93 #define super IOService
94 OSDefineMetaClassAndStructors(AppleCuda
,IOService
)
96 static void cuda_interrupt ( AppleCuda
* self
);
98 static void cuda_process_response(AppleCuda
* self
);
99 static void cuda_transmit_data(AppleCuda
* self
);
100 static void cuda_expected_attention(AppleCuda
* self
);
101 static void cuda_unexpected_attention(AppleCuda
* self
);
102 static void cuda_receive_data(AppleCuda
* self
);
103 static void cuda_receive_last_byte(AppleCuda
* self
);
104 static void cuda_collision(AppleCuda
* self
);
105 static void cuda_idle(AppleCuda
* self
);
107 static void cuda_poll(AppleCuda
* self
);
108 static void cuda_error(AppleCuda
* self
);
109 static void cuda_send_request(AppleCuda
* self
);
110 static IOReturn
cuda_do_sync_request( AppleCuda
* self
,
111 cuda_request_t
* request
, bool polled
);
112 static void cuda_do_state_transition_delay(AppleCuda
* self
);
114 static int Cuda_PE_poll_input(unsigned int options
, char * c
);
115 static int Cuda_PE_read_write_time_of_day(unsigned int options
, long * secs
);
116 static int Cuda_PE_halt_restart(unsigned int type
);
117 static int Cuda_PE_write_IIC(unsigned char addr
, unsigned char reg
,
121 autopollArrived ( OSObject
*inCuda
, IOInterruptEventSource
*, int );
123 static int set_cuda_power_message ( int command
);
124 static int set_cuda_file_server_mode ( int command
);
125 static void cuda_async_set_power_message_enable( thread_call_param_t param
, thread_call_param_t
);
126 static void cuda_async_set_file_server_mode( thread_call_param_t param
, thread_call_param_t
) ;
128 bool CudahasRoot( OSObject
* us
, void *, IOService
* yourDevice
);
135 static __inline__
unsigned char cuda_read_data(AppleCuda
* self
)
137 volatile unsigned char val
;
139 val
= *self
->cuda_via_regs
.shift
; eieio();
143 static __inline__
int cuda_get_result(cuda_request_t
*request
)
145 int status
= ADB_RET_OK
;
146 int theStatus
= request
->a_reply
.a_header
[1];
148 if ( theStatus
& kCudaTimeOutMask
) {
149 status
= ADB_RET_TIMEOUT
;
151 // these are expected before autopoll mask is set
152 } else if ( theStatus
& kCudaSRQAssertMask
) {
153 status
= ADB_RET_UNEXPECTED_RESULT
;
155 } else if ( theStatus
& kCudaSRQErrorMask
) {
156 status
= ADB_RET_REQUEST_ERROR
;
157 } else if ( theStatus
& kCudaBusErrorMask
) {
158 status
= ADB_RET_BUS_ERROR
;
164 static __inline__
void cuda_lock(AppleCuda
* self
)
166 if( !self
->cuda_polled_mode
)
167 IOSimpleLockLock(self
->cuda_request_lock
);
170 static __inline__
void cuda_unlock(AppleCuda
* self
)
172 if( !self
->cuda_polled_mode
)
173 IOSimpleLockUnlock(self
->cuda_request_lock
);
181 static AppleCuda
* gCuda
;
182 // **********************************************************************************
185 // **********************************************************************************
186 bool AppleCuda::init ( OSDictionary
* properties
= 0 )
188 return super::init(properties
);
192 // **********************************************************************************
195 // **********************************************************************************
196 bool AppleCuda::start ( IOService
* nub
)
199 IOMemoryMap
* viaMap
;
200 unsigned char * cuda_base
;
202 if( !super::start(nub
))
206 // callPlatformFunction symbols
207 cuda_check_any_interrupt
= OSSymbol::withCString("cuda_check_any_interrupt");
211 ourADBinterface
= NULL
;
214 workLoop
= IOWorkLoop::workLoop();
216 kprintf("Start is bailing\n");
220 eventSrc
= IOInterruptEventSource::interruptEventSource(this, autopollArrived
);
222 kIOReturnSuccess
!= workLoop
->addEventSource(eventSrc
) ) {
223 kprintf("Start is bailing\n");
227 if( 0 == (viaMap
= nub
->mapDeviceMemoryWithIndex( 0 )) ) {
228 IOLog("%s: no via memory\n", getName());
229 kprintf("Start is bailing\n");
232 cuda_base
= (unsigned char *)viaMap
->getVirtualAddress();
234 kprintf("VIA base = %08x\n", (UInt32
)cuda_base
);
235 ourADBinterface
= new IOCudaADBController
;
236 if ( !ourADBinterface
) {
237 kprintf("Start is bailing\n");
240 if ( !ourADBinterface
->init(0,this) ) {
241 kprintf("Start is bailing\n");
245 if ( !ourADBinterface
->attach( this) ) {
246 kprintf("Start is bailing\n");
250 cuda_request_lock
= IOSimpleLockAlloc();
251 IOSimpleLockInit(cuda_request_lock
);
253 cuda_via_regs
.dataB
= cuda_base
;
254 cuda_via_regs
.handshakeDataA
= cuda_base
+0x0200;
255 cuda_via_regs
.dataDirectionB
= cuda_base
+0x0400;
256 cuda_via_regs
.dataDirectionA
= cuda_base
+0x0600;
257 cuda_via_regs
.timer1CounterLow
= cuda_base
+0x0800;
258 cuda_via_regs
.timer1CounterHigh
= cuda_base
+0x0A00;
259 cuda_via_regs
.timer1LatchLow
= cuda_base
+0x0C00;
260 cuda_via_regs
.timer1LatchHigh
= cuda_base
+0x0E00;
261 cuda_via_regs
.timer2CounterLow
= cuda_base
+0x1000;
262 cuda_via_regs
.timer2CounterHigh
= cuda_base
+0x1200;
263 cuda_via_regs
.shift
= cuda_base
+0x1400;
264 cuda_via_regs
.auxillaryControl
= cuda_base
+0x1600;
265 cuda_via_regs
.peripheralControl
= cuda_base
+0x1800;
266 cuda_via_regs
.interruptFlag
= cuda_base
+0x1A00;
267 cuda_via_regs
.interruptEnable
= cuda_base
+0x1C00;
268 cuda_via_regs
.dataA
= cuda_base
+0x1E00;
270 // we require delays of this duration between certain state transitions
271 clock_interval_to_absolutetime_interval(200, 1, &cuda_state_transition_delay
);
273 // Set the direction of the cuda signals. ByteACk and TIP are output and
276 *cuda_via_regs
.dataDirectionB
|= (kCudaByteAcknowledgeMask
| kCudaTransferInProgressMask
);
277 *cuda_via_regs
.dataDirectionB
&= ~kCudaTransferRequestMask
;
279 // Set the clock control. Set to shift data in by external clock CB1.
281 *cuda_via_regs
.auxillaryControl
= (*cuda_via_regs
.auxillaryControl
| kCudaTransferMode
) &
284 // Clear any posible cuda interupt.
286 if ( *cuda_via_regs
.shift
);
288 // Initialize the internal data.
290 cuda_interrupt_state
= CUDA_STATE_IDLE
;
291 cuda_transaction_state
= CUDA_TS_NO_REQUEST
;
292 cuda_is_header_transfer
= false;
293 cuda_is_packet_type
= false;
294 cuda_transfer_count
= 0;
295 cuda_current_response
= NULL
;
296 for( i
= 0; i
< NUM_AP_BUFFERS
; i
++ ) {
297 cuda_unsolicited
[ i
].a_buffer
= cuda_autopoll_buffers
[ i
];
300 // Terminate transaction and set idle state
302 cuda_neg_tip_and_byteack(this);
304 // we want to delay 4 mS for ADB reset to complete
308 // Clear pending interrupt if any...
310 (void)cuda_read_data(this);
312 // Issue a Sync Transaction, ByteAck asserted while TIP is negated.
314 cuda_assert_byte_ack(this);
316 // Wait for the Sync acknowledgement, cuda to assert TREQ
318 cuda_wait_for_transfer_request_assert(this);
320 // Wait for the Sync acknowledgement interrupt.
322 cuda_wait_for_interrupt(this);
324 // Clear pending interrupt
326 (void)cuda_read_data(this);
328 // Terminate the sync cycle by Negating ByteAck
330 cuda_neg_byte_ack(this);
332 // Wait for the Sync termination acknowledgement, cuda negates TREQ.
334 cuda_wait_for_transfer_request_neg(this);
336 // Wait for the Sync termination acknowledgement interrupt.
338 cuda_wait_for_interrupt(this);
340 // Terminate transaction and set idle state, TIP negate and ByteAck negate.
341 cuda_neg_transfer_in_progress(this);
343 // Clear pending interrupt, if there is one...
344 (void)cuda_read_data(this);
347 cuda_polled_mode
= true;
349 #define VIA_DEV_CUDA 2
350 nub
->registerInterrupt(VIA_DEV_CUDA
,
351 this, (IOInterruptAction
) cuda_interrupt
);
352 nub
->enableInterrupt(VIA_DEV_CUDA
);
355 PE_poll_input
= Cuda_PE_poll_input
;
356 PE_read_write_time_of_day
= Cuda_PE_read_write_time_of_day
;
357 PE_halt_restart
= Cuda_PE_halt_restart
;
358 PE_write_IIC
= Cuda_PE_write_IIC
;
359 publishResource( "IOiic0", this );
360 publishResource( "IORTC", this );
363 //set_cuda_power_message(kADB_powermsg_enable); //won't work on beige G3
364 thread_call_func(cuda_async_set_power_message_enable
, (thread_call_param_t
)this, true);
365 thread_call_func(cuda_async_set_file_server_mode
, (thread_call_param_t
)this, true);
367 registerService(); //Gossamer needs to find this driver for waking up G3
369 _cuda_power_state
= 1; //default is wake state
370 //We want to know when sleep is about to occur
371 addNotification( gIOPublishNotification
,serviceMatching("IOPMrootDomain"),
372 (IOServiceNotificationHandler
)CudahasRoot
, this, 0 );
374 ourADBinterface
->start( this );
379 /* Here are some power management functions so we can tell when system is
381 bool CudahasRoot( OSObject
* us
, void *, IOService
* yourDevice
)
383 if (( yourDevice
!= NULL
) && ((AppleCuda
*)us
)->_rootDomain
== 0)
385 ((AppleCuda
*)us
)->_rootDomain
= (IOPMrootDomain
*) yourDevice
;
386 ((IOPMrootDomain
*)yourDevice
)->registerInterestedDriver((IOService
*) us
);
391 IOReturn
AppleCuda::powerStateWillChangeTo ( IOPMPowerFlags theFlags
, unsigned long unused1
,
394 //kprintf("will change to %x", theFlags);
395 if ( ! (theFlags
& IOPMPowerOn
) )
397 _cuda_power_state
= 0; //0 means sleeping
399 return IOPMAckImplied
;
402 IOReturn
AppleCuda::powerStateDidChangeTo ( IOPMPowerFlags theFlags
, unsigned long unused1
,
405 //kprintf("did change to %x", theFlags);
406 if (theFlags
& IOPMPowerOn
)
408 _cuda_power_state
= 1; //1 means awake
410 return IOPMAckImplied
;
415 // *****************************************************************************
418 // Return the cuda's workloop.
420 // *****************************************************************************
421 IOWorkLoop
*AppleCuda::getWorkLoop() const
426 // *****************************************************************************
429 // Release everything we may have allocated.
431 // *****************************************************************************
432 void AppleCuda::free ( void )
440 if ( ourADBinterface
) {
441 ourADBinterface
->release();
445 _rootDomain
->deRegisterInterestedDriver((IOService
*) this);
452 // **********************************************************************************
453 // registerForADBInterrupts
455 // Some driver is calling to say it is prepared to receive "unsolicited" adb
456 // interrupts (e.g. autopoll keyboard and trackpad data). The parameters identify
457 // who to call when we get one.
458 // **********************************************************************************
459 void AppleCuda::registerForADBInterrupts ( ADB_callback_func handler
, IOService
* caller
)
461 autopoll_handler
= handler
;
466 // **********************************************************************************
469 // **********************************************************************************
470 static void autopollArrived ( OSObject
* CudaDriver
, IOInterruptEventSource
*, int )
472 ((AppleCuda
*)CudaDriver
)->serviceAutopolls();
475 #define RB_BOOT 1 /* Causes reboot, not halt. Is in xnu/bsd/sys/reboot.h */
477 void boot(int paniced
, int howto
, char * command
);
481 static void cuda_async_set_power_message_enable( thread_call_param_t param
, thread_call_param_t
)
483 //AppleCuda * me = (AppleCuda *) param;
485 set_cuda_power_message(kADB_powermsg_enable
);
488 static void cuda_async_set_file_server_mode( thread_call_param_t param
, thread_call_param_t
)
490 set_cuda_file_server_mode(1);
493 // **********************************************************************************
495 // We get here just before calling autopollHandler() in IOADBController.cpp
496 // **********************************************************************************
497 void AppleCuda::serviceAutopolls ( void )
499 cuda_packet_t
* response
;
501 while( inIndex
!= outIndex
) {
503 response
= &cuda_unsolicited
[ outIndex
];
505 //Check for power messages, which are handled differently from regular
506 // autopoll data coming from mouse or keyboard.
507 if (response
->a_header
[0] == ADB_PACKET_POWER
)
509 unsigned char flag
, cmd
;
511 flag
= response
->a_header
[1];
512 cmd
= response
->a_header
[2];
514 if ((flag
== kADB_powermsg_flag_chassis
)
515 && (cmd
== kADB_powermsg_cmd_chassis_off
))
517 thread_call_func(cuda_async_set_power_message_enable
,
518 (thread_call_param_t
)this, true);
522 if (_cuda_power_state
)
524 //Put system to sleep now
525 _rootDomain
->receivePowerNotification (kIOPMSleepNow
);
527 else //If asleep, wake up the system
529 //Tickle activity timer in root domain. This will not
530 // wake up machine that is in demand-sleep, but it will
531 // wake up an inactive system that dozed
532 _rootDomain
->activityTickle(0,0);
536 else if ((flag
== kADB_powermsg_flag_keyboardpwr
)
537 && (cmd
== kADB_powermsg_cmd_keyboardoff
))
539 //set_cuda_power_message(kADB_powermsg_continue);
540 //This needs to by async so Beige G3 ADB won't lock up
541 thread_call_func(cuda_async_set_power_message_enable
,
542 (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
)
584 return kIOReturnSuccess
;
587 return kIOReturnBadArgument
;
591 // **********************************************************************************
592 // cuda_do_sync_request
594 // **********************************************************************************
595 IOReturn
cuda_do_sync_request ( AppleCuda
* self
, cuda_request_t
* request
, bool polled
)
597 bool wasPolled
= false;
598 IOInterruptState ints
;
601 request
->sync
= IOSyncer::create();
602 request
->needWake
= true;
605 ints
= IOSimpleLockLockDisableInterrupt(self
->cuda_request_lock
);
608 wasPolled
= self
->cuda_polled_mode
;
609 self
->cuda_polled_mode
= polled
;
612 if( self
->cuda_last_request
)
613 self
->cuda_last_request
->a_next
= request
;
615 self
->cuda_request
= request
;
617 self
->cuda_last_request
= request
;
619 if( self
->cuda_interrupt_state
== CUDA_STATE_IDLE
)
620 cuda_send_request(self
);
624 self
->cuda_polled_mode
= wasPolled
;
625 assert( 0 == self
->cuda_request
);
626 assert( 0 == self
->cuda_last_request
);
629 IOSimpleLockUnlockEnableInterrupt(self
->cuda_request_lock
, ints
);
632 request
->sync
->wait();
634 return cuda_get_result(request
);
638 // **********************************************************************************
639 // Cuda_PE_read_write_time_of_day
641 // **********************************************************************************
642 static int Cuda_PE_read_write_time_of_day ( unsigned int options
, long * secs
)
646 adb_init_request(&cmd
);
648 cmd
.a_cmd
.a_hcount
= 2;
649 cmd
.a_cmd
.a_header
[0] = ADB_PACKET_PSEUDO
;
654 cmd
.a_cmd
.a_header
[1] = ADB_PSEUDOCMD_GET_REAL_TIME
;
655 cmd
.a_reply
.a_buffer
= (UInt8
*)secs
;
656 cmd
.a_reply
.a_bcount
= sizeof(*secs
);
660 cmd
.a_cmd
.a_header
[1] = ADB_PSEUDOCMD_SET_REAL_TIME
;
661 cmd
.a_cmd
.a_buffer
= (UInt8
*)secs
;
662 cmd
.a_cmd
.a_bcount
= sizeof(*secs
);
669 return cuda_do_sync_request(gCuda
, &cmd
, true);
673 // **********************************************************************************
674 // Cuda_PE_halt_restart
676 // **********************************************************************************
677 static int Cuda_PE_halt_restart ( unsigned int type
)
681 adb_init_request(&cmd
);
683 cmd
.a_cmd
.a_hcount
= 2;
684 cmd
.a_cmd
.a_header
[0] = ADB_PACKET_PSEUDO
;
689 cmd
.a_cmd
.a_header
[1] = ADB_PSEUDOCMD_RESTART_SYSTEM
;
693 cmd
.a_cmd
.a_header
[1] = ADB_PSEUDOCMD_POWER_DOWN
;
700 return cuda_do_sync_request(gCuda
, &cmd
, true);
704 // **********************************************************************************
705 // In case this machine loses power, it will automatically reboot when power is
706 // restored. Only desktop machines have Cuda, so this feature will not affect
708 // **********************************************************************************
709 static int set_cuda_file_server_mode ( int command
)
713 adb_init_request(&cmd
);
715 cmd
.a_cmd
.a_hcount
= 3;
716 cmd
.a_cmd
.a_header
[0] = ADB_PACKET_PSEUDO
;
717 cmd
.a_cmd
.a_header
[1] = ADB_PSEUDOCMD_FILE_SERVER_FLAG
;
718 cmd
.a_cmd
.a_header
[2] = command
;
720 return cuda_do_sync_request(gCuda
, &cmd
, true);
723 // **********************************************************************************
724 // Fix front panel power key (mostly on Yosemites) so that one press won't power
725 // down the entire machine
727 // **********************************************************************************
728 static int set_cuda_power_message ( int command
)
732 if (command
>= kADB_powermsg_invalid
)
733 return 0; //invalid Cuda power request
735 adb_init_request(&cmd
);
737 cmd
.a_cmd
.a_hcount
= 3;
738 cmd
.a_cmd
.a_header
[0] = ADB_PACKET_PSEUDO
;
739 cmd
.a_cmd
.a_header
[1] = ADB_PSEUDOCMD_SET_POWER_MESSAGES
;
740 cmd
.a_cmd
.a_header
[2] = command
;
742 return cuda_do_sync_request(gCuda
, &cmd
, true);
746 // **********************************************************************************
749 // **********************************************************************************
750 static int Cuda_PE_write_IIC ( unsigned char addr
, unsigned char reg
, unsigned char data
)
754 adb_init_request(&cmd
);
756 cmd
.a_cmd
.a_header
[0] = ADB_PACKET_PSEUDO
;
757 cmd
.a_cmd
.a_header
[1] = ADB_PSEUDOCMD_GET_SET_IIC
;
758 cmd
.a_cmd
.a_header
[2] = addr
;
759 cmd
.a_cmd
.a_header
[3] = reg
;
760 cmd
.a_cmd
.a_header
[4] = data
;
761 cmd
.a_cmd
.a_hcount
= 5;
763 return cuda_do_sync_request(gCuda
, &cmd
, true);
767 AppleCudaWriteIIC( UInt8 address
, const UInt8
* buffer
, IOByteCount
* count
)
773 return( kIOReturnUnsupported
);
775 adb_init_request(&cmd
);
777 cmd
.a_cmd
.a_header
[0] = ADB_PACKET_PSEUDO
;
778 cmd
.a_cmd
.a_header
[1] = ADB_PSEUDOCMD_GET_SET_IIC
;
779 cmd
.a_cmd
.a_header
[2] = address
;
780 cmd
.a_cmd
.a_hcount
= 3;
781 cmd
.a_cmd
.a_buffer
= (UInt8
*) buffer
;
782 cmd
.a_cmd
.a_bcount
= *count
;
784 ret
= cuda_do_sync_request(gCuda
, &cmd
, true);
786 *count
= cmd
.a_cmd
.a_bcount
;
792 AppleCudaReadIIC( UInt8 address
, UInt8
* buffer
, IOByteCount
* count
)
798 return( kIOReturnUnsupported
);
800 adb_init_request(&cmd
);
802 cmd
.a_cmd
.a_header
[0] = ADB_PACKET_PSEUDO
;
803 cmd
.a_cmd
.a_header
[1] = ADB_PSEUDOCMD_GET_SET_IIC
;
804 cmd
.a_cmd
.a_header
[2] = address
;
805 cmd
.a_cmd
.a_hcount
= 3;
806 cmd
.a_reply
.a_buffer
= buffer
;
807 cmd
.a_reply
.a_bcount
= *count
;
809 ret
= cuda_do_sync_request(gCuda
, &cmd
, true);
810 *count
= cmd
.a_reply
.a_bcount
;
816 // **********************************************************************************
817 // Cuda_PE_poll_input
819 // **********************************************************************************
820 static int Cuda_PE_poll_input ( unsigned int, char * c
)
822 AppleCuda
* self
= gCuda
;
825 cuda_packet_t
* response
; //0123456789abcdef
826 static char keycodes2ascii
[] = "asdfhgzxcv_bqwer" //00
827 "yt123465=97-80]o" //10
828 "u[ip\nlj'k;_,/nm." //20
837 self
->cuda_polled_mode
= true;
838 interruptflag
= *self
->cuda_via_regs
.interruptFlag
& kCudaInterruptMask
;
840 if( interruptflag
) {
841 cuda_interrupt(self
);
844 if( self
->inIndex
!= self
->outIndex
) {
845 response
= &self
->cuda_unsolicited
[ self
->outIndex
];
846 if( ((response
->a_header
[2] >> 4) == 2)
847 && (response
->a_bcount
> 1) ) {
848 code
= response
->a_buffer
[0];
849 if( code
< sizeof(keycodes2ascii
) ) {
850 *c
= keycodes2ascii
[ code
];
853 self
->outIndex
= self
->inIndex
;
856 self
->cuda_polled_mode
= false;
866 // **********************************************************************************
869 // **********************************************************************************
870 static void cuda_send_request ( AppleCuda
* self
)
873 // The data register must written with the data byte 25uS
874 // after examining TREQ or we run the risk of getting out of sync
875 // with Cuda. So call with disabled interrupts and spinlock held.
877 // Check if we can commence with the packet transmission. First, check if
878 // Cuda can service our request now. Second, check if Cuda wants to send
879 // a response packet now.
881 if( !cuda_is_transfer_in_progress(self
) ) {
882 // Set the shift register direction to output to Cuda by setting
883 // the direction bit.
885 cuda_set_data_direction_to_output(self
);
887 // Write the first byte to the shift register
888 cuda_write_data(self
, self
->cuda_request
->a_cmd
.a_header
[0]);
890 // Set up the transfer state info here.
892 self
->cuda_is_header_transfer
= true;
893 self
->cuda_transfer_count
= 1;
895 // Make sure we're in idle state before transaction, and then
896 // assert TIP to tell Cuda we're starting command
897 cuda_neg_byte_ack(self
);
898 cuda_assert_transfer_in_progress(self
);
900 // The next state is going to be a transmit state, if there is
901 // no collision. This is a requested response but call it sync.
903 self
->cuda_interrupt_state
= CUDA_STATE_TRANSMIT_EXPECTED
;
904 self
->cuda_transaction_state
= CUDA_TS_SYNC_RESPONSE
;
909 IOLog("Req = %x, state = %x, TIP = %x\n", self
->cuda_request
,
910 self
->cuda_interrupt_state
, cuda_is_transfer_in_progress(self
));
916 // **********************************************************************************
919 // **********************************************************************************
920 static void cuda_poll( AppleCuda
* self
)
923 cuda_wait_for_interrupt(self
);
924 cuda_interrupt(self
);
925 } while( self
->cuda_interrupt_state
!= CUDA_STATE_IDLE
);
929 // cuda_process_response
930 // Execute at secondary interrupt.
934 // **********************************************************************************
935 // cuda_process_response
937 // **********************************************************************************
938 static void cuda_process_response ( AppleCuda
* self
)
940 volatile cuda_request_t
* request
;
941 unsigned int newIndex
;
943 // Almost ready for the next state, which should be a Idle state.
944 // Just need to notifiy the client.
946 if ( self
->cuda_transaction_state
== CUDA_TS_SYNC_RESPONSE
) {
950 request
= self
->cuda_request
;
951 if( NULL
== (self
->cuda_request
= request
->a_next
) ) {
952 self
->cuda_last_request
= NULL
;
956 // wake the sync request thread
957 if ( ((cuda_request_t
*)request
)->needWake
) {
958 ((cuda_request_t
*)request
)->sync
->signal();
963 if ( self
->cuda_transaction_state
== CUDA_TS_ASYNC_RESPONSE
) {
964 newIndex
= (self
->inIndex
+ 1) & (NUM_AP_BUFFERS
- 1);
965 if( newIndex
!= self
->outIndex
) {
966 self
->inIndex
= newIndex
;
969 // drop this packet, and reuse the buffer
971 if ( !self
->cuda_polled_mode
) {
972 // wake thread to service autopolls
973 self
->eventSrc
->interruptOccurred(0, 0, 0);
981 // **********************************************************************************
984 // **********************************************************************************
985 static void cuda_interrupt ( AppleCuda
* self
)
987 unsigned char interruptState
;
989 // Get the relevant signal in determining the cause of the interrupt:
990 // the shift direction, the transfer request line and the transfer
993 interruptState
= cuda_get_interrupt_state(self
);
995 //kprintf("%02x",interruptState);
997 switch ( interruptState
) {
998 case kCudaReceiveByte
:
999 cuda_receive_data(self
);
1002 case kCudaReceiveLastByte
:
1003 cuda_receive_last_byte(self
);
1006 case kCudaTransmitByte
:
1007 cuda_transmit_data(self
);
1010 case kCudaUnexpectedAttention
:
1011 cuda_unexpected_attention(self
);
1014 case kCudaExpectedAttention
:
1015 cuda_expected_attention(self
);
1018 case kCudaIdleState
:
1022 case kCudaCollision
:
1023 cuda_collision(self
);
1026 // Unknown interrupt, clear it and leave.
1035 // Executes at hardware interrupt level.
1038 // **********************************************************************************
1039 // cuda_transmit_data
1041 // **********************************************************************************
1042 static void cuda_transmit_data ( AppleCuda
* self
)
1044 // Clear the pending interrupt by reading the shift register.
1046 if ( self
->cuda_is_header_transfer
) {
1047 // There are more header bytes, write one out.
1048 cuda_write_data(self
, self
->cuda_request
->a_cmd
.a_header
[self
->cuda_transfer_count
++]);
1050 // Toggle the handshake line.
1051 if ( self
->cuda_transfer_count
>= self
->cuda_request
->a_cmd
.a_hcount
) {
1052 self
->cuda_is_header_transfer
= FALSE
;
1053 self
->cuda_transfer_count
= 0;
1056 cuda_toggle_byte_ack( self
);
1059 if ( self
->cuda_transfer_count
< self
->cuda_request
->a_cmd
.a_bcount
) {
1060 // There are more command bytes, write one out and update the pointer
1061 cuda_write_data( self
,
1062 *(self
->cuda_request
->a_cmd
.a_buffer
+ self
->cuda_transfer_count
++));
1063 // Toggle the handshake line.
1064 cuda_toggle_byte_ack(self
);
1067 (void)cuda_read_data(self
);
1068 // There is no more command bytes, terminate the send transaction.
1069 // Cuda should send a expected attention interrupt soon.
1071 cuda_neg_tip_and_byteack(self
);
1073 // The next interrupt should be a expected attention interrupt.
1075 self
->cuda_interrupt_state
= CUDA_STATE_ATTN_EXPECTED
;
1081 // cuda_expected_attention
1082 // Executes at hardware interrupt level.
1086 // **********************************************************************************
1087 // cuda_expected_attention
1089 // **********************************************************************************
1090 static void cuda_expected_attention ( AppleCuda
* self
)
1092 // Clear the pending interrupt by reading the shift register.
1094 (void)cuda_read_data(self
);
1096 // Allow the VIA to settle directions.. else the possibility of
1098 cuda_do_state_transition_delay(self
);
1100 if ( self
->cuda_transaction_state
== CUDA_TS_SYNC_RESPONSE
) {
1101 self
->cuda_current_response
= (cuda_packet_t
*)&self
->cuda_request
->a_reply
;
1104 self
->cuda_current_response
= &self
->cuda_unsolicited
[ self
->inIndex
];
1105 self
->cuda_current_response
->a_hcount
= 0;
1106 self
->cuda_current_response
->a_bcount
= MAX_AP_RESPONSE
;
1109 self
->cuda_is_header_transfer
= true;
1110 self
->cuda_is_packet_type
= true;
1111 self
->cuda_transfer_count
= 0;
1113 // Set the shift register direction to input.
1114 cuda_set_data_direction_to_input(self
);
1116 // Start the response packet transaction.
1117 cuda_assert_transfer_in_progress(self
);
1119 // The next interrupt should be a receive data interrupt.
1120 self
->cuda_interrupt_state
= CUDA_STATE_RECEIVE_EXPECTED
;
1124 // cuda_unexpected_attention
1125 // Executes at hardware interrupt level.
1129 // **********************************************************************************
1130 // cuda_expected_attention
1132 // **********************************************************************************
1133 static void cuda_unexpected_attention ( AppleCuda
* self
)
1135 // Clear the pending interrupt by reading the shift register.
1136 (void)cuda_read_data(self
);
1138 // Get ready for a unsolicited response.
1139 self
->cuda_current_response
= &self
->cuda_unsolicited
[ self
->inIndex
];
1140 self
->cuda_current_response
->a_hcount
= 0;
1141 self
->cuda_current_response
->a_bcount
= MAX_AP_RESPONSE
;
1143 self
->cuda_is_header_transfer
= TRUE
;
1144 self
->cuda_is_packet_type
= TRUE
;
1145 self
->cuda_transfer_count
= 0;
1147 // Start the response packet transaction, Transaction In Progress
1148 cuda_assert_transfer_in_progress(self
);
1150 // The next interrupt should be a receive data interrupt and the next
1151 // response should be an async response.
1153 self
->cuda_interrupt_state
= CUDA_STATE_RECEIVE_EXPECTED
;
1155 self
->cuda_transaction_state
= CUDA_TS_ASYNC_RESPONSE
;
1159 // cuda_receive_data
1160 // Executes at hardware interrupt level.
1164 // **********************************************************************************
1165 // cuda_receive_data
1167 // **********************************************************************************
1168 static void cuda_receive_data ( AppleCuda
* self
)
1170 if ( self
->cuda_is_packet_type
) {
1171 unsigned char packetType
;
1173 packetType
= cuda_read_data( self
);
1174 self
->cuda_current_response
->a_header
[self
->cuda_transfer_count
++] = packetType
;
1176 if ( packetType
== ADB_PACKET_ERROR
) {
1177 self
->cuda_current_response
->a_hcount
= 4;
1180 self
->cuda_current_response
->a_hcount
= 3;
1183 self
->cuda_is_packet_type
= false;
1185 cuda_toggle_byte_ack(self
);
1191 if ( self
->cuda_is_header_transfer
) {
1193 self
->cuda_current_response
->a_header
[self
->cuda_transfer_count
++] =
1194 cuda_read_data(self
);
1196 if (self
->cuda_transfer_count
>= self
->cuda_current_response
->a_hcount
) {
1197 self
->cuda_is_header_transfer
= FALSE
;
1198 self
->cuda_transfer_count
= 0;
1201 cuda_toggle_byte_ack(self
);
1204 if ( self
->cuda_transfer_count
< self
->cuda_current_response
->a_bcount
) {
1205 // Still room for more bytes. Get the byte and tell Cuda to continue.
1206 // Toggle the handshake line, ByteAck, to acknowledge receive.
1208 *(self
->cuda_current_response
->a_buffer
+ self
->cuda_transfer_count
++) =
1209 cuda_read_data(self
);
1210 cuda_toggle_byte_ack(self
);
1214 // Cuda is still sending data but the buffer is full.
1215 // Normally should not get here. The only exceptions are open ended
1216 // request such as PRAM read... In any event time to exit.
1218 self
->cuda_current_response
->a_bcount
= self
->cuda_transfer_count
;
1220 cuda_read_data(self
);
1222 cuda_process_response(self
);
1223 cuda_neg_tip_and_byteack(self
);
1231 // cuda_receive_last_byte
1232 // Executes at hardware interrupt level.
1236 // **********************************************************************************
1237 // cuda_receive_last_byte
1239 // **********************************************************************************
1240 static void cuda_receive_last_byte ( AppleCuda
* self
)
1243 if ( self
->cuda_is_header_transfer
) {
1244 self
->cuda_current_response
->a_header
[self
->cuda_transfer_count
++] =
1245 cuda_read_data(self
);
1247 self
->cuda_transfer_count
= 0;
1250 if ( self
->cuda_transfer_count
< self
->cuda_current_response
->a_bcount
) {
1251 *(self
->cuda_current_response
->a_buffer
+ self
->cuda_transfer_count
++) =
1252 cuda_read_data(self
);
1255 /* Overrun -- ignore data */
1256 (void) cuda_read_data(self
);
1259 self
->cuda_current_response
->a_bcount
= self
->cuda_transfer_count
;
1260 // acknowledge before response so polled mode can work
1261 // from inside the handler
1262 cuda_neg_tip_and_byteack(self
);
1263 cuda_process_response(self
);
1269 // Executes at hardware interrupt level.
1273 // **********************************************************************************
1276 // **********************************************************************************
1277 static void cuda_collision ( AppleCuda
* self
)
1279 // Clear the pending interrupt by reading the shift register.
1280 (void)cuda_read_data(self
);
1282 // Negate TIP to abort the send. Cuda should send a second attention
1283 // interrupt to acknowledge the abort cycle.
1284 cuda_neg_transfer_in_progress(self
);
1286 // The next interrupt should be an expected attention and the next
1287 // response packet should be an async response.
1289 self
->cuda_interrupt_state
= CUDA_STATE_ATTN_EXPECTED
;
1290 self
->cuda_transaction_state
= CUDA_TS_ASYNC_RESPONSE
;
1292 /* queue the request */
1293 self
->cuda_is_header_transfer
= false;
1294 self
->cuda_transfer_count
= 0;
1300 // Executes at hardware interrupt level.
1304 // **********************************************************************************
1307 // **********************************************************************************
1308 static void cuda_idle ( AppleCuda
* self
)
1311 // Clear the pending interrupt by reading the shift register.
1312 (void)cuda_read_data(self
);
1315 // Set to the idle state.
1316 self
->cuda_interrupt_state
= CUDA_STATE_IDLE
;
1317 // See if there are any pending requests.
1318 if( self
->cuda_request
) {
1319 cuda_send_request(self
);
1325 // **********************************************************************************
1328 // **********************************************************************************
1329 static void cuda_error ( AppleCuda
* self
)
1331 //printf("{Error %d}", self->cuda_transaction_state);
1333 // Was looking at cuda_transaction_state - doesn't seem right
1335 switch ( self
->cuda_interrupt_state
) {
1336 case CUDA_STATE_IDLE
:
1337 cuda_neg_tip_and_byteack(self
);
1340 case CUDA_STATE_TRANSMIT_EXPECTED
:
1341 if ( self
->cuda_is_header_transfer
&& self
->cuda_transfer_count
<= 1 ) {
1342 cuda_do_state_transition_delay(self
);
1343 cuda_neg_transfer_in_progress(self
);
1344 cuda_set_data_direction_to_input(self
);
1345 panic ("CUDA - TODO FORCE COMMAND BACK UP!\n");
1348 self
->cuda_interrupt_state
= CUDA_STATE_ATTN_EXPECTED
;
1349 cuda_neg_tip_and_byteack(self
);
1353 case CUDA_STATE_ATTN_EXPECTED
:
1354 cuda_assert_transfer_in_progress(self
);
1356 cuda_do_state_transition_delay(self
);
1357 cuda_set_data_direction_to_input(self
);
1358 cuda_neg_transfer_in_progress(self
);
1359 panic("CUDA - TODO CHECK FOR TRANSACTION TYPE AND ERROR");
1362 case CUDA_STATE_RECEIVE_EXPECTED
:
1363 cuda_neg_tip_and_byteack(self
);
1364 panic("Cuda - todo check for transaction type and error");
1368 cuda_set_data_direction_to_input(self
);
1369 cuda_neg_tip_and_byteack(self
);
1374 static void cuda_do_state_transition_delay( AppleCuda
* self
)
1376 AbsoluteTime deadline
;
1378 clock_absolutetime_interval_to_deadline(
1379 self
->cuda_state_transition_delay
, &deadline
);
1380 clock_delay_until(deadline
);