|
|
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 "AppleOHCI.h"
31: #include <libkern/OSByteOrder.h>
32:
33: #define nil (0)
34: #define DEBUGGING_LEVEL 0 // 1 = low; 2 = high; 3 = extreme
35:
36: #define super IOUSBController
37: #define self this
38:
39: /*
40: * Root hub methods
41: */
42: // FIXME Should this routine go in the device?
43: IOReturn AppleOHCI::getRootHubDeviceDescriptor(IOUSBDeviceDescriptor *desc)
44: {
45: IOUSBDeviceDescriptor newDesc =
46: {
47: sizeof(IOUSBDeviceDescriptor), // UInt8 length;
48: kUSBDeviceDesc, // UInt8 descType;
49: USB_CONSTANT16(kUSBRel10), // UInt16 usbRel;
50: kUSBHubClass, // UInt8 class;
51: kUSBRootHubSubClass, // UInt8 subClass;
52: 0, // UInt8 protocol;
53: 8, // UInt8 maxPacketSize;
54: USB_CONSTANT16(_vendorID), // UInt16 vendor;
55: USB_CONSTANT16(_deviceID), // UInt16 product;
56: USB_CONSTANT16(_revisionID), // UInt16 devRel;
57: 0, // UInt8 manuIdx;
58: 0, // UInt8 prodIdx;
59: 0, // UInt8 serialIdx;
60: 1 // UInt8 numConf;
61: };
62:
63: if (!desc)
64: return(kIOReturnNoMemory);
65:
66: bcopy(&newDesc, desc, newDesc.length);
67:
68: return(kIOReturnSuccess);
69: }
70:
71: IOReturn AppleOHCI::getRootHubDescriptor(IOUSBHubDescriptor *desc)
72: {
73: IOUSBHubDescriptor hubDesc;
74: UInt8 pps, nps, cd, ppoc, noc;
75: UInt32 descriptorA, descriptorB;
76:
77:
78: descriptorA = OSSwapInt32(pOHCIUIMData->pOHCIRegisters->hcRhDescriptorA);
79: descriptorB = OSSwapInt32(pOHCIUIMData->pOHCIRegisters->hcRhDescriptorB);
80: hubDesc.length = sizeof(IOUSBHubDescriptor);
81: hubDesc.hubType = kUSBHubDescriptorType;
82: hubDesc.numPorts = ((descriptorA & kOHCIHcRhDescriptorA_NDP)
83: >> kOHCIHcRhDescriptorA_NDPPhase);
84: // Characteristics
85: pps = descriptorA & kOHCIHcRhDescriptorA_PSM;
86: nps = descriptorA & kOHCIHcRhDescriptorA_NPS;
87: cd = descriptorA & kOHCIHcRhDescriptorA_DT;
88: ppoc = descriptorA & kOHCIHcRhDescriptorA_OCPM;
89: noc = descriptorA & kOHCIHcRhDescriptorA_NOCP;
90: hubDesc.characteristics = 0;
91: hubDesc.characteristics |= (pps ? kPerPortSwitchingBit : 0);
92: hubDesc.characteristics |= (nps ? kNoPowerSwitchingBit : 0);
93: hubDesc.characteristics |= (cd ? kCompoundDeviceBit : 0);
94: hubDesc.characteristics |= (ppoc ? kPerPortOverCurrentBit : 0);
95: hubDesc.characteristics |= (noc ? kNoOverCurrentBit : 0);
96: hubDesc.characteristics = HostToUSBWord(hubDesc.characteristics);
97:
98: hubDesc.powerOnToGood = ((descriptorA & kOHCIHcRhDescriptorA_POTPGT)
99: >> kOHCIHcRhDescriptorA_POTPGTPhase);
100: // the root hub has no power requirements
101: hubDesc.hubCurrent = 0;
102:
103: // bitmap of removable ports
104: *((UInt16*)&hubDesc.removablePortFlags[0]) =
105: ((descriptorB & kOHCIHcRhDescriptorB_DR)
106: >> kOHCIHcRhDescriptorB_DRPhase);
107: *((UInt16 *)&hubDesc.removablePortFlags[2]) = 0; // OHCI supports 15 ports
108: *((UInt32 *)&hubDesc.removablePortFlags[4]) = 0; // so zero out the rest
109:
110: // bitmap of power mode for each port
111: *((UInt16 *)&hubDesc.pwrCtlPortFlags[0]) =
112: ((descriptorB & kOHCIHcRhDescriptorB_PPCM)
113: >> kOHCIHcRhDescriptorB_PPCMPhase);
114: *((UInt16 *)&hubDesc.pwrCtlPortFlags[2]) = 0; // OHCI supports 15 ports
115: *((UInt32 *)&hubDesc.pwrCtlPortFlags[4]) = 0; // so zero out the rest
116:
117: if (!desc)
118: return(kIOReturnNoMemory);
119:
120: bcopy(&hubDesc, desc, hubDesc.length);
121:
122: /*
123: if (!buffer->appendBytes(&hubDesc, hubDesc.length))
124: return(kIOReturnNoMemory);
125: */
126:
127: return(kIOReturnSuccess);
128: }
129:
130: IOReturn AppleOHCI::getRootHubConfDescriptor(OSData *desc)
131: {
132: IOUSBConfigurationDescriptor confDesc =
133: {
134: sizeof(IOUSBConfigurationDescriptor),//UInt8 length;
135: kUSBConfDesc, //UInt8 descriptorType;
136: USB_CONSTANT16(sizeof(IOUSBConfigurationDescriptor) +
137: sizeof(IOUSBInterfaceDescriptor) +
138: sizeof(IOUSBEndpointDescriptor)), //UInt16 totalLength;
139: 1, //UInt8 numInterfaces;
140: 1, //UInt8 configValue;
141: 0, //UInt8 configStrIndex;
142: 0x60, //UInt8 attributes; self powered,
143: // supports remote wkup
144: 0, //UInt8 maxPower;
145: };
146: IOUSBInterfaceDescriptor intfDesc =
147: {
148: sizeof(IOUSBInterfaceDescriptor),//UInt8 length;
149: kUSBInterfaceDesc, //UInt8 descriptorType;
150: 0, //UInt8 interfaceNumber;
151: 0, //UInt8 alternateSetting;
152: 1, //UInt8 numEndpoints;
153: kUSBHubClass, //UInt8 interfaceClass;
154: kUSBHubSubClass, //UInt8 interfaceSubClass;
155: 1, //UInt8 interfaceProtocol;
156: 0 //UInt8 interfaceStrIndex;
157: };
158: IOUSBEndpointDescriptor endptDesc =
159: {
160: sizeof(IOUSBEndpointDescriptor),//UInt8 length;
161: kUSBEndpointDesc, //UInt8 descriptorType;
162: 0x81, //UInt8 endpointAddress; In, 1
163: kUSBInterrupt, //UInt8 attributes;
164: 8, 0, //UInt16 maxPacketSize;
165: 255, //UInt8 interval;
166: };
167:
168: if (!desc)
169: return(kIOReturnNoMemory);
170:
171: if (!desc->appendBytes(&confDesc, confDesc.length))
172: return(kIOReturnNoMemory);
173:
174: if (!desc->appendBytes(&intfDesc, intfDesc.length))
175: return(kIOReturnNoMemory);
176:
177: if (!desc->appendBytes(&endptDesc, endptDesc.length))
178: return(kIOReturnNoMemory);
179:
180: return(kIOReturnSuccess);
181: }
182:
183: IOReturn AppleOHCI::setRootHubDescriptor(OSData * /*buffer*/)
184: {
185: IOLog("%s: unimplemented set root hub descriptor\n", getName());
186: return(kIOReturnSuccess);
187: }
188:
189: IOReturn AppleOHCI::getRootHubStatus(IOUSBHubStatus *status)
190: {
191: *(UInt32*)status = pOHCIUIMData->pOHCIRegisters->hcRhStatus;
192: return(kIOReturnSuccess);
193: }
194:
195: IOReturn AppleOHCI::setRootHubFeature(UInt16 wValue)
196: {
197: switch(wValue)
198: {
199: case kUSBHubLocalPowerChangeFeature :
200: IOLog("%s: unimplemented Set Power Change Feature\n", getName());
201: // OHCIRootHubLPSChange(true); // not implemented yet
202: break;
203:
204: case kUSBHubOverCurrentChangeFeature :
205: IOLog("%s: unimplemented Set Overcurrent Change Feature\n",
206: getName());
207: // OHCIRootHubOCChange(true); // not implemented yet
208: break;
209:
210: default:
211: IOLog("%s: Unknown hub set (%d) in root hub\n", getName(), wValue);
212: break;
213: }
214:
215: return(kIOReturnSuccess);
216: }
217:
218: IOReturn AppleOHCI::clearRootHubFeature(UInt16 wValue)
219: {
220: switch(wValue)
221: {
222: case kUSBHubLocalPowerChangeFeature :
223: IOLog("%s: unimplemented Clear Power Change Feature\n", getName());
224: // OHCIRootHubLPSChange(false); // not implemented yet
225: break;
226:
227: case kUSBHubOverCurrentChangeFeature :
228: IOLog("%s: unimplemented Clear Overcurrent Change Feature\n",
229: getName());
230: // OHCIRootHubOCChange(false); // not implemented yet
231: break;
232:
233: default:
234: IOLog("%s: Unknown hub set (%d) in root hub\n", getName(), wValue);
235: break;
236: }
237:
238: return(kIOReturnSuccess);
239: }
240:
241: IOReturn AppleOHCI::getRootHubPortStatus(IOUSBHubPortStatus *status, UInt16 port)
242: {
243: if (port < 1 || port > 15)
244: return(kIOReturnBadArgument); // FIXME change error code
245: *(UInt32*)status = pOHCIUIMData->pOHCIRegisters->hcRhPortStatus[port-1];
246: return(kIOReturnSuccess);
247: }
248:
249: IOReturn AppleOHCI::setRootHubPortFeature(UInt16 wValue, UInt16 wIndex)
250: {
251: UInt16 port = wIndex-1;
252:
253: switch(wValue)
254: {
255: case kUSBHubPortSuspendFeature :
256: OHCIRootHubPortSuspend(port, true);
257: break;
258:
259: case kUSBHubPortResetFeature :
260: OHCIRootHubResetPort(port);
261: break;
262:
263: case kUSBHubPortEnableFeature :
264: OHCIRootHubPortEnable(port, true);
265: break;
266:
267: case kUSBHubPortPowerFeature :
268: OHCIRootHubPortPower(port, true);
269: OHCIRootHubPower(true);
270: break;
271:
272: default:
273: IOLog("%s: Unknown port set (%d) in root hub\n", getName(), wValue);
274: break;
275: }
276: return(kIOReturnSuccess);
277: }
278:
279: IOReturn AppleOHCI::clearRootHubPortFeature(UInt16 wValue, UInt16 wIndex)
280: {
281: UInt16 port = wIndex-1;
282:
283: switch(wValue)
284: {
285: case kUSBHubPortEnableFeature :
286: OHCIRootHubPortEnable(port, false);
287: break;
288:
289: case kUSBHubPortSuspendFeature :
290: OHCIRootHubPortSuspend(port, false);
291: break;
292:
293: case kUSBHubPortPowerFeature :
294: OHCIRootHubPortPower(port, false);
295: // Now need to check if all ports are switched off and
296: // gang off if in gang mode
297: break;
298:
299: // ****** Change features *******
300: case kUSBHubPortConnectionChangeFeature :
301: OHCIRootHubResetChangeConnection(port);
302: break;
303:
304: case kUSBHubPortEnableChangeFeature :
305: OHCIRootHubResetEnableChange(port);
306: break;
307:
308: case kUSBHubPortSuspendChangeFeature :
309: OHCIRootHubResetSuspendChange(port);
310: break;
311:
312: case kUSBHubPortOverCurrentChangeFeature :
313: OHCIRootHubResetOverCurrentChange(port);
314: break;
315:
316: case kUSBHubPortResetChangeFeature :
317: OHCIRootHubResetResetChange(port);
318: break;
319:
320: default:
321: IOLog("%s: Unknown port clear (%d) in root hub\n", getName(), wValue);
322: break;
323: }
324: return(kIOReturnSuccess);
325: }
326:
327: IOReturn AppleOHCI::getRootHubPortState(UInt8 */*state*/, UInt16 /*port*/)
328: {
329: IOLog("%s: unimplemented get hub bus state", getName());
330: return(kIOReturnSuccess);
331: }
332:
333:
334: IOReturn AppleOHCI::setHubAddress(UInt16 wValue)
335: {
336: pOHCIUIMData->rootHubFuncAddress = wValue;
337: return (kIOReturnSuccess);
338: }
339:
340: void AppleOHCI::OHCIRootHubPower(bool on)
341: {
342: UInt32 value = 0;
343: OHCIRegistersPtr pOHCIRegisters = pOHCIUIMData->pOHCIRegisters;
344:
345: pOHCIRegisters->hcRhDescriptorA = OSSwapInt32 (OSSwapInt32(pOHCIUIMData->pOHCIRegisters->hcRhDescriptorA) | kOHCIHcRhDescriptorA_NPS); //FIXME ERIC
346:
347: if(on)
348: {
349: value |= kOHCIHcRhStatus_LPSC;/* power on to all ganged ports */
350: value |= kOHCIHcRhStatus_CRWE;/* clear remove wakeup enable */
351: value |= kOHCIHcRhStatus_OCIC;/* clear over current change indicator */
352: }
353: else
354: value |= kOHCIHcRhStatus_LPS; /* turn global power off */
355:
356: pOHCIRegisters->hcRhStatus = OSSwapInt32 (value);
357:
358: return;
359: }
360:
361: void AppleOHCI::OHCIRootHubResetChangeConnection(UInt16 port)
362: {
363: UInt32 value = 0;
364: OHCIRegistersPtr pOHCIRegisters = pOHCIUIMData->pOHCIRegisters;
365:
366:
367: value |= kOHCIHcRhPortStatus_CSC; /* clear status change */
368:
369: pOHCIRegisters->hcRhPortStatus[port] = OSSwapInt32 (value);
370: IOSync();
371:
372: return;
373: }
374:
375:
376: void AppleOHCI::OHCIRootHubResetResetChange(UInt16 port)
377: {
378: UInt32 value = 0;
379: OHCIRegistersPtr pOHCIRegisters = pOHCIUIMData->pOHCIRegisters;
380:
381:
382: value |= kOHCIHcRhPortStatus_PRSC; /* clear reset status change */
383:
384: pOHCIRegisters->hcRhPortStatus[port] = OSSwapInt32 (value);
385: IOSync();
386:
387: return;
388: }
389:
390: void AppleOHCI::OHCIRootHubResetSuspendChange(UInt16 port)
391: {
392: UInt32 value = 0;
393: OHCIRegistersPtr pOHCIRegisters = pOHCIUIMData->pOHCIRegisters;
394:
395:
396: value |= kOHCIHcRhPortStatus_PSSC; /* clear suspend status change */
397:
398: pOHCIRegisters->hcRhPortStatus[port] = OSSwapInt32 (value);
399: IOSync();
400:
401: return;
402: }
403:
404: void AppleOHCI::OHCIRootHubResetEnableChange(UInt16 port)
405: {
406: UInt32 value = 0;
407: OHCIRegistersPtr pOHCIRegisters = pOHCIUIMData->pOHCIRegisters;
408:
409:
410: value |= kOHCIHcRhPortStatus_PESC; /* clear enable status change */
411:
412: pOHCIRegisters->hcRhPortStatus[port] = OSSwapInt32 (value);
413: IOSync();
414:
415: return;
416: }
417:
418:
419:
420: void AppleOHCI::OHCIRootHubResetOverCurrentChange(UInt16 port)
421: {
422: UInt32 value = 0;
423: OHCIRegistersPtr pOHCIRegisters = pOHCIUIMData->pOHCIRegisters;
424:
425:
426: value |= kOHCIHcRhPortStatus_OCIC; /* clear over current status change */
427:
428: pOHCIRegisters->hcRhPortStatus[port] = OSSwapInt32 (value);
429: IOSync();
430:
431: return;
432: }
433:
434:
435: void AppleOHCI::OHCIRootHubResetPort (UInt16 port)
436: {
437: UInt32 value = 0;
438: OHCIRegistersPtr pOHCIRegisters = pOHCIUIMData->pOHCIRegisters;
439:
440:
441: value |= kOHCIHcRhPortStatus_PRS; /* sets Bit 8 in port root hub register */
442: pOHCIRegisters->hcRhPortStatus[port] = OSSwapInt32 (value);
443: IOSync();
444: return;
445:
446: }
447:
448: void AppleOHCI::OHCIRootHubPortEnable(UInt16 port,
449: bool on)
450: {
451: UInt32 value = 0;
452: OHCIRegistersPtr pOHCIRegisters = pOHCIUIMData->pOHCIRegisters;
453:
454:
455: if(on)
456: value |= kOHCIHcRhPortStatus_PES; /* enable port */
457: else
458: value |= kOHCIHcRhPortStatus_CCS; /* disable port */
459:
460: pOHCIRegisters->hcRhPortStatus[port] = OSSwapInt32 (value);
461: IOSync();
462:
463: return;
464: }
465:
466: void AppleOHCI::OHCIRootHubPortSuspend(UInt16 port,
467: bool on)
468: {
469: UInt32 value = 0;
470: OHCIRegistersPtr pOHCIRegisters = pOHCIUIMData->pOHCIRegisters;
471:
472:
473: if(on)
474: value |= kOHCIHcRhPortStatus_PSS; /* suspend port */
475: else
476: value |= kOHCIHcRhPortStatus_POCI; /* resume port */
477:
478: pOHCIRegisters->hcRhPortStatus[port] = OSSwapInt32 (value);
479: IOSync();
480:
481: return;
482: }
483:
484: void AppleOHCI::OHCIRootHubPortPower(UInt16 port,
485: bool on)
486: {
487: UInt32 value = 0;
488: OHCIRegistersPtr pOHCIRegisters = pOHCIUIMData->pOHCIRegisters;
489:
490:
491: if(on)
492: value |= kOHCIHcRhPortStatus_PPS; /* enable port power */
493: else
494: value |= kOHCIHcRhPortStatus_LSDA; /* disable port power */
495:
496: pOHCIRegisters->hcRhPortStatus[port] = OSSwapInt32 (value);
497: IOSync();
498:
499: return;
500: }
501:
502: /*
503: * UIMRootHubStatusChange
504: *
505: * This method gets called when there is a change in the root hub status
506: * or a change in the status of one of the ports. It is assumed that the
507: * interrupt will be cleared for us, but we don't clear the change
508: * condition, we will get another interrupt. So turn off the interrupt.
509: * Entering this function means that someone turned on the RHSC interrupt
510: * and that there is a client waiting in the queue. The client expects a
511: * status change bitmap.
512: * To fix: currently there can only be one client in the queue. The RHSC
513: * interrupt should only be turned off if there is no one else in the queue,
514: * or, all clients should be responded to with the one interrupt.
515: */
516: void AppleOHCI::UIMRootHubStatusChange(void)
517: {
518: OHCIRegistersPtr pOHCIRegisters = pOHCIUIMData->pOHCIRegisters;
519: UInt32 hubStatus, portStatus, statusBit;
520: UInt16 statusChangedBitmap; /* only have 15 ports in OHCI */
521: UInt8 numPorts;
522: unsigned int index, port, move;
523: struct InterruptTransaction last;
524: UInt32 descriptorA;
525:
526:
527: /* turn off RHSC interrupt */
528: pOHCIRegisters->hcInterruptDisable = OSSwapInt32(kOHCIHcInterrupt_RHSC);
529: IOSync();
530:
531: /*
532: * Encode the status change bitmap. The format of the bitmap:
533: * bit0 = hub status changed
534: * bit1 = port 1 status changed
535: * bit2 = port 2 status changed
536: * ...
537: * See USB 1.0 spec section 11.8.3 for more info.
538: */
539:
540: statusChangedBitmap = 0;
541: statusBit = 1;
542:
543: getRootHubStatus((IOUSBHubStatus *)&hubStatus);
544: if ((hubStatus & kOHCIHcRhStatus_Change ) != 0)
545: statusChangedBitmap |= statusBit; /* Hub status change bit */
546:
547: descriptorA = OSSwapInt32(pOHCIRegisters->hcRhDescriptorA);
548: numPorts = ((descriptorA & kOHCIHcRhDescriptorA_NDP)
549: >> kOHCIHcRhDescriptorA_NDPPhase);
550:
551: for (port = 1; port <= numPorts; port++)
552: {
553: statusBit <<= 1; /* Next bit */
554:
555: getRootHubPortStatus((IOUSBHubPortStatus *)&portStatus, port);
556: if ((portStatus & kOHCIHcRhPortStatus_Change) != 0)
557: statusChangedBitmap |= statusBit; /* Hub status change bit */
558: }
559:
560: /*
561: * If a transaction is queued, handle it
562: */
563: if(_outstandingTrans[0].completion.action != nil)
564: {
565: last = _outstandingTrans[0];
566: IOTakeLock(_intLock);
567: for (index = 1; index < kMaxOutstandingTrans ; index++)
568: {
569: _outstandingTrans[index-1] = _outstandingTrans[index];
570: if (_outstandingTrans[index].completion.action == nil)
571: break;
572: }
573:
574: move = last.bufLen;
575: if (move > sizeof(statusChangedBitmap))
576: move = sizeof(statusChangedBitmap);
577: if (numPorts < 8)
578: move = 1;
579:
580: statusChangedBitmap = HostToUSBWord(statusChangedBitmap);
581: last.buf->writeBytes(0,&statusChangedBitmap, move);
582: IOUnlock(_intLock); /* Unlock the queue */
583: complete(last.completion, kIOReturnSuccess, last.bufLen - move);
584: }
585: }
586:
587: /*
588: * SimulateRootHubInt
589: * Simulate the interrupt pipe (status change pipe) of a hub for the root
590: * hub. The basic concept is to simulate the UIMCreateInterruptTransfer
591: * so we keep our own little queue -> _outstandingTrans. We are turning
592: * on the RHSC interrupt so UIMRootHubStatusChange() should handle the
593: * dequeueing.
594: */
595: void AppleOHCI::SimulateRootHubInt(
596: UInt8 endpoint,
597: IOMemoryDescriptor * buf,
598: UInt32 bufLen,
599: IOUSBCompletion completion)
600: {
601: int index;
602: OHCIRegistersPtr pOHCIRegisters = pOHCIUIMData->pOHCIRegisters;
603:
604: if (endpoint != 1)
605: {
606: complete(completion, -1, bufLen);
607: return;
608: }
609:
610: IOTakeLock(_intLock);
611:
612: for (index = 0; index < kMaxOutstandingTrans; index++)
613: {
614: if (_outstandingTrans[index].completion.action == nil)
615: {
616: /* found free trans */
617: _outstandingTrans[index].buf = buf;
618: _outstandingTrans[index].bufLen = bufLen;
619: _outstandingTrans[index].completion = completion;
620: IOUnlock(_intLock); /* Unlock the queue */
621:
622: /* turn on RHSC interrupt */
623: pOHCIRegisters->hcInterruptEnable =pOHCIRegisters->hcInterruptEnable
624: | OSSwapInt32(kOHCIHcInterrupt_RHSC);
625: IOSync();
626:
627: return;
628: }
629: }
630:
631: IOUnlock(_intLock); /* Unlock the queue */
632: complete(completion, -1, bufLen); /* too many trans */
633: }
634:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.