Browse Source

removed ALSA MIDI client

tags/0.124.0
Paul Davis 10 years ago
parent
commit
71b91eeb81
13 changed files with 2 additions and 2734 deletions
  1. +2
    -10
      Makefile.am
  2. +0
    -13
      alsa_midi/Makefile.am
  3. +0
    -132
      alsa_midi/a2j.h
  4. +0
    -41
      alsa_midi/a2j_in.la
  5. +0
    -860
      alsa_midi/alsa_midi.c
  6. +0
    -147
      alsa_midi/list.c
  7. +0
    -903
      alsa_midi/list.h
  8. +0
    -217
      alsa_midi/port.c
  9. +0
    -29
      alsa_midi/port.h
  10. +0
    -63
      alsa_midi/port_hash.c
  11. +0
    -35
      alsa_midi/port_hash.h
  12. +0
    -235
      alsa_midi/port_thread.c
  13. +0
    -49
      alsa_midi/port_thread.h

+ 2
- 10
Makefile.am View File

@@ -1,11 +1,5 @@
MAINTAINERCLEANFILES = Makefile.in

if HAVE_ALSA_MIDI
ALSA_MIDI_DIR = alsa_midi
else
ALSA_MIDI_DIR =
endif

if HAVE_READLINE
JACK_TRANSPORT = jack_transport
dist-check-readline:
@@ -172,12 +166,10 @@ alsa_out_LDADD = $(top_builddir)/libjack/libjack.la
endif #HAVE_ALSA
endif #HAVE_SAMPLERATE

SUBDIRS = $(ALSA_MIDI_DIR)

#if HAVE_ZITA_BRIDGE_DEPS
SUBDIRS += zalsa
SUBDIRS = zalsa
#endif

DIST_SUBDIRS = alsa_midi zalsa
DIST_SUBDIRS = zalsa

# XXX ? dist-hook: dist-check-sndfile dist-check-samplerate

+ 0
- 13
alsa_midi/Makefile.am View File

@@ -1,13 +0,0 @@
MAINTAINERCLEANFILES = Makefile.in

#
# in-process ALSA/JACK MIDI bridge client
#

alsa_mididir = $(ADDON_DIR)

alsa_midi_LTLIBRARIES = alsa_midi.la
alsa_midi_la_LDFLAGS = -module -avoid-version @OS_LDFLAGS@
alsa_midi_la_SOURCES = alsa_midi.c port.c port_hash.c port_thread.c list.c

noinst_HEADERS = a2j.h list.h port.h port_hash.h port_thread.h

+ 0
- 132
alsa_midi/a2j.h View File

@@ -1,132 +0,0 @@
/* -*- Mode: C ; c-basic-offset: 2 -*- */
/*
* ALSA SEQ < - > JACK MIDI bridge
*
* Copyright (c) 2006,2007 Dmitry S. Baikov <c0ff@konstruktiv.org>
* Copyright (c) 2007,2008,2009 Nedko Arnaudov <nedko@arnaudov.name>
*
* 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; version 2 of the License.
*
* 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
*/

#ifndef __jack_alsa_midi_h__
#define __jack_alsa_midi_h__

#include <stdbool.h>
#include <semaphore.h>
#include <jack/midiport.h>

#define JACK_INVALID_PORT NULL

#define MAX_PORTS 2048
#define MAX_EVENT_SIZE 1024

#define PORT_HASH_BITS 4
#define PORT_HASH_SIZE (1 << PORT_HASH_BITS)

/* Beside enum use, these are indeces for (struct a2j).stream array */
#define A2J_PORT_CAPTURE 0 // ALSA playback port -> JACK capture port
#define A2J_PORT_PLAYBACK 1 // JACK playback port -> ALSA capture port

typedef struct a2j_port * a2j_port_hash_t[PORT_HASH_SIZE];

struct a2j;

struct a2j_port
{
struct a2j_port * next; /* hash - jack */
struct list_head siblings; /* list - main loop */
struct a2j * a2j_ptr;
bool is_dead;
char name[64];
snd_seq_addr_t remote;
jack_port_t * jack_port;
jack_ringbuffer_t * inbound_events; // alsa_midi_event_t + data
int64_t last_out_time;
void * jack_buf;
};

struct a2j_stream
{
snd_midi_event_t *codec;
jack_ringbuffer_t *new_ports;
a2j_port_hash_t port_hash;
struct list_head list;
};

struct a2j
{
jack_client_t * jack_client;
snd_seq_t *seq;
pthread_t alsa_input_thread;
pthread_t alsa_output_thread;
int client_id;
int port_id;
int queue;
bool freewheeling;
bool running;
bool finishing;

jack_ringbuffer_t* port_add; // snd_seq_addr_t
jack_ringbuffer_t* port_del; // struct a2j_port*
jack_ringbuffer_t* outbound_events; // struct a2j_delivery_event
jack_nframes_t cycle_start;
sem_t output_semaphore;

struct a2j_stream stream[2];
};

#define NSEC_PER_SEC ((int64_t)1000*1000*1000)

struct a2j_alsa_midi_event
{
int64_t time;
int size;
};

#define MAX_JACKMIDI_EV_SIZE 16

struct a2j_delivery_event
{
struct list_head siblings;
/* a jack MIDI event, plus the port its destined for: everything
the ALSA output thread needs to deliver the event. time is
part of the jack_event.
*/
jack_midi_event_t jack_event;
jack_nframes_t time; /* realtime, not offset time */
struct a2j_port* port;
char midistring[MAX_JACKMIDI_EV_SIZE];
};

void a2j_error (const char* fmt, ...);

#define A2J_DEBUG
/*#undef A2J_DEBUG*/

#ifdef A2J_DEBUG
extern bool a2j_do_debug;
extern void _a2j_debug (const char* fmt, ...);
#define a2j_debug(fmt, ...) if (a2j_do_debug) { _a2j_debug ((fmt), ##__VA_ARGS__); }
#else
#define a2j_debug(fmt,...)
#endif

#endif /* __jack_alsa_midi_h__ */

+ 0
- 41
alsa_midi/a2j_in.la View File

@@ -1,41 +0,0 @@
# a2j_in.la - a libtool library file
# Generated by ltmain.sh (GNU libtool) 2.2.6b
#
# Please DO NOT delete this file!
# It is necessary for linking the library.

# The name that we can dlopen(3).
dlname='a2j_in.so'

# Names of this library.
library_names='a2j_in.so a2j_in.so a2j_in.so'

# The name of the static archive.
old_library=''

# Linker flags that can not go in dependency_libs.
inherited_linker_flags=''

# Libraries that this one depends upon.
dependency_libs=' -lrt -lm -lpthread -ldl -luuid'

# Names of additional weak libraries provided by this library
weak_library_names=''

# Version information for a2j_in.
current=0
age=0
revision=0

# Is this an already installed library?
installed=no

# Should we warn about portability when linking against -modules?
shouldnotlink=yes

# Files to dlopen/dlpreopen
dlopen=''
dlpreopen=''

# Directory that this library needs to be installed in:
libdir='/usr/lib64/jack'

+ 0
- 860
alsa_midi/alsa_midi.c View File

@@ -1,860 +0,0 @@
/* -*- Mode: C ; c-basic-offset: 2 -*- */
/*
* ALSA SEQ < - > JACK MIDI bridge
*
* Copyright (c) 2006,2007 Dmitry S. Baikov <c0ff@konstruktiv.org>
* Copyright (c) 2007,2008,2009 Nedko Arnaudov <nedko@arnaudov.name>
* Copyright (c) 2009,2010,2013 Paul Davis <paul@linuxaudiosystems.com>
*
* 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; version 2 of the License.
*
* 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 <stdbool.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
#include <alsa/asoundlib.h>
#include <jack/jack.h>
#include <jack/midiport.h>
#include <jack/ringbuffer.h>

#include "list.h"
#include "a2j.h"
#include "port_hash.h"
#include "port.h"
#include "port_thread.h"

#ifdef A2J_DEBUG
bool a2j_do_debug = false;

void
_a2j_debug (const char* fmt, ...)
{
va_list ap;
va_start (ap, fmt);
vfprintf (stderr, fmt, ap);
fputc ('\n', stdout);
}
#endif

void
a2j_error (const char* fmt, ...)
{
va_list ap;
va_start (ap, fmt);
vfprintf (stdout, fmt, ap);
fputc ('\n', stdout);
}

static bool
a2j_stream_init(struct a2j * self, int which)
{
struct a2j_stream *str = &self->stream[which];
str->new_ports = jack_ringbuffer_create (MAX_PORTS * sizeof(struct a2j_port *));
if (str->new_ports == NULL) {
return false;
}
snd_midi_event_new (MAX_EVENT_SIZE, &str->codec);
INIT_LIST_HEAD (&str->list);
return true;
}

static void
a2j_stream_detach (struct a2j_stream * stream_ptr)
{
struct a2j_port * port_ptr;
struct list_head * node_ptr;

while (!list_empty (&stream_ptr->list)) {
node_ptr = stream_ptr->list.next;
list_del (node_ptr);
port_ptr = list_entry (node_ptr, struct a2j_port, siblings);
a2j_debug ("port deleted: %s", port_ptr->name);
a2j_port_free (port_ptr);
}
}

static
void
a2j_stream_close (struct a2j * self, int which)
{
struct a2j_stream *str = &self->stream[which];

if (str->codec)
snd_midi_event_free (str->codec);
if (str->new_ports)
jack_ringbuffer_free (str->new_ports);
}

static void
stop_threads (struct a2j* self)
{
if (self->running) {
void* thread_status;

self->running = false; /* tell alsa io thread to stop, whenever they wake up */
/* do something that we need to do anyway and will wake the io thread, then join */
snd_seq_disconnect_from (self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE);
a2j_debug ("wait for ALSA input thread\n");
pthread_join (self->alsa_input_thread, &thread_status);
a2j_debug ("input thread done\n");
/* wake output thread and join */
sem_post(&self->output_semaphore);
pthread_join(self->alsa_output_thread, &thread_status);
a2j_debug ("output thread done\n");
}
}

/*
* =================== Input/output port handling =========================
*/

void a2j_add_ports (struct a2j_stream * str)
{
struct a2j_port * port_ptr;
while (jack_ringbuffer_read (str->new_ports, (char *)&port_ptr, sizeof(port_ptr))) {
a2j_debug("jack: inserted port %s", port_ptr->name);
a2j_port_insert (str->port_hash, port_ptr);
}
}

static
void
a2j_port_event (struct a2j * self, snd_seq_event_t * ev)
{
const snd_seq_addr_t addr = ev->data.addr;

if (addr.client == self->client_id)
return;

if (ev->type == SND_SEQ_EVENT_PORT_START || ev->type == SND_SEQ_EVENT_PORT_CHANGE) {
if (jack_ringbuffer_write_space(self->port_add) >= sizeof(addr)) {
a2j_debug("port_event: add/change %d:%d", addr.client, addr.port);
jack_ringbuffer_write(self->port_add, (char*)&addr, sizeof(addr));
} else {
a2j_error("dropping port_event: add/change %d:%d", addr.client, addr.port);
}
} else if (ev->type == SND_SEQ_EVENT_PORT_EXIT) {
a2j_debug("port_event: del %d:%d", addr.client, addr.port);
a2j_port_setdead(self->stream[A2J_PORT_CAPTURE].port_hash, addr);
a2j_port_setdead(self->stream[A2J_PORT_PLAYBACK].port_hash, addr);
}
}

/* --- INBOUND FROM ALSA TO JACK ---- */

static void
a2j_input_event (struct a2j * self, snd_seq_event_t * alsa_event)
{
jack_midi_data_t data[MAX_EVENT_SIZE];
struct a2j_stream *str = &self->stream[A2J_PORT_CAPTURE];
long size;
struct a2j_port *port;
jack_nframes_t now;

now = jack_frame_time (self->jack_client);
if ((port = a2j_port_get(str->port_hash, alsa_event->source)) == NULL) {
return;
}

/*
* RPNs, NRPNs, Bank Change, etc. need special handling
* but seems, ALSA does it for us already.
*/
snd_midi_event_reset_decode(str->codec);
if ((size = snd_midi_event_decode(str->codec, data, sizeof(data), alsa_event))<0) {
return;
}

// fixup NoteOn with vel 0
if ((data[0] & 0xF0) == 0x90 && data[2] == 0x00) {
data[0] = 0x80 + (data[0] & 0x0F);
data[2] = 0x40;
}

a2j_debug("input: %d bytes at event_frame=%u", (int)size, now);

if (jack_ringbuffer_write_space(port->inbound_events) >= (sizeof(struct a2j_alsa_midi_event) + size)) {
struct a2j_alsa_midi_event ev;
char *ev_charp = (char*) &ev;
size_t limit;
size_t to_write = sizeof(ev);

jack_ringbuffer_data_t vec[2];
jack_ringbuffer_get_write_vector( port->inbound_events, vec );
ev.time = now;
ev.size = size;

limit = (to_write > vec[0].len ? vec[0].len : to_write);
if (limit) {
memcpy( vec[0].buf, ev_charp, limit );
to_write -= limit;
ev_charp += limit;
vec[0].buf += limit;
vec[0].len -= limit;
}
if (to_write) {
memcpy( vec[1].buf, ev_charp, to_write );
vec[1].buf += to_write;
vec[1].len -= to_write;
}

to_write = size;
ev_charp = (char *)data;
limit = (to_write > vec[0].len ? vec[0].len : to_write);
if (limit) {
memcpy (vec[0].buf, ev_charp, limit);
}
to_write -= limit;
ev_charp += limit;
if (to_write) {
memcpy (vec[1].buf, ev_charp, to_write);
}

jack_ringbuffer_write_advance( port->inbound_events, sizeof(ev) + size );
} else {
a2j_error ("MIDI data lost (incoming event buffer full): %ld bytes lost", size);
}

}

static int
a2j_process_incoming (struct a2j* self, struct a2j_port* port, jack_nframes_t nframes)
{
jack_nframes_t one_period;
struct a2j_alsa_midi_event ev;
char *ev_buf;

/* grab data queued by the ALSA input thread and write it into the JACK
port buffer. it will delivered during the JACK period that this
function is called from.
*/
/* first clear the JACK port buffer in preparation for new data
*/
a2j_debug ("PORT: %s process input", jack_port_name (port->jack_port));
jack_midi_clear_buffer (port->jack_buf);
one_period = jack_get_buffer_size (self->jack_client);
while (jack_ringbuffer_peek (port->inbound_events, (char*)&ev, sizeof(ev) ) == sizeof(ev) ) {
jack_midi_data_t* buf;
jack_nframes_t offset;
if (ev.time >= self->cycle_start) {
break;
}
//jack_ringbuffer_read_advance (port->inbound_events, sizeof (ev));
ev_buf = (char *) alloca( sizeof(ev) + ev.size );
if (jack_ringbuffer_peek (port->inbound_events, ev_buf, sizeof(ev) + ev.size ) != sizeof(ev) + ev.size)
break;
offset = self->cycle_start - ev.time;
if (offset > one_period) {
/* from a previous cycle, somehow. cram it in at the front */
offset = 0;
} else {
/* offset from start of the current cycle */
offset = one_period - offset;
}
a2j_debug ("event at %d offset %d", ev.time, offset);
/* make sure there is space for it */
buf = jack_midi_event_reserve (port->jack_buf, offset, ev.size);
if (buf) {
/* grab the event */
memcpy( buf, ev_buf + sizeof(ev), ev.size );
} else {
/* throw it away (no space) */
a2j_error ("threw away MIDI event - not reserved at time %d", ev.time);
}
jack_ringbuffer_read_advance (port->inbound_events, sizeof(ev) + ev.size);
a2j_debug("input on %s: sucked %d bytes from inbound at %d", jack_port_name (port->jack_port), ev.size, ev.time);
}
return 0;
}

void*
alsa_input_thread (void* arg)
{
struct a2j * self = arg;
int npfd;
struct pollfd * pfd;
snd_seq_addr_t addr;
snd_seq_client_info_t * client_info;
snd_seq_port_info_t * port_info;
bool initial;
snd_seq_event_t * event;
int ret;

npfd = snd_seq_poll_descriptors_count(self->seq, POLLIN);
pfd = (struct pollfd *)alloca(npfd * sizeof(struct pollfd));
snd_seq_poll_descriptors(self->seq, pfd, npfd, POLLIN);

initial = true;

while (self->running) {
if ((ret = poll(pfd, npfd, 1000)) > 0) {

while (snd_seq_event_input (self->seq, &event) > 0) {
if (initial) {
snd_seq_client_info_alloca(&client_info);
snd_seq_port_info_alloca(&port_info);
snd_seq_client_info_set_client(client_info, -1);
while (snd_seq_query_next_client(self->seq, client_info) >= 0) {
addr.client = snd_seq_client_info_get_client(client_info);
if (addr.client == SND_SEQ_CLIENT_SYSTEM || addr.client == self->client_id) {
continue;
}
snd_seq_port_info_set_client(port_info, addr.client);
snd_seq_port_info_set_port(port_info, -1);
while (snd_seq_query_next_port(self->seq, port_info) >= 0) {
addr.port = snd_seq_port_info_get_port(port_info);
a2j_update_port(self, addr, port_info);
}
}

initial = false;
}

if (event->source.client == SND_SEQ_CLIENT_SYSTEM) {
a2j_port_event(self, event);
} else {
a2j_input_event(self, event);
}

snd_seq_free_event (event);
}
}
}

return (void*) 0;
}

/* --- OUTBOUND FROM JACK TO ALSA ---- */

int
a2j_process_outgoing (
struct a2j * self,
struct a2j_port * port)
{
/* collect data from JACK port buffer and queue it for delivery by ALSA output thread */
int nevents;
jack_ringbuffer_data_t vec[2];
int i;
int written = 0;
size_t limit;
struct a2j_delivery_event* dev;
size_t gap = 0;

jack_ringbuffer_get_write_vector (self->outbound_events, vec);

dev = (struct a2j_delivery_event*) vec[0].buf;
limit = vec[0].len / sizeof (struct a2j_delivery_event);
nevents = jack_midi_get_event_count (port->jack_buf);

for (i = 0; (i < nevents) && (written < limit); ++i) {

jack_midi_event_get (&dev->jack_event, port->jack_buf, i);
if (dev->jack_event.size <= MAX_JACKMIDI_EV_SIZE)
{
dev->time = dev->jack_event.time;
dev->port = port;
memcpy( dev->midistring, dev->jack_event.buffer, dev->jack_event.size );
written++;
++dev;
}
}

/* anything left? use the second part of the vector, as much as possible */

if (i < nevents)
{
if (vec[0].len)
{
gap = vec[0].len - written * sizeof(struct a2j_delivery_event);
}

dev = (struct a2j_delivery_event*) vec[1].buf;

limit += (vec[1].len / sizeof (struct a2j_delivery_event));

while ((i < nevents) && (written < limit))
{
jack_midi_event_get(&dev->jack_event, port->jack_buf, i);
if (dev->jack_event.size <= MAX_JACKMIDI_EV_SIZE)
{
dev->time = dev->jack_event.time;
dev->port = port;
memcpy(dev->midistring, dev->jack_event.buffer, dev->jack_event.size);
written++;
++dev;
}
++i;
}
}

a2j_debug( "done pushing events: %d ... gap: %d ", (int)written, (int)gap );
/* clear JACK port buffer; advance ring buffer ptr */

jack_ringbuffer_write_advance (self->outbound_events, written * sizeof (struct a2j_delivery_event) + gap);

return nevents;
}

static int
time_sorter (struct a2j_delivery_event * a, struct a2j_delivery_event * b)
{
if (a->time < b->time) {
return -1;
} else if (a->time > b->time) {
return 1;
}
return 0;
}

static void*
alsa_output_thread(void * arg)
{
struct a2j * self = (struct a2j*) arg;
struct a2j_stream *str = &self->stream[A2J_PORT_PLAYBACK];
int i;
struct list_head evlist;
struct list_head * node_ptr;
jack_ringbuffer_data_t vec[2];
snd_seq_event_t alsa_event;
struct a2j_delivery_event* ev;
float sr;
jack_nframes_t now;
int err;
int limit;

while (self->running) {
/* first, make a list of all events in the outbound_events FIFO */
INIT_LIST_HEAD(&evlist);

jack_ringbuffer_get_read_vector (self->outbound_events, vec);

a2j_debug ("output thread: got %d+%d events",
(vec[0].len / sizeof (struct a2j_delivery_event)),
(vec[1].len / sizeof (struct a2j_delivery_event)));
ev = (struct a2j_delivery_event*) vec[0].buf;
limit = vec[0].len / sizeof (struct a2j_delivery_event);
for (i = 0; i < limit; ++i) {
list_add_tail(&ev->siblings, &evlist);
ev++;
}

ev = (struct a2j_delivery_event*) vec[1].buf;
limit = vec[1].len / sizeof (struct a2j_delivery_event);
for (i = 0; i < limit; ++i) {
list_add_tail(&ev->siblings, &evlist);
ev++;
}

if (vec[0].len < sizeof(struct a2j_delivery_event) && (vec[1].len == 0)) {
/* no events: wait for some */
a2j_debug ("output thread: wait for events");
sem_wait (&self->output_semaphore);
a2j_debug ("output thread: AWAKE ... loop back for events");
continue;
}

/* now sort this list by time */

list_sort(&evlist, struct a2j_delivery_event, siblings, time_sorter);

/* now deliver */

sr = jack_get_sample_rate (self->jack_client);

list_for_each(node_ptr, &evlist)
{
ev = list_entry(node_ptr, struct a2j_delivery_event, siblings);

snd_seq_ev_clear(&alsa_event);
snd_midi_event_reset_encode(str->codec);
if (!snd_midi_event_encode(str->codec, (const unsigned char *)ev->midistring, ev->jack_event.size, &alsa_event))
{
continue; // invalid event
}
snd_seq_ev_set_source(&alsa_event, self->port_id);
snd_seq_ev_set_dest(&alsa_event, ev->port->remote.client, ev->port->remote.port);
snd_seq_ev_set_direct (&alsa_event);
now = jack_frame_time (self->jack_client);

ev->time += self->cycle_start;

a2j_debug ("@ %d, next event @ %d", now, ev->time);
/* do we need to wait a while before delivering? */

if (ev->time > now) {
struct timespec nanoseconds;
jack_nframes_t sleep_frames = ev->time - now;
float seconds = sleep_frames / sr;

/* if the gap is long enough, sleep */

if (seconds > 0.001) {
nanoseconds.tv_sec = (time_t) seconds;
nanoseconds.tv_nsec = (long) NSEC_PER_SEC * (seconds - nanoseconds.tv_sec);
a2j_debug ("output thread sleeps for %.2f msec", ((double) nanoseconds.tv_nsec / NSEC_PER_SEC) * 1000.0);

if (nanosleep (&nanoseconds, NULL) < 0) {
fprintf (stderr, "BAD SLEEP\n");
/* do something ? */
}
}
}
/* its time to deliver */
err = snd_seq_event_output(self->seq, &alsa_event);
snd_seq_drain_output (self->seq);
now = jack_frame_time (self->jack_client);
a2j_debug("alsa_out: written %d bytes to %s at %d, DELTA = %d", ev->jack_event.size, ev->port->name, now,
(int32_t) (now - ev->time));
}

/* free up space in the FIFO */
jack_ringbuffer_read_advance (self->outbound_events, vec[0].len + vec[1].len);

/* and head back for more */
}

return (void*) 0;
}

/** CORE JACK PROCESSING */


/* ALSA */

static void
a2j_jack_process_internal (struct a2j * self, int dir, jack_nframes_t nframes)
{
struct a2j_stream * stream_ptr;
int i;
struct a2j_port ** port_ptr_ptr;
struct a2j_port * port_ptr;
int nevents = 0;

stream_ptr = &self->stream[dir];
a2j_add_ports(stream_ptr);

// process ports
for (i = 0 ; i < PORT_HASH_SIZE ; i++)
{
port_ptr_ptr = &stream_ptr->port_hash[i];
while (*port_ptr_ptr != NULL)
{
port_ptr = *port_ptr_ptr;

if (!port_ptr->is_dead) {
port_ptr->jack_buf = jack_port_get_buffer(port_ptr->jack_port, nframes);
if (dir == A2J_PORT_CAPTURE) {
a2j_process_incoming (self, port_ptr, nframes);
} else {
nevents += a2j_process_outgoing (self, port_ptr);
}
} else if (jack_ringbuffer_write_space (self->port_del) >= sizeof(port_ptr)) {
a2j_debug("jack: removed port %s", port_ptr->name);
*port_ptr_ptr = port_ptr->next;
jack_ringbuffer_write(self->port_del, (char*)&port_ptr, sizeof(port_ptr));
continue;
}

port_ptr_ptr = &port_ptr->next;
}
}

if (dir == A2J_PORT_PLAYBACK && nevents > 0) {
int sv;

/* if we queued up anything for output, tell the output thread in
case its waiting for us.
*/
sem_getvalue (&self->output_semaphore, &sv);
sem_post (&self->output_semaphore);
}
}

static int
a2j_process(jack_nframes_t nframes, void * arg)
{
struct a2j* self = (struct a2j *) arg;
if (self->freewheeling) {
return 0;
}

self->cycle_start = jack_last_frame_time (self->jack_client);

a2j_jack_process_internal (self, A2J_PORT_CAPTURE, nframes);
a2j_jack_process_internal (self, A2J_PORT_PLAYBACK, nframes);

return 0;
}

/* --- */

static
void
a2j_freewheel(int starting, void * arg)
{
struct a2j* self = (struct a2j*) arg;
self->freewheeling = starting;
}

static
void
a2j_shutdown (void * arg)
{
struct a2j* self = (struct a2j*) self;
a2j_debug ("JACK server shutdown notification received.");
stop_threads (self);
}

int
connect_to_alsa (struct a2j* self)
{
int error;
void* thread_status;

self->port_add = jack_ringbuffer_create (2 * MAX_PORTS * sizeof(snd_seq_addr_t));

if (self->port_add == NULL) {
goto free_self;
}

self->port_del = jack_ringbuffer_create(2 * MAX_PORTS * sizeof(struct a2j_port *));
if (self->port_del == NULL) {
goto free_ringbuffer_add;
}

self->outbound_events = jack_ringbuffer_create (MAX_EVENT_SIZE * 16 * sizeof(struct a2j_delivery_event));
if (self->outbound_events == NULL) {
goto free_ringbuffer_del;
}
if (!a2j_stream_init (self, A2J_PORT_CAPTURE)) {
goto free_ringbuffer_outbound;
}

if (!a2j_stream_init (self, A2J_PORT_PLAYBACK)) {
goto close_capture_stream;
}

if ((error = snd_seq_open(&self->seq, "hw", SND_SEQ_OPEN_DUPLEX, 0)) < 0) {
a2j_error("failed to open alsa seq");
goto close_playback_stream;
}

if ((error = snd_seq_set_client_name(self->seq, "jackmidi")) < 0) {
a2j_error("snd_seq_set_client_name() failed");
goto close_seq_client;
}

if ((self->port_id = snd_seq_create_simple_port(
self->seq,
"port",
SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_WRITE
#ifndef DEBUG
|SND_SEQ_PORT_CAP_NO_EXPORT
#endif
,SND_SEQ_PORT_TYPE_APPLICATION)) < 0) {

a2j_error("snd_seq_create_simple_port() failed");
goto close_seq_client;
}

if ((self->client_id = snd_seq_client_id(self->seq)) < 0) {
a2j_error("snd_seq_client_id() failed");
goto close_seq_client;
}
if ((self->queue = snd_seq_alloc_queue(self->seq)) < 0) {
a2j_error("snd_seq_alloc_queue() failed");
goto close_seq_client;
}

snd_seq_start_queue (self->seq, self->queue, 0);

if ((error = snd_seq_nonblock(self->seq, 1)) < 0) {
a2j_error("snd_seq_nonblock() failed");
goto close_seq_client;
}

snd_seq_drop_input (self->seq);

a2j_add_ports(&self->stream[A2J_PORT_CAPTURE]);
a2j_add_ports(&self->stream[A2J_PORT_PLAYBACK]);

if (sem_init(&self->output_semaphore, 0, 0) < 0) {
a2j_error("can't create IO semaphore");
goto close_jack_client;
}

self->running = true;

if (pthread_create(&self->alsa_input_thread, NULL, alsa_input_thread, self) < 0) {
a2j_error("cannot start ALSA input thread");
goto sem_destroy;
}

/* wake the poll loop in the alsa input thread so initial ports are fetched */
if ((error = snd_seq_connect_from (self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE)) < 0) {
a2j_error("snd_seq_connect_from() failed");
goto join_input_thread;
}

if (pthread_create(&self->alsa_output_thread, NULL, alsa_output_thread, self) < 0) {
a2j_error("cannot start ALSA input thread");
goto sem_destroy;
}

return 0;

/* error handling */

self->running = false; /* tell alsa threads to stop */
self->finishing = false;

snd_seq_disconnect_from(self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE);
join_input_thread:
pthread_join (self->alsa_input_thread, &thread_status);
sem_destroy:
sem_destroy (&self->output_semaphore);
close_jack_client:
if ((error = jack_client_close(self->jack_client)) < 0) {
a2j_error("Cannot close jack client");
}
close_seq_client:
snd_seq_close(self->seq);
close_playback_stream:
a2j_stream_close(self, A2J_PORT_PLAYBACK);
close_capture_stream:
a2j_stream_close(self, A2J_PORT_CAPTURE);
free_ringbuffer_outbound:
jack_ringbuffer_free(self->outbound_events);
free_ringbuffer_del:
jack_ringbuffer_free(self->port_del);
free_ringbuffer_add:
jack_ringbuffer_free(self->port_add);
free_self:
free(self);
return -1;
}

/* JACK internal client API: 2 entry points
*/

int
jack_initialize (jack_client_t *client, const char* load_init)
{
struct a2j* self = calloc(1, sizeof(struct a2j));

if (!self) {
return -1;
}

self->jack_client = client;

if (load_init) {
char* args = strdup (load_init);
char* token;
char* ptr = args;
char* savep;

while (1) {
if ((token = strtok_r (ptr, ", ", &savep)) == NULL) {
break;
}

#ifdef A2J_DEBUG
if (strncasecmp (token, "debug", 2) == 0) {
a2j_do_debug = true;
}
#endif

ptr = NULL;
}

free (args);
}

if (connect_to_alsa (self)) {
free (self);
return -1;
}

jack_set_process_callback (client, a2j_process, self);
jack_set_freewheel_callback (client, a2j_freewheel, self);
jack_on_shutdown (client, a2j_shutdown, self);

jack_activate (client);

return 0;
}

void
jack_finish (void *arg)
{
struct a2j* self = (struct a2j*) arg;

self->finishing = true;

stop_threads (self);
sem_destroy(&self->output_semaphore);
jack_ringbuffer_reset (self->port_add);
a2j_stream_detach (&self->stream[A2J_PORT_CAPTURE]);
a2j_stream_detach (&self->stream[A2J_PORT_PLAYBACK]);
snd_seq_close(self->seq);
self->seq = NULL;
a2j_stream_close (self, A2J_PORT_CAPTURE);
a2j_stream_close (self, A2J_PORT_PLAYBACK);
jack_ringbuffer_free(self->outbound_events);
jack_ringbuffer_free(self->port_add);
jack_ringbuffer_free(self->port_del);
free (self);
}

+ 0
- 147
alsa_midi/list.c View File

@@ -1,147 +0,0 @@
/* -*- Mode: C ; c-basic-offset: 2 -*- */
/*****************************************************************************
*
* list_sort() adapted from linux kernel.
*
* 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; version 2 of the License
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
*****************************************************************************/

#include <assert.h>

#include "list.h"

/* list sort from Mark J Roberts (mjr@znex.org) */
void
__list_sort(
struct list_head *head,
int member_offset,
int (*cmp)(void * a, void * b))
{
struct list_head *p, *q, *e, *list, *tail, *oldhead;
int insize, nmerges, psize, qsize, i;

list = head->next;
list_del(head);
insize = 1;
for (;;) {
p = oldhead = list;
list = tail = NULL;
nmerges = 0;

while (p) {
nmerges++;
q = p;
psize = 0;
for (i = 0; i < insize; i++) {
psize++;
q = q->next == oldhead ? NULL : q->next;
if (!q)
break;
}

qsize = insize;
while (psize > 0 || (qsize > 0 && q)) {
if (!psize) {
e = q;
q = q->next;
qsize--;
if (q == oldhead)
q = NULL;
} else if (!qsize || !q) {
e = p;
p = p->next;
psize--;
if (p == oldhead)
p = NULL;
} else if (cmp((void *)p - member_offset, (void *)q - member_offset) <= 0) {
e = p;
p = p->next;
psize--;
if (p == oldhead)
p = NULL;
} else {
e = q;
q = q->next;
qsize--;
if (q == oldhead)
q = NULL;
}
if (tail)
tail->next = e;
else
list = e;
e->prev = tail;
tail = e;
}
p = q;
}

tail->next = list;
list->prev = tail;

if (nmerges <= 1)
break;

insize *= 2;
}

head->next = list;
head->prev = list->prev;
list->prev->next = head;
list->prev = head;
}

struct test_list_el {
int value;
struct list_head test_list_node;
};

int test_list_sort_comparator(struct test_list_el * e1, struct test_list_el * e2)
{
return e1->value - e2->value;
}

void test_list_sort(void)
{
struct list_head test_list;
struct test_list_el *el, *next;
struct test_list_el te1 = {.value = 1};
struct test_list_el te2 = {.value = 2};
struct test_list_el te3 = {.value = 3};
struct test_list_el te4 = {.value = 4};
struct test_list_el te5 = {.value = 5};
struct test_list_el te6 = {.value = 6};
struct test_list_el te7 = {.value = 7};

const int expected[] = {1, 2, 3, 4, 5, 6, 7};
int i;

INIT_LIST_HEAD(&test_list);
list_add_tail(&te2.test_list_node, &test_list);
list_add_tail(&te6.test_list_node, &test_list);
list_add_tail(&te4.test_list_node, &test_list);
list_add_tail(&te5.test_list_node, &test_list);
list_add_tail(&te7.test_list_node, &test_list);
list_add_tail(&te1.test_list_node, &test_list);
list_add_tail(&te3.test_list_node, &test_list);

list_sort(&test_list, struct test_list_el, test_list_node, test_list_sort_comparator);

i = 0;
list_for_each_entry_safe(el, next, &test_list, test_list_node) {
assert(el->value == expected[i]);
i++;
}
}

+ 0
- 903
alsa_midi/list.h View File

@@ -1,903 +0,0 @@
/* -*- Mode: C ; c-basic-offset: 2 -*- */
/*****************************************************************************
*
* Linux kernel header adapted for user-mode
* The 2.6.17-rt1 version was used.
*
* Original copyright holders of this code are unknown, they were not
* mentioned in the original file.
*
* 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; version 2 of the License
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
*****************************************************************************/

#ifndef _LINUX_LIST_H
#define _LINUX_LIST_H

#include <stddef.h>

#if !defined(offsetof)
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif

/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})

#define prefetch(x) (x = x)

/*
* These are non-NULL pointers that will result in page faults
* under normal circumstances, used to verify that nobody uses
* non-initialized list entries.
*/
#define LIST_POISON1 ((void *) 0x00100100)
#define LIST_POISON2 ((void *) 0x00200200)

/*
* Simple doubly linked list implementation.
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/

struct list_head {
struct list_head *next, *prev;
};

#define LIST_HEAD_INIT(name) { &(name), &(name) }

#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)

static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}

/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}

/**
* list_add - add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}

/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}

/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_add_rcu(struct list_head * new,
struct list_head * prev, struct list_head * next)
{
new->next = next;
new->prev = prev;
// smp_wmb();
next->prev = new;
prev->next = new;
}

/**
* list_add_rcu - add a new entry to rcu-protected list
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*
* The caller must take whatever precautions are necessary
* (such as holding appropriate locks) to avoid racing
* with another list-mutation primitive, such as list_add_rcu()
* or list_del_rcu(), running on this same list.
* However, it is perfectly legal to run concurrently with
* the _rcu list-traversal primitives, such as
* list_for_each_entry_rcu().
*/
static inline void list_add_rcu(struct list_head *new, struct list_head *head)
{
__list_add_rcu(new, head, head->next);
}

/**
* list_add_tail_rcu - add a new entry to rcu-protected list
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*
* The caller must take whatever precautions are necessary
* (such as holding appropriate locks) to avoid racing
* with another list-mutation primitive, such as list_add_tail_rcu()
* or list_del_rcu(), running on this same list.
* However, it is perfectly legal to run concurrently with
* the _rcu list-traversal primitives, such as
* list_for_each_entry_rcu().
*/
static inline void list_add_tail_rcu(struct list_head *new,
struct list_head *head)
{
__list_add_rcu(new, head->prev, head);
}

/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
next->prev = prev;
prev->next = next;
}

/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty on entry does not return true after this, the entry is
* in an undefined state.
*/
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = LIST_POISON1;
entry->prev = LIST_POISON2;
}

/**
* list_del_rcu - deletes entry from list without re-initialization
* @entry: the element to delete from the list.
*
* Note: list_empty on entry does not return true after this,
* the entry is in an undefined state. It is useful for RCU based
* lockfree traversal.
*
* In particular, it means that we can not poison the forward
* pointers that may still be used for walking the list.
*
* The caller must take whatever precautions are necessary
* (such as holding appropriate locks) to avoid racing
* with another list-mutation primitive, such as list_del_rcu()
* or list_add_rcu(), running on this same list.
* However, it is perfectly legal to run concurrently with
* the _rcu list-traversal primitives, such as
* list_for_each_entry_rcu().
*
* Note that the caller is not permitted to immediately free
* the newly deleted entry. Instead, either synchronize_rcu()
* or call_rcu() must be used to defer freeing until an RCU
* grace period has elapsed.
*/
static inline void list_del_rcu(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->prev = LIST_POISON2;
}

/*
* list_replace_rcu - replace old entry by new one
* @old : the element to be replaced
* @new : the new element to insert
*
* The old entry will be replaced with the new entry atomically.
*/
static inline void list_replace_rcu(struct list_head *old,
struct list_head *new)
{
new->next = old->next;
new->prev = old->prev;
// smp_wmb();
new->next->prev = new;
new->prev->next = new;
old->prev = LIST_POISON2;
}

/**
* list_del_init - deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.
*/
static inline void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
}

/**
* list_move - delete from one list and add as another's head
* @list: the entry to move
* @head: the head that will precede our entry
*/
static inline void list_move(struct list_head *list, struct list_head *head)
{
__list_del(list->prev, list->next);
list_add(list, head);
}

/**
* list_move_tail - delete from one list and add as another's tail
* @list: the entry to move
* @head: the head that will follow our entry
*/
static inline void list_move_tail(struct list_head *list,
struct list_head *head)
{
__list_del(list->prev, list->next);
list_add_tail(list, head);
}

/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
static inline int list_empty(const struct list_head *head)
{
return head->next == head;
}

/**
* list_empty_careful - tests whether a list is
* empty _and_ checks that no other CPU might be
* in the process of still modifying either member
*
* NOTE: using list_empty_careful() without synchronization
* can only be safe if the only activity that can happen
* to the list entry is list_del_init(). Eg. it cannot be used
* if another CPU could re-list_add() it.
*
* @head: the list to test.
*/
static inline int list_empty_careful(const struct list_head *head)
{
struct list_head *next = head->next;
return (next == head) && (next == head->prev);
}

static inline void __list_splice(struct list_head *list,
struct list_head *head)
{
struct list_head *first = list->next;
struct list_head *last = list->prev;
struct list_head *at = head->next;

first->prev = head;
head->next = first;

last->next = at;
at->prev = last;
}

/**
* list_splice - join two lists
* @list: the new list to add.
* @head: the place to add it in the first list.
*/
static inline void list_splice(struct list_head *list, struct list_head *head)
{
if (!list_empty(list))
__list_splice(list, head);
}

/**
* list_splice_init - join two lists and reinitialise the emptied list.
* @list: the new list to add.
* @head: the place to add it in the first list.
*
* The list at @list is reinitialised
*/
static inline void list_splice_init(struct list_head *list,
struct list_head *head)
{
if (!list_empty(list)) {
__list_splice(list, head);
INIT_LIST_HEAD(list);
}
}

/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)

/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each(pos, head) \
for (pos = (head)->next; prefetch(pos->next), pos != (head); \
pos = pos->next)

/**
* __list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*
* This variant differs from list_for_each() in that it's the
* simplest possible list iteration code, no prefetching is done.
* Use this for code that knows the list to be very short (empty
* or 1 entry) most of the time.
*/
#define __list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)

/**
* list_for_each_prev - iterate over a list backwards
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each_prev(pos, head) \
for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
pos = pos->prev)

/**
* list_for_each_safe - iterate over a list safe against removal of list entry
* @pos: the &struct list_head to use as a loop counter.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*/
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)

/**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop counter.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
prefetch(pos->member.next), &pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))

/**
* list_for_each_entry_reverse - iterate backwards over list of given type.
* @pos: the type * to use as a loop counter.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_reverse(pos, head, member) \
for (pos = list_entry((head)->prev, typeof(*pos), member); \
prefetch(pos->member.prev), &pos->member != (head); \
pos = list_entry(pos->member.prev, typeof(*pos), member))

/**
* list_prepare_entry - prepare a pos entry for use as a start point in
* list_for_each_entry_continue
* @pos: the type * to use as a start point
* @head: the head of the list
* @member: the name of the list_struct within the struct.
*/
#define list_prepare_entry(pos, head, member) \
((pos) ? : list_entry(head, typeof(*pos), member))

/**
* list_for_each_entry_continue - iterate over list of given type
* continuing after existing point
* @pos: the type * to use as a loop counter.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_continue(pos, head, member) \
for (pos = list_entry(pos->member.next, typeof(*pos), member); \
prefetch(pos->member.next), &pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))

/**
* list_for_each_entry_from - iterate over list of given type
* continuing from existing point
* @pos: the type * to use as a loop counter.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_from(pos, head, member) \
for (; prefetch(pos->member.next), &pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))

/**
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
* @pos: the type * to use as a loop counter.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))

/**
* list_for_each_entry_safe_continue - iterate over list of given type
* continuing after existing point safe against removal of list entry
* @pos: the type * to use as a loop counter.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_safe_continue(pos, n, head, member) \
for (pos = list_entry(pos->member.next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))

/**
* list_for_each_entry_safe_from - iterate over list of given type
* from existing point safe against removal of list entry
* @pos: the type * to use as a loop counter.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_safe_from(pos, n, head, member) \
for (n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))

/**
* list_for_each_entry_safe_reverse - iterate backwards over list of given type safe against
* removal of list entry
* @pos: the type * to use as a loop counter.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_safe_reverse(pos, n, head, member) \
for (pos = list_entry((head)->prev, typeof(*pos), member), \
n = list_entry(pos->member.prev, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.prev, typeof(*n), member))

/**
* list_for_each_rcu - iterate over an rcu-protected list
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*
* This list-traversal primitive may safely run concurrently with
* the _rcu list-mutation primitives such as list_add_rcu()
* as long as the traversal is guarded by rcu_read_lock().
*/
#define list_for_each_rcu(pos, head) \
for (pos = (head)->next; \
prefetch(rcu_dereference(pos)->next), pos != (head); \
pos = pos->next)

#define __list_for_each_rcu(pos, head) \
for (pos = (head)->next; \
rcu_dereference(pos) != (head); \
pos = pos->next)

/**
* list_for_each_safe_rcu - iterate over an rcu-protected list safe
* against removal of list entry
* @pos: the &struct list_head to use as a loop counter.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*
* This list-traversal primitive may safely run concurrently with
* the _rcu list-mutation primitives such as list_add_rcu()
* as long as the traversal is guarded by rcu_read_lock().
*/
#define list_for_each_safe_rcu(pos, n, head) \
for (pos = (head)->next; \
n = rcu_dereference(pos)->next, pos != (head); \
pos = n)

/**
* list_for_each_entry_rcu - iterate over rcu list of given type
* @pos: the type * to use as a loop counter.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*
* This list-traversal primitive may safely run concurrently with
* the _rcu list-mutation primitives such as list_add_rcu()
* as long as the traversal is guarded by rcu_read_lock().
*/
#define list_for_each_entry_rcu(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
prefetch(rcu_dereference(pos)->member.next), \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))


/**
* list_for_each_continue_rcu - iterate over an rcu-protected list
* continuing after existing point.
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*
* This list-traversal primitive may safely run concurrently with
* the _rcu list-mutation primitives such as list_add_rcu()
* as long as the traversal is guarded by rcu_read_lock().
*/
#define list_for_each_continue_rcu(pos, head) \
for ((pos) = (pos)->next; \
prefetch(rcu_dereference((pos))->next), (pos) != (head); \
(pos) = (pos)->next)

/*
* Double linked lists with a single pointer list head.
* Mostly useful for hash tables where the two pointer list head is
* too wasteful.
* You lose the ability to access the tail in O(1).
*/

struct hlist_head {
struct hlist_node *first;
};

struct hlist_node {
struct hlist_node *next, **pprev;
};

#define HLIST_HEAD_INIT { .first = NULL }
#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
static inline void INIT_HLIST_NODE(struct hlist_node *h)
{
h->next = NULL;
h->pprev = NULL;
}

static inline int hlist_unhashed(const struct hlist_node *h)
{
return !h->pprev;
}

static inline int hlist_empty(const struct hlist_head *h)
{
return !h->first;
}

static inline void __hlist_del(struct hlist_node *n)
{
struct hlist_node *next = n->next;
struct hlist_node **pprev = n->pprev;
*pprev = next;
if (next)
next->pprev = pprev;
}

static inline void hlist_del(struct hlist_node *n)
{
__hlist_del(n);
n->next = LIST_POISON1;
n->pprev = LIST_POISON2;
}

/**
* hlist_del_rcu - deletes entry from hash list without re-initialization
* @n: the element to delete from the hash list.
*
* Note: list_unhashed() on entry does not return true after this,
* the entry is in an undefined state. It is useful for RCU based
* lockfree traversal.
*
* In particular, it means that we can not poison the forward
* pointers that may still be used for walking the hash list.
*
* The caller must take whatever precautions are necessary
* (such as holding appropriate locks) to avoid racing
* with another list-mutation primitive, such as hlist_add_head_rcu()
* or hlist_del_rcu(), running on this same list.
* However, it is perfectly legal to run concurrently with
* the _rcu list-traversal primitives, such as
* hlist_for_each_entry().
*/
static inline void hlist_del_rcu(struct hlist_node *n)
{
__hlist_del(n);
n->pprev = LIST_POISON2;
}

static inline void hlist_del_init(struct hlist_node *n)
{
if (!hlist_unhashed(n)) {
__hlist_del(n);
INIT_HLIST_NODE(n);
}
}

/*
* hlist_replace_rcu - replace old entry by new one
* @old : the element to be replaced
* @new : the new element to insert
*
* The old entry will be replaced with the new entry atomically.
*/
static inline void hlist_replace_rcu(struct hlist_node *old,
struct hlist_node *new)
{
struct hlist_node *next = old->next;

new->next = next;
new->pprev = old->pprev;
// smp_wmb();
if (next)
new->next->pprev = &new->next;
*new->pprev = new;
old->pprev = LIST_POISON2;
}

static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
{
struct hlist_node *first = h->first;
n->next = first;
if (first)
first->pprev = &n->next;
h->first = n;
n->pprev = &h->first;
}


/**
* hlist_add_head_rcu - adds the specified element to the specified hlist,
* while permitting racing traversals.
* @n: the element to add to the hash list.
* @h: the list to add to.
*
* The caller must take whatever precautions are necessary
* (such as holding appropriate locks) to avoid racing
* with another list-mutation primitive, such as hlist_add_head_rcu()
* or hlist_del_rcu(), running on this same list.
* However, it is perfectly legal to run concurrently with
* the _rcu list-traversal primitives, such as
* hlist_for_each_entry_rcu(), used to prevent memory-consistency
* problems on Alpha CPUs. Regardless of the type of CPU, the
* list-traversal primitive must be guarded by rcu_read_lock().
*/
static inline void hlist_add_head_rcu(struct hlist_node *n,
struct hlist_head *h)
{
struct hlist_node *first = h->first;
n->next = first;
n->pprev = &h->first;
// smp_wmb();
if (first)
first->pprev = &n->next;
h->first = n;
}

/* next must be != NULL */
static inline void hlist_add_before(struct hlist_node *n,
struct hlist_node *next)
{
n->pprev = next->pprev;
n->next = next;
next->pprev = &n->next;
*(n->pprev) = n;
}

static inline void hlist_add_after(struct hlist_node *n,
struct hlist_node *next)
{
next->next = n->next;
n->next = next;
next->pprev = &n->next;

if(next->next)
next->next->pprev = &next->next;
}

/**
* hlist_add_before_rcu - adds the specified element to the specified hlist
* before the specified node while permitting racing traversals.
* @n: the new element to add to the hash list.
* @next: the existing element to add the new element before.
*
* The caller must take whatever precautions are necessary
* (such as holding appropriate locks) to avoid racing
* with another list-mutation primitive, such as hlist_add_head_rcu()
* or hlist_del_rcu(), running on this same list.
* However, it is perfectly legal to run concurrently with
* the _rcu list-traversal primitives, such as
* hlist_for_each_entry_rcu(), used to prevent memory-consistency
* problems on Alpha CPUs.
*/
static inline void hlist_add_before_rcu(struct hlist_node *n,
struct hlist_node *next)
{
n->pprev = next->pprev;
n->next = next;
// smp_wmb();
next->pprev = &n->next;
*(n->pprev) = n;
}

/**
* hlist_add_after_rcu - adds the specified element to the specified hlist
* after the specified node while permitting racing traversals.
* @prev: the existing element to add the new element after.
* @n: the new element to add to the hash list.
*
* The caller must take whatever precautions are necessary
* (such as holding appropriate locks) to avoid racing
* with another list-mutation primitive, such as hlist_add_head_rcu()
* or hlist_del_rcu(), running on this same list.
* However, it is perfectly legal to run concurrently with
* the _rcu list-traversal primitives, such as
* hlist_for_each_entry_rcu(), used to prevent memory-consistency
* problems on Alpha CPUs.
*/
static inline void hlist_add_after_rcu(struct hlist_node *prev,
struct hlist_node *n)
{
n->next = prev->next;
n->pprev = &prev->next;
// smp_wmb();
prev->next = n;
if (n->next)
n->next->pprev = &n->next;
}

#define hlist_entry(ptr, type, member) container_of(ptr,type,member)

#define hlist_for_each(pos, head) \
for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
pos = pos->next)

#define hlist_for_each_safe(pos, n, head) \
for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
pos = n)

/**
* hlist_for_each_entry - iterate over list of given type
* @tpos: the type * to use as a loop counter.
* @pos: the &struct hlist_node to use as a loop counter.
* @head: the head for your list.
* @member: the name of the hlist_node within the struct.
*/
#define hlist_for_each_entry(tpos, pos, head, member) \
for (pos = (head)->first; \
pos && ({ prefetch(pos->next); 1;}) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = pos->next)

/**
* hlist_for_each_entry_continue - iterate over a hlist continuing after existing point
* @tpos: the type * to use as a loop counter.
* @pos: the &struct hlist_node to use as a loop counter.
* @member: the name of the hlist_node within the struct.
*/
#define hlist_for_each_entry_continue(tpos, pos, member) \
for (pos = (pos)->next; \
pos && ({ prefetch(pos->next); 1;}) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = pos->next)

/**
* hlist_for_each_entry_from - iterate over a hlist continuing from existing point
* @tpos: the type * to use as a loop counter.
* @pos: the &struct hlist_node to use as a loop counter.
* @member: the name of the hlist_node within the struct.
*/
#define hlist_for_each_entry_from(tpos, pos, member) \
for (; pos && ({ prefetch(pos->next); 1;}) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = pos->next)

/**
* hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
* @tpos: the type * to use as a loop counter.
* @pos: the &struct hlist_node to use as a loop counter.
* @n: another &struct hlist_node to use as temporary storage
* @head: the head for your list.
* @member: the name of the hlist_node within the struct.
*/
#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
for (pos = (head)->first; \
pos && ({ n = pos->next; 1; }) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = n)

/**
* hlist_for_each_entry_rcu - iterate over rcu list of given type
* @tpos: the type * to use as a loop counter.
* @pos: the &struct hlist_node to use as a loop counter.
* @head: the head for your list.
* @member: the name of the hlist_node within the struct.
*
* This list-traversal primitive may safely run concurrently with
* the _rcu list-mutation primitives such as hlist_add_head_rcu()
* as long as the traversal is guarded by rcu_read_lock().
*/
#define hlist_for_each_entry_rcu(tpos, pos, head, member) \
for (pos = (head)->first; \
rcu_dereference(pos) && ({ prefetch(pos->next); 1;}) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = pos->next)

#endif

/**
* __list_sort - sort the list using given comparator with merge-sort algorithm
* @head: is a head of the list to be sorted
* @member_offset: is machine offset inside the list entry structure to the
* field of type struct list_head which links that entry with
* the list.
*/
extern void __list_sort(struct list_head * head,
int member_offset,
int (*comparator)(void*,void*));

/**
* list_sort - wrapper for __list_sort
* @head: is a head of the list to be sorted
* @type: is the type of list entry
* @member: is the name of the field inside entry that links that entry with
* other entries in the list.
* @comaprator: function comparing two entries, should return value lesser
* than 0 when the first argument is lesser than the second one.
*/
#define list_sort(head,type,member,comparator) \
({ \
__list_sort(head, \
offsetof(type, member), \
(int (*)(void*, void*)) comparator); \
})

void test_list_sort(void);

+ 0
- 217
alsa_midi/port.c View File

@@ -1,217 +0,0 @@
/*
* ALSA SEQ < - > JACK MIDI bridge