1/*
2 * Copyright (c) 1998-2004 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.2 (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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
17 * Please see the License for the specific language governing rights and
18 * limitations under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23    /* AppleUSBCDCWCM.cpp - MacOSX implementation of			*/
24    /* USB Communication Device Class (CDC) Driver, WMC Interface.	*/
25
26#include <machine/limits.h>			/* UINT_MAX */
27#include <libkern/OSByteOrder.h>
28
29#include <IOKit/assert.h>
30#include <IOKit/IOLib.h>
31#include <IOKit/IOService.h>
32#include <IOKit/IOBufferMemoryDescriptor.h>
33#include <IOKit/IOMessage.h>
34
35#include <IOKit/pwr_mgt/RootDomain.h>
36
37#if !TARGET_OS_IPHONE
38#include <IOKit/usb/IOUSBBus.h>
39#endif /* TARGET_OS_IPHONE */
40
41#include <IOKit/usb/IOUSBNub.h>
42#include <IOKit/usb/IOUSBDevice.h>
43#include <IOKit/usb/IOUSBLog.h>
44#include <IOKit/usb/IOUSBPipe.h>
45#include <IOKit/usb/USB.h>
46#include <IOKit/usb/IOUSBInterface.h>
47
48#include <IOKit/serial/IOSerialKeys.h>
49#include <IOKit/serial/IOSerialDriverSync.h>
50#include <IOKit/serial/IOModemSerialStreamSync.h>
51#include <IOKit/serial/IORS232SerialStreamSync.h>
52
53#include <UserNotification/KUNCUserNotifications.h>
54
55#define DEBUG_NAME "AppleUSBCDCWCM"
56
57#include "AppleUSBCDCWCM.h"
58
59    // Globals
60
61static IOPMPowerState gOurPowerStates[kNumCDCStates] =
62{
63    {1,0,0,0,0,0,0,0,0,0,0,0},
64    {1,IOPMDeviceUsable,IOPMPowerOn,IOPMPowerOn,0,0,0,0,0,0,0,0}
65};
66
67#define super IOService
68
69OSDefineMetaClassAndStructors(AppleUSBCDCWCM, IOService);
70
71/****************************************************************************************************/
72//
73//		Method:		AppleUSBCDCWCM::probe
74//
75//		Inputs:		provider - my provider
76//
77//		Outputs:	IOService - from super::probe, score - probe score
78//
79//		Desc:		Modify the probe score if necessary (we don't  at the moment)
80//
81/****************************************************************************************************/
82
83IOService* AppleUSBCDCWCM::probe( IOService *provider, SInt32 *score )
84{
85    IOService   *res;
86
87		// If our IOUSBInterface has a "do not match" property, it means that we should not match and need
88		// to bail.  See rdar://3716623
89
90    OSBoolean *boolObj = OSDynamicCast(OSBoolean, provider->getProperty("kDoNotClassMatchThisInterface"));
91    if (boolObj && boolObj->isTrue())
92    {
93        XTRACE(this, 0, 0, "probe - provider doesn't want us to match");
94        return NULL;
95    }
96
97    res = super::probe(provider, score);
98
99    return res;
100
101}/* end probe */
102
103/****************************************************************************************************/
104//
105//		Method:		AppleUSBCDCWCM::start
106//
107//		Inputs:		provider - my provider
108//
109//		Outputs:	Return code - true (it's me), false (sorry it probably was me, but I can't configure it)
110//
111//		Desc:		This is called once it has beed determined I'm probably the best
112//				driver for this interface.
113//
114/****************************************************************************************************/
115
116bool AppleUSBCDCWCM::start(IOService *provider)
117{
118
119    fTerminate = false;
120    fStopping = false;
121	fControlLen = 0;
122	fControlMap = NULL;
123
124    XTRACE(this, 0, 0, "start");
125
126    if(!super::start(provider))
127    {
128        ALERT(0, 0, "start - super failed");
129        return false;
130    }
131
132	// Get my USB provider - the interface
133
134    fInterface = OSDynamicCast(IOUSBInterface, provider);
135    if(!fInterface)
136    {
137        ALERT(0, 0, "start - provider invalid");
138        return false;
139    }
140
141    if (!configureDevice())
142    {
143        ALERT(0, 0, "start - configureDevice failed");
144        return false;
145    }
146
147    if (!allocateResources())
148    {
149        ALERT(0, 0, "start - allocateResources failed");
150        return false;
151    }
152
153    if (!initForPM(provider))
154    {
155        ALERT(0, 0, "start - initForPM failed");
156        return false;
157    }
158
159    fInterface->retain();
160
161    registerService();
162
163    XTRACE(this, 0, 0, "start - successful");
164	Log(DEBUG_NAME ": Version number - %s\n", VersionNumber);
165
166    return true;
167
168}/* end start */
169
170/****************************************************************************************************/
171//
172//		Method:		AppleUSBCDCWCM::stop
173//
174//		Inputs:		provider - my provider
175//
176//		Outputs:	None
177//
178//		Desc:		Stops the driver
179//
180/****************************************************************************************************/
181
182void AppleUSBCDCWCM::stop(IOService *provider)
183{
184
185    XTRACE(this, 0, 0, "stop");
186
187    fStopping = true;
188
189    releaseResources();
190
191    PMstop();
192
193	if (fControlMap)
194	{
195		IOFree(fControlMap, fControlLen);
196		fControlMap = NULL;
197		fControlLen = 0;
198	}
199
200    super::stop(provider);
201
202}/* end stop */
203
204/****************************************************************************************************/
205//
206//		Method:		AppleUSBCDCWCM::configureWHCM
207//
208//		Inputs:		None
209//
210//		Outputs:	return Code - true (configured), false (not configured)
211//
212//		Desc:		Configures the Wireless handset Control Model interface
213//
214/****************************************************************************************************/
215
216bool AppleUSBCDCWCM::configureWHCM()
217{
218
219    XTRACE(this, 0, 0, "configureWHCM");
220
221    fInterfaceNumber = fInterface->GetInterfaceNumber();
222    XTRACE(this, 0, fInterfaceNumber, "configureWHCM - Comm interface number.");
223
224    if (!getFunctionalDescriptors())
225    {
226        XTRACE(this, 0, 0, "configureWHCM - getFunctionalDescriptors failed");
227        return false;
228    }
229
230    return true;
231
232}/* end configureWHCM */
233
234/****************************************************************************************************/
235//
236//		Method:		AppleUSBCDCWCM::configureDevice
237//
238//		Inputs:		None
239//
240//		Outputs:	return Code - true (device configured), false (device not configured)
241//
242//		Desc:		Finds the appropriate interface etc.
243//
244/****************************************************************************************************/
245
246bool AppleUSBCDCWCM::configureDevice()
247{
248    bool	configOK = false;
249
250    XTRACE(this, 0, 0, "configureDevice");
251
252    fInterfaceNumber = fInterface->GetInterfaceNumber();
253    fSubClass = fInterface->GetInterfaceSubClass();
254    XTRACE(this, fSubClass, fInterfaceNumber, "configureDevice - Subclass and interface number.");
255
256    switch (fSubClass)
257    {
258        case kUSBWirelessHandsetControlModel:
259            if (configureWHCM())
260            {
261                configOK = true;
262            }
263            break;
264        default:
265            XTRACE(this, 0, fSubClass, "configureDevice - Unsupported subclass");
266            break;
267        }
268
269    if (!configOK)
270    {
271        XTRACE(this, 0, 0, "configureDevice - configuration failed");
272        return false;
273    }
274
275    return true;
276
277}/* end configureDevice */
278
279/****************************************************************************************************/
280//
281//		Method:		AppleUSBCDCWCM::getFunctionalDescriptors
282//
283//		Inputs:
284//
285//		Outputs:	return - true (descriptors ok), false (somethings not right or not supported)
286//
287//		Desc:		Finds all the functional descriptors for the specific interface
288//
289/****************************************************************************************************/
290
291bool AppleUSBCDCWCM::getFunctionalDescriptors()
292{
293    bool				gotDescriptors = false;
294    UInt16				vers;
295    UInt16				*chkVers;
296    const FunctionalDescriptorHeader 	*funcDesc = NULL;
297    HDRFunctionalDescriptor		*HDRFDesc;		// header functional descriptor
298    WHCMFunctionalDescriptor		*WCMFDesc;		// whcm functional descriptor
299    UnionFunctionalDescriptor		*UNNFDesc;		// union functional descriptor
300
301    XTRACE(this, 0, 0, "getFunctionalDescriptors");
302
303    do
304    {
305        funcDesc = (const FunctionalDescriptorHeader *)fInterface->FindNextAssociatedDescriptor((void*)funcDesc, CS_INTERFACE);
306        if (!funcDesc)
307        {
308            gotDescriptors = true;				// We're done
309        } else {
310            switch (funcDesc->bDescriptorSubtype)
311            {
312                case Header_FunctionalDescriptor:
313                    HDRFDesc = (HDRFunctionalDescriptor *)funcDesc;
314                    XTRACE(this, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - Header Functional Descriptor");
315                    chkVers = (UInt16 *)&HDRFDesc->bcdCDC1;
316                    vers = USBToHostWord(*chkVers);
317                    if (vers > kUSBRel11)
318                    {
319                        XTRACE(this, vers, kUSBRel11, "getFunctionalDescriptors - Header descriptor version number is incorrect");
320                    }
321                    break;
322                case Union_FunctionalDescriptor:
323                    UNNFDesc = (UnionFunctionalDescriptor *)funcDesc;
324                    XTRACE(this, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - Union Functional Descriptor");
325                    if (UNNFDesc->bFunctionLength > sizeof(FunctionalDescriptorHeader))
326                    {
327						if (fInterfaceNumber != UNNFDesc->bMasterInterface)
328                        {
329                            XTRACE(this, fInterfaceNumber, UNNFDesc->bMasterInterface, "getFunctionalDescriptors - Master interface incorrect");
330                        } else {
331							fControlLen = UNNFDesc->bFunctionLength - sizeof(FunctionalDescriptorHeader);
332							fControlLen -= sizeof(UNNFDesc->bMasterInterface);					// Step over master as it's us and we've already checked it
333							fControlMap = (UInt8 *)IOMalloc(fControlLen);
334							bcopy(&UNNFDesc->bSlaveInterface, fControlMap, fControlLen);		// Just save them for now...
335							XTRACEP(this, fControlMap, fControlLen, "getFunctionalDescriptors - Map and length");
336						}
337                    } else {
338                        XTRACE(this, UNNFDesc->bFunctionLength, 0, "getFunctionalDescriptors - Union descriptor length error");
339                    }
340                    break;
341                case WCM_FunctionalDescriptor:
342                    WCMFDesc = (WHCMFunctionalDescriptor *)funcDesc;
343                    XTRACE(this, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - WHCM Functional Descriptor");
344                    chkVers = (UInt16 *)&WCMFDesc->bcdCDC1;
345                    vers = USBToHostWord(*chkVers);
346                    if (vers > kUSBRel10)
347                    {
348                        XTRACE(this, vers, kUSBRel10, "getFunctionalDescriptors - WHCM descriptor version number is incorrect");
349                    }
350                    break;
351                default:
352                    XTRACE(this, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - unknown Functional Descriptor");
353                    break;
354            }
355        }
356    } while(!gotDescriptors);
357
358
359
360    return true;
361
362}/* end getFunctionalDescriptors */
363
364/****************************************************************************************************/
365//
366//		Method:		AppleUSBCDCWCM::allocateResources
367//
368//		Inputs:
369//
370//		Outputs:	return code - true (allocate was successful), false (it failed)
371//
372//		Desc:		Finishes up the rest of the configuration
373//
374/****************************************************************************************************/
375
376bool AppleUSBCDCWCM::allocateResources()
377{
378
379    XTRACE(this, 0, 0, "allocateResources.");
380
381        // Open the interface
382
383    if (!fInterface->open(this))
384    {
385        XTRACE(this, 0, 0, "allocateResources - open comm interface failed.");
386        return false;
387    }
388
389    return true;
390
391}/* end allocateResources */
392
393/****************************************************************************************************/
394//
395//		Method:		AppleUSBCDCWCM::releaseResources
396//
397//		Inputs:
398//
399//		Outputs:
400//
401//		Desc:		Frees up the resources allocated in allocateResources
402//
403/****************************************************************************************************/
404
405void AppleUSBCDCWCM::releaseResources()
406{
407    XTRACE(this, 0, 0, "releaseResources");
408
409    if (fInterface)
410    {
411        fInterface->close(this);
412        fInterface->release();
413        fInterface = NULL;
414    }
415
416}/* end releaseResources */
417
418/****************************************************************************************************/
419//
420//		Method:		AppleUSBCDCWCM::resetLogicalHandset
421//
422//		Inputs:
423//
424//		Outputs:
425//
426//		Desc:		Reset the logical handset after waking.
427//
428/****************************************************************************************************/
429
430void AppleUSBCDCWCM::resetLogicalHandset(void)
431{
432
433    XTRACE(this, 0, 0, "resetLogicalHandset");
434
435    if ((fStopping) || (fInterface == NULL))
436    {
437        return;
438    }
439
440
441
442}/* end resetLogicalHandset */
443
444/****************************************************************************************************/
445//
446//		Method:		AppleUSBCDCWCM::message
447//
448//		Inputs:		type - message type
449//				provider - my provider
450//				argument - additional parameters
451//
452//		Outputs:	return Code - kIOReturnSuccess
453//
454//		Desc:		Handles IOKit messages.
455//
456/****************************************************************************************************/
457
458IOReturn AppleUSBCDCWCM::message(UInt32 type, IOService *provider, void *argument)
459{
460
461    XTRACE(this, 0, type, "message");
462
463    switch (type)
464    {
465        case kIOMessageServiceIsTerminated:
466            XTRACE(this, 0, type, "message - kIOMessageServiceIsTerminated");
467            fTerminate = true;		// We're being terminated (unplugged)
468            releaseResources();
469            return kIOReturnSuccess;
470        case kIOMessageServiceIsSuspended:
471            XTRACE(this, 0, type, "message - kIOMessageServiceIsSuspended");
472            break;
473        case kIOMessageServiceIsResumed:
474            XTRACE(this, 0, type, "message - kIOMessageServiceIsResumed");
475            break;
476        case kIOMessageServiceIsRequestingClose:
477            XTRACE(this, 0, type, "message - kIOMessageServiceIsRequestingClose");
478            break;
479        case kIOMessageServiceWasClosed:
480            XTRACE(this, 0, type, "message - kIOMessageServiceWasClosed");
481            break;
482        case kIOMessageServiceBusyStateChange:
483            XTRACE(this, 0, type, "message - kIOMessageServiceBusyStateChange");
484            break;
485        case kIOUSBMessagePortHasBeenResumed:
486            XTRACE(this, 0, type, "message - kIOUSBMessagePortHasBeenResumed");
487            break;
488        case kIOUSBMessageHubResumePort:
489            XTRACE(this, 0, type, "message - kIOUSBMessageHubResumePort");
490            break;
491        default:
492            XTRACE(this, 0, type, "message - unknown message");
493            break;
494    }
495
496    return super::message(type, provider, argument);
497
498}/* end message */
499
500/****************************************************************************************************/
501//
502//		Method:		AppleUSBCDCWCM::initForPM
503//
504//		Inputs:		provider - my provider
505//
506//		Outputs:	return code - true(initialized), false(failed)
507//
508//		Desc:		Add ourselves to the power management tree so we can do
509//				the right thing on sleep/wakeup.
510//
511/****************************************************************************************************/
512
513bool AppleUSBCDCWCM::initForPM(IOService *provider)
514{
515    XTRACE(this, 0, 0, "initForPM");
516
517    fPowerState = kCDCPowerOnState;				// init our power state to be 'on'
518    PMinit();							// init power manager instance variables
519    provider->joinPMtree(this);					// add us to the power management tree
520    if (pm_vars != NULL)
521    {
522
523            // register ourselves with ourself as policy-maker
524
525        registerPowerDriver(this, gOurPowerStates, kNumCDCStates);
526        return true;
527    } else {
528        XTRACE(this, 0, 0, "initForPM - Initializing power manager failed");
529    }
530
531    return false;
532
533}/* end initForPM */
534
535/****************************************************************************************************/
536//
537//		Method:		AppleUSBCDCWCM::initialPowerStateForDomainState
538//
539//		Inputs:		flags -
540//
541//		Outputs:	return code - Current power state
542//
543//		Desc:		Request for our initial power state.
544//
545/****************************************************************************************************/
546
547unsigned long AppleUSBCDCWCM::initialPowerStateForDomainState(IOPMPowerFlags flags)
548{
549
550    XTRACE(this, 0, flags, "initialPowerStateForDomainState");
551
552    return fPowerState;
553
554}/* end initialPowerStateForDomainState */
555
556/****************************************************************************************************/
557//
558//		Method:		AppleUSBCDCWCM::setPowerState
559//
560//		Inputs:		powerStateOrdinal - on/off
561//
562//		Outputs:	return code - IOPMNoErr, IOPMAckImplied or IOPMNoSuchState
563//
564//		Desc:		Request to turn device on or off.
565//
566/****************************************************************************************************/
567
568IOReturn AppleUSBCDCWCM::setPowerState(unsigned long powerStateOrdinal, IOService *whatDevice)
569{
570
571    XTRACE(this, 0, powerStateOrdinal, "setPowerState");
572
573    if (powerStateOrdinal == kCDCPowerOffState || powerStateOrdinal == kCDCPowerOnState)
574    {
575        if (powerStateOrdinal == fPowerState)
576            return IOPMAckImplied;
577
578        fPowerState = powerStateOrdinal;
579        if (fPowerState == kCDCPowerOnState)
580        {
581            resetLogicalHandset();
582        }
583
584        return IOPMAckImplied;
585    }
586
587    return IOPMAckImplied;
588
589}/* end setPowerState */