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