suspend & resume implementations
This commit is contained in:
parent
76a3719cf9
commit
df642295da
107
us144mkii.c
107
us144mkii.c
|
|
@ -21,9 +21,20 @@ MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
#define DRIVER_NAME "snd-usb-us144mkii"
|
#define DRIVER_NAME "snd-usb-us144mkii"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO:
|
||||||
|
* - Implement audio input capture.
|
||||||
|
* - Implement MIDI IN/OUT.
|
||||||
|
* - Expose hardware features via the ALSA Control API (mixers):
|
||||||
|
* - Digital output format selection.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* --- Module Parameters --- */
|
||||||
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
|
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
|
||||||
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
|
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
|
||||||
static bool enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
|
static bool enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
|
||||||
|
static int dev_idx;
|
||||||
|
|
||||||
module_param_array(index, int, NULL, 0444);
|
module_param_array(index, int, NULL, 0444);
|
||||||
MODULE_PARM_DESC(index, "Index value for the US-144MKII soundcard.");
|
MODULE_PARM_DESC(index, "Index value for the US-144MKII soundcard.");
|
||||||
|
|
@ -41,7 +52,7 @@ MODULE_PARM_DESC(enable, "Enable this US-144MKII soundcard.");
|
||||||
#define EP_AUDIO_OUT 0x02
|
#define EP_AUDIO_OUT 0x02
|
||||||
#define EP_MIDI_IN 0x83
|
#define EP_MIDI_IN 0x83
|
||||||
#define EP_MIDI_OUT 0x04
|
#define EP_MIDI_OUT 0x04
|
||||||
#define EP_CAPTURE_DATA 0x86
|
#define EP_AUDIO_IN 0x86
|
||||||
|
|
||||||
/* --- USB Control Message Protocol --- */
|
/* --- USB Control Message Protocol --- */
|
||||||
#define RT_H2D_CLASS_EP (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT)
|
#define RT_H2D_CLASS_EP (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT)
|
||||||
|
|
@ -83,6 +94,16 @@ MODULE_PARM_DESC(enable, "Enable this US-144MKII soundcard.");
|
||||||
struct tascam_card;
|
struct tascam_card;
|
||||||
static struct usb_driver tascam_alsa_driver;
|
static struct usb_driver tascam_alsa_driver;
|
||||||
|
|
||||||
|
/* --- Forward Declarations --- */
|
||||||
|
static void playback_urb_complete(struct urb *urb);
|
||||||
|
static void feedback_urb_complete(struct urb *urb);
|
||||||
|
static int us144mkii_configure_device_for_rate(struct tascam_card *tascam, int rate);
|
||||||
|
static int tascam_probe(struct usb_interface *intf, const struct usb_device_id *id);
|
||||||
|
static void tascam_disconnect(struct usb_interface *intf);
|
||||||
|
static int tascam_suspend(struct usb_interface *intf, pm_message_t message);
|
||||||
|
static int tascam_resume(struct usb_interface *intf);
|
||||||
|
|
||||||
|
/* --- Rate-to-Packet Fixing Data --- */
|
||||||
static const unsigned int patterns_48khz[5][8] = {
|
static const unsigned int patterns_48khz[5][8] = {
|
||||||
{5, 6, 6, 6, 5, 6, 6, 6}, {5, 6, 6, 6, 6, 6, 6, 6},
|
{5, 6, 6, 6, 5, 6, 6, 6}, {5, 6, 6, 6, 6, 6, 6, 6},
|
||||||
{6, 6, 6, 6, 6, 6, 6, 6}, {7, 6, 6, 6, 6, 6, 6, 6},
|
{6, 6, 6, 6, 6, 6, 6, 6}, {7, 6, 6, 6, 6, 6, 6, 6},
|
||||||
|
|
@ -104,6 +125,7 @@ static const unsigned int patterns_44khz[5][8] = {
|
||||||
{6, 6, 6, 5, 6, 6, 6, 5}
|
{6, 6, 6, 5, 6, 6, 6, 5}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* --- Main Driver Data Structure --- */
|
||||||
struct tascam_card {
|
struct tascam_card {
|
||||||
struct usb_device *dev;
|
struct usb_device *dev;
|
||||||
struct usb_interface *iface0;
|
struct usb_interface *iface0;
|
||||||
|
|
@ -141,9 +163,6 @@ struct tascam_card {
|
||||||
static const unsigned int playback_iso_packet_counts_tiers[] = { 8, 24, 40 };
|
static const unsigned int playback_iso_packet_counts_tiers[] = { 8, 24, 40 };
|
||||||
static const unsigned int hardware_feedback_packet_counts[] = { 1, 2, 5 };
|
static const unsigned int hardware_feedback_packet_counts[] = { 1, 2, 5 };
|
||||||
|
|
||||||
static void playback_urb_complete(struct urb *urb);
|
|
||||||
static void feedback_urb_complete(struct urb *urb);
|
|
||||||
|
|
||||||
static const struct snd_pcm_hardware tascam_pcm_hw = {
|
static const struct snd_pcm_hardware tascam_pcm_hw = {
|
||||||
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
|
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
|
||||||
SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID |
|
SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID |
|
||||||
|
|
@ -312,7 +331,7 @@ static int us144mkii_configure_device_for_rate(struct tascam_card *tascam, int r
|
||||||
|
|
||||||
err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), VENDOR_REQ_MODE_CONTROL, RT_H2D_VENDOR_DEV, MODE_VAL_CONFIG, 0x0000, NULL, 0, USB_CTRL_TIMEOUT_MS);
|
err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), VENDOR_REQ_MODE_CONTROL, RT_H2D_VENDOR_DEV, MODE_VAL_CONFIG, 0x0000, NULL, 0, USB_CTRL_TIMEOUT_MS);
|
||||||
if (err < 0) goto fail;
|
if (err < 0) goto fail;
|
||||||
err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, RT_H2D_CLASS_EP, UAC_SAMPLING_FREQ_CONTROL, EP_CAPTURE_DATA, rate_payload_buf, 3, USB_CTRL_TIMEOUT_MS);
|
err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, RT_H2D_CLASS_EP, UAC_SAMPLING_FREQ_CONTROL, EP_AUDIO_IN, rate_payload_buf, 3, USB_CTRL_TIMEOUT_MS);
|
||||||
if (err < 0) goto fail;
|
if (err < 0) goto fail;
|
||||||
err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, RT_H2D_CLASS_EP, UAC_SAMPLING_FREQ_CONTROL, EP_AUDIO_OUT, rate_payload_buf, 3, USB_CTRL_TIMEOUT_MS);
|
err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, RT_H2D_CLASS_EP, UAC_SAMPLING_FREQ_CONTROL, EP_AUDIO_OUT, rate_payload_buf, 3, USB_CTRL_TIMEOUT_MS);
|
||||||
if (err < 0) goto fail;
|
if (err < 0) goto fail;
|
||||||
|
|
@ -687,13 +706,87 @@ static void tascam_card_private_free(struct snd_card *card)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tascam_suspend - Called when the device is being suspended.
|
||||||
|
* @intf: The USB interface.
|
||||||
|
* @message: Power management message.
|
||||||
|
*
|
||||||
|
* Stops all active audio streams to prepare for system sleep.
|
||||||
|
*
|
||||||
|
* Returns: 0 on success.
|
||||||
|
*/
|
||||||
|
static int tascam_suspend(struct usb_interface *intf, pm_message_t message)
|
||||||
|
{
|
||||||
|
struct tascam_card *tascam = usb_get_intfdata(intf);
|
||||||
|
|
||||||
|
if (!tascam || !tascam->pcm)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
snd_pcm_suspend_all(tascam->pcm);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tascam_resume - Called when the device is being resumed.
|
||||||
|
* @intf: The USB interface.
|
||||||
|
*
|
||||||
|
* Re-initializes the device hardware after system resume, restoring its
|
||||||
|
* alternate settings and sample rate configuration. This is necessary because
|
||||||
|
* the device may lose its state during suspend.
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, or a negative error code on failure.
|
||||||
|
*/
|
||||||
|
static int tascam_resume(struct usb_interface *intf)
|
||||||
|
{
|
||||||
|
struct tascam_card *tascam = usb_get_intfdata(intf);
|
||||||
|
struct usb_device *dev;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!tascam)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
dev = tascam->dev;
|
||||||
|
dev_info(&intf->dev, "Resuming and re-initializing device...\n");
|
||||||
|
|
||||||
|
/* Re-establish alternate settings for both interfaces */
|
||||||
|
err = usb_set_interface(dev, 0, 1);
|
||||||
|
if (err < 0) {
|
||||||
|
dev_err(&intf->dev, "Resume: Set Alt Setting on Intf 0 failed: %d\n", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
err = usb_set_interface(dev, 1, 1);
|
||||||
|
if (err < 0) {
|
||||||
|
dev_err(&intf->dev, "Resume: Set Alt Setting on Intf 1 failed: %d\n", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Re-configure the device for the last used sample rate.
|
||||||
|
* If no stream was ever started, current_rate will be 0, and we skip this.
|
||||||
|
* The ALSA core will handle resuming the PCM streams, which will
|
||||||
|
* trigger our .prepare and .trigger ops as needed.
|
||||||
|
*/
|
||||||
|
if (tascam->current_rate > 0) {
|
||||||
|
dev_info(&intf->dev, "Restoring sample rate to %d Hz\n", tascam->current_rate);
|
||||||
|
err = us144mkii_configure_device_for_rate(tascam, tascam->current_rate);
|
||||||
|
if (err < 0) {
|
||||||
|
dev_err(&intf->dev, "Resume: Failed to restore sample rate configuration\n");
|
||||||
|
/* Invalidate the rate so the next hw_params will re-configure fully. */
|
||||||
|
tascam->current_rate = 0;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int tascam_probe(struct usb_interface *intf, const struct usb_device_id *usb_id)
|
static int tascam_probe(struct usb_interface *intf, const struct usb_device_id *usb_id)
|
||||||
{
|
{
|
||||||
struct usb_device *dev = interface_to_usbdev(intf);
|
struct usb_device *dev = interface_to_usbdev(intf);
|
||||||
struct tascam_card *tascam;
|
struct tascam_card *tascam;
|
||||||
struct snd_card *card;
|
struct snd_card *card;
|
||||||
int err;
|
int err;
|
||||||
static int dev_idx;
|
|
||||||
u8 *handshake_buf;
|
u8 *handshake_buf;
|
||||||
|
|
||||||
if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
|
if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
|
||||||
|
|
@ -820,6 +913,8 @@ static struct usb_driver tascam_alsa_driver = {
|
||||||
.probe = tascam_probe,
|
.probe = tascam_probe,
|
||||||
.disconnect = tascam_disconnect,
|
.disconnect = tascam_disconnect,
|
||||||
.id_table = tascam_id_table,
|
.id_table = tascam_id_table,
|
||||||
|
.suspend = tascam_suspend,
|
||||||
|
.resume = tascam_resume,
|
||||||
};
|
};
|
||||||
|
|
||||||
module_usb_driver(tascam_alsa_driver);
|
module_usb_driver(tascam_alsa_driver);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue