|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: File: USLhubs.c
27:
28: Contains: Hub specific functions for the USL (mainly add and subtract devices)
29:
30: Version: Nepturn 1.0
31:
32: Copyright: � 1997-1998 by Apple Computer, Inc., all rights reserved.
33:
34: File Ownership:
35:
36: DRI: Barry Twycross
37:
38: Other Contact: xxx put other contact here xxx
39:
40: Technology: USB
41:
42: Writers:
43:
44: (DF) David Ferguson
45: (CJK) Craig Keithley
46: (BT) Barry Twycross
47:
48: Change History (most recent first):
49:
50: <USB40> 11/4/98 BT Comment inobvious zering of refCon
51: <USB39> 10/29/98 BT Close old configurations on reset or reconfiguration.
52: <USB38> 10/7/98 BT Fix hub not killing children
53: <USB37> 10/3/98 BT Add more port reset stuff
54: <USB36> 9/29/98 BT Use real frame timing
55: <USB35> 9/28/98 BT Add device reset function
56: <USB34> 9/17/98 BT 1.1 rules for captive devices.
57: <USB33> 8/25/98 BT Isoc name changes
58: <USB32> 8/24/98 BT Cope without #define for reserved4
59: <USB31> 8/13/98 BT Add multibus support
60: <USB30> 7/10/98 BT DO secondary interrupt right, set address fail returns ref 0.
61: <USB29> 7/9/98 BT Fix previous fixes. Secondary interrupt does not queue secondary
62: interrupt
63: <USB28> 7/9/98 BT Clean up queues when device deleted
64: <USB27> 6/15/98 BT Cope with 1.1 hubs speed detection
65: <USB26> 6/14/98 DF Add RemoveRootHub function
66: <USB25> 6/5/98 BT Pass pb to delete device
67: <USB24> 5/20/98 BT Version 2 PB new names
68: <USB23> 4/29/98 BT FIx negative timeout
69: <USB22> 4/26/98 BT FIx timeout adding dead device
70: <USB21> 4/23/98 BT Add watchdog
71: <USB20> 4/21/98 BT Allow requests to device zero, pipe zero.
72: <USB19> 4/16/98 BT Eliminate debugger
73: <USB18> 4/14/98 BT Impliment device remove
74: <USB17> 4/10/98 BT Add device remove
75: <USB16> 4/9/98 CJK remove uimpriv.h and uslpriv.h
76: <USB15> 4/9/98 BT Use USB.h
77: <14> 4/8/98 BT More error checking
78: <13> 4/6/98 BT Change w names
79: <12> 4/6/98 BT New param block names
80: <11> 4/2/98 BT Eliminate obsolete delay function
81: <10> 2/23/98 BT Only add device if set address was sucessful
82: <9> 2/4/98 BT Fix uslControlPacket to have errors. Add more support for
83: usbProbe
84: <8> 1/26/98 BT Mangle names after design review
85: <7> 1/15/98 CJK Change include of USL.h to USBServicesLib.h
86: <6> 1/13/98 BT Change uslPacket to uslControlPacket
87: <5> 12/19/97 BT UIM now a Shared lib
88: <4> 12/18/97 BT Fix header dependancies and add expert call back
89: */
90:
91: #include "../USB.h"
92: #include "../USBpriv.h"
93:
94: #include "../uimpriv.h"
95: #include "uslpriv.h"
96:
97: #include "../driverservices.h"
98:
99:
100: static QHdrPtr hubAddQueue;
101: static unsigned long hubAddFlag = 0;
102: static USBDeviceRef deviceZero;
103: static UInt32 busZero;
104: static Duration lastAdd;
105: static USBPB timeout={0,0, sizeof(USBPB), kUSBCurrentPBVersion};
106:
107: void initialiseHubs(void)
108: {
109: if( (PBQueueCreate(&hubAddQueue) != noErr) ||
110: (PBQueueInit(hubAddQueue) != noErr) )
111: {
112: /* Panic */
113: USBExpertStatus(0,"USL - failed to initialise hub queue", 0);
114: }
115: }
116:
117: void finaliseHubs(void)
118: {
119: // really need to count the busses!
120: //RemoveRootHub(0); // This should only happen if bus is removed????
121: //PBQueueDelete(hubAddQueue);
122: }
123:
124: Boolean uslHubValidateDevZero(USBDeviceRef ref, UInt32 *bus)
125: {
126: if(bus != nil)
127: {
128: *bus = busZero;
129: }
130: return(ref == deviceZero);
131: }
132:
133: OSStatus USBHubConfigurePipeZero(USBPB *pb)
134: {
135: UInt32 bus=0;
136: if(!checkPBVersion(pb, 1))
137: {
138: return(pb->usbStatus);
139: }
140: if(pb->pbVersion == 2) // v1.00+ only
141: {
142: pb->usbStatus = kUSBPBVersionError;
143: return(pb->usbStatus);
144: }
145: if(!uslHubValidateDevZero(pb->usbReference, &bus))
146: {
147: pb->usbStatus = kUSBUnknownDeviceErr;
148: return(pb->usbStatus);
149: }
150:
151: kprintf("USBHubConfigurePipeZero:calling UIMControlEDCreate\n");
152: pb->usbStatus = UIMControlEDCreate(bus, 0, 0, pb->usb.cntl.WValue, pb->usbFlags);
153: (*pb->usbCompletion)(pb);
154: return(kUSBPending);
155: }
156:
157:
158: void uslCleanHubQueue(USBDeviceRef ref)
159: { // This is assuming its called at secondary interrupt time.
160: uslCleanAQueue(hubAddQueue, ref);
161: }
162:
163: static void processAddQ(void)
164: {
165: OSStatus err;
166: USBPB *pb;
167: if(CompareAndSwap(0, 1, &hubAddFlag))
168: { /* We now have the queue*/
169: if(PBDequeueFirst(hubAddQueue, (void *)&pb) == noErr)
170: {
171:
172: // Could validate ref here.
173:
174: busZero = pb->usbOther;
175: lastAdd = deltaFrames(0, busZero);
176: if(pb->pbVersion == 2)
177: {
178: kprintf("processAddQ:calling UIMControlEDCreate\n");
179: err = UIMControlEDCreate(busZero, 0, 0, 8, pb->usbFlags);
180: /* Error checking ??? */
181: }
182:
183: deviceZero = MakeDevRef(busZero, 0);
184: pb->usbReference = deviceZero;
185: pb->usbStatus = noErr;
186: (*pb->usbCompletion)(pb);
187: }
188: }
189: }
190:
191: /* Takes bus in reference */
192:
193: void uslHubAddDevice(USBPB *pb)
194: {
195: pb->qType = kUSBHubQType;
196: pb->usbStatus = kUSBPending;
197: PBEnqueueLast((void *)pb, hubAddQueue);
198: processAddQ();
199: }
200:
201: OSStatus USBHubAddDevice(USBPB *pb)
202: {
203: UInt32 bus;
204:
205: pb->usbStatus = validateRef(pb->usbReference, &bus);
206: if(pb->usbStatus != noErr)
207: {
208: return(pb->usbStatus);
209: }
210:
211: if(!checkPBVersion(pb, 1))
212: {
213: return(pb->usbStatus);
214: }
215:
216: pb->usbOther = bus;
217: uslHubAddDevice(pb);
218:
219: return(kUSBPending);
220: }
221:
222: /* Takes bus in reference */
223:
224: static void setAddressHandler(USBPB *pb)
225: {
226: UInt32 bus;
227: UInt32 power;
228:
229: bus = busZero;
230:
231: // UIMEDDelete(0, 0, 0);
232: kprintf("setAddressHandler: calling UIMControlEDDelete\n");
233: UIMControlEDDelete(bus, 0, 0);
234: deviceZero = 0;
235: lastAdd = 0;
236:
237: if(pb->reserved2 != nil)
238: { /* real user call back */
239: if(pb->usbStatus == noErr)
240: {
241: power = ( (pb->usbFlags & kUSBHubPower) != 0)?pb->usbOther:kUSB500mAAvailable;
242: if((pb->usbFlags & kUSBHubReaddress) == 0)
243: {
244: /* Note, this is relying on having usbValue swapped by uiminterface */
245: pb->usbReference = addNewDevice(bus, pb->usb.cntl.WValue, pb->usbFlags&1, pb->wValueStash, power);
246: }
247: }
248: else
249: {
250: pb->usbReference = 0;
251: USBExpertStatus(0, "USL - Error setting address:", pb->usbReference);
252: }
253:
254: pb->usbCompletion = (void *)pb->reserved2;
255: (*pb->usbCompletion)(pb);
256: }
257: else
258: { /* timeout call back */
259:
260: /* This really is refcon, not reference, this is not a bug. */
261: /* This is the call back from the watchdog timer */
262: pb->usbRefcon = 0;
263: }
264: CompareAndSwap(1, 0, &hubAddFlag); /* Unlock the queue */
265:
266: if(hubAddQueue->qHead != nil)
267: {
268: processAddQ();
269: }
270: }
271:
272:
273:
274: static void uslHubSetAddress(USBPB *pb)
275: {
276: OSStatus err;
277: pb->reserved2 = (UInt32) pb->usbCompletion;
278: pb->usbCompletion = setAddressHandler;
279: pb->wValueStash = pb->usb.cntl.WValue;
280:
281: /* Note this does not have to faff around with */
282: /* pbVersion etc its writing a packet directly */
283: pb->usb.cntl.BMRequestType = 0; /* bmRqTyp = 0, bRq = 5 */
284: pb->usb.cntl.BRequest = kUSBRqSetAddress; /* bmRqTyp = 0, bRq = 5 */
285:
286: if(pb->usbFlags & kUSBHubReaddress)
287: {
288: usbDevice *d;
289: d = getDevicePtr(pb->usbReference);
290: if(d == nil)
291: {
292: pb->usbStatus = kUSBUnknownDeviceErr;
293: setAddressHandler(pb);
294: return;
295: }
296: pb->usb.cntl.WValue = HostToUSBWord(d->usbAddress);
297: }
298: else
299: {
300: pb->usb.cntl.WValue = HostToUSBWord(getNewAddress());
301: }
302: pb->usb.cntl.WIndex = 0;
303: pb->usb.cntl.reserved4 = 0; /* zero length */
304:
305: pb->usbStatus = kUSBPending;
306: err = usbControlPacket(busZero, pb, 0, 0);
307:
308: if(err != noErr)
309: { /* Even if error, we need to go through handler */
310: pb->usbStatus = err;
311: setAddressHandler(pb);
312: }
313: }
314:
315: OSStatus USBHubSetAddress(USBPB *pb)
316: {
317: if(!checkPBVersion(pb, 1|kUSBHubPower|kUSBHubReaddress))
318: {
319: return(pb->usbStatus);
320: }
321:
322: if(pb->usbFlags & kUSBHubReaddress)
323: {
324: if(getDevicePtr(pb->usbReference) == nil)
325: {
326: pb->usbStatus = kUSBUnknownDeviceErr;
327: return(pb->usbStatus);
328: }
329: }
330: else
331: {
332: if(!uslHubValidateDevZero(pb->usbReference, nil))
333: {
334: pb->usbReference = 0;
335: pb->usbStatus = paramErr;
336: return(pb->usbStatus);
337: }
338: }
339:
340: uslHubSetAddress(pb);
341:
342: return(kUSBPending);
343: }
344:
345: static OSStatus secondaryCleanInternalQueues(void *p1, void *p2)
346: { // Any new queues should put an entry in here
347: USBDeviceRef ref;
348: p2=0;
349: ref = (USBDeviceRef)p1;
350:
351: uslCleanHubQueue(ref);
352: uslCleanDelayQueue(ref);
353: uslCleanNotifyQueue(ref);
354: uslCleanMemQueue(ref);
355:
356: return(noErr); // no one's listening
357: }
358:
359: static OSStatus uslCleanInternalQueues(USBDeviceRef ref)
360: {
361: return(CallSecondaryInterruptHandler2(secondaryCleanInternalQueues, nil, (void *)ref, 0));
362: }
363:
364: OSStatus USBHubDeviceRemoved(USBPB *pb)
365: {
366: OSStatus err = kUSBPending;
367: usbDevice *deviceP;
368: OSStatus retVal = noErr;
369: Boolean noCallBack;
370:
371: noCallBack = (pb->usbCompletion == kUSBNoCallBack);
372: if(noCallBack)
373: {
374: pb->usbCompletion = (void *)-2;
375: }
376: if(!checkPBVersion(pb, 0))
377: {
378: return(pb->usbStatus);
379: }
380: if(noCallBack)
381: {
382: pb->usbCompletion = kUSBNoCallBack;
383: }
384:
385: deviceP = getDevicePtr(pb->usbReference);
386: if(deviceP == nil)
387: {
388: pb->usbStatus = kUSBUnknownDeviceErr;
389: return(kUSBUnknownDeviceErr);
390: }
391:
392: // Must do this before pipes are closed.
393: retVal = uslCleanInternalQueues(deviceP->ID);
394: if(retVal != noErr) // if this returns an erro we're hosed.
395: {
396: return(retVal);
397: }
398:
399: uslClosePipe(deviceP->pipe0);
400:
401: uslCloseNonDefaultPipes(deviceP);
402:
403: return(uslDeleteDevice(pb, deviceP));
404: }
405:
406: void uslHubWatchDog(Duration currentMilliSec)
407: {
408: USBReference currDevZero;
409: UInt32 bus;
410:
411: if((hubAddQueue->qHead != nil) && (lastAdd != 0) )
412: {
413: currDevZero = deviceZero;
414: bus = deviceZero;
415: if(lastAdd < currentMilliSec - 1000)
416: { /* Candidate for removal */
417:
418: if(CompareAndSwap(currDevZero, 0, (void *)&deviceZero))
419: { /* if we're here, deviceZero didn't change since we checked the time */
420: /* We've also just diabled that device zero */
421: if(timeout.usbRefcon != 0)
422: {
423: USBExpertStatus(0, "USL hubs - force set address timed out", 0);
424: /* timeout in use already */
425: kprintf("uslHubWatchDog: calling UIMControlEDDelete\n");
426: UIMControlEDDelete(bus, 0, 0);
427: timeout.usbRefcon = 0;
428: }
429: else
430: {
431: USBExpertStatus(0, "USL hubs - timing out add", 0);
432: timeout.usbRefcon = 1;
433: lastAdd = currentMilliSec + 1000;
434: uslHubSetAddress(&timeout);
435: }
436: }
437:
438: }
439: }
440: }
441:
442:
443:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.