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

📄 seq_ports.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
	/* set port name */	if (info->name[0])		strlcpy(port->name, info->name, sizeof(port->name));		/* set capabilities */	port->capability = info->capability;		/* get port type */	port->type = info->type;	/* information about supported channels/voices */	port->midi_channels = info->midi_channels;	port->midi_voices = info->midi_voices;	port->synth_voices = info->synth_voices;	/* timestamping */	port->timestamping = (info->flags & SNDRV_SEQ_PORT_FLG_TIMESTAMP) ? 1 : 0;	port->time_real = (info->flags & SNDRV_SEQ_PORT_FLG_TIME_REAL) ? 1 : 0;	port->time_queue = info->time_queue;	return 0;}/* get port info fields */int snd_seq_get_port_info(client_port_t * port, snd_seq_port_info_t * info){	snd_assert(port && info, return -EINVAL);	/* get port name */	strlcpy(info->name, port->name, sizeof(info->name));		/* get capabilities */	info->capability = port->capability;	/* get port type */	info->type = port->type;	/* information about supported channels/voices */	info->midi_channels = port->midi_channels;	info->midi_voices = port->midi_voices;	info->synth_voices = port->synth_voices;	/* get subscriber counts */	info->read_use = port->c_src.count;	info->write_use = port->c_dest.count;		/* timestamping */	info->flags = 0;	if (port->timestamping) {		info->flags |= SNDRV_SEQ_PORT_FLG_TIMESTAMP;		if (port->time_real)			info->flags |= SNDRV_SEQ_PORT_FLG_TIME_REAL;		info->time_queue = port->time_queue;	}	return 0;}/* * call callback functions (if any): * the callbacks are invoked only when the first (for connection) or * the last subscription (for disconnection) is done.  Second or later * subscription results in increment of counter, but no callback is * invoked. * This feature is useful if these callbacks are associated with * initialization or termination of devices (see seq_midi.c). * * If callback_all option is set, the callback function is invoked * at each connnection/disconnection.  */static int subscribe_port(client_t *client, client_port_t *port, port_subs_info_t *grp,			  snd_seq_port_subscribe_t *info, int send_ack){	int err = 0;	if (!try_module_get(port->owner))		return -EFAULT;	grp->count++;	if (grp->open && (port->callback_all || grp->count == 1)) {		err = grp->open(port->private_data, info);		if (err < 0) {			module_put(port->owner);			grp->count--;		}	}	if (err >= 0 && send_ack && client->type == USER_CLIENT)		snd_seq_client_notify_subscription(port->addr.client, port->addr.port,						   info, SNDRV_SEQ_EVENT_PORT_SUBSCRIBED);	return err;}static int unsubscribe_port(client_t *client, client_port_t *port,			    port_subs_info_t *grp,			    snd_seq_port_subscribe_t *info, int send_ack){	int err = 0;	if (! grp->count)		return -EINVAL;	grp->count--;	if (grp->close && (port->callback_all || grp->count == 0))		err = grp->close(port->private_data, info);	if (send_ack && client->type == USER_CLIENT)		snd_seq_client_notify_subscription(port->addr.client, port->addr.port,						   info, SNDRV_SEQ_EVENT_PORT_UNSUBSCRIBED);	module_put(port->owner);	return err;}/* check if both addresses are identical */static inline int addr_match(snd_seq_addr_t *r, snd_seq_addr_t *s){	return (r->client == s->client) && (r->port == s->port);}/* check the two subscribe info match *//* if flags is zero, checks only sender and destination addresses */static int match_subs_info(snd_seq_port_subscribe_t *r,			   snd_seq_port_subscribe_t *s){	if (addr_match(&r->sender, &s->sender) &&	    addr_match(&r->dest, &s->dest)) {		if (r->flags && r->flags == s->flags)			return r->queue == s->queue;		else if (! r->flags)			return 1;	}	return 0;}/* connect two ports */int snd_seq_port_connect(client_t *connector,			 client_t *src_client, client_port_t *src_port,			 client_t *dest_client, client_port_t *dest_port,			 snd_seq_port_subscribe_t *info){	port_subs_info_t *src = &src_port->c_src;	port_subs_info_t *dest = &dest_port->c_dest;	subscribers_t *subs;	struct list_head *p;	int err, src_called = 0;	unsigned long flags;	int exclusive;	subs = kzalloc(sizeof(*subs), GFP_KERNEL);	if (! subs)		return -ENOMEM;	subs->info = *info;	atomic_set(&subs->ref_count, 2);	down_write(&src->list_mutex);	down_write(&dest->list_mutex);	exclusive = info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE ? 1 : 0;	err = -EBUSY;	if (exclusive) {		if (! list_empty(&src->list_head) || ! list_empty(&dest->list_head))			goto __error;	} else {		if (src->exclusive || dest->exclusive)			goto __error;		/* check whether already exists */		list_for_each(p, &src->list_head) {			subscribers_t *s = list_entry(p, subscribers_t, src_list);			if (match_subs_info(info, &s->info))				goto __error;		}		list_for_each(p, &dest->list_head) {			subscribers_t *s = list_entry(p, subscribers_t, dest_list);			if (match_subs_info(info, &s->info))				goto __error;		}	}	if ((err = subscribe_port(src_client, src_port, src, info,				  connector->number != src_client->number)) < 0)		goto __error;	src_called = 1;	if ((err = subscribe_port(dest_client, dest_port, dest, info,				  connector->number != dest_client->number)) < 0)		goto __error;	/* add to list */	write_lock_irqsave(&src->list_lock, flags);	// write_lock(&dest->list_lock); // no other lock yet	list_add_tail(&subs->src_list, &src->list_head);	list_add_tail(&subs->dest_list, &dest->list_head);	// write_unlock(&dest->list_lock); // no other lock yet	write_unlock_irqrestore(&src->list_lock, flags);	src->exclusive = dest->exclusive = exclusive;	up_write(&dest->list_mutex);	up_write(&src->list_mutex);	return 0; __error:	if (src_called)		unsubscribe_port(src_client, src_port, src, info,				 connector->number != src_client->number);	kfree(subs);	up_write(&dest->list_mutex);	up_write(&src->list_mutex);	return err;}/* remove the connection */int snd_seq_port_disconnect(client_t *connector,			    client_t *src_client, client_port_t *src_port,			    client_t *dest_client, client_port_t *dest_port,			    snd_seq_port_subscribe_t *info){	port_subs_info_t *src = &src_port->c_src;	port_subs_info_t *dest = &dest_port->c_dest;	subscribers_t *subs;	struct list_head *p;	int err = -ENOENT;	unsigned long flags;	down_write(&src->list_mutex);	down_write(&dest->list_mutex);	/* look for the connection */	list_for_each(p, &src->list_head) {		subs = list_entry(p, subscribers_t, src_list);		if (match_subs_info(info, &subs->info)) {			write_lock_irqsave(&src->list_lock, flags);			// write_lock(&dest->list_lock);  // no lock yet			list_del(&subs->src_list);			list_del(&subs->dest_list);			// write_unlock(&dest->list_lock);			write_unlock_irqrestore(&src->list_lock, flags);			src->exclusive = dest->exclusive = 0;			unsubscribe_port(src_client, src_port, src, info,					 connector->number != src_client->number);			unsubscribe_port(dest_client, dest_port, dest, info,					 connector->number != dest_client->number);			kfree(subs);			err = 0;			break;		}	}	up_write(&dest->list_mutex);	up_write(&src->list_mutex);	return err;}/* get matched subscriber */subscribers_t *snd_seq_port_get_subscription(port_subs_info_t *src_grp,					     snd_seq_addr_t *dest_addr){	struct list_head *p;	subscribers_t *s, *found = NULL;	down_read(&src_grp->list_mutex);	list_for_each(p, &src_grp->list_head) {		s = list_entry(p, subscribers_t, src_list);		if (addr_match(dest_addr, &s->info.dest)) {			found = s;			break;		}	}	up_read(&src_grp->list_mutex);	return found;}/* * Attach a device driver that wants to receive events from the * sequencer.  Returns the new port number on success. * A driver that wants to receive the events converted to midi, will * use snd_seq_midisynth_register_port(). *//* exported */int snd_seq_event_port_attach(int client,			      snd_seq_port_callback_t *pcbp,			      int cap, int type, int midi_channels,			      int midi_voices, char *portname){	snd_seq_port_info_t portinfo;	int  ret;	/* Set up the port */	memset(&portinfo, 0, sizeof(portinfo));	portinfo.addr.client = client;	strlcpy(portinfo.name, portname ? portname : "Unamed port",		sizeof(portinfo.name));	portinfo.capability = cap;	portinfo.type = type;	portinfo.kernel = pcbp;	portinfo.midi_channels = midi_channels;	portinfo.midi_voices = midi_voices;	/* Create it */	ret = snd_seq_kernel_client_ctl(client,					SNDRV_SEQ_IOCTL_CREATE_PORT,					&portinfo);	if (ret >= 0)		ret = portinfo.addr.port;	return ret;}/* * Detach the driver from a port. *//* exported */int snd_seq_event_port_detach(int client, int port){	snd_seq_port_info_t portinfo;	int  err;	memset(&portinfo, 0, sizeof(portinfo));	portinfo.addr.client = client;	portinfo.addr.port   = port;	err = snd_seq_kernel_client_ctl(client,					SNDRV_SEQ_IOCTL_DELETE_PORT,					&portinfo);	return err;}

⌨️ 快捷键说明

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