Annotation of XNU/iokit/IOKit/storage/scsi/IOSCSICDDrive.h, revision 1.1.1.1

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) 1999 Apple Computer, Inc.  All rights reserved. 
                     24:  *
                     25:  * IOSCSICDDrive.h
                     26:  *
                     27:  * This class implements SCSI CDROM functionality.
                     28:  *
                     29:  * Subclasses may modify the operations to handle device-specific variations.
                     30:  */
                     31: 
                     32: #ifndef _IOSCSICDDRIVE_H
                     33: #define        _IOSCSICDDRIVE_H
                     34: 
                     35: #include <IOKit/IOTypes.h>
                     36: #include <IOKit/scsi/IOSCSIDeviceInterface.h>
                     37: #include <IOKit/storage/IOCDTypes.h>
                     38: #include <IOKit/storage/scsi/IOSCSIHDDrive.h>
                     39: 
                     40: const UInt8    drive_left_signal       = 0x01;
                     41: const UInt8    drive_right_signal      = 0x02;
                     42: const UInt8    drive_both_signals      = drive_left_signal | drive_right_signal;
                     43: enum channel {
                     44:     kLeft,
                     45:     kRight
                     46: };
                     47: 
                     48: const UInt8    SOP_SEEK                = 0x2b;         /* seek */
                     49: const UInt8    SOP_READSUBCHANNEL      = 0x42;         /* read subchannel data */
                     50: const UInt8    SOP_READTOC             = 0x43;         /* read TOC */
                     51: const UInt8    SOP_READHEADER          = 0x44;         /* read header */
                     52: const UInt8    SOP_PLAYAUDIO           = 0x45;         /* play audio by lba */
                     53: const UInt8    SOP_PLAYAUDIOMSF        = 0x47;         /* play audio by M:S:F */
                     54: const UInt8    SOP_AUDIOSCAN           = 0xcd;         /* audio scan */
                     55: 
                     56: struct IOAudioScancdb {
                     57:     UInt8      opcode;
                     58:     UInt8      lunbits;
                     59: static const UInt8     kForward = 0x10;
                     60:     UInt8      start3;                 /* msb */
                     61:     UInt8      start2;
                     62:     UInt8      start1;
                     63:     UInt8      start0;                 /* lsb */
                     64:     UInt8      ctlbyte;
                     65: static const UInt8     kType_lba       = 0x00;
                     66: static const UInt8     kType_msf       = 0x40;
                     67: static const UInt8     kType_track     = 0x80;
                     68: };
                     69: 
                     70: struct IOAudioPlaycdb {
                     71:     UInt8      opcode;
                     72:     UInt8      lunbits;
                     73:     UInt8      lba_3;          /* msb */
                     74:     UInt8      lba_2;
                     75:     UInt8      lba_1;
                     76:     UInt8      lba_0;          /* lsb */
                     77:     UInt8      reserved1;
                     78:     UInt8      len_hi;
                     79:     UInt8      len_lo;
                     80:     UInt8      ctlbyte;
                     81: };
                     82: 
                     83: struct IOAudioPlayMSFcdb {
                     84:     UInt8      opcode;
                     85:     UInt8      lunbits;
                     86:     UInt8      reserved1;
                     87:     UInt8      start_m;
                     88:     UInt8      start_s;
                     89:     UInt8      start_f;
                     90:     UInt8      end_m;
                     91:     UInt8      end_s;
                     92:     UInt8      end_f;
                     93:     UInt8      ctlbyte;
                     94: };
                     95: 
                     96: struct IOReadHeadercdb {
                     97:     UInt8      opcode;
                     98:     UInt8      lunbits;
                     99: static const UInt8     kMSF = 0x02;
                    100:     UInt8      lba_3;          /* msb */
                    101:     UInt8      lba_2;
                    102:     UInt8      lba_1;
                    103:     UInt8      lba_0;          /* lsb */
                    104:     UInt8      reserved1;
                    105:     UInt8      len_hi;
                    106:     UInt8      len_lo;
                    107:     UInt8      ctlbyte;
                    108: };
                    109: 
                    110: struct IOReadToccdb {
                    111:     UInt8      opcode;
                    112:     UInt8      lunbits;
                    113: static const UInt8     kMSF = 0x02;            /* set to get mm:ss:ff format, else logical addr */
                    114:     UInt8      reserved1;
                    115:     UInt8      reserved2;
                    116:     UInt8      reserved3;
                    117:     UInt8      reserved4;
                    118:     UInt8      start_trk_session;      /* starting track/session number */
                    119:     UInt8      len_hi;
                    120:     UInt8      len_lo;
                    121:     UInt8      ctlbyte;                /* and format code */
                    122: static const UInt8     kSCSI2          = 0x00;         /* ANSI SCSI2 style: all track descriptors */
                    123: static const UInt8     kSessionInfo    = 0x40;         /* first & last session #s, last sess start addr. */
                    124: static const UInt8     kQLeadIn        = 0x80;         /* all Q subcodes for lead-in of specified sess */
                    125: };
                    126: 
                    127: struct IORSCcdb {
                    128:     UInt8      opcode;
                    129:     UInt8      lunbits;
                    130: static const UInt8     kMSF = 0x02;            /* set to get mm:ss:ff format, else logical addr */
                    131:     UInt8      subq;
                    132: static const UInt8     kSubq = 0x40;           /* set to get subq data */
                    133:     UInt8      dataformat;
                    134: static const UInt8     kCurrentPosition        = 1;
                    135: static const UInt8     kMCN                    = 2;
                    136: static const UInt8     kISRC                   = 3;
                    137:     UInt8      reserved1;
                    138:     UInt8      reserved2;
                    139:     UInt8      track;
                    140:     UInt8      len_hi;
                    141:     UInt8      len_lo;
                    142:     UInt8      ctlbyte;
                    143: };
                    144: 
                    145: struct IOSeekcdb {
                    146:     UInt8      opcode;
                    147:     UInt8      lunbits;
                    148:     UInt8      lba_3;          /* msb */
                    149:     UInt8      lba_2;
                    150:     UInt8      lba_1;
                    151:     UInt8      lba_0;          /* lsb */
                    152:     UInt8      reserved1;
                    153:     UInt8      reserved2;
                    154:     UInt8      reserved3;
                    155:     UInt8      ctlbyte;
                    156: };
                    157: 
                    158: /*!
                    159:  * @class IOSCSICDDrive : public IOSCSIHDDrive
                    160:  * @abstract
                    161:  * Driver for SCSI CD-ROM drives.
                    162:  * @discussion
                    163:  * IOSCSICDDrive is a subclass of IOSCSIHDDrive. It adds appropriate CD-ROM
                    164:  * APIs (e.g. audio), and overrides some methods of IOSCSIHDDrive in order
                    165:  * to alter their behavior for CD-ROM devices.
                    166:  */
                    167: /*------------------------------------------------*/
                    168: class IOSCSICDDrive : public IOSCSIHDDrive {
                    169: 
                    170:     OSDeclareDefaultStructors(IOSCSICDDrive)
                    171: 
                    172: public:
                    173: 
                    174:     /* Overrides from IOService: */
                    175:     
                    176:     virtual bool       init(OSDictionary * properties);
                    177:     
                    178:     /* Overrides from IOBasicSCSI: */
                    179: 
                    180:     /*!
                    181:      * @function deviceTypeMatches
                    182:      * @abstract
                    183:      * Determine if the device type matches that which we expect.
                    184:      * @discussion
                    185:      * This override allows us to check for the SCSI CD-ROM
                    186:      * device type instead of hard disk.
                    187:      * See IOBasicSCSI for details.
                    188:      */
                    189:     virtual bool       deviceTypeMatches(UInt8 inqBuf[],UInt32 inqLen);
                    190: 
                    191:     /* End of IOBasicSCSI overrides */
                    192: 
                    193:     /* IOSCSIHDDrive overrides: */
                    194: 
                    195:     /*!
                    196:      * @function getDeviceTypeName
                    197:      * @abstract
                    198:      * Return a character string for the device type.
                    199:      * @discussion
                    200:      * This override returns kDeviceTypeCDROM.   
                    201:      */
                    202:     virtual const char * getDeviceTypeName(void);
                    203:     /*!
                    204:      * @function instantiateNub
                    205:      * @abstract
                    206:      * Create the device nub.
                    207:      * @discussion
                    208:      * This override instantiates an IOSCSICDDriveNub instead of an IOSCSIHDDriveNub.
                    209:      */
                    210:     virtual IOService *        instantiateNub(void);
                    211: 
                    212:     /* We want to track media changes to do cleanup.     */
                    213:     /*!
                    214:      * @function reportMediaState
                    215:      * @abstract
                    216:      * Report the device's media state.
                    217:      * @discussion
                    218:      * This override allows us to reset device settings when media changes.
                    219:      */
                    220:     virtual IOReturn   reportMediaState(bool *mediaPresent,bool *changed);
                    221: 
                    222:     /* end of IOSCSIHDDrive overrides */
                    223:     
                    224:     /* ------------------------------------------------*/
                    225:     /* APIs that affect the entire media in the drive, */
                    226:     /* exported eventually by IOCDMedia:               */
                    227:     /* ------------------------------------------------*/
                    228: 
                    229:     /*!
                    230:      * @function audioPause
                    231:      * @abstract
                    232:      * Pause or resume the audio playback.
                    233:      * @param pause
                    234:      * True to pause playback; False to resume.
                    235:      */
                    236:     virtual IOReturn   audioPause(bool pause);
                    237:     
                    238:     /*!
                    239:      * @function audioScan
                    240:      * @abstract
                    241:      * Perform a fast-forward or fast-backward operation.
                    242:      * @param addressType
                    243:      * The type of positioning address. See positioningType for details.
                    244:      * @param address
                    245:      * The position from which to begin.
                    246:      * @param reverse
                    247:      * True to go backward; False to go forward.
                    248:      */
                    249:     virtual IOReturn   audioScan(positioningType addressType,cdAddress address,bool reverse);
                    250:     
                    251:     /*!
                    252:      * @function readAudioData
                    253:      * @abstract
                    254:      * Read audio data blocks.
                    255:      * @param addressType
                    256:      * The type of positioning address. See positioningType for details.
                    257:      * @param address
                    258:      * The position from which to begin.
                    259:      * @param blockCount
                    260:      * The number of blocks to read.
                    261:      * @param buffer
                    262:      * The buffer for the data.
                    263:      */
                    264:     virtual IOReturn   readAudioData(positioningType addressType,cdAddress address,
                    265:                                        UInt8 blockCount,UInt8 *buffer);
                    266:     
                    267:     /*!
                    268:      * @function readAudioSubcodes
                    269:      * @abstract
                    270:      * Read audio subcodes only.
                    271:      * @param addressType
                    272:      * The type of positioning address. See positioningType for details.
                    273:      * @param address
                    274:      * The position from which to begin.
                    275:      * @param blockCount
                    276:      * The number of blocks to read.
                    277:      * @param buffer
                    278:      * The buffer for the data.
                    279:      */
                    280:     virtual IOReturn   readAudioSubcodes(positioningType addressType,cdAddress address,
                    281:                                        UInt8 blockCount,UInt8 *buffer);
                    282:     
                    283:     /*!
                    284:      * @function readAudioWithQSubcode
                    285:      * @abstract
                    286:      * Read audio blocks along with the Q subcode.
                    287:      * @param addressType
                    288:      * The type of positioning address. See positioningType for details.
                    289:      * @param address
                    290:      * The position from which to begin.
                    291:      * @param blockCount
                    292:      * The number of blocks to read.
                    293:      * @param buffer
                    294:      * The buffer for the data.
                    295:      */
                    296:     virtual IOReturn   readAudioWithQSubcode(positioningType addressType,cdAddress address,
                    297:                                        UInt8 blockCount,UInt8 *buffer);
                    298:     
                    299:     /*!
                    300:      * @function readAudioWithAllSubcodes
                    301:      * @abstract
                    302:      * Read audio data along with all subcodes.
                    303:      * @param addressType
                    304:      * The type of positioning address. See positioningType for details.
                    305:      * @param address
                    306:      * The position from which to begin.
                    307:      * @param blockCount
                    308:      * The number of blocks to read.
                    309:      * @param buffer
                    310:      * The buffer for the data.
                    311:      */
                    312:     virtual IOReturn   readAudioWithAllSubcodes(positioningType addressType,cdAddress address,
                    313:                                        UInt8 blockCount,UInt8 *buffer);
                    314:     
                    315:     /*!
                    316:      * @function readHeader
                    317:      * @abstract
                    318:      * Read the header for the specified logical block.
                    319:      * @param address
                    320:      * The logical block from which to read the header data.
                    321:      * @param buffer
                    322:      * The buffer for the header data.
                    323:      */
                    324:     virtual IOReturn   readHeader(UInt32 blockAddress,struct headerInfo *buffer);
                    325: 
                    326:     /*!
                    327:      * @function readISRC
                    328:      * @abstract
                    329:      * Read the ISRC data for the disc.
                    330:      * @param track
                    331:      * The track number from which to read the ISRC.
                    332:      * @param buffer
                    333:      * The buffer for the ISRC data.
                    334:      * @param found
                    335:      * A pointer to the result: True if the ISRC was found, else False.
                    336:      */
                    337:     virtual IOReturn   readISRC(UInt32 track,UInt8 *buffer,bool *found);
                    338:     
                    339:     /*!
                    340:      * @function readMCN
                    341:      * @abstract
                    342:      * Read the MCN (Media Catalog Number) for the disc.
                    343:      * @param buffer
                    344:      * The buffer for the MCN data.
                    345:      * @param found
                    346:      * A pointer to the result: True if the ISRC was found, else False.
                    347:      */
                    348:     virtual IOReturn   readMCN(UInt8 *buffer,bool *found);
                    349:     
                    350:     /*!
                    351:      * @function readQSubcodes
                    352:      * @abstract
                    353:      * Read the Q subcode entries in the lead-in areas of the disc.
                    354:      * @param buffer
                    355:      * The buffer for the returned data
                    356:      * @param bufSize
                    357:      * The size of the buffer in bytes.
                    358:      */
                    359:     virtual IOReturn   readQSubcodes(struct qSubcodeTocInfo *buffer,UInt32 bufSize);
                    360:     
                    361:     /*!
                    362:      * @function readSubcodeBuffer
                    363:      * @abstract
                    364:      * Read the device subcode buffer while audio is playing.
                    365:      * @param buffer
                    366:      * The buffer for the returned data
                    367:      * @param purge
                    368:      * True if the buffer should be purged before doing the read.
                    369:      * @param entryCount
                    370:      * The number of consecutive subcode blocks (96 bytes each) to return.
                    371:      */
                    372:     virtual IOReturn   readSubcodeBuffer(UInt8 *buffer,bool purge,UInt32 entryCount);
                    373:     
                    374:     /*!
                    375:      * @function readTheQSubcode
                    376:      * @abstract
                    377:      * Read the Q-subcode information for the current track.
                    378:      * @param buffer
                    379:      * The buffer for the returned data
                    380:      */
                    381:     virtual IOReturn   readTheQSubcode(struct qSubcode *buffer);
                    382:     
                    383:     /*!
                    384:      * @function readTOC
                    385:      * @abstract
                    386:      * Read the entire Table Of Contents (TOC) for the disc.
                    387:      * @param buffer
                    388:      * The buffer for the returned data
                    389:      * @param length
                    390:      * The maximum length of the buffer.
                    391:      * @param format
                    392:      * The desired TOC format desired. See tocFormat for details.
                    393:      */
                    394:     virtual IOReturn   readTOC(struct rawToc *buffer,UInt32 length,tocFormat format);
                    395:     
                    396:     /*!
                    397:      * @function setAudioStopAddress
                    398:      * @abstract
                    399:      * Set the address at which the device is to stop playing audio.
                    400:      * @param addressType
                    401:      * The type of positioning address. See positioningType for details.
                    402:      * @param address
                    403:      * The position from which to begin.
                    404:      */
                    405:     virtual IOReturn   setAudioStopAddress(positioningType addressType,cdAddress address);
                    406: 
                    407:     /* ---------------------------------------------------*/
                    408:     /*  APIs exported eventually by IOCDAudioNub:         */
                    409:     /* ---------------------------------------------------*/
                    410: 
                    411:     /*!
                    412:      * @function audioPlay
                    413:      * @abstract
                    414:      * Play audio.
                    415:      * @param addressType
                    416:      * The type of positioning address. See positioningType for details.
                    417:      * @param address
                    418:      * The position from which to begin.
                    419:      * @param mode
                    420:      * The mode for playing the audio. See audioPlayMode for details.
                    421:      */
                    422:     virtual IOReturn   audioPlay(positioningType addressType,cdAddress address,
                    423:                                                audioPlayMode mode);
                    424:     /*!
                    425:      * @function audioTrackSearch
                    426:      * @abstract
                    427:      * Position the optical pick-up at the specified audio address.
                    428:      * @param addressType
                    429:      * The type of positioning address. See positioningType for details.
                    430:      * @param address
                    431:      * The position from which to begin.
                    432:      * @param startPlay
                    433:      * True to begin playing audio after positioning; False to enter the pause state.
                    434:      * @param mode
                    435:      * The mode for playing the audio. See audioPlayMode for details.
                    436:      */
                    437:     virtual IOReturn   audioTrackSearch(positioningType addressType,cdAddress address,
                    438:                                                bool startPlay,audioPlayMode mode);
                    439:     /*!
                    440:      * @function getAudioStatus
                    441:      * @abstract
                    442:      * Return the current audio play status information.
                    443:      * @param status
                    444:      * The buffer for the returned information.
                    445:      */
                    446:     virtual IOReturn   getAudioStatus(struct audioStatus *status);
                    447:     /*!
                    448:      * @function readAudioVolume
                    449:      * @abstract
                    450:      * Read the current audio volume.
                    451:      * @param leftVolume
                    452:      * A pointer to the returned left-channel volume.
                    453:      * @param rightVolume
                    454:      * A pointer to the returned right-channel volume.
                    455:      */
                    456:     virtual IOReturn   readAudioVolume(UInt8 *leftVolume,UInt8 *rightVolume);
                    457:     /*!
                    458:      * @function setVolume
                    459:      * @abstract
                    460:      * Set the audio volume.
                    461:      * @param leftVolume
                    462:      * The desired left-channel volume.
                    463:      * @param rightVolume
                    464:      * The desired right-channel volume.
                    465:      */
                    466:     virtual IOReturn   setVolume(UInt8 leftVolume,UInt8 rightVolume);
                    467: 
                    468: protected:
                    469: 
                    470:     /* Internally used methods: */
                    471: 
                    472:     /*!
                    473:      * @function convertMSFToLba
                    474:      * @abstract
                    475:      * Convert an MM:SS:FF value to a Logical Block Address
                    476:      * @param lba
                    477:      * A pointer to the returned LBA.
                    478:      * @param address
                    479:      * The address to convert from MM:SS:FF format.
                    480:      * @return
                    481:      * This routine always returns kIOReturnSuccess
                    482:      */
                    483:     virtual IOReturn   convertMSFToLba(UInt32 *lba,cdAddress address);
                    484:     
                    485:     /*!
                    486:      * @function doAudioPlayCommand
                    487:      * @abstract
                    488:      * Issue an audio play command to the device.
                    489:      * @param startType
                    490:      * The type of positioning address. See positioningType for details.
                    491:      * @param startAddress
                    492:      * The position from which to begin.
                    493:      * @param endType
                    494:      * The type of positioning address. See positioningType for details.
                    495:      * @param endAddress
                    496:      * The position at which to end.
                    497:      */
                    498:     virtual IOReturn   doAudioPlayCommand(positioningType startType,cdAddress startAddress,
                    499:                                             positioningType endType,cdAddress endAddress);
                    500:     /*!
                    501:      * @function initAudioModes
                    502:      * @abstract
                    503:      * Initialize audio modes for the device when media is changed.
                    504:      */
                    505:     virtual void       initAudioModes(void);
                    506:     
                    507:     /*!
                    508:      * @function mediaGone
                    509:      * @abstract
                    510:      * React to media going away.
                    511:      */
                    512:     virtual void       mediaGone(void);
                    513:     
                    514:     /*!
                    515:      * @function playModeToDriveBits
                    516:      * @abstract
                    517:      * Convert an audioPlayMode value to the format used by the device.
                    518:      * @param mode
                    519:      * The audioPlayMode value to be converted.
                    520:      * @param chan
                    521:      * The desired audio channel.
                    522:      * @return
                    523:      * The converted bits in a format directly usable by the device.
                    524:      */
                    525:     virtual UInt8      playModeToDriveBits(audioPlayMode mode,channel chan);
                    526:     
                    527:     /*!
                    528:      * @function readISRCMCN
                    529:      * @abstract
                    530:      * Perform the command necessary to read ISRC or MCN data.
                    531:      * @param dataformat
                    532:      * The desired data format: ISRC or MCN.
                    533:      * @param track
                    534:      * The desired track from which to read the data
                    535:      * @param buffer
                    536:      * The buffer for the data.
                    537:      * @param found
                    538:      * A pointer to the result: True if the item was found; false if not.
                    539:      */
                    540:     virtual IOReturn   readISRCMCN(UInt8 dataformat,UInt32 track,UInt8 *buffer,bool *found);
                    541:     
                    542:     /*!
                    543:      * @function readSubchannel
                    544:      * @abstract
                    545:      * Issue the command necessary to read subchannel data.
                    546:      * @param buffer
                    547:      * The buffer for the data.
                    548:      * @param length
                    549:      * The maximum data length desired.
                    550:      * @param track
                    551:      * The desired track from which to read the data
                    552:      * @param dataFormat
                    553:      * The subchannel data desired.
                    554:      */
                    555:     virtual IOReturn   readSubchannel(UInt8 *buffer,UInt32 length,UInt8 track,UInt8 dataFormat);
                    556:     
                    557:     /*!
                    558:      * @function seek
                    559:      * @abstract
                    560:      * Issue the command necessary to position the device at the specified LBA.
                    561:      * @param lba
                    562:      * The desired Logical Block Address at which to position the device.
                    563:      */
                    564:     virtual IOReturn   seek(UInt32 lba);
                    565:     
                    566:     /*!
                    567:      * @function setDefaultAudioModes
                    568:      * @abstract
                    569:      * Set the device audio modes to the default.
                    570:      * @discussion
                    571:      * This method calls initAudioModes and then sets volume to the max.
                    572:      */
                    573:     virtual IOReturn   setDefaultAudioModes(void);
                    574: 
                    575:     /*!
                    576:      * @var _audioPlayMode
                    577:      * The current audio play mode for the device.
                    578:      */
                    579:     audioPlayMode              _audioPlayMode;
                    580: 
                    581:     /*!
                    582:      * @var _leftVolume
                    583:      * The current volume of the left channel.
                    584:      */
                    585:     UInt8              _leftVolume;
                    586: 
                    587:     /*!
                    588:      * @var _rightVolume
                    589:      * The current volume of the right channel.
                    590:      */
                    591:     UInt8              _rightVolume;
                    592: 
                    593:     /*!
                    594:      * @var _leftPortChannel
                    595:      * The current signal-routing assignment of the left-channel audio signal.
                    596:      */
                    597:     UInt8              _leftPortChannel;       /* matches IOCDTypes consts */
                    598: 
                    599:     /*!
                    600:      * @var _rightPortChannel
                    601:      * The current signal-routing assignment of the right-channel audio signal.
                    602:      */
                    603:     UInt8              _rightPortChannel;      /* matches IOCDTypes consts */
                    604: 
                    605:     struct qualifiedCDAddress          _audioStopAddress;
                    606: };
                    607: #endif

unix.superglobalmegacorp.com

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