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

📄 seq_ports.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *   ALSA sequencer Ports *   Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl> *                         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 <sound/driver.h>#include <sound/core.h>#include <linux/slab.h>#include "seq_system.h"#include "seq_ports.h"#include "seq_clientmgr.h"/*   registration of client ports *//* NOTE: the current implementation of the port structure as a linked list isnot optimal for clients that have many ports. For sending messages to allsubscribers of a port we first need to find the address of the portstructure, which means we have to traverse the list. A direct access table(array) would be better, but big preallocated arrays waste memory.Possible actions:1) leave it this way, a client does normaly does not have more than a fewports2) replace the linked list of ports by a array of pointers which isdynamicly kmalloced. When a port is added or deleted we can simply allocatea new array, copy the corresponding pointers, and delete the old one. Wethen only need a pointer to this array, and an integer that tells us howmuch elements are in array.*//* return pointer to port structure - port is locked if found */client_port_t *snd_seq_port_use_ptr(client_t *client, int num){	struct list_head *p;	client_port_t *port;	if (client == NULL)		return NULL;	read_lock(&client->ports_lock);	list_for_each(p, &client->ports_list_head) {		port = list_entry(p, client_port_t, list);		if (port->addr.port == num) {			if (port->closing)				break; /* deleting now */			snd_use_lock_use(&port->use_lock);			read_unlock(&client->ports_lock);			return port;		}	}	read_unlock(&client->ports_lock);	return NULL;		/* not found */}/* search for the next port - port is locked if found */client_port_t *snd_seq_port_query_nearest(client_t *client, snd_seq_port_info_t *pinfo){	int num;	struct list_head *p;	client_port_t *port, *found;	num = pinfo->addr.port;	found = NULL;	read_lock(&client->ports_lock);	list_for_each(p, &client->ports_list_head) {		port = list_entry(p, client_port_t, list);		if (port->addr.port < num)			continue;		if (port->addr.port == num) {			found = port;			break;		}		if (found == NULL || port->addr.port < found->addr.port)			found = port;	}	if (found) {		if (found->closing)			found = NULL;		else			snd_use_lock_use(&found->use_lock);	}	read_unlock(&client->ports_lock);	return found;}/* initialize port_subs_info_t */static void port_subs_info_init(port_subs_info_t *grp){	INIT_LIST_HEAD(&grp->list_head);	grp->count = 0;	grp->exclusive = 0;	rwlock_init(&grp->list_lock);	init_rwsem(&grp->list_mutex);	grp->open = NULL;	grp->close = NULL;}/* create a port, port number is returned (-1 on failure) */client_port_t *snd_seq_create_port(client_t *client, int port){	unsigned long flags;	client_port_t *new_port;	struct list_head *l;	int num = -1;		/* sanity check */	snd_assert(client, return NULL);	if (client->num_ports >= SNDRV_SEQ_MAX_PORTS - 1) {		snd_printk(KERN_WARNING "too many ports for client %d\n", client->number);		return NULL;	}	/* create a new port */	new_port = kzalloc(sizeof(*new_port), GFP_KERNEL);	if (! new_port) {		snd_printd("malloc failed for registering client port\n");		return NULL;	/* failure, out of memory */	}	/* init port data */	new_port->addr.client = client->number;	new_port->addr.port = -1;	new_port->owner = THIS_MODULE;	sprintf(new_port->name, "port-%d", num);	snd_use_lock_init(&new_port->use_lock);	port_subs_info_init(&new_port->c_src);	port_subs_info_init(&new_port->c_dest);	num = port >= 0 ? port : 0;	down(&client->ports_mutex);	write_lock_irqsave(&client->ports_lock, flags);	list_for_each(l, &client->ports_list_head) {		client_port_t *p = list_entry(l, client_port_t, list);		if (p->addr.port > num)			break;		if (port < 0) /* auto-probe mode */			num = p->addr.port + 1;	}	/* insert the new port */	list_add_tail(&new_port->list, l);	client->num_ports++;	new_port->addr.port = num;	/* store the port number in the port */	write_unlock_irqrestore(&client->ports_lock, flags);	up(&client->ports_mutex);	sprintf(new_port->name, "port-%d", num);	return new_port;}/* */enum group_type_t {	SRC_LIST, DEST_LIST};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);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);static client_port_t *get_client_port(snd_seq_addr_t *addr, client_t **cp){	client_port_t *p;	*cp = snd_seq_client_use_ptr(addr->client);	if (*cp) {		p = snd_seq_port_use_ptr(*cp, addr->port);		if (! p) {			snd_seq_client_unlock(*cp);			*cp = NULL;		}		return p;	}	return NULL;}/* * remove all subscribers on the list * this is called from port_delete, for each src and dest list. */static void clear_subscriber_list(client_t *client, client_port_t *port,				  port_subs_info_t *grp, int grptype){	struct list_head *p, *n;	down_write(&grp->list_mutex);	list_for_each_safe(p, n, &grp->list_head) {		subscribers_t *subs;		client_t *c;		client_port_t *aport;		if (grptype == SRC_LIST) {			subs = list_entry(p, subscribers_t, src_list);			aport = get_client_port(&subs->info.dest, &c);		} else {			subs = list_entry(p, subscribers_t, dest_list);			aport = get_client_port(&subs->info.sender, &c);		}		list_del(p);		unsubscribe_port(client, port, grp, &subs->info, 0);		if (!aport) {			/* looks like the connected port is being deleted.			 * we decrease the counter, and when both ports are deleted			 * remove the subscriber info			 */			if (atomic_dec_and_test(&subs->ref_count))				kfree(subs);		} else {			/* ok we got the connected port */			port_subs_info_t *agrp;			agrp = (grptype == SRC_LIST) ? &aport->c_dest : &aport->c_src;			down_write(&agrp->list_mutex);			if (grptype == SRC_LIST)				list_del(&subs->dest_list);			else				list_del(&subs->src_list);			unsubscribe_port(c, aport, agrp, &subs->info, 1);			kfree(subs);			up_write(&agrp->list_mutex);			snd_seq_port_unlock(aport);			snd_seq_client_unlock(c);		}	}	up_write(&grp->list_mutex);}/* delete port data */static int port_delete(client_t *client, client_port_t *port){	/* set closing flag and wait for all port access are gone */	port->closing = 1;	snd_use_lock_sync(&port->use_lock); 	/* clear subscribers info */	clear_subscriber_list(client, port, &port->c_src, SRC_LIST);	clear_subscriber_list(client, port, &port->c_dest, DEST_LIST);	if (port->private_free)		port->private_free(port->private_data);	snd_assert(port->c_src.count == 0,);	snd_assert(port->c_dest.count == 0,);	kfree(port);	return 0;}/* delete a port with the given port id */int snd_seq_delete_port(client_t *client, int port){	unsigned long flags;	struct list_head *l;	client_port_t *found = NULL;	down(&client->ports_mutex);	write_lock_irqsave(&client->ports_lock, flags);	list_for_each(l, &client->ports_list_head) {		client_port_t *p = list_entry(l, client_port_t, list);		if (p->addr.port == port) {			/* ok found.  delete from the list at first */			list_del(l);			client->num_ports--;			found = p;			break;		}	}	write_unlock_irqrestore(&client->ports_lock, flags);	up(&client->ports_mutex);	if (found)		return port_delete(client, found);	else		return -ENOENT;}/* delete the all ports belonging to the given client */int snd_seq_delete_all_ports(client_t *client){	unsigned long flags;	struct list_head deleted_list, *p, *n;		/* move the port list to deleted_list, and	 * clear the port list in the client data.	 */	down(&client->ports_mutex);	write_lock_irqsave(&client->ports_lock, flags);	if (! list_empty(&client->ports_list_head)) {		__list_add(&deleted_list,			   client->ports_list_head.prev,			   client->ports_list_head.next);		INIT_LIST_HEAD(&client->ports_list_head);	} else {		INIT_LIST_HEAD(&deleted_list);	}	client->num_ports = 0;	write_unlock_irqrestore(&client->ports_lock, flags);	/* remove each port in deleted_list */	list_for_each_safe(p, n, &deleted_list) {		client_port_t *port = list_entry(p, client_port_t, list);		list_del(p);		snd_seq_system_client_ev_port_exit(port->addr.client, port->addr.port);		port_delete(client, port);	}	up(&client->ports_mutex);	return 0;}/* set port info fields */int snd_seq_set_port_info(client_port_t * port, snd_seq_port_info_t * info){	snd_assert(port && info, return -EINVAL);

⌨️ 快捷键说明

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