|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: #import "pmu.h"
26: #import "pmupriv.h"
27: #import "pmumisc.h"
28: #import "pmutables.h"
29: #import <kern/clock.h>
30: #import <kernserv/prototypes.h>
31: #import <kernserv/clock_timer.h>
32: #import <kernserv/ns_timer.h>
33: #import <bsd/sys/time.h>
34: #import <sys/callout.h>
35: #import <machdep/ppc/proc_reg.h>
1.1.1.2 ! root 36: #import <machdep/ppc/powermac.h>
1.1 root 37: #import <driverkit/generalFuncs.h>
38: #import <driverkit/kernelDriver.h>
39: #import <driverkit/interruptMsg.h>
40:
41: // extern to let us fix up the boot time.
42: extern void set_boot_time(void);
43:
44: void gotInterruptCause(id, UInt32, UInt32, UInt8 *);
45: void timer_expired(port_t mach_port);
46:
47: extern void kprintf(const char *, ...);
48: extern void bcopy(void *, void *, int);
49: extern msg_send_from_kernel(msg_header_t *, int, int);
50:
51: extern id ApplePMUId;
52:
53: @implementation ApplePMU
54:
55: // **********************************************************************************
56: // probe
57: //
58: //
59: //
60: // **********************************************************************************
61: + (Boolean) probe : deviceDescription
62: {
63: id dev;
64: kprintf("PMU probe\n");
65: if ( (dev = [ self alloc ]) == nil ) {
66: return NO;
67: }
68:
69: if ([dev initFromDeviceDescription:deviceDescription] == nil) {
70: return NO;
71: }
72:
73: ApplePMUId = dev;
74:
75: set_boot_time();
76:
77: return YES;
78: }
79:
80:
81:
82:
83: // **********************************************************************************
84: // initFromDeviceDescription
85: //
86: //
87: //
88: // **********************************************************************************
89: - initFromDeviceDescription:(IODeviceDescription *)deviceDescription
90: {
91: VIAAddress physicalAddress;
92: IORange *ioRange;
93: PMUmachMessage theRequest;
94: unsigned int *oldIRQs, newIRQs[2], tmpIRQ;
95:
96:
97: if ( [super initFromDeviceDescription:deviceDescription] == nil ) {
98: [self free];
99: return nil;
100: }
101:
102: [self setDeviceKind:"PM Subsystem"];
103: [self setLocation:NULL];
104: [self setName:"PMU"];
105:
106: ioRange = [deviceDescription memoryRangeList];
107: physicalAddress = (VIAAddress)ioRange->start;
108:
109: VIA1_shift = physicalAddress + 0x1400; // initialize VIA addresses
110: VIA1_auxillaryControl = physicalAddress + 0x1600;
111: VIA1_interruptFlag = physicalAddress + 0x1A00;
112: VIA1_interruptEnable = physicalAddress + 0x1C00;
113: // VIA2_dataB = physicalAddress + 0x2000; // 5300
114: // PMreq = 1 << M2Req;
115: // PMack = 1 << M2Ack;
116: VIA2_dataB = physicalAddress + 0x0000; // Hooper uses VIA 1 instead
117: PMreq = 1 << HooperReq; // and different bits in it as well
118: PMack = 1 << HooperAck;
119: // initialize other variables
120: ADBclient = NULL;
121: RTCclient = NULL;
122: debugging = FALSE;
123: queueHead = NULL;
124: queueTail = NULL;
125: PGE_ISR_state = kPMUidle;
126: pollList = 0;
127: autopollOn = FALSE;
128: adb_reading = FALSE;
129: PMU_int_pending = FALSE;
130:
131: adb_read_timeout = 100000000;
132:
133: [self AcknowledgePMUInterrupt]; // turn off any pending PGE interrupt
134: [self EnablePMUInterrupt]; // enable PGE interrupts
135:
136: // This is a still sleazy hack...
137: oldIRQs = [deviceDescription interruptList];
138:
1.1.1.2 ! root 139: if (IsSawtooth()) {
! 140: // On Sawtooth it is ExtInt1...
! 141: tmpIRQ = 47 ^ 0x18;
! 142: } else {
! 143: // This is another sleazy hack.
! 144: //The second irq is two lower in the via table.
! 145: tmpIRQ = ((*oldIRQs ^ 0x18) + 2) ^ 0x18;
! 146: }
1.1 root 147:
148: newIRQs[0] = *oldIRQs;
149: newIRQs[1] = tmpIRQ;
150:
151: [deviceDescription setInterruptList:newIRQs num:2];
152:
153: [self enableAllInterrupts];
154:
155: if ([self startIOThread] != IO_R_SUCCESS) {
156: [self free];
157: return nil;
158: }
159:
160: port = IOConvertPort([self interruptPort],IO_KernelIOTask,IO_Kernel);
161:
162: theRequest.msgBody.pmCommand = kPMUSetModem1SecInt; // tell PGE why it may interrupt
163: theRequest.msgBody.pmFlag = FALSE;
164: theRequest.msgBody.pmSLength1 = 1;
165: theRequest.msgBody.pmSBuffer1[0] = kPMUMD2Int | kPMUbrightnessInt | kPMUADBint;
166: theRequest.msgBody.pmSLength2 = 0;
167: theRequest.msgBody.pmCallback = NULL;
168:
169: theRequest.msgHeader.msg_simple = TRUE;
170: theRequest.msgHeader.msg_type = MSG_TYPE_NORMAL;
171: theRequest.msgHeader.msg_remote_port = port;
172: theRequest.msgHeader.msg_local_port = PORT_NULL;
173: theRequest.msgHeader.msg_size = sizeof(PMUmachMessage);
174: msg_send_from_kernel(&theRequest.msgHeader, MSG_OPTION_NONE, 0);
175:
176: theRequest.msgBody.pmCommand = kPMUreadINT; // read any pending interrupt from PGE
177: theRequest.msgBody.pmFlag = FALSE;
178: theRequest.msgBody.pmSLength1 = 0; // just to clear it
179: theRequest.msgBody.pmSLength2 = 0;
180: theRequest.msgBody.pmRBuffer = &interruptState[0];
181: theRequest.msgBody.pmCallback = NULL;
182:
183: theRequest.msgHeader.msg_simple = TRUE;
184: theRequest.msgHeader.msg_type = MSG_TYPE_NORMAL;
185: theRequest.msgHeader.msg_remote_port = port;
186: theRequest.msgHeader.msg_local_port = PORT_NULL;
187: theRequest.msgHeader.msg_size = sizeof(PMUmachMessage);
188: msg_send_from_kernel(&theRequest.msgHeader, MSG_OPTION_NONE, 0);
189:
190: [self registerDevice];
191:
192: return self;
193: }
194:
195:
196: // **********************************************************************************
197: // free
198: //
199: //
200: //
201: // **********************************************************************************
202: - free
203: {
204: return [ super free ];
205: }
206:
207:
208:
209:
210:
211: // **********************************************************************************
212: // poll_device
213: //
214: // System interrupts are disabled, but we are still operating the PMU for mini-
215: // monitor keyboard input. We are called here in a loop to service the PMU.
216: //
217: // **********************************************************************************
218: - (void)poll_device
219: {
220: if ( *VIA1_interruptFlag & 0x04 ) { // is shift register done? ( ifSR )
221: [self interruptOccurred]; // yes, handle it
222: return;
223: }
224: if ( *VIA1_interruptFlag & 0x10 ) { // is PMU requesting service? ( ifCB1 )
225: *VIA1_interruptFlag = 0x10; // yes, clear interrupt ( ifCB1 )
226: PGE_ISR_state = kPMUidle; // and handle it
227: [self interruptOccurredAt:1];
228: }
229: }
230:
231:
232: // **********************************************************************************
233: // receiveMsg
234: //
235: //
236: //
237: // **********************************************************************************
238: - (void)receiveMsg
239: {
240: PMUmachMessage * toQueue;
241: IOReturn result;
242: if ( (PGE_ISR_state == kPMUidle) && !adb_reading ) {
243: localMachMessage.msgHeader.msg_size = sizeof(PMUmachMessage);
244: localMachMessage.msgHeader.msg_local_port = [self interruptPort];
245: result = msg_receive(&localMachMessage.msgHeader, (msg_option_t)RCV_TIMEOUT, 0);
246: if ( result == RCV_SUCCESS ) {
247: [self StartPMUTransmission:&localMachMessage.msgBody];
248: }
249: }
250: else {
251: toQueue = (PMUmachMessage*)kalloc(sizeof(PMUmachMessage));
252: toQueue->msgHeader.msg_size = sizeof(PMUmachMessage);
253: toQueue->msgHeader.msg_local_port = [self interruptPort];
254: result = msg_receive(&toQueue->msgHeader, (msg_option_t)RCV_TIMEOUT, 0);
255: if ( result == RCV_SUCCESS ) {
256: toQueue->msgBody.prev = queueTail;
257: toQueue->msgBody.next = NULL;
258: if ( queueTail != NULL ) {
259: queueTail->msgBody.next = toQueue;
260: }
261: else {
262: queueHead = toQueue;
263: }
264: queueTail = toQueue;
265: }
266: }
267: }
268:
269:
270: // **********************************************************************************
271: // timeoutOccurred
272: //
273: // Our adb-read timer has expired after sending an adb-read command to the PMU.
274: // This means there is no such addressed device on the ADB bus.
275: // We call back to the ADB driver with a zero-characters-received response and
276: // dequeue our command queue and carry on.
277: // **********************************************************************************
278: - (void)timeoutOccurred
279: {
280: adb_reading = FALSE;
281: if ( clientRequest->pmCallback != NULL ) { // Make the client callback
282: clientRequest->pmCallback(clientRequest->pmId, clientRequest->pmRefNum, 0, NULL);
283: } // with zero received-length
284: [self CheckRequestQueue];
285: }
286:
287:
288: // ****************************************************************************
289: // CheckRequestQueue
290: // Called at interrupt time when current request is complete. We may start
291: // another request here if one is in queue, or we may re-enable PMU interrupts
292: // (they were turned off in PMUStartIO) and return.
293: // ****************************************************************************
294: - (void)CheckRequestQueue
295: {
296: PMUmachMessage * nextRequest;
297:
298: if ( queueHead == NULL ) { // is queue empty?
299: [self EnablePMUInterrupt]; // yes, enable interrupt and return
300: }
301: else {
302: nextRequest = queueHead; // no, dequeue first command
303: queueHead = nextRequest->msgBody.next;
304: if ( queueHead == NULL ) {
305: queueTail = NULL;
306: }
307: bcopy (&nextRequest->msgBody, &localMachMessage.msgBody, sizeof(PMURequest)); // copy it
308: kfree(nextRequest, sizeof(PMUmachMessage)); // free its memory
309: [self StartPMUTransmission:&localMachMessage.msgBody]; // and send it to the PMU
310: }
311: }
312:
313:
314: // **********************************************************************************
315: // registerForADBAutopoll
316: //
317: // The ADB driver is calling to tell us that it is prepared to receive
318: // "unsolicited" ADB autopoll data. The parameter tells who to call
319: // when we get some.
320: //
321: // **********************************************************************************
322: - (void)registerForADBAutopoll :(pmADBinput_func)InputHandler
323: :(id)caller
324: {
325: ADBclient = InputHandler;
326: ADBid = caller;
327: }
328:
329:
330: // **********************************************************************************
331: // ADBWrite
332: //
333: // **********************************************************************************
334: - (PMUStatus)ADBWrite :(UInt32)DevAddr
335: :(UInt32)DevReg
336: :(UInt32)ByteCount
337: :(UInt8*)Buffer
338: :(UInt32)RefNum
339: :(id)Id
340: :(pmCallback_func)Callback
341: {
342: PMUmachMessage request;
343: msg_return_t return_code;
344:
345: if ( (ByteCount == 0) ||
346: (Buffer == NULL) ||
347: (ByteCount > (MISC_LENGTH-3) ) ) {
348: return kPMUParameterError;
349: }
350:
351: request.msgBody.pmCommand = kPMUpMgrADB;
352: request.msgBody.pmFlag = TRUE; // this op solicits input from PGE
353: request.msgBody.pmSLength1 = 3;
354: request.msgBody.pmSBuffer2 = Buffer;
355: request.msgBody.pmSLength2 = ByteCount;
356: request.msgBody.pmRBuffer = NULL;
357: request.msgBody.pmCallback = Callback;
358: request.msgBody.pmId = Id;
359: request.msgBody.pmRefNum = RefNum;
360: request.msgBody.pmSBuffer1[0] = kPMUWriteADB | (DevAddr << kPMUADBAddressField) | (DevReg);
361: if ( autopollOn ) {
362: request.msgBody.pmSBuffer1[1] = 2;
363: }
364: else {
365: request.msgBody.pmSBuffer1[1] = 0;
366: }
367: request.msgBody.pmSBuffer1[2] = ByteCount;
368:
369: request.msgHeader.msg_simple = TRUE;
370: request.msgHeader.msg_type = MSG_TYPE_NORMAL;
371: request.msgHeader.msg_remote_port = port;
372: request.msgHeader.msg_local_port = PORT_NULL;
373: request.msgHeader.msg_size = sizeof(PMUmachMessage);
374: return_code = msg_send_from_kernel(&request.msgHeader, MSG_OPTION_NONE, 0);
375:
376: if ( return_code == SEND_SUCCESS ) {
377: return kPMUNoError;
378: }
379: else {
380: return kPMUIOError;
381: }
382: }
383:
384:
385: // **********************************************************************************
386: // ADBRead
387: //
388: // **********************************************************************************
389: - (PMUStatus)ADBRead :(UInt32)DevAddr
390: :(UInt32)DevReg
391: :(UInt32)RefNum
392: :(id)Id
393: :(pmCallback_func)Callback
394: {
395: PMUmachMessage request;
396: msg_return_t return_code;
397:
398: request.msgBody.pmCommand = kPMUpMgrADB;
399: request.msgBody.pmFlag = TRUE; // this op solicits input from PGE
400: request.msgBody.pmSLength1 = 3;
401: request.msgBody.pmSBuffer2 = NULL;
402: request.msgBody.pmSLength2 = 0;
403: request.msgBody.pmRBuffer = NULL;
404: request.msgBody.pmCallback = Callback;
405: request.msgBody.pmId = Id;
406: request.msgBody.pmRefNum = RefNum;
407: request.msgBody.pmSBuffer1[0] = kPMUReadADB | (DevAddr << kPMUADBAddressField) | (DevReg);
408: if ( autopollOn ) {
409: request.msgBody.pmSBuffer1[1] = 2;
410: }
411: else {
412: request.msgBody.pmSBuffer1[1] = 0;
413: }
414: request.msgBody.pmSBuffer1[2] = 0;
415:
416: request.msgHeader.msg_simple = TRUE;
417: request.msgHeader.msg_type = MSG_TYPE_NORMAL;
418: request.msgHeader.msg_remote_port = port;
419: request.msgHeader.msg_local_port = PORT_NULL;
420: request.msgHeader.msg_size = sizeof(PMUmachMessage);
421: return_code = msg_send_from_kernel(&request.msgHeader, MSG_OPTION_NONE, 0);
422:
423: if ( return_code == SEND_SUCCESS ) {
424: return kPMUNoError;
425: }
426: else {
427: return kPMUIOError;
428: }
429: }
430:
431:
432: // **********************************************************************************
433: // ADBReset
434: //
435: // **********************************************************************************
436: - (PMUStatus)ADBReset :(UInt32)RefNum
437: :(id)Id
438: :(pmCallback_func)Callback
439: {
440: PMUmachMessage request;
441: msg_return_t return_code;
442:
443: request.msgBody.pmCommand = kPMUpMgrADB;
444: request.msgBody.pmFlag = TRUE; // this op solicits input from PGE
445: request.msgBody.pmSLength1 = 3;
446: request.msgBody.pmSBuffer2 = NULL;
447: request.msgBody.pmSLength2 = 0;
448: request.msgBody.pmRBuffer = NULL;
449: request.msgBody.pmCallback = Callback;
450: request.msgBody.pmId = Id;
451: request.msgBody.pmRefNum = RefNum;
452: request.msgBody.pmSBuffer1[0] = kPMUResetADBBus;
453: request.msgBody.pmSBuffer1[1] = 0;
454: request.msgBody.pmSBuffer1[2] = 0;
455:
456: request.msgHeader.msg_simple = TRUE;
457: request.msgHeader.msg_type = MSG_TYPE_NORMAL;
458: request.msgHeader.msg_remote_port = port;
459: request.msgHeader.msg_local_port = PORT_NULL;
460: request.msgHeader.msg_size = sizeof(PMUmachMessage);
461: return_code = msg_send_from_kernel(&request.msgHeader, MSG_OPTION_NONE, 0);
462:
463: if ( return_code == SEND_SUCCESS ) {
464: return kPMUNoError;
465: }
466: else {
467: return kPMUIOError;
468: }
469: }
470:
471:
472: // **********************************************************************************
473: // ADBFlush
474: //
475: // **********************************************************************************
476: - (PMUStatus)ADBFlush :(UInt32)DevAddr
477: :(UInt32)RefNum
478: :(id)Id
479: :(pmCallback_func)Callback
480: {
481: PMUmachMessage request;
482: msg_return_t return_code;
483:
484: request.msgBody.pmCommand = kPMUpMgrADB;
485: request.msgBody.pmFlag = TRUE;
486: request.msgBody.pmSLength1 = 3;
487: request.msgBody.pmSBuffer2 = NULL;
488: request.msgBody.pmSLength2 = 0;
489: request.msgBody.pmRBuffer = NULL;
490: request.msgBody.pmId = Id;
491: request.msgBody.pmRefNum = RefNum;
492: request.msgBody.pmCallback = Callback;
493: request.msgBody.pmSBuffer1[0] = kPMUFlushADB | (DevAddr << kPMUADBAddressField);
494: if ( autopollOn ) {
495: request.msgBody.pmSBuffer1[1] = 2;
496: }
497: else {
498: request.msgBody.pmSBuffer1[1] = 0;
499: }
500: request.msgBody.pmSBuffer1[2] = 0;
501:
502: request.msgHeader.msg_simple = TRUE;
503: request.msgHeader.msg_type = MSG_TYPE_NORMAL;
504: request.msgHeader.msg_remote_port = port;
505: request.msgHeader.msg_local_port = PORT_NULL;
506: request.msgHeader.msg_size = sizeof(PMUmachMessage);
507: return_code = msg_send_from_kernel(&request.msgHeader, MSG_OPTION_NONE, 0);
508:
509: if ( return_code == SEND_SUCCESS ) {
510: return kPMUNoError;
511: }
512: else {
513: return kPMUIOError;
514: }
515: }
516:
517:
518: // **********************************************************************************
519: // ADBSetPollList
520: //
521: // **********************************************************************************
522: - (PMUStatus)ADBSetPollList :(UInt32)PollBitField
523: :(UInt32)RefNum
524: :(id)Id
525: :(pmCallback_func)Callback
526: {
527: PMUmachMessage request;
528: msg_return_t return_code;
529:
530: pollList = PollBitField; // remember the new poll list
531:
532: if ( autopollOn ) { // if PMU is currently autopolling,
533: request.msgBody.pmCommand = kPMUpMgrADB; // give it the new list
534: request.msgBody.pmFlag = FALSE;
535: request.msgBody.pmSLength1 = 4;
536: request.msgBody.pmSBuffer2 = NULL;
537: request.msgBody.pmSLength2 = 0;
538: request.msgBody.pmRBuffer = NULL;
539: request.msgBody.pmRefNum = RefNum;
540: request.msgBody.pmId = Id;
541: request.msgBody.pmCallback = Callback;
542: request.msgBody.pmSBuffer1[0] = 0;
543: request.msgBody.pmSBuffer1[1] = 0x86;
544: request.msgBody.pmSBuffer1[2] = (UInt8)(PollBitField >> 8);
545: request.msgBody.pmSBuffer1[3] = (UInt8)(PollBitField & 0xff);
546:
547: request.msgHeader.msg_simple = TRUE;
548: request.msgHeader.msg_type = MSG_TYPE_NORMAL;
549: request.msgHeader.msg_remote_port = port;
550: request.msgHeader.msg_local_port = PORT_NULL;
551: request.msgHeader.msg_size = sizeof(PMUmachMessage);
552: return_code = msg_send_from_kernel(&request.msgHeader, MSG_OPTION_NONE, 0);
553:
554: if ( return_code == SEND_SUCCESS ) {
555: return kPMUNoError;
556: }
557: else {
558: return kPMUIOError;
559: }
560: }
561: else { // we'll do it later
562: if ( Callback != NULL ) { // but make the client callback now
563: Callback(Id, RefNum, 0, NULL);
564: }
565: }
566: return kPMUNoError;
567: }
568:
569:
570: // **********************************************************************************
571: // ADBSetFileServerMode()
572: //
573: // **********************************************************************************
574: - (PMUStatus)ADBSetFileServerMode :(UInt32)RefNum
575: :(id)Id
576: :(pmCallback_func)Callback
577:
578: {
579: return kPMUNotSupported;
580: }
581:
582:
583: // **********************************************************************************
584: // ADBPollEnable
585: //
586: // **********************************************************************************
587: - (PMUStatus)ADBPollEnable :(UInt32)RefNum
588: :(id)Id
589: :(pmCallback_func)Callback
590:
591: {
592: PMUmachMessage request;
593: msg_return_t return_code;
594:
595:
596: request.msgBody.pmCommand = kPMUpMgrADB; // give it the list we have
597: request.msgBody.pmFlag = FALSE;
598: request.msgBody.pmSLength1 = 4;
599: request.msgBody.pmSBuffer2 = NULL;
600: request.msgBody.pmSLength2 = 0;
601: request.msgBody.pmRBuffer = NULL;
602: request.msgBody.pmRefNum = RefNum;
603: request.msgBody.pmId = Id;
604: request.msgBody.pmCallback = Callback;
605: request.msgBody.pmSBuffer1[0] = 0;
606: request.msgBody.pmSBuffer1[1] = 0x86;
607: request.msgBody.pmSBuffer1[2] = (UInt8)(pollList >> 8);
608: request.msgBody.pmSBuffer1[3] = (UInt8)(pollList & 0xff);
609:
610: request.msgHeader.msg_simple = TRUE;
611: request.msgHeader.msg_type = MSG_TYPE_NORMAL;
612: request.msgHeader.msg_remote_port = port;
613: request.msgHeader.msg_local_port = PORT_NULL;
614: request.msgHeader.msg_size = sizeof(PMUmachMessage);
615: return_code = msg_send_from_kernel(&request.msgHeader, MSG_OPTION_NONE, 0);
616:
617: if ( return_code == SEND_SUCCESS ) {
618: autopollOn = TRUE;
619: return kPMUNoError;
620: }
621: else {
622: return kPMUIOError;
623: }
624: }
625:
626:
627: // **********************************************************************************
628: // ADBPollDisable
629: //
630: // **********************************************************************************
631: - (PMUStatus)ADBPollDisable :(UInt32)RefNum
632: :(id)Id
633: :(pmCallback_func)Callback
634: {
635: PMUmachMessage request;
636: msg_return_t return_code;
637:
638: request.msgBody.pmCommand = kPMUpMgrADBoff;
639: request.msgBody.pmFlag = FALSE;
640: request.msgBody.pmFlag = TRUE;
641: request.msgBody.pmSLength1 = 0;
642: request.msgBody.pmSBuffer2 = NULL;
643: request.msgBody.pmSLength2 = 0;
644: request.msgBody.pmRBuffer = NULL;
645: request.msgBody.pmRefNum = RefNum;
646: request.msgBody.pmId = Id;
647: request.msgBody.pmCallback = Callback;
648:
649: request.msgHeader.msg_simple = TRUE;
650: request.msgHeader.msg_type = MSG_TYPE_NORMAL;
651: request.msgHeader.msg_remote_port = port;
652: request.msgHeader.msg_local_port = PORT_NULL;
653: request.msgHeader.msg_size = sizeof(PMUmachMessage);
654: return_code = msg_send_from_kernel(&request.msgHeader, MSG_OPTION_NONE, 0);
655:
656: if ( return_code == SEND_SUCCESS ) {
657: autopollOn = FALSE;
658: return kPMUNoError;
659: }
660: else {
661: return kPMUIOError;
662: }
663: }
664:
665:
666: // **********************************************************************************
667: // ADBSetPollRate
668: //
669: // **********************************************************************************
670: - (PMUStatus)ADBSetPollRate :(UInt32)NewRate
671: :(UInt32)RefNum
672: :(id)Id
673: :(pmCallback_func)Callback
674: {
675: return kPMUNotSupported;
676: }
677:
678:
679: // **********************************************************************************
680: // ADBGetPollRate
681: //
682: // **********************************************************************************
683: - (PMUStatus)ADBGetPollRate :(UInt32 *)CurrentRate
684: :(UInt32)RefNum
685: :(id)Id
686: :(pmCallback_func)Callback
687: {
688: return kPMUNotSupported;
689: }
690:
691:
692: // **********************************************************************************
693: // ADBSetAlternateKeyboard
694: //
695: // **********************************************************************************
696: - (PMUStatus)ADBSetAlternateKeyboard :(UInt32)DevAddr
697: :(UInt32)RefNum
698: :(id)Id
699: :(pmCallback_func)Callback
700: {
701: return kPMUNotSupported;
702: }
703:
704:
705: // **********************************************************************************
706: // ADBinput
707: //
708: // The PGE has interrupted with ADB data. We package this up and send
709: // it to our ADB client, if there is one, either as the result to its previous
710: // read command, or as autopoll data.
711: //
712: // **********************************************************************************
713: - (void)ADBinput:(UInt32)theLength:(UInt8 *)theInput
714: {
715: if ( theInput[0] & kPMUautopoll ) { // autopoll data?
716: if ( ADBclient != NULL ) {
717: ADBclient(ADBid, 0, (theInput[1]>>4)&0x0F, theLength-2, theInput+2);
718: // yes, call adb input handler
719: }
720: return;
721: }
722: if ( adb_reading ) { // no, expecting adb input?
723: if ( clientRequest->pmSBuffer1[0] == theInput[1] ) { // yes, is it our input?
724: ns_untimeout((func)timer_expired,(void *)port); // yes, turn off our timer
725: if ( clientRequest->pmCallback != NULL ) { // Make the client callback
726: clientRequest->pmCallback(clientRequest->pmId, clientRequest->pmRefNum, theLength-2, theInput+2);
727: }
728: adb_reading = FALSE;
729: return;
730: }
731: }
732: kprintf("unexpected adb input: %02d %02x %02x %02x %02x\n", theLength, interruptState[0], interruptState[1], interruptState[2], interruptState[3]);
733: }
734:
735:
736: // **********************************************************************************
737: // registerForClockTicks
738: //
739: // The RTC driver is calling to tell us that it is prepared to receive clock
740: // ticks every second. The parameter block tells who to call when we get one.
741: //
742: // **********************************************************************************
743: - (void)registerForClockTicks :(pmCallback_func)TickHandler
744: :(id)caller
745: {
746: RTCclient = TickHandler;
747: RTCid = caller;
748: }
749:
750:
751: // **********************************************************************************
752: // setRealTimeClock
753: //
754: // The RTC driver is calling to set the real time clock. We translate this into
755: // a PMU command and enqueue it to our command queue.
756: //
757: // **********************************************************************************
758: - (PMUStatus)setRealTimeClock :(UInt8 *)newTime
759: :(UInt32)RefNum
760: :(id)Id
761: :(pmCallback_func)Callback
762: {
763: PMUmachMessage request;
764: msg_return_t return_code;
765:
766: if ( newTime == NULL ) {
767: return kPMUParameterError;
768: }
769:
770: request.msgBody.pmCommand = kPMUtimeWrite;
771: request.msgBody.pmFlag = FALSE;
772: request.msgBody.pmSLength1 = 0;
773: request.msgBody.pmSBuffer2 = newTime;
774: request.msgBody.pmSLength2 = 4;
775: request.msgBody.pmRBuffer = NULL;
776: request.msgBody.pmRefNum = RefNum;
777: request.msgBody.pmId = Id;
778: request.msgBody.pmCallback = Callback;
779:
780: request.msgHeader.msg_simple = TRUE;
781: request.msgHeader.msg_type = MSG_TYPE_NORMAL;
782: request.msgHeader.msg_remote_port = port;
783: request.msgHeader.msg_local_port = PORT_NULL;
784: request.msgHeader.msg_size = sizeof(PMUmachMessage);
785: return_code = msg_send_from_kernel(&request.msgHeader, MSG_OPTION_NONE, 0);
786:
787: if ( return_code == SEND_SUCCESS ) {
788: return kPMUNoError;
789: }
790: else {
791: return kPMUIOError;
792: }
793: }
794:
795:
796: // **********************************************************************************
797: // getRealTimeClock
798: //
799: // The RTC driver is calling to read the real time clock. We translate this into
800: // a PMU command and enqueue it to our command queue.
801: //
802: // **********************************************************************************
803: - (PMUStatus)getRealTimeClock :(UInt8 *)currentTime
804: :(UInt32)RefNum
805: :(id)Id
806: :(pmCallback_func)Callback
807: {
808: PMUmachMessage request;
809: msg_return_t return_code;
810:
811: if ( currentTime == NULL ) {
812: return kPMUParameterError;
813: }
814:
815: request.msgBody.pmCommand = kPMUtimeRead;
816: request.msgBody.pmFlag = FALSE;
817: request.msgBody.pmSLength1 = 0;
818: request.msgBody.pmSBuffer2 = NULL;
819: request.msgBody.pmSLength2 = 0;
820: request.msgBody.pmRBuffer = currentTime;
821: request.msgBody.pmRefNum = RefNum;
822: request.msgBody.pmId = Id;
823: request.msgBody.pmCallback = Callback;
824:
825: request.msgHeader.msg_simple = TRUE;
826: request.msgHeader.msg_type = MSG_TYPE_NORMAL;
827: request.msgHeader.msg_remote_port = port;
828: request.msgHeader.msg_local_port = PORT_NULL;
829: request.msgHeader.msg_size = sizeof(PMUmachMessage);
830: return_code = msg_send_from_kernel(&request.msgHeader, MSG_OPTION_NONE, 0);
831:
832: if ( return_code == SEND_SUCCESS ) {
833: return kPMUNoError;
834: }
835: else {
836: return kPMUIOError;
837: }
838: }
839:
840:
841: // **********************************************************************************
842: // readNVRAM
843: //
844: // The NVRAM driver is calling to read part of the NVRAM. We translate this into
845: // single-byte PMU commands and enqueue them to our command queue.
846: //
847: // **********************************************************************************
848: - (PMUStatus) readNVRAM :(UInt32)Offset
849: :(UInt32)Length
850: :(UInt8 *)Buffer
851: :(UInt32)RefNum
852: :(id)Id
853: :(pmCallback_func)Callback
854: {
855: PMUmachMessage request;
856: msg_return_t return_code;
857: int i;
858: UInt8 * client_buffer = Buffer;
859: UInt32 our_offset = Offset;
860:
861: if ( (Buffer == NULL) ||
862: (Length == 0) ||
863: (Length > 8192) ||
864: (Offset > 8192) ||
865: ((Length + Offset) > 8192) ) {
866: return kPMUParameterError;
867: }
868:
869: for ( i = 0; i < (Length - 1); i++ ) { // read all but the last byte
870: request.msgBody.pmCommand = kPMUNVRAMRead;
871: request.msgBody.pmFlag = FALSE;
872: request.msgBody.pmSLength1 = 2;
873: request.msgBody.pmSBuffer2 = NULL;
874: request.msgBody.pmSLength2 = 0;
875: request.msgBody.pmRBuffer = client_buffer++;
876: request.msgBody.pmCallback = NULL;
877: request.msgBody.pmSBuffer1[0] = our_offset >> 8;
878: request.msgBody.pmSBuffer1[1] = our_offset++;
879:
880: request.msgHeader.msg_simple = TRUE;
881: request.msgHeader.msg_type = MSG_TYPE_NORMAL;
882: request.msgHeader.msg_remote_port = port;
883: request.msgHeader.msg_local_port = PORT_NULL;
884: request.msgHeader.msg_size = sizeof(PMUmachMessage);
885: return_code = msg_send_from_kernel(&request.msgHeader, MSG_OPTION_NONE, 0);
886:
887: if ( return_code != SEND_SUCCESS ) {
888: return kPMUIOError;
889: }
890: }
891:
892: request.msgBody.pmCommand = kPMUNVRAMRead; // now read last byte
893: request.msgBody.pmFlag = FALSE;
894: request.msgBody.pmSLength1 = 2;
895: request.msgBody.pmSBuffer2 = NULL;
896: request.msgBody.pmSLength2 = 0;
897: request.msgBody.pmRBuffer = client_buffer;
898: request.msgBody.pmRefNum = RefNum;
899: request.msgBody.pmId = Id;
900: request.msgBody.pmCallback = Callback;
901: request.msgBody.pmSBuffer1[0] = our_offset >> 8;
902: request.msgBody.pmSBuffer1[1] = our_offset;
903:
904: request.msgHeader.msg_simple = TRUE;
905: request.msgHeader.msg_type = MSG_TYPE_NORMAL;
906: request.msgHeader.msg_remote_port = port;
907: request.msgHeader.msg_local_port = PORT_NULL;
908: request.msgHeader.msg_size = sizeof(PMUmachMessage);
909: return_code = msg_send_from_kernel(&request.msgHeader, MSG_OPTION_NONE, 0);
910:
911: if ( return_code == SEND_SUCCESS ) {
912: return kPMUNoError;
913: }
914: else {
915: return kPMUIOError;
916: }
917: }
918:
919:
920: // **********************************************************************************
921: // writeNVRAM
922: //
923: // The NVRAM driver is calling to write part of the NVRAM. We translate this into
924: // single-byte PMU commands and enqueue them to our command queue.
925: //
926: // **********************************************************************************
927: - (PMUStatus) writeNVRAM:(UInt32)Offset
928: :(UInt32)Length
929: :(UInt8 *)Buffer
930: :(UInt32)RefNum
931: :(id)Id
932: :(pmCallback_func)Callback
933: {
934: PMUmachMessage request;
935: msg_return_t return_code;
936: int i;
937: UInt32 our_offset = Offset;
938: UInt8 * client_buffer = Buffer;
939:
940: if ( (Buffer == NULL) ||
941: (Length == 0) ||
942: (Length > 8192) ||
943: (Offset > 8192) ||
944: ((Length + Offset) > 8192) ) {
945: return kPMUParameterError;
946: }
947:
948: for ( i = 0; i < (Length - 1); i++ ) { // write all but the last byte
949: request.msgBody.pmCommand = kPMUNVRAMWrite;
950: request.msgBody.pmFlag = FALSE;
951: request.msgBody.pmSLength1 = 3;
952: request.msgBody.pmSBuffer2 = NULL;
953: request.msgBody.pmSLength2 = 0;
954: request.msgBody.pmRBuffer = NULL;
955: request.msgBody.pmCallback = NULL;
956: request.msgBody.pmSBuffer1[0] = our_offset >> 8;
957: request.msgBody.pmSBuffer1[1] = our_offset++;
958: request.msgBody.pmSBuffer1[2] = *client_buffer++;
959:
960: request.msgHeader.msg_simple = TRUE;
961: request.msgHeader.msg_type = MSG_TYPE_NORMAL;
962: request.msgHeader.msg_remote_port = port;
963: request.msgHeader.msg_local_port = PORT_NULL;
964: request.msgHeader.msg_size = sizeof(PMUmachMessage);
965: return_code = msg_send_from_kernel(&request.msgHeader, MSG_OPTION_NONE, 0);
966:
967: if ( return_code != SEND_SUCCESS ) {
968: return kPMUIOError;
969: }
970: }
971:
972: request.msgBody.pmCommand = kPMUNVRAMWrite; // write the last byte
973: request.msgBody.pmFlag = FALSE;
974: request.msgBody.pmSLength1 = 3;
975: request.msgBody.pmSBuffer2 = NULL;
976: request.msgBody.pmSLength2 = 0;
977: request.msgBody.pmRBuffer = NULL;
978: request.msgBody.pmRefNum = RefNum;
979: request.msgBody.pmId = Id;
980: request.msgBody.pmCallback = Callback;
981: request.msgBody.pmSBuffer1[0] = our_offset >> 8;
982: request.msgBody.pmSBuffer1[1] = our_offset;
983: request.msgBody.pmSBuffer1[2] = *client_buffer;
984:
985: request.msgHeader.msg_simple = TRUE;
986: request.msgHeader.msg_type = MSG_TYPE_NORMAL;
987: request.msgHeader.msg_remote_port = port;
988: request.msgHeader.msg_local_port = PORT_NULL;
989: request.msgHeader.msg_size = sizeof(PMUmachMessage);
990: return_code = msg_send_from_kernel(&request.msgHeader, MSG_OPTION_NONE, 0);
991:
992: if ( return_code == SEND_SUCCESS ) {
993: return kPMUNoError;
994: }
995: else {
996: return kPMUIOError;
997: }
998: }
999:
1000:
1001: // **********************************************************************************
1002: // registerForPowerInterrupts
1003: //
1004: // Some driver is calling to say it is prepared to receive "unsolicited" power-system
1005: // interrups (e.g. battery low). The parameter block says who to call when we get one.
1006: //
1007: // **********************************************************************************
1008: - (void)registerForPowerInterrupts :(pmCallback_func)buttonHandler
1009: :(id)caller
1010: {
1011: PWRclient = buttonHandler;
1012: PWRid = caller;
1013: }
1014:
1015:
1016: // **********************************************************************************
1017: // sendMiscCommand
1018: //
1019: // Some driver is calling to send some miscellaneous command. We copy this into a
1020: // PMU command and enqueue it to our command queue.
1021: //
1022: // **********************************************************************************
1023: - (PMUStatus)sendMiscCommand :(UInt32)Command
1024: :(UInt32)SLength
1025: :(UInt8 *)SBuffer
1026: :(UInt8 *)RBuffer
1027: :(UInt32)RefNum
1028: :(id)Id
1029: :(pmCallback_func)Callback
1030: {
1031: PMUmachMessage request;
1032: msg_return_t return_code;
1033: SInt32 rsp_length;
1034: SInt32 send_length;
1035:
1036: rsp_length = rspLengthTable[Command]; // get cmd and response lengths from table
1037: send_length = cmdLengthTable[Command];
1038:
1039: if ( ((SLength != 0) && (SBuffer == NULL)) || // validate pointers
1040: ((rsp_length != 0) && (RBuffer == NULL)) ) {
1041: return kPMUParameterError;
1042: }
1043: if ( (Command != kPMUdownloadFlash) &&
1044: ((send_length != -1) && (send_length != SLength)) ) {
1045: return kPMUParameterError;
1046: }
1047:
1048: if ( send_length > MISC_LENGTH ) {
1049: return kPMUParameterError;
1050: }
1051:
1052: request.msgBody.pmCommand = Command;
1053: request.msgBody.pmFlag = FALSE;
1054: request.msgBody.pmSLength1 = 0;
1055: request.msgBody.pmSBuffer2 = SBuffer;
1056: request.msgBody.pmSLength2 = SLength;
1057: request.msgBody.pmRBuffer = RBuffer;
1058: request.msgBody.pmRefNum = RefNum;
1059: request.msgBody.pmId = Id;
1060: request.msgBody.pmCallback = Callback;
1061:
1062: request.msgHeader.msg_simple = TRUE;
1063: request.msgHeader.msg_type = MSG_TYPE_NORMAL;
1064: request.msgHeader.msg_remote_port = port;
1065: request.msgHeader.msg_local_port = PORT_NULL;
1066: request.msgHeader.msg_size = sizeof(PMUmachMessage);
1067: return_code = msg_send_from_kernel(&request.msgHeader, MSG_OPTION_NONE, 0);
1068:
1069: if ( return_code == SEND_SUCCESS ) {
1070: return kPMUNoError;
1071: }
1072: else {
1073: return kPMUIOError;
1074: }
1075: }
1076:
1077:
1078: // **********************************************************************************
1079: // StartPMUTransmission
1080: //
1081: // Transmission of the command byte is started. The transaction will be
1082: // completed by the Shift Register Interrupt Service Routine.
1083: // **********************************************************************************
1084: - (void)StartPMUTransmission:(PMURequest *)plugInMessage
1085: {
1086: if ( !debugging ) {
1087: clientRequest = plugInMessage;
1088: firstChar = plugInMessage->pmCommand; // get command byte
1089: charCountS1 = plugInMessage->pmSLength1; // get caller's length counters
1090: charCountS2 = plugInMessage->pmSLength2;
1091: dataPointer1 = plugInMessage->pmSBuffer1; // and transmit data pointers
1092: dataPointer2 = plugInMessage->pmSBuffer2;
1093: dataPointer = plugInMessage->pmRBuffer; // set up read pointer for data bytes
1094: charCountR = rspLengthTable[firstChar]; // get response length from table
1095: charCountR2 = charCountR;
1096:
1097: // figure out what happens after command byte transmission
1098: if ( cmdLengthTable[firstChar] < 0 ) { // will we be sending a length byte next?
1099: PGE_ISR_state = kPMUxmtLen; // yes
1100: }
1101: else { // no, will we be sending data next?
1102: if ( cmdLengthTable[firstChar] > 0 ) {
1103: PGE_ISR_state = kPMUxmtData; // yes
1104: }
1105: else { // no, will we be receiving a length byte next?
1106: if ( charCountR < 0 ) {
1107: PGE_ISR_state = kPMUreadLen_cmd; // yes
1108: }
1109: else { // no, will we be receiving data next?
1110: if ( charCountR > 0 ) {
1111: PGE_ISR_state = kPMUreadData; // yes
1112: }
1113: else {
1114: PGE_ISR_state = kPMUdone; // no, this is a single-byte transaction
1115: }
1116: }
1117: }
1118: }
1119: // ready to start the command byte
1120: *VIA1_auxillaryControl |= 0x1C; // set shift register to output
1121: *VIA1_shift = firstChar; // give it the byte (this clears any pending SR interrupt)
1122: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
1123: *VIA2_dataB &= ~PMreq; // assert /REQ
1124: return;
1125:
1126: }
1127: else {
1128: UInt32 i;
1129:
1130: *VIA1_interruptEnable = 0x04; // disable SR interrupt
1131:
1132: firstChar = plugInMessage->pmCommand; // get command byte
1133: charCountS1 = plugInMessage->pmSLength1; // get caller's length counters
1134: charCountS2 = plugInMessage->pmSLength2;
1135: dataPointer1 = plugInMessage->pmSBuffer1; // and transmit data pointers
1136: dataPointer2 = plugInMessage->pmSBuffer2;
1137:
1138: charCountR = rspLengthTable[firstChar]; // get response length from table
1139: charCountR2 = charCountR;
1140:
1141: [self SendPMUByte:firstChar]; // send command byte
1142:
1143: if ( cmdLengthTable[firstChar] < 0 ) { // should we send a length byte?
1144: [self SendPMUByte:(UInt8)(charCountS1 + charCountS2)]; // yes, do it
1145: }
1146:
1147: for ( i = 0; i < charCountS1; i++ ) { // send data bytes
1148: [self SendPMUByte:*dataPointer1++];
1149: }
1150:
1151: for ( i = 0; i < charCountS2; i++ ) { // send more data bytes
1152: [self SendPMUByte:*dataPointer2++];
1153: }
1154: /* charCountR == 0: no reply at all
1155: 1: only a reply byte will be sent by the PGE
1156: <0: a length byte and a reply will be sent
1157: >1: a reply will be sent, but no length byte
1158: (length is charCount - 1)
1159: */
1160: if ( charCountR ) { // receive the reply byte
1161: if ( charCountR == 1 ) {
1162: [self ReadPMUByte:plugInMessage->pmRBuffer];
1163: }
1164: else {
1165: if ( charCountR < 0 ) { // receive the length byte
1166: [self ReadPMUByte:&receivedByte];
1167: charCountR = receivedByte;
1168: }
1169: else {
1170: charCountR--;
1171: }
1172: dataPointer = plugInMessage->pmRBuffer;
1173: for ( i = 0; i < charCountR; i++ ) {
1174: [self ReadPMUByte:dataPointer++]; // receive the rest of the reply
1175: }
1176: }
1177: }
1178:
1179: if ( plugInMessage->pmCallback != NULL ) { // Make the client callback
1180: plugInMessage->pmCallback(plugInMessage->pmId, plugInMessage->pmRefNum, charCountR, plugInMessage->pmRBuffer);
1181: }
1182: return;
1183: }
1184: }
1185:
1186:
1187:
1188: // ****************************************************************************
1189: // interruptOccurred
1190: // The shift register has finished shifting in a byte from PG&E or finished
1191: // shifting out a byte to PG&E. Here we continue the transaction by starting
1192: // the i/o of the next byte, or we finish the transaction by calling the
1193: // client's callback function.
1194: // Both the VIA interrupt flag register and the interrupt enable registers
1195: // have been cleared by the ohare ISR.
1196: // ****************************************************************************
1197:
1198: - (void)interruptOccurred
1199: {
1200: *VIA2_dataB |= PMreq; // deassert /REQ line
1201: // what state are we in?
1202: switch ( PGE_ISR_state ) {
1203: // We are processing a PMU interrupt. We are reading the response
1204: // to the kPMUreadINT command, and a byte has arrived.
1205: case kPMUrcvData_int:
1206: *dataPointer++ = *VIA1_shift; // read the data byte
1207: charCountR2--;
1208: if ( charCountR2 > 0 ) { // is there more to read?
1209: while ( !(*VIA2_dataB & PMack) ) {
1210: }
1211: *VIA2_dataB &= ~PMreq; // yes, assert /REQ
1212: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
1213: return; // next interrupt will be next data byte
1214: }
1215: if ( interruptState[0] & kPMUADBint ) { // no, what kind of interrupt was it?
1216: [self ADBinput: (UInt32)charCountR: &interruptState[0]]; // ADB
1217: }
1218: else {
1219: if ( interruptState[0] & kPMUbattInt ) {
1220: kprintf("battery PGE interrupt\n");
1221: }
1222: else {
1223: if ( interruptState[0] & kPMUoneSecInt ) {
1224: // kprintf("one-second PGE interrupt\n");
1225: if ( RTCclient != NULL ) { // one-second interrupt
1226: RTCclient(RTCid,0,0,0);
1227: }
1228: }
1229: else {
1230: if ( interruptState[0] & kPMUenvironmentInt ) {
1231: kprintf("environment interrupt\n");
1232: }
1233: else {
1234: if ( interruptState[0] & kPMUbrightnessInt ) {
1235: kprintf("brightness button PGE interrupt\n");
1236: }
1237: else {
1238: kprintf("machine-dependent PGE interrupt\n");
1239: }
1240: }
1241: }
1242: }
1243: }
1244: PGE_ISR_state = kPMUidle; // set the state
1245: if ( !PMU_int_pending ) { // is PMU requesting service again?
1246: // if ( !(*VIA1_interruptFlag & 0x10) ) { // is PMU requesting service again? ( ifCB1 )
1247: // if ( queueHead == (PMUmachMessage*)0 ) { // no, queue empty?
1248: // *VIA1_interruptEnable = 0x90; // yes, enable PMU interrupts ( ifCB1 )
1249: // return; // and we are completely idle
1250: // }
1251: [self CheckRequestQueue]; // no, start next queued transaction
1252: }
1253: else {
1254: // *VIA1_interruptFlag = 0x10; // PMU wants service, acknowledge VIA interrupt ( ifCB1 )
1255: PMU_int_pending = FALSE;
1256: *VIA1_auxillaryControl |= 0x1C; // set shift register to output
1257: *VIA1_shift = kPMUreadINT; // give it the command byte
1258: *VIA2_dataB &= ~PMreq; // assert /REQ
1259: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
1260: PGE_ISR_state = kPMUreadLen_int; // set the state
1261: dataPointer = &interruptState[0]; // set up read pointer for data bytes
1262: return; // next interrupt is command byte transmission complete
1263: }
1264: return;
1265:
1266: // We are processing a PMU interrupt.
1267: // We have finished transmitting the kPMUreadINT command byte, and
1268: // according to our table, we will be getting a response and a
1269: // length byte for it. Finish the transmit handshake and set up
1270: case kPMUreadLen_int: // a receive for the length byte.
1271: receivedByte = *VIA1_shift; // read shift reg to turn off SR int
1272: PGE_ISR_state = kPMUrcvLen_int;
1273: *VIA1_auxillaryControl &= 0xEF; // set shift register to input
1274: while ( !(*VIA2_dataB & PMack) ) {
1275: }
1276: *VIA2_dataB &= ~PMreq; // assert /REQ
1277: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
1278: return; // next interrupt will be the length byte
1279:
1280: // We are processing a PMU interrupt.
1281: case kPMUrcvLen_int: // The length byte has arrived. Read it and start data read
1282: charCountR = *VIA1_shift; // read it
1283:
1284: charCountR2 = charCountR;
1285: PGE_ISR_state = kPMUrcvData_int;
1286: while ( !(*VIA2_dataB & PMack) ) {
1287: }
1288: *VIA2_dataB &= ~PMreq; // assert /REQ
1289: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
1290: return; // next interrupt will be the first data byte
1291:
1292: // We are doing a command transaction. The command byte transmission
1293: case kPMUxmtLen: // has completed. Start length byte transmission
1294: PGE_ISR_state = kPMUxmtData;
1295: while ( !(*VIA2_dataB & PMack) ) {
1296: }
1297: *VIA1_shift = (UInt8)(charCountS1 + charCountS2); // give it the length byte
1298: *VIA2_dataB &= ~PMreq; // assert /REQ
1299: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
1300: return; // next interrupt start sending data
1301:
1302: // We are doing a command transaction. A byte transmission has completed.
1303: case kPMUxmtData: // Continue data byte transmission
1304: while ( !(*VIA2_dataB & PMack) ) {
1305: }
1306: if ( charCountS1 ) {
1307: *VIA1_shift = *dataPointer1++; // give it the next data byte from buffer 1
1308: *VIA2_dataB &= ~PMreq; // assert /REQ
1309: if ( --charCountS1 + charCountS2 ) {
1310: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
1311: return; // next interrupt do another byte
1312: }
1313: }
1314: else {
1315: if ( charCountS2 ) {
1316: *VIA1_shift = *dataPointer2++; // buffer 1 empty, give it the next byte from buffer 2
1317: *VIA2_dataB &= ~PMreq; // assert /REQ
1318: if ( --charCountS2 ) {
1319: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
1320: return; // next interrupt do another byte
1321: }
1322: }
1323: }
1324: // sending last byte, what's next?
1325: if ( charCountR < 0 ) {
1326: PGE_ISR_state = kPMUreadLen_cmd; // we will receive a length byte
1327: }
1328: else {
1329: if ( charCountR > 0 ) {
1330: PGE_ISR_state = kPMUreadData; // we will receive constant-length data
1331: }
1332: else {
1333: PGE_ISR_state = kPMUdone; // nothing, we're done
1334: }
1335: }
1336: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
1337: return;
1338:
1339: // We have finished the transmission part of a command transaction, and
1340: // according to our table, we will be getting a response and a
1341: // length byte for it. Finish the transmit handshake and set up
1342: case kPMUreadLen_cmd: // a receive for the length byte.
1343: receivedByte = *VIA1_shift; // read shift reg to turn off SR int
1344: PGE_ISR_state = kPMUrcvLen_cmd;
1345: *VIA1_auxillaryControl &= 0xEF; // set shift register to input
1346: while ( !(*VIA2_dataB & PMack) ) {
1347: }
1348: *VIA2_dataB &= ~PMreq; // assert /REQ
1349: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
1350: return; // next interrupt will be the length byte
1351:
1352: case kPMUrcvLen_cmd: // the length byte has arrived, read it and start data read
1353: charCountR = *VIA1_shift; // read it
1354: charCountR2 = charCountR;
1355: PGE_ISR_state = kPMUrcvData_cmd;
1356: if ( !(*VIA2_dataB & PMack) )
1357: if ( ![self WaitForAckHi] ) {
1358: return; // make sure ACK is high
1359: }
1360: *VIA2_dataB &= ~PMreq; // assert /REQ
1361: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
1362: return; // next interrupt will be the first data byte
1363:
1364:
1365: // We have finished the transmission part of a command transaction, and
1366: // according to our table, we will be getting a response but not a
1367: // length byte for it. Finish the transmit handshake and set up
1368: case kPMUreadData: // a receive for the first data byte.
1369: if ( charCountR > 1 ) {
1370: charCountR2--; // make constant (byte count + 1) into byte count
1371: charCountR--;
1372: }
1373: // receivedByte = *VIA1_shift; // read shift reg to turn off SR int
1374: PGE_ISR_state = kPMUrcvData_cmd;
1375: *VIA1_auxillaryControl &= 0xEF; // set shift register to input
1376: if ( !(*VIA2_dataB & PMack) )
1377: if ( ![self WaitForAckHi] ) {
1378: return; // make sure ACK is high
1379: }
1380: *VIA2_dataB &= ~PMreq; // assert /REQ
1381: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
1382: return; // next interrupt will be the first data character
1383:
1384: // We are reading the response in a command transaction, and
1385: case kPMUrcvData_cmd: // a data byte has arrived
1386: *dataPointer++ = *VIA1_shift; // read the data byte
1387: charCountR2--;
1388: if ( charCountR2 > 0 ) { // is there more to read?
1389: if ( !(*VIA2_dataB & PMack) )
1390: if ( ![self WaitForAckHi] ) {
1391: return; // yes, make sure ACK is high
1392: }
1393: *VIA2_dataB &= ~PMreq; // assert /REQ
1394: return; // next interrupt will be next data byte
1395: }
1396: if ( clientRequest->pmCallback != NULL ) { // no, make the client callback
1397: clientRequest->pmCallback(clientRequest->pmId, clientRequest->pmRefNum, charCountR, clientRequest->pmRBuffer);
1398: }
1399: PGE_ISR_state = kPMUidle; // set the state
1400: if ( !PMU_int_pending ) { // is PMU now requesting service?
1401: // if ( !(*VIA1_interruptFlag & 0x10) ) { // is PMU now requesting service? (ifCB1)
1402: // if ( queueHead == (PMUmachMessage*)0 ) { // no, queue empty?
1403: // *VIA1_interruptEnable = 0x90; // yes, enable PMU interrupts ( ifCB1 )
1404: // return; // and we are completely idle
1405: // }
1406: [self CheckRequestQueue]; // no, start next queued transaction
1407: }
1408: else {
1409: // *VIA1_interruptFlag = 0x10; // PMU wants service, acknowledge VIA interrupt ( ifCB1 )
1410: PMU_int_pending = FALSE;
1411: *VIA1_auxillaryControl |= 0x1C; // set shift register to output
1412: *VIA1_shift = kPMUreadINT; // give it the command byte
1413: *VIA2_dataB &= ~PMreq; // assert /REQ
1414: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
1415: PGE_ISR_state = kPMUreadLen_int; // set the state
1416: dataPointer = &interruptState[0]; // set up read pointer for data bytes
1417: return; // next interrupt is command byte transmission complete
1418: }
1419: return;
1420:
1421: case kPMUdone: // this was the last xmt SR interrupt of a command transaction
1422: // receivedByte = *VIA1_shift; // read shift reg to turn off SR int
1423:
1424: if ( clientRequest->pmFlag ) { // does this command cause input?
1425: PGE_ISR_state = kPMUidle; // yes, set the state
1426: adb_reading = TRUE; // don't do callback now
1427: // who_to_call = clientRequest->pmCallback; // do it after the read completes
1428: // theirId = clientRequest->pmId;
1429: // theirRefNum = clientRequest->pmRefNum;
1430: ns_timeout((func)timer_expired,(void *)port,adb_read_timeout,CALLOUT_PRI_SOFTINT0); // start timer
1431: if ( !PMU_int_pending ) { // is PMU now requesting service?
1432: // if ( !(*VIA1_interruptFlag & 0x10) ) { // is PMU now requesting service? (ifCB1)
1433: // *VIA1_interruptEnable = 0x90; // yes, enable PMU interrupts ( ifCB1 )
1434: return; // and we are completely idle
1435: }
1436: else {
1437: // *VIA1_interruptFlag = 0x10; // PMU wants service, acknowledge VIA interrupt ( ifCB1 )
1438: PMU_int_pending = FALSE;
1439: *VIA1_auxillaryControl |= 0x1C; // set shift register to output
1440: *VIA1_shift = kPMUreadINT; // give it the command byte
1441: *VIA2_dataB &= ~PMreq; // assert /REQ
1442: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
1443: PGE_ISR_state = kPMUreadLen_int; // set the state
1444: dataPointer = &interruptState[0]; // set up read pointer for data bytes
1445: return; // next interrupt is command byte transmission complete
1446: }
1447: }
1448: // not an adb read
1449: if ( clientRequest->pmCallback != NULL ) { // Make the client callback
1450: clientRequest->pmCallback(clientRequest->pmId, clientRequest->pmRefNum, 0, NULL);
1451: }
1452: if ( !PMU_int_pending ) { // is PMU now requesting service?
1453: // if ( !(*VIA1_interruptFlag & 0x10) ) { // is PMU now requesting service? (ifCB1)
1454: // if ( queueHead == (PMUmachMessage*)0 ) { // no, queue empty?
1455: PGE_ISR_state = kPMUidle;
1456: // *VIA1_interruptEnable = 0x90; // yes, enable PMU interrupts ( ifCB1 )
1457: // return; // and we are completely idle
1458: // }
1459: [self CheckRequestQueue]; // no, start next queued transaction
1460: }
1461: else {
1462: *VIA1_interruptFlag = 0x10; // PMU wants service, acknowledge VIA interrupt ( ifCB1 )
1463: PMU_int_pending = FALSE;
1464: *VIA1_auxillaryControl |= 0x1C; // set shift register to output
1465: *VIA1_shift = kPMUreadINT; // give it the command byte
1466: *VIA2_dataB &= ~PMreq; // assert /REQ
1467: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
1468: PGE_ISR_state = kPMUreadLen_int; // set the state
1469: dataPointer = &interruptState[0]; // set up read pointer for data bytes
1470: return; // next interrupt is command byte transmission complete
1471: }
1472: return;
1473: }
1474: return;
1475: }
1476:
1477: // ****************************************************************************
1478: // interruptOccurredAt
1479: // PGE has interrupted. Send the ReadInt command to find out why.
1480: // When the command byte is sent, the Shift Register will interrupt.
1481: // If we are mid-transaction when we find out about the interrupt,
1482: // set a flag and find out why later.
1483: //
1484: // ****************************************************************************
1485:
1486: - (void)interruptOccurredAt:(int)localInterrupt
1487: {
1488: if ( PGE_ISR_state != kPMUidle ) {
1489: PMU_int_pending = TRUE;
1490: return;
1491: }
1492: if ( !debugging ) {
1493: // make sure ACK is high
1494: // *VIA1_interruptFlag = 0x10; // acknowledge VIA interrupt ( ifCB1 )
1495: // *VIA1_interruptEnable = 0x10; // and disable it entirely ( ifCB1 )
1496: while ( !(*VIA2_dataB & PMack) ) {
1497: }
1498: *VIA1_auxillaryControl |= 0x1C; // set shift register to output
1499: *VIA1_shift = kPMUreadINT; // give it the command byte
1500: *VIA2_dataB &= ~PMreq; // assert /REQ
1501: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
1502: PGE_ISR_state = kPMUreadLen_int; // set the state
1503: dataPointer = &interruptState[0]; // set up read pointer for data bytes
1504: return; // return till character transmission completes
1505: }
1506: else {
1507: PMURequest getInterruptState; // debug mode PMU interrupt handler
1508:
1509: // [self AcknowledgePMUInterrupt]; // turn off VIA interrupt
1510: *VIA1_interruptEnable = 0x04; // disable SR interrupt
1511:
1512: getInterruptState.pmCommand = kPMUreadINT; // find out cause of interrupt from PGE
1513: getInterruptState.pmFlag = FALSE;
1514: getInterruptState.pmSLength1 = 0;
1515: getInterruptState.pmSLength2 = 0;
1516: getInterruptState.pmRBuffer = &interruptState[0];
1517: getInterruptState.pmCallback = gotInterruptCause;
1518: getInterruptState.pmId = self;
1519:
1520: [self StartPMUTransmission:&getInterruptState];
1521: }
1522: }
1523:
1524:
1525: // ****************************************************************************
1526: // gotInterruptCause
1527: //
1528: // Called by the debug-mode PMU interrupt handler as the Callback function
1529: // after sending the kPMUreadInt command and receiving its response
1530: // ****************************************************************************
1531: void gotInterruptCause(id PMUdriver, UInt32 unused, UInt32 length, UInt8 * data)
1532: {
1533: UInt8 interruptSource;
1534:
1535: interruptSource = *data;
1536:
1537: if ( interruptSource & kPMUADBint ) {
1538: [PMUdriver ADBinput: length: data];
1539: }
1540: else {
1541: if ( interruptSource & kPMUbattInt ) {
1542: IOLog("battery PGE interrupt");
1543: }
1544: else {
1545: if ( interruptSource & kPMUoneSecInt ) {
1546: IOLog("one-second PGE interrupt");
1547: }
1548: else {
1549: if ( interruptSource & kPMUenvironmentInt ) {
1550: IOLog("environment interrupt");
1551: }
1552: else {
1553: if ( interruptSource & kPMUbrightnessInt ) {
1554: IOLog("brightness button PGE interrupt");
1555: }
1556: else {
1557: IOLog("machine-dependent PGE interrupt");
1558: }
1559: }
1560: }
1561: }
1562: }
1563: }
1564:
1565:
1566: // ****************************************************************************
1567: // SendPMUByte
1568: // ****************************************************************************
1569: - (void)SendPMUByte:(UInt8)theByte
1570: {
1571: *VIA1_auxillaryControl |= 0x1C; // set shift register to output
1572: eieio();
1573: *VIA1_shift = theByte; // give it the byte
1574: eieio();
1575: *VIA2_dataB &= ~PMreq; // assert /REQ
1576: eieio();
1577: if ( [self WaitForAckLo] ) { // ack now low
1578: *VIA2_dataB |= PMreq; // deassert /REQ line
1579: eieio();
1580: if ( ! [self WaitForAckHi] ) {
1581: return;
1582: }
1583: }
1584: else {
1585: *VIA2_dataB |= PMreq; // deassert /REQ line
1586: eieio();
1587: return;
1588: }
1589: return;
1590: }
1591:
1592:
1593: // ****************************************************************************
1594: // ReadPMUByte
1595: // ****************************************************************************
1596: - (void)ReadPMUByte:(UInt8 *)theByte
1597: {
1598: *VIA1_auxillaryControl |= 0x0C; // set shift register to input
1599: *VIA1_auxillaryControl &= ~0x10;
1600: *theByte = *VIA1_shift; // read a byte to reset shift reg
1601: eieio();
1602: *VIA2_dataB &= ~PMreq; // assert /REQ
1603: eieio();
1604: if ( [self WaitForAckLo] ) { // ack now low
1605: *VIA2_dataB |= PMreq; // deassert /REQ line
1606: eieio();
1607: if ( [self WaitForAckHi] ) { // wait for /ACK high
1608: *theByte = *VIA1_shift; // got it, read the byte
1609: eieio();
1610: }
1611: else {
1612: return;
1613: }
1614: }
1615: else {
1616: *VIA2_dataB |= PMreq; // deassert /REQ line
1617: eieio();
1618: return;
1619: }
1620: return;
1621: }
1622:
1623:
1624: // ****************************************************************************
1625: // WaitForAckLo
1626: // ****************************************************************************
1627: - (Boolean)WaitForAckLo
1628: {
1629: struct timeval startTime;
1630: struct timeval currentTime;
1631: ns_time_t x;
1632:
1633: // wait up to 32 milliseconds for Ack signal from PG&E to go low
1634:
1635: IOGetTimestamp(&x);
1636: ns_time_to_timeval(x, &startTime); // get current time
1637:
1638: while ( TRUE ) {
1639: if ( !(*VIA2_dataB & PMack) ) {
1640: return ( TRUE ); // ack is low, return
1641: }
1642: IOGetTimestamp(&x);
1643: ns_time_to_timeval(x, ¤tTime);
1644: if ( startTime.tv_usec > currentTime.tv_usec ) {
1645: currentTime.tv_usec += 1000000; // clock has wrapped, adjust it
1646: }
1647: if ( currentTime.tv_usec > (startTime.tv_usec + 32000) ) { // has 32 ms elapsed?
1648: return ( FALSE ); // yes, return
1649: }
1650: }
1651: }
1652:
1653:
1654: // ****************************************************************************
1655: // WaitForAckHi
1656: // ****************************************************************************
1657: - (Boolean)WaitForAckHi
1658: {
1659: struct timeval startTime;
1660: struct timeval currentTime;
1661: ns_time_t x;
1662:
1663: // wait up to 32 milliseconds for Ack signal from PG&E to go high
1664:
1665: IOGetTimestamp(&x);
1666: ns_time_to_timeval(x, &startTime); // get current time
1667:
1668: while ( TRUE ) {
1669: if ( *VIA2_dataB & PMack ) {
1670: return ( TRUE ); // ack is high, return
1671: }
1672: IOGetTimestamp(&x);
1673: ns_time_to_timeval(x, ¤tTime);
1674: if ( startTime.tv_usec > currentTime.tv_usec ) {
1675: currentTime.tv_usec += 1000000; // clock has wrapped, adjust it
1676: }
1677: if ( currentTime.tv_usec > (startTime.tv_usec + 32000) ) { // has 32 ms elapsed?
1678: return ( FALSE ); // yes, return
1679: }
1680: }
1681: }
1682:
1683:
1684: // ****************************************************************************
1685: // GetPMUInterruptState
1686: // ****************************************************************************
1687: - (UInt8)GetPMUInterruptState
1688: { // return current state of CB1 int enable
1689: return (*VIA1_interruptEnable & (1<<ifCB1));
1690: }
1691:
1692:
1693: // ****************************************************************************
1694: // RestorePMUInterrupt
1695: // ****************************************************************************
1696: - (void)RestorePMUInterrupt:(UInt8)savedValue
1697: {
1698: if ( savedValue ) { // restore VIA interrupt state
1699: *VIA1_interruptEnable = savedValue | 0x80;
1700: }
1701: eieio();
1702: }
1703:
1704:
1705: // ****************************************************************************
1706: // DisablePMUInterrupt
1707: // ****************************************************************************
1708: - (void)DisablePMUInterrupt
1709: {
1710: *VIA1_interruptEnable = 1<<ifCB1;
1711: eieio();
1712: }
1713:
1714:
1715: // ****************************************************************************
1716: // EnablePMUInterrupt
1717: // ****************************************************************************
1718: - (void)EnablePMUInterrupt
1719: {
1720: *VIA1_interruptEnable = (1<<ifCB1) | 0x80;
1721: eieio();
1722: }
1723:
1724:
1725: // ****************************************************************************
1726: // AcknowledgePMUInterrupt
1727: // ****************************************************************************
1728: - (void)AcknowledgePMUInterrupt
1729: {
1730: *VIA1_interruptFlag = 1<<ifCB1;
1731: eieio();
1732: }
1733:
1734:
1735: // ****************************************************************************
1736: // GetSRInterruptState
1737: // ****************************************************************************
1738: - (UInt8)GetSRInterruptState
1739: { // return current state of SR int enable
1740: return (*VIA1_interruptEnable & (1<<ifSR));
1741: }
1742:
1743:
1744: // ****************************************************************************
1745: // RestoreSRInterrupt
1746: // ****************************************************************************
1747: - (void)RestoreSRInterrupt:(UInt8)savedValue
1748: {
1749: if ( savedValue ) { // restore SR interrupt state
1750: *VIA1_interruptEnable = savedValue | 0x80;
1751: eieio();
1752: }
1753: }
1754:
1755:
1756: // ****************************************************************************
1757: // DisableSRInterrupt
1758: // ****************************************************************************
1759: - (void)DisableSRInterrupt
1760: {
1761: *VIA1_interruptEnable = 1<<ifSR;
1762: }
1763:
1764:
1765: // ****************************************************************************
1766: // EnableSRInterrupt
1767: // ****************************************************************************
1768: - (void)EnableSRInterrupt
1769: {
1770: *VIA1_interruptEnable = (1<<ifSR) | 0x80;
1771: }
1772:
1773:
1774:
1775: // ****************************************************************************
1776: // timer_expired
1777: //
1778: // Our adb-read timer has expired, so we have to notify our i/o thread by
1779: // enqueuing a Timeout message to its interrupt port.
1780: // ****************************************************************************
1781: void timer_expired(port_t mach_port)
1782: {
1783: PMUmachMessage request;
1784:
1785: request.msgHeader.msg_simple = TRUE;
1786: request.msgHeader.msg_type = MSG_TYPE_NORMAL;
1787: request.msgHeader.msg_id = IO_TIMEOUT_MSG;
1788: request.msgHeader.msg_remote_port = mach_port;
1789: request.msgHeader.msg_local_port = PORT_NULL;
1790: request.msgHeader.msg_size = sizeof(msg_header_t);
1791: msg_send_from_kernel(&request.msgHeader, MSG_OPTION_NONE, 0);
1792:
1793: }
1794:
1795:
1796: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.