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

📄 seq_clientmgr.c

📁 鼎力推荐!本程序是基于嵌入式LUNUX系统开发的源程序代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	    ! client->accept_input)		return 0; /* ignored */	/* set up quoted error */	memset(&bounce_ev, 0, sizeof(bounce_ev));	bounce_ev.type = SNDRV_SEQ_EVENT_KERNEL_ERROR;	bounce_ev.flags = SNDRV_SEQ_EVENT_LENGTH_FIXED;	bounce_ev.queue = SNDRV_SEQ_QUEUE_DIRECT;	bounce_ev.source.client = SNDRV_SEQ_CLIENT_SYSTEM;	bounce_ev.source.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;	bounce_ev.dest.client = client->number;	bounce_ev.dest.port = event->source.port;	bounce_ev.data.quote.origin = event->dest;	bounce_ev.data.quote.event = event;	bounce_ev.data.quote.value = -err; /* use positive value */	result = snd_seq_deliver_single_event(NULL, &bounce_ev, 0, atomic, hop + 1);	if (result < 0) {		client->event_lost++;		return result;	}	return result;}/* * rewrite the time-stamp of the event record with the curren time * of the given queue. * return non-zero if updated. */static int update_timestamp_of_queue(snd_seq_event_t *event, int queue, int real_time){	queue_t *q;	q = queueptr(queue);	if (! q)		return 0;	event->queue = queue;	event->flags &= ~SNDRV_SEQ_TIME_STAMP_MASK;	if (real_time) {		event->time.time = snd_seq_timer_get_cur_time(q->timer);		event->flags |= SNDRV_SEQ_TIME_STAMP_REAL;	} else {		event->time.tick = snd_seq_timer_get_cur_tick(q->timer);		event->flags |= SNDRV_SEQ_TIME_STAMP_TICK;	}	queuefree(q);	return 1;}/* * deliver an event to the specified destination. * if filter is non-zero, client filter bitmap is tested. * *  RETURN VALUE: 0 : if succeeded *		 <0 : error */static int snd_seq_deliver_single_event(client_t *client,					snd_seq_event_t *event,					int filter, int atomic, int hop){	client_t *dest = NULL;	client_port_t *dest_port = NULL;	int result = -ENOENT;	int direct;	direct = snd_seq_ev_is_direct(event);	dest = get_event_dest_client(event, filter);	if (dest == NULL)		goto __skip;	dest_port = snd_seq_port_use_ptr(dest, event->dest.port);	if (dest_port == NULL)		goto __skip;	/* check permission */	if (! check_port_perm(dest_port, SNDRV_SEQ_PORT_CAP_WRITE)) {		result = -EPERM;		goto __skip;	}			if (dest_port->timestamping)		update_timestamp_of_queue(event, dest_port->time_queue,					  dest_port->time_real);	switch (dest->type) {	case USER_CLIENT:		if (dest->data.user.fifo)			result = snd_seq_fifo_event_in(dest->data.user.fifo, event);		break;	case KERNEL_CLIENT:		if (dest_port->event_input == NULL)			break;		result = dest_port->event_input(event, direct, dest_port->private_data, atomic, hop);		break;	default:		break;	}  __skip:	if (dest_port)		snd_seq_port_unlock(dest_port);	if (dest)		snd_seq_client_unlock(dest);	if (result < 0 && !direct) {		result = bounce_error_event(client, event, result, atomic, hop);	}	return result;}/* * send the event to all subscribers: */static int deliver_to_subscribers(client_t *client,				  snd_seq_event_t *event,				  int atomic, int hop){	subscribers_t *subs;	int err = 0, num_ev = 0;	snd_seq_event_t event_saved;	client_port_t *src_port;	struct list_head *p;	port_subs_info_t *grp;	src_port = snd_seq_port_use_ptr(client, event->source.port);	if (src_port == NULL)		return -EINVAL; /* invalid source port */	/* save original event record */	event_saved = *event;	grp = &src_port->c_src;		/* lock list */	if (atomic)		read_lock(&grp->list_lock);	else		down_read(&grp->list_mutex);	list_for_each(p, &grp->list_head) {		subs = list_entry(p, subscribers_t, src_list);		event->dest = subs->info.dest;		if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP)			/* convert time according to flag with subscription */			update_timestamp_of_queue(event, subs->info.queue,						  subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIME_REAL);		err = snd_seq_deliver_single_event(client, event,						   0, atomic, hop);		if (err < 0)			break;		num_ev++;		/* restore original event record */		*event = event_saved;	}	if (atomic)		read_unlock(&grp->list_lock);	else		up_read(&grp->list_mutex);	*event = event_saved; /* restore */	snd_seq_port_unlock(src_port);	return (err < 0) ? err : num_ev;}#ifdef SUPPORT_BROADCAST /* * broadcast to all ports: */static int port_broadcast_event(client_t *client,				snd_seq_event_t *event,				int atomic, int hop){	int num_ev = 0, err = 0;	client_t *dest_client;	struct list_head *p;	dest_client = get_event_dest_client(event, SNDRV_SEQ_FILTER_BROADCAST);	if (dest_client == NULL)		return 0; /* no matching destination */	read_lock(&dest_client->ports_lock);	list_for_each(p, &dest_client->ports_list_head) {		client_port_t *port = list_entry(p, client_port_t, list);		event->dest.port = port->addr.port;		/* pass NULL as source client to avoid error bounce */		err = snd_seq_deliver_single_event(NULL, event,						   SNDRV_SEQ_FILTER_BROADCAST,						   atomic, hop);		if (err < 0)			break;		num_ev++;	}	read_unlock(&dest_client->ports_lock);	snd_seq_client_unlock(dest_client);	event->dest.port = SNDRV_SEQ_ADDRESS_BROADCAST; /* restore */	return (err < 0) ? err : num_ev;}/* * send the event to all clients: * if destination port is also ADDRESS_BROADCAST, deliver to all ports. */static int broadcast_event(client_t *client,			   snd_seq_event_t *event, int atomic, int hop){	int err = 0, num_ev = 0;	int dest;	snd_seq_addr_t addr;	addr = event->dest; /* save */	for (dest = 0; dest < SNDRV_SEQ_MAX_CLIENTS; dest++) {		/* don't send to itself */		if (dest == client->number)			continue;		event->dest.client = dest;		event->dest.port = addr.port;		if (addr.port == SNDRV_SEQ_ADDRESS_BROADCAST)			err = port_broadcast_event(client, event, atomic, hop);		else			/* pass NULL as source client to avoid error bounce */			err = snd_seq_deliver_single_event(NULL, event,							   SNDRV_SEQ_FILTER_BROADCAST,							   atomic, hop);		if (err < 0)			break;		num_ev += err;	}	event->dest = addr; /* restore */	return (err < 0) ? err : num_ev;}/* multicast - not supported yet */static int multicast_event(client_t *client, snd_seq_event_t *event,			   int atomic, int hop){	snd_printd("seq: multicast not supported yet.\n");	return 0; /* ignored */}#endif /* SUPPORT_BROADCAST *//* deliver an event to the destination port(s). * if the event is to subscribers or broadcast, the event is dispatched * to multiple targets. * * RETURN VALUE: n > 0  : the number of delivered events. *               n == 0 : the event was not passed to any client. *               n < 0  : error - event was not processed. */static int snd_seq_deliver_event(client_t *client, snd_seq_event_t *event,				 int atomic, int hop){	int result;	hop++;	if (hop >= SNDRV_SEQ_MAX_HOPS) {		snd_printd("too long delivery path (%d:%d->%d:%d)\n",			   event->source.client, event->source.port,			   event->dest.client, event->dest.port);		return -EMLINK;	}	if (event->queue == SNDRV_SEQ_ADDRESS_SUBSCRIBERS ||	    event->dest.client == SNDRV_SEQ_ADDRESS_SUBSCRIBERS)		result = deliver_to_subscribers(client, event, atomic, hop);#ifdef SUPPORT_BROADCAST	else if (event->queue == SNDRV_SEQ_ADDRESS_BROADCAST ||		 event->dest.client == SNDRV_SEQ_ADDRESS_BROADCAST)		result = broadcast_event(client, event, atomic, hop);	else if (event->dest.client >= SNDRV_SEQ_MAX_CLIENTS)		result = multicast_event(client, event, atomic, hop);	else if (event->dest.port == SNDRV_SEQ_ADDRESS_BROADCAST)		result = port_broadcast_event(client, event, atomic, hop);#endif	else		result = snd_seq_deliver_single_event(client, event, 0, atomic, hop);	return result;}/* * dispatch an event cell: * This function is called only from queue check routines in timer * interrupts or after enqueued. * The event cell shall be released or re-queued in this function. * * RETURN VALUE: n > 0  : the number of delivered events. *		 n == 0 : the event was not passed to any client. *		 n < 0  : error - event was not processed. */int snd_seq_dispatch_event(snd_seq_event_cell_t *cell, int atomic, int hop){	client_t *client;	int result;	snd_assert(cell != NULL, return -EINVAL);	client = snd_seq_client_use_ptr(cell->event.source.client);	if (client == NULL) {		snd_seq_cell_free(cell); /* release this cell */		return -EINVAL;	}	if (cell->event.type == SNDRV_SEQ_EVENT_NOTE) {		/* NOTE event:		 * the event cell is re-used as a NOTE-OFF event and		 * enqueued again.		 */		snd_seq_event_t tmpev, *ev;		/* reserve this event to enqueue note-off later */		tmpev = cell->event;		tmpev.type = SNDRV_SEQ_EVENT_NOTEON;		result = snd_seq_deliver_event(client, &tmpev, atomic, hop);		/*		 * This was originally a note event.  We now re-use the		 * cell for the note-off event.		 */		ev = &cell->event;		ev->type = SNDRV_SEQ_EVENT_NOTEOFF;		ev->flags |= SNDRV_SEQ_PRIORITY_HIGH;		/* add the duration time */		switch (ev->flags & SNDRV_SEQ_TIME_STAMP_MASK) {		case SNDRV_SEQ_TIME_STAMP_TICK:			ev->time.tick += ev->data.note.duration;			break;		case SNDRV_SEQ_TIME_STAMP_REAL:			/* unit for duration is ms */			ev->time.time.tv_nsec += 1000000 * (ev->data.note.duration % 1000);			ev->time.time.tv_sec += ev->data.note.duration / 1000 +						ev->time.time.tv_nsec / 1000000000;			ev->time.time.tv_nsec %= 1000000000;			break;		}		ev->data.note.velocity = ev->data.note.off_velocity;		/* Now queue this cell as the note off event */		if (snd_seq_enqueue_event(cell, atomic, hop) < 0)			snd_seq_cell_free(cell); /* release this cell */	} else {		/* Normal events:		 * event cell is freed after processing the event		 */		result = snd_seq_deliver_event(client, &cell->event, atomic, hop);		snd_seq_cell_free(cell);	}	snd_seq_client_unlock(client);	return result;}/* Allocate a cell from client pool and enqueue it to queue: * if pool is empty and blocking is TRUE, sleep until a new cell is * available. */static int snd_seq_client_enqueue_event(client_t *client,					snd_seq_event_t *event,					struct file *file, int blocking,					int atomic, int hop){	snd_seq_event_cell_t *cell;	int err;	/* special queue values - force direct passing */	if (event->queue == SNDRV_SEQ_ADDRESS_SUBSCRIBERS) {		event->dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;		event->queue = SNDRV_SEQ_QUEUE_DIRECT;	} else#ifdef SUPPORT_BROADCAST		if (event->queue == SNDRV_SEQ_ADDRESS_BROADCAST) {			event->dest.client = SNDRV_SEQ_ADDRESS_BROADCAST;			event->queue = SNDRV_SEQ_QUEUE_DIRECT;		}#endif	if (event->dest.client == SNDRV_SEQ_ADDRESS_SUBSCRIBERS) {		/* check presence of source port */		client_port_t *src_port = snd_seq_port_use_ptr(client, event->source.port);		if (src_port == NULL)			return -EINVAL;		snd_seq_port_unlock(src_port);	}	/* direct event processing without enqueued */	if (snd_seq_ev_is_direct(event)) {		if (event->type == SNDRV_SEQ_EVENT_NOTE)			return -EINVAL; /* this event must be enqueued! */		return snd_seq_deliver_event(client, event, atomic, hop);	}	/* Not direct, normal queuing */	if (snd_seq_queue_is_used(event->queue, client->number) <= 0)		return -EINVAL;  /* invalid queue */	if (! snd_seq_write_pool_allocated(client))		return -ENXIO; /* queue is not allocated */	/* allocate an event cell */	err = snd_seq_event_dup(client->pool, event, &cell, !blocking || atomic, file);	if (err < 0)		return err;	/* we got a cell. enqueue it. */	if ((err = snd_seq_enqueue_event(cell, atomic, hop)) < 0) {		snd_seq_cell_free(cell);		return err;	}	return 0;}/* * check validity of event type and data length. * return non-zero if invalid. */static int check_event_type_and_length(snd_seq_event_t *ev){	switch (snd_seq_ev_length_type(ev)) {	case SNDRV_SEQ_EVENT_LENGTH_FIXED:		if (snd_seq_ev_is_variable_type(ev))			return -EINVAL;		break;	case SNDRV_SEQ_EVENT_LENGTH_VARIABLE:		if (! snd_seq_ev_is_variable_type(ev) ||		    (ev->data.ext.len & ~SNDRV_SEQ_EXT_MASK) >= SNDRV_SEQ_MAX_EVENT_LEN)			return -EINVAL;		break;	case SNDRV_SEQ_EVENT_LENGTH_VARUSR:		if (! snd_seq_ev_is_instr_type(ev) ||		    ! snd_seq_ev_is_direct(ev))			return -EINVAL;		break;	}	return 0;}/* handle write() *//* possible error values: *	-ENXIO	invalid client or file open mode *	-ENOMEM	malloc failed *	-EFAULT	seg. fault during copy from user space *	-EINVAL	invalid event *	-EAGAIN	no space in output pool *	-EINTR	interrupts while sleep *	-EMLINK	too many hops *	others	depends on return value from driver callback */static ssize_t snd_seq_write(struct file *file, const char __user *buf, size_t count, loff_t *offset){	client_t *client = (client_t *) file->private_data;	int written = 0, len;	int err = -EINVAL;	snd_seq_event_t event;	if (!(snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT))		return -ENXIO;	/* check client structures are in place */	snd_assert(client != NULL, return -ENXIO);			if (!client->accept_output || client->pool == NULL)		return -ENXIO;	/* allocate the pool now if the pool is not allocated yet */ 	if (client->pool->size > 0 && !snd_seq_write_pool_allocated(client)) {		if (snd_seq_pool_init(client->pool) < 0)			return -ENOMEM;	}	/* only process whole events */	while (count >= sizeof(snd_seq_event_t)) {		/* Read in the event header from the user */		len = sizeof(event);		if (copy_from_user(&event, buf, len)) {			err = -EFAULT;			break;		}		event.source.client = client->number;	/* fill in client number */		/* Check for extension data length */		if (check_event_type_and_length(&event)) {			err = -EINVAL;			break;		}		/* check for special events */		if (event.type == SNDRV_SEQ_EVENT_NONE)			goto __skip_event;		else if (snd_seq_ev_is_reserved(&event)) {			err = -EINVAL;			break;		}

⌨️ 快捷键说明

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