staticint sq_allocate_buffers(struct sound_queue *sq, int num, int size)
{ int i;
if (sq->buffers) return0;
sq->numBufs = num;
sq->bufSize = size;
sq->buffers = kmalloc_array (num, sizeof(char *), GFP_KERNEL); if (!sq->buffers) return -ENOMEM; for (i = 0; i < num; i++) {
sq->buffers[i] = dmasound.mach.dma_alloc(size, GFP_KERNEL); if (!sq->buffers[i]) { while (i--)
dmasound.mach.dma_free(sq->buffers[i], size);
kfree(sq->buffers);
sq->buffers = NULL; return -ENOMEM;
}
} return0;
}
staticvoid sq_release_buffers(struct sound_queue *sq)
{ int i;
if (sq->buffers) { for (i = 0; i < sq->numBufs; i++)
dmasound.mach.dma_free(sq->buffers[i], sq->bufSize);
kfree(sq->buffers);
sq->buffers = NULL;
}
}
staticint sq_setup(struct sound_queue *sq)
{ int (*setup_func)(void) = NULL; int hard_frame ;
if (sq->locked) { /* are we already set? - and not changeable */ #ifdef DEBUG_DMASOUND
printk("dmasound_core: tried to sq_setup a locked queue\n") ; #endif return -EINVAL ;
}
sq->locked = 1 ; /* don't think we have a race prob. here _check_ */
/* make sure that the parameters are set up Thisshouldhavebeendonealready...
*/
dmasound.mach.init();
/* OK. If the user has set fragment parameters explicitly, then we shouldleavethemalone...aslongastheyarevalid. Invaliduserfragmentparamscanoccurifweallowthewholebuffer tobeusedwhentheuserrequeststhefragmentssizes(withnosoft x-lation)andthentheusersubsequentlysetsasoftx-lationthat requiresincreasedinternalbuffering.
/* ++TeSche: Is something like this necessary? *Hey,that'sanhonestquestion!Ordoesanyotherpartofthe *filesystemalreadychecksthissituation?Ireallydon'tknow.
*/ if (uLeft == 0) return0;
/* implement any changes we have made to the soft/hard params. thisisnotsatisfactoryreally,allwehavedoneuptonowisto saywhatwewouldlike-therehasn'tbeenanyrealcheckingofcapability
*/
/* set up the sq if it is not already done. This may seem a dumb place todoit-butitiswhatOSSrequires.Itmeansthatwrite()can returnmemoryallocationerrors.Toavoidthispossibilityusethe GETBLKSIZEorGETOSPACEioctls(afteryou'vefiddledwithallthe paramsyouwanttochange)-theseioctlsalsoforcethesetup.
*/
if (write_sq.locked == 0) { if ((uWritten = sq_setup(&write_sq)) < 0) return uWritten ;
uWritten = 0 ;
}
/* FIXME: I think that this may be the wrong behaviour when we get strapped fortimeandthecpuisclosetobeing(oractually)behindinsendingdata. -becausewe'velostthetimethattheNsamples,alreadyinthebuffer, wouldhavegivenustogetherewiththenextlotfromtheuser.
*/ /* The interrupt doesn't start to play the last, incomplete frame. *Thuswecanappendtoitwithoutdisablingtheinterrupts!(Note *alsothatwrite_sq.rearisn'taffectedbytheinterrupt.)
*/
/* as of 1.6 this behaviour changes if SNDCTL_DSP_POST has been issued: thiswillmimicthebehaviourofsyncingandallowthesq_play()to queueapartialfragment.Sincesq_play()may/willbecalledfrom theIRQhandler-atleastonPmacwehavetodealwithit. Thestrategy-possiblynotoptimum-istokill_POSTstatusifwe gethere.Thisseems,atleast,reasonable-inthesensethatPOST issupposedtoindicatethatwemightnotwritebeforethequeue isdrained-andifwegethereintimethenitdoesnotapply.
*/
spin_lock_irqsave(&dmasound.lock, flags);
write_sq.syncing &= ~2 ; /* take out POST status */
spin_unlock_irqrestore(&dmasound.lock, flags);
/* Here, we can avoid disabling the interrupt by first *copyingandtranslatingthedata,andthenupdating *thewrite_sqvariables.Untilthisisdone,theinterrupt *won'tseethenewframeandwecanworkonit *undisturbed.
*/
staticint sq_open(struct inode *inode, struct file *file)
{ int rc;
mutex_lock(&dmasound_core_mutex); if (!try_module_get(dmasound.mach.owner)) {
mutex_unlock(&dmasound_core_mutex); return -ENODEV;
}
rc = write_sq_open(file); /* checks the f_mode */ if (rc) goto out; if (file->f_mode & FMODE_READ) { /* TODO: if O_RDWR, release any resources grabbed by write part */
rc = -ENXIO ; /* I think this is what is required by open(2) */ goto out;
}
if (dmasound.mach.sq_open)
dmasound.mach.sq_open(file->f_mode);
/* CHECK whether this is sensible - in the case that dsp0 could be opened O_RDONLYanddsp1couldbeopenedO_WRONLY
*/
dmasound.minDev = iminor(inode) & 0x0f;
/* OK. - we should make some attempt at consistency. At least the H'ware optionsshouldbesetwithavalidmode.WewillmakeitthattheLL drivermustsupplydefaultsforhard&softparams.
*/
if (shared_resource_owner == 0) { /* you can make this AFMT_U8/mono/8K if you want to mimic old
OSS behaviour - while we still have soft translations ;-) */
dmasound.soft = dmasound.mach.default_soft ;
dmasound.dsp = dmasound.mach.default_soft ;
dmasound.hard = dmasound.mach.default_hard ;
}
#ifndef DMASOUND_STRICT_OSS_COMPLIANCE /* none of the current LL drivers can actually do this "native" at the moment OSSdoesnotreallyrequireustosupply/dev/audioifwecan'tdoit.
*/ if (dmasound.minDev == SND_DEV_AUDIO) {
sound_set_speed(8000);
sound_set_stereo(0);
sound_set_format(AFMT_MU_LAW);
} #endif
mutex_unlock(&dmasound_core_mutex); return0;
out:
module_put(dmasound.mach.owner);
mutex_unlock(&dmasound_core_mutex); return rc;
}
staticvoid sq_reset_output(void)
{
sound_silence(); /* this _must_ stop DMA, we might be about to lose the buffers */
write_sq.active = 0;
write_sq.count = 0;
write_sq.rear_size = 0; /* write_sq.front = (write_sq.rear+1) % write_sq.max_count;*/
write_sq.front = 0 ;
write_sq.rear = -1 ; /* same as for set-up */
/* OK - we can unlock the parameters and fragment settings */
write_sq.locked = 0 ;
write_sq.user_frags = 0 ;
write_sq.user_frag_size = 0 ;
}
staticvoid sq_reset(void)
{
sq_reset_output() ; /* we could consider resetting the shared_resources_owner here... but I thinkitisprobablystillrathernon-obvioustoapplicationwriter
*/
/* we release everything else though */
shared_resources_initialised = 0 ;
}
staticint sq_fsync(void)
{ int rc = 0; int timeout = 5;
write_sq.syncing |= 1;
sq_play(); /* there may be an incomplete frame waiting */
while (write_sq.active) {
wait_event_interruptible_timeout(write_sq.sync_queue,
!write_sq.active, HZ); if (signal_pending(current)) { /* While waiting for audio output to drain, an *interruptoccurred.Stopaudiooutputimmediately
* and clear the queue. */
sq_reset_output();
rc = -EINTR; break;
} if (!--timeout) {
printk(KERN_WARNING "dmasound: Timeout draining output\n");
sq_reset_output();
rc = -EIO; break;
}
}
/* flag no sync regardless of whether we had a DSP_POST or not */
write_sq.syncing = 0 ; return rc;
}
if (file->f_mode & FMODE_WRITE) { if (write_sq.busy)
rc = sq_fsync();
sq_reset_output() ; /* make sure dma is stopped and all is quiet */
write_sq_release_buffers();
write_sq.busy = 0;
}
if (file->f_mode & shared_resource_owner) { /* it's us that has them */
shared_resource_owner = 0 ;
shared_resources_initialised = 0 ;
dmasound.hard = dmasound.mach.default_hard ;
}
module_put(dmasound.mach.owner);
#if0/* blocking open() */ /* Wake up a process waiting for the queue being released. *Note:Theremaybeseveralprocesseswaitingforacall
* to open() returning. */
/* Iain: hmm I don't understand this next comment ... */ /* There is probably a DOS atack here. They change the mode flag. */ /* XXX add check here,*/
read_sq_wake_up(file); /* checks f_mode */
write_sq_wake_up(file); /* checks f_mode */ #endif/* blocking open() */
mutex_unlock(&dmasound_core_mutex);
return rc;
}
/* here we see if we have a right to modify format, channels, size and so on ifno-oneelsehasclaimeditalreadythenwedo...
/* if either queue is locked we must deny the right to change shared params
*/
staticint queues_are_quiescent(void)
{ if (write_sq.locked) return0 ; return1 ;
}
/* check and set a queue's fragments per user's wishes... wewillcheckagainstthepre-definedliteralsandtheactualsizes. Thisisabitfraught-becausesofttranslationscanmesswithour bufferrequirements*after*thiscall-OSSsays"callsetfragsfirst"
*/
/* It is possible to replace all the -EINVAL returns with an override that justputstheallowablevaluein.ThismaybewhatmanyOSSappsrequire
*/
staticint set_queue_frags(struct sound_queue *sq, int bufs, int size)
{ if (sq->locked) { #ifdef DEBUG_DMASOUND
printk("dmasound_core: tried to set_queue_frags on a locked queue\n") ; #endif return -EINVAL ;
}
if ((size < MIN_FRAG_SIZE) || (size > MAX_FRAG_SIZE)) return -EINVAL ;
size = (1<<size) ; /* now in bytes */ if (size > sq->bufSize) return -EINVAL ; /* this might still not work */
if (bufs <= 0) return -EINVAL ; if (bufs > sq->numBufs) /* the user is allowed say "don't care" with 0x7fff */
bufs = sq->numBufs ;
/* there is, currently, no way to specify max_active separately frommax_count.ThiscouldbeaLLdriverissue-Iguess ifthereisarequirementforthesevaluestobedifferentthen wewillhavetopassthatinfo.uptothislevel.
*/
sq->user_frags =
sq->max_active = bufs ;
sq->user_frag_size = size ;
return0 ;
}
staticint sq_ioctl(struct file *file, u_int cmd, u_long arg)
{ int val, result;
u_long fmt; int data; int size, nbufs;
audio_buf_info info;
switch (cmd) { case SNDCTL_DSP_RESET:
sq_reset(); return0; case SNDCTL_DSP_GETFMTS:
fmt = dmasound.mach.hardware_afmts ; /* this is what OSS says.. */ return IOCTL_OUT(arg, fmt); case SNDCTL_DSP_GETBLKSIZE: /* this should tell the caller about bytes that the app can read/write-theappdoesn'tcareaboutourinternalbuffers. Weforcesq_setup()hereasperOSS1.1(whichshould computethevaluesnecessary). Sincethereisnomechanismtospecifyread/writeseparately,for fdsopenedO_RDWR,thewrite_sqvalueswill,arbitrarily,overwrite theread_sqones.
*/
size = 0 ; if (file->f_mode & FMODE_WRITE) { if ( !write_sq.locked )
sq_setup(&write_sq) ;
size = write_sq.user_frag_size ;
} return IOCTL_OUT(arg, size); case SNDCTL_DSP_POST: /* all we are going to do is to tell the LL that any partialfragscanbequeuedforoutput. TheLLwillhavetoclearthisflagwhenlastoutput isqueued.
*/
write_sq.syncing |= 0x2 ;
sq_play() ; return0 ; case SNDCTL_DSP_SYNC: /* This call, effectively, has the same behaviour as SNDCTL_DSP_RESET exceptthatitwaitsforoutputtofinishbeforeresetting everything-read,however,iskilledimmediately.
*/
result = 0 ; if (file->f_mode & FMODE_WRITE) {
result = sq_fsync();
sq_reset_output() ;
} /* if we are the shared resource owner then release them */ if (file->f_mode & shared_resource_owner)
shared_resources_initialised = 0 ; return result ; case SOUND_PCM_READ_RATE: return IOCTL_OUT(arg, dmasound.soft.speed); case SNDCTL_DSP_SPEED: /* changing this on the fly will have weird effects on the sound. Wheretherearerateconversionsimplementedinsoftform-it willcausethe_ctx_xxx()functionstobesubstituted. However,theredoesn'tappeartobeanyreasontodis-allowitfrom adriverpov.
*/ if (shared_resources_are_mine(file->f_mode)) {
IOCTL_IN(arg, data);
data = sound_set_speed(data) ;
shared_resources_initialised = 0 ; return IOCTL_OUT(arg, data);
} else return -EINVAL ; break ; /* OSS says these next 4 actions are undefined when the device is busy/active-wewilljustreturn-EINVAL. Tobeallowedtochangeone-(a)youhavetoowntheright (b)thequeue(s)mustbequiescent
*/ case SNDCTL_DSP_STEREO: if (shared_resources_are_mine(file->f_mode) &&
queues_are_quiescent()) {
IOCTL_IN(arg, data);
shared_resources_initialised = 0 ; return IOCTL_OUT(arg, sound_set_stereo(data));
} else return -EINVAL ; break ; case SOUND_PCM_WRITE_CHANNELS: if (shared_resources_are_mine(file->f_mode) &&
queues_are_quiescent()) {
IOCTL_IN(arg, data); /* the user might ask for 20 channels, we will return 1 or 2 */
shared_resources_initialised = 0 ; return IOCTL_OUT(arg, sound_set_stereo(data-1)+1);
} else return -EINVAL ; break ; case SNDCTL_DSP_SETFMT: if (shared_resources_are_mine(file->f_mode) &&
queues_are_quiescent()) { int format;
IOCTL_IN(arg, data);
shared_resources_initialised = 0 ;
format = sound_set_format(data);
result = IOCTL_OUT(arg, format); if (result < 0) return result; if (format != data && data != AFMT_QUERY) return -EINVAL; return0;
} else return -EINVAL ; case SNDCTL_DSP_SUBDIVIDE: return -EINVAL ; case SNDCTL_DSP_SETFRAGMENT: /* we can do this independently for the two queues - with the provisothatforfdsopenedO_RDWRwecannotseparatethe actionsandbothqueueswillbesetperthelastcall. NOTE:thisdoes*NOT*actuallysetthequeueup-merely registersourintentions.
*/
IOCTL_IN(arg, data);
result = 0 ;
nbufs = (data >> 16) & 0x7fff ; /* 0x7fff is 'use maximum' */
size = data & 0xffff; if (file->f_mode & FMODE_WRITE) {
result = set_queue_frags(&write_sq, nbufs, size) ; if (result) return result ;
} /* NOTE: this return value is irrelevant - OSS specifically says that thevalueis'random'andthattheuser_must_checktheactual
frags values using SNDCTL_DSP_GETBLKSIZE or similar */ return IOCTL_OUT(arg, data); case SNDCTL_DSP_GETOSPACE: /*
*/ if (file->f_mode & FMODE_WRITE) { if ( !write_sq.locked )
sq_setup(&write_sq) ;
info.fragments = write_sq.max_active - write_sq.count;
info.fragstotal = write_sq.max_active;
info.fragsize = write_sq.user_frag_size;
info.bytes = info.fragments * info.fragsize; if (copy_to_user((void __user *)arg, &info, sizeof(info))) return -EFAULT; return0;
} else return -EINVAL ; break ; case SNDCTL_DSP_GETCAPS:
val = dmasound.mach.capabilities & 0xffffff00; return IOCTL_OUT(arg,val);
/* These parameters will be restored for every clean open() *inthecaseofmultipleopen()s(e.g.dsp0&dsp1)they *willbesetsolongasthesharedresourceshavenoowner.
*/
/* we allow more space for record-enabled because there are extra output lines. thenumberheremustincludetheamountwearepreparedtogivetothelow-level driver.
*/
#define STAT_BUFF_LEN 768
/* this is how much space we will allow the low-level driver to use inthestatbuffer.Currently,2*(80characterline+<NL>). Wedonotpolicethis(itisuptothelldrivertobehonest).
*/
#define LOW_LEVEL_STAT_ALLOC 162
staticstruct { int busy; char buf[STAT_BUFF_LEN]; /* state.buf should not overflow! */ int len, ptr;
} state;
/* publish this function for use by low-level code, if required */
staticchar *get_afmt_string(int afmt)
{ switch(afmt) { case AFMT_MU_LAW: return"mu-law"; case AFMT_A_LAW: return"A-law"; case AFMT_U8: return"unsigned 8 bit"; case AFMT_S8: return"signed 8 bit"; case AFMT_S16_BE: return"signed 16 bit BE"; case AFMT_U16_BE: return"unsigned 16 bit BE"; case AFMT_S16_LE: return"signed 16 bit LE"; case AFMT_U16_LE: return"unsigned 16 bit LE"; case0: return"format not set" ; default: break ;
} return"ERROR: Unsupported AFMT_XXXX code" ;
}
staticint state_open(struct inode *inode, struct file *file)
{ char *buffer = state.buf; int len = 0; int ret;
mutex_lock(&dmasound_core_mutex);
ret = -EBUSY; if (state.busy) goto out;
ret = -ENODEV; if (!try_module_get(dmasound.mach.owner)) goto out;
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.51Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-27)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.