Linux Audio

Check our new training course

Buildroot integration, development and maintenance

Need a Buildroot system for your embedded project?
Loading...
v5.4
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * OSS compatible sequencer driver
  4 *
  5 * Timer control routines
  6 *
  7 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
  8 */
  9
 10#include "seq_oss_timer.h"
 11#include "seq_oss_event.h"
 12#include <sound/seq_oss_legacy.h>
 13#include <linux/slab.h>
 14
 15/*
 16 */
 17#define MIN_OSS_TEMPO		8
 18#define MAX_OSS_TEMPO		360
 19#define MIN_OSS_TIMEBASE	1
 20#define MAX_OSS_TIMEBASE	1000
 21
 22/*
 23 */
 24static void calc_alsa_tempo(struct seq_oss_timer *timer);
 25static int send_timer_event(struct seq_oss_devinfo *dp, int type, int value);
 26
 27
 28/*
 29 * create and register a new timer.
 30 * if queue is not started yet, start it.
 31 */
 32struct seq_oss_timer *
 33snd_seq_oss_timer_new(struct seq_oss_devinfo *dp)
 34{
 35	struct seq_oss_timer *rec;
 36
 37	rec = kzalloc(sizeof(*rec), GFP_KERNEL);
 38	if (rec == NULL)
 39		return NULL;
 40
 41	rec->dp = dp;
 42	rec->cur_tick = 0;
 43	rec->realtime = 0;
 44	rec->running = 0;
 45	rec->oss_tempo = 60;
 46	rec->oss_timebase = 100;
 47	calc_alsa_tempo(rec);
 48
 49	return rec;
 50}
 51
 52
 53/*
 54 * delete timer.
 55 * if no more timer exists, stop the queue.
 56 */
 57void
 58snd_seq_oss_timer_delete(struct seq_oss_timer *rec)
 59{
 60	if (rec) {
 61		snd_seq_oss_timer_stop(rec);
 62		kfree(rec);
 63	}
 64}
 65
 66
 67/*
 68 * process one timing event
 69 * return 1 : event proceseed -- skip this event
 70 *        0 : not a timer event -- enqueue this event
 71 */
 72int
 73snd_seq_oss_process_timer_event(struct seq_oss_timer *rec, union evrec *ev)
 74{
 75	abstime_t parm = ev->t.time;
 76
 77	if (ev->t.code == EV_TIMING) {
 78		switch (ev->t.cmd) {
 79		case TMR_WAIT_REL:
 80			parm += rec->cur_tick;
 81			rec->realtime = 0;
 82			/* fall through */
 83		case TMR_WAIT_ABS:
 84			if (parm == 0) {
 85				rec->realtime = 1;
 86			} else if (parm >= rec->cur_tick) {
 87				rec->realtime = 0;
 88				rec->cur_tick = parm;
 89			}
 90			return 1;	/* skip this event */
 91			
 92		case TMR_START:
 93			snd_seq_oss_timer_start(rec);
 94			return 1;
 95
 96		}
 97	} else if (ev->s.code == SEQ_WAIT) {
 98		/* time = from 1 to 3 bytes */
 99		parm = (ev->echo >> 8) & 0xffffff;
100		if (parm > rec->cur_tick) {
101			/* set next event time */
102			rec->cur_tick = parm;
103			rec->realtime = 0;
104		}
105		return 1;
106	}
107
108	return 0;
109}
110
111
112/*
113 * convert tempo units
114 */
115static void
116calc_alsa_tempo(struct seq_oss_timer *timer)
117{
118	timer->tempo = (60 * 1000000) / timer->oss_tempo;
119	timer->ppq = timer->oss_timebase;
120}
121
122
123/*
124 * dispatch a timer event
125 */
126static int
127send_timer_event(struct seq_oss_devinfo *dp, int type, int value)
128{
129	struct snd_seq_event ev;
130
131	memset(&ev, 0, sizeof(ev));
132	ev.type = type;
133	ev.source.client = dp->cseq;
134	ev.source.port = 0;
135	ev.dest.client = SNDRV_SEQ_CLIENT_SYSTEM;
136	ev.dest.port = SNDRV_SEQ_PORT_SYSTEM_TIMER;
137	ev.queue = dp->queue;
138	ev.data.queue.queue = dp->queue;
139	ev.data.queue.param.value = value;
140	return snd_seq_kernel_client_dispatch(dp->cseq, &ev, 1, 0);
141}
142
143/*
144 * set queue tempo and start queue
145 */
146int
147snd_seq_oss_timer_start(struct seq_oss_timer *timer)
148{
149	struct seq_oss_devinfo *dp = timer->dp;
150	struct snd_seq_queue_tempo tmprec;
151
152	if (timer->running)
153		snd_seq_oss_timer_stop(timer);
154
155	memset(&tmprec, 0, sizeof(tmprec));
156	tmprec.queue = dp->queue;
157	tmprec.ppq = timer->ppq;
158	tmprec.tempo = timer->tempo;
159	snd_seq_set_queue_tempo(dp->cseq, &tmprec);
160
161	send_timer_event(dp, SNDRV_SEQ_EVENT_START, 0);
162	timer->running = 1;
163	timer->cur_tick = 0;
164	return 0;
165}
166
167
168/*
169 * stop queue
170 */
171int
172snd_seq_oss_timer_stop(struct seq_oss_timer *timer)
173{
174	if (! timer->running)
175		return 0;
176	send_timer_event(timer->dp, SNDRV_SEQ_EVENT_STOP, 0);
177	timer->running = 0;
178	return 0;
179}
180
181
182/*
183 * continue queue
184 */
185int
186snd_seq_oss_timer_continue(struct seq_oss_timer *timer)
187{
188	if (timer->running)
189		return 0;
190	send_timer_event(timer->dp, SNDRV_SEQ_EVENT_CONTINUE, 0);
191	timer->running = 1;
192	return 0;
193}
194
195
196/*
197 * change queue tempo
198 */
199int
200snd_seq_oss_timer_tempo(struct seq_oss_timer *timer, int value)
201{
202	if (value < MIN_OSS_TEMPO)
203		value = MIN_OSS_TEMPO;
204	else if (value > MAX_OSS_TEMPO)
205		value = MAX_OSS_TEMPO;
206	timer->oss_tempo = value;
207	calc_alsa_tempo(timer);
208	if (timer->running)
209		send_timer_event(timer->dp, SNDRV_SEQ_EVENT_TEMPO, timer->tempo);
210	return 0;
211}
212
213
214/*
215 * ioctls
216 */
217int
218snd_seq_oss_timer_ioctl(struct seq_oss_timer *timer, unsigned int cmd, int __user *arg)
219{
220	int value;
221
222	if (cmd == SNDCTL_SEQ_CTRLRATE) {
223		/* if *arg == 0, just return the current rate */
224		if (get_user(value, arg))
225			return -EFAULT;
226		if (value)
227			return -EINVAL;
228		value = ((timer->oss_tempo * timer->oss_timebase) + 30) / 60;
229		return put_user(value, arg) ? -EFAULT : 0;
230	}
231
232	if (timer->dp->seq_mode == SNDRV_SEQ_OSS_MODE_SYNTH)
233		return 0;
234
235	switch (cmd) {
236	case SNDCTL_TMR_START:
237		return snd_seq_oss_timer_start(timer);
238	case SNDCTL_TMR_STOP:
239		return snd_seq_oss_timer_stop(timer);
240	case SNDCTL_TMR_CONTINUE:
241		return snd_seq_oss_timer_continue(timer);
242	case SNDCTL_TMR_TEMPO:
243		if (get_user(value, arg))
244			return -EFAULT;
245		return snd_seq_oss_timer_tempo(timer, value);
246	case SNDCTL_TMR_TIMEBASE:
247		if (get_user(value, arg))
248			return -EFAULT;
249		if (value < MIN_OSS_TIMEBASE)
250			value = MIN_OSS_TIMEBASE;
251		else if (value > MAX_OSS_TIMEBASE)
252			value = MAX_OSS_TIMEBASE;
253		timer->oss_timebase = value;
254		calc_alsa_tempo(timer);
255		return 0;
256
257	case SNDCTL_TMR_METRONOME:
258	case SNDCTL_TMR_SELECT:
259	case SNDCTL_TMR_SOURCE:
260		/* not supported */
261		return 0;
262	}
263	return 0;
264}
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * OSS compatible sequencer driver
  4 *
  5 * Timer control routines
  6 *
  7 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
  8 */
  9
 10#include "seq_oss_timer.h"
 11#include "seq_oss_event.h"
 12#include <sound/seq_oss_legacy.h>
 13#include <linux/slab.h>
 14
 15/*
 16 */
 17#define MIN_OSS_TEMPO		8
 18#define MAX_OSS_TEMPO		360
 19#define MIN_OSS_TIMEBASE	1
 20#define MAX_OSS_TIMEBASE	1000
 21
 22/*
 23 */
 24static void calc_alsa_tempo(struct seq_oss_timer *timer);
 25static int send_timer_event(struct seq_oss_devinfo *dp, int type, int value);
 26
 27
 28/*
 29 * create and register a new timer.
 30 * if queue is not started yet, start it.
 31 */
 32struct seq_oss_timer *
 33snd_seq_oss_timer_new(struct seq_oss_devinfo *dp)
 34{
 35	struct seq_oss_timer *rec;
 36
 37	rec = kzalloc(sizeof(*rec), GFP_KERNEL);
 38	if (rec == NULL)
 39		return NULL;
 40
 41	rec->dp = dp;
 42	rec->cur_tick = 0;
 43	rec->realtime = 0;
 44	rec->running = 0;
 45	rec->oss_tempo = 60;
 46	rec->oss_timebase = 100;
 47	calc_alsa_tempo(rec);
 48
 49	return rec;
 50}
 51
 52
 53/*
 54 * delete timer.
 55 * if no more timer exists, stop the queue.
 56 */
 57void
 58snd_seq_oss_timer_delete(struct seq_oss_timer *rec)
 59{
 60	if (rec) {
 61		snd_seq_oss_timer_stop(rec);
 62		kfree(rec);
 63	}
 64}
 65
 66
 67/*
 68 * process one timing event
 69 * return 1 : event proceseed -- skip this event
 70 *        0 : not a timer event -- enqueue this event
 71 */
 72int
 73snd_seq_oss_process_timer_event(struct seq_oss_timer *rec, union evrec *ev)
 74{
 75	abstime_t parm = ev->t.time;
 76
 77	if (ev->t.code == EV_TIMING) {
 78		switch (ev->t.cmd) {
 79		case TMR_WAIT_REL:
 80			parm += rec->cur_tick;
 81			rec->realtime = 0;
 82			fallthrough;
 83		case TMR_WAIT_ABS:
 84			if (parm == 0) {
 85				rec->realtime = 1;
 86			} else if (parm >= rec->cur_tick) {
 87				rec->realtime = 0;
 88				rec->cur_tick = parm;
 89			}
 90			return 1;	/* skip this event */
 91			
 92		case TMR_START:
 93			snd_seq_oss_timer_start(rec);
 94			return 1;
 95
 96		}
 97	} else if (ev->s.code == SEQ_WAIT) {
 98		/* time = from 1 to 3 bytes */
 99		parm = (ev->echo >> 8) & 0xffffff;
100		if (parm > rec->cur_tick) {
101			/* set next event time */
102			rec->cur_tick = parm;
103			rec->realtime = 0;
104		}
105		return 1;
106	}
107
108	return 0;
109}
110
111
112/*
113 * convert tempo units
114 */
115static void
116calc_alsa_tempo(struct seq_oss_timer *timer)
117{
118	timer->tempo = (60 * 1000000) / timer->oss_tempo;
119	timer->ppq = timer->oss_timebase;
120}
121
122
123/*
124 * dispatch a timer event
125 */
126static int
127send_timer_event(struct seq_oss_devinfo *dp, int type, int value)
128{
129	struct snd_seq_event ev;
130
131	memset(&ev, 0, sizeof(ev));
132	ev.type = type;
133	ev.source.client = dp->cseq;
134	ev.source.port = 0;
135	ev.dest.client = SNDRV_SEQ_CLIENT_SYSTEM;
136	ev.dest.port = SNDRV_SEQ_PORT_SYSTEM_TIMER;
137	ev.queue = dp->queue;
138	ev.data.queue.queue = dp->queue;
139	ev.data.queue.param.value = value;
140	return snd_seq_kernel_client_dispatch(dp->cseq, &ev, 1, 0);
141}
142
143/*
144 * set queue tempo and start queue
145 */
146int
147snd_seq_oss_timer_start(struct seq_oss_timer *timer)
148{
149	struct seq_oss_devinfo *dp = timer->dp;
150	struct snd_seq_queue_tempo tmprec;
151
152	if (timer->running)
153		snd_seq_oss_timer_stop(timer);
154
155	memset(&tmprec, 0, sizeof(tmprec));
156	tmprec.queue = dp->queue;
157	tmprec.ppq = timer->ppq;
158	tmprec.tempo = timer->tempo;
159	snd_seq_set_queue_tempo(dp->cseq, &tmprec);
160
161	send_timer_event(dp, SNDRV_SEQ_EVENT_START, 0);
162	timer->running = 1;
163	timer->cur_tick = 0;
164	return 0;
165}
166
167
168/*
169 * stop queue
170 */
171int
172snd_seq_oss_timer_stop(struct seq_oss_timer *timer)
173{
174	if (! timer->running)
175		return 0;
176	send_timer_event(timer->dp, SNDRV_SEQ_EVENT_STOP, 0);
177	timer->running = 0;
178	return 0;
179}
180
181
182/*
183 * continue queue
184 */
185int
186snd_seq_oss_timer_continue(struct seq_oss_timer *timer)
187{
188	if (timer->running)
189		return 0;
190	send_timer_event(timer->dp, SNDRV_SEQ_EVENT_CONTINUE, 0);
191	timer->running = 1;
192	return 0;
193}
194
195
196/*
197 * change queue tempo
198 */
199int
200snd_seq_oss_timer_tempo(struct seq_oss_timer *timer, int value)
201{
202	if (value < MIN_OSS_TEMPO)
203		value = MIN_OSS_TEMPO;
204	else if (value > MAX_OSS_TEMPO)
205		value = MAX_OSS_TEMPO;
206	timer->oss_tempo = value;
207	calc_alsa_tempo(timer);
208	if (timer->running)
209		send_timer_event(timer->dp, SNDRV_SEQ_EVENT_TEMPO, timer->tempo);
210	return 0;
211}
212
213
214/*
215 * ioctls
216 */
217int
218snd_seq_oss_timer_ioctl(struct seq_oss_timer *timer, unsigned int cmd, int __user *arg)
219{
220	int value;
221
222	if (cmd == SNDCTL_SEQ_CTRLRATE) {
223		/* if *arg == 0, just return the current rate */
224		if (get_user(value, arg))
225			return -EFAULT;
226		if (value)
227			return -EINVAL;
228		value = ((timer->oss_tempo * timer->oss_timebase) + 30) / 60;
229		return put_user(value, arg) ? -EFAULT : 0;
230	}
231
232	if (timer->dp->seq_mode == SNDRV_SEQ_OSS_MODE_SYNTH)
233		return 0;
234
235	switch (cmd) {
236	case SNDCTL_TMR_START:
237		return snd_seq_oss_timer_start(timer);
238	case SNDCTL_TMR_STOP:
239		return snd_seq_oss_timer_stop(timer);
240	case SNDCTL_TMR_CONTINUE:
241		return snd_seq_oss_timer_continue(timer);
242	case SNDCTL_TMR_TEMPO:
243		if (get_user(value, arg))
244			return -EFAULT;
245		return snd_seq_oss_timer_tempo(timer, value);
246	case SNDCTL_TMR_TIMEBASE:
247		if (get_user(value, arg))
248			return -EFAULT;
249		if (value < MIN_OSS_TIMEBASE)
250			value = MIN_OSS_TIMEBASE;
251		else if (value > MAX_OSS_TIMEBASE)
252			value = MAX_OSS_TIMEBASE;
253		timer->oss_timebase = value;
254		calc_alsa_tempo(timer);
255		return 0;
256
257	case SNDCTL_TMR_METRONOME:
258	case SNDCTL_TMR_SELECT:
259	case SNDCTL_TMR_SOURCE:
260		/* not supported */
261		return 0;
262	}
263	return 0;
264}