|
|
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: /*
23: * Copyright (c) 1998 Apple Computer, Inc. All rights reserved.
24: *
25: * HISTORY
26: *
27: */
28:
29:
30: #include "IOUSBHub.h"
31: #include <IOKit/usb/IOUSBController.h>
32:
33: //#define super IOService
34: #define self this
35: #define DEBUGGING_LEVEL 0 // 1 = low; 2 = high; 3 = extreme
36: #define DEBUGLOG kprintf
37:
38: static portStatusChangeVector defaultPortVectors[kNumChangeHandlers] =
39: {
40: { 0, kHubPortOverCurrent, kUSBHubPortOverCurrentChangeFeature },
41: { 0, kHubPortBeingReset, kUSBHubPortResetChangeFeature },
42: { 0, kHubPortSuspend, kUSBHubPortSuspendChangeFeature },
43: { 0, kHubPortEnabled, kUSBHubPortEnableChangeFeature },
44: { 0, kHubPortConnection, kUSBHubPortConnectionChangeFeature },
45: };
46:
47: void IOUSBHubPort::init( IOUSBHub *parent, int portNum, UInt32 powerAvailable )
48: {
49: _hub = parent;
50: _bus = parent->_bus;
51: _hubDesc = &parent->_hubDescriptor;
52: _portNum = portNum;
53: _portDevice = 0;
54: _portPowerAvailable = powerAvailable;
55: initPortVectors();
56:
57: if (!_hub) DEBUGLOG("init: _hub is invalid\n");
58: if (!_bus) DEBUGLOG("init: _bus is invalid\n");
59: if (!_hubDesc) DEBUGLOG("init: _hubDesc is invalid\n");
60: if (portNum < 1 || portNum > 64) DEBUGLOG("init: portNum is invalid\n");
61: }
62:
63: /*
64: * start:
65: * Here we really just need to turn on power to the ports. The change
66: * handler will take it from there. However, we need to check for 2 conditions
67: * before we exit:
68: * 1. are there permanent devices connected,
69: * 2. some hubs don't generate a change connection if the ports are
70: * powered on with a device already connected.
71: * If either of these exist, then add the port.
72: */
73: IOReturn IOUSBHubPort::start(void)
74: {
75: IOReturn err = kIOReturnSuccess;
76: IOUSBHubPortStatus status;
77:
78:
79: do
80: {
81: /* turn on Power to the port */
82: if ((err = _hub->SetPortFeature(kUSBHubPortPowerFeature, _portNum)))
83: {
84: fatalError(err, "setting port power");
85: break;
86: }
87:
88: if ((err = _hub->GetPortStatus(&status, _portNum)))
89: {
90: fatalError(err, "getting port status (1)");
91: break;
92: }
93:
94: #if (DEBUGGING_LEVEL > 0)
95: DEBUGLOG("0x%x\t(start) port %d status = %xs/%xc\n", _hub,
96: _portNum, status.statusFlags, status.changeFlags);
97: #endif
98:
99: // If there is a connection change, then let the handler take it
100: // from here. Also, in some cases the hub was in a suspend state
101: // (rather than a reset state) and does not register a connection
102: // change when the port is powered. So also check for a connection
103: // with no change connection.
104: // Is there a change connection OR no connection?
105: // THEN we're all done for now; int handler will take it from here
106: //if ((status.changeFlags & kHubPortConnection) ||
107: // (status.statusFlags & kHubPortConnection) == 0)
108: break;
109:
110: /* wait for the power on good time */
111: IOSleep(_hubDesc->powerOnToGood * 2);
112:
113: if ((err = _hub->GetPortStatus(&status, _portNum)))
114: {
115: fatalError(err, "getting port status (2)");
116: break;
117: }
118:
119: #if (DEBUGGING_LEVEL > 0)
120: DEBUGLOG("0x%x\t(start) port %d status = %xs/%xc\n", _hub,
121: _portNum, status.statusFlags, status.changeFlags);
122: #endif
123:
124: /* we now have port status */
125: if (status.changeFlags & kHubPortConnection)
126: {
127: if ((err = _hub->ClearPortFeature
128: (kUSBHubPortConnectionChangeFeature, _portNum)))
129: {
130: fatalError(err, "clearing port connection change");
131: break;
132: }
133:
134: /* We should now be in the disconnected state */
135: /* Do a port request on current port */
136: if ((err = _hub->GetPortStatus(&status, _portNum)))
137: {
138: fatalError(err, "getting port status (3)");
139: break;
140: }
141: }
142:
143: if (status.statusFlags & kHubPortConnection)
144: {
145: /* We have a connection on this port */
146: #if (DEBUGGING_LEVEL > 0)
147: DEBUGLOG("0x%x\t(start)device detected @ port %d\n", _hub,
148: _portNum);
149: #endif
150: if ((err = addDevice()))
151: fatalError(err, "adding device");
152: }
153: } while(false);
154:
155: return(err);
156: }
157:
158: void IOUSBHubPort::stop(void)
159: {
160: // Ugh. This could get nasty. What if stop is called while
161: // a thread is adding a device? I think we need to start tracking
162: // states. And we might need a flag to tell us where it's because
163: // the device has been unplugged, or the system is shutting down.
164:
165: removeDevice();
166: }
167:
168: IOReturn IOUSBHubPort::addDevice(void)
169: {
170: IOReturn err = kIOReturnSuccess;
171:
172: do
173: {
174: _devZero = _bus->AcquireDeviceZero() == kIOReturnSuccess;
175: if (!_devZero)
176: {
177: fatalError(/*FIXME*/0, "acquiring device zero");
178: break;
179: }
180:
181: if ((err = _hub->SetPortFeature(kUSBHubPortResetFeature,
182: _portNum)))
183: {
184: fatalError(err, "set feature (resetting port)");
185: break;
186: }
187: {
188: // Now poll for exit from reset.
189: IOUSBHubPortStatus status;
190: int portByte;
191: UInt8 portMask;
192: bool waitReset = true;
193: AbsoluteTime endResetTime, nowTime;
194: AbsoluteTime_to_scalar(&nowTime) = 0;
195: portByte = _portNum / 8;
196: portMask = 1 << (_portNum % 8);
197: clock_interval_to_deadline(1, kSecondScale, &endResetTime);
198: do
199: {
200: const UInt8* stat = _hub->getStatusChanged();
201: if(stat == NULL)
202: break;
203: // Check if we've waited long enough!
204: if( CMP_ABSOLUTETIME(&nowTime, &endResetTime) > 0) {
205: err = kIOReturnTimeout;
206: break;
207: }
208: clock_get_uptime(&nowTime);
209: if(!stat[portByte] & portMask) {
210: IOSleep(2);
211: continue;
212: }
213: /* Do a port status request on current port */
214: if ((err = _hub->GetPortStatus(&status, _portNum)))
215: {
216: fatalError(err, "get status (waiting for reset end)");
217: break;
218: }
219: #if (DEBUGGING_LEVEL > 0)
220: DEBUGLOG("0x%x\t(waiting for reset end) port %d status = %xs/%xc\n", _hub,
221: _portNum, status.statusFlags, status.changeFlags);
222: #endif
223: if(status.changeFlags & kHubPortBeingReset)
224: {
225: if ((err = _hub->ClearPortFeature(
226: kUSBHubPortResetChangeFeature, _portNum)))
227: {
228: fatalError(err, "clear port vector bit feature");
229: break;
230: }
231: err = addDeviceResetChangeHandler(status.changeFlags);
232: waitReset = false;
233: }
234: } while (waitReset);
235: }
236: } while(false);
237:
238: if (err && _devZero)
239: {
240: _bus->ReleaseDeviceZero();
241: _devZero = false;
242:
243: // put it back to the default if there was an error
244: #if (DEBUGGING_LEVEL > 0)
245: DEBUGLOG("error: setting change handler to default\n");
246: #endif
247: setPortVector(&IOUSBHubPort::defaultResetChangeHandler,
248: kHubPortBeingReset);
249: }
250:
251: return(err);
252: }
253:
254: void IOUSBHubPort::removeDevice(void)
255: {
256: bool ok;
257:
258: if (_portDevice) {
259: ok = _portDevice->terminate(kIOServiceRequired);
260: if( !ok)
261: DEBUGLOG("IOUSBHubPort: terminate() failed\n");
262: _portDevice->release();
263: _portDevice = 0;
264: }
265: initPortVectors();
266: }
267:
268: IOReturn IOUSBHubPort::resetDevice()
269: {
270: IOReturn err = kIOReturnSuccess;
271:
272: do {
273: _devZero = _bus->AcquireDeviceZero() == kIOReturnSuccess;
274: if (!_devZero)
275: {
276: fatalError(/*FIXME*/0, "acquiring device zero");
277: err = kIOReturnCannotLock;
278: break;
279: }
280:
281: setPortVector(&IOUSBHubPort::handleResetDevice, kHubPortBeingReset);
282:
283: err = _hub->SetPortFeature(kUSBHubPortResetFeature, _portNum);
284: if(err != kIOReturnSuccess)
285: break;
286:
287: } while (false);
288:
289: if(err == kIOReturnSuccess)
290: {
291: _bus->WaitForReleaseDeviceZero();
292: }
293: else if(_devZero)
294: {
295: _bus->ReleaseDeviceZero();
296: _devZero = false;
297: }
298:
299: return err;
300: }
301:
302: IOReturn IOUSBHubPort::handleResetDevice(UInt16 changeFlags)
303: {
304: IOReturn err = kIOReturnSuccess;
305:
306: setPortVector(&IOUSBHubPort::defaultResetChangeHandler, kHubPortBeingReset);
307: /* Now address the device */
308: _bus->ConfigureDeviceZero(_desc.maxPacketSize, _speed);
309: err = _bus->SetDeviceZeroAddress(_portDevice->address(),
310: _desc.maxPacketSize, _speed);
311:
312: _bus->ReleaseDeviceZero();
313: _devZero = false;
314:
315: return err;
316: }
317:
318: void IOUSBHubPort::fatalError(IOReturn err, char *str)
319: {
320: DEBUGLOG("IOUSBHubPort: Error 0x%x on port %d: %s\n", err, _portNum, str);
321: if (_portDevice != 0)
322: {
323: DEBUGLOG("IOUSBHubPort: Removing %s from port %d\n",
324: _portDevice->getName(), _portNum);
325: removeDevice();
326: }
327: }
328:
329:
330: /**********************************************************************
331: **
332: ** CHANGE HANDLER FUNCTIONS
333: **
334: **********************************************************************/
335: IOReturn IOUSBHubPort::addDeviceResetChangeHandler(UInt16 changeFlags)
336: {
337: IOReturn err = kIOReturnSuccess;
338: IOUSBHubPortStatus status;
339:
340: do
341: {
342: /* Tell the USB to add the device */
343: if ((err = _hub->GetPortStatus(&status, _portNum)))
344: {
345: fatalError(err, "getting port status (3)");
346: break;
347: }
348:
349: if (status.statusFlags & kHubPortBeingReset)
350: {
351: DEBUGLOG("%s: port not finished resetting, retrying\n", _hub->getName());
352: // we should never be here, just wait for another status change int
353: break;
354: }
355:
356: // macally iKey doesn't tell us until now what the device speed is.
357: _speed = ((status.statusFlags & kHubPortSpeed) != 0);
358: #if (DEBUGGING_LEVEL > 0)
359: DEBUGLOG("0x%x\t(reset end) port %d status = %xs/%xc, %s speed\n", _hub,
360: _portNum, status.statusFlags, status.changeFlags, _speed ? "low" : "high");
361: #endif
362:
363: /* Now wait 10 ms after reset */
364: IOSleep(10);
365:
366: // Configure algorithm:
367: // * start with maxpacketsize of 8.
368: // This is the smallest legal maxpacket, and the only legal size for
369: // low-speed devices. The correct maxpacket size is in byte 8 of the
370: // device descriptor, so even if the device sends back a bigger packet
371: // (an overrun error) we should still get the correct value.
372: // * get device descriptor.
373: // * if we recieved the whole descriptor AND maxpacketsize is 64,
374: // success, so continue on.
375: // * if descriptor returns with a different maxpacketsize, then
376: // reconfigure with the new one and try again. Otherwise,
377: // reconfigure with 8 and try again.
378: if ((err = _bus->ConfigureDeviceZero(8, _speed)))
379: {
380: fatalError(err, "configuring endpoint zero");
381: break;
382: }
383:
384: // Now do a device request to find out what it is
385: // Some fast devices send back packets > 8 bytes to address 0.
386: bzero(&_desc, sizeof(_desc));
387: err = _bus->GetDeviceZeroDescriptor(&_desc);
388:
389: #if (DEBUGGING_LEVEL > 0)
390: DEBUGLOG("IOUSBHubPort: getDeviceDescriptor err = 0x%x max = %d numconf = %d\n", err, _desc.maxPacketSize, _desc.numConf);
391: #endif
392: // Check for specific conditions here before going on.
393: // 1) if the pipe cannot handle the default max packet size of 8,
394: // then reconfigure the pipe and try again. If just the size is
395: // wrong, it should return at least the correct size if not
396: // the whole descriptor.
397: // 2) If there is still an err, bail out.
398: if (err || _desc.maxPacketSize != 8)
399: {
400: // Reconfigure the pipe if the max packet size is not the default
401: // of 8, but we explicitly don't want to set it to 0. It might be
402: // good to do a little more checking here...later.
403: if (_desc.maxPacketSize != 0 && _desc.maxPacketSize != 8)
404: {
405: err = _bus->ConfigureDeviceZero(_desc.maxPacketSize, _speed);
406: err = _bus->GetDeviceZeroDescriptor(&_desc);
407: }
408: // The device really didn't like 8. Probably got a stall or
409: // something like that. As a last ditch effort, try 64.
410: else if (err)
411: {
412: err = _bus->ConfigureDeviceZero(64, _speed);
413: err = _bus->GetDeviceZeroDescriptor(&_desc);
414: }
415:
416: if (err == kIOReturnOverrun)
417: {
418: // Not sure what to do with this error. It means more data
419: // came back than the size of a descriptor. Hmmm. For now
420: // just ignore it and assume the data that did come back is
421: // useful.
422: #if (DEBUGGING_LEVEL > 0)
423: DEBUGLOG("%s: overrun error reading device descriptor\n",
424: _hub->getName());
425: #endif
426: }
427:
428: if (err)
429: {
430: fatalError(err, "getting full device descriptor");
431: continue;
432: }
433: }
434:
435: /* ERIC FIXME? what are we doing here?
436: if ((_hubDescriptor.removablePortFlags[pp->portByte] & pp->portMask))
437: {
438: pb->usbOther = powerForCaptive;
439: }
440: else
441: {
442: pb->usbOther = selfPowerGood?kUSB500mAAvailable:kUSB100mAAvailable;
443: }
444: */
445:
446: /* Now create and address the device */
447: if ((_portDevice = _bus->MakeDevice(&_desc, _speed, _portPowerAvailable)) == 0)
448: {
449: _portDevice = 0;
450: err = kIOReturnDeviceError;
451: fatalError(err, "setting the device address");
452: continue;
453: }
454: /* Tell the device who it's port is */
455: _portDevice->setPort(this);
456:
457: /* Release */
458: _bus->ReleaseDeviceZero();
459: _devZero = false;
460:
461: /* Finally use the data gathered */
462: _portDevice->registerService();
463:
464: } while(false);
465:
466: // reset the vector back to the default
467: #if (DEBUGGING_LEVEL > 0)
468: DEBUGLOG("0x%x\t(port %d)setting change handler to default\n", _hub, _portNum);
469: #endif
470: setPortVector(&IOUSBHubPort::defaultResetChangeHandler, kHubPortBeingReset);
471:
472: if (err)
473: {
474: if (_devZero)
475: {
476: _bus->ReleaseDeviceZero();
477: _devZero = false;
478: }
479: }
480: return err;
481: }
482:
483: IOReturn IOUSBHubPort::defaultOverCrntChangeHandler(UInt16 changeFlags)
484: {
485: #if (DEBUGGING_LEVEL > 0)
486: DEBUGLOG("IOUSBHubPort: over current change notification\n");
487: #endif
488: return kIOReturnSuccess;
489: }
490:
491: IOReturn IOUSBHubPort::defaultResetChangeHandler(UInt16 changeFlags)
492: {
493: #if (DEBUGGING_LEVEL > 0)
494: DEBUGLOG("IOUSBHubPort: reset change notification\n");
495: #endif
496: return kIOReturnSuccess;
497: }
498:
499: IOReturn IOUSBHubPort::defaultSuspendChangeHandler(UInt16 changeFlags)
500: {
501: #if (DEBUGGING_LEVEL > 0)
502: DEBUGLOG("IOUSBHubPort: suspend change notification\n");
503: #endif
504: return kIOReturnSuccess;
505: }
506:
507: IOReturn IOUSBHubPort::defaultEnableChangeHandler(UInt16 changeFlags)
508: {
509: IOReturn err = kIOReturnSuccess;
510: IOUSBHubPortStatus status;
511:
512: #if (DEBUGGING_LEVEL > 0)
513: DEBUGLOG("IOUSBHubPort: enable change notification\n");
514: #endif
515:
516: if ((err = _hub->GetPortStatus(&status, _portNum)))
517: {
518: fatalError(err, "getting port status");
519: return err;
520: }
521:
522: if (!(status.statusFlags & kHubPortEnabled) &&
523: !(changeFlags & kHubPortConnection))
524: {
525: // The hub gave us an enable status change and we're
526: // now disabled, strange. Cosmo does this sometimes,
527: // try Re-enabling the port.
528: #if (DEBUGGING_LEVEL > 0)
529: DEBUGLOG("IOUSBHubPort: re-enabling dead port %d\n", _portNum);
530: #endif
531: if ((err = _hub->SetPortFeature(kUSBHubPortEnableFeature, _portNum)))
532: fatalError(err, "re-enabling dead port");
533: }
534: return err;
535: }
536:
537: IOReturn IOUSBHubPort::defaultConnectionChangeHandler(UInt16 changeFlags)
538: {
539: IOReturn err = kIOReturnSuccess;
540: IOUSBHubPortStatus status;
541:
542: #if (DEBUGGING_LEVEL > 0)
543: DEBUGLOG("0x%x\t(port %d)connection change notification\n", _hub, _portNum);
544: #endif
545:
546: do
547: {
548: /* wait for the power on good time */
549: IOSleep(_hubDesc->powerOnToGood * 2);
550:
551: // If we get to here, there was a connection change
552: // if we already have a device it must have been disconnected
553: // at sometime. We should kill it before servicing a connect event
554: if (_portDevice != 0)
555: {
556: #if (DEBUGGING_LEVEL > 0)
557: DEBUGLOG("0x%x\t(port %d): removing %s device @ %d\n",
558: _hub, _portNum, _portDevice->getName(), _portDevice->address());
559: #endif
560:
561: removeDevice();
562: }
563:
564: // BT 23Jul98 Check port again after delay. Get bounced connections
565: /* Do a port status request on current port */
566: if ((err = _hub->GetPortStatus(&status, _portNum)))
567: {
568: fatalError(err, "getting port status");
569: break;
570: }
571:
572: #if (DEBUGGING_LEVEL > 0)
573: DEBUGLOG("0x%x\t(conn change) port %d status = %xs/%xc\n", _hub,
574: _portNum, status.statusFlags, status.changeFlags);
575: #endif
576:
577: if (status.changeFlags & kHubPortConnection)
578: {
579: DEBUGLOG("IOUSBHubPort: connection bounce\n");
580: break;
581: }
582:
583: if (status.statusFlags & kHubPortConnection)
584: {
585: /* We have a connection on this port */
586: #if (DEBUGGING_LEVEL > 0)
587: DEBUGLOG("0x%x\tdevice detected @ port %d\n", _hub, _portNum);
588: #endif
589: for(int i=0; i<2; i++) {
590: err = addDevice();
591: if (err == kIOReturnSuccess)
592: break;
593: err = _hub->ClearPortFeature(kUSBHubPortEnableFeature, _portNum);
594: if (err != kIOReturnSuccess)
595: fatalError(err, "adding device");
596: }
597: }
598:
599: } while(false);
600: return err;
601: }
602:
603: bool IOUSBHubPort::statusChanged(void)
604: {
605: IOReturn err = kIOReturnSuccess;
606: int which;
607: IOUSBHubPortStatus status;
608:
609:
610: do
611: {
612: /* Do a port status request on current port */
613: if ((err = _hub->GetPortStatus(&status, _portNum)))
614: {
615: fatalError(err, "get status (first in port status change)");
616: break;
617: }
618:
619: #if (DEBUGGING_LEVEL > 0)
620: DEBUGLOG("0x%x\t(status changed 1) port %d status = %xs/%xc\n", _hub,
621: _portNum, status.statusFlags, status.changeFlags);
622: #endif
623:
624: // First clear the change condition before we return. This prevents
625: // a race condition for handling the change.
626: for (which = 0; which < kNumChangeHandlers; which++)
627: {
628: // sometimes a change is reported but there really is
629: // no change. This will catch that.
630: if (!(status.changeFlags & _changeHandler[which].bit))
631: continue;
632:
633: if ((err = _hub->ClearPortFeature(
634: _changeHandler[which].clearFeature, _portNum)))
635: {
636: fatalError(err, "clear port vector bit feature");
637: continue;
638: }
639: }
640:
641: err = statusChangeHandler(status.changeFlags);
642:
643: } while(false);
644:
645: return(err == kIOReturnSuccess);
646: }
647:
648:
649: IOReturn IOUSBHubPort::statusChangeHandler(UInt16 changeFlags)
650: {
651: int which;
652: IOReturn res = kIOReturnSuccess;
653:
654: // Handle each change in sequential order.
655: for (which = 0; which < kNumChangeHandlers; which++)
656: {
657: if (!(changeFlags & _changeHandler[which].bit))
658: continue;
659: res = (self->*_changeHandler[which].handler)(changeFlags);
660: if(res != kIOReturnSuccess)
661: break;
662: }
663:
664: return(res);
665: }
666:
667:
668: void IOUSBHubPort::initPortVectors(void)
669: {
670: int vector;
671: for (vector = 0; vector < kNumChangeHandlers; vector++)
672: {
673: _changeHandler[vector] = defaultPortVectors[vector];
674: switch (defaultPortVectors[vector].bit)
675: {
676: case kHubPortOverCurrent:
677: _changeHandler[vector].handler =
678: &IOUSBHubPort::defaultOverCrntChangeHandler;
679: break;
680: case kHubPortBeingReset:
681: _changeHandler[vector].handler =
682: &IOUSBHubPort::defaultResetChangeHandler;
683: break;
684: case kHubPortSuspend:
685: _changeHandler[vector].handler =
686: &IOUSBHubPort::defaultSuspendChangeHandler;
687: break;
688: case kHubPortEnabled:
689: _changeHandler[vector].handler =
690: &IOUSBHubPort::defaultEnableChangeHandler;
691: break;
692: case kHubPortConnection:
693: _changeHandler[vector].handler =
694: &IOUSBHubPort::defaultConnectionChangeHandler;
695: break;
696: }
697: }
698: }
699:
700: void IOUSBHubPort::setPortVector(ChangeHandlerFuncPtr routine,
701: UInt32 condition)
702: {
703: int vector;
704: for(vector = 0; vector < kNumChangeHandlers; vector++)
705: {
706: if(condition == _changeHandler[vector].bit)
707: {
708: _changeHandler[vector].handler = routine;
709: }
710: }
711: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.