📄 timer.c
字号:
.stop = snd_timer_s_stop};static void snd_timer_free_system(struct snd_timer *timer){ kfree(timer->private_data);}static int snd_timer_register_system(void){ struct snd_timer *timer; struct snd_timer_system_private *priv; int err; err = snd_timer_global_new("system", SNDRV_TIMER_GLOBAL_SYSTEM, &timer); if (err < 0) return err; strcpy(timer->name, "system timer"); timer->hw = snd_timer_system; priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (priv == NULL) { snd_timer_free(timer); return -ENOMEM; } init_timer(&priv->tlist); priv->tlist.function = snd_timer_s_function; priv->tlist.data = (unsigned long) timer; timer->private_data = priv; timer->private_free = snd_timer_free_system; return snd_timer_global_register(timer);}#ifdef CONFIG_PROC_FS/* * Info interface */static void snd_timer_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer){ struct snd_timer *timer; struct snd_timer_instance *ti; mutex_lock(®ister_mutex); list_for_each_entry(timer, &snd_timer_list, device_list) { switch (timer->tmr_class) { case SNDRV_TIMER_CLASS_GLOBAL: snd_iprintf(buffer, "G%i: ", timer->tmr_device); break; case SNDRV_TIMER_CLASS_CARD: snd_iprintf(buffer, "C%i-%i: ", timer->card->number, timer->tmr_device); break; case SNDRV_TIMER_CLASS_PCM: snd_iprintf(buffer, "P%i-%i-%i: ", timer->card->number, timer->tmr_device, timer->tmr_subdevice); break; default: snd_iprintf(buffer, "?%i-%i-%i-%i: ", timer->tmr_class, timer->card ? timer->card->number : -1, timer->tmr_device, timer->tmr_subdevice); } snd_iprintf(buffer, "%s :", timer->name); if (timer->hw.resolution) snd_iprintf(buffer, " %lu.%03luus (%lu ticks)", timer->hw.resolution / 1000, timer->hw.resolution % 1000, timer->hw.ticks); if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) snd_iprintf(buffer, " SLAVE"); snd_iprintf(buffer, "\n"); list_for_each_entry(ti, &timer->open_list_head, open_list) snd_iprintf(buffer, " Client %s : %s\n", ti->owner ? ti->owner : "unknown", ti->flags & (SNDRV_TIMER_IFLG_START | SNDRV_TIMER_IFLG_RUNNING) ? "running" : "stopped"); } mutex_unlock(®ister_mutex);}static struct snd_info_entry *snd_timer_proc_entry;static void __init snd_timer_proc_init(void){ struct snd_info_entry *entry; entry = snd_info_create_module_entry(THIS_MODULE, "timers", NULL); if (entry != NULL) { entry->c.text.read = snd_timer_proc_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); entry = NULL; } } snd_timer_proc_entry = entry;}static void __exit snd_timer_proc_done(void){ snd_info_free_entry(snd_timer_proc_entry);}#else /* !CONFIG_PROC_FS */#define snd_timer_proc_init()#define snd_timer_proc_done()#endif/* * USER SPACE interface */static void snd_timer_user_interrupt(struct snd_timer_instance *timeri, unsigned long resolution, unsigned long ticks){ struct snd_timer_user *tu = timeri->callback_data; struct snd_timer_read *r; int prev; spin_lock(&tu->qlock); if (tu->qused > 0) { prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1; r = &tu->queue[prev]; if (r->resolution == resolution) { r->ticks += ticks; goto __wake; } } if (tu->qused >= tu->queue_size) { tu->overrun++; } else { r = &tu->queue[tu->qtail++]; tu->qtail %= tu->queue_size; r->resolution = resolution; r->ticks = ticks; tu->qused++; } __wake: spin_unlock(&tu->qlock); kill_fasync(&tu->fasync, SIGIO, POLL_IN); wake_up(&tu->qchange_sleep);}static void snd_timer_user_append_to_tqueue(struct snd_timer_user *tu, struct snd_timer_tread *tread){ if (tu->qused >= tu->queue_size) { tu->overrun++; } else { memcpy(&tu->tqueue[tu->qtail++], tread, sizeof(*tread)); tu->qtail %= tu->queue_size; tu->qused++; }}static void snd_timer_user_ccallback(struct snd_timer_instance *timeri, int event, struct timespec *tstamp, unsigned long resolution){ struct snd_timer_user *tu = timeri->callback_data; struct snd_timer_tread r1; if (event >= SNDRV_TIMER_EVENT_START && event <= SNDRV_TIMER_EVENT_PAUSE) tu->tstamp = *tstamp; if ((tu->filter & (1 << event)) == 0 || !tu->tread) return; r1.event = event; r1.tstamp = *tstamp; r1.val = resolution; spin_lock(&tu->qlock); snd_timer_user_append_to_tqueue(tu, &r1); spin_unlock(&tu->qlock); kill_fasync(&tu->fasync, SIGIO, POLL_IN); wake_up(&tu->qchange_sleep);}static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri, unsigned long resolution, unsigned long ticks){ struct snd_timer_user *tu = timeri->callback_data; struct snd_timer_tread *r, r1; struct timespec tstamp; int prev, append = 0; memset(&tstamp, 0, sizeof(tstamp)); spin_lock(&tu->qlock); if ((tu->filter & ((1 << SNDRV_TIMER_EVENT_RESOLUTION) | (1 << SNDRV_TIMER_EVENT_TICK))) == 0) { spin_unlock(&tu->qlock); return; } if (tu->last_resolution != resolution || ticks > 0) getnstimeofday(&tstamp); if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) && tu->last_resolution != resolution) { r1.event = SNDRV_TIMER_EVENT_RESOLUTION; r1.tstamp = tstamp; r1.val = resolution; snd_timer_user_append_to_tqueue(tu, &r1); tu->last_resolution = resolution; append++; } if ((tu->filter & (1 << SNDRV_TIMER_EVENT_TICK)) == 0) goto __wake; if (ticks == 0) goto __wake; if (tu->qused > 0) { prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1; r = &tu->tqueue[prev]; if (r->event == SNDRV_TIMER_EVENT_TICK) { r->tstamp = tstamp; r->val += ticks; append++; goto __wake; } } r1.event = SNDRV_TIMER_EVENT_TICK; r1.tstamp = tstamp; r1.val = ticks; snd_timer_user_append_to_tqueue(tu, &r1); append++; __wake: spin_unlock(&tu->qlock); if (append == 0) return; kill_fasync(&tu->fasync, SIGIO, POLL_IN); wake_up(&tu->qchange_sleep);}static int snd_timer_user_open(struct inode *inode, struct file *file){ struct snd_timer_user *tu; tu = kzalloc(sizeof(*tu), GFP_KERNEL); if (tu == NULL) return -ENOMEM; spin_lock_init(&tu->qlock); init_waitqueue_head(&tu->qchange_sleep); mutex_init(&tu->tread_sem); tu->ticks = 1; tu->queue_size = 128; tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read), GFP_KERNEL); if (tu->queue == NULL) { kfree(tu); return -ENOMEM; } file->private_data = tu; return 0;}static int snd_timer_user_release(struct inode *inode, struct file *file){ struct snd_timer_user *tu; if (file->private_data) { tu = file->private_data; file->private_data = NULL; fasync_helper(-1, file, 0, &tu->fasync); if (tu->timeri) snd_timer_close(tu->timeri); kfree(tu->queue); kfree(tu->tqueue); kfree(tu); } return 0;}static void snd_timer_user_zero_id(struct snd_timer_id *id){ id->dev_class = SNDRV_TIMER_CLASS_NONE; id->dev_sclass = SNDRV_TIMER_SCLASS_NONE; id->card = -1; id->device = -1; id->subdevice = -1;}static void snd_timer_user_copy_id(struct snd_timer_id *id, struct snd_timer *timer){ id->dev_class = timer->tmr_class; id->dev_sclass = SNDRV_TIMER_SCLASS_NONE; id->card = timer->card ? timer->card->number : -1; id->device = timer->tmr_device; id->subdevice = timer->tmr_subdevice;}static int snd_timer_user_next_device(struct snd_timer_id __user *_tid){ struct snd_timer_id id; struct snd_timer *timer; struct list_head *p; if (copy_from_user(&id, _tid, sizeof(id))) return -EFAULT; mutex_lock(®ister_mutex); if (id.dev_class < 0) { /* first item */ if (list_empty(&snd_timer_list)) snd_timer_user_zero_id(&id); else { timer = list_entry(snd_timer_list.next, struct snd_timer, device_list); snd_timer_user_copy_id(&id, timer); } } else { switch (id.dev_class) { case SNDRV_TIMER_CLASS_GLOBAL: id.device = id.device < 0 ? 0 : id.device + 1; list_for_each(p, &snd_timer_list) { timer = list_entry(p, struct snd_timer, device_list); if (timer->tmr_class > SNDRV_TIMER_CLASS_GLOBAL) { snd_timer_user_copy_id(&id, timer); break; } if (timer->tmr_device >= id.device) { snd_timer_user_copy_id(&id, timer); break; } } if (p == &snd_timer_list) snd_timer_user_zero_id(&id); break; case SNDRV_TIMER_CLASS_CARD: case SNDRV_TIMER_CLASS_PCM: if (id.card < 0) { id.card = 0; } else { if (id.card < 0) { id.card = 0; } else { if (id.device < 0) { id.device = 0; } else { if (id.subdevice < 0) { id.subdevice = 0; } else { id.subdevice++; } } } } list_for_each(p, &snd_timer_list) { timer = list_entry(p, struct snd_timer, device_list); if (timer->tmr_class > id.dev_class) { snd_timer_user_copy_id(&id, timer); break; } if (timer->tmr_class < id.dev_class) continue; if (timer->card->number > id.card) { snd_timer_user_copy_id(&id, timer); break; } if (timer->card->number < id.card) continue; if (timer->tmr_device > id.device) { snd_timer_user_copy_id(&id, timer); break; } if (timer->tmr_device < id.device) continue; if (timer->tmr_subdevice > id.subdevice) { snd_timer_user_copy_id(&id, timer); break; } if (timer->tmr_subdevice < id.subdevice) continue; snd_timer_user_copy_id(&id, timer); break; } if (p == &snd_timer_list) snd_timer_user_zero_id(&id); break; default: snd_timer_user_zero_id(&id); } } mutex_unlock(®ister_mutex); if (copy_to_user(_tid, &id, sizeof(*_tid))) return -EFAULT; return 0;}static int snd_timer_user_ginfo(struct file *file, struct snd_timer_ginfo __user *_ginfo){ struct snd_timer_ginfo *ginfo; struct snd_timer_id tid; struct snd_timer *t; struct list_head *p; int err = 0; ginfo = kmalloc(sizeof(*ginfo), GFP_KERNEL); if (! ginfo) return -ENOMEM; if (copy_from_user(ginfo, _ginfo, sizeof(*ginfo))) { kfree(ginfo); return -EFAULT; } tid = ginfo->tid; memset(ginfo, 0, sizeof(*ginfo)); ginfo->tid = tid; mutex_lock(®ister_mutex); t = snd_timer_find(&tid); if (t != NULL) { ginfo->card = t->card ? t->card->number : -1; if (t->hw.flags & SNDRV_TIMER_HW_SLAVE) ginfo->flags |= SNDRV_TIMER_FLG_SLAVE; strlcpy(ginfo->id, t->id, sizeof(ginfo->id)); strlcpy(ginfo->name, t->name, sizeof(ginfo->name)); ginfo->resolution = t->hw.resolution; if (t->hw.resolution_min > 0) { ginfo->resolution_min = t->hw.resolution_min; ginfo->resolution_max = t->hw.resolution_max; } list_for_each(p, &t->open_list_head) { ginfo->clients++; } } else { err = -ENODEV; } mutex_unlock(®ister_mutex); if (err >= 0 && copy_to_user(_ginfo, ginfo, sizeof(*ginfo))) err = -EFAULT; kfree(ginfo); return err;}static int snd_timer_user_gparams(struct file *file, struct snd_timer_gparams __user *_gparams){ struct snd_timer_gparams gparams; struct snd_timer *t; int err; if (copy_from_user(&gparams, _gparams, sizeof(gparams))) return -EFAULT; mutex_lock(®ister_mutex); t = snd_timer_find(&gparams.tid); if (!t) { err = -ENODEV; goto _error; } if (!list_empty(&t->open_list_head)) { err = -EBUSY; goto _error; } if (!t->hw.set_period) { err = -ENOSYS; goto _error; } err = t->hw.set_period(t, gparams.period_num, gparams.period_den);_error: mutex_unlock(®ister_mutex); return err;}static int snd_timer_user_gstatus(struct file *file, struct snd_timer_gstatus __user *_gstatus){ struct snd_timer_gstatus gstatus; struct snd_timer_id tid; struct snd_timer *t; int err = 0; if (copy_from_user(&gstatus, _gstatus, sizeof(gstatus))) return -EFAULT; tid = gstatus.tid; memset(&gstatus, 0, sizeof(gstatus)); gstatus.tid = tid; mutex_lock(®ister_mutex); t = snd_timer_find(&tid); if (t != NULL) { if (t->hw.c_resolution) gstatus.resolution = t->hw.c_resolution(t); else gstatus.resolution = t->hw.resolution; if (t->hw.precise_resolution) { t->hw.precise_resolution(t, &gstatus.resolution_num, &gstatus.resolution_den); } else { gstatus.resolution_num = gstatus.resolution; gstatus.resolution_den = 1000000000uL; } } else { err = -ENODEV; } mutex_unlock(®ister_mutex); if (err >= 0 && copy_to_user(_gstatus, &gstatus, sizeof(gstatus))) err = -EFAULT; return err;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -