예제 #1
0
static int init_midi(void) {
    int err;
    struct snd_seq_port_info *pinfo;

    err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(struct snd_card), &card);
    if (err < 0) {
        printk(KERN_INFO LOGPREFIX "error creating card: %d\n", err);
        return err;
    }

    client = snd_seq_create_kernel_client(card, 0, "new_midi-client");
    if (client < 0) {
        printk(KERN_INFO LOGPREFIX "error creating client: %d\n", err);
        return err;
    }

    pinfo = kzalloc(sizeof(struct snd_seq_port_info), GFP_KERNEL);
    if (!pinfo) {
        err = -ENOMEM;
        return err;
    }
    pinfo->addr.client = client;
    //pinfo->capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
    pinfo->capability |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SYNC_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ;

    err = snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_CREATE_PORT, pinfo);
    if (err < 0) {
        printk(KERN_INFO LOGPREFIX "error creating port: %d\n", err);
        return err;
    }

    return 0;
}
예제 #2
0
/*
 * Create a sequencer client
 */
static int
get_client(snd_card_t *card, int index, char *name)
{
	snd_seq_client_callback_t callbacks;
	snd_seq_client_info_t cinfo;
	int client;

	memset(&callbacks, 0, sizeof(callbacks));
	callbacks.private_data = NULL;
	callbacks.allow_input = 1;
	callbacks.allow_output = 1;

	/* Find a free client, start from 1 as the MPU expects to use 0 */
	client = snd_seq_create_kernel_client(card, index, &callbacks);
	if (client < 0)
		return client;

	memset(&cinfo, 0, sizeof(cinfo));
	cinfo.client = client;
	cinfo.type = KERNEL_CLIENT;
	strcpy(cinfo.name, name);
	snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &cinfo);

	return client;
}
예제 #3
0
/* register our internal client */
int __init snd_seq_system_client_init(void)
{

    snd_seq_client_callback_t callbacks;
    snd_seq_port_callback_t pcallbacks;
    snd_seq_client_info_t *inf;
    snd_seq_port_info_t *port;

    inf = kcalloc(1, sizeof(*inf), GFP_KERNEL);
    port = kcalloc(1, sizeof(*port), GFP_KERNEL);
    if (! inf || ! port) {
        kfree(inf);
        kfree(port);
        return -ENOMEM;
    }

    memset(&callbacks, 0, sizeof(callbacks));
    memset(&pcallbacks, 0, sizeof(pcallbacks));
    pcallbacks.owner = THIS_MODULE;
    pcallbacks.event_input = event_input_timer;

    /* register client */
    callbacks.allow_input = callbacks.allow_output = 1;
    sysclient = snd_seq_create_kernel_client(NULL, 0, &callbacks);

    /* set our name */
    inf->client = 0;
    inf->type = KERNEL_CLIENT;
    strcpy(inf->name, "System");
    snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, inf);

    /* register timer */
    strcpy(port->name, "Timer");
    port->capability = SNDRV_SEQ_PORT_CAP_WRITE; /* accept queue control */
    port->capability |= SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ; /* for broadcast */
    port->kernel = &pcallbacks;
    port->type = 0;
    port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
    port->addr.client = sysclient;
    port->addr.port = SNDRV_SEQ_PORT_SYSTEM_TIMER;
    snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, port);

    /* register announcement port */
    strcpy(port->name, "Announce");
    port->capability = SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ; /* for broadcast only */
    port->kernel = NULL;
    port->type = 0;
    port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
    port->addr.client = sysclient;
    port->addr.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
    snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, port);
    announce_port = port->addr.port;

    kfree(inf);
    kfree(port);
    return 0;
}
예제 #4
0
/*
 * create sequencer client for OSS sequencer
 */
int __init
snd_seq_oss_create_client(void)
{
	int rc;
	struct snd_seq_port_info *port;
	struct snd_seq_port_callback port_callback;

	port = kmalloc(sizeof(*port), GFP_KERNEL);
	if (!port) {
		rc = -ENOMEM;
		goto __error;
	}

	/* create ALSA client */
	rc = snd_seq_create_kernel_client(NULL, SNDRV_SEQ_CLIENT_OSS,
					  "OSS sequencer");
	if (rc < 0)
		goto __error;

	system_client = rc;
	debug_printk(("new client = %d\n", rc));

	/* look up midi devices */
	snd_seq_oss_midi_lookup_ports(system_client);

	/* create annoucement receiver port */
	memset(port, 0, sizeof(*port));
	strcpy(port->name, "Receiver");
	port->addr.client = system_client;
	port->capability = SNDRV_SEQ_PORT_CAP_WRITE; /* receive only */
	port->type = 0;

	memset(&port_callback, 0, sizeof(port_callback));
	/* don't set port_callback.owner here. otherwise the module counter
	 * is incremented and we can no longer release the module..
	 */
	port_callback.event_input = receive_announce;
	port->kernel = &port_callback;
	
	call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, port);
	if ((system_port = port->addr.port) >= 0) {
		struct snd_seq_port_subscribe subs;

		memset(&subs, 0, sizeof(subs));
		subs.sender.client = SNDRV_SEQ_CLIENT_SYSTEM;
		subs.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
		subs.dest.client = system_client;
		subs.dest.port = system_port;
		call_ctl(SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs);
	}
	rc = 0;

 __error:
	kfree(port);
	return rc;
}
예제 #5
0
static int snd_opl4_seq_new_device(struct snd_seq_device *dev)
{
    struct snd_opl4 *opl4;
    int client;
    struct snd_seq_port_callback pcallbacks;

    opl4 = *(struct snd_opl4 **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
    if (!opl4)
        return -EINVAL;

    if (snd_yrw801_detect(opl4) < 0)
        return -ENODEV;

    opl4->chset = snd_midi_channel_alloc_set(16);
    if (!opl4->chset)
        return -ENOMEM;
    opl4->chset->private_data = opl4;

    /* allocate new client */
    client = snd_seq_create_kernel_client(opl4->card, opl4->seq_dev_num,
                                          "OPL4 Wavetable");
    if (client < 0) {
        snd_midi_channel_free_set(opl4->chset);
        return client;
    }
    opl4->seq_client = client;
    opl4->chset->client = client;

    /* create new port */
    memset(&pcallbacks, 0, sizeof(pcallbacks));
    pcallbacks.owner = THIS_MODULE;
    pcallbacks.use = snd_opl4_seq_use;
    pcallbacks.unuse = snd_opl4_seq_unuse;
    pcallbacks.event_input = snd_opl4_seq_event_input;
    pcallbacks.private_free = snd_opl4_seq_free_port;
    pcallbacks.private_data = opl4;

    opl4->chset->port = snd_seq_event_port_attach(client, &pcallbacks,
                        SNDRV_SEQ_PORT_CAP_WRITE |
                        SNDRV_SEQ_PORT_CAP_SUBS_WRITE,
                        SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
                        SNDRV_SEQ_PORT_TYPE_MIDI_GM |
                        SNDRV_SEQ_PORT_TYPE_HARDWARE |
                        SNDRV_SEQ_PORT_TYPE_SYNTHESIZER,
                        16, 24,
                        "OPL4 Wavetable Port");
    if (opl4->chset->port < 0) {
        int err = opl4->chset->port;
        snd_midi_channel_free_set(opl4->chset);
        snd_seq_delete_kernel_client(client);
        opl4->seq_client = -1;
        return err;
    }
    return 0;
}
예제 #6
0
static int snd_opl3_seq_new_device(struct snd_seq_device *dev)
{
	struct snd_opl3 *opl3;
	int client, err;
	char name[32];
	int opl_ver;

	opl3 = *(struct snd_opl3 **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
	if (opl3 == NULL)
		return -EINVAL;

	spin_lock_init(&opl3->voice_lock);

	opl3->seq_client = -1;

	/* allocate new client */
	opl_ver = (opl3->hardware & OPL3_HW_MASK) >> 8;
	sprintf(name, "OPL%i FM synth", opl_ver);
	client = opl3->seq_client =
		snd_seq_create_kernel_client(opl3->card, opl3->seq_dev_num,
					     name);
	if (client < 0)
		return client;

	if ((err = snd_opl3_synth_create_port(opl3)) < 0) {
		snd_seq_delete_kernel_client(client);
		opl3->seq_client = -1;
		return err;
	}

	/* initialize instrument list */
	opl3->ilist = snd_seq_instr_list_new();
	if (opl3->ilist == NULL) {
		snd_seq_delete_kernel_client(client);
		opl3->seq_client = -1;
		return -ENOMEM;
	}
	opl3->ilist->flags = SNDRV_SEQ_INSTR_FLG_DIRECT;
	snd_seq_fm_init(&opl3->fm_ops, NULL);

	/* setup system timer */
	init_timer(&opl3->tlist);
	opl3->tlist.function = snd_opl3_timer_func;
	opl3->tlist.data = (unsigned long) opl3;
	spin_lock_init(&opl3->sys_timer_lock);
	opl3->sys_timer_status = 0;

#ifdef CONFIG_SND_SEQUENCER_OSS
	snd_opl3_init_seq_oss(opl3, name);
#endif
	return 0;
}
예제 #7
0
/*
 * register client and create ports
 */
static int __init
register_client(void)
{
	snd_seq_client_callback_t cb;
	snd_seq_client_info_t cinfo;
	snd_seq_dummy_port_t *rec1, *rec2;
	int i;

	if (ports < 1) {
		snd_printk(KERN_ERR "invalid number of ports %d\n", ports);
		return -EINVAL;
	}

	/* create client */
	memset(&cb, 0, sizeof(cb));
	cb.allow_input = 1;
	cb.allow_output = 1;
	my_client = snd_seq_create_kernel_client(NULL, SNDRV_SEQ_CLIENT_DUMMY, &cb);
	if (my_client < 0)
		return my_client;

	/* set client name */
	memset(&cinfo, 0, sizeof(cinfo));
	cinfo.client = my_client;
	cinfo.type = KERNEL_CLIENT;
	strcpy(cinfo.name, "Midi Through");
	snd_seq_kernel_client_ctl(my_client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &cinfo);

	/* create ports */
	for (i = 0; i < ports; i++) {
		rec1 = create_port(i, 0);
		if (rec1 == NULL) {
			snd_seq_delete_kernel_client(my_client);
			return -ENOMEM;
		}
		if (duplex) {
			rec2 = create_port(i, 1);
			if (rec2 == NULL) {
				snd_seq_delete_kernel_client(my_client);
				return -ENOMEM;
			}
			rec1->connect = rec2->port;
			rec2->connect = rec1->port;
		}
	}

	return 0;
}
예제 #8
0
/*
 * Initialise the EMUX Synth by creating a client and registering
 * a series of ports.
 * Each of the ports will contain the 16 midi channels.  Applications
 * can connect to these ports to play midi data.
 */
int
snd_emux_init_seq(struct snd_emux *emu, struct snd_card *card, int index)
{
	int  i;
	struct snd_seq_port_callback pinfo;
	char tmpname[64];

	emu->client = snd_seq_create_kernel_client(card, index,
						   "%s WaveTable", emu->name);
	if (emu->client < 0) {
		snd_printk(KERN_ERR "can't create client\n");
		return -ENODEV;
	}

	if (emu->num_ports < 0) {
		snd_printk(KERN_WARNING "seqports must be greater than zero\n");
		emu->num_ports = 1;
	} else if (emu->num_ports >= SNDRV_EMUX_MAX_PORTS) {
		snd_printk(KERN_WARNING "too many ports."
			   "limited max. ports %d\n", SNDRV_EMUX_MAX_PORTS);
		emu->num_ports = SNDRV_EMUX_MAX_PORTS;
	}

	memset(&pinfo, 0, sizeof(pinfo));
	pinfo.owner = THIS_MODULE;
	pinfo.use = snd_emux_use;
	pinfo.unuse = snd_emux_unuse;
	pinfo.event_input = snd_emux_event_input;

	for (i = 0; i < emu->num_ports; i++) {
		struct snd_emux_port *p;

		sprintf(tmpname, "%s Port %d", emu->name, i);
		p = snd_emux_create_port(emu, tmpname, MIDI_CHANNELS,
					 0, &pinfo);
		if (p == NULL) {
			snd_printk(KERN_ERR "can't create port\n");
			return -ENOMEM;
		}

		p->port_mode =  SNDRV_EMUX_PORT_MODE_MIDI;
		snd_emux_init_port(p);
		emu->ports[i] = p->chset.port;
		emu->portptrs[i] = p;
	}

	return 0;
}
예제 #9
0
/* register our internal client */
int __init snd_seq_system_client_init(void)
{
	struct snd_seq_port_callback pcallbacks;
	struct snd_seq_port_info *port;

	port = kzalloc(sizeof(*port), GFP_KERNEL);
	if (!port)
		return -ENOMEM;

	memset(&pcallbacks, 0, sizeof(pcallbacks));
	pcallbacks.owner = THIS_MODULE;
	pcallbacks.event_input = event_input_timer;

	/* register client */
	sysclient = snd_seq_create_kernel_client(NULL, 0, "System");

	/* register timer */
	strcpy(port->name, "Timer");
	port->capability = SNDRV_SEQ_PORT_CAP_WRITE; /* accept queue control */
	port->capability |= SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ; /* for broadcast */
	port->kernel = &pcallbacks;
	port->type = 0;
	port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
	port->addr.client = sysclient;
	port->addr.port = SNDRV_SEQ_PORT_SYSTEM_TIMER;
	snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, port);

	/* register announcement port */
	strcpy(port->name, "Announce");
	port->capability = SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ; /* for broadcast only */
	port->kernel = NULL;
	port->type = 0;
	port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
	port->addr.client = sysclient;
	port->addr.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
	snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, port);
	announce_port = port->addr.port;

	kfree(port);
	return 0;
}
예제 #10
0
파일: opl3_seq.c 프로젝트: mdamt/linux
static int snd_opl3_seq_probe(struct device *_dev)
{
	struct snd_seq_device *dev = to_seq_dev(_dev);
	struct snd_opl3 *opl3;
	int client, err;
	char name[32];
	int opl_ver;

	opl3 = *(struct snd_opl3 **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
	if (opl3 == NULL)
		return -EINVAL;

	spin_lock_init(&opl3->voice_lock);

	opl3->seq_client = -1;

	/* allocate new client */
	opl_ver = (opl3->hardware & OPL3_HW_MASK) >> 8;
	sprintf(name, "OPL%i FM synth", opl_ver);
	client = opl3->seq_client =
		snd_seq_create_kernel_client(opl3->card, opl3->seq_dev_num,
					     name);
	if (client < 0)
		return client;

	if ((err = snd_opl3_synth_create_port(opl3)) < 0) {
		snd_seq_delete_kernel_client(client);
		opl3->seq_client = -1;
		return err;
	}

	/* setup system timer */
	setup_timer(&opl3->tlist, snd_opl3_timer_func, (unsigned long) opl3);
	spin_lock_init(&opl3->sys_timer_lock);
	opl3->sys_timer_status = 0;

#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS)
	snd_opl3_init_seq_oss(opl3, name);
#endif
	return 0;
}
예제 #11
0
/*
 * register client and create ports
 */
static int __init
register_client(void)
{
	struct snd_seq_dummy_port *rec1, *rec2;
	int i;

	if (ports < 1) {
		snd_printk(KERN_ERR "invalid number of ports %d\n", ports);
		return -EINVAL;
	}

	/* create client */
	my_client = snd_seq_create_kernel_client(NULL, SNDRV_SEQ_CLIENT_DUMMY,
						 "Midi Through");
	if (my_client < 0)
		return my_client;

	/* create ports */
	for (i = 0; i < ports; i++) {
		rec1 = create_port(i, 0);
		if (rec1 == NULL) {
			snd_seq_delete_kernel_client(my_client);
			return -ENOMEM;
		}
		if (duplex) {
			rec2 = create_port(i, 1);
			if (rec2 == NULL) {
				snd_seq_delete_kernel_client(my_client);
				return -ENOMEM;
			}
			rec1->connect = rec2->port;
			rec2->connect = rec1->port;
		}
	}

	return 0;
}
예제 #12
0
/* register new midi synth port */
int
snd_seq_midisynth_register_port(snd_seq_device_t *dev)
{
	seq_midisynth_client_t *client;
	seq_midisynth_t *msynth, *ms;
	snd_seq_port_info_t port;
	snd_rawmidi_info_t info;
	int newclient = 0, p, ports;
	snd_seq_client_callback_t callbacks;
	snd_seq_port_callback_t pcallbacks;
	snd_seq_client_info_t inf;
	snd_card_t *card = dev->card;
	int device = dev->device;
	unsigned int input_count = 0, output_count = 0;

	snd_assert(card != NULL && device >= 0 && device < SNDRV_RAWMIDI_DEVICES, return -EINVAL);
	info.device = device;
	info.stream = SNDRV_RAWMIDI_STREAM_OUTPUT;
	info.subdevice = 0;
	if (snd_rawmidi_info_select(card, &info) >= 0)
		output_count = info.subdevices_count;
	info.stream = SNDRV_RAWMIDI_STREAM_INPUT;
	if (snd_rawmidi_info_select(card, &info) >= 0) {
		input_count = info.subdevices_count;
	}
	ports = output_count;
	if (ports < input_count)
		ports = input_count;
	if (ports == 0)
		return -ENODEV;
	if (ports > (256 / SNDRV_RAWMIDI_DEVICES))
		ports = 256 / SNDRV_RAWMIDI_DEVICES;

	down(&register_mutex);
	client = synths[card->number];
	if (client == NULL) {
		newclient = 1;
		client = snd_kcalloc(sizeof(seq_midisynth_client_t), GFP_KERNEL);
		if (client == NULL) {
			up(&register_mutex);
			return -ENOMEM;
		}
		memset(&callbacks, 0, sizeof(callbacks));
		callbacks.private_data = client;
		callbacks.allow_input = callbacks.allow_output = 1;
		client->seq_client = snd_seq_create_kernel_client(card, 0, &callbacks);
		if (client->seq_client < 0) {
			kfree(client);
			up(&register_mutex);
			return -ENOMEM;
		}
		/* set our client name */
		memset(&inf,0,sizeof(snd_seq_client_info_t));
		inf.client = client->seq_client;
		inf.type = KERNEL_CLIENT;
		sprintf(inf.name, "External MIDI %i", card->number);
		snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &inf);
	}

	msynth = snd_kcalloc(sizeof(seq_midisynth_t) * ports, GFP_KERNEL);
	if (msynth == NULL)
		goto __nomem;

	for (p = 0; p < ports; p++) {
		ms = &msynth[p];

		if (snd_seq_midisynth_new(ms, card, device, p) < 0)
			goto __nomem;

		/* declare port */
		memset(&port, 0, sizeof(port));
		port.addr.client = client->seq_client;
		port.addr.port = device * (256 / SNDRV_RAWMIDI_DEVICES) + p;
		port.flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
		memset(&info, 0, sizeof(info));
		info.device = device;
		if (p < output_count)
			info.stream = SNDRV_RAWMIDI_STREAM_OUTPUT;
		else
			info.stream = SNDRV_RAWMIDI_STREAM_INPUT;
		info.subdevice = p;
		if (snd_rawmidi_info_select(card, &info) >= 0)
			strcpy(port.name, info.subname);
		if (! port.name[0]) {
			if (ports > 1)
				sprintf(port.name, "MIDI %d-%d-%d", card->number, device, p);
			else
				sprintf(port.name, "MIDI %d-%d", card->number, device);
		}
		if ((info.flags & SNDRV_RAWMIDI_INFO_OUTPUT) && p < output_count)
			port.capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
		if ((info.flags & SNDRV_RAWMIDI_INFO_INPUT) && p < input_count)
			port.capability |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SYNC_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ;
		if ((port.capability & (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ)) == (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ) &&
		    info.flags & SNDRV_RAWMIDI_INFO_DUPLEX)
			port.capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
		port.type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC;
		port.midi_channels = 16;
		memset(&pcallbacks, 0, sizeof(pcallbacks));
		pcallbacks.owner = THIS_MODULE;
		pcallbacks.private_data = ms;
		pcallbacks.subscribe = midisynth_subscribe;
		pcallbacks.unsubscribe = midisynth_unsubscribe;
		pcallbacks.use = midisynth_use;
		pcallbacks.unuse = midisynth_unuse;
		pcallbacks.event_input = event_process_midi;
		port.kernel = &pcallbacks;
		if (snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_CREATE_PORT, &port)<0)
			goto __nomem;
		ms->seq_client = client->seq_client;
		ms->seq_port = port.addr.port;
	}
	client->ports_per_device[device] = ports;
	client->ports[device] = msynth;
	client->num_ports++;
	if (newclient)
		synths[card->number] = client;
	up(&register_mutex);
	return 0;	/* success */

      __nomem:
	if (msynth != NULL) {
	      	for (p = 0; p < ports; p++)
	      		snd_seq_midisynth_delete(&msynth[p]);
		kfree(msynth);
	}
	if (newclient) {
		snd_seq_delete_kernel_client(client->seq_client);
		kfree(client);
	}
	up(&register_mutex);
	return -ENOMEM;
}
예제 #13
0
/* register new midi synth port */
static int
snd_seq_midisynth_register_port(struct snd_seq_device *dev)
{
	struct seq_midisynth_client *client;
	struct seq_midisynth *msynth, *ms;
	struct snd_seq_port_info *port;
	struct snd_rawmidi_info *info;
	struct snd_rawmidi *rmidi = dev->private_data;
	int newclient = 0;
	unsigned int p, ports;
	struct snd_seq_port_callback pcallbacks;
	struct snd_card *card = dev->card;
	int device = dev->device;
	unsigned int input_count = 0, output_count = 0;

	if (snd_BUG_ON(!card || device < 0 || device >= SNDRV_RAWMIDI_DEVICES))
		return -EINVAL;
	info = kmalloc(sizeof(*info), GFP_KERNEL);
	if (! info)
		return -ENOMEM;
	info->device = device;
	info->stream = SNDRV_RAWMIDI_STREAM_OUTPUT;
	info->subdevice = 0;
	if (snd_rawmidi_info_select(card, info) >= 0)
		output_count = info->subdevices_count;
	info->stream = SNDRV_RAWMIDI_STREAM_INPUT;
	if (snd_rawmidi_info_select(card, info) >= 0) {
		input_count = info->subdevices_count;
	}
	ports = output_count;
	if (ports < input_count)
		ports = input_count;
	if (ports == 0) {
		kfree(info);
		return -ENODEV;
	}
	if (ports > (256 / SNDRV_RAWMIDI_DEVICES))
		ports = 256 / SNDRV_RAWMIDI_DEVICES;

	mutex_lock(&register_mutex);
	client = synths[card->number];
	if (client == NULL) {
		newclient = 1;
		client = kzalloc(sizeof(*client), GFP_KERNEL);
		if (client == NULL) {
			mutex_unlock(&register_mutex);
			kfree(info);
			return -ENOMEM;
		}
		client->seq_client =
			snd_seq_create_kernel_client(
				card, 0, "%s", card->shortname[0] ?
				(const char *)card->shortname : "External MIDI");
		if (client->seq_client < 0) {
			kfree(client);
			mutex_unlock(&register_mutex);
			kfree(info);
			return -ENOMEM;
		}
	}

	msynth = kcalloc(ports, sizeof(struct seq_midisynth), GFP_KERNEL);
	port = kmalloc(sizeof(*port), GFP_KERNEL);
	if (msynth == NULL || port == NULL)
		goto __nomem;

	for (p = 0; p < ports; p++) {
		ms = &msynth[p];

		if (snd_seq_midisynth_new(ms, card, device, p) < 0)
			goto __nomem;

		/* declare port */
		memset(port, 0, sizeof(*port));
		port->addr.client = client->seq_client;
		port->addr.port = device * (256 / SNDRV_RAWMIDI_DEVICES) + p;
		port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
		memset(info, 0, sizeof(*info));
		info->device = device;
		if (p < output_count)
			info->stream = SNDRV_RAWMIDI_STREAM_OUTPUT;
		else
			info->stream = SNDRV_RAWMIDI_STREAM_INPUT;
		info->subdevice = p;
		if (snd_rawmidi_info_select(card, info) >= 0)
			strcpy(port->name, info->subname);
		if (! port->name[0]) {
			if (info->name[0]) {
				if (ports > 1)
					snprintf(port->name, sizeof(port->name), "%s-%d", info->name, p);
				else
					snprintf(port->name, sizeof(port->name), "%s", info->name);
			} else {
				/* last resort */
				if (ports > 1)
					sprintf(port->name, "MIDI %d-%d-%d", card->number, device, p);
				else
					sprintf(port->name, "MIDI %d-%d", card->number, device);
			}
		}
		if ((info->flags & SNDRV_RAWMIDI_INFO_OUTPUT) && p < output_count)
			port->capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
		if ((info->flags & SNDRV_RAWMIDI_INFO_INPUT) && p < input_count)
			port->capability |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SYNC_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ;
		if ((port->capability & (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ)) == (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ) &&
		    info->flags & SNDRV_RAWMIDI_INFO_DUPLEX)
			port->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
		port->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC
			| SNDRV_SEQ_PORT_TYPE_HARDWARE
			| SNDRV_SEQ_PORT_TYPE_PORT;
		port->midi_channels = 16;
		memset(&pcallbacks, 0, sizeof(pcallbacks));
		pcallbacks.owner = THIS_MODULE;
		pcallbacks.private_data = ms;
		pcallbacks.subscribe = midisynth_subscribe;
		pcallbacks.unsubscribe = midisynth_unsubscribe;
		pcallbacks.use = midisynth_use;
		pcallbacks.unuse = midisynth_unuse;
		pcallbacks.event_input = event_process_midi;
		port->kernel = &pcallbacks;
		if (rmidi->ops && rmidi->ops->get_port_info)
			rmidi->ops->get_port_info(rmidi, p, port);
		if (snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_CREATE_PORT, port)<0)
			goto __nomem;
		ms->seq_client = client->seq_client;
		ms->seq_port = port->addr.port;
	}
	client->ports_per_device[device] = ports;
	client->ports[device] = msynth;
	client->num_ports++;
	if (newclient)
		synths[card->number] = client;
	mutex_unlock(&register_mutex);
	kfree(info);
	kfree(port);
	return 0;	/* success */

      __nomem:
	if (msynth != NULL) {
	      	for (p = 0; p < ports; p++)
	      		snd_seq_midisynth_delete(&msynth[p]);
		kfree(msynth);
	}
	if (newclient) {
		snd_seq_delete_kernel_client(client->seq_client);
		kfree(client);
	}
	kfree(info);
	kfree(port);
	mutex_unlock(&register_mutex);
	return -ENOMEM;
}
예제 #14
0
/*
 * create sequencer client for OSS sequencer
 */
int __init
snd_seq_oss_create_client(void)
{
	int rc;
	snd_seq_client_callback_t callback;
	snd_seq_client_info_t info;
	snd_seq_port_info_t port;
	snd_seq_port_callback_t port_callback;

	/* create ALSA client */
	memset(&callback, 0, sizeof(callback));

	callback.private_data = NULL;
	callback.allow_input = 1;
	callback.allow_output = 1;

	rc = snd_seq_create_kernel_client(NULL, SNDRV_SEQ_CLIENT_OSS, &callback);
	if (rc < 0)
		return rc;

	system_client = rc;
	debug_printk(("new client = %d\n", rc));

	/* set client information */
	memset(&info, 0, sizeof(info));
	info.client = system_client;
	info.type = KERNEL_CLIENT;
	strcpy(info.name, "OSS sequencer");

	rc = call_ctl(SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &info);

	/* look up midi devices */
	snd_seq_oss_midi_lookup_ports(system_client);

	/* create annoucement receiver port */
	memset(&port, 0, sizeof(port));
	strcpy(port.name, "Receiver");
	port.addr.client = system_client;
	port.capability = SNDRV_SEQ_PORT_CAP_WRITE; /* receive only */
	port.type = 0;

	memset(&port_callback, 0, sizeof(port_callback));
	/* don't set port_callback.owner here. otherwise the module counter
	 * is incremented and we can no longer release the module..
	 */
	port_callback.event_input = receive_announce;
	port.kernel = &port_callback;
	
	call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, &port);
	if ((system_port = port.addr.port) >= 0) {
		snd_seq_port_subscribe_t subs;

		memset(&subs, 0, sizeof(subs));
		subs.sender.client = SNDRV_SEQ_CLIENT_SYSTEM;
		subs.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
		subs.dest.client = system_client;
		subs.dest.port = system_port;
		call_ctl(SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs);
	}


	return 0;
}
예제 #15
0
static int snd_gus_synth_new_device(snd_seq_device_t *dev)
{
    snd_gus_card_t *gus;
    int client, i;
    snd_seq_client_callback_t callbacks;
    snd_seq_client_info_t *cinfo;
    snd_seq_port_subscribe_t sub;
    snd_iwffff_ops_t *iwops;
    snd_gf1_ops_t *gf1ops;
    snd_simple_ops_t *simpleops;

    gus = *(snd_gus_card_t**)SNDRV_SEQ_DEVICE_ARGPTR(dev);
    if (gus == NULL)
        return -EINVAL;

    init_MUTEX(&gus->register_mutex);
    gus->gf1.seq_client = -1;

    cinfo = kmalloc(sizeof(*cinfo), GFP_KERNEL);
    if (! cinfo)
        return -ENOMEM;

    /* allocate new client */
    memset(&callbacks, 0, sizeof(callbacks));
    callbacks.private_data = gus;
    callbacks.allow_output = callbacks.allow_input = 1;
    client = gus->gf1.seq_client =
                 snd_seq_create_kernel_client(gus->card, 1, &callbacks);
    if (client < 0) {
        kfree(cinfo);
        return client;
    }

    /* change name of client */
    memset(cinfo, 0, sizeof(*cinfo));
    cinfo->client = client;
    cinfo->type = KERNEL_CLIENT;
    sprintf(cinfo->name, gus->interwave ? "AMD InterWave" : "GF1");
    snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, cinfo);
    kfree(cinfo);

    for (i = 0; i < 4; i++)
        snd_gus_synth_create_port(gus, i);

    gus->gf1.ilist = snd_seq_instr_list_new();
    if (gus->gf1.ilist == NULL) {
        snd_seq_delete_kernel_client(client);
        gus->gf1.seq_client = -1;
        return -ENOMEM;
    }
    gus->gf1.ilist->flags = SNDRV_SEQ_INSTR_FLG_DIRECT;

    simpleops = &gus->gf1.simple_ops;
    snd_seq_simple_init(simpleops, gus, NULL);
    simpleops->put_sample = snd_gus_simple_put_sample;
    simpleops->get_sample = snd_gus_simple_get_sample;
    simpleops->remove_sample = snd_gus_simple_remove_sample;
    simpleops->notify = snd_gus_synth_instr_notify;

    gf1ops = &gus->gf1.gf1_ops;
    snd_seq_gf1_init(gf1ops, gus, &simpleops->kops);
    gf1ops->put_sample = snd_gus_gf1_put_sample;
    gf1ops->get_sample = snd_gus_gf1_get_sample;
    gf1ops->remove_sample = snd_gus_gf1_remove_sample;
    gf1ops->notify = snd_gus_synth_instr_notify;

    iwops = &gus->gf1.iwffff_ops;
    snd_seq_iwffff_init(iwops, gus, &gf1ops->kops);
    iwops->put_sample = snd_gus_iwffff_put_sample;
    iwops->get_sample = snd_gus_iwffff_get_sample;
    iwops->remove_sample = snd_gus_iwffff_remove_sample;
    iwops->notify = snd_gus_synth_instr_notify;

    memset(&sub, 0, sizeof(sub));
    sub.sender.client = SNDRV_SEQ_CLIENT_SYSTEM;
    sub.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
    sub.dest.client = client;
    sub.dest.port = 0;
    snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &sub);

    return 0;
}
예제 #16
0
/*
 * register client and create port
 */
struct ALSADriver *ALSARegisterClient(void *drv)
{

	struct ALSADriver *driver;

	int ret, err;

	printk("registering alsa client\n");

	driver = kmalloc(sizeof(struct ALSADriver), GFP_KERNEL);

	driver->priv = kmalloc(sizeof(struct privateData), GFP_KERNEL);

	driver->priv->list.message = &(driver->priv->msg);
	driver->priv->list.next = NULL;
	driver->priv->drv = drv;

	err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(struct snd_card),
			      &(driver->card));
	if (err < 0) {
		pr_err("alsa error creating card: %d\n", err);
		goto fail_card;
	}

	/* create client */
	driver->client =
	    snd_seq_create_kernel_client(driver->card, 0, "AppleMidi");
	if (driver->client < 0) {
		pr_err("failed to register alsa client : %d\n", driver->client);
		goto fail_client;
	}

	/* create port */
	pr_debug("register alsa port\n");
	ret = _create_port(driver->client, 0, 0, driver->priv);
	if (ret < 0) {
		goto fail_port;
	}

	pr_debug("registering snd card\n");
	err = snd_card_register(driver->card);
	if (err < 0) {
		pr_err("failed to register card:err:%d\n", err);
		goto fail_port;
	}

	pr_debug("registered alsa client\n");

	return driver;

fail_port:
	snd_seq_delete_kernel_client(driver->client);

fail_client:
	snd_card_free(driver->card);

fail_card:
	kfree(driver->priv);
	kfree(driver);

	return (NULL);
}