Annotation of kernel/bsd/dev/ppc/drvUSBCMD/Library/usl.c, revision 1.1.1.1

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:           usl.c
                     27: 
                     28:        Contains:       USB Services Library source code.
                     29:  
                     30:        Version:        Neptune 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:                (TC)    Tom Clark
                     46:                (BG)    Bill Galcher
                     47:                (DKF)   David Ferguson
                     48:                (CJK)   Craig Keithley
                     49:                (BT)    Barry Twycross
                     50: 
                     51:        Change History (most recent first):
                     52: 
                     53:         <USB76>        11/25/98        TC              Add calls to USBExpertStatusLevel.
                     54:         <USB75>        11/16/98        BT              Mark pipe stalled on allocate to check open pipe is clearing it
                     55:                                                                        properly.
                     56:         <USB74>         11/8/98        TC              We need to assign a unique DeviceRef for UIM's. So when creating
                     57:                                                                        DeviceRefs, don't return one that matches kUIMRefID.
                     58:         <USB73>         11/6/98        TC              Formalize parameter names for uslRefToBus.
                     59:         <USB72>         11/6/98        BT              ref to bus function
                     60:         <USB71>        10/29/98        BT              Close old configurations on reset or reconfiguration.
                     61:         <USB70>        10/21/98        DF              Add uslDeviceAddrToBus function
                     62:         <USB69>         10/7/98        BT              Fix hub not killing children
                     63:         <USB68>         9/17/98        BT              1.1 rules for captive devices.
                     64:         <USB67>         8/24/98        BT              Eliminate old checkPB version, add new one for Isoc
                     65:         <USB66>         8/13/98        BT              Add multibus support
                     66:         <USB65>         7/10/98        BT              Device zero has a valid ref, delete device deletes mem even
                     67:                                                                        after trashing device and ref.
                     68:         <USB64>          7/9/98        BT              Fix previous fixes. Device refs can also be validated
                     69:         <USB63>          7/9/98        BT              Clean up after delete device and config clash.
                     70:         <USB62>         6/13/98        BT              Eliminate V1 param blocks
                     71:         <USB61>         6/10/98        CJK             add uslGetDeviceRefByID function (thanks Barry!)
                     72:         <USB60>          6/5/98        BT              Delete mem properly in delete device
                     73:         <USB59>          6/5/98        TC              Change uxBusRef to USBBusRef.
                     74:         <USB58>          6/3/98        BT              Make dispose interface ref able to ignore call back
                     75:         <USB57>         5/21/98        BT              Don't initialise redundant firstConf field in dev structure
                     76:         <USB56>         5/20/98        BT              Add check for V2 param block function
                     77:         <USB55>         5/19/98        BG              Fixed ZeroMem() be a little easier for MrC to swallow.
                     78:         <USB54>         5/17/98        BT              Impliment new interface ref correctly, add some functions to
                     79:                                                                        support config stuff
                     80:         <USB53>         5/12/98        BT              New interface handling
                     81:         <USB52>          5/8/98        BT              Add open interface for Tom
                     82:         <USB51>         4/26/98        BT              Add pipe state control
                     83:         <USB50>         4/24/98        BT              Add clear endpoint stall
                     84:         <USB49>         4/24/98        CJK             change string for status message
                     85:         <USB48>         4/21/98        BT              Allow requests to device zero, pipe zero.
                     86:         <USB47>         4/20/98        BT              Add abort pipe
                     87:         <USB46>         4/16/98        BT              Add back UIMpriv prototypes
                     88:         <USB45>         4/15/98        BT              Remove redundant diagnostic
                     89:         <USB44>         4/15/98        BT              Fix wrong flags check.
                     90:         <USB43>         4/14/98        BT              Impliment device remove
                     91:         <USB42>          4/9/98        CJK             remove uimpriv.h
                     92:         <USB41>          4/9/98        BT              Use USB.h
                     93:                <40>      4/8/98        BT              More error checking
                     94:                <39>      4/6/98        BT              Change w names
                     95:                <38>      4/6/98        BT              New param block names
                     96:                <37>      4/2/98        BT              Start on config/interface/endpoint stuff. First caching config
                     97:                                                                        descriptors.
                     98:                <36>     3/24/98        BT              Record device speed in device structure. (Fixes low speed int
                     99:                                                                        pipe problems.)
                    100:                <35>     3/24/98        BT              Fix recording of Maxpacketsize
                    101:                <34>     3/19/98        BT              Stop double inititialisation
                    102:                <33>     3/19/98        BT              Open bulk takes max poacket size in usbValue.
                    103:                <32>     3/18/98        BT              Add remove device.
                    104:                <31>      3/5/98        BT              Add interrupt pipe
                    105:         <USB30>         2/17/98        DKF             Fix a typo in the error codes
                    106:                <29>     2/16/98        BT              Direct notifications to expert
                    107:                <28>      2/9/98        BT              Add add interface stuff
                    108:                <27>      2/8/98        BT              Power Allocation stuff
                    109:                <26>      2/5/98        BT              Add status notification stuff
                    110:                <25>      2/4/98        BT              Add ref/port info to expert notify]
                    111:                <24>      2/4/98        BT              More USBprobe support
                    112:                <23>      2/3/98        BT              Fix uslControlPacket to have errors. Add mnore support for
                    113:                                                                        usbProbe. Also add USBExpertNotify
                    114:                <22>      2/2/98        BT              Add bulk stuff
                    115:                <21>     1/29/98        BT              Utility stuff split off
                    116:                <20>     1/26/98        CJK             Change to use USBDeviceDescriptor (instead of just
                    117:                                                                        deviceDescriptor)
                    118:                <19>     1/26/98        BT              Mangle names after design review, finish up
                    119:                <18>     1/26/98        BT              Mangle names after design review
                    120:                <17>     1/26/98        BT              Make expert notify public
                    121:                <16>     1/26/98        BT              Fix status in USB delay function
                    122:                <15>     1/23/98        BT              Add USB delay function
                    123:                <14>     1/20/98        BT              Increase number of timers
                    124:                <13>     1/19/98        BT              Fix race condition
                    125:                <12>     1/15/98        BT              Use new USBClassDrivers.h
                    126:                <11>     1/14/98        BT              Remove outdated expert stuff
                    127:                <10>     1/13/98        BT              User timer services for task time, starting implimenting Int
                    128:                                                                        transactions (not finished)
                    129:                 <9>    12/23/97        BT              Remove obsolete include
                    130:                 <8>    12/19/97        BT              Add add and remove bus.
                    131:                 <7>    12/19/97        BT              UIM now a Shared lib
                    132:                 <6>    12/18/97        BT              Changed expert proc declaratiopn in USLInitialise
                    133:                 <5>    12/18/97        BT              Fix header dependancies, add expert call back
                    134:                 <4>    12/17/97        BT              Fix header
                    135:                 <3>    12/17/97        BT              First checking to BBS
                    136: */
                    137: 
                    138: 
                    139: 
                    140: /* ************* Includes ************* */
                    141: #include "../USB.h"
                    142: #include "../USBpriv.h"
                    143: #include "../driverservices.h"
                    144: 
                    145: #include "uslpriv.h"
                    146: #include "../uimpriv.h" // This does need to be included. It contains prototypes
                    147:                                            // Stupid MPW just doesn't tell
                    148: /*****************************************************************************
                    149: 
                    150:        Data Structures
                    151:        
                    152: There is an array of devices. 
                    153: 
                    154: Each device entry has information specific to it. It also holds and array of
                    155: indexes of pipes (open endpoints) for the device.
                    156: 
                    157: Each open pipe holds information specific to it.
                    158: 
                    159: Devices are refrenced by device IDs, which are currently an index in tot the
                    160: devices table in the lower bits and random number in the high bits. This 
                    161: knowledge is kept to a few functions and could be changed.
                    162: 
                    163: The pipe refs are similarly indexes in to the pipes array.
                    164: 
                    165: ******************************************************************************/
                    166: 
                    167: static pipe AllPipes[kUSBMaxPipes];
                    168: static usbDevice devices[kUSBMaxDevices];
                    169: 
                    170: enum{
                    171:        kUSBInterfaceShift = 8,
                    172:        kUSBMaxInterface = 1 << kUSBInterfaceShift,
                    173:        kUSBIntefaceMask = kUSBMaxInterface-1
                    174:        };
                    175: static uslInterface interfaces[kUSBMaxInterface];
                    176: 
                    177: //static usbDevice *devices;
                    178: 
                    179: static Boolean initialised;
                    180: 
                    181: 
                    182: /* ************* CallBack prototyopes. ************* */
                    183: /* These need to be referenced before the properplace for their definition */
                    184: static void controlCallBack(
                    185:                UInt32  refcon,                         /* General Purpose reference supplied by call */
                    186:                OSStatus status,                        /* normal or error condition */
                    187:                short shortFall);                       /* how much less than requested transferred */
                    188: 
                    189: 
                    190: 
                    191: 
                    192: /* ************* Actual Code *************** */
                    193: 
                    194: /* This doesn't work without length bytes in the strings */
                    195: 
                    196: OSStatus USBServicesGetVersion(UInt32 ID, VersRec *vers, UInt32 versSize)
                    197: {
                    198: #if 0
                    199: static VersRec ID1=
                    200: #if kOverrideIndividualVersions
                    201:        {
                    202:        {kPKGHexMajorVers, kPKGHexMinorVers, kPKGCurrentRelease, kPKGReleaseStage},
                    203:        0,                                      /* Country code */
                    204:        "\p"kPKGStringVersShort, "\p"kPKGStringVers1Long
                    205:        
                    206:        },
                    207: #else
                    208:        {
                    209:        {kSRVHexMajorVers, kSRVHexMinorVers, kSRVCurrentRelease, kSRVReleaseStage},
                    210:        0,                                      /* Country code */
                    211:        kMNGRStringVersShort kMNGRStringVers1Long
                    212:        
                    213:        },
                    214: #endif
                    215:        ID2 = {
                    216:        {kPKGHexMajorVers, kPKGHexMinorVers, kPKGCurrentRelease, kPKGReleaseStage},
                    217:        0,                                      /* Country code */
                    218:        kPKGStringVersShort kPKGStringVers1Long
                    219:        
                    220:        },
                    221:        *theVers;
                    222: 
                    223:        if( (ID == 0) || (ID > 2) )
                    224:        {
                    225:                return(paramErr);
                    226:        }
                    227:        if(ID == 1)
                    228:        {
                    229:                theVers = &ID1;
                    230:        }
                    231:        else
                    232:        {
                    233:                theVers = &ID2;
                    234:        }
                    235:        if(versSize > sizeof(VersRec) )
                    236:        {
                    237:                versSize = sizeof(VersRec);
                    238:        }
                    239:        usb_BlockMoveData(theVers, vers, versSize);
                    240: #endif
                    241:        ID = 0;
                    242:        vers = 0;
                    243:        versSize = 0;
                    244:        return(noErr);
                    245: }
                    246: /* ******** Interfaces ********** */
                    247: 
                    248: /* This impliments the arbitrary high bits as a counter. */
                    249: static USBInterfaceRef MakeInterfaceRef(UInt16 addr)
                    250: {
                    251: static long strangeCounter = 0x980508;
                    252: long shiftedCounter;
                    253: 
                    254:        strangeCounter++;
                    255:        shiftedCounter = strangeCounter << kUSBInterfaceShift;
                    256:        if(shiftedCounter == 0)
                    257:        {
                    258:                shiftedCounter = ++strangeCounter << kUSBInterfaceShift;
                    259:        }
                    260:        return(addr | shiftedCounter | 0x80000000);     // high bit is one
                    261: }
                    262: 
                    263: /* Given a interfaceRef find the pointer to its structure */
                    264:        
                    265: OSStatus findInterface(USBInterfaceRef InterfaceRef, uslInterface **p)
                    266: {
                    267: InterfacesIdx idx;
                    268: uslInterface *theInterface;
                    269: 
                    270:        idx = InterfaceRef & kUSBIntefaceMask;
                    271:        theInterface = & interfaces[idx];
                    272:        *p = theInterface;
                    273:        if(theInterface->ref == InterfaceRef)
                    274:        {
                    275: #if 0
                    276:                if(theInterface->state != kUSBActive)
                    277:                {
                    278:                        if(theInterface->state == kUSBIdle)
                    279:                        {
                    280:                                return(kUSBInterfaceIdleError);
                    281:                        }
                    282:                        else
                    283:                        {
                    284:                                return(kUSBInterfaceStalledError);
                    285:                        }                       
                    286:                }
                    287: #endif
                    288:                return(noErr);
                    289:        }
                    290:        *p = nil;
                    291:        return(kUSBUnknownInterfaceErr);
                    292: }
                    293: 
                    294: 
                    295: /* This probably is not the best method for Interfaces */
                    296: static InterfacesIdx AllocInterfaceIdx(void)
                    297: {
                    298: static InterfacesIdx current;
                    299: InterfacesIdx new;
                    300: unsigned counted;
                    301: 
                    302: /* Allocates a Interface. This implimentation has a pointer to */
                    303: /* the next Interface to be allocated, which is incrimented each */
                    304: /* time. If that Interface is in use, the list is search linearly */
                    305: /* from that point for the next free Interface */
                    306: /* Same as packet allocator */
                    307: 
                    308: /* Do we need to use atomicTestAndSet for this? */
                    309: /* Not if transactions are queued */
                    310: 
                    311:        new = current;
                    312:        counted = 0;
                    313: 
                    314:        while(counted < kUSBMaxInterface)
                    315:        {
                    316:                if(interfaces[new].ref == 0)    /* Zero not a valid Interface ref */
                    317:                {
                    318:                        break;
                    319:                }
                    320:                counted++;
                    321:                new++;
                    322:                if(new > kUSBMaxInterface)
                    323:                {
                    324:                        new = 0;
                    325:                }
                    326:                
                    327:        }
                    328:        if(counted < kUSBMaxInterface)
                    329:        {
                    330:                if(counted > 0)
                    331:                {
                    332:                        /* maybe keep track of these at some time */
                    333:                }
                    334:                interfaces[new].ref = 0;
                    335:        }
                    336:        else
                    337:        {
                    338:                /* maybe keep track of these at some time */
                    339:                new = -1;
                    340:        }
                    341: 
                    342:        current++;
                    343:        if(current > kUSBMaxInterface)
                    344:        {
                    345:                current = 0;
                    346:        }
                    347:        return(new);
                    348: }
                    349: 
                    350: /* Allocate a new Interface structure for the given device and endpoint */
                    351: uslInterface *AllocInterface(USBDeviceRef device)
                    352: {
                    353: long newIdx;
                    354: 
                    355:        newIdx = AllocInterfaceIdx();
                    356:        if(newIdx == -1)
                    357:        {
                    358:                return(nil);
                    359:        }
                    360:        interfaces[newIdx].ref = MakeInterfaceRef(newIdx);
                    361:        interfaces[newIdx].device = device;
                    362:        return(&interfaces[newIdx]);
                    363: }
                    364: 
                    365: 
                    366: static void deallocAllDeviceInterfaces(USBDeviceRef ID)
                    367: {
                    368: int i;
                    369:        for(i = 0; i<kUSBMaxInterface ; i++)
                    370:        {
                    371:                if(interfaces[i].device == ID)
                    372:                {
                    373:                        USBExpertStatusLevel(4, interfaces[i].ref, "USL - Delete undeleted interface", 0);
                    374:                        
                    375:                        interfaces[i].device = 0;
                    376:                        interfaces[i].interfaceNum = 0;
                    377:                        interfaces[i].alt = 0;
                    378:                        interfaces[i].ref = 0;
                    379:                }
                    380:        }
                    381: 
                    382: 
                    383: }
                    384: 
                    385: /* ************* Device Table maintainance internal functions *************/
                    386: unsigned makeDeviceIdx(USBDeviceRef device)
                    387: {
                    388:        return(device & kUSBDeviceIDMask);
                    389: }
                    390: 
                    391: Boolean uslIsInterfaceRef(USBInterfaceRef interf)
                    392: {
                    393:        return((interf & 0x80000000) != 0);
                    394: }
                    395: 
                    396: usbDevice *getDevicePtrFromIdx(unsigned deviceIndex)
                    397: {
                    398:        if(deviceIndex > kUSBMaxDevices)
                    399:        {
                    400:                return(nil);
                    401:        }
                    402:        return(&devices[deviceIndex]);
                    403: }
                    404: 
                    405: USBDeviceRef uslGetDeviceRefByID(unsigned short deviceID, USBBusRef bus);
                    406: 
                    407: USBDeviceRef uslGetDeviceRefByID(unsigned short deviceID, USBBusRef bus)
                    408: {
                    409: usbDevice *device;
                    410:        if(bus != 1)
                    411:        {
                    412:                return(kUSBUnknownDeviceErr);
                    413:        }
                    414:        device = getDevicePtrFromIdx(deviceID);
                    415:        if(device == nil)
                    416:        {
                    417:                return(kUSBUnknownDeviceErr);
                    418:        }
                    419:        return(device->ID);
                    420: 
                    421: }
                    422: 
                    423: usbDevice *getDevicePtr(USBDeviceRef device)
                    424: {
                    425: unsigned deviceIndex;
                    426: 
                    427:        if( (device & 0x80000000) != 0)
                    428:        {
                    429:        OSStatus err;
                    430:        uslInterface *intrfc;
                    431:        
                    432:                err = findInterface(device, &intrfc);
                    433:                if(intrfc == nil)
                    434:                {
                    435:                        return(nil);
                    436:                }
                    437:                device = intrfc->device;
                    438:        }
                    439: 
                    440:        deviceIndex = makeDeviceIdx(device);
                    441:        if(devices[deviceIndex].ID == device)
                    442:        {
                    443:                return(&devices[deviceIndex]);
                    444:        }
                    445:        return(nil);
                    446: }
                    447: 
                    448: OSStatus uslRefToBus(USBReference ref, USBBusRef *bus)
                    449: {
                    450: usbDevice *dev;
                    451:        dev = getDevicePtr(ref);
                    452:        if(dev != nil)
                    453:        {
                    454:                if(bus != nil)
                    455:                {
                    456:                        *bus = dev->bus;
                    457:                }
                    458:                return(noErr);
                    459:        }
                    460:        else
                    461:        {
                    462:                return(kUSBUnknownDeviceErr);
                    463:        }
                    464: 
                    465: }
                    466: 
                    467: 
                    468: /* This one is a prober only hack function */
                    469: UInt32 uslDeviceAddrToBus(UInt16 addr)
                    470: {
                    471: unsigned deviceIndex;
                    472: 
                    473:        for(deviceIndex = 0; deviceIndex < kUSBMaxDevices; deviceIndex++)
                    474:        {
                    475:                if ((devices[deviceIndex].ID != 0) && (devices[deviceIndex].usbAddress == addr))
                    476:                {
                    477:                        return(devices[deviceIndex].bus);
                    478:                }
                    479:        }
                    480:        return (0xffff);  // indicate that we couldn't find a bus
                    481: }
                    482: 
                    483: 
                    484: 
                    485: static void initialiseOneDevice(usbDevice *device)
                    486: {      /* Shared by delete device */
                    487:        device->ID = 0; 
                    488: }
                    489: 
                    490: static void initialiseDevices(void)
                    491: {
                    492: unsigned deviceIndex;
                    493: 
                    494:        for(deviceIndex = 0; deviceIndex < kUSBMaxDevices; deviceIndex++)
                    495:        {
                    496:                initialiseOneDevice(&devices[deviceIndex]);
                    497:        }
                    498: 
                    499: }
                    500: 
                    501: UInt8 getNewAddress(void)
                    502: {
                    503: static int addr = -1;
                    504: int counted = 1;
                    505:        if(addr == -1)
                    506:        {
                    507:        AbsoluteTime t;
                    508:                t = UpTime();
                    509:                //naga addr = t.lo & 0x7f;
                    510:                addr = t & 0x7f;
                    511:        }
                    512:        do{
                    513:                addr++;
                    514:                if(addr > 127)
                    515:                {
                    516:                        addr = 1;
                    517:                }
                    518:                if(devices[addr].ID == 0)
                    519:                {
                    520:                        break;
                    521:                }
                    522:        }while(counted++ <= 127);
                    523:        
                    524:        if(counted > 127)
                    525:        {
                    526:                addr = 0;
                    527:        }
                    528:        
                    529:        USBExpertStatusLevel(4, 0, "USL - New device:", addr); // Paging Mr. Twycross
                    530: kprintf("****getNewAddress returning addr=%d***\n",addr);
                    531:        return(addr);
                    532: }
                    533: 
                    534: 
                    535: /* This impliments the arbitrary high bits as a counter. */
                    536: USBDeviceRef MakeDevRef(UInt32 bus, UInt16 addr)
                    537: {
                    538: static long strangeCounter = 0x090263;
                    539: long shiftedCounter;
                    540: 
                    541:        strangeCounter++;
                    542:        shiftedCounter = strangeCounter << kUSBDeviceIDShift;
                    543:        if(shiftedCounter == 0)
                    544:        {
                    545:                shiftedCounter = ++strangeCounter << kUSBDeviceIDShift;
                    546:        }
                    547: 
                    548:        bus = 0; // currenty not used.
                    549:        return( (addr + shiftedCounter) & 0x7fffffff);  // High bit is zero
                    550: }
                    551: 
                    552: /* ************* Pipe Table Maintainance internal functions ************* */
                    553: 
                    554: /* So that stale pipeRefs can not be reused, the pipe ref is */
                    555: /* the index into the pipe table (the interesting part) */
                    556: /* and an arbitrary value stuffing the high bits. */
                    557: /* A pipe ref is only accepted if it matches the pipeRef */
                    558: /* stored in the pipe structure. */
                    559: 
                    560: /* This impliments the arbitrary high bits as a counter. */
                    561: static USBPipeRef MakePipeRef(long pipeIdx)
                    562: {
                    563: static long strangeCounter = 0x230259;
                    564: long shiftedCounter;
                    565: 
                    566:        strangeCounter++;
                    567:        shiftedCounter = strangeCounter << kUSBMaxPipeIDShift;
                    568:        if(shiftedCounter == 0)
                    569:        {
                    570:                shiftedCounter = ++strangeCounter << kUSBMaxPipeIDShift;
                    571:        }
                    572:        return(pipeIdx + shiftedCounter);
                    573: }
                    574: 
                    575: /* Given a pipeRef find the pointer to its structure */
                    576:        
                    577: OSStatus findPipe(USBPipeRef pipeRef, pipe **p)
                    578: {
                    579: pipesIdx idx;
                    580: pipe *thePipe;
                    581: 
                    582:        idx = pipeRef & kUSBPipeIDMask;
                    583:        thePipe = & AllPipes[idx];
                    584:        *p = thePipe;
                    585:        if(thePipe->ref == pipeRef)
                    586:        {
                    587:                if(thePipe->state != kUSBActive)
                    588:                {
                    589:                        if(thePipe->state == kUSBIdle)
                    590:                        {
                    591:                                return(kUSBPipeIdleError);
                    592:                        }
                    593:                        else
                    594:                        {
                    595:                                return(kUSBPipeStalledError);
                    596:                        }                       
                    597:                }
                    598:                return(noErr);
                    599:        }
                    600:        *p = nil;       // BT some things rely on this being nil if no pipe, oops.
                    601:        return(kUSBUnknownPipeErr);
                    602: }
                    603: 
                    604: 
                    605: /* This probably is not the best method for pipes */
                    606: static pipesIdx AllocPipeIdx(void)
                    607: {
                    608: static pipesIdx current;
                    609: pipesIdx new;
                    610: unsigned counted;
                    611: 
                    612: /* Allocates a pipe. This implimentation has a pointer to */
                    613: /* the next pipe to be allocated, which is incrimented each */
                    614: /* time. If that pipe is in use, the list is search linearly */
                    615: /* from that point for the next free pipe */
                    616: /* Same as packet allocator */
                    617: 
                    618: /* Do we need to use atomicTestAndSet for this? */
                    619: /* Not if transactions are queued */
                    620: 
                    621:        new = current;
                    622:        counted = 0;
                    623: 
                    624:        while(counted < kUSBMaxPipes)
                    625:        {
                    626:                if(AllPipes[new].ref == 0)      /* Zero not a valid pipe ref */
                    627:                {
                    628:                        break;
                    629:                }
                    630:                counted++;
                    631:                new++;
                    632:                if(new > kUSBMaxPipes)
                    633:                {
                    634:                        new = 0;
                    635:                }
                    636:                
                    637:        }
                    638:        if(counted < kUSBMaxPipes)
                    639:        {
                    640:                if(counted > 0)
                    641:                {
                    642:                        /* maybe keep track of these at some time */
                    643:                }
                    644:                AllPipes[new].ref = 0;
                    645:                AllPipes[new].state = kUSBStalled;      // This is just here to tell me an open pipe forgot to set state
                    646:        }
                    647:        else
                    648:        {
                    649:                /* maybe keep track of these at some time */
                    650:                new = -1;
                    651:        }
                    652: 
                    653:        current++;
                    654:        if(current > kUSBMaxPipes)
                    655:        {
                    656:                current = 0;
                    657:        }
                    658:        return(new);
                    659: }
                    660: 
                    661: int makeDevPipeIdx( UInt8 endpoint, UInt8 direction)
                    662: {
                    663: int devPipeIdx;
                    664:        devPipeIdx = endpoint-1;
                    665:        if(direction != kUSBOut)
                    666:        {
                    667:                devPipeIdx += kUSBMaxEndptPerDevice/2;
                    668:        }
                    669:        return(devPipeIdx);
                    670: }
                    671: 
                    672: /* Given a device and an endpoint, wheres the pipe? */
                    673: pipe *getPipe(usbDevice *device, UInt8 endpoint, UInt8 direction)
                    674: {
                    675: pipesIdx index;
                    676:        index = device->pipes[makeDevPipeIdx(endpoint, direction)];
                    677:        if(index == -1)
                    678:        {
                    679:                return(nil);
                    680:        }
                    681:        else
                    682:        {
                    683:                return(&AllPipes[index]);
                    684:        }
                    685: }
                    686: 
                    687: pipe *getPipeByIdx(pipesIdx idx)
                    688: {
                    689:        if(idx > kUSBMaxPipes)
                    690:        {
                    691:                return(nil);
                    692:        }
                    693:        
                    694:        return(&AllPipes[idx]);
                    695: 
                    696: }
                    697: 
                    698: /* Allocate a new pipe structure for the given device and endpoint */
                    699: pipe *AllocPipe(usbDevice *device, UInt8 endpoint, UInt8 direction)
                    700: {
                    701: long newIdx;
                    702: 
                    703:        newIdx = AllocPipeIdx();
                    704:        if(newIdx == -1)
                    705:        {
                    706:                return(nil);
                    707:        }
                    708:        device->pipes[makeDevPipeIdx(endpoint, direction)] = newIdx;
                    709:        AllPipes[newIdx].ref = MakePipeRef(newIdx);
                    710:        return(&AllPipes[newIdx]);
                    711: }
                    712: 
                    713: 
                    714: /* XXXXXXXX More to be done */
                    715: void deallocPipe(usbDevice *device, UInt8 endpoint, UInt8 direction)
                    716: {
                    717: pipesIdx index;
                    718: int devPipeIdx;
                    719: 
                    720:        devPipeIdx = makeDevPipeIdx(endpoint, direction);
                    721:        index = device->pipes[devPipeIdx];
                    722:        AllPipes[index].ref = 0;
                    723:        AllPipes[index].state = kUSBStalled;    // This is just here to tell me an open pipe forgot to set state
                    724:        device->pipes[devPipeIdx] = -1;
                    725: }
                    726: 
                    727: 
                    728: OSStatus uslClosePipe(pipesIdx pipe)
                    729: {
                    730: OSStatus err;
                    731:        if(pipe == -1)
                    732:        {
                    733:                return(noErr);
                    734:        }
                    735:        if(AllPipes[pipe].type == kUSBControl)
                    736:        {
                    737: kprintf("uslClosePipe:calling UIMControlEDDelete\n");
                    738:                err = UIMControlEDDelete(AllPipes[pipe].bus, AllPipes[pipe].devAddress, AllPipes[pipe].endPt);
                    739:        }
                    740:        else
                    741:        {
                    742:                err = UIMEDDelete(AllPipes[pipe].bus, AllPipes[pipe].devAddress, AllPipes[pipe].endPt, AllPipes[pipe].direction);
                    743:        }
                    744: 
                    745:        AllPipes[pipe].ref = 0;
                    746:        AllPipes[pipe].state = kUSBStalled;     // This is just here to tell me an open pipe forgot to set state
                    747:        return(noErr);
                    748: }
                    749: 
                    750: void uslCloseNonDefaultPipes(usbDevice *deviceP)
                    751: {
                    752: int i;
                    753:        for(i = 0; i< kUSBMaxEndptPerDevice; i++)
                    754:        {
                    755:                uslClosePipe(deviceP->pipes[i]);
                    756:                deviceP->pipes[i] = -1;
                    757:        }
                    758: }
                    759: 
                    760: void uslCloseInterfacePipes(USBInterfaceRef iRef, usbDevice *deviceP)
                    761: {
                    762: int i;
                    763:        for(i = 0; i< kUSBMaxEndptPerDevice; i++)
                    764:        {
                    765:                if(AllPipes[deviceP->pipes[i]].devIntfRef == iRef)
                    766:                {
                    767:                        uslClosePipe(deviceP->pipes[i]);
                    768:                        deviceP->pipes[i] = -1;
                    769:                }
                    770:        }
                    771: }
                    772: 
                    773: 
                    774: OSStatus validateRef(USBReference ref, UInt32 *bus)
                    775: {
                    776: OSStatus err;
                    777: usbDevice *dev;
                    778: pipe *p;
                    779: 
                    780:        dev = getDevicePtr(ref);
                    781:        if(dev != nil)
                    782:        {
                    783:                if(bus != nil)
                    784:                {
                    785:                        *bus = dev->bus;
                    786:                }
                    787:                return(noErr);
                    788:        }
                    789:        err = findPipe(ref, &p);
                    790:        if(p != nil)
                    791:        {
                    792:                if(bus != nil)
                    793:                {
                    794:                        *bus = p->bus;
                    795:                }
                    796:                return(noErr);
                    797:        }
                    798:        if(uslHubValidateDevZero(ref, bus))
                    799:        {
                    800:                return(noErr);
                    801:        }
                    802:        USBExpertStatusLevel(2, ref, "USL - Invalid ref passed to USL", 0);
                    803: 
                    804:        return(kUSBUnknownDeviceErr);
                    805: }
                    806: 
                    807: Boolean isSameDevice(USBReference ref, USBDeviceRef devRef)
                    808: {      // true if the ref refers to the device
                    809: usbDevice *dev;
                    810: OSStatus err;
                    811: pipe *p;
                    812: 
                    813:        dev = getDevicePtr(ref);
                    814:        if(dev == nil)
                    815:        {
                    816:                err = findPipe(ref, &p);
                    817:                if(p == nil)
                    818:                {
                    819:                        return(false);
                    820:                }
                    821:                
                    822:                dev = getDevicePtr(p->devIntfRef);
                    823:        }
                    824:        if(dev != nil)
                    825:        {
                    826:                if(dev->ID == devRef)
                    827:                {
                    828:                        return(true);
                    829:                }
                    830:        }
                    831:        return(false);
                    832: }
                    833: 
                    834: static void ZeroMem(void *addr, UInt32 len)
                    835: {
                    836: UInt8  *byteAddr;
                    837: 
                    838:        if(len == 0)
                    839:                return;
                    840: 
                    841:        byteAddr = (UInt8 *) addr;
                    842:        while(len--)
                    843:        {
                    844:                *byteAddr++ = 0;
                    845:        }
                    846: }
                    847: 
                    848: 
                    849: void uslUnconfigureDevice(usbDevice *device)
                    850: {
                    851:        uslCloseNonDefaultPipes(device);
                    852:        deallocAllDeviceInterfaces(device->ID);
                    853:        device->currentConfiguration = 0;
                    854: }
                    855: 
                    856: OSStatus uslDeleteDevice(USBPB *pb, usbDevice *device)
                    857: {      /* All pipes are closed, kill off the device */
                    858: OSStatus retVal = noErr;
                    859: void *allConfDesc;
                    860: 
                    861:        if(device->configLock != 0)
                    862:        {
                    863:                USBExpertStatusLevel(2, device->ID, "USL - Device busy when deleting: Address ==", device->usbAddress);
                    864:                device->killMe = true;
                    865:                if(device->configLock != 0)
                    866:                {       // Make sure it hasn't been asynchronously unlocked                     
                    867:                        return(noErr);
                    868:                }
                    869:                USBExpertStatusLevel(2, device->ID, "USL - Device no longer busy: Address ==", device->usbAddress);
                    870:        }
                    871: 
                    872:        USBExpertStatusLevel(4, 0, "USL - Deleting device: Address ==", device->usbAddress);
                    873: 
                    874:        allConfDesc = device->allConfigDescriptors;
                    875:        
                    876:        deallocAllDeviceInterfaces(device->ID);
                    877:        
                    878:        /* Zero out the structure, not strictly necessary, but prudent */
                    879:        /* This bit relies on allConfigDescriptors being the second field after ID */
                    880:        ZeroMem(&device->allConfigDescriptors, sizeof(usbDevice)-OFFSET(usbDevice, allConfigDescriptors));
                    881:        
                    882:        initialiseOneDevice(device);
                    883: 
                    884:        if(allConfDesc != nil)
                    885:        {
                    886:                if(CurrentExecutionLevel() != kTaskLevel)
                    887:                {
                    888:                        if(pb->usbCompletion == kUSBNoCallBack)
                    889:                        {
                    890:                                retVal = kUSBCompletionError;
                    891:                        }
                    892:                        else
                    893:                        {
                    894:                                pb->usbBuffer = allConfDesc;
                    895:                                retVal = kUSBPending;
                    896:                                uslDeallocMem(pb);
                    897:                        }
                    898:                }
                    899:                else
                    900:                {
                    901:                        PoolDeallocate(device->allConfigDescriptors);
                    902:                }
                    903:        }
                    904: 
                    905:        return(retVal);
                    906: }
                    907: 
                    908: 
                    909: /* Given a pipeRef, whats the pipe index? */
                    910: long recoverPipeIdx(USBPipeRef pipeRef)
                    911: {
                    912:        if(pipeRef == 0)
                    913:        {
                    914:                return(-1);
                    915:        }
                    916:        
                    917:        return(pipeRef & kUSBPipeIDMask);
                    918: }
                    919: 
                    920: 
                    921: /* GIven a pipeRef, find the pipe structure */
                    922: pipe *GetPipePtr(USBPipeRef pipeRef)
                    923: {
                    924: pipe *retPipe = nil;
                    925: long pipeIdx;
                    926:        do{
                    927:                pipeIdx = recoverPipeIdx(pipeRef);
                    928:                if(pipeIdx == -1)
                    929:                {
                    930:                        break;
                    931:                }
                    932:                
                    933:                retPipe = &AllPipes[pipeIdx];
                    934:                
                    935:                if(pipeRef != retPipe->ref)
                    936:                {
                    937:                        retPipe = nil;
                    938:                        break;
                    939:                }
                    940:                
                    941:        }while(0);
                    942: 
                    943:        return(retPipe);
                    944: }
                    945: 
                    946: /* Mark all pipes unused */
                    947: static void initialisePipes(void)
                    948: {
                    949: long index, index2;
                    950: 
                    951:        /* Mark all pipes close */
                    952:        for(index = 0; index < kUSBMaxDevices; index++)
                    953:        {
                    954:                for(index2 = 0; index2 < kUSBMaxEndptPerDevice; index2++)
                    955:                {
                    956:                        devices[index].pipes[index2] = -1;
                    957:                }
                    958:        }
                    959:        
                    960:        
                    961: }
                    962: #define  kUIMRefID 0x061563
                    963: /* This needs to take account of bus in some manner */
                    964: USBDeviceRef addNewDevice(UInt32 bus, UInt16 addr, UInt8 speed, UInt8 maxPacket, UInt32 power)
                    965: {
                    966: USBDeviceRef new;
                    967: usbDevice *dev;
                    968: long pipeIdx;
                    969: pipe *pipe0;
                    970: 
                    971:        new = 0;
                    972:        
                    973:        do{     /* for error checking */
                    974: 
                    975:        if( (addr == 0) || (addr > kUSBMaxDevice) )
                    976:        {
                    977:                break;
                    978:        }
                    979: 
                    980:        if(UIMControlEDCreate(bus, addr, 0, maxPacket, speed) != noErr)
                    981:        {
                    982:                break;
                    983:        }
                    984: 
                    985: 
                    986:        dev = &devices[addr];
                    987:        if(dev->ID != 0)
                    988:        {
                    989:                break;
                    990:        }
                    991:        
                    992:        do
                    993:        {
                    994:                new = MakeDevRef(bus, addr);
                    995:        }while (new == kUIMRefID);
                    996:        
                    997:        dev->bus = bus;
                    998:        dev->ID = new;
                    999:        dev->usbAddress = addr;
                   1000:        dev->speed = speed;
                   1001:        dev->powerAvailable = power;    
                   1002:        USBExpertStatusLevel(4, dev->ID, "USL - New device power:", power);
                   1003: 
                   1004:        pipeIdx = AllocPipeIdx();
                   1005:        if(pipeIdx == -1)
                   1006:        {
                   1007:                break;
                   1008:        }       
                   1009:        dev->pipe0 = pipeIdx;
                   1010:        pipe0 = &AllPipes[pipeIdx];
                   1011:        
                   1012: /* this is repeated with open control endpoint. Should be consolodated */
                   1013:        pipe0->bus = bus;
                   1014:        pipe0->devIntfRef = new;
                   1015:        pipe0->endPt = 0;
                   1016:        pipe0->ref = MakePipeRef(pipeIdx);
                   1017:        pipe0->devAddress = addr;
                   1018:        pipe0->type = kUSBControl;
                   1019:        pipe0->state = kUSBActive;
                   1020:        for(pipeIdx = 0; pipeIdx < kUSBMaxEndptPerDevice; pipeIdx++)
                   1021:        {
                   1022:                dev->pipes[pipeIdx] = -1;
                   1023:        }
                   1024:        
                   1025:        }while(0);
                   1026:        
                   1027:        return(new);
                   1028: }
                   1029: 
                   1030: 
                   1031: 
                   1032: /* ************* Functions dealing with transactions ************* */
                   1033: 
                   1034: /* Each pipe has a number of possible transactions outstanding */
                   1035: /* on it at one time. The pipe structure has 2 tables one of the */
                   1036: /* UIM transaction ref for these and another parallel one which */
                   1037: /* has the index of the packet its using */
                   1038: 
                   1039: 
                   1040: 
                   1041: /* ************* Actual Functions ************* */
                   1042: 
                   1043: 
                   1044: 
                   1045: 
                   1046: 
                   1047: USBPipeRef getPipeZero(USBDeviceRef device)
                   1048: {
                   1049: usbDevice *deviceP;
                   1050: pipesIdx pipe0Idx;
                   1051: USBPipeRef retVal = 0;
                   1052:        
                   1053:        /* Validate device */
                   1054:        deviceP = getDevicePtr(device);
                   1055:        
                   1056:        if(deviceP == nil)
                   1057:        {
                   1058:                return(0);
                   1059:        }
                   1060:        pipe0Idx = deviceP->pipe0;
                   1061:        if( (pipe0Idx < 0) || (pipe0Idx > kUSBMaxPipes) )
                   1062:        {
                   1063:                return(0);
                   1064:        }
                   1065:        return(AllPipes[pipe0Idx].ref);         
                   1066: }
                   1067: 
                   1068: 
                   1069: OSStatus USBServicesInitialise(void *exProc)
                   1070: {      
                   1071: kprintf("***USBServicesInitialize:calling severel inits***\n");
                   1072:        if(initialised)
                   1073:        {
                   1074:                return(kUSBAlreadyOpenErr);
                   1075:        }
                   1076:        SetExpertFunction(exProc);
                   1077:        
                   1078:        initialiseDevices();
                   1079:        initialisePipes();
                   1080:        initialiseHubs();
                   1081:        initialiseDelays();
                   1082:        initialiseNotifications();
                   1083: 
                   1084:        initialised = true;
                   1085:        
                   1086:        return(noErr);
                   1087: }
                   1088: 
                   1089: void USBServicesFinalise(void)
                   1090: {
                   1091:        if(!initialised)
                   1092:        {
                   1093:                return;//(paramErr);
                   1094:        }
                   1095:        finaliseHubs();
                   1096:        finaliseDelays();
                   1097:        finaliseNotifications();
                   1098:        
                   1099:        initialised = false;
                   1100: }
                   1101: 
                   1102: 
                   1103: Boolean checkPBVersionIsoc(USBPB *pb, UInt32 flags)
                   1104: {
                   1105:        if(     ( (pb->pbVersion == 0x109) || (pb->pbVersion == 0x109) )&& 
                   1106:                (pb->pbLength >= sizeof(USBPB)) &&
                   1107:                ( (pb->usbCompletion != nil) && (pb->usbCompletion != (void *)-1) ) &&
                   1108:                ((pb->usbFlags & ~flags) == 0) )
                   1109:        {
                   1110:                pb->usbStatus = noErr;
                   1111:                return(true);
                   1112:        }
                   1113:        else
                   1114:        {
                   1115:                if((pb->pbVersion != 0x109) && (pb->pbVersion != 0x109) )
                   1116:                {
                   1117:                        USBExpertStatusLevel(2, pb->usbReference, "USL error - Bad param block version", pb->pbVersion);
                   1118:                        pb->usbStatus = kUSBPBVersionError;
                   1119:                }
                   1120:                else if(pb->pbLength < sizeof(USBPB)) 
                   1121:                {
                   1122:                        USBExpertStatusLevel(2, pb->usbReference, "USL error - small param block version", pb->pbLength);
                   1123:                        pb->usbStatus = kUSBPBLengthError;
                   1124:                }
                   1125:                else if( (pb->usbCompletion == nil) || (pb->usbCompletion == (void *)-1) )
                   1126:                {
                   1127:                        USBExpertStatusLevel(2, pb->usbReference, "USL error - bad completion function", (UInt32)pb->usbCompletion);
                   1128:                        pb->usbStatus = kUSBCompletionError;
                   1129:                }
                   1130:                else if((pb->usbFlags & ~flags) != 0)
                   1131:                {
                   1132:                        USBExpertStatusLevel(2, pb->usbReference, "USL error - bad flags", pb->usbFlags & ~flags);
                   1133:                        pb->usbStatus = kUSBFlagsError;
                   1134:                }
                   1135:                else
                   1136:                {
                   1137:                        USBExpertStatusLevel(2, pb->usbReference, "USL error - What??", 0);
                   1138:                        pb->usbStatus = paramErr;
                   1139:                }
                   1140:                return(false);
                   1141:        }
                   1142: }
                   1143: 
                   1144: Boolean checkPBVersion(USBPB *pb, UInt32 flags)
                   1145: {
                   1146:        if(     ( (pb->pbVersion == 2) || (pb->pbVersion == 0x100) || (pb->pbVersion == 0x109))&& 
                   1147:                (pb->pbLength >= sizeof(USBPB)) &&
                   1148:                ( (pb->usbCompletion != nil) && (pb->usbCompletion != (void *)-1) ) &&
                   1149:                ((pb->usbFlags & ~flags) == 0) )
                   1150:        {
                   1151:                pb->usbStatus = noErr;
                   1152:                return(true);
                   1153:        }
                   1154:        else
                   1155:        {
                   1156:                if((pb->pbVersion != 2) && (pb->pbVersion != 0x100)  && (pb->pbVersion != 0x109) )
                   1157:                {
                   1158:                        USBExpertStatusLevel(2, pb->usbReference, "USL error - Bad param block version", pb->pbVersion);
                   1159:                        pb->usbStatus = kUSBPBVersionError;
                   1160:                }
                   1161:                else if(pb->pbLength < sizeof(USBPB)) 
                   1162:                {
                   1163:                        USBExpertStatusLevel(2, pb->usbReference, "USL error - small param block version", pb->pbLength);
                   1164:                        pb->usbStatus = kUSBPBLengthError;
                   1165:                }
                   1166:                else if( (pb->usbCompletion == nil) || (pb->usbCompletion == (void *)-1) )
                   1167:                {
                   1168:                        USBExpertStatusLevel(2, pb->usbReference, "USL error - bad completion function", (UInt32)pb->usbCompletion);
                   1169:                        pb->usbStatus = kUSBCompletionError;
                   1170:                }
                   1171:                else if((pb->usbFlags & ~flags) != 0)
                   1172:                {
                   1173:                        USBExpertStatusLevel(2, pb->usbReference, "USL error - bad flags", pb->usbFlags & ~flags);
                   1174:                        pb->usbStatus = kUSBFlagsError;
                   1175:                }
                   1176:                else
                   1177:                {
                   1178:                        USBExpertStatusLevel(2, pb->usbReference, "USL error - What??", 0);
                   1179:                        pb->usbStatus = paramErr;
                   1180:                }
                   1181:                return(false);
                   1182:        }
                   1183: }
                   1184: 
                   1185: 
                   1186: 
                   1187: UInt8 USBMakeBMRequestType(USBDirection direction, USBRqType type, USBRqRecipient recipient)
                   1188: {
                   1189: UInt8 rq = 0xff;
                   1190:        do{
                   1191:                if(direction == kUSBNone)
                   1192:                {
                   1193:                        direction = kUSBOut;
                   1194:                }
                   1195:                if(direction != kUSBOut && direction != kUSBIn)
                   1196:                {
                   1197:                        break;
                   1198:                }
                   1199:                if(type < kUSBStandard || type > kUSBVendor)
                   1200:                {
                   1201:                        break;
                   1202:                }
                   1203:                if(recipient < kUSBDevice || recipient > kUSBOther)
                   1204:                {
                   1205:                        break;
                   1206:                }
                   1207:        
                   1208:                rq = recipient + (type << kUSBRqTypeShift) + (direction << kUSBRqDirnShift);
                   1209:        
                   1210:        }while(0);
                   1211:        return(rq);
                   1212: }
                   1213: 
                   1214: 
                   1215: 
                   1216: OSStatus USBDisposeInterfaceRef(USBPB *pb)
                   1217: {
                   1218: //      --> usbReference        --> interface
                   1219: OSStatus err;
                   1220: uslInterface *intfrc;
                   1221: Boolean nocallBack = false;
                   1222:        
                   1223:        if(pb->usbCompletion == kUSBNoCallBack)
                   1224:        {
                   1225:                nocallBack = true;
                   1226:                pb->usbCompletion = (void *)-2;
                   1227:        }
                   1228:        
                   1229:        if(!checkPBVersion(pb, 0))
                   1230:        {
                   1231:                return(pb->usbStatus);
                   1232:        }
                   1233:        err = findInterface(pb->usbReference, &intfrc);
                   1234:        if(intfrc == nil)
                   1235:        {
                   1236:                USBExpertStatusLevel(4, pb->usbReference, "USL - Interface to dispose not found", 0);
                   1237:                return(kUSBUnknownInterfaceErr);
                   1238:        }
                   1239:        intfrc->device = 0;
                   1240:        intfrc->interfaceNum = 0;
                   1241:        intfrc->alt = 0;
                   1242:        intfrc->ref = 0;
                   1243:        
                   1244:        if(nocallBack)
                   1245:        {
                   1246:                pb->usbCompletion = kUSBNoCallBack;
                   1247:        }
                   1248:        else
                   1249:        {
                   1250:                (*pb->usbCompletion)(pb);
                   1251:        }
                   1252:        return(kUSBPending);
                   1253: }
                   1254: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.