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