Annotation of driverkit/libDriver/Kernel/InputStream.m, 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:  * 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.