summaryrefslogtreecommitdiff
path: root/include/sound/core.h
blob: 9117c23e3a01b9b885eb97f18c06efd79f677347 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
#ifndef __SOUND_CORE_H
#define __SOUND_CORE_H

/*
 *  Main header file for the ALSA driver
 *  Copyright (c) 1994-2001 by Jaroslav Kysela <perex@suse.cz>
 *
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 */

#include <linux/sched.h>		/* wake_up() */
#include <asm/semaphore.h>		/* struct semaphore */
#include <linux/rwsem.h>		/* struct rw_semaphore */
#include <linux/workqueue.h>		/* struct workqueue_struct */
#include <linux/pm.h>			/* pm_message_t */

/* Typedef's */
typedef struct timespec snd_timestamp_t;
typedef struct sndrv_interval snd_interval_t;
typedef enum sndrv_card_type snd_card_type;
typedef struct sndrv_xferi snd_xferi_t;
typedef struct sndrv_xfern snd_xfern_t;
typedef struct sndrv_xferv snd_xferv_t;

/* forward declarations */
#ifdef CONFIG_PCI
struct pci_dev;
#endif
#ifdef CONFIG_SBUS
struct sbus_dev;
#endif

/* device allocation stuff */

#define SNDRV_DEV_TYPE_RANGE_SIZE		0x1000

typedef enum {
	SNDRV_DEV_TOPLEVEL =		(0*SNDRV_DEV_TYPE_RANGE_SIZE),
	SNDRV_DEV_CONTROL,
	SNDRV_DEV_LOWLEVEL_PRE,
	SNDRV_DEV_LOWLEVEL_NORMAL =	(1*SNDRV_DEV_TYPE_RANGE_SIZE),
	SNDRV_DEV_PCM,
	SNDRV_DEV_RAWMIDI,
	SNDRV_DEV_TIMER,
	SNDRV_DEV_SEQUENCER,
	SNDRV_DEV_HWDEP,
	SNDRV_DEV_INFO,
	SNDRV_DEV_BUS,
	SNDRV_DEV_CODEC,
	SNDRV_DEV_LOWLEVEL =		(2*SNDRV_DEV_TYPE_RANGE_SIZE)
} snd_device_type_t;

typedef enum {
	SNDRV_DEV_BUILD,
	SNDRV_DEV_REGISTERED,
	SNDRV_DEV_DISCONNECTED
} snd_device_state_t;

typedef enum {
	SNDRV_DEV_CMD_PRE = 0,
	SNDRV_DEV_CMD_NORMAL = 1,
	SNDRV_DEV_CMD_POST = 2
} snd_device_cmd_t;

typedef struct _snd_card snd_card_t;
typedef struct _snd_device snd_device_t;

typedef int (snd_dev_free_t)(snd_device_t *device);
typedef int (snd_dev_register_t)(snd_device_t *device);
typedef int (snd_dev_disconnect_t)(snd_device_t *device);
typedef int (snd_dev_unregister_t)(snd_device_t *device);

typedef struct {
	snd_dev_free_t *dev_free;
	snd_dev_register_t *dev_register;
	snd_dev_disconnect_t *dev_disconnect;
	snd_dev_unregister_t *dev_unregister;
} snd_device_ops_t;

struct _snd_device {
	struct list_head list;		/* list of registered devices */
	snd_card_t *card;		/* card which holds this device */
	snd_device_state_t state;	/* state of the device */
	snd_device_type_t type;		/* device type */
	void *device_data;		/* device structure */
	snd_device_ops_t *ops;		/* operations */
};

#define snd_device(n) list_entry(n, snd_device_t, list)

/* various typedefs */

typedef struct snd_info_entry snd_info_entry_t;
typedef struct _snd_pcm snd_pcm_t;
typedef struct _snd_pcm_str snd_pcm_str_t;
typedef struct _snd_pcm_substream snd_pcm_substream_t;
typedef struct _snd_mixer snd_kmixer_t;
typedef struct _snd_rawmidi snd_rawmidi_t;
typedef struct _snd_ctl_file snd_ctl_file_t;
typedef struct _snd_kcontrol snd_kcontrol_t;
typedef struct _snd_timer snd_timer_t;
typedef struct _snd_timer_instance snd_timer_instance_t;
typedef struct _snd_hwdep snd_hwdep_t;
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
typedef struct _snd_oss_mixer snd_mixer_oss_t;
#endif

/* monitor files for graceful shutdown (hotplug) */

struct snd_monitor_file {
	struct file *file;
	struct snd_monitor_file *next;
};

struct snd_shutdown_f_ops;	/* define it later */

/* main structure for soundcard */

struct _snd_card {
	int number;			/* number of soundcard (index to snd_cards) */

	char id[16];			/* id string of this card */
	char driver[16];		/* driver name */
	char shortname[32];		/* short name of this soundcard */
	char longname[80];		/* name of this soundcard */
	char mixername[80];		/* mixer name */
	char components[80];		/* card components delimited with space */

	struct module *module;		/* top-level module */

	void *private_data;		/* private data for soundcard */
	void (*private_free) (snd_card_t *card); /* callback for freeing of private data */

	struct list_head devices;	/* devices */

	unsigned int last_numid;	/* last used numeric ID */
	struct rw_semaphore controls_rwsem;	/* controls list lock */
	rwlock_t ctl_files_rwlock;	/* ctl_files list lock */
	int controls_count;		/* count of all controls */
	int user_ctl_count;		/* count of all user controls */
	struct list_head controls;	/* all controls for this card */
	struct list_head ctl_files;	/* active control files */

	snd_info_entry_t *proc_root;	/* root for soundcard specific files */
	snd_info_entry_t *proc_id;	/* the card id */
	struct proc_dir_entry *proc_root_link;	/* number link to real id */

	struct snd_monitor_file *files; /* all files associated to this card */
	struct snd_shutdown_f_ops *s_f_ops; /* file operations in the shutdown state */
	spinlock_t files_lock;		/* lock the files for this card */
	int shutdown;			/* this card is going down */
	wait_queue_head_t shutdown_sleep;
	struct work_struct free_workq;	/* for free in workqueue */
	struct device *dev;

#ifdef CONFIG_PM
	int (*pm_suspend)(snd_card_t *card, pm_message_t state);
	int (*pm_resume)(snd_card_t *card);
	void *pm_private_data;
	unsigned int power_state;	/* power state */
	struct semaphore power_lock;	/* power lock */
	wait_queue_head_t power_sleep;
#ifdef CONFIG_SND_GENERIC_PM
	struct snd_generic_device *pm_dev;	/* for ISA */
#endif
#endif

#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
	snd_mixer_oss_t *mixer_oss;
	int mixer_oss_change_count;
#endif
};

#ifdef CONFIG_PM
static inline void snd_power_lock(snd_card_t *card)
{
	down(&card->power_lock);
}

static inline void snd_power_unlock(snd_card_t *card)
{
	up(&card->power_lock);
}

int snd_power_wait(snd_card_t *card, unsigned int power_state, struct file *file);

static inline unsigned int snd_power_get_state(snd_card_t *card)
{
	return card->power_state;
}

static inline void snd_power_change_state(snd_card_t *card, unsigned int state)
{
	card->power_state = state;
	wake_up(&card->power_sleep);
}
int snd_card_set_pm_callback(snd_card_t *card,
			     int (*suspend)(snd_card_t *, pm_message_t),
			     int (*resume)(snd_card_t *),
			     void *private_data);
int snd_card_set_generic_pm_callback(snd_card_t *card,
				     int (*suspend)(snd_card_t *, pm_message_t),
				     int (*resume)(snd_card_t *),
				     void *private_data);
#define snd_card_set_isa_pm_callback(card,suspend,resume,data) \
	snd_card_set_generic_pm_callback(card, suspend, resume, data)
struct pci_dev;
int snd_card_pci_suspend(struct pci_dev *dev, pm_message_t state);
int snd_card_pci_resume(struct pci_dev *dev);
#define SND_PCI_PM_CALLBACKS \
	.suspend = snd_card_pci_suspend,  .resume = snd_card_pci_resume

#else /* ! CONFIG_PM */

#define snd_power_lock(card)		do { (void)(card); } while (0)
#define snd_power_unlock(card)		do { (void)(card); } while (0)
static inline int snd_power_wait(snd_card_t *card, unsigned int state, struct file *file) { return 0; }
#define snd_power_get_state(card)	SNDRV_CTL_POWER_D0
#define snd_power_change_state(card, state)	do { (void)(card); } while (0)
#define snd_card_set_pm_callback(card,suspend,resume,data)
#define snd_card_set_generic_pm_callback(card,suspend,resume,data)
#define snd_card_set_isa_pm_callback(card,suspend,resume,data)
#define SND_PCI_PM_CALLBACKS

#endif /* CONFIG_PM */

/* device.c */

struct _snd_minor {
	struct list_head list;		/* list of all minors per card */
	int number;			/* minor number */
	int device;			/* device number */
	const char *comment;		/* for /proc/asound/devices */
	struct file_operations *f_ops;	/* file operations */
	char name[0];			/* device name (keep at the end of structure) */
};

typedef struct _snd_minor snd_minor_t;

/* sound.c */

extern int snd_ecards_limit;

void snd_request_card(int card);

int snd_register_device(int type, snd_card_t *card, int dev, snd_minor_t *reg, const char *name);
int snd_unregister_device(int type, snd_card_t *card, int dev);

#ifdef CONFIG_SND_OSSEMUL
int snd_register_oss_device(int type, snd_card_t *card, int dev, snd_minor_t *reg, const char *name);
int snd_unregister_oss_device(int type, snd_card_t *card, int dev);
#endif

int snd_minor_info_init(void);
int snd_minor_info_done(void);

/* sound_oss.c */

#ifdef CONFIG_SND_OSSEMUL
int snd_minor_info_oss_init(void);
int snd_minor_info_oss_done(void);
int snd_oss_init_module(void);
#else
#define snd_minor_info_oss_init() /*NOP*/
#define snd_minor_info_oss_done() /*NOP*/
#define snd_oss_init_module() 0
#endif

/* memory.c */

#ifdef CONFIG_SND_DEBUG_MEMORY
void snd_memory_init(void);
void snd_memory_done(void);
int snd_memory_info_init(void);
int snd_memory_info_done(void);
void *snd_hidden_kmalloc(size_t size, int flags);
void *snd_hidden_kcalloc(size_t n, size_t size, int flags);
void snd_hidden_kfree(const void *obj);
void *snd_hidden_vmalloc(unsigned long size);
void snd_hidden_vfree(void *obj);
#define kmalloc(size, flags) snd_hidden_kmalloc(size, flags)
#define kcalloc(n, size, flags) snd_hidden_kcalloc(n, size, flags)
#define kfree(obj) snd_hidden_kfree(obj)
#define vmalloc(size) snd_hidden_vmalloc(size)
#define vfree(obj) snd_hidden_vfree(obj)
#define kmalloc_nocheck(size, flags) snd_wrapper_kmalloc(size, flags)
#define vmalloc_nocheck(size) snd_wrapper_vmalloc(size)
#define kfree_nocheck(obj) snd_wrapper_kfree(obj)
#define vfree_nocheck(obj) snd_wrapper_vfree(obj)
#else
#define snd_memory_init() /*NOP*/
#define snd_memory_done() /*NOP*/
#define snd_memory_info_init() /*NOP*/
#define snd_memory_info_done() /*NOP*/
#define kmalloc_nocheck(size, flags) kmalloc(size, flags)
#define vmalloc_nocheck(size) vmalloc(size)
#define kfree_nocheck(obj) kfree(obj)
#define vfree_nocheck(obj) vfree(obj)
#endif
char *snd_kmalloc_strdup(const char *string, int flags);
int copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size_t count);
int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size_t count);

/* init.c */

extern unsigned int snd_cards_lock;
extern snd_card_t *snd_cards[SNDRV_CARDS];
extern rwlock_t snd_card_rwlock;
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
#define SND_MIXER_OSS_NOTIFY_REGISTER	0
#define SND_MIXER_OSS_NOTIFY_DISCONNECT	1
#define SND_MIXER_OSS_NOTIFY_FREE	2
extern int (*snd_mixer_oss_notify_callback)(snd_card_t *card, int cmd);
#endif

snd_card_t *snd_card_new(int idx, const char *id,
			 struct module *module, int extra_size);
int snd_card_disconnect(snd_card_t *card);
int snd_card_free(snd_card_t *card);
int snd_card_free_in_thread(snd_card_t *card);
int snd_card_register(snd_card_t *card);
int snd_card_info_init(void);
int snd_card_info_done(void);
int snd_component_add(snd_card_t *card, const char *component);
int snd_card_file_add(snd_card_t *card, struct file *file);
int snd_card_file_remove(snd_card_t *card, struct file *file);

#ifndef snd_card_set_dev
#define snd_card_set_dev(card,devptr) ((card)->dev = (devptr))
#endif

/* device.c */

int snd_device_new(snd_card_t *card, snd_device_type_t type,
		   void *device_data, snd_device_ops_t *ops);
int snd_device_register(snd_card_t *card, void *device_data);
int snd_device_register_all(snd_card_t *card);
int snd_device_disconnect(snd_card_t *card, void *device_data);
int snd_device_disconnect_all(snd_card_t *card);
int snd_device_free(snd_card_t *card, void *device_data);
int snd_device_free_all(snd_card_t *card, snd_device_cmd_t cmd);

/* isadma.c */

#define DMA_MODE_NO_ENABLE	0x0100

void snd_dma_program(unsigned long dma, unsigned long addr, unsigned int size, unsigned short mode);
void snd_dma_disable(unsigned long dma);
unsigned int snd_dma_pointer(unsigned long dma, unsigned int size);

/* misc.c */

int snd_task_name(struct task_struct *task, char *name, size_t size);
#ifdef CONFIG_SND_VERBOSE_PRINTK
void snd_verbose_printk(const char *file, int line, const char *format, ...)
     __attribute__ ((format (printf, 3, 4)));
#endif
#if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_VERBOSE_PRINTK)
void snd_verbose_printd(const char *file, int line, const char *format, ...)
     __attribute__ ((format (printf, 3, 4)));
#endif

/* --- */

#ifdef CONFIG_SND_VERBOSE_PRINTK
/**
 * snd_printk - printk wrapper
 * @fmt: format string
 *
 * Works like print() but prints the file and the line of the caller
 * when configured with CONFIG_SND_VERBOSE_PRINTK.
 */
#define snd_printk(fmt, args...) \
	snd_verbose_printk(__FILE__, __LINE__, fmt ,##args)
#else
#define snd_printk(fmt, args...) \
	printk(fmt ,##args)
#endif

#ifdef CONFIG_SND_DEBUG

#define __ASTRING__(x) #x

#ifdef CONFIG_SND_VERBOSE_PRINTK
/**
 * snd_printd - debug printk
 * @format: format string
 *
 * Compiled only when Works like snd_printk() for debugging purpose.
 * Ignored when CONFIG_SND_DEBUG is not set.
 */
#define snd_printd(fmt, args...) \
	snd_verbose_printd(__FILE__, __LINE__, fmt ,##args)
#else
#define snd_printd(fmt, args...) \
	printk(fmt ,##args)
#endif
/**
 * snd_assert - run-time assersion macro
 * @expr: expression
 * @args...: the action
 *
 * This macro checks the expression in run-time and invokes the commands
 * given in the rest arguments if the assertion is failed.
 * When CONFIG_SND_DEBUG is not set, the expression is executed but
 * not checked.
 */
#define snd_assert(expr, args...) do {\
	if (unlikely(!(expr))) {				\
		snd_printk(KERN_ERR "BUG? (%s) (called from %p)\n", __ASTRING__(expr), __builtin_return_address(0));\
		args;\
	}\
} while (0)
/**
 * snd_runtime_check - run-time assersion macro
 * @expr: expression
 * @args...: the action
 *
 * This macro checks the expression in run-time and invokes the commands
 * given in the rest arguments if the assertion is failed.
 * Unlike snd_assert(), the action commands are executed even if
 * CONFIG_SND_DEBUG is not set but without any error messages.
 */
#define snd_runtime_check(expr, args...) do {\
	if (unlikely(!(expr))) {				\
		snd_printk(KERN_ERR "ERROR (%s) (called from %p)\n", __ASTRING__(expr), __builtin_return_address(0));\
		args;\
	}\
} while (0)

#else /* !CONFIG_SND_DEBUG */

#define snd_printd(fmt, args...)	/* nothing */
#define snd_assert(expr, args...)	(void)(expr)
#define snd_runtime_check(expr, args...) do { if (!(expr)) { args; } } while (0)

#endif /* CONFIG_SND_DEBUG */

#ifdef CONFIG_SND_DEBUG_DETECT
/**
 * snd_printdd - debug printk
 * @format: format string
 *
 * Compiled only when Works like snd_printk() for debugging purpose.
 * Ignored when CONFIG_SND_DEBUG_DETECT is not set.
 */
#define snd_printdd(format, args...) snd_printk(format, ##args)
#else
#define snd_printdd(format, args...) /* nothing */
#endif

#define snd_BUG() snd_assert(0, )


static inline void snd_timestamp_now(struct timespec *tstamp, int timespec)
{
	struct timeval val;
	/* FIXME: use a linear time source */
	do_gettimeofday(&val);
	tstamp->tv_sec = val.tv_sec;
	tstamp->tv_nsec = val.tv_usec;
	if (timespec)
		tstamp->tv_nsec *= 1000L;
}

static inline void snd_timestamp_zero(struct timespec *tstamp)
{
	tstamp->tv_sec = 0;
	tstamp->tv_nsec = 0;
}

static inline int snd_timestamp_null(struct timespec *tstamp)
{
	return tstamp->tv_sec == 0 && tstamp->tv_nsec == 0;
}

#define SNDRV_OSS_VERSION         ((3<<16)|(8<<8)|(1<<4)|(0))	/* 3.8.1a */

/* for easier backward-porting */
#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
#ifndef gameport_set_dev_parent
#define gameport_set_dev_parent(gp,xdev) ((gp)->dev.parent = (xdev))
#define gameport_set_port_data(gp,r) ((gp)->port_data = (r))
#define gameport_get_port_data(gp) (gp)->port_data
#endif
#endif

#endif /* __SOUND_CORE_H */