/* * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991 * All Rights Reserved * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appears in all copies and * that both the copyright notice and this permission notice appear in * supporting documentation. * * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ /* * Copyright 1996 1995 by Apple Computer, Inc. 1997 1996 1995 1994 1993 1992 1991 * All Rights Reserved * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appears in all copies and * that both the copyright notice and this permission notice appear in * supporting documentation. * * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * MKLINUX-1.0DR2 */ /* * 18 June 1998 sdouglas Start IOKit version. * 16 Nov 1998 suurballe Port to c++ */ #include #include "IOADBControllerUserClient.h" #include #include #include #include #include #include #include "IOADBBusPriv.h" bool ADBhasRoot( OSObject *, void *, IOService * ); void doProbe ( thread_call_param_t, thread_call_param_t); #define kTenSeconds 10000000 #define super IOADBBus OSDefineMetaClass(IOADBController,IOADBBus) OSDefineAbstractStructors(IOADBController,IOADBBus) // ********************************************************************************** // start // // ********************************************************************************** bool IOADBController::start ( IOService * nub ) { if( !super::start(nub)) { return false; } probeBus(); rootDomain = NULL; busProbed = true; // creates the probe thread for when we wake up: probeThread = thread_call_allocate((thread_call_func_t)doProbe, (thread_call_param_t)this); if (probeThread == NULL) { IOLog("IOADBController::start fails to call thread_call_allocate \n"); return false; } addNotification( gIOPublishNotification,serviceMatching("IOPMrootDomain"), // look for the Root Domain (IOServiceNotificationHandler)ADBhasRoot, this, 0 ); return true; } // ********************************************************************************** // ADBhasRoot // // The Root Power Domain has registered. // Register as an interested driver so we find out when the system is // going to sleep and waking up. // ********************************************************************************** bool ADBhasRoot( OSObject * us, void *, IOService * yourDevice ) { if ( yourDevice != NULL ) { ((IOADBController *)us)->rootDomain = (IOPMrootDomain *)yourDevice; ((IOADBController *)us)->rootDomain->registerInterestedDriver((IOService *) us); } return true; } //********************************************************************************* // powerStateWillChangeTo // // We are notified here of power changes in the root domain. // // If power is going down in the root domain, then the system is going to // sleep, and we tear down the ADB stack. //********************************************************************************* IOReturn IOADBController::powerStateWillChangeTo ( IOPMPowerFlags theFlags, unsigned long, IOService*) { int i; if ( ! (theFlags & kIOPMPowerOn) && ! (theFlags & kIOPMDoze) ) { busProbed = false; for ( i = 1; i < ADB_DEVICE_COUNT; i++ ) { if( adbDevices[ i ] != NULL ) { if ( adbDevices[ i ]->nub ) { adbDevices[ i ]->nub->terminate(kIOServiceRequired | kIOServiceSynchronous); adbDevices[ i ]->nub->release(); } IOFree( adbDevices[ i ], sizeof (ADBDeviceControl)); adbDevices[ i ] = NULL; } } } return IOPMAckImplied; } //********************************************************************************* // powerStateDidChangeTo // // We are notified here of power changes in the root domain // // If power is has been brought up, then the system is waking from sleep. // We re-probe the bus //********************************************************************************* IOReturn IOADBController::powerStateDidChangeTo ( IOPMPowerFlags theFlags, unsigned long, IOService*) { if ( (theFlags & kIOPMPowerOn) || (theFlags & kIOPMDoze) ) { if ( ! busProbed ) { thread_call_enter(probeThread); busProbed = true; return kTenSeconds; } } return IOPMAckImplied; } void doProbe ( thread_call_param_t arg, thread_call_param_t) { ((IOADBController *)arg)->probeBus(); ((IOADBController *)arg)->rootDomain->acknowledgePowerChange((IOService *)arg); } // ********************************************************************************** // probeAddress // // ********************************************************************************** bool IOADBController::probeAddress ( IOADBAddress addr ) { IOReturn err; ADBDeviceControl * deviceInfo; UInt16 value; IOByteCount length; length = 2; err = readFromDevice(addr,3,(UInt8 *)&value,&length); if (err == ADB_RET_OK) { if( NULL == (deviceInfo = adbDevices[ addr ])) { deviceInfo = (ADBDeviceControl *)IOMalloc(sizeof(ADBDeviceControl)); bzero(deviceInfo, sizeof(ADBDeviceControl)); adbDevices[ addr ] = deviceInfo; deviceInfo->defaultAddress = addr; deviceInfo->handlerID = deviceInfo->defaultHandlerID = (value & 0xff); } deviceInfo->address = addr; } return( (err == ADB_RET_OK)); } // ********************************************************************************** // firstBit // // ********************************************************************************** unsigned int IOADBController::firstBit ( unsigned int mask ) { int bit = 15; while( 0 == (mask & (1 << bit))) { bit--; } return(bit); } // ********************************************************************************** // moveDeviceFrom // // ********************************************************************************** bool IOADBController::moveDeviceFrom ( IOADBAddress from, IOADBAddress to, bool check ) { IOReturn err; UInt16 value; IOByteCount length; bool moved; length = 2; value = ((to << 8) | ADB_DEVCMD_CHANGE_ID); err = writeToDevice(from,3,(UInt8 *)&value,&length); adbDevices[ to ] = adbDevices[ from ]; moved = probeAddress(to); if( moved || (!check)) { adbDevices[ from ] = NULL; } else { adbDevices[ to ] = NULL; } return moved; } // ********************************************************************************** // probeBus // // ********************************************************************************** IOReturn IOADBController::probeBus ( void ) { int i; UInt32 unresolvedAddrs; UInt32 freeAddrs; IOADBAddress freeNum, devNum; IOADBDevice * newDev; OSDictionary * newProps; char nameStr[ 10 ]; const OSNumber * object; const OSSymbol * key; /* Kill the auto poll until a new dev id's have been setup */ setAutoPollEnable(false); /* * Send a ADB bus reset - reply is sent after bus has reset, * so there is no need to wait for the reset to complete. */ resetBus(); /* * Okay, now attempt reassign the * bus */ unresolvedAddrs = 0; freeAddrs = 0xfffe; /* Skip 0 -- it's special! */ for (i = 1; i < ADB_DEVICE_COUNT; i++) { if( probeAddress(i) ) { unresolvedAddrs |= ( 1 << i ); freeAddrs &= ~( 1 << i ); } } /* Now attempt to reassign the addresses */ while( unresolvedAddrs) { if( !freeAddrs) { panic("ADB: Cannot find a free ADB slot for reassignment!"); } freeNum = firstBit(freeAddrs); devNum = firstBit(unresolvedAddrs); if( !moveDeviceFrom(devNum, freeNum, true) ) { /* It didn't move.. bad! */ IOLog("WARNING : ADB DEVICE %d having problems " "probing!\n", devNum); } else { if( probeAddress(devNum) ) { /* Found another device at the address, leave * the first device moved to one side and set up * newly found device for probing */ freeAddrs &= ~( 1 << freeNum ); devNum = 0; } else { /* no more at this address, good !*/ /* Move it back.. */ moveDeviceFrom(freeNum,devNum,false); } } if(devNum) { unresolvedAddrs &= ~( 1 << devNum ); } } IOLog("ADB present:%lx\n", (freeAddrs ^ 0xfffe)); setAutoPollList(freeAddrs ^ 0xfffe); setAutoPollPeriod(11111); setAutoPollEnable(true); // publish the nubs for ( i = 1; i < ADB_DEVICE_COUNT; i++ ) { if( 0 == adbDevices[ i ] ) { continue; } newDev = new IOADBDevice; // make a nub if ( newDev == NULL ) { continue; } adbDevices[ i ]->nub = newDev; // keep a pointer to it newProps = OSDictionary::withCapacity( 10 ); // create a property table for it if ( newProps == NULL ) { newDev->free(); continue; } key = OSSymbol::withCString(ADBaddressProperty); // make key/object for address if ( key == NULL ) { newDev->free(); newProps->free(); continue; } object = OSNumber::withNumber((unsigned long long)adbDevices[i]->address,8); if ( object == NULL ) { key->release(); newDev->free(); newProps->free(); continue; } newProps->setObject(key, (OSObject *)object); // put it in newProps key->release(); object->release(); key = OSSymbol::withCString(ADBhandlerIDProperty); // make key/object for handlerID if ( key == NULL ) { newDev->free(); newProps->free(); continue; } object = OSNumber::withNumber((unsigned long long)adbDevices[i]->handlerID,8); if ( object == NULL ) { key->release(); newDev->free(); newProps->free(); continue; } newProps->setObject(key, (OSObject *)object); // put it in newProps key->release(); object->release(); key = OSSymbol::withCString(ADBdefAddressProperty); // make key/object for default addr if ( key == NULL ) { newDev->free(); newProps->free(); continue; } object = OSNumber::withNumber((unsigned long long)adbDevices[i]->defaultAddress,8); if ( object == NULL ) { key->release(); newDev->free(); newProps->free(); continue; } newProps->setObject(key, (OSObject *)object); // put it in newProps key->release(); object->release(); key = OSSymbol::withCString(ADBdefHandlerProperty); // make key/object for default h id if ( key == NULL ) { newDev->free(); newProps->free(); continue; } object = OSNumber::withNumber((unsigned long long)adbDevices[i]->defaultHandlerID,8); if ( object == NULL ) { key->release(); newDev->free(); newProps->free(); continue; } newProps->setObject(key, (OSObject *)object); // put it in newProps key->release(); object->release(); if ( ! newDev->init(newProps,adbDevices[i]) ) { // give it to our new nub kprintf("adb nub init failed\n"); newDev->release(); continue; } sprintf(nameStr,"%x-%02x",adbDevices[i]->defaultAddress,adbDevices[i]->handlerID); newDev->setName(nameStr); sprintf(nameStr, "%x", adbDevices[i]->defaultAddress); newDev->setLocation(nameStr); newProps->release(); // we're done with it if ( !newDev->attach(this) ) { kprintf("adb nub attach failed\n"); newDev->release(); continue; } newDev->start(this); newDev->registerService(); newDev->waitQuiet(); } // repeat loop return kIOReturnSuccess; } // ********************************************************************************** // autopollHandler // // ********************************************************************************** void autopollHandler ( IOService * us, UInt8 adbCommand, IOByteCount length, UInt8 * data ) { ((IOADBController *)us)->packet(data,length,adbCommand); } // ********************************************************************************** // packet // // ********************************************************************************** void IOADBController::packet ( UInt8 * data, IOByteCount length, UInt8 adbCommand ) { ADBDeviceControl * deviceInfo; deviceInfo = adbDevices[ adbCommand >> 4 ]; if( deviceInfo != NULL ) { if( deviceInfo->owner != NULL ) { deviceInfo->handler(deviceInfo->owner, adbCommand, length, data); } } else { // new device arrival? // IOLog("IOADBBus: new device @%x\n", address); } } // ********************************************************************************** // matchDevice // // ********************************************************************************** bool IOADBController::matchNubWithPropertyTable( IOService * device, OSDictionary * propTable ) { bool matched = false; const char * keys; ADBDeviceControl * deviceInfo = (ADBDeviceControl *)(((IOADBDevice *)device)->busRef()); OSObject * X; do { X = propTable->getObject("ADB Match"); if( !X ) { break; } keys = ((OSString *)X)->getCStringNoCopy(); if( *keys == '*' ) { keys++; } else { if( deviceInfo->defaultAddress != strtol(keys, (char **) &keys, 16)) { break; } } if( *keys++ == '-' ) { if( deviceInfo->defaultHandlerID != strtol(keys, (char **) &keys, 16)) { break; } } matched = true; } while ( false ); return matched; } /////// nub -> bus // ********************************************************************************** // setOwner // // ********************************************************************************** IOReturn IOADBController::setOwner ( void * device, IOService * client, ADB_callback_func handler ) { ADBDeviceControl * deviceInfo = (ADBDeviceControl *)device; deviceInfo->handler = handler; deviceInfo->owner = client; return kIOReturnSuccess; } // ********************************************************************************** // clearOwner // // ********************************************************************************** IOReturn IOADBController::clearOwner ( void * device ) { ADBDeviceControl * deviceInfo = (ADBDeviceControl *)device; kprintf("IOADBController::clearOwner\n"); deviceInfo->owner = NULL; deviceInfo->handler = NULL; return kIOReturnSuccess; } // ********************************************************************************** // claimDevice // // Called by the user client // ********************************************************************************** IOReturn IOADBController::claimDevice (unsigned long ADBaddress, IOService * client, ADB_callback_func handler ) { if ( claimed_devices[ADBaddress] == true ) { // is this address already claimed by the user? return kIOReturnExclusiveAccess; // yes } if ( adbDevices[ADBaddress] == NULL ) { // no, is there a device at that address? return kIOReturnNoDevice; // no } if (adbDevices[ADBaddress]->handler != NULL ) { // yes, is it already owned by the kernel? return kIOReturnExclusiveAccess; // yes } claimed_devices[ADBaddress] = true; // no, user can have it return kIOReturnSuccess; } // ********************************************************************************** // releaseDevice // // Called by the user client // ********************************************************************************** IOReturn IOADBController::releaseDevice (unsigned long ADBaddress ) { if ( claimed_devices[ADBaddress] == false ) { return kIOReturnBadArgument; } claimed_devices[ADBaddress] = false; return kIOReturnSuccess; } // ********************************************************************************** // readDeviceForUser // // Called by the user client // ********************************************************************************** IOReturn IOADBController::readDeviceForUser (unsigned long address, unsigned long adbRegister, UInt8 * data, IOByteCount * length) { if ( claimed_devices[address] == false ) { return kIOReturnBadArgument; } return (readFromDevice((IOADBAddress)address,(IOADBRegister)adbRegister,data,length)); } // ********************************************************************************** // writeDeviceForUser // // Called by the user client // ********************************************************************************** IOReturn IOADBController::writeDeviceForUser (unsigned long address, unsigned long adbRegister, UInt8 * data, IOByteCount * length) { if ( claimed_devices[address] == false ) { return kIOReturnBadArgument; } return (writeToDevice((IOADBAddress)address,(IOADBRegister)adbRegister,data,length)); } // ********************************************************************************** // address // // ********************************************************************************** IOADBAddress IOADBController::address ( ADBDeviceControl * busRef ) { return busRef->address; } // ********************************************************************************** // defaultAddress // // ********************************************************************************** IOADBAddress IOADBController::defaultAddress ( ADBDeviceControl * busRef ) { return busRef->defaultAddress; } // ********************************************************************************** // handlerID // // ********************************************************************************** UInt8 IOADBController::handlerID ( ADBDeviceControl * busRef ) { return busRef->handlerID; } // ********************************************************************************** // defaultHandlerID // // ********************************************************************************** UInt8 IOADBController::defaultHandlerID ( ADBDeviceControl * busRef ) { return busRef->defaultHandlerID; } // ********************************************************************************** // cancelAllIO // // ********************************************************************************** IOReturn IOADBController::cancelAllIO ( void ) { return kIOReturnSuccess; } // ********************************************************************************** // flush // // ********************************************************************************** IOReturn IOADBController::flush ( ADBDeviceControl * busRef ) { return(flushDevice(busRef->address)); } // ********************************************************************************** // readRegister // // ********************************************************************************** IOReturn IOADBController::readRegister ( ADBDeviceControl * busRef, IOADBRegister adbRegister, UInt8 * data, IOByteCount * length ) { return readFromDevice(busRef->address,adbRegister,data,length); } // ********************************************************************************** // writeRegister // // ********************************************************************************** IOReturn IOADBController::writeRegister ( ADBDeviceControl * busRef, IOADBRegister adbRegister, UInt8 * data, IOByteCount * length ) { return writeToDevice(busRef->address,adbRegister,data,length); } // ********************************************************************************** // setHandlerID // // ********************************************************************************** IOReturn IOADBController::setHandlerID ( ADBDeviceControl * deviceInfo, UInt8 handlerID ) { IOReturn err; UInt16 value; IOByteCount length; IOADBAddress addr = deviceInfo->address; length = 2; err = readFromDevice(addr,3,(UInt8 *)&value,&length); if ( err ) { return err; } value = (value & 0xf000) | handlerID | (addr << 8); length = sizeof(value); err = writeToDevice(addr,3,(UInt8 *)&value,&length); length = sizeof(value); err = readFromDevice(addr,3,(UInt8 *)&value,&length); if ( err == kIOReturnSuccess ) { deviceInfo->handlerID = value & 0xff; } if ( deviceInfo->handlerID == handlerID ) { err = kIOReturnSuccess; } else { err = kIOReturnNoResources; } return err; } // ********************************************************************************** // getURLComponentUnit // // ********************************************************************************** int IOADBController::getURLComponentUnit ( IOService * device, char * path, int maxLen ) { ADBDeviceControl * deviceInfo = (ADBDeviceControl *)((IOADBDevice *)device)->busRef(); if( maxLen > 1 ) { sprintf( path, "%x", deviceInfo->address ); return(1); } else { return(0); } } // ********************************************************************************** // newUserClient // // ********************************************************************************** IOReturn IOADBController::newUserClient( task_t owningTask, void * /* security_id */, UInt32 type, IOUserClient ** handler ) { IOReturn err = kIOReturnSuccess; IOADBControllerUserClient * client; client = IOADBControllerUserClient::withTask(owningTask); if( !client || (false == client->attach( this )) || (false == client->start( this )) ) { if(client) { client->detach( this ); client->release(); client = NULL; } err = kIOReturnNoMemory; } *handler = client; return err; }