Commit 5e0ddd07 authored by Takashi Iwai's avatar Takashi Iwai

Merge branch 'topic/line6' into for-next

parents 1001fb81 247d95ee
......@@ -29,6 +29,8 @@ config SND_USB_PODHD
config SND_USB_TONEPORT
tristate "TonePort GX, UX1 and UX2 USB support"
select SND_USB_LINE6
select NEW_LEDS
select LEDS_CLASS
help
This is a driver for TonePort GX, UX1 and UX2 devices.
......
......@@ -20,26 +20,24 @@
/*
Find a free URB and submit it.
must be called in line6pcm->in.lock context
*/
static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm)
{
int index;
unsigned long flags;
int i, urb_size;
int ret;
struct urb *urb_in;
spin_lock_irqsave(&line6pcm->lock_audio_in, flags);
index =
find_first_zero_bit(&line6pcm->active_urb_in, LINE6_ISO_BUFFERS);
find_first_zero_bit(&line6pcm->in.active_urbs, LINE6_ISO_BUFFERS);
if (index < 0 || index >= LINE6_ISO_BUFFERS) {
spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
return -EINVAL;
}
urb_in = line6pcm->urb_audio_in[index];
urb_in = line6pcm->in.urbs[index];
urb_size = 0;
for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
......@@ -51,7 +49,7 @@ static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm)
}
urb_in->transfer_buffer =
line6pcm->buffer_in +
line6pcm->in.buffer +
index * LINE6_ISO_PACKETS * line6pcm->max_packet_size;
urb_in->transfer_buffer_length = urb_size;
urb_in->context = line6pcm;
......@@ -59,81 +57,29 @@ static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm)
ret = usb_submit_urb(urb_in, GFP_ATOMIC);
if (ret == 0)
set_bit(index, &line6pcm->active_urb_in);
set_bit(index, &line6pcm->in.active_urbs);
else
dev_err(line6pcm->line6->ifcdev,
"URB in #%d submission failed (%d)\n", index, ret);
spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
return 0;
}
/*
Submit all currently available capture URBs.
must be called in line6pcm->in.lock context
*/
int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm)
{
int ret, i;
int ret = 0, i;
for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
ret = submit_audio_in_urb(line6pcm);
if (ret < 0)
return ret;
}
return 0;
}
/*
Unlink all currently active capture URBs.
*/
void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm)
{
unsigned int i;
for (i = LINE6_ISO_BUFFERS; i--;) {
if (test_bit(i, &line6pcm->active_urb_in)) {
if (!test_and_set_bit(i, &line6pcm->unlink_urb_in)) {
struct urb *u = line6pcm->urb_audio_in[i];
usb_unlink_urb(u);
}
}
}
}
/*
Wait until unlinking of all currently active capture URBs has been
finished.
*/
void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
{
int timeout = HZ;
unsigned int i;
int alive;
do {
alive = 0;
for (i = LINE6_ISO_BUFFERS; i--;) {
if (test_bit(i, &line6pcm->active_urb_in))
alive++;
}
if (!alive)
break;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
} while (--timeout > 0);
if (alive)
snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
}
}
/*
Unlink all currently active capture URBs, and wait for finishing.
*/
void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
{
line6_unlink_audio_in_urbs(line6pcm);
line6_wait_clear_audio_in_urbs(line6pcm);
return ret;
}
/*
......@@ -150,18 +96,18 @@ void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize)
if (runtime == NULL)
return;
if (line6pcm->pos_in_done + frames > runtime->buffer_size) {
if (line6pcm->in.pos_done + frames > runtime->buffer_size) {
/*
The transferred area goes over buffer boundary,
copy two separate chunks.
*/
int len;
len = runtime->buffer_size - line6pcm->pos_in_done;
len = runtime->buffer_size - line6pcm->in.pos_done;
if (len > 0) {
memcpy(runtime->dma_area +
line6pcm->pos_in_done * bytes_per_frame, fbuf,
line6pcm->in.pos_done * bytes_per_frame, fbuf,
len * bytes_per_frame);
memcpy(runtime->dma_area, fbuf + len * bytes_per_frame,
(frames - len) * bytes_per_frame);
......@@ -173,12 +119,12 @@ void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize)
} else {
/* copy single chunk */
memcpy(runtime->dma_area +
line6pcm->pos_in_done * bytes_per_frame, fbuf, fsize);
line6pcm->in.pos_done * bytes_per_frame, fbuf, fsize);
}
line6pcm->pos_in_done += frames;
if (line6pcm->pos_in_done >= runtime->buffer_size)
line6pcm->pos_in_done -= runtime->buffer_size;
line6pcm->in.pos_done += frames;
if (line6pcm->in.pos_done >= runtime->buffer_size)
line6pcm->in.pos_done -= runtime->buffer_size;
}
void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length)
......@@ -186,19 +132,15 @@ void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length)
struct snd_pcm_substream *substream =
get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE);
line6pcm->bytes_in += length;
if (line6pcm->bytes_in >= line6pcm->period_in) {
line6pcm->bytes_in %= line6pcm->period_in;
line6pcm->in.bytes += length;
if (line6pcm->in.bytes >= line6pcm->in.period) {
line6pcm->in.bytes %= line6pcm->in.period;
spin_unlock(&line6pcm->in.lock);
snd_pcm_period_elapsed(substream);
spin_lock(&line6pcm->in.lock);
}
}
void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm)
{
kfree(line6pcm->buffer_in);
line6pcm->buffer_in = NULL;
}
/*
* Callback for completed capture URB.
*/
......@@ -209,14 +151,14 @@ static void audio_in_callback(struct urb *urb)
struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context;
line6pcm->last_frame_in = urb->start_frame;
line6pcm->in.last_frame = urb->start_frame;
/* find index of URB */
for (index = 0; index < LINE6_ISO_BUFFERS; ++index)
if (urb == line6pcm->urb_audio_in[index])
if (urb == line6pcm->in.urbs[index])
break;
spin_lock_irqsave(&line6pcm->lock_audio_in, flags);
spin_lock_irqsave(&line6pcm->in.lock, flags);
for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
char *fbuf;
......@@ -243,27 +185,26 @@ static void audio_in_callback(struct urb *urb)
line6pcm->prev_fbuf = fbuf;
line6pcm->prev_fsize = fsize;
if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE))
if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM,
&line6pcm->flags) && (fsize > 0))
line6_capture_copy(line6pcm, fbuf, fsize);
if (!test_bit(LINE6_STREAM_IMPULSE, &line6pcm->in.running) &&
test_bit(LINE6_STREAM_PCM, &line6pcm->in.running) &&
fsize > 0)
line6_capture_copy(line6pcm, fbuf, fsize);
}
clear_bit(index, &line6pcm->active_urb_in);
clear_bit(index, &line6pcm->in.active_urbs);
if (test_and_clear_bit(index, &line6pcm->unlink_urb_in))
if (test_and_clear_bit(index, &line6pcm->in.unlink_urbs))
shutdown = 1;
spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
if (!shutdown) {
submit_audio_in_urb(line6pcm);
if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE))
if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM,
&line6pcm->flags))
line6_capture_check_period(line6pcm, length);
if (!test_bit(LINE6_STREAM_IMPULSE, &line6pcm->in.running) &&
test_bit(LINE6_STREAM_PCM, &line6pcm->in.running))
line6_capture_check_period(line6pcm, length);
}
spin_unlock_irqrestore(&line6pcm->in.lock, flags);
}
/* open capture callback */
......@@ -290,102 +231,16 @@ static int snd_line6_capture_close(struct snd_pcm_substream *substream)
return 0;
}
/* hw_params capture callback */
static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
int ret;
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
/* -- Florian Demski [FD] */
/* don't ask me why, but this fixes the bug on my machine */
if (line6pcm == NULL) {
if (substream->pcm == NULL)
return -ENOMEM;
if (substream->pcm->private_data == NULL)
return -ENOMEM;
substream->private_data = substream->pcm->private_data;
line6pcm = snd_pcm_substream_chip(substream);
}
/* -- [FD] end */
ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
if (ret < 0)
return ret;
ret = snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params));
if (ret < 0) {
line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
return ret;
}
line6pcm->period_in = params_period_bytes(hw_params);
return 0;
}
/* hw_free capture callback */
static int snd_line6_capture_hw_free(struct snd_pcm_substream *substream)
{
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
return snd_pcm_lib_free_pages(substream);
}
/* trigger callback */
int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd)
{
int err;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
err = line6_pcm_acquire(line6pcm,
LINE6_BIT_PCM_ALSA_CAPTURE_STREAM);
if (err < 0)
return err;
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
err = line6_pcm_release(line6pcm,
LINE6_BIT_PCM_ALSA_CAPTURE_STREAM);
if (err < 0)
return err;
break;
default:
return -EINVAL;
}
return 0;
}
/* capture pointer callback */
static snd_pcm_uframes_t
snd_line6_capture_pointer(struct snd_pcm_substream *substream)
{
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
return line6pcm->pos_in_done;
}
/* capture operators */
struct snd_pcm_ops snd_line6_capture_ops = {
.open = snd_line6_capture_open,
.close = snd_line6_capture_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_line6_capture_hw_params,
.hw_free = snd_line6_capture_hw_free,
.hw_params = snd_line6_hw_params,
.hw_free = snd_line6_hw_free,
.prepare = snd_line6_prepare,
.trigger = snd_line6_trigger,
.pointer = snd_line6_capture_pointer,
.pointer = snd_line6_pointer,
};
int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm)
......@@ -398,7 +253,7 @@ int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm)
struct urb *urb;
/* URB for audio in: */
urb = line6pcm->urb_audio_in[i] =
urb = line6pcm->in.urbs[i] =
usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
if (urb == NULL)
......
......@@ -24,12 +24,6 @@ extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf,
extern void line6_capture_check_period(struct snd_line6_pcm *line6pcm,
int length);
extern int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm);
extern void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm);
extern int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm);
extern void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm);
extern void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm
*line6pcm);
extern void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm);
extern int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd);
#endif
......@@ -412,27 +412,13 @@ int line6_read_serial_number(struct usb_line6 *line6, int *serial_number)
}
EXPORT_SYMBOL_GPL(line6_read_serial_number);
/*
No operation (i.e., unsupported).
*/
ssize_t line6_nop_read(struct device *dev, struct device_attribute *attr,
char *buf)
{
return 0;
}
EXPORT_SYMBOL_GPL(line6_nop_read);
/*
Card destructor.
*/
static void line6_destruct(struct snd_card *card)
{
struct usb_line6 *line6 = card->private_data;
struct usb_device *usbdev;
if (!line6)
return;
usbdev = line6->usbdev;
struct usb_device *usbdev = line6->usbdev;
/* free buffer memory first: */
kfree(line6->buffer_message);
......@@ -441,82 +427,96 @@ static void line6_destruct(struct snd_card *card)
/* then free URBs: */
usb_free_urb(line6->urb_listen);
/* free interface data: */
kfree(line6);
/* decrement reference counters: */
usb_put_dev(usbdev);
}
/* get data from endpoint descriptor (see usb_maxpacket): */
static void line6_get_interval(struct usb_line6 *line6)
{
struct usb_device *usbdev = line6->usbdev;
struct usb_host_endpoint *ep;
unsigned pipe = usb_rcvintpipe(usbdev, line6->properties->ep_ctrl_r);
unsigned epnum = usb_pipeendpoint(pipe);
ep = usbdev->ep_in[epnum];
if (ep) {
line6->interval = ep->desc.bInterval;
line6->max_packet_size = le16_to_cpu(ep->desc.wMaxPacketSize);
} else {
dev_err(line6->ifcdev,
"endpoint not available, using fallback values");
line6->interval = LINE6_FALLBACK_INTERVAL;
line6->max_packet_size = LINE6_FALLBACK_MAXPACKETSIZE;
}
}
static int line6_init_cap_control(struct usb_line6 *line6)
{
int ret;
/* initialize USB buffers: */
line6->buffer_listen = kmalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL);
if (!line6->buffer_listen)
return -ENOMEM;
line6->buffer_message = kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL);
if (!line6->buffer_message)
return -ENOMEM;
line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL);
if (!line6->urb_listen)
return -ENOMEM;
ret = line6_start_listen(line6);
if (ret < 0) {
dev_err(line6->ifcdev, "cannot start listening: %d\n", ret);
return ret;
}
return 0;
}
/*
Probe USB device.
*/
int line6_probe(struct usb_interface *interface,
struct usb_line6 *line6,
const struct usb_device_id *id,
const struct line6_properties *properties,
int (*private_init)(struct usb_interface *, struct usb_line6 *))
int (*private_init)(struct usb_line6 *, const struct usb_device_id *id),
size_t data_size)
{
struct usb_device *usbdev = interface_to_usbdev(interface);
struct snd_card *card;
struct usb_line6 *line6;
int interface_number;
int ret;
/* we don't handle multiple configurations */
if (usbdev->descriptor.bNumConfigurations != 1) {
ret = -ENODEV;
goto err_put;
}
/* initialize device info: */
dev_info(&interface->dev, "Line 6 %s found\n", properties->name);
if (WARN_ON(data_size < sizeof(*line6)))
return -EINVAL;
/* query interface number */
interface_number = interface->cur_altsetting->desc.bInterfaceNumber;
/* we don't handle multiple configurations */
if (usbdev->descriptor.bNumConfigurations != 1)
return -ENODEV;
ret = usb_set_interface(usbdev, interface_number,
properties->altsetting);
if (ret < 0) {
dev_err(&interface->dev, "set_interface failed\n");
goto err_put;
}
ret = snd_card_new(&interface->dev,
SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
THIS_MODULE, data_size, &card);
if (ret < 0)
return ret;
/* store basic data: */
line6 = card->private_data;
line6->card = card;
line6->properties = properties;
line6->usbdev = usbdev;
line6->ifcdev = &interface->dev;
/* get data from endpoint descriptor (see usb_maxpacket): */
{
struct usb_host_endpoint *ep;
unsigned pipe = usb_rcvintpipe(usbdev, properties->ep_ctrl_r);
unsigned epnum = usb_pipeendpoint(pipe);
ep = usbdev->ep_in[epnum];
if (ep != NULL) {
line6->interval = ep->desc.bInterval;
line6->max_packet_size =
le16_to_cpu(ep->desc.wMaxPacketSize);
} else {
line6->interval = LINE6_FALLBACK_INTERVAL;
line6->max_packet_size = LINE6_FALLBACK_MAXPACKETSIZE;
dev_err(line6->ifcdev,
"endpoint not available, using fallback values");
}
}
ret = snd_card_new(line6->ifcdev,
SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
THIS_MODULE, 0, &card);
if (ret < 0)
goto err_put;
line6->card = card;
strcpy(card->id, line6->properties->id);
strcpy(card->id, properties->id);
strcpy(card->driver, DRIVER_NAME);
strcpy(card->shortname, line6->properties->name);
sprintf(card->longname, "Line 6 %s at USB %s", line6->properties->name,
strcpy(card->shortname, properties->name);
sprintf(card->longname, "Line 6 %s at USB %s", properties->name,
dev_name(line6->ifcdev));
card->private_data = line6;
card->private_free = line6_destruct;
usb_set_intfdata(interface, line6);
......@@ -524,52 +524,43 @@ int line6_probe(struct usb_interface *interface,
/* increment reference counters: */
usb_get_dev(usbdev);
if (properties->capabilities & LINE6_CAP_CONTROL) {
/* initialize USB buffers: */
line6->buffer_listen =
kmalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL);
if (line6->buffer_listen == NULL) {
ret = -ENOMEM;
goto err_destruct;
}
/* initialize device info: */
dev_info(&interface->dev, "Line 6 %s found\n", properties->name);
line6->buffer_message =
kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL);
if (line6->buffer_message == NULL) {
ret = -ENOMEM;
goto err_destruct;
}
/* query interface number */
interface_number = interface->cur_altsetting->desc.bInterfaceNumber;
line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL);
ret = usb_set_interface(usbdev, interface_number,
properties->altsetting);
if (ret < 0) {
dev_err(&interface->dev, "set_interface failed\n");
goto error;
}
if (line6->urb_listen == NULL) {
ret = -ENOMEM;
goto err_destruct;
}
line6_get_interval(line6);
ret = line6_start_listen(line6);
if (ret < 0) {
dev_err(&interface->dev, "%s: usb_submit_urb failed\n",
__func__);
goto err_destruct;
}
if (properties->capabilities & LINE6_CAP_CONTROL) {
ret = line6_init_cap_control(line6);
if (ret < 0)
goto error;
}
/* initialize device data based on device: */
ret = private_init(interface, line6);
ret = private_init(line6, id);
if (ret < 0)
goto err_destruct;
goto error;
/* creation of additional special files should go here */
dev_info(&interface->dev, "Line 6 %s now attached\n",
line6->properties->name);
properties->name);
return 0;
err_destruct:
error:
if (line6->disconnect)
line6->disconnect(line6);
snd_card_free(card);
err_put:
return ret;
}
EXPORT_SYMBOL_GPL(line6_probe);
......@@ -579,32 +570,23 @@ EXPORT_SYMBOL_GPL(line6_probe);
*/
void line6_disconnect(struct usb_interface *interface)
{
struct usb_line6 *line6;
struct usb_device *usbdev;
int interface_number;
struct usb_line6 *line6 = usb_get_intfdata(interface);
struct usb_device *usbdev = interface_to_usbdev(interface);
if (interface == NULL)
return;
usbdev = interface_to_usbdev(interface);
if (usbdev == NULL)
if (!line6)
return;
interface_number = interface->cur_altsetting->desc.bInterfaceNumber;
line6 = usb_get_intfdata(interface);
if (!line6)
if (WARN_ON(usbdev != line6->usbdev))
return;
if (line6->urb_listen != NULL)
line6_stop_listen(line6);
if (usbdev != line6->usbdev)
dev_err(line6->ifcdev, "driver bug: inconsistent usb device\n");
snd_card_disconnect(line6->card);
if (line6->line6pcm)
line6_pcm_disconnect(line6->line6pcm);
if (line6->disconnect)
line6->disconnect(interface);
line6->disconnect(line6);
dev_info(&interface->dev, "Line 6 %s now disconnected\n",
line6->properties->name);
......
......@@ -157,13 +157,11 @@ struct usb_line6 {
int message_length;
void (*process_message)(struct usb_line6 *);
void (*disconnect)(struct usb_interface *);
void (*disconnect)(struct usb_line6 *line6);
};
extern char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1,
int code2, int size);
extern ssize_t line6_nop_read(struct device *dev,
struct device_attribute *attr, char *buf);
extern int line6_read_data(struct usb_line6 *line6, int address, void *data,
size_t datalen);
extern int line6_read_serial_number(struct usb_line6 *line6,
......@@ -182,9 +180,11 @@ extern int line6_write_data(struct usb_line6 *line6, int address, void *data,
size_t datalen);
int line6_probe(struct usb_interface *interface,
struct usb_line6 *line6,
const struct usb_device_id *id,
const struct line6_properties *properties,
int (*private_init)(struct usb_interface *, struct usb_line6 *));
int (*private_init)(struct usb_line6 *, const struct usb_device_id *id),
size_t data_size);
void line6_disconnect(struct usb_interface *interface);
#ifdef CONFIG_PM
......
......@@ -45,12 +45,9 @@ static void line6_midi_transmit(struct snd_rawmidi_substream *substream)
line6_rawmidi_substream_midi(substream)->line6;
struct snd_line6_midi *line6midi = line6->line6midi;
struct midi_buffer *mb = &line6midi->midibuf_out;
unsigned long flags;
unsigned char chunk[LINE6_FALLBACK_MAXPACKETSIZE];
int req, done;
spin_lock_irqsave(&line6->line6midi->midi_transmit_lock, flags);
for (;;) {
req = min(line6_midibuf_bytes_free(mb), line6->max_packet_size);
done = snd_rawmidi_transmit_peek(substream, chunk, req);
......@@ -71,8 +68,6 @@ static void line6_midi_transmit(struct snd_rawmidi_substream *substream)
send_midi_async(line6, chunk, done);
}
spin_unlock_irqrestore(&line6->line6midi->midi_transmit_lock, flags);
}
/*
......@@ -92,7 +87,7 @@ static void midi_sent(struct urb *urb)
if (status == -ESHUTDOWN)
return;
spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags);
spin_lock_irqsave(&line6->line6midi->lock, flags);
num = --line6->line6midi->num_active_send_urbs;
if (num == 0) {
......@@ -103,12 +98,12 @@ static void midi_sent(struct urb *urb)
if (num == 0)
wake_up(&line6->line6midi->send_wait);
spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags);
spin_unlock_irqrestore(&line6->line6midi->lock, flags);
}
/*
Send an asynchronous MIDI message.
Assumes that line6->line6midi->send_urb_lock is held
Assumes that line6->line6midi->lock is held
(i.e., this function is serialized).
*/
static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
......@@ -166,12 +161,12 @@ static void line6_midi_output_trigger(struct snd_rawmidi_substream *substream,
line6_rawmidi_substream_midi(substream)->line6;
line6->line6midi->substream_transmit = substream;
spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags);
spin_lock_irqsave(&line6->line6midi->lock, flags);
if (line6->line6midi->num_active_send_urbs == 0)
line6_midi_transmit(substream);
spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags);
spin_unlock_irqrestore(&line6->line6midi->lock, flags);
}
static void line6_midi_output_drain(struct snd_rawmidi_substream *substream)
......@@ -281,8 +276,7 @@ int line6_init_midi(struct usb_line6 *line6)
rmidi->private_free = snd_line6_midi_free;
init_waitqueue_head(&line6midi->send_wait);
spin_lock_init(&line6midi->send_urb_lock);
spin_lock_init(&line6midi->midi_transmit_lock);
spin_lock_init(&line6midi->lock);
line6midi->line6 = line6;
err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0);
......
......@@ -39,15 +39,10 @@ struct snd_line6_midi {
*/
int num_active_send_urbs;
/**
Spin lock to protect updates of send_urb.
*/
spinlock_t send_urb_lock;
/**
Spin lock to protect MIDI buffer handling.
*/
spinlock_t midi_transmit_lock;
spinlock_t lock;
/**
Wait queue for MIDI transmission.
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -30,12 +30,6 @@
extern struct snd_pcm_ops snd_line6_playback_ops;
extern int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm);
extern void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm);
extern int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm);
extern void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm);
extern void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm
*line6pcm);
extern void line6_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm);
extern int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd);
#endif
......@@ -399,27 +399,18 @@ static struct snd_kcontrol_new pod_control_monitor = {
/*
POD device disconnected.
*/
static void line6_pod_disconnect(struct usb_interface *interface)
static void line6_pod_disconnect(struct usb_line6 *line6)
{
struct usb_line6_pod *pod;
struct usb_line6_pod *pod = (struct usb_line6_pod *)line6;
struct device *dev = line6->ifcdev;
if (interface == NULL)
return;
pod = usb_get_intfdata(interface);
if (pod != NULL) {
struct device *dev = &interface->dev;
if (dev != NULL) {
/* remove sysfs entries: */
device_remove_file(dev, &dev_attr_device_id);
device_remove_file(dev, &dev_attr_firmware_version);
device_remove_file(dev, &dev_attr_serial_number);
}
/* remove sysfs entries: */
device_remove_file(dev, &dev_attr_device_id);
device_remove_file(dev, &dev_attr_firmware_version);
device_remove_file(dev, &dev_attr_serial_number);
del_timer_sync(&pod->startup_timer);
cancel_work_sync(&pod->startup_work);
}
del_timer_sync(&pod->startup_timer);
cancel_work_sync(&pod->startup_work);
}
/*
......@@ -444,8 +435,8 @@ static int pod_create_files2(struct device *dev)
/*
Try to init POD device.
*/
static int pod_init(struct usb_interface *interface,
struct usb_line6 *line6)
static int pod_init(struct usb_line6 *line6,
const struct usb_device_id *id)
{
int err;
struct usb_line6_pod *pod = (struct usb_line6_pod *) line6;
......@@ -456,11 +447,8 @@ static int pod_init(struct usb_interface *interface,
init_timer(&pod->startup_timer);
INIT_WORK(&pod->startup_work, pod_startup4);
if ((interface == NULL) || (pod == NULL))
return -ENODEV;
/* create sysfs entries: */
err = pod_create_files2(&interface->dev);
err = pod_create_files2(line6->ifcdev);
if (err < 0)
return err;
......@@ -603,14 +591,9 @@ static const struct line6_properties pod_properties_table[] = {
static int pod_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
struct usb_line6_pod *pod;
pod = kzalloc(sizeof(*pod), GFP_KERNEL);
if (!pod)
return -ENODEV;
return line6_probe(interface, &pod->line6,
return line6_probe(interface, id,
&pod_properties_table[id->driver_info],
pod_init);
pod_init, sizeof(struct usb_line6_pod));
}
static struct usb_driver pod_driver = {
......
......@@ -87,15 +87,11 @@ static struct line6_pcm_properties podhd_pcm_properties = {
/*
Try to init POD HD device.
*/
static int podhd_init(struct usb_interface *interface,
struct usb_line6 *line6)
static int podhd_init(struct usb_line6 *line6,
const struct usb_device_id *id)
{
struct usb_line6_podhd *podhd = (struct usb_line6_podhd *) line6;
int err;
if ((interface == NULL) || (podhd == NULL))
return -ENODEV;
/* initialize MIDI subsystem: */
err = line6_init_midi(line6);
if (err < 0)
......@@ -181,14 +177,9 @@ static const struct line6_properties podhd_properties_table[] = {
static int podhd_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
struct usb_line6_podhd *podhd;
podhd = kzalloc(sizeof(*podhd), GFP_KERNEL);
if (!podhd)
return -ENODEV;
return line6_probe(interface, &podhd->line6,
return line6_probe(interface, id,
&podhd_properties_table[id->driver_info],
podhd_init);
podhd_init, sizeof(struct usb_line6_podhd));
}
static struct usb_driver podhd_driver = {
......
......@@ -14,6 +14,7 @@
#include <linux/usb.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/leds.h>
#include <sound/core.h>
#include <sound/control.h>
......@@ -32,6 +33,15 @@ enum line6_device_type {
LINE6_TONEPORT_UX2,
};
struct usb_line6_toneport;
struct toneport_led {
struct led_classdev dev;
char name[64];
struct usb_line6_toneport *toneport;
bool registered;
};
struct usb_line6_toneport {
/**
Generic Line 6 USB data.
......@@ -62,6 +72,9 @@ struct usb_line6_toneport {
Device type.
*/
enum line6_device_type type;
/* LED instances */
struct toneport_led leds[2];
};
static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2);
......@@ -117,15 +130,6 @@ static struct line6_pcm_properties toneport_pcm_properties = {
.bytes_per_frame = 4
};
/*
For the led on Guitarport.
Brightness goes from 0x00 to 0x26. Set a value above this to have led
blink.
(void cmd_0x02(byte red, byte green)
*/
static int led_red = 0x00;
static int led_green = 0x26;
static const struct {
const char *name;
int code;
......@@ -136,62 +140,6 @@ static const struct {
{"Inst & Mic", 0x0901}
};
static bool toneport_has_led(enum line6_device_type type)
{
return
(type == LINE6_GUITARPORT) ||
(type == LINE6_TONEPORT_GX);
/* add your device here if you are missing support for the LEDs */
}
static void toneport_update_led(struct device *dev)
{
struct usb_interface *interface = to_usb_interface(dev);
struct usb_line6_toneport *tp = usb_get_intfdata(interface);
struct usb_line6 *line6;
if (!tp)
return;
line6 = &tp->line6;
if (line6)
toneport_send_cmd(line6->usbdev, (led_red << 8) | 0x0002,
led_green);
}
static ssize_t toneport_set_led_red(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int retval;
retval = kstrtoint(buf, 10, &led_red);
if (retval)
return retval;
toneport_update_led(dev);
return count;
}
static ssize_t toneport_set_led_green(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int retval;
retval = kstrtoint(buf, 10, &led_green);
if (retval)
return retval;
toneport_update_led(dev);
return count;
}
static DEVICE_ATTR(led_red, S_IWUSR | S_IRUGO, line6_nop_read,
toneport_set_led_red);
static DEVICE_ATTR(led_green, S_IWUSR | S_IRUGO, line6_nop_read,
toneport_set_led_green);
static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2)
{
int ret;
......@@ -234,16 +182,23 @@ static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
int err;
if (ucontrol->value.integer.value[0] == line6pcm->volume_monitor)
return 0;
line6pcm->volume_monitor = ucontrol->value.integer.value[0];
if (line6pcm->volume_monitor > 0)
line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_MONITOR);
else
line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR);
if (line6pcm->volume_monitor > 0) {
err = line6_pcm_acquire(line6pcm, LINE6_STREAM_MONITOR);
if (err < 0) {
line6pcm->volume_monitor = 0;
line6_pcm_release(line6pcm, LINE6_STREAM_MONITOR);
return err;
}
} else {
line6_pcm_release(line6pcm, LINE6_STREAM_MONITOR);
}
return 1;
}
......@@ -304,7 +259,7 @@ static void toneport_start_pcm(unsigned long arg)
struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg;
struct usb_line6 *line6 = &toneport->line6;
line6_pcm_acquire(line6->line6pcm, LINE6_BITS_PCM_MONITOR);
line6_pcm_acquire(line6->line6pcm, LINE6_STREAM_MONITOR);
}
/* control definition */
......@@ -329,6 +284,78 @@ static struct snd_kcontrol_new toneport_control_source = {
.put = snd_toneport_source_put
};
/*
For the led on Guitarport.
Brightness goes from 0x00 to 0x26. Set a value above this to have led
blink.
(void cmd_0x02(byte red, byte green)
*/
static bool toneport_has_led(enum line6_device_type type)
{
return
(type == LINE6_GUITARPORT) ||
(type == LINE6_TONEPORT_GX);
/* add your device here if you are missing support for the LEDs */
}
static const char * const led_colors[2] = { "red", "green" };
static const int led_init_vals[2] = { 0x00, 0x26 };
static void toneport_update_led(struct usb_line6_toneport *toneport)
{
toneport_send_cmd(toneport->line6.usbdev,
(toneport->leds[0].dev.brightness << 8) | 0x0002,
toneport->leds[1].dev.brightness);
}
static void toneport_led_brightness_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct toneport_led *leds =
container_of(led_cdev, struct toneport_led, dev);
toneport_update_led(leds->toneport);
}
static int toneport_init_leds(struct usb_line6_toneport *toneport)
{
struct device *dev = &toneport->line6.usbdev->dev;
int i, err;
for (i = 0; i < 2; i++) {
struct toneport_led *led = &toneport->leds[i];
struct led_classdev *leddev = &led->dev;
led->toneport = toneport;
snprintf(led->name, sizeof(led->name), "%s::%s",
dev_name(dev), led_colors[i]);
leddev->name = led->name;
leddev->brightness = led_init_vals[i];
leddev->max_brightness = 0x26;
leddev->brightness_set = toneport_led_brightness_set;
err = led_classdev_register(dev, leddev);
if (err)
return err;
led->registered = true;
}
return 0;
}
static void toneport_remove_leds(struct usb_line6_toneport *toneport)
{
struct toneport_led *led;
int i;
for (i = 0; i < 2; i++) {
led = &toneport->leds[i];
if (!led->registered)
break;
led_classdev_unregister(&led->dev);
led->registered = false;
}
}
/*
Setup Toneport device.
*/
......@@ -359,42 +386,38 @@ static void toneport_setup(struct usb_line6_toneport *toneport)
}
if (toneport_has_led(toneport->type))
toneport_update_led(&usbdev->dev);
toneport_update_led(toneport);
mod_timer(&toneport->timer, jiffies + TONEPORT_PCM_DELAY * HZ);
}
/*
Toneport device disconnected.
*/
static void line6_toneport_disconnect(struct usb_interface *interface)
static void line6_toneport_disconnect(struct usb_line6 *line6)
{
struct usb_line6_toneport *toneport;
u16 idProduct;
if (interface == NULL)
return;
struct usb_line6_toneport *toneport =
(struct usb_line6_toneport *)line6;
toneport = usb_get_intfdata(interface);
del_timer_sync(&toneport->timer);
idProduct = le16_to_cpu(toneport->line6.usbdev->descriptor.idProduct);
if (toneport_has_led(idProduct)) {
device_remove_file(&interface->dev, &dev_attr_led_red);
device_remove_file(&interface->dev, &dev_attr_led_green);
}
if (toneport_has_led(toneport->type))
toneport_remove_leds(toneport);
}
/*
Try to init Toneport device.
*/
static int toneport_init(struct usb_interface *interface,
struct usb_line6 *line6)
static int toneport_init(struct usb_line6 *line6,
const struct usb_device_id *id)
{
int err;
struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6;
if ((interface == NULL) || (toneport == NULL))
return -ENODEV;
toneport->type = id->driver_info;
setup_timer(&toneport->timer, toneport_start_pcm,
(unsigned long)toneport);
line6->disconnect = line6_toneport_disconnect;
......@@ -431,20 +454,13 @@ static int toneport_init(struct usb_interface *interface,
line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1);
if (toneport_has_led(toneport->type)) {
err = device_create_file(&interface->dev, &dev_attr_led_red);
if (err < 0)
return err;
err = device_create_file(&interface->dev, &dev_attr_led_green);
err = toneport_init_leds(toneport);
if (err < 0)
return err;
}
toneport_setup(toneport);
setup_timer(&toneport->timer, toneport_start_pcm,
(unsigned long)toneport);
mod_timer(&toneport->timer, jiffies + TONEPORT_PCM_DELAY * HZ);
/* register audio system: */
return snd_card_register(line6->card);
}
......@@ -549,15 +565,9 @@ static const struct line6_properties toneport_properties_table[] = {
static int toneport_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
struct usb_line6_toneport *toneport;
toneport = kzalloc(sizeof(*toneport), GFP_KERNEL);
if (!toneport)
return -ENODEV;
toneport->type = id->driver_info;
return line6_probe(interface, &toneport->line6,
return line6_probe(interface, id,
&toneport_properties_table[id->driver_info],
toneport_init);
toneport_init, sizeof(struct usb_line6_toneport));
}
static struct usb_driver toneport_driver = {
......
......@@ -210,16 +210,9 @@ static void line6_variax_process_message(struct usb_line6 *line6)
/*
Variax destructor.
*/
static void line6_variax_disconnect(struct usb_interface *interface)
static void line6_variax_disconnect(struct usb_line6 *line6)
{
struct usb_line6_variax *variax;
if (!interface)
return;
variax = usb_get_intfdata(interface);
if (!variax)
return;
struct usb_line6_variax *variax = (struct usb_line6_variax *)line6;
del_timer(&variax->startup_timer1);
del_timer(&variax->startup_timer2);
......@@ -231,8 +224,8 @@ static void line6_variax_disconnect(struct usb_interface *interface)
/*
Try to init workbench device.
*/
static int variax_init(struct usb_interface *interface,
struct usb_line6 *line6)
static int variax_init(struct usb_line6 *line6,
const struct usb_device_id *id)
{
struct usb_line6_variax *variax = (struct usb_line6_variax *) line6;
int err;
......@@ -244,9 +237,6 @@ static int variax_init(struct usb_interface *interface,
init_timer(&variax->startup_timer2);
INIT_WORK(&variax->startup_work, variax_startup6);
if ((interface == NULL) || (variax == NULL))
return -ENODEV;
/* initialize USB buffers: */
variax->buffer_activate = kmemdup(variax_activate,
sizeof(variax_activate), GFP_KERNEL);
......@@ -306,14 +296,9 @@ static const struct line6_properties variax_properties_table[] = {
static int variax_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
struct usb_line6_variax *variax;
variax = kzalloc(sizeof(*variax), GFP_KERNEL);
if (!variax)
return -ENODEV;
return line6_probe(interface, &variax->line6,
return line6_probe(interface, id,
&variax_properties_table[id->driver_info],
variax_init);
variax_init, sizeof(struct usb_line6_variax));
}
static struct usb_driver variax_driver = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment