|
|
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(®ionQueue, 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(®ionQueue)) {
288: region = (region_t *)queue_first(®ionQueue);
289: while (!queue_end(®ionQueue, (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(®ion->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, ®ion->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(®ionQueue, 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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.