]> git.saurik.com Git - apple/xnu.git/blame - iokit/Drivers/platform/drvAppleCuda/AppleCuda.cpp
xnu-124.13.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"
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>
90
91#include <IOKit/assert.h>
92
93#define super IOService
94OSDefineMetaClassAndStructors(AppleCuda,IOService)
95
96static void cuda_interrupt ( AppleCuda * self );
97
98static void cuda_process_response(AppleCuda * self);
99static void cuda_transmit_data(AppleCuda * self);
100static void cuda_expected_attention(AppleCuda * self);
101static void cuda_unexpected_attention(AppleCuda * self);
102static void cuda_receive_data(AppleCuda * self);
103static void cuda_receive_last_byte(AppleCuda * self);
104static void cuda_collision(AppleCuda * self);
105static void cuda_idle(AppleCuda * self);
106
107static void cuda_poll(AppleCuda * self);
108static void cuda_error(AppleCuda * self);
109static void cuda_send_request(AppleCuda * self);
110static IOReturn cuda_do_sync_request( AppleCuda * self,
111 cuda_request_t * request, bool polled);
112static void cuda_do_state_transition_delay(AppleCuda * self);
113
114static int Cuda_PE_poll_input(unsigned int options, char * c);
115static int Cuda_PE_read_write_time_of_day(unsigned int options, long * secs);
116static int Cuda_PE_halt_restart(unsigned int type);
117static int Cuda_PE_write_IIC(unsigned char addr, unsigned char reg,
118 unsigned char data);
119
120static void
121autopollArrived ( OSObject *inCuda, IOInterruptEventSource *, int );
122
123static int set_cuda_power_message ( int command );
124static int set_cuda_file_server_mode ( int command );
125static void cuda_async_set_power_message_enable( thread_call_param_t param, thread_call_param_t );
126static void cuda_async_set_file_server_mode( thread_call_param_t param, thread_call_param_t ) ;
127
128bool CudahasRoot( OSObject * us, void *, IOService * yourDevice );
129
130
131//
132// inline functions
133//
134
135static __inline__ unsigned char cuda_read_data(AppleCuda * self)
136{
137 volatile unsigned char val;
138
139 val = *self->cuda_via_regs.shift; eieio();
140 return val;
141}
142
143static __inline__ int cuda_get_result(cuda_request_t *request)
144{
145 int status = ADB_RET_OK;
146 int theStatus = request->a_reply.a_header[1];
147
148 if ( theStatus & kCudaTimeOutMask ) {
149 status = ADB_RET_TIMEOUT;
150#if 0
151 // these are expected before autopoll mask is set
152 } else if ( theStatus & kCudaSRQAssertMask ) {
153 status = ADB_RET_UNEXPECTED_RESULT;
154#endif
155 } else if ( theStatus & kCudaSRQErrorMask ) {
156 status = ADB_RET_REQUEST_ERROR;
157 } else if ( theStatus & kCudaBusErrorMask ) {
158 status = ADB_RET_BUS_ERROR;
159 }
160
161 return status;
162}
163
164static __inline__ void cuda_lock(AppleCuda * self)
165{
166 if( !self->cuda_polled_mode)
167 IOSimpleLockLock(self->cuda_request_lock);
168}
169
170static __inline__ void cuda_unlock(AppleCuda * self)
171{
172 if( !self->cuda_polled_mode)
173 IOSimpleLockUnlock(self->cuda_request_lock);
174}
175
176//
177//
178//
179
180
181static AppleCuda * gCuda;
182// **********************************************************************************
183// init
184//
185// **********************************************************************************
186bool AppleCuda::init ( OSDictionary * properties = 0 )
187{
188return super::init(properties);
189}
190
191
192// **********************************************************************************
193// start
194//
195// **********************************************************************************
196bool AppleCuda::start ( IOService * nub )
197{
198int i;
199IOMemoryMap * viaMap;
200unsigned char * cuda_base;
201
202if( !super::start(nub))
203 return false;
204
205gCuda = this;
206 // callPlatformFunction symbols
207 cuda_check_any_interrupt = OSSymbol::withCString("cuda_check_any_interrupt");
208
209workLoop = NULL;
210eventSrc = NULL;
211ourADBinterface = NULL;
212_rootDomain = 0;
213
214workLoop = IOWorkLoop::workLoop();
215if ( !workLoop ) {
216 kprintf("Start is bailing\n");
217 return false;
218}
219
220eventSrc = IOInterruptEventSource::interruptEventSource(this, autopollArrived);
221if (!eventSrc ||
222 kIOReturnSuccess != workLoop->addEventSource(eventSrc) ) {
223 kprintf("Start is bailing\n");
224 return false;
225}
226
227if( 0 == (viaMap = nub->mapDeviceMemoryWithIndex( 0 )) ) {
228 IOLog("%s: no via memory\n", getName());
229 kprintf("Start is bailing\n");
230 return false;
231}
232cuda_base = (unsigned char *)viaMap->getVirtualAddress();
233
234kprintf("VIA base = %08x\n", (UInt32)cuda_base);
235ourADBinterface = new IOCudaADBController;
236if ( !ourADBinterface ) {
237 kprintf("Start is bailing\n");
238 return false;
239}
240if ( !ourADBinterface->init(0,this) ) {
241 kprintf("Start is bailing\n");
242 return false;
243}
244
245if ( !ourADBinterface->attach( this) ) {
246 kprintf("Start is bailing\n");
247 return false;
248}
249
250cuda_request_lock = IOSimpleLockAlloc();
251IOSimpleLockInit(cuda_request_lock);
252
253cuda_via_regs.dataB = cuda_base;
254cuda_via_regs.handshakeDataA = cuda_base+0x0200;
255cuda_via_regs.dataDirectionB = cuda_base+0x0400;
256cuda_via_regs.dataDirectionA = cuda_base+0x0600;
257cuda_via_regs.timer1CounterLow = cuda_base+0x0800;
258cuda_via_regs.timer1CounterHigh = cuda_base+0x0A00;
259cuda_via_regs.timer1LatchLow = cuda_base+0x0C00;
260cuda_via_regs.timer1LatchHigh = cuda_base+0x0E00;
261cuda_via_regs.timer2CounterLow = cuda_base+0x1000;
262cuda_via_regs.timer2CounterHigh = cuda_base+0x1200;
263cuda_via_regs.shift = cuda_base+0x1400;
264cuda_via_regs.auxillaryControl = cuda_base+0x1600;
265cuda_via_regs.peripheralControl = cuda_base+0x1800;
266cuda_via_regs.interruptFlag = cuda_base+0x1A00;
267cuda_via_regs.interruptEnable = cuda_base+0x1C00;
268cuda_via_regs.dataA = cuda_base+0x1E00;
269
270// we require delays of this duration between certain state transitions
271clock_interval_to_absolutetime_interval(200, 1, &cuda_state_transition_delay);
272
273// Set the direction of the cuda signals. ByteACk and TIP are output and
274// TREQ is an input
275
276*cuda_via_regs.dataDirectionB |= (kCudaByteAcknowledgeMask | kCudaTransferInProgressMask);
277*cuda_via_regs.dataDirectionB &= ~kCudaTransferRequestMask;
278
279// Set the clock control. Set to shift data in by external clock CB1.
280
281*cuda_via_regs.auxillaryControl = (*cuda_via_regs.auxillaryControl | kCudaTransferMode) &
282 kCudaSystemRecieve;
283
284// Clear any posible cuda interupt.
285
286if ( *cuda_via_regs.shift );
287
288// Initialize the internal data.
289
290cuda_interrupt_state = CUDA_STATE_IDLE;
291cuda_transaction_state = CUDA_TS_NO_REQUEST;
292cuda_is_header_transfer = false;
293cuda_is_packet_type = false;
294cuda_transfer_count = 0;
295cuda_current_response = NULL;
296for( i = 0; i < NUM_AP_BUFFERS; i++ ) {
297 cuda_unsolicited[ i ].a_buffer = cuda_autopoll_buffers[ i ];
298}
299
300// Terminate transaction and set idle state
301
302cuda_neg_tip_and_byteack(this);
303
304// we want to delay 4 mS for ADB reset to complete
305
306IOSleep( 4 );
307
308// Clear pending interrupt if any...
309
310(void)cuda_read_data(this);
311
312// Issue a Sync Transaction, ByteAck asserted while TIP is negated.
313
314cuda_assert_byte_ack(this);
315
316// Wait for the Sync acknowledgement, cuda to assert TREQ
317
318cuda_wait_for_transfer_request_assert(this);
319
320// Wait for the Sync acknowledgement interrupt.
321
322cuda_wait_for_interrupt(this);
323
324// Clear pending interrupt
325
326(void)cuda_read_data(this);
327
328// Terminate the sync cycle by Negating ByteAck
329
330cuda_neg_byte_ack(this);
331
332// Wait for the Sync termination acknowledgement, cuda negates TREQ.
333
334cuda_wait_for_transfer_request_neg(this);
335
336// Wait for the Sync termination acknowledgement interrupt.
337
338cuda_wait_for_interrupt(this);
339
340// Terminate transaction and set idle state, TIP negate and ByteAck negate.
341cuda_neg_transfer_in_progress(this);
342
343// Clear pending interrupt, if there is one...
344(void)cuda_read_data(this);
345
346#if 0
347 cuda_polled_mode = true;
348#else
349#define VIA_DEV_CUDA 2
350nub->registerInterrupt(VIA_DEV_CUDA,
351 this, (IOInterruptAction) cuda_interrupt);
352nub->enableInterrupt(VIA_DEV_CUDA);
353#endif
354
355PE_poll_input = Cuda_PE_poll_input;
356PE_read_write_time_of_day = Cuda_PE_read_write_time_of_day;
357PE_halt_restart = Cuda_PE_halt_restart;
358PE_write_IIC = Cuda_PE_write_IIC;
359publishResource( "IOiic0", this );
360publishResource( "IORTC", this );
361
362
363//set_cuda_power_message(kADB_powermsg_enable); //won't work on beige G3
364thread_call_func(cuda_async_set_power_message_enable, (thread_call_param_t)this, true);
365thread_call_func(cuda_async_set_file_server_mode, (thread_call_param_t)this, true);
366
367 registerService(); //Gossamer needs to find this driver for waking up G3
368
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 );
373
374ourADBinterface->start( this );
375
376return true;
377}
378
379/* Here are some power management functions so we can tell when system is
380 going to sleep. */
381bool CudahasRoot( OSObject * us, void *, IOService * yourDevice )
382{
383 if (( yourDevice != NULL ) && ((AppleCuda *)us)->_rootDomain == 0)
384 {
385 ((AppleCuda *)us)->_rootDomain = (IOPMrootDomain *) yourDevice;
386 ((IOPMrootDomain *)yourDevice)->registerInterestedDriver((IOService *) us);
387 }
388 return true;
389}
390
391IOReturn AppleCuda::powerStateWillChangeTo ( IOPMPowerFlags theFlags, unsigned long unused1,
392 IOService* unused2)
393{
394//kprintf("will change to %x", theFlags);
395 if ( ! (theFlags & IOPMPowerOn) )
396 {
397 _cuda_power_state = 0; //0 means sleeping
398 }
399 return IOPMAckImplied;
400}
401
402IOReturn AppleCuda::powerStateDidChangeTo ( IOPMPowerFlags theFlags, unsigned long unused1,
403 IOService* unused2)
404{
405//kprintf("did change to %x", theFlags);
406 if (theFlags & IOPMPowerOn)
407 {
408 _cuda_power_state = 1; //1 means awake
409 }
410 return IOPMAckImplied;
411}
412
413
414
415// *****************************************************************************
416// getWorkLoop
417//
418// Return the cuda's workloop.
419//
420// *****************************************************************************
421IOWorkLoop *AppleCuda::getWorkLoop() const
422{
423 return workLoop;
424}
425
426// *****************************************************************************
427// free
428//
429// Release everything we may have allocated.
430//
431// *****************************************************************************
432void AppleCuda::free ( void )
433{
434if ( workLoop ) {
435 workLoop->release();
436}
437if ( eventSrc ) {
438 eventSrc->release();
439}
440if ( ourADBinterface ) {
441 ourADBinterface->release();
442}
443 if (_rootDomain)
444 {
445 _rootDomain->deRegisterInterestedDriver((IOService *) this);
446 _rootDomain = 0;
447 }
448super::free();
449}
450
451
452// **********************************************************************************
453// registerForADBInterrupts
454//
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// **********************************************************************************
459void AppleCuda::registerForADBInterrupts ( ADB_callback_func handler, IOService * caller )
460{
461autopoll_handler = handler;
462ADBid = caller;
463}
464
465
466// **********************************************************************************
467// autopollArrived
468//
469// **********************************************************************************
470static void autopollArrived ( OSObject * CudaDriver, IOInterruptEventSource *, int )
471{
472((AppleCuda *)CudaDriver)->serviceAutopolls();
473}
474
475#define RB_BOOT 1 /* Causes reboot, not halt. Is in xnu/bsd/sys/reboot.h */
476extern "C" {
477 void boot(int paniced, int howto, char * command);
478}
479
480
481static void cuda_async_set_power_message_enable( thread_call_param_t param, thread_call_param_t )
482{
483 //AppleCuda * me = (AppleCuda *) param;
484
485 set_cuda_power_message(kADB_powermsg_enable);
486}
487
488static void cuda_async_set_file_server_mode( thread_call_param_t param, thread_call_param_t )
489{
490 set_cuda_file_server_mode(1);
491}
492
493// **********************************************************************************
494// serviceAutopolls
495// We get here just before calling autopollHandler() in IOADBController.cpp
496// **********************************************************************************
497void AppleCuda::serviceAutopolls ( void )
498{
499cuda_packet_t * response;
500
501 while( inIndex != outIndex ) {
502
503 response = &cuda_unsolicited[ outIndex ];
504
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)
508 {
509 unsigned char flag, cmd;
510
511 flag = response->a_header[1];
512 cmd = response->a_header[2];
513
514 if ((flag == kADB_powermsg_flag_chassis)
515 && (cmd == kADB_powermsg_cmd_chassis_off))
516 {
517 thread_call_func(cuda_async_set_power_message_enable,
518 (thread_call_param_t)this, true);
519
520 if (_rootDomain)
521 {
522 if (_cuda_power_state)
523 {
524 //Put system to sleep now
525 _rootDomain->receivePowerNotification (kIOPMSleepNow);
526 }
527 else //If asleep, wake up the system
528 {
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);
533 }
534 }
535 }
536 else if ((flag == kADB_powermsg_flag_keyboardpwr)
537 && (cmd == kADB_powermsg_cmd_keyboardoff))
538 {
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);
543 }
544
545 }
546
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 }
584 return kIOReturnSuccess;
585 }
586
587 return kIOReturnBadArgument;
588}
589
590
591// **********************************************************************************
592// cuda_do_sync_request
593//
594// **********************************************************************************
595IOReturn cuda_do_sync_request ( AppleCuda * self, cuda_request_t * request, bool polled )
596{
597 bool wasPolled = false;
598 IOInterruptState ints;
599
600 if( !polled ) {
601 request->sync = IOSyncer::create();
602 request->needWake = true;
603 }
604
605 ints = IOSimpleLockLockDisableInterrupt(self->cuda_request_lock);
606
607 if( polled ) {
608 wasPolled = self->cuda_polled_mode;
609 self->cuda_polled_mode = polled;
610 }
611
612 if( self->cuda_last_request )
613 self->cuda_last_request->a_next = request;
614 else
615 self->cuda_request = request;
616
617 self->cuda_last_request = request;
618
619 if( self->cuda_interrupt_state == CUDA_STATE_IDLE )
620 cuda_send_request(self);
621
622 if( polled ) {
623 cuda_poll(self);
624 self->cuda_polled_mode = wasPolled;
625 assert( 0 == self->cuda_request );
626 assert( 0 == self->cuda_last_request );
627 }
628
629 IOSimpleLockUnlockEnableInterrupt(self->cuda_request_lock, ints);
630
631 if( !polled)
632 request->sync->wait();
633
634 return cuda_get_result(request);
635}
636
637
638// **********************************************************************************
639// Cuda_PE_read_write_time_of_day
640//
641// **********************************************************************************
642static int Cuda_PE_read_write_time_of_day ( unsigned int options, long * secs )
643{
644cuda_request_t cmd;
645
646adb_init_request(&cmd);
647
648cmd.a_cmd.a_hcount = 2;
649cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO;
650
651switch( options ) {
652
653 case kPEReadTOD:
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);
657 break;
658
659 case kPEWriteTOD:
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);
663 break;
664
665 default:
666 return 1;
667}
668
669return cuda_do_sync_request(gCuda, &cmd, true);
670}
671
672
673// **********************************************************************************
674// Cuda_PE_halt_restart
675//
676// **********************************************************************************
677static int Cuda_PE_halt_restart ( unsigned int type )
678{
679cuda_request_t cmd;
680
681adb_init_request(&cmd);
682
683cmd.a_cmd.a_hcount = 2;
684cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO;
685
686switch( type ) {
687
688 case kPERestartCPU:
689 cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_RESTART_SYSTEM;
690 break;
691
692 case kPEHaltCPU:
693 cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_POWER_DOWN;
694 break;
695
696 default:
697 return 1;
698 }
699
700return cuda_do_sync_request(gCuda, &cmd, true);
701}
702
703
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
707// PowerBooks.
708// **********************************************************************************
709static int set_cuda_file_server_mode ( int command )
710{
711cuda_request_t cmd;
712
713adb_init_request(&cmd);
714
715cmd.a_cmd.a_hcount = 3;
716cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO;
717cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_FILE_SERVER_FLAG;
718cmd.a_cmd.a_header[2] = command;
719
720return cuda_do_sync_request(gCuda, &cmd, true);
721}
722
723// **********************************************************************************
724// Fix front panel power key (mostly on Yosemites) so that one press won't power
725// down the entire machine
726//
727// **********************************************************************************
728static int set_cuda_power_message ( int command )
729{
730cuda_request_t cmd;
731
732if (command >= kADB_powermsg_invalid)
733 return 0; //invalid Cuda power request
734
735adb_init_request(&cmd);
736
737cmd.a_cmd.a_hcount = 3;
738cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO;
739cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_SET_POWER_MESSAGES;
740cmd.a_cmd.a_header[2] = command;
741
742return cuda_do_sync_request(gCuda, &cmd, true);
743}
744
745
746// **********************************************************************************
747// Cuda_PE_write_IIC
748//
749// **********************************************************************************
750static int Cuda_PE_write_IIC ( unsigned char addr, unsigned char reg, unsigned char data )
751{
752cuda_request_t cmd;
753
754adb_init_request(&cmd);
755
756cmd.a_cmd.a_header[0] = ADB_PACKET_PSEUDO;
757cmd.a_cmd.a_header[1] = ADB_PSEUDOCMD_GET_SET_IIC;
758cmd.a_cmd.a_header[2] = addr;
759cmd.a_cmd.a_header[3] = reg;
760cmd.a_cmd.a_header[4] = data;
761cmd.a_cmd.a_hcount = 5;
762
763return cuda_do_sync_request(gCuda, &cmd, true);
764}
765
766IOReturn
767AppleCudaWriteIIC( UInt8 address, const UInt8 * buffer, IOByteCount * count )
768{
769 IOReturn ret;
770 cuda_request_t cmd;
771
772 if( !gCuda)
773 return( kIOReturnUnsupported );
774
775 adb_init_request(&cmd);
776
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;
783
784 ret = cuda_do_sync_request(gCuda, &cmd, true);
785
786 *count = cmd.a_cmd.a_bcount;
787
788 return( ret );
789}
790
791IOReturn
792AppleCudaReadIIC( UInt8 address, UInt8 * buffer, IOByteCount * count )
793{
794 IOReturn ret;
795 cuda_request_t cmd;
796
797 if( !gCuda)
798 return( kIOReturnUnsupported );
799
800 adb_init_request(&cmd);
801
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;
808
809 ret = cuda_do_sync_request(gCuda, &cmd, true);
810 *count = cmd.a_reply.a_bcount;
811
812 return( ret );
813}
814
815
816// **********************************************************************************
817// Cuda_PE_poll_input
818//
819// **********************************************************************************
820static int Cuda_PE_poll_input ( unsigned int, char * c )
821{
822AppleCuda * self = gCuda;
823int interruptflag;
824UInt8 code;
825cuda_packet_t * response; //0123456789abcdef
826static char keycodes2ascii[] = "asdfhgzxcv_bqwer" //00
827 "yt123465=97-80]o" //10
828 "u[ip\nlj'k;_,/nm." //20
829 "\t_"; //30
830
831*c = 0xff;
832
833if( !self ) {
834 return 1;
835}
836
837self->cuda_polled_mode = true;
838interruptflag = *self->cuda_via_regs.interruptFlag & kCudaInterruptMask;
839eieio();
840if( interruptflag ) {
841 cuda_interrupt(self);
842}
843
844if( 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 ];
851 }
852 }
853 self->outIndex = self->inIndex;
854}
855
856self->cuda_polled_mode = false;
857return 0;
858}
859
860
861//
862// internal
863//
864
865
866// **********************************************************************************
867// cuda_send_request
868//
869// **********************************************************************************
870static void cuda_send_request ( AppleCuda * self )
871{
872
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.
876
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.
880
881if( !cuda_is_transfer_in_progress(self) ) {
882 // Set the shift register direction to output to Cuda by setting
883 // the direction bit.
884
885 cuda_set_data_direction_to_output(self);
886
887 // Write the first byte to the shift register
888 cuda_write_data(self, self->cuda_request->a_cmd.a_header[0]);
889
890 // Set up the transfer state info here.
891
892 self->cuda_is_header_transfer = true;
893 self->cuda_transfer_count = 1;
894
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);
899
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.
902
903 self->cuda_interrupt_state = CUDA_STATE_TRANSMIT_EXPECTED;
904 self->cuda_transaction_state = CUDA_TS_SYNC_RESPONSE;
905}
906
907#if 0
908else {
909 IOLog("Req = %x, state = %x, TIP = %x\n", self->cuda_request,
910 self->cuda_interrupt_state, cuda_is_transfer_in_progress(self));
911}
912#endif
913}
914
915
916// **********************************************************************************
917// cuda_poll
918//
919// **********************************************************************************
920static void cuda_poll( AppleCuda * self )
921{
922 do {
923 cuda_wait_for_interrupt(self);
924 cuda_interrupt(self);
925 } while( self->cuda_interrupt_state != CUDA_STATE_IDLE );
926}
927
928//
929// cuda_process_response
930// Execute at secondary interrupt.
931//
932
933
934// **********************************************************************************
935// cuda_process_response
936//
937// **********************************************************************************
938static void cuda_process_response ( AppleCuda * self )
939{
940volatile cuda_request_t * request;
941unsigned int newIndex;
942
943 // Almost ready for the next state, which should be a Idle state.
944 // Just need to notifiy the client.
945
946if ( self->cuda_transaction_state == CUDA_TS_SYNC_RESPONSE ) {
947
948 // dequeue reqeuest
949 cuda_lock(self);
950 request = self->cuda_request;
951 if( NULL == (self->cuda_request = request->a_next) ) {
952 self->cuda_last_request = NULL;
953 }
954 cuda_unlock(self);
955
956 // wake the sync request thread
957 if ( ((cuda_request_t *)request)->needWake ) {
958 ((cuda_request_t *)request)->sync->signal();
959 }
960
961}
962else {
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;
967 }
968 else {
969 // drop this packet, and reuse the buffer
970 }
971 if ( !self->cuda_polled_mode ) {
972 // wake thread to service autopolls
973 self->eventSrc->interruptOccurred(0, 0, 0);
974 }
975 }
976}
977return;
978}
979
980
981// **********************************************************************************
982// cuda_interrupt
983//
984// **********************************************************************************
985static void cuda_interrupt ( AppleCuda * self )
986{
987unsigned char interruptState;
988
989 // Get the relevant signal in determining the cause of the interrupt:
990 // the shift direction, the transfer request line and the transfer
991 // request line.
992
993interruptState = cuda_get_interrupt_state(self);
994
995//kprintf("%02x",interruptState);
996
997switch ( interruptState ) {
998 case kCudaReceiveByte:
999 cuda_receive_data(self);
1000 break;
1001
1002 case kCudaReceiveLastByte:
1003 cuda_receive_last_byte(self);
1004 break;
1005
1006 case kCudaTransmitByte:
1007 cuda_transmit_data(self);
1008 break;
1009
1010 case kCudaUnexpectedAttention:
1011 cuda_unexpected_attention(self);
1012 break;
1013
1014 case kCudaExpectedAttention:
1015 cuda_expected_attention(self);
1016 break;
1017
1018 case kCudaIdleState:
1019 cuda_idle(self);
1020 break;
1021
1022 case kCudaCollision:
1023 cuda_collision(self);
1024 break;
1025
1026 // Unknown interrupt, clear it and leave.
1027 default:
1028 cuda_error(self);
1029 break;
1030}
1031}
1032
1033//
1034// TransmitCudaData
1035// Executes at hardware interrupt level.
1036//
1037
1038// **********************************************************************************
1039// cuda_transmit_data
1040//
1041// **********************************************************************************
1042static void cuda_transmit_data ( AppleCuda * self )
1043{
1044 // Clear the pending interrupt by reading the shift register.
1045
1046if ( 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++]);
1049
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;
1054 }
1055
1056 cuda_toggle_byte_ack( self);
1057}
1058else {
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);
1065 }
1066 else {
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.
1070
1071 cuda_neg_tip_and_byteack(self);
1072
1073 // The next interrupt should be a expected attention interrupt.
1074
1075 self->cuda_interrupt_state = CUDA_STATE_ATTN_EXPECTED;
1076 }
1077}
1078}
1079
1080//
1081// cuda_expected_attention
1082// Executes at hardware interrupt level.
1083//
1084
1085
1086// **********************************************************************************
1087// cuda_expected_attention
1088//
1089// **********************************************************************************
1090static void cuda_expected_attention ( AppleCuda * self )
1091{
1092 // Clear the pending interrupt by reading the shift register.
1093
1094(void)cuda_read_data(self);
1095
1096 // Allow the VIA to settle directions.. else the possibility of
1097 // data corruption.
1098cuda_do_state_transition_delay(self);
1099
1100if ( self->cuda_transaction_state == CUDA_TS_SYNC_RESPONSE ) {
1101 self->cuda_current_response = (cuda_packet_t*)&self->cuda_request->a_reply;
1102}
1103else {
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;
1107}
1108
1109self->cuda_is_header_transfer = true;
1110self->cuda_is_packet_type = true;
1111self->cuda_transfer_count = 0;
1112
1113 // Set the shift register direction to input.
1114cuda_set_data_direction_to_input(self);
1115
1116 // Start the response packet transaction.
1117cuda_assert_transfer_in_progress(self);
1118
1119 // The next interrupt should be a receive data interrupt.
1120self->cuda_interrupt_state = CUDA_STATE_RECEIVE_EXPECTED;
1121}
1122
1123//
1124// cuda_unexpected_attention
1125// Executes at hardware interrupt level.
1126//
1127
1128
1129// **********************************************************************************
1130// cuda_expected_attention
1131//
1132// **********************************************************************************
1133static void cuda_unexpected_attention ( AppleCuda * self )
1134{
1135 // Clear the pending interrupt by reading the shift register.
1136(void)cuda_read_data(self);
1137
1138 // Get ready for a unsolicited response.
1139self->cuda_current_response = &self->cuda_unsolicited[ self->inIndex ];
1140self->cuda_current_response->a_hcount = 0;
1141self->cuda_current_response->a_bcount = MAX_AP_RESPONSE;
1142
1143self->cuda_is_header_transfer = TRUE;
1144self->cuda_is_packet_type = TRUE;
1145self->cuda_transfer_count = 0;
1146
1147 // Start the response packet transaction, Transaction In Progress
1148cuda_assert_transfer_in_progress(self);
1149
1150 // The next interrupt should be a receive data interrupt and the next
1151 // response should be an async response.
1152
1153self->cuda_interrupt_state = CUDA_STATE_RECEIVE_EXPECTED;
1154
1155self->cuda_transaction_state = CUDA_TS_ASYNC_RESPONSE;
1156}
1157
1158//
1159// cuda_receive_data
1160// Executes at hardware interrupt level.
1161//
1162
1163
1164// **********************************************************************************
1165// cuda_receive_data
1166//
1167// **********************************************************************************
1168static void cuda_receive_data ( AppleCuda * self )
1169{
1170if ( self->cuda_is_packet_type ) {
1171 unsigned char packetType;
1172
1173 packetType = cuda_read_data( self);
1174 self->cuda_current_response->a_header[self->cuda_transfer_count++] = packetType;
1175
1176 if ( packetType == ADB_PACKET_ERROR) {
1177 self->cuda_current_response->a_hcount = 4;
1178 }
1179 else {
1180 self->cuda_current_response->a_hcount = 3;
1181 }
1182
1183 self->cuda_is_packet_type = false;
1184
1185 cuda_toggle_byte_ack(self);
1186
1187}
1188else {
1189
1190
1191 if ( self->cuda_is_header_transfer ) {
1192
1193 self->cuda_current_response->a_header[self->cuda_transfer_count++] =
1194 cuda_read_data(self);
1195
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;
1199 }
1200
1201 cuda_toggle_byte_ack(self);
1202 }
1203 else {
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.
1207
1208 *(self->cuda_current_response->a_buffer + self->cuda_transfer_count++) =
1209 cuda_read_data(self);
1210 cuda_toggle_byte_ack(self);
1211
1212 }
1213 else {
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.
1217
1218 self->cuda_current_response->a_bcount = self->cuda_transfer_count;
1219
1220 cuda_read_data(self);
1221
1222 cuda_process_response(self);
1223 cuda_neg_tip_and_byteack(self);
1224 }
1225 }
1226}
1227}
1228
1229
1230//
1231// cuda_receive_last_byte
1232// Executes at hardware interrupt level.
1233//
1234
1235
1236// **********************************************************************************
1237// cuda_receive_last_byte
1238//
1239// **********************************************************************************
1240static void cuda_receive_last_byte ( AppleCuda * self )
1241{
1242
1243if ( self->cuda_is_header_transfer ) {
1244 self->cuda_current_response->a_header[self->cuda_transfer_count++] =
1245 cuda_read_data(self);
1246
1247 self->cuda_transfer_count = 0;
1248 }
1249else {
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);
1253 }
1254 else {
1255 /* Overrun -- ignore data */
1256 (void) cuda_read_data(self);
1257 }
1258}
1259self->cuda_current_response->a_bcount = self->cuda_transfer_count;
1260 // acknowledge before response so polled mode can work
1261 // from inside the handler
1262cuda_neg_tip_and_byteack(self);
1263cuda_process_response(self);
1264}
1265
1266
1267//
1268// cuda_collision
1269// Executes at hardware interrupt level.
1270//
1271
1272
1273// **********************************************************************************
1274// cuda_collision
1275//
1276// **********************************************************************************
1277static void cuda_collision ( AppleCuda * self )
1278{
1279// Clear the pending interrupt by reading the shift register.
1280(void)cuda_read_data(self);
1281
1282// Negate TIP to abort the send. Cuda should send a second attention
1283// interrupt to acknowledge the abort cycle.
1284cuda_neg_transfer_in_progress(self);
1285
1286// The next interrupt should be an expected attention and the next
1287// response packet should be an async response.
1288
1289self->cuda_interrupt_state = CUDA_STATE_ATTN_EXPECTED;
1290self->cuda_transaction_state = CUDA_TS_ASYNC_RESPONSE;
1291
1292/* queue the request */
1293self->cuda_is_header_transfer = false;
1294self->cuda_transfer_count = 0;
1295}
1296
1297
1298//
1299//
1300// Executes at hardware interrupt level.
1301//
1302
1303
1304// **********************************************************************************
1305// cuda_idle
1306//
1307// **********************************************************************************
1308static void cuda_idle ( AppleCuda * self )
1309{
1310
1311// Clear the pending interrupt by reading the shift register.
1312(void)cuda_read_data(self);
1313
1314cuda_lock(self);
1315 // Set to the idle state.
1316self->cuda_interrupt_state = CUDA_STATE_IDLE;
1317 // See if there are any pending requests.
1318if( self->cuda_request ) {
1319 cuda_send_request(self);
1320}
1321cuda_unlock(self);
1322}
1323
1324
1325// **********************************************************************************
1326// cuda_error
1327//
1328// **********************************************************************************
1329static void cuda_error ( AppleCuda * self )
1330{
1331//printf("{Error %d}", self->cuda_transaction_state);
1332
1333// Was looking at cuda_transaction_state - doesn't seem right
1334
1335switch ( self->cuda_interrupt_state ) {
1336 case CUDA_STATE_IDLE:
1337 cuda_neg_tip_and_byteack(self);
1338 break;
1339
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");
1346 }
1347 else {
1348 self->cuda_interrupt_state = CUDA_STATE_ATTN_EXPECTED;
1349 cuda_neg_tip_and_byteack(self);
1350 }
1351 break;
1352
1353 case CUDA_STATE_ATTN_EXPECTED:
1354 cuda_assert_transfer_in_progress(self);
1355
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");
1360 break;
1361
1362 case CUDA_STATE_RECEIVE_EXPECTED:
1363 cuda_neg_tip_and_byteack(self);
1364 panic("Cuda - todo check for transaction type and error");
1365 break;
1366
1367 default:
1368 cuda_set_data_direction_to_input(self);
1369 cuda_neg_tip_and_byteack(self);
1370 break;
1371}
1372}
1373
1374static void cuda_do_state_transition_delay( AppleCuda * self )
1375{
1376 AbsoluteTime deadline;
1377
1378 clock_absolutetime_interval_to_deadline(
1379 self->cuda_state_transition_delay, &deadline);
1380 clock_delay_until(deadline);
1381}