Annotation of driverkit/libDriver/Kernel/InputStream.m, revision 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:  * InputStream.m
        !            26:  *
        !            27:  * Copyright (c) 1991, NeXT Computer, Inc.  All rights reserved.
        !            28:  *
        !            29:  *      Audio driver input stream object.
        !            30:  *
        !            31:  * HISTORY
        !            32:  *      07/14/92/mtm    Original coding.
        !            33:  */
        !            34: 
        !            35: #import <mach/mach_types.h>
        !            36: #import <kern/lock.h>
        !            37: #import <mach/mach_user_internal.h>
        !            38: #import <mach/mach_interface.h>
        !            39: #import <kernserv/kern_server_types.h>
        !            40: #import <kernserv/prototypes.h>
        !            41: #import "InputStream.h"
        !            42: #import <driverkit/IOAudioPrivate.h>
        !            43: #import "snd_reply.h"
        !            44: #import "audioLog.h"
        !            45: #import "audioReply.h"
        !            46: #import <mach/vm_param.h>              // PAGE_SIZE
        !            47: #import <architecture/byte_order.h>
        !            48: #import <driverkit/kernelDriver.h>
        !            49: 
        !            50: @implementation InputStream
        !            51: 
        !            52: /*
        !            53:  * Enqueue buffer to region queue.
        !            54:  */
        !            55: - (BOOL)recordSize:(u_int)byteCount tag:(int)aTag
        !            56:                           replyTo:(port_t)replyPort
        !            57:                         replyMsgs:(ASMsgRequest)messages
        !            58: {
        !            59:     region_t *region;
        !            60:     kern_return_t krtn;
        !            61:     port_t kernReplyPort;
        !            62:     vm_address_t kmem;
        !            63:     vm_task_t kernelTask = (vm_task_t)kern_serv_kernel_task_port();
        !            64: 
        !            65:     kernReplyPort = IOConvertPort(replyPort, IO_CurrentTask, IO_Kernel);
        !            66: 
        !            67:     /*
        !            68:      * Truncate count if necessary.
        !            69:      */
        !            70:     if (dataFormat == IOAudioDataFormatLinear16)
        !            71:        byteCount &= (channelCount == 1 ? ~(2-1) : ~(4-1));
        !            72: 
        !            73:     /*
        !            74:      * Allocate memory in the kernel map.
        !            75:      */
        !            76:     krtn = vm_allocate(kernelTask, &kmem, byteCount, TRUE);
        !            77:     if (krtn != KERN_SUCCESS) {
        !            78:        IOLog("Audio: record request (%d bytes) too large\n", byteCount);
        !            79:        return NO;
        !            80:     }
        !            81: 
        !            82:     region = [self newRegion];
        !            83:     region->enq_ptr = region->record_ptr = region->data = kmem;
        !            84:     region->end = region->data + byteCount;
        !            85:     region->count = byteCount;
        !            86:     region->tag = aTag;
        !            87:     region->reply_port = kernReplyPort;
        !            88:     region->messages = messages;
        !            89: 
        !            90:     /*
        !            91:      * Some reply messages are per stream in NXSound interface.
        !            92:      * FIXME: these only get set if data sent to stream.
        !            93:      */
        !            94:     userReplyMessages = messages;
        !            95:     userReplyPort = kernReplyPort;
        !            96: 
        !            97:     xpr_audio_stream("IS: locking regionQueue\n", 1,2,3,4,5);
        !            98:     [regionQueueLock lock];
        !            99:     queue_enter(&regionQueue, region, region_t *, link);
        !           100:     [regionQueueLock unlock];
        !           101:     xpr_audio_stream("IS: unlocked regionQueue\n", 1,2,3,4,5);
        !           102:     [device _dataPendingForChannel: [self channel]];
        !           103:     return YES;
        !           104: }
        !           105: 
        !           106: /*
        !           107:  * Return count of bytes required for this region.
        !           108:  */
        !           109: - (u_int)mixRegion:(region_t *)region descriptor:(dma_desc_t *)ddp
        !           110:             buffer:(vm_address_t)data maxCount:(u_int)max
        !           111:             virgin:(BOOL)isVirgin rate:(u_int)srate format:(IOAudioDataFormat)format
        !           112:            channelCount:(u_int)chans
        !           113: {
        !           114:     u_int count = region->end - region->enq_ptr;
        !           115: 
        !           116:     /* FIXME
        !           117:      * Crystal chip sends 4 bytes per sample, even in mono 8-bit mode.
        !           118:      */
        !           119: //    max /= 4;
        !           120:     if (count > max)
        !           121:        count = max;
        !           122:     region->enq_ptr += count;
        !           123:     xpr_audio_stream("IS: requested %d bytes\n", count, 2,3,4,5);
        !           124:     return count;
        !           125: }
        !           126: 
        !           127: /*
        !           128:  * Read kernel memory into our task.
        !           129:  */
        !           130: static vm_address_t readFromKernel(vm_address_t kmem, u_int size)
        !           131: {
        !           132:     vm_address_t data;
        !           133:     kern_return_t kerr;
        !           134:     unsigned int count;
        !           135:     vm_address_t kmem_page = trunc_page(kmem);
        !           136:     unsigned int offset = kmem - kmem_page;
        !           137:     vm_task_t kernelTask = (vm_task_t)kern_serv_kernel_task_port();
        !           138: 
        !           139:     /*
        !           140:      * Note: kmem is normally on a page boundry because we get
        !           141:      * it from vm_allocate.  This function, however, handles the
        !           142:      * more general case of an offset.
        !           143:      */
        !           144: 
        !           145:     /*
        !           146:      * Read data from kernel map
        !           147:      * (vm_read allocates memory for us).
        !           148:      */
        !           149:     kerr = vm_read(kernelTask, kmem_page, round_page(size + offset),
        !           150:                   (pointer_t *)&data, &count);
        !           151:     if (kerr != KERN_SUCCESS) {
        !           152:        IOLog("Audio: vm_read returned %d\n", kerr);
        !           153:        //IOPanic("Audio: vm_read\n");
        !           154:     }
        !           155:     /*
        !           156:      * Return offset of the data in our task.
        !           157:      */
        !           158:     return data + offset;
        !           159: }
        !           160: 
        !           161: /*
        !           162:  * Send recorded data to user.
        !           163:  */
        !           164: - sendRecordedDataForRegion:(region_t *)region
        !           165: {
        !           166:     kern_return_t krtn;
        !           167:     u_int count;
        !           168:     vm_address_t data;
        !           169:     port_t ourReplyPort, ourUserPort;
        !           170:     
        !           171:     count = region->record_ptr - region->data;
        !           172: 
        !           173:     data = readFromKernel(region->data, count);
        !           174:     xpr_audio_stream("IS: sendRecordedDataForRegion 0x%x, count=%d\n",
        !           175:                     region, count, 3,4,5);
        !           176:     if (count == 0) {
        !           177:        log_debug(("Audio: no data recorded for region!\n"));
        !           178:        return self;
        !           179:     }
        !           180: 
        !           181:     ourReplyPort = IOConvertPort(region->reply_port, IO_Kernel,
        !           182:                                 IO_KernelIOTask);
        !           183:     ourUserPort = IOConvertPort(kernUserPort, IO_Kernel, IO_KernelIOTask);
        !           184: 
        !           185:     if (type == AS_TypeUser) {
        !           186:        krtn = _NXAudioReplyRecordedData(ourReplyPort, ourUserPort,
        !           187:                                         ourReplyPort, tag,
        !           188:                                         region->tag,
        !           189:                                         data, count);
        !           190:        if (krtn != KERN_SUCCESS) {
        !           191:            xpr_audio_stream("IS: sendRecData replyRecData error %d\n",
        !           192:                             krtn, 2,3,4,5);
        !           193:        }
        !           194:     } else {
        !           195:        if (!sndReplyMsg) {
        !           196:            sndReplyMsg = (msg_header_t *)IOMalloc(MSG_SIZE_MAX);
        !           197:            sndReplyMsg->msg_simple = TRUE;
        !           198:            sndReplyMsg->msg_size = sizeof(msg_header_t);
        !           199:            sndReplyMsg->msg_type = MSG_TYPE_NORMAL;
        !           200:            sndReplyMsg->msg_local_port = PORT_NULL;
        !           201:            sndReplyMsg->msg_remote_port = PORT_NULL;
        !           202:            sndReplyMsg->msg_id = 0;
        !           203:        }
        !           204:        audio_snd_reply_recorded_data(sndReplyMsg, ourReplyPort, region->tag,
        !           205:                                data, count);
        !           206:        krtn = msg_send(sndReplyMsg, STREAM_SEND_OPTIONS, STREAM_SEND_TIMEOUT);
        !           207:        if (krtn != KERN_SUCCESS) {
        !           208:            xpr_audio_stream("IS: sendRecData msg_send error %s (%d)\n",
        !           209:                             mach_error_string(krtn), krtn, 3,4,5);
        !           210:        }
        !           211:     }
        !           212:     return self;
        !           213: }
        !           214: 
        !           215: /*
        !           216:  * Copy recorded data to region.
        !           217:  */
        !           218: - completeRegion:(region_t *)region descriptor:(dma_desc_t *)ddp
        !           219:             size:(u_int)xfer used:(u_int *)used
        !           220: {
        !           221:     u_int needed = region->enq_ptr - region->record_ptr;
        !           222:     int i;
        !           223:     short *src, *dest;
        !           224: 
        !           225: #ifdef DEBUG
        !           226:     if (xfer < ddp->size) {
        !           227:        xpr_audio_stream("IS: xfer (%d) < ddp->size (%d)\n", xfer, ddp->size,
        !           228:                         3,4,5);
        !           229:        log_debug(("Audio: recorded %d bytes, wanted %d\n", xfer, ddp->size));
        !           230:     }
        !           231: #endif         DEBUG
        !           232: 
        !           233:     if ((xfer > 0) && (needed > 0)) {
        !           234:        xpr_audio_stream("IS: completeRegion needs %d bytes\n", needed,
        !           235:                         2,3,4,5);
        !           236:        if (*used + needed > xfer)
        !           237:            needed = xfer - *used;
        !           238:        xpr_audio_stream("IS: completeRegion copies %d bytes from 0x%x "
        !           239:                         "to 0x%x\n", needed, ddp->mem + *used,
        !           240:                         region->record_ptr, 4,5);
        !           241:        /*
        !           242:         * Swap in place.
        !           243:         */
        !           244:        src = (short *)(ddp->mem + *used);
        !           245:        dest = (short *)region->record_ptr;
        !           246:        if (dataFormat == IOAudioDataFormatLinear16) {
        !           247:            for (i = 0; i < needed / 2; i++)
        !           248:                *dest++ = NXSwapHostShortToBig(*src++);
        !           249:        } else if (dataFormat == IOAudioDataFormatLinear8) { /* && isUnary */
        !           250:            char *csrc = (char *)src;
        !           251:            char *cdest = (char *)dest;
        !           252:            for (i = 0; i < needed; i++) {
        !           253:                /* convert to 2's comp. by xor'ing the high bit */
        !           254:                *cdest++ = (*csrc ^ 0x80) | (*csrc & 0x7f);
        !           255:                csrc++;
        !           256:            }
        !           257:        } else if (dataFormat == IOAudioDataFormatMulaw8)
        !           258:            bcopy ((char *)src, (char *)dest, needed);
        !           259:        *used += needed;
        !           260:        region->record_ptr += needed;
        !           261:        bytesProcessed += needed;
        !           262:     }
        !           263:     /*
        !           264:      * Return recorded data on last ddp even if not all data was recorded.
        !           265:      */
        !           266:     if ((region->end_ddp == ddp) || region->flags.split)
        !           267:        [self sendRecordedDataForRegion:region];
        !           268:     return self;
        !           269: }
        !           270: 
        !           271: /*
        !           272:  * Split current region and return data recorded so far.
        !           273:  */
        !           274: - returnRecordedData
        !           275: {
        !           276:     region_t *region = 0, *newRegion;
        !           277:     BOOL found = NO;
        !           278:     kern_return_t krtn;
        !           279:     int completedSize, remainingSize, enqueuedSize;
        !           280:     vm_task_t kernelTask = (vm_task_t)kern_serv_kernel_task_port();
        !           281: 
        !           282:     xpr_audio_stream("IS: locking regionQueue\n", 1,2,3,4,5);
        !           283:     [regionQueueLock lock];
        !           284:     /*
        !           285:      * Find the first non-completed region.
        !           286:      */
        !           287:     if (!queue_empty(&regionQueue)) {
        !           288:        region = (region_t *)queue_first(&regionQueue);
        !           289:        while (!queue_end(&regionQueue, (queue_entry_t)region)) {
        !           290:            if ((region->record_ptr > region->data) &&
        !           291:                (region->record_ptr < region->end)) {
        !           292:                xpr_audio_stream("IS: returnRecData: region 0x%x\n", region,
        !           293:                                 2,3,4,5);
        !           294:                found = YES;
        !           295:                break;
        !           296:            }
        !           297:            region = (region_t *)queue_next(&region->link);
        !           298:        }
        !           299:     }
        !           300:     if (!found) {
        !           301:        [regionQueueLock unlock];
        !           302:        xpr_audio_stream("IS: unlocked regionQueue\n", 1,2,3,4,5);
        !           303:        xpr_audio_stream("IS: returnRecData: no region to split\n", 1,2,3,4,5);
        !           304:        wantsRecordedData = YES;
        !           305:        return self;
        !           306:     }
        !           307: 
        !           308:     newRegion = (region_t *)IOMalloc(sizeof(region_t));
        !           309:     *newRegion = *region;
        !           310:     completedSize = region->record_ptr - region->data;
        !           311:     remainingSize = region->count - completedSize;
        !           312:     enqueuedSize = region->enq_ptr - region->record_ptr;
        !           313:     xpr_audio_stream("IS: returnRecData: complete=%d, remain=%d "
        !           314:                     "enq=%d\n", completedSize, remainingSize,
        !           315:                     enqueuedSize, 4,5);
        !           316: 
        !           317:     /*
        !           318:      * Copy recorded data to a new region, free original data,
        !           319:      * and allocate new data for original region.
        !           320:      */
        !           321:     krtn = vm_allocate(kernelTask, &newRegion->data, completedSize, TRUE);
        !           322:     if (krtn != KERN_SUCCESS) {
        !           323:        IOLog("Audio: cannot allocate record memory\n");
        !           324:        IOFree(newRegion, sizeof(region_t));
        !           325:        [regionQueueLock unlock];
        !           326:        wantsRecordedData = YES;
        !           327:        return self;
        !           328:     }
        !           329: 
        !           330:     region->start_ddp = 0;
        !           331:     region->flags.started = FALSE;
        !           332: 
        !           333:     bcopy((char *)region->data, (char *)newRegion->data, completedSize);
        !           334: 
        !           335:     krtn = vm_deallocate(kernelTask, region->data, region->count);
        !           336:     if (krtn != KERN_SUCCESS)
        !           337:        log_error(("Audio: vm_deallocate: %s\n", mach_error_string(krtn)));
        !           338: 
        !           339:     krtn = vm_allocate(kernelTask, &region->data, remainingSize, TRUE);
        !           340:     if (krtn != KERN_SUCCESS) {
        !           341:        IOLog("Audio: cannot allocate record memory\n");
        !           342:        remainingSize = enqueuedSize = 0;
        !           343:     }
        !           344: 
        !           345:     region->count = remainingSize;
        !           346:     region->end = region->data + region->count;
        !           347:     region->record_ptr = region->data;
        !           348:     region->enq_ptr = region->data + enqueuedSize;
        !           349: 
        !           350:     /*
        !           351:      * Enter the new, completed region at the front of the queue.
        !           352:      */
        !           353:     newRegion->count = completedSize;
        !           354:     newRegion->end = newRegion->data + newRegion->count;
        !           355:     newRegion->record_ptr = newRegion->enq_ptr = newRegion->end;
        !           356:     newRegion->flags.ended = newRegion->flags.split = TRUE;
        !           357:     queue_enter_first(&regionQueue, newRegion, region_t *, link);
        !           358: 
        !           359:     [regionQueueLock unlock];
        !           360:     xpr_audio_stream("IS: unlocked regionQueue\n", 1,2,3,4,5);
        !           361:     wantsRecordedData = NO;
        !           362:     return self;
        !           363: }
        !           364: 
        !           365: /*
        !           366:  * Override from superclass to see if we need to return recorded data.
        !           367:  */
        !           368: - dmaCompleteDescriptor:(dma_desc_t *)ddp transfered:(u_int)count
        !           369: {
        !           370:     [super dmaCompleteDescriptor:ddp transfered:count];
        !           371: 
        !           372:     if (wantsRecordedData)
        !           373:        [self returnRecordedData];
        !           374:     return self;
        !           375: }
        !           376: 
        !           377: /*
        !           378:  * Free a region.
        !           379:  */
        !           380: - freeRegion:(region_t *)region
        !           381: {
        !           382:     kern_return_t krtn;
        !           383: 
        !           384:     log_debug(("IS: freeRegion dealloc %d bytes at 0x%x\n", region->count,
        !           385:               region->data));
        !           386:     /*
        !           387:      * Must get a fresh kernel task port here since
        !           388:      * we are in the IO task.
        !           389:      */
        !           390:     krtn = vm_deallocate((vm_task_t)kern_serv_kernel_task_port(),
        !           391:                         region->data, region->count);
        !           392:     if (krtn != KERN_SUCCESS)
        !           393:        log_error(("Audio: stream vm_deallocate error %s\n",
        !           394:                   mach_error_string(krtn)));
        !           395:     return [super freeRegion:region];
        !           396: }
        !           397: 
        !           398: @end

unix.superglobalmegacorp.com

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