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

📄 seq_clientmgr.c

📁 鼎力推荐!本程序是基于嵌入式LUNUX系统开发的源程序代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * query next client */static int snd_seq_ioctl_query_next_client(client_t *client, void __user *arg){	client_t *cptr = NULL;	snd_seq_client_info_t 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(client_t *client, void __user *arg){	client_t *cptr;	client_port_t *port = NULL;	snd_seq_port_info_t 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)(client_t *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(client_t *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 int snd_seq_ioctl(struct inode *inode, struct file *file,			 unsigned int cmd, unsigned long arg){	client_t *client = (client_t *) file->private_data;	int err;	snd_assert(client != NULL, return -ENXIO);			/* FIXME: need to unlock BKL to allow preemption */	unlock_kernel();	err = snd_seq_do_ioctl(client, cmd, (void __user *) arg);	lock_kernel();	return err;}/* -------------------------------------------------------- *//* exported to kernel modules */int snd_seq_create_kernel_client(snd_card_t *card, int client_index, snd_seq_client_callback_t * callback){	client_t *client;	snd_assert(! in_interrupt(), return -EBUSY);	if (callback == NULL)		return -EINVAL;	if (card && client_index > 7)		return -EINVAL;	if (card == NULL && client_index > 63)		return -EINVAL;	if (card)		client_index += 64 + (card->number << 3);	if (down_interruptible(&register_mutex))		return -ERESTARTSYS;	/* empty write queue as default */	client = seq_create_client1(client_index, 0);	if (client == NULL) {		up(&register_mutex);		return -EBUSY;	/* failure code */	}	usage_alloc(&client_usage, 1);	client->accept_input = callback->allow_output;	client->accept_output = callback->allow_input;			/* fill client data */	client->data.kernel.card = card;	client->data.kernel.private_data = callback->private_data;	sprintf(client->name, "Client-%d", client->number);	client->type = KERNEL_CLIENT;	up(&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){	client_t *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, snd_seq_event_t *ev,				 struct file *file, int blocking,				 int atomic, int hop){	client_t *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, snd_seq_event_t * 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, snd_seq_event_t * 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, snd_seq_event_t * ev,				   int atomic, int hop){	client_t *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){	client_t *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, 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){	client_t *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;}/*---------------------------------------------------------------------------*//* *  /proc interface */static void snd_seq_info_dump_subscribers(snd_info_buffer_t *buffer, port_subs_info_t *group, int is_src, char *msg){	struct list_head *p;	subscribers_t *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, subscribers_t, src_list);		else			s = list_entry(p, subscribers_t, 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(snd_info_buffer_t *buffer, client_t *client){	struct list_head *l;	down(&client->ports_mutex);	list_for_each(l, &client->ports_list_head) {		client_port_t *p = list_entry(l, client_port_t, 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: ");	}	up(&client->ports_mutex);}/* exported to seq_info.c */void snd_seq_info_clients_read(snd_info_entry_t *entry, 			       snd_info_buffer_t * buffer){	extern void snd_seq_info_pool(snd_info_buffer_t * buffer, pool_t * pool, char *space);	int c;	client_t *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 the client table */	for (c = 0; c < SNDRV_SEQ_MAX_CLIENTS; c++) {		client = snd_seq_client_use_ptr(c);		if (client == NULL)			continue;		if (client->type == NO_CLIENT) {			snd_seq_client_unlock(client);			continue;		}		snd_iprintf(buffer, "Client %3d : \"%s\" [%s]\n",			    c, client->name,			    client->type == USER_CLIENT ? "User" : "Kernel");		snd_seq_info_dump_ports(buffer, client);		if (snd_seq_write_pool_allocated(client)) {			snd_iprintf(buffer, "  Output pool :\n");			snd_seq_info_pool(buffer, client->pool, "    ");		}		if (client->type == USER_CLIENT && client->data.user.fifo &&		    client->data.user.fifo->pool) {			snd_iprintf(buffer, "  Input pool :\n");			snd_seq_info_pool(buffer, client->data.user.fifo->pool, "    ");		}		snd_seq_client_unlock(client);	}}/*---------------------------------------------------------------------------*//* *  REGISTRATION PART */static struct file_operations snd_seq_f_ops ={	.owner =	THIS_MODULE,	.read =		snd_seq_read,	.write =	snd_seq_write,	.open =		snd_seq_open,	.release =	snd_seq_release,	.poll =		snd_seq_poll,	.ioctl =	snd_seq_ioctl,};static snd_minor_t snd_seq_reg ={	.comment =	"sequencer",	.f_ops =	&snd_seq_f_ops,};/*  * register sequencer device  */int __init snd_sequencer_device_init(void){	int err;	if (down_interruptible(&register_mutex))		return -ERESTARTSYS;	if ((err = snd_register_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0, &snd_seq_reg, "seq")) < 0) {		up(&register_mutex);		return err;	}		up(&register_mutex);	return 0;}/*  * unregister sequencer device  */void __exit snd_sequencer_device_done(void){	snd_unregister_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0);}

⌨️ 快捷键说明

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