/*
* Edirol UA-101/UA-1000 driver
* Copyright (c) Clemens Ladisch <clemens@ladisch.de>
*
* This driver is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.
*
* This driver 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 driver. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/usb/audio.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include "../usbaudio.h"
#include "../midi.h"
MODULE_DESCRIPTION("Edirol UA-101/1000 driver");
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
MODULE_LICENSE("GPL v2");
MODULE_SUPPORTED_DEVICE("{{Edirol,UA-101},{Edirol,UA-1000}}");
/*
* Should not be lower than the minimum scheduling delay of the host
* controller. Some Intel controllers need more than one frame; as long as
* that driver doesn't tell us about this, use 1.5 frames just to be sure.
*/
#define MIN_QUEUE_LENGTH 12
/* Somewhat random. */
#define MAX_QUEUE_LENGTH 30
/*
* This magic value optimizes memory usage efficiency for the UA-101's packet
* sizes at all sample rates, taking into account the stupid cache pool sizes
* that usb_alloc_coherent() uses.
*/
#define DEFAULT_QUEUE_LENGTH 21
#define MAX_PACKET_SIZE 672 /* hardware specific */
#define MAX_MEMORY_BUFFERS DIV_ROUND_UP(MAX_QUEUE_LENGTH, \
PAGE_SIZE / MAX_PACKET_SIZE)
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
static unsigned int queue_length = 21;
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "card index");
module_param_array(id, charp, NULL, 0444);
MODULE_PARM_DESC(id, "ID string");
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "enable card");
module_param(queue_length, uint, 0644);
MODULE_PARM_DESC(queue_length, "USB queue length in microframes, "
__stringify(MIN_QUEUE_LENGTH)"-"__stringify(MAX_QUEUE_LENGTH));
enum {
INTF_PLAYBACK,
INTF_CAPTURE,
INTF_MIDI,
INTF_COUNT
};
/* bits in struct ua101::states */
enum {
USB_CAPTURE_RUNNING,
USB_PLAYBACK_RUNNING,
ALSA_CAPTURE_OPEN,
ALSA_PLAYBACK_OPEN,
ALSA_CAPTURE_RUNNING,
ALSA_PLAYBACK_RUNNING,
CAPTURE_URB_COMPLETED,
PLAYBACK_URB_COMPLETED,
DISCONNECTED,
};
struct ua101 {
struct usb_device *dev;
struct snd_card *card;
struct usb_interface *intf[INTF_COUNT];
int card_index;
struct snd_pcm *pcm;
struct list_head midi_list;
u64 format_bit;
unsigned int rate;
unsigned int packets_per_second;
spinlock_t lock;
struct mutex mutex;
unsigned long states;
/* FIFO to synchronize playback rate to capture rate */
unsigned int rate_feedback_start;
unsigned int rate_feedback_count;
u8 rate_feedback[MAX_QUEUE_LENGTH];
struct list_head ready_playback_urbs;
struct tasklet_struct playback_tasklet;
wait_queue_head_t alsa_capture_wait;
wait_queue_head_t rate_feedback_wait;
wait_queue_head_t alsa_playback_wait;
struct ua101_stream {
struct snd_pcm_substream *substream;
unsigned int usb_pipe;
unsigned int channels;
unsigned int frame_bytes;
unsigned int max_packet_bytes;
unsigned int period_pos;
unsigned int buffer_pos;
unsigned int queue_length;
struct ua101_urb {
struct urb urb;
struct usb_iso_packet_descriptor iso_frame_desc[1];
struct list_head ready_list;
} *urbs[MAX_QUEUE_LENGTH];
struct {
unsigned int size;
void *addr;
dma_addr_t dma;
} buffers[MAX_MEMORY_BUFFERS];
} capture, playback;
};
static DEFINE_MUTEX(devices_mutex);
static unsigned int devices_used;
static struct usb_driver ua101_driver;
static void abort_alsa_playback(struct ua101 *ua);
static void abort_alsa_capture(struct ua101 *ua);
static const char *usb_error_string(int err)
{
switch (err) {
case -ENODEV:
return "no device";
case -ENOENT:
return "endpoint not enabled";
case -EPIPE:
return "endpoint stalled";
case
|