|
|
1.1 root 1: /*
2: * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: #include <IOKit/IOPlatformExpert.h>
23: #include <IOKit/IODeviceTreeSupport.h>
24: extern "C" {
25: #include <machine/machine_routines.h>
26: #include <kern/clock.h>
27: }
28: #include <IOKit/assert.h>
29: #include <IOKit/IOSyncer.h>
30:
31: #include "pmupriv.h"
32: #include "pmutables.h"
33: #include "IOPMUADBController.h"
34: #include "IOPMUNVRAMController.h"
35: #include "IOPMURTCController.h"
36: //#include "IOPMUPwrController.h"
37:
38: //extern void kprintf(const char *, ...);
39:
40: void receiveMsg ( OSObject * unused, void * newRequest, void * unused1,
41: void * unused2, void * unused3 );
42: //void shiftRegisterInt ( OSObject * PMUdriver, IOInterruptEventSource * unused, int alsoUnused );
43: void commandDoneInt ( OSObject * PMUdriver, IOInterruptEventSource * unused, int alsoUnused );
44: void unsolicitedInt ( OSObject * PMUdriver, IOInterruptEventSource * unused, int alsoUnused );
45:
46: void PMUint ( OSObject * PMUdriver, IOInterruptEventSource * unused, int alsoUnused );
47: void serviceShiftRegister ( ApplePMU * );
48:
49: static int PMU_PE_poll_input ( unsigned int, char * );
50: static int PMU_PE_halt_restart ( unsigned int type );
51: static int PMU_PE_write_IIC ( unsigned char, unsigned char, unsigned char );
52: static int PMU_PE_read_write_time_of_day ( unsigned int, long * );
53:
54: // Interrupt Vectors
55: #define VIA_DEV_VIA0 2
56: #define VIA_DEV_VIA2 4
57:
58: #define super IOService
59: OSDefineMetaClassAndStructors(ApplePMU,IOService)
60:
61: static ApplePMU * gOurself;
62:
63: // **********************************************************************************
64: // init
65: //
66: // **********************************************************************************
67: bool ApplePMU::init ( OSDictionary * properties = 0 )
68: {
69: return super::init(properties);
70: }
71:
72:
73: // **********************************************************************************
74: // start
75: //
76: // **********************************************************************************
77: bool ApplePMU::start ( IOService * nub )
78: {
79: IOMemoryMap * viaMap;
80: unsigned char * physicalAddress;
81: PMUrequest theRequest;
82:
83: workLoop = NULL;
84: commandQueue = NULL;
85: //SRintEventSrc = NULL;
86: cmdDoneEventSrc = NULL;
87: unsolicitedEventSrc = NULL;
88: PMUintEventSrc = NULL;
89: ourADBinterface = NULL;
90: ourRTCinterface = NULL;
91: /*
92: ourNVRAMinterface = NULL;
93: ourPwrinterface = NULL;
94: */
95: ADBclient = NULL;
96: RTCclient = NULL;
97: queueHead = NULL;
98: queueTail = NULL;
99: PGE_ISR_state = kPMUidle;
100: adb_reading = false;
101: PMU_int_pending = false;
102:
103: adb_read_timeout.tv_sec = 0;
104: adb_read_timeout.tv_nsec = 100000000;
105:
106: gOurself = this;
107:
108: if( 0 == (viaMap = nub->mapDeviceMemoryWithIndex( 0 )) ) {
109: IOLog("%s: no via memory\n", getName());
110: return false;
111: }
112: physicalAddress = (unsigned char *)viaMap->getVirtualAddress();
113:
114: //kprintf("VIA base = %08x\n", (UInt32)physicalAddress);
115:
116: VIA1_shift = physicalAddress + 0x1400; // initialize VIA addresses
117: VIA1_auxillaryControl = physicalAddress + 0x1600;
118: VIA1_interruptFlag = physicalAddress + 0x1A00;
119: VIA1_interruptEnable = physicalAddress + 0x1C00;
120: VIA2_dataB = physicalAddress + 0x0000;
121:
122: PMreq = 1 << HooperReq;
123: PMack = 1 << HooperAck;
124:
125: // max to wait for ack low after SR interrupt, 100us
126: clock_interval_to_absolutetime_interval(100, 1000, &SR_to_ack_transition_delay);
127:
128: workLoop = IOWorkLoop::workLoop(); // make the workloop
129: if ( !workLoop ) {
130: kprintf("can't create workloop\n");
131: return false;
132: }
133: // make the command queue
134: commandQueue = IOCommandQueue::commandQueue(this, receiveMsg);
135: if (!commandQueue ||
136: (workLoop->addEventSource(commandQueue) != kIOReturnSuccess) ) { // add it to the workloop
137: kprintf("can't create or add commandQueue\n");
138: return false;
139: }
140: #if 0
141: // make the shift register interrupt source
142: SRintEventSrc = IOInterruptEventSource::
143: interruptEventSource(this, shiftRegisterInt, nub, VIA_DEV_VIA0);
144: if ( !SRintEventSrc ||
145: (workLoop->addEventSource(SRintEventSrc) != kIOReturnSuccess) ) { // add it to the workloop
146: kprintf("can't create or add SRintEventSrc\n");
147: return false;
148: }
149: #endif
150:
151: nub->registerInterrupt(VIA_DEV_VIA0,this,(IOInterruptAction) serviceShiftRegister);
152: nub->enableInterrupt(VIA_DEV_VIA0);
153:
154: // make the command-done interrupt source
155: cmdDoneEventSrc = IOInterruptEventSource::interruptEventSource(this, commandDoneInt);
156: if ( !cmdDoneEventSrc || // add it to the workloop
157: (workLoop->addEventSource(cmdDoneEventSrc) != kIOReturnSuccess) ) {
158: kprintf("can't create or add cmdDoneEventSrc\n");
159: return false;
160: }
161:
162: // make the unsolicited interrupt source
163: unsolicitedEventSrc = IOInterruptEventSource::interruptEventSource(this, unsolicitedInt);
164: if ( !unsolicitedEventSrc || // add it to the workloop
165: (workLoop->addEventSource(unsolicitedEventSrc) != kIOReturnSuccess) ) {
166: kprintf("can't create or add unsolicitedEventSrc\n");
167: return false;
168: }
169: // make the PMU interrupt source
170: PMUintEventSrc = IOInterruptEventSource::
171: interruptEventSource(this, PMUint, nub, VIA_DEV_VIA2);
172: if ( !PMUintEventSrc ||
173: (workLoop->addEventSource(PMUintEventSrc) != kIOReturnSuccess) ) { // add it to the workloop
174: kprintf("can't create or add PMUintEventSrc\n");
175: return false;
176: }
177:
178: AcknowledgePMUInterrupt(); // turn off any pending PGE interrupt
179: workLoop->enableAllInterrupts(); // enable interrupt delivery
180: EnablePMUInterrupt(); // enable PGE interrupts
181: EnableSRInterrupt();
182:
183: theRequest.sync = IOSyncer::create();
184: theRequest.pmCommand = kPMUSetModem1SecInt; // tell PGE why it may interrupt
185: theRequest.pmFlag = false;
186: theRequest.pmSLength1 = 1;
187: //theRequest.pmSBuffer1[0] = kPMUMD2Int | kPMUbrightnessInt | kPMUADBint;
188: theRequest.pmSBuffer1[0] = kPMUMD2Int | kPMUbrightnessInt | kPMUADBint | kPMUoneSecInt;
189: theRequest.pmSLength2 = 0;
190: commandQueue->enqueueCommand(true, &theRequest);
191: theRequest.sync->wait(); // wait till done
192:
193: theRequest.sync = IOSyncer::create();
194: theRequest.pmCommand = kPMUreadINT; // read any pending interrupt from PGE
195: theRequest.pmFlag = false;
196: theRequest.pmSLength1 = 0; // just to clear it
197: theRequest.pmSLength2 = 0;
198: theRequest.pmRBuffer = &interruptState[0];
199: commandQueue->enqueueCommand(true, &theRequest);
200: theRequest.sync->wait(); // wait till done
201:
202: // initialize our interfaces
203:
204: // Do not create the IOPMUADBController if the no-adb property is set.
205: if (!nub->getProperty("no-adb")) {
206: ourADBinterface = new IOPMUADBController;
207: if ( !ourADBinterface ) {
208: return false;
209: }
210: if ( !ourADBinterface->init(0,this) ) {
211: return false;
212: }
213: if ( !ourADBinterface->attach( this) ) {
214: return false;
215: }
216: }
217:
218: // Do not create the IOPMUNVRAMController if the no-nvram property is set.
219: if (!nub->getProperty("no-nvram")) {
220: ourNVRAMinterface = new IOPMUNVRAMController;
221: if ( !ourNVRAMinterface ) {
222: return false;
223: }
224: if ( !ourNVRAMinterface->init(0,this) ) {
225: return false;
226: }
227: if ( !ourNVRAMinterface->attach( this) ) {
228: return false;
229: }
230: }
231:
232:
233: ourRTCinterface = new IOPMURTCController;
234: if ( !ourRTCinterface ) {
235: return false;
236: }
237: if ( !ourRTCinterface->init(0,this) ) {
238: return false;
239: }
240:
241: /*
242: ourPwrinterface = new IOPMUPwrController;
243: if ( !ourPwrinterface ) {
244: return false;
245: }
246: if ( !ourPwrinterface->init(ourRegEntry,this) ) {
247: return false;
248: }
249: */
250:
251: if (ourADBinterface) ourADBinterface->start( this );
252: if (ourNVRAMinterface) ourNVRAMinterface->start( this );
253: if (ourRTCinterface) ourRTCinterface->start( this );
254: if (ourRTCinterface) {
255: PE_read_write_time_of_day = PMU_PE_read_write_time_of_day;
256: }
257:
258: PE_poll_input =PMU_PE_poll_input;
259: PE_halt_restart =PMU_PE_halt_restart;
260: PE_write_IIC = PMU_PE_write_IIC;
261:
262: /* are these even implemented? */
263: publishResource( "IOiic0", this );
264: publishResource( "IORTC", this );
265:
266: OSSerializer * infoSerializer = OSSerializer::forTarget(
267: (void *) this, &serializeBatteryInfo );
268: if( infoSerializer) {
269: IORegistryEntry * entry;
270: if( (entry = IORegistryEntry::fromPath("mac-io/battery",
271: gIODTPlane))) {
272: entry->setProperty( kIOBatteryInfoKey, infoSerializer );
273: entry->release();
274: }
275: infoSerializer->release();
276: }
277:
278: publishResource(kPMUname, this);
279:
280: return true;
281: }
282:
283:
284: // *****************************************************************************
285: // getWorkLoop
286: //
287: // Return the PMU's workloop.
288: //
289: // *****************************************************************************
290: IOWorkLoop *ApplePMU::getWorkLoop() const
291: {
292: return workLoop;
293: }
294:
295: // *****************************************************************************
296: // free
297: //
298: // Release everything we may have allocated.
299: //
300: // *****************************************************************************
301: void ApplePMU::free ( void )
302: {
303: if ( workLoop ) {
304: workLoop->release();
305: }
306: if ( commandQueue ) {
307: commandQueue->release();
308: }
309: #if 0
310: if ( SRintEventSrc ) {
311: SRintEventSrc->release();
312: }
313: #endif
314: if ( cmdDoneEventSrc ) {
315: cmdDoneEventSrc->release();
316: }
317: if ( unsolicitedEventSrc ) {
318: unsolicitedEventSrc->release();
319: }
320: if ( PMUintEventSrc ) {
321: PMUintEventSrc->release();
322: }
323: if ( ourADBinterface ) {
324: ourADBinterface->release();
325: }
326: if ( ourNVRAMinterface ) {
327: ourNVRAMinterface->release();
328: }
329:
330: if ( ourRTCinterface ) {
331: ourRTCinterface->release();
332: }
333: /*
334: if ( ourPwrinterface ) {
335: ourPwrinterface->release();
336: }
337: */
338: super::free();
339: }
340:
341:
342: // **********************************************************************************
343: // PMU_PE_halt_restart
344: //
345: // **********************************************************************************
346: static int PMU_PE_halt_restart ( unsigned int type )
347: {
348: PMUrequest theRequest;
349: UInt8 reply_byte;
350:
351: switch( type ) {
352:
353: case kPERestartCPU:
354: theRequest.sync = IOSyncer::create();
355: theRequest.pmCommand = kPMUresetCPU;
356: theRequest.pmFlag = false;
357: theRequest.pmSLength1 = 0;
358: theRequest.pmSLength2 = 0;
359: theRequest.pmRBuffer = &reply_byte;
360: gOurself->enqueueCommand(&theRequest);
361: theRequest.sync->wait(); // wait till done
362: break;
363:
364: case kPEHaltCPU:
365: theRequest.sync = IOSyncer::create();
366: theRequest.pmCommand = kPMUPmgrPWRoff;
367: theRequest.pmFlag = false;
368: theRequest.pmSLength1 = 4;
369: theRequest.pmSBuffer1[0] = 'M';
370: theRequest.pmSBuffer1[1] = 'A';
371: theRequest.pmSBuffer1[2] = 'T';
372: theRequest.pmSBuffer1[3] = 'T';
373: theRequest.pmSLength2 = 0;
374: theRequest.pmRBuffer = &reply_byte;
375: gOurself->enqueueCommand(&theRequest);
376: theRequest.sync->wait(); // wait till done
377: break;
378:
379: default:
380: return 1;
381: }
382:
383: // workaround 2377033; avoid memory accesses after this point
384: ml_set_interrupts_enabled(false);
385: while(true) {}
386:
387: return 1;
388: }
389:
390:
391: // **********************************************************************************
392: // PMU_PE_read_write_time_of_day
393: //
394: // **********************************************************************************
395: static int PMU_PE_read_write_time_of_day ( unsigned int options, long * secs )
396: {
397: UInt8 currentTime[8];
398: IOByteCount length,i;
399: long longTime = 0;
400:
401: if( (options == kPEReadTOD) && (gOurself->ourRTCinterface != NULL) )
402: {
403: gOurself->ourRTCinterface->getRealTimeClock(currentTime,&length);
404:
405: for ( i = 0; i < length; i++ )
406: {
407: longTime |= currentTime[i] << ((length-i-1)*8);
408: }
409: *secs = longTime;
410: }
411:
412: if( (options == kPEWriteTOD) && (gOurself->ourRTCinterface != NULL) )
413: {
414: gOurself->ourRTCinterface->setRealTimeClock((UInt8 *)secs);
415: }
416:
417: return 0;
418: }
419:
420:
421: // **********************************************************************************
422: // PMU_PE_write_IIC
423: //
424: // **********************************************************************************
425: static int PMU_PE_write_IIC ( unsigned char, unsigned char, unsigned char )
426: {
427: kprintf ("PMU_PE_write_IIC - ");
428:
429: return 1;
430: }
431:
432:
433: // **********************************************************************************
434: // PMU_PE_poll_input
435: //
436: // System interrupts are disabled, but we are still operating the PMU for mini-
437: // monitor keyboard input. We are called here in a loop to service the PMU.
438: //
439: // **********************************************************************************
440: static int PMU_PE_poll_input ( unsigned int, char * )
441: {
442: return 1; // XXX -- svail: what is the correct value???
443: }
444:
445: #if 0
446: // **********************************************************************************
447: // poll_device
448: //
449: // System interrupts are disabled, but we are still operating the PMU for mini-
450: // monitor keyboard input. We are called here in a loop to service the PMU.
451: //
452: // **********************************************************************************
453: void ApplePMU::poll_device( void )
454: {
455: if ( *VIA1_interruptFlag & 0x04 ) { // is shift register done? ( ifSR )
456: serviceShiftRegister(); // yes, handle it
457: return;
458: }
459: if ( *VIA1_interruptFlag & 0x10 ) { // is PMU requesting service? ( ifCB1 )
460: *VIA1_interruptFlag = 0x10; // yes, clear interrupt ( ifCB1 )
461: PGE_ISR_state = kPMUidle; // and handle it
462: servicePMU();
463: }
464: }
465: #endif
466:
467: // **********************************************************************************
468: // receiveMsg
469: //
470: //
471: //
472: // **********************************************************************************
473: void receiveMsg ( OSObject * theDriver, void * newRequest, void *, void *, void * )
474: {
475: ApplePMU * PMUdriver = (ApplePMU *) theDriver;
476:
477: if ( (PMUdriver->PGE_ISR_state == kPMUidle) && !PMUdriver->adb_reading ) {
478: PMUdriver->StartPMUTransmission((PMUrequest *)newRequest);
479: }
480: else {
481: ((PMUrequest *) newRequest)->prev = PMUdriver->queueTail;
482: ((PMUrequest *) newRequest)->next = NULL;
483: if ( PMUdriver->queueTail != NULL ) {
484: PMUdriver->queueTail->next = (PMUrequest *) newRequest;
485: }
486: else {
487: PMUdriver->queueHead = (PMUrequest *)newRequest;
488: }
489: PMUdriver->queueTail = (PMUrequest *)newRequest;
490: }
491: }
492:
493:
494: // **********************************************************************************
495: // timeoutOccurred
496: //
497: // Our adb-read timer has expired after sending an adb-read command to the PMU.
498: // This means there is no such addressed device on the ADB bus.
499: // We call back to the ADB driver with a zero-characters-received response and
500: // dequeue our command queue and carry on.
501: // **********************************************************************************
502: void ApplePMU::timeoutOccurred ( void )
503: {
504: adb_reading = false;
505: clientRequest->pmRLength = 0; // nothing was read
506: clientRequest->sync->signal(); // unblock the caller
507: clientRequest = 0;
508: CheckRequestQueue();
509: }
510:
511:
512: // ****************************************************************************
513: // CheckRequestQueue
514: // Called at interrupt time when current request is complete. We start
515: // another request here if one is in queue.
516: // ****************************************************************************
517: void ApplePMU::CheckRequestQueue ( void )
518: {
519: PMUrequest * nextRequest;
520:
521: if ( queueHead != NULL ) { // is queue empty?
522: nextRequest = queueHead; // no, dequeue first command
523: queueHead = nextRequest->next;
524: if ( queueHead == NULL ) {
525: queueTail = NULL;
526: }
527: StartPMUTransmission(nextRequest); // and send it to the PMU
528: }
529: }
530:
531:
532: // **********************************************************************************
533: // enqueueCommand
534: //
535: // **********************************************************************************
536: void ApplePMU::enqueueCommand ( PMUrequest * request )
537: {
538: commandQueue->enqueueCommand(true,request);
539: }
540:
541:
542: // **********************************************************************************
543: // ADBinput
544: //
545: // The PGE has interrupted with ADB data. We package this up and send
546: // it to our ADB client, if there is one, either as the result to its previous
547: // read command, or as autopoll data.
548: //
549: // **********************************************************************************
550: void ApplePMU::ADBinput(UInt32 theLength, UInt8 * theInput)
551: {
552: if ( theInput[0] & kPMUautopoll ) { // autopoll data?
553: if ( ADBclient != NULL ) {
554: // kprintf("autopoll: %d %02x %02x %02x %02x\n", theLength, theInput[0], theInput[1], theInput[2], theInput[3]);
555:
556: (* ADBclient)(ADBid, theInput[1], theLength-2, theInput+2 );// yes, call adb input handler
557: }
558: return;
559: }
560: if ( adb_reading ) { // no, expecting adb input?
561: if ( clientRequest->pmSBuffer1[0] == theInput[1] ) { // yes, is it our input?
562: // q8q // yes, turn off our timer
563: clientRequest->pmRLength = theLength-2; // this much was read
564: clientRequest->pmRBuffer = theInput+2; // to here
565: clientRequest->sync->signal(); // unblock the caller
566: clientRequest = 0;
567: adb_reading = false;
568: return;
569: }
570: }
571: kprintf("unexpected adb input: %02d %02x %02x %02x %02x %02x\n", theLength, theInput[0], theInput[1], theInput[2], theInput[3], clientRequest->pmSBuffer1[0]);
572: }
573:
574:
575: // **********************************************************************************
576: // registerForADBInterrupts
577: //
578: // Some driver is calling to say it is prepared to receive "unsolicited" adb
579: // interrupts (e.g. autopoll keyboard and trackpad data). The parameters identify
580: // who to call when we get one.
581: // **********************************************************************************
582: void ApplePMU::registerForADBInterrupts ( ADB_callback_func client, IOService * caller )
583: {
584: ADBclient = client;
585: ADBid = caller;
586: }
587:
588:
589: // **********************************************************************************
590: // registerForPowerInterrupts
591: //
592: // Some driver is calling to say it is prepared to receive "unsolicited" power-system
593: // interrupts (e.g. battery low). The parameters identify who to call when we get one.
594: // **********************************************************************************
595: void ApplePMU::registerForPowerInterrupts ( pmCallback_func buttonHandler, IOService * caller )
596: {
597: PWRclient = buttonHandler;
598: PWRid = caller;
599: }
600:
601:
602: // **********************************************************************************
603: // registerForClockInterrupts
604: //
605: // Some driver is calling to say it is prepared to receive "unsolicited" real-time clock
606: // interrupts (e.g. one-second tick). The parameters identify who to call when we get one.
607: // **********************************************************************************
608: void ApplePMU::registerForClockInterrupts ( pmCallback_func tickHandler, IOService * caller )
609: {
610: RTCclient = tickHandler;
611: RTCid = caller;
612: }
613:
614:
615: // **********************************************************************************
616: // buttonInput
617: //
618: // The PGE has interrupted with Brightness/Contrast data. We package this up and send
619: // it to our Display client, if there is one.
620: //
621: // **********************************************************************************
622: void ApplePMU::buttonInput ( UInt32 theLength, UInt8 * theInput )
623: {
624: if ( PWRclient != NULL ) {
625: (* PWRclient)(PWRid, theLength-1, theInput+1);
626: }
627: }
628:
629: // **********************************************************************************
630:
631: bool ApplePMU::serializeBatteryInfo( void * target, void * ref, OSSerialize * s )
632: {
633: UInt32 flags, current, capacity;
634: OSArray * array;
635: OSDictionary * dict;
636: OSNumber * num;
637: UInt32 battery;
638: UInt8 data[16];
639: IOByteCount readLen;
640: IOReturn err;
641: bool ok = true;
642:
643: array = OSArray::withCapacity(2);
644: if( !array)
645: return( false );
646:
647: for( battery = 1; battery <= 2; battery++) {
648: data[0] = battery;
649: err = ((ApplePMU *) target)->sendMiscCommand( kPMUGetSOB,
650: 1, data, &readLen, data );
651: if( kIOReturnSuccess == err) {
652: switch( data[0] ) {
653: case 3:
654: case 4:
655: current = data[2];
656: capacity = data[3];
657: break;
658: case 5:
659: current = (data[2] << 8) | data[3];
660: capacity = (data[4] << 8) | data[5];
661: break;
662: default:
663: continue;
664: }
665: flags = data[1];
666: dict = OSDictionary::withCapacity(2);
667: if( !dict)
668: continue;
669: num = OSNumber::withNumber(flags, 32);
670: if( num) {
671: dict->setObject(kIOBatteryFlagsKey, num);
672: num->release();
673: }
674: num = OSNumber::withNumber(current, 32);
675: if( num) {
676: dict->setObject(kIOBatteryCurrentChargeKey, num);
677: num->release();
678: }
679: num = OSNumber::withNumber(capacity, 32);
680: if( num) {
681: dict->setObject(kIOBatteryCapacityKey, num);
682: num->release();
683: }
684: array->setObject( dict );
685: dict->release();
686: }
687: }
688:
689: ok = array->serialize(s);
690: array->release();
691:
692: return( ok );
693: }
694:
695:
696: // **********************************************************************************
697: // sendMiscCommand
698: //
699: // Some driver is calling to send some miscellaneous command. We copy this into a
700: // PMU command and enqueue it to our command queue.
701: //
702: // The read-length parameter is ignored on entry. On exit it is set to the number
703: // of bytes read in response to transmission of the command.
704: // **********************************************************************************
705: IOReturn ApplePMU::sendMiscCommand ( UInt32 Command, IOByteCount SLength,
706: UInt8 * SBuffer, IOByteCount * RLength, UInt8 * RBuffer )
707: {
708: PMUrequest request;
709: SInt32 rsp_length;
710: SInt32 send_length;
711:
712: rsp_length = rspLengthTable[Command]; // get cmd and response lengths from table
713: send_length = cmdLengthTable[Command];
714:
715: if ( ((SLength != 0) && (SBuffer == NULL)) || // validate pointers
716: ((rsp_length != 0) && (RBuffer == NULL)) ||
717: (RLength == NULL) ) {
718: return kPMUParameterError;
719: }
720: if ( (Command != kPMUdownloadFlash) &&
721: ((send_length != -1) && ((IOByteCount )send_length != SLength)) ) {
722: return kPMUParameterError;
723: }
724:
725: if ( send_length > MISC_LENGTH ) {
726: return kPMUParameterError;
727: }
728:
729: request.sync = IOSyncer::create();
730: request.pmCommand = Command;
731: request.pmFlag = false; // this is usually correct, but the API needs to be enhanced
732: request.pmSLength1 = 0;
733: request.pmSBuffer2 = SBuffer;
734: request.pmSLength2 = SLength;
735: request.pmRBuffer = RBuffer;
736:
737: commandQueue->enqueueCommand(true, &request);
738: request.sync->wait(); // wait till done
739:
740: *RLength = request.pmRLength; // set user's receive byte count
741:
742: return kPMUNoError;
743: }
744:
745:
746: // **********************************************************************************
747: // StartPMUTransmission
748: //
749: // Transmission of the command byte is started. The transaction will be
750: // completed by the Shift Register Interrupt Service Routine.
751: // **********************************************************************************
752: void ApplePMU::StartPMUTransmission ( PMUrequest * plugInMessage )
753: {
754: clientRequest = plugInMessage;
755: firstChar = plugInMessage->pmCommand; // get command byte
756: charCountS1 = plugInMessage->pmSLength1; // get caller's length counters
757: charCountS2 = plugInMessage->pmSLength2;
758: dataPointer1 = plugInMessage->pmSBuffer1; // and transmit data pointers
759: dataPointer2 = plugInMessage->pmSBuffer2;
760: dataPointer = plugInMessage->pmRBuffer; // set up read pointer for data bytes
761: charCountR = rspLengthTable[firstChar]; // get response length from table
762: charCountR2 = charCountR;
763: // figure out what happens after command byte transmission
764: if ( cmdLengthTable[firstChar] < 0 ) { // will we be sending a length byte next?
765: PGE_ISR_state = kPMUxmtLen; // yes
766: }
767: else { // no, will we be sending data next?
768: if ( cmdLengthTable[firstChar] > 0 ) {
769: PGE_ISR_state = kPMUxmtData; // yes
770: }
771: else { // no, will we be receiving a length byte next?
772: if ( charCountR < 0 ) {
773: PGE_ISR_state = kPMUreadLen_cmd; // yes
774: }
775: else { // no, will we be receiving data next?
776: if ( charCountR > 0 ) {
777: PGE_ISR_state = kPMUreadData; // yes
778: }
779: else {
780: PGE_ISR_state = kPMUdone; // no, this is a single-byte transaction
781: }
782: }
783: }
784: }
785: // ready to start the command byte
786: *VIA1_auxillaryControl |= 0x1C; // set shift register to output
787: *VIA1_shift = firstChar; // give it the byte (this clears any pending SR interrupt)
788: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
789: *VIA2_dataB &= ~PMreq; // assert /REQ
790: return;
791: }
792:
793: #if 0
794: // ****************************************************************************
795: // shiftRegisterInt
796: //
797: // ****************************************************************************
798:
799: void shiftRegisterInt ( OSObject * PMUdriver, IOInterruptEventSource *, int )
800: {
801: ((ApplePMU *)PMUdriver)->serviceShiftRegister();
802: }
803: #endif
804:
805:
806: // ****************************************************************************
807: // commandDoneInt
808: //
809: // ****************************************************************************
810:
811: void commandDoneInt ( OSObject * PMUdriver, IOInterruptEventSource *, int )
812: {
813: ApplePMU * pmu = (ApplePMU *)PMUdriver;
814: pmu->PGE_ISR_state = kPMUidle; // set the state
815: if ( pmu->clientRequest->pmFlag ) { // does this command cause input?
816: if ( ! pmu->adb_reading ) { // yes, is this the input completion?
817: pmu->adb_reading = true; // no, don't unblock caller now
818: //q8q // start timer
819: if ( pmu->PMU_int_pending ) { // is PMU now requesting service?
820: pmu->PMU_int_pending = false;
821: *(pmu->VIA1_auxillaryControl) |= 0x1C; // set shift register to output
822: *(pmu->VIA1_shift) = kPMUreadINT; // give it this command byte
823: *(pmu->VIA2_dataB) &= ~(pmu->PMreq); // assert /REQ
824: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
825: pmu->PGE_ISR_state = kPMUreadLen_int; // next int is cmd byte xmt done
826: pmu->dataPointer = &(pmu->interruptState[0]); // set up read ptr for data bytes
827: }
828: return;
829: }
830: }
831:
832: pmu->clientRequest->sync->signal(); // unblock the caller
833: pmu->clientRequest = 0;
834: if ( !(pmu->PMU_int_pending) ) { // is PMU now requesting service?
835: pmu->CheckRequestQueue(); // no, start next queued transaction
836: }
837: else {
838: pmu->PMU_int_pending = false;
839: *(pmu->VIA1_auxillaryControl) |= 0x1C; // set shift register to output
840: *(pmu->VIA1_shift) = kPMUreadINT; // give it this command byte
841: *(pmu->VIA2_dataB) &= ~(pmu->PMreq); // assert /REQ
842: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
843: pmu->PGE_ISR_state = kPMUreadLen_int; // next int is cmd byte xmt done
844: pmu->dataPointer = &(pmu->interruptState[0]); // set up read ptr for data bytes
845: }
846: }
847:
848:
849: // ****************************************************************************
850: // unsolicitedInt
851: //
852: // ****************************************************************************
853:
854: void unsolicitedInt ( OSObject * PMUdriver, IOInterruptEventSource *, int )
855: {
856: ApplePMU * pmu = (ApplePMU *)PMUdriver;
857: if ( pmu->interruptState[0] & kPMUADBint ) { // what kind of int was it?
858: pmu->ADBinput((UInt32)(pmu->charCountR), &(pmu->interruptState[0])); // ADB
859: }
860: else {
861: if ( pmu->interruptState[0] & kPMUbattInt ) {
862: // kprintf("battery PGE interrupt\n");
863: }
864: else {
865: if ( pmu->interruptState[0] & kPMUoneSecInt ) {
866: // kprintf("one-second PGE interrupt\n");
867: if ( pmu->RTCclient != NULL ) { // one-second interrupt
868: // (* RTCclient)(RTCid,0,0,0);
869: }
870: }
871: else {
872: if ( pmu->interruptState[0] & kPMUenvironmentInt ) {
873: // kprintf("environment interrupt\n");
874: }
875: else {
876: if ( pmu->interruptState[0] & kPMUbrightnessInt ) {
877: // kprintf("brightness button PGE interrupt\n");
878: pmu->buttonInput((UInt32)(pmu->charCountR),&(pmu->interruptState[0]));
879: }
880: else {
881: // kprintf("machine-dependent PGE interrupt\n");
882: }
883: }
884: }
885: }
886: }
887: pmu->PGE_ISR_state = kPMUidle; // set the state
888:
889: if ( !(pmu->PMU_int_pending) ) { // is PMU requesting service again?
890: if (0 == pmu->clientRequest)
891: pmu->CheckRequestQueue(); // no, start next queued command
892: }
893: else {
894: pmu->PMU_int_pending = false;
895: *(pmu->VIA1_auxillaryControl) |= 0x1C; // set shift register to output
896: *(pmu->VIA1_shift) = kPMUreadINT; // give it this command byte
897: *(pmu->VIA2_dataB) &= ~(pmu->PMreq); // assert /REQ
898: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
899: pmu->PGE_ISR_state = kPMUreadLen_int; // next int is cmd byte xmt done
900: pmu->dataPointer = &(pmu->interruptState[0]); // set up read ptr for data bytes
901: }
902: }
903:
904: bool ApplePMU::WaitForAckLo ( void )
905: {
906: AbsoluteTime deadline, now;
907: bool ok = true;
908:
909: clock_absolutetime_interval_to_deadline(
910: SR_to_ack_transition_delay, &deadline);
911:
912: while( ok && ((*VIA2_dataB) & PMack) ) {
913: clock_get_uptime( &now );
914: ok = (CMP_ABSOLUTETIME( &now, &deadline ) < 0);
915: }
916: eieio();
917:
918: return( ok );
919: }
920:
921: // ****************************************************************************
922: // serviceShiftRegister
923: // The shift register has finished shifting in a byte from PG&E or finished
924: // shifting out a byte to PG&E. Here we continue the transaction by starting
925: // the i/o of the next byte, or we finish the transaction by indicating an
926: // interrupt on either the command-done interrupt source or the autopoll
927: // interrupt source on the workloop.
928: // Both the VIA interrupt flag register and the interrupt enable registers
929: // have been cleared by the ohare ISR.
930: // ****************************************************************************
931:
932: void serviceShiftRegister ( ApplePMU * pmu )
933: {
934:
935: if( (*(pmu->VIA2_dataB) & pmu->PMack) )
936: pmu->WaitForAckLo();
937:
938: *(pmu->VIA2_dataB) |= pmu->PMreq; // deassert /REQ line
939: // what state are we in?
940: switch ( pmu->PGE_ISR_state ) {
941: // We are processing a PMU interrupt. We are reading the response
942: // to the kPMUreadINT command, and a byte has arrived.
943: case kPMUrcvData_int:
944: *(pmu->dataPointer)++ = *(pmu->VIA1_shift); // read the data byte
945: (pmu->charCountR2)--;
946: if ( pmu->charCountR2 > 0 ) { // is there more to read?
947: while ( !(*(pmu->VIA2_dataB) & pmu->PMack) ) {
948: }
949: *(pmu->VIA2_dataB) &= ~(pmu->PMreq); // yes, assert /REQ
950: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
951: return; // next int is next data byte
952: }
953: pmu->unsolicitedEventSrc->interruptOccurred(0,0,0); // no, inform workloop
954: return;
955:
956: // We are processing a PMU interrupt.
957: // We have finished transmitting the kPMUreadINT command byte,
958: // and according to our table, we will be getting a response and
959: // a length byte for it. Finish the transmit handshake and set
960: case kPMUreadLen_int: // up a receive for the length byte.
961: pmu->receivedByte = *(pmu->VIA1_shift); // read shift reg to turn off SR int
962: pmu->PGE_ISR_state = kPMUrcvLen_int;
963: *(pmu->VIA1_auxillaryControl) &= 0xEF; // set shift register to input
964: while ( !(*(pmu->VIA2_dataB) & pmu->PMack) ) {
965: }
966: *(pmu->VIA2_dataB) &= ~(pmu->PMreq); // assert /REQ
967: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
968: return; // next interrupt will be the length byte
969:
970: // We are processing a PMU interrupt.
971: case kPMUrcvLen_int: // The length byte has arrived. Read it and start data read
972: pmu->charCountR = *(pmu->VIA1_shift); // read it
973:
974: pmu->charCountR2 = pmu->charCountR;
975: pmu->PGE_ISR_state = kPMUrcvData_int;
976: while ( !(*(pmu->VIA2_dataB) & pmu->PMack) ) {
977: }
978: *(pmu->VIA2_dataB) &= ~(pmu->PMreq); // assert /REQ
979: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
980: return; // next int will be the first data byte
981:
982: // We are doing a command transaction. The command byte
983: case kPMUxmtLen: // transmission has completed. Start length byte transmission
984: pmu->PGE_ISR_state = kPMUxmtData;
985: while ( !(*(pmu->VIA2_dataB) & pmu->PMack) ) {
986: }
987: *(pmu->VIA1_shift) = (UInt8)(pmu->charCountS1 + pmu->charCountS2); // give it the length byte
988: *(pmu->VIA2_dataB) &= ~(pmu->PMreq); // assert /REQ
989: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
990: return; // next int start sending data
991:
992: // We are doing a command transaction. A byte transmission has
993: case kPMUxmtData: // completed . Continue data byte transmission
994: while ( !(*(pmu->VIA2_dataB) & pmu->PMack) ) {
995: }
996: if ( pmu->charCountS1 ) {
997: *(pmu->VIA1_shift) = *(pmu->dataPointer1)++; // give it the next data byte from buffer 1
998: *(pmu->VIA2_dataB) &= ~(pmu->PMreq); // assert /REQ
999: if ( --(pmu->charCountS1) + pmu->charCountS2 ) {
1000: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
1001: return; // next interrupt do another byte
1002: }
1003: }
1004: else {
1005: if ( pmu->charCountS2 ) { // buffer 1 empty,
1006: *(pmu->VIA1_shift) = *(pmu->dataPointer2)++; // give it the next byte from buffer 2
1007: *(pmu->VIA2_dataB) &= ~(pmu->PMreq); // assert /REQ
1008: if ( --(pmu->charCountS2) ) {
1009: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
1010: return; // next interrupt do another byte
1011: }
1012: }
1013: }
1014: // sending last byte, what's next?
1015: if ( pmu->charCountR < 0 ) {
1016: pmu->PGE_ISR_state = kPMUreadLen_cmd; // we will receive a length byte
1017: }
1018: else {
1019: if ( pmu->charCountR > 0 ) {
1020: pmu->PGE_ISR_state = kPMUreadData; // we will receive constant-length data
1021: }
1022: else {
1023: pmu->PGE_ISR_state = kPMUdone; // nothing, we're done
1024: }
1025: }
1026: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
1027: return;
1028:
1029: // We have finished the transmission part of a command transaction, and
1030: // according to our table, we will be getting a response and a
1031: // length byte for it. Finish the transmit handshake and set up
1032: case kPMUreadLen_cmd: // a receive for the length byte.
1033: pmu->receivedByte = *(pmu->VIA1_shift); // read shift reg to turn off SR int
1034: pmu->PGE_ISR_state = kPMUrcvLen_cmd;
1035: *(pmu->VIA1_auxillaryControl) &= 0xEF; // set shift register to input
1036: while ( !(*(pmu->VIA2_dataB) & pmu->PMack) ) {
1037: }
1038: *(pmu->VIA2_dataB) &= ~(pmu->PMreq); // assert /REQ
1039: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
1040: return; // next interrupt will be the length byte
1041:
1042: case kPMUrcvLen_cmd: // the length byte has arrived, read it and start data read
1043: pmu->charCountR = *(pmu->VIA1_shift); // read it
1044: pmu->charCountR2 = pmu->charCountR;
1045: pmu->PGE_ISR_state = kPMUrcvData_cmd;
1046: if ( pmu->charCountR2 > 0 ) { // is there anything to read?
1047: if ( !(*(pmu->VIA2_dataB) & pmu->PMack) ) {
1048: if ( !(pmu->WaitForAckHi()) ) {
1049: return; // yes, make sure ACK is high
1050: }
1051: }
1052: *(pmu->VIA2_dataB) &= ~(pmu->PMreq); // assert /REQ
1053: return; // next interrupt will be first data byte
1054: }
1055: pmu->clientRequest->pmRLength = pmu->charCountR; // no, this much was read
1056: pmu->cmdDoneEventSrc->interruptOccurred(0,0,0); // inform workloop
1057: return;
1058: // We have finished the transmission part of a command transaction, and
1059: // according to our table, we will be getting a response but not a
1060: // length byte for it. Finish the transmit handshake and set up
1061: case kPMUreadData: // a receive for the first data byte.
1062: if ( pmu->charCountR > 1 ) {
1063: pmu->charCountR2--; // make constant (byte count + 1) into byte count
1064: pmu->charCountR--;
1065: }
1066: // receivedByte = *VIA1_shift; // read shift reg to turn off SR int
1067: pmu->PGE_ISR_state = kPMUrcvData_cmd;
1068: *(pmu->VIA1_auxillaryControl) &= 0xEF; // set shift register to input
1069: if ( !(*(pmu->VIA2_dataB) & pmu->PMack) ) {
1070: if ( !(pmu->WaitForAckHi()) ) {
1071: return; // make sure ACK is high
1072: }
1073: }
1074: *(pmu->VIA2_dataB) &= ~(pmu->PMreq);// assert /REQ
1075: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
1076: return; // next interrupt will be the first data character
1077:
1078: // We are reading the response in a command transaction, and
1079: case kPMUrcvData_cmd: // a data byte has arrived
1080: *(pmu->dataPointer)++ = *(pmu->VIA1_shift); // read the data byte
1081: pmu->charCountR2--;
1082: if ( pmu->charCountR2 > 0 ) { // is there more to read?
1083: if ( !(*(pmu->VIA2_dataB) & pmu->PMack) ) {
1084: if ( !(pmu->WaitForAckHi()) ) {
1085: return; // yes, make sure ACK is high
1086: }
1087: }
1088: *(pmu->VIA2_dataB) &= ~(pmu->PMreq); // assert /REQ
1089: return; // next interrupt will be next data byte
1090: }
1091: pmu->clientRequest->pmRLength = pmu->charCountR; // no, this much was read
1092: pmu->cmdDoneEventSrc->interruptOccurred(0,0,0); // inform workloop
1093: return;
1094:
1095: case kPMUdone: // this was the last xmt SR interrupt of a command transaction
1096: // receivedByte = *VIA1_shift; // read shift reg to turn off SR int
1097: pmu->clientRequest->pmRLength = 0; // nothing was read
1098: pmu->cmdDoneEventSrc->interruptOccurred(0,0,0); // inform workloop
1099: return;
1100: }
1101: return;
1102: }
1103:
1104:
1105: // ****************************************************************************
1106: // PMUint
1107: //
1108: // ****************************************************************************
1109:
1110: void PMUint ( OSObject * PMUdriver, IOInterruptEventSource *, int )
1111: {
1112: ((ApplePMU *)PMUdriver)->servicePMU();
1113: }
1114:
1115:
1116: // ****************************************************************************
1117: // servicePMU
1118: // PGE has interrupted. Send the ReadInt command to find out why.
1119: // When the command byte is sent, the Shift Register will interrupt.
1120: // If we are mid-transaction when we find out about the interrupt,
1121: // set a flag and find out why later.
1122: //
1123: // ****************************************************************************
1124:
1125: void ApplePMU::servicePMU ( void )
1126: {
1127: if ( PGE_ISR_state != kPMUidle ) {
1128: PMU_int_pending = true;
1129: return;
1130: }
1131:
1132: // *VIA1_interruptFlag = 0x10; // acknowledge VIA interrupt ( ifCB1 )
1133: // *VIA1_interruptEnable = 0x10; // and disable it entirely ( ifCB1 )
1134: while ( !(*VIA2_dataB & PMack) ) { // make sure ACK is high
1135: }
1136: *VIA1_auxillaryControl |= 0x1C; // set shift register to output
1137: *VIA1_shift = kPMUreadINT; // give it this command byte
1138: *VIA2_dataB &= ~PMreq; // assert /REQ
1139: // *VIA1_interruptEnable = 0x84; // enable SR interrupt
1140: PGE_ISR_state = kPMUreadLen_int; // set the state
1141: dataPointer = &interruptState[0]; // set up read pointer for data bytes
1142: return; // return till character transmission completes
1143: }
1144:
1145:
1146: // ****************************************************************************
1147: // WaitForAckHi
1148: // ****************************************************************************
1149: bool ApplePMU::WaitForAckHi ( void )
1150: {
1151: // q8q struct timeval startTime;
1152: // q8q struct timeval currentTime;
1153: // q8q ns_time_t x;
1154:
1155: // wait up to 32 milliseconds for Ack signal from PG&E to go high
1156:
1157: // q8q IOGetTimestamp(&x);
1158: // q8q ns_time_to_timeval(x, &startTime); // get current time
1159:
1160: while ( true ) {
1161: if ( *VIA2_dataB & PMack ) {
1162: return ( true ); // ack is high, return
1163: }
1164: // q8q IOGetTimestamp(&x);
1165: // q8q ns_time_to_timeval(x, ¤tTime);
1166: // q8q if ( startTime.tv_usec > currentTime.tv_usec ) {
1167: // q8q currentTime.tv_usec += 1000000; // clock has wrapped, adjust it
1168: // q8q }
1169: // q8q if ( currentTime.tv_usec > (startTime.tv_usec + 32000) ) { // has 32 ms elapsed?
1170: // q8q return ( false ); // yes, return
1171: // q8q }
1172: }
1173: }
1174:
1175:
1176: // ****************************************************************************
1177: // DisablePMUInterrupt
1178: // ****************************************************************************
1179: void ApplePMU::DisablePMUInterrupt ( void )
1180: {
1181: *VIA1_interruptEnable = 1<<ifCB1;
1182: eieio();
1183: }
1184:
1185:
1186: // ****************************************************************************
1187: // EnablePMUInterrupt
1188: // ****************************************************************************
1189: void ApplePMU::EnablePMUInterrupt ( void )
1190: {
1191: *VIA1_interruptEnable = (1<<ifCB1) | 0x80;
1192: eieio();
1193: }
1194:
1195:
1196: // ****************************************************************************
1197: // AcknowledgePMUInterrupt
1198: // ****************************************************************************
1199: void ApplePMU::AcknowledgePMUInterrupt ( void )
1200: {
1201: *VIA1_interruptFlag = 1<<ifCB1;
1202: eieio();
1203: }
1204:
1205:
1206: // ****************************************************************************
1207: // DisableSRInterrupt
1208: // ****************************************************************************
1209: void ApplePMU::DisableSRInterrupt ( void )
1210: {
1211: *VIA1_interruptEnable = 1<<ifSR;
1212: }
1213:
1214:
1215: // ****************************************************************************
1216: // EnableSRInterrupt
1217: // ****************************************************************************
1218: void ApplePMU::EnableSRInterrupt ( void )
1219: {
1220: *VIA1_interruptEnable = (1<<ifSR) | 0x80;
1221: }
1222:
1223:
1224:
1225: // ****************************************************************************
1226: // timer_expired
1227: //
1228: // Our adb-read timer has expired, so we have to notify our i/o thread by
1229: // enqueuing a Timeout message to its interrupt port.
1230: // ****************************************************************************
1231: // q8q void timer_expired(port_t mach_port)
1232: // q8q {
1233:
1234: // q8q }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.