⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 seq_clientmgr.c

📁 LINUX 2.6.17.4的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
 */static int snd_seq_ioctl_query_subs(struct snd_seq_client *client,				    void __user *arg){	int result = -ENXIO;	struct snd_seq_client *cptr = NULL;	struct snd_seq_client_port *port = NULL;	struct snd_seq_query_subs subs;	struct snd_seq_port_subs_info *group;	struct list_head *p;	int i;	if (copy_from_user(&subs, arg, sizeof(subs)))		return -EFAULT;	if ((cptr = snd_seq_client_use_ptr(subs.root.client)) == NULL)		goto __end;	if ((port = snd_seq_port_use_ptr(cptr, subs.root.port)) == NULL)		goto __end;	switch (subs.type) {	case SNDRV_SEQ_QUERY_SUBS_READ:		group = &port->c_src;		break;	case SNDRV_SEQ_QUERY_SUBS_WRITE:		group = &port->c_dest;		break;	default:		goto __end;	}	down_read(&group->list_mutex);	/* search for the subscriber */	subs.num_subs = group->count;	i = 0;	result = -ENOENT;	list_for_each(p, &group->list_head) {		if (i++ == subs.index) {			/* found! */			struct snd_seq_subscribers *s;			if (subs.type == SNDRV_SEQ_QUERY_SUBS_READ) {				s = list_entry(p, struct snd_seq_subscribers, src_list);				subs.addr = s->info.dest;			} else {				s = list_entry(p, struct snd_seq_subscribers, dest_list);				subs.addr = s->info.sender;			}			subs.flags = s->info.flags;			subs.queue = s->info.queue;			result = 0;			break;		}	}	up_read(&group->list_mutex);      __end:   	if (port)		snd_seq_port_unlock(port);	if (cptr)		snd_seq_client_unlock(cptr);	if (result >= 0) {		if (copy_to_user(arg, &subs, sizeof(subs)))			return -EFAULT;	}	return result;}/* * query next client */static int snd_seq_ioctl_query_next_client(struct snd_seq_client *client,					   void __user *arg){	struct snd_seq_client *cptr = NULL;	struct snd_seq_client_info info;	if (copy_from_user(&info, arg, sizeof(info)))		return -EFAULT;	/* search for next client */	info.client++;	if (info.client < 0)		info.client = 0;	for (; info.client < SNDRV_SEQ_MAX_CLIENTS; info.client++) {		cptr = snd_seq_client_use_ptr(info.client);		if (cptr)			break; /* found */	}	if (cptr == NULL)		return -ENOENT;	get_client_info(cptr, &info);	snd_seq_client_unlock(cptr);	if (copy_to_user(arg, &info, sizeof(info)))		return -EFAULT;	return 0;}/*  * query next port */static int snd_seq_ioctl_query_next_port(struct snd_seq_client *client,					 void __user *arg){	struct snd_seq_client *cptr;	struct snd_seq_client_port *port = NULL;	struct snd_seq_port_info info;	if (copy_from_user(&info, arg, sizeof(info)))		return -EFAULT;	cptr = snd_seq_client_use_ptr(info.addr.client);	if (cptr == NULL)		return -ENXIO;	/* search for next port */	info.addr.port++;	port = snd_seq_port_query_nearest(cptr, &info);	if (port == NULL) {		snd_seq_client_unlock(cptr);		return -ENOENT;	}	/* get port info */	info.addr = port->addr;	snd_seq_get_port_info(port, &info);	snd_seq_port_unlock(port);	snd_seq_client_unlock(cptr);	if (copy_to_user(arg, &info, sizeof(info)))		return -EFAULT;	return 0;}/* -------------------------------------------------------- */static struct seq_ioctl_table {	unsigned int cmd;	int (*func)(struct snd_seq_client *client, void __user * arg);} ioctl_tables[] = {	{ SNDRV_SEQ_IOCTL_SYSTEM_INFO, snd_seq_ioctl_system_info },	{ SNDRV_SEQ_IOCTL_RUNNING_MODE, snd_seq_ioctl_running_mode },	{ SNDRV_SEQ_IOCTL_GET_CLIENT_INFO, snd_seq_ioctl_get_client_info },	{ SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, snd_seq_ioctl_set_client_info },	{ SNDRV_SEQ_IOCTL_CREATE_PORT, snd_seq_ioctl_create_port },	{ SNDRV_SEQ_IOCTL_DELETE_PORT, snd_seq_ioctl_delete_port },	{ SNDRV_SEQ_IOCTL_GET_PORT_INFO, snd_seq_ioctl_get_port_info },	{ SNDRV_SEQ_IOCTL_SET_PORT_INFO, snd_seq_ioctl_set_port_info },	{ SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, snd_seq_ioctl_subscribe_port },	{ SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT, snd_seq_ioctl_unsubscribe_port },	{ SNDRV_SEQ_IOCTL_CREATE_QUEUE, snd_seq_ioctl_create_queue },	{ SNDRV_SEQ_IOCTL_DELETE_QUEUE, snd_seq_ioctl_delete_queue },	{ SNDRV_SEQ_IOCTL_GET_QUEUE_INFO, snd_seq_ioctl_get_queue_info },	{ SNDRV_SEQ_IOCTL_SET_QUEUE_INFO, snd_seq_ioctl_set_queue_info },	{ SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE, snd_seq_ioctl_get_named_queue },	{ SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS, snd_seq_ioctl_get_queue_status },	{ SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO, snd_seq_ioctl_get_queue_tempo },	{ SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO, snd_seq_ioctl_set_queue_tempo },	{ SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER, snd_seq_ioctl_get_queue_timer },	{ SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER, snd_seq_ioctl_set_queue_timer },	{ SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT, snd_seq_ioctl_get_queue_client },	{ SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT, snd_seq_ioctl_set_queue_client },	{ SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, snd_seq_ioctl_get_client_pool },	{ SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, snd_seq_ioctl_set_client_pool },	{ SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION, snd_seq_ioctl_get_subscription },	{ SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT, snd_seq_ioctl_query_next_client },	{ SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, snd_seq_ioctl_query_next_port },	{ SNDRV_SEQ_IOCTL_REMOVE_EVENTS, snd_seq_ioctl_remove_events },	{ SNDRV_SEQ_IOCTL_QUERY_SUBS, snd_seq_ioctl_query_subs },	{ 0, NULL },};static int snd_seq_do_ioctl(struct snd_seq_client *client, unsigned int cmd,			    void __user *arg){	struct seq_ioctl_table *p;	switch (cmd) {	case SNDRV_SEQ_IOCTL_PVERSION:		/* return sequencer version number */		return put_user(SNDRV_SEQ_VERSION, (int __user *)arg) ? -EFAULT : 0;	case SNDRV_SEQ_IOCTL_CLIENT_ID:		/* return the id of this client */		return put_user(client->number, (int __user *)arg) ? -EFAULT : 0;	}	if (! arg)		return -EFAULT;	for (p = ioctl_tables; p->cmd; p++) {		if (p->cmd == cmd)			return p->func(client, arg);	}	snd_printd("seq unknown ioctl() 0x%x (type='%c', number=0x%2x)\n",		   cmd, _IOC_TYPE(cmd), _IOC_NR(cmd));	return -ENOTTY;}static long snd_seq_ioctl(struct file *file, unsigned int cmd, unsigned long arg){	struct snd_seq_client *client = file->private_data;	snd_assert(client != NULL, return -ENXIO);			return snd_seq_do_ioctl(client, cmd, (void __user *) arg);}#ifdef CONFIG_COMPAT#include "seq_compat.c"#else#define snd_seq_ioctl_compat	NULL#endif/* -------------------------------------------------------- *//* exported to kernel modules */int snd_seq_create_kernel_client(struct snd_card *card, int client_index,				 const char *name_fmt, ...){	struct snd_seq_client *client;	va_list args;	snd_assert(! in_interrupt(), return -EBUSY);	if (card && client_index >= SNDRV_SEQ_CLIENTS_PER_CARD)		return -EINVAL;	if (card == NULL && client_index >= SNDRV_SEQ_GLOBAL_CLIENTS)		return -EINVAL;	if (mutex_lock_interruptible(&register_mutex))		return -ERESTARTSYS;	if (card) {		client_index += SNDRV_SEQ_GLOBAL_CLIENTS			+ card->number * SNDRV_SEQ_CLIENTS_PER_CARD;		if (client_index >= SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN)			client_index = -1;	}	/* empty write queue as default */	client = seq_create_client1(client_index, 0);	if (client == NULL) {		mutex_unlock(&register_mutex);		return -EBUSY;	/* failure code */	}	usage_alloc(&client_usage, 1);	client->accept_input = 1;	client->accept_output = 1;			va_start(args, name_fmt);	vsnprintf(client->name, sizeof(client->name), name_fmt, args);	va_end(args);	client->type = KERNEL_CLIENT;	mutex_unlock(&register_mutex);	/* make others aware this new client */	snd_seq_system_client_ev_client_start(client->number);		/* return client number to caller */	return client->number;}/* exported to kernel modules */int snd_seq_delete_kernel_client(int client){	struct snd_seq_client *ptr;	snd_assert(! in_interrupt(), return -EBUSY);	ptr = clientptr(client);	if (ptr == NULL)		return -EINVAL;	seq_free_client(ptr);	kfree(ptr);	return 0;}/* skeleton to enqueue event, called from snd_seq_kernel_client_enqueue * and snd_seq_kernel_client_enqueue_blocking */static int kernel_client_enqueue(int client, struct snd_seq_event *ev,				 struct file *file, int blocking,				 int atomic, int hop){	struct snd_seq_client *cptr;	int result;	snd_assert(ev != NULL, return -EINVAL);	if (ev->type == SNDRV_SEQ_EVENT_NONE)		return 0; /* ignore this */	if (ev->type == SNDRV_SEQ_EVENT_KERNEL_ERROR)		return -EINVAL; /* quoted events can't be enqueued */	/* fill in client number */	ev->source.client = client;	if (check_event_type_and_length(ev))		return -EINVAL;	cptr = snd_seq_client_use_ptr(client);	if (cptr == NULL)		return -EINVAL;		if (! cptr->accept_output)		result = -EPERM;	else /* send it */		result = snd_seq_client_enqueue_event(cptr, ev, file, blocking, atomic, hop);	snd_seq_client_unlock(cptr);	return result;}/* * exported, called by kernel clients to enqueue events (w/o blocking) * * RETURN VALUE: zero if succeed, negative if error */int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event * ev,				  int atomic, int hop){	return kernel_client_enqueue(client, ev, NULL, 0, atomic, hop);}/* * exported, called by kernel clients to enqueue events (with blocking) * * RETURN VALUE: zero if succeed, negative if error */int snd_seq_kernel_client_enqueue_blocking(int client, struct snd_seq_event * ev,					   struct file *file,					   int atomic, int hop){	return kernel_client_enqueue(client, ev, file, 1, atomic, hop);}/*  * exported, called by kernel clients to dispatch events directly to other * clients, bypassing the queues.  Event time-stamp will be updated. * * RETURN VALUE: negative = delivery failed, *		 zero, or positive: the number of delivered events */int snd_seq_kernel_client_dispatch(int client, struct snd_seq_event * ev,				   int atomic, int hop){	struct snd_seq_client *cptr;	int result;	snd_assert(ev != NULL, return -EINVAL);	/* fill in client number */	ev->queue = SNDRV_SEQ_QUEUE_DIRECT;	ev->source.client = client;	if (check_event_type_and_length(ev))		return -EINVAL;	cptr = snd_seq_client_use_ptr(client);	if (cptr == NULL)		return -EINVAL;	if (!cptr->accept_output)		result = -EPERM;	else		result = snd_seq_deliver_event(cptr, ev, atomic, hop);	snd_seq_client_unlock(cptr);	return result;}/* * exported, called by kernel clients to perform same functions as with * userland ioctl()  */int snd_seq_kernel_client_ctl(int clientid, unsigned int cmd, void *arg){	struct snd_seq_client *client;	mm_segment_t fs;	int result;	client = clientptr(clientid);	if (client == NULL)		return -ENXIO;	fs = snd_enter_user();	result = snd_seq_do_ioctl(client, cmd, (void __user *)arg);	snd_leave_user(fs);	return result;}/* exported (for OSS emulator) */int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table *wait){	struct snd_seq_client *client;	client = clientptr(clientid);	if (client == NULL)		return -ENXIO;	if (! snd_seq_write_pool_allocated(client))		return 1;	if (snd_seq_pool_poll_wait(client->pool, file, wait))		return 1;	return 0;}/*---------------------------------------------------------------------------*/#ifdef CONFIG_PROC_FS/* *  /proc interface */static void snd_seq_info_dump_subscribers(struct snd_info_buffer *buffer,					  struct snd_seq_port_subs_info *group,					  int is_src, char *msg){	struct list_head *p;	struct snd_seq_subscribers *s;	int count = 0;	down_read(&group->list_mutex);	if (list_empty(&group->list_head)) {		up_read(&group->list_mutex);		return;	}	snd_iprintf(buffer, msg);	list_for_each(p, &group->list_head) {		if (is_src)			s = list_entry(p, struct snd_seq_subscribers, src_list);		else			s = list_entry(p, struct snd_seq_subscribers, dest_list);		if (count++)			snd_iprintf(buffer, ", ");		snd_iprintf(buffer, "%d:%d",			    is_src ? s->info.dest.client : s->info.sender.client,			    is_src ? s->info.dest.port : s->info.sender.port);		if (s->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP)			snd_iprintf(buffer, "[%c:%d]", ((s->info.flags & SNDRV_SEQ_PORT_SUBS_TIME_REAL) ? 'r' : 't'), s->info.queue);		if (group->exclusive)			snd_iprintf(buffer, "[ex]");	}	up_read(&group->list_mutex);	snd_iprintf(buffer, "\n");}#define FLAG_PERM_RD(perm) ((perm) & SNDRV_SEQ_PORT_CAP_READ ? ((perm) & SNDRV_SEQ_PORT_CAP_SUBS_READ ? 'R' : 'r') : '-')#define FLAG_PERM_WR(perm) ((perm) & SNDRV_SEQ_PORT_CAP_WRITE ? ((perm) & SNDRV_SEQ_PORT_CAP_SUBS_WRITE ? 'W' : 'w') : '-')#define FLAG_PERM_EX(perm) ((perm) & SNDRV_SEQ_PORT_CAP_NO_EXPORT ? '-' : 'e')#define FLAG_PERM_DUPLEX(perm) ((perm) & SNDRV_SEQ_PORT_CAP_DUPLEX ? 'X' : '-')static void snd_seq_info_dump_ports(struct snd_info_buffer *buffer,				    struct snd_seq_client *client){	struct list_head *l;	mutex_lock(&client->ports_mutex);	list_for_each(l, &client->ports_list_head) {		struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list);		snd_iprintf(buffer, "  Port %3d : \"%s\" (%c%c%c%c)\n",			    p->addr.port, p->name,			    FLAG_PERM_RD(p->capability),			    FLAG_PERM_WR(p->capability),			    FLAG_PERM_EX(p->capability),			    FLAG_PERM_DUPLEX(p->capability));		snd_seq_info_dump_subscribers(buffer, &p->c_src, 1, "    Connecting To: ");		snd_seq_info_dump_subscribers(buffer, &p->c_dest, 0, "    Connected From: ");	}	mutex_unlock(&client->ports_mutex);}void snd_seq_info_pool(struct snd_info_buffer *buffer,		       struct snd_seq_pool *pool, char *space);/* exported to seq_info.c */void snd_seq_info_clients_read(struct snd_info_entry *entry, 			       struct snd_info_buffer *buffer){	int c;	struct snd_seq_client *client;	snd_iprintf(buffer, "Client info\n");	snd_iprintf(buffer, "  cur  clients : %d\n", client_usage.cur);	snd_iprintf(buffer, "  peak clients : %d\n", client_usage.peak);	snd_iprintf(buffer, "  max  clients : %d\n", SNDRV_SEQ_MAX_CLIENTS);	snd_iprintf(buffer, "\n");	/* list t

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -