aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2005-04-29 10:26:14 -0400
committerJaroslav Kysela <perex@suse.cz>2005-05-29 04:05:40 -0400
commit6639b6c2367f884ca172b78d69f7da17bfab2e5e (patch)
tree5e2a119766b6199f7ce873e31c44e1462b206138 /sound/usb
parent84957a8ab086377a025e0448fa716ed5983f3c3a (diff)
[ALSA] usb-audio - add mixer control notifications
USB generic driver Add support for the optional status interrupt endpoint in audio control interfaces, and translate USB status notifications into ALSA mixer control notifications. Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Diffstat (limited to 'sound/usb')
-rw-r--r--sound/usb/usbmixer.c101
1 files changed, 98 insertions, 3 deletions
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
index 7bbccebd76c6..dd045ea6fb01 100644
--- a/sound/usb/usbmixer.c
+++ b/sound/usb/usbmixer.c
@@ -55,6 +55,8 @@ struct usb_mixer_interface {
55 unsigned int ctrlif; 55 unsigned int ctrlif;
56 struct list_head list; 56 struct list_head list;
57 unsigned int ignore_ctl_error; 57 unsigned int ignore_ctl_error;
58 struct urb *urb;
59 usb_mixer_elem_info_t **id_elems; /* array[256], indexed by unit id */
58}; 60};
59 61
60 62
@@ -83,13 +85,15 @@ struct usb_mixer_build {
83 85
84struct usb_mixer_elem_info { 86struct usb_mixer_elem_info {
85 struct usb_mixer_interface *mixer; 87 struct usb_mixer_interface *mixer;
88 usb_mixer_elem_info_t *next_id_elem; /* list of controls with same id */
89 snd_ctl_elem_id_t *elem_id;
86 unsigned int id; 90 unsigned int id;
87 unsigned int control; /* CS or ICN (high byte) */ 91 unsigned int control; /* CS or ICN (high byte) */
88 unsigned int cmask; /* channel mask bitmap: 0 = master */ 92 unsigned int cmask; /* channel mask bitmap: 0 = master */
89 int channels; 93 int channels;
90 int val_type; 94 int val_type;
91 int min, max, res; 95 int min, max, res;
92 unsigned int initialized: 1; 96 u8 initialized;
93}; 97};
94 98
95 99
@@ -414,6 +418,7 @@ static int check_matrix_bitmap(unsigned char *bmap, int ich, int och, int num_ou
414 418
415static int add_control_to_empty(mixer_build_t *state, snd_kcontrol_t *kctl) 419static int add_control_to_empty(mixer_build_t *state, snd_kcontrol_t *kctl)
416{ 420{
421 usb_mixer_elem_info_t *cval = kctl->private_data;
417 int err; 422 int err;
418 423
419 while (snd_ctl_find_id(state->chip->card, &kctl->id)) 424 while (snd_ctl_find_id(state->chip->card, &kctl->id))
@@ -421,8 +426,12 @@ static int add_control_to_empty(mixer_build_t *state, snd_kcontrol_t *kctl)
421 if ((err = snd_ctl_add(state->chip->card, kctl)) < 0) { 426 if ((err = snd_ctl_add(state->chip->card, kctl)) < 0) {
422 snd_printd(KERN_ERR "cannot add control (err = %d)\n", err); 427 snd_printd(KERN_ERR "cannot add control (err = %d)\n", err);
423 snd_ctl_free_one(kctl); 428 snd_ctl_free_one(kctl);
429 return err;
424 } 430 }
425 return err; 431 cval->elem_id = &kctl->id;
432 cval->next_id_elem = state->mixer->id_elems[cval->id];
433 state->mixer->id_elems[cval->id] = cval;
434 return 0;
426} 435}
427 436
428 437
@@ -1522,6 +1531,11 @@ static int parse_audio_unit(mixer_build_t *state, int unitid)
1522 1531
1523static void snd_usb_mixer_free(struct usb_mixer_interface *mixer) 1532static void snd_usb_mixer_free(struct usb_mixer_interface *mixer)
1524{ 1533{
1534 kfree(mixer->id_elems);
1535 if (mixer->urb) {
1536 kfree(mixer->urb->transfer_buffer);
1537 usb_free_urb(mixer->urb);
1538 }
1525 kfree(mixer); 1539 kfree(mixer);
1526} 1540}
1527 1541
@@ -1580,6 +1594,76 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
1580 return 0; 1594 return 0;
1581} 1595}
1582 1596
1597static void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer,
1598 int unitid)
1599{
1600 usb_mixer_elem_info_t *info;
1601
1602 for (info = mixer->id_elems[unitid]; info; info = info->next_id_elem)
1603 snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
1604 info->elem_id);
1605}
1606
1607static void snd_usb_mixer_status_complete(struct urb *urb, struct pt_regs *regs)
1608{
1609 struct usb_mixer_interface *mixer = urb->context;
1610
1611 if (urb->status == 0) {
1612 u8 *buf = urb->transfer_buffer;
1613 int i;
1614
1615 for (i = urb->actual_length; i >= 2; buf += 2, i -= 2) {
1616 snd_printd(KERN_DEBUG "status interrupt: %02x %02x\n",
1617 buf[0], buf[1]);
1618 /* ignore any notifications not from the control interface */
1619 if ((buf[0] & 0x0f) != 0)
1620 continue;
1621 if (!(buf[0] & 0x40))
1622 snd_usb_mixer_notify_id(mixer, buf[1]);
1623 }
1624 }
1625 if (urb->status != -ENOENT && urb->status != -ECONNRESET) {
1626 urb->dev = mixer->chip->dev;
1627 usb_submit_urb(urb, GFP_ATOMIC);
1628 }
1629}
1630
1631/* create the handler for the optional status interrupt endpoint */
1632static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer)
1633{
1634 struct usb_host_interface *hostif;
1635 struct usb_endpoint_descriptor *ep;
1636 void *transfer_buffer;
1637 int buffer_length;
1638 unsigned int epnum;
1639
1640 hostif = &usb_ifnum_to_if(mixer->chip->dev, mixer->ctrlif)->altsetting[0];
1641 /* we need one interrupt input endpoint */
1642 if (get_iface_desc(hostif)->bNumEndpoints < 1)
1643 return 0;
1644 ep = get_endpoint(hostif, 0);
1645 if ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_IN ||
1646 (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT)
1647 return 0;
1648
1649 epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
1650 buffer_length = le16_to_cpu(ep->wMaxPacketSize);
1651 transfer_buffer = kmalloc(buffer_length, GFP_KERNEL);
1652 if (!transfer_buffer)
1653 return -ENOMEM;
1654 mixer->urb = usb_alloc_urb(0, GFP_KERNEL);
1655 if (!mixer->urb) {
1656 kfree(transfer_buffer);
1657 return -ENOMEM;
1658 }
1659 usb_fill_int_urb(mixer->urb, mixer->chip->dev,
1660 usb_rcvintpipe(mixer->chip->dev, epnum),
1661 transfer_buffer, buffer_length,
1662 snd_usb_mixer_status_complete, mixer, ep->bInterval);
1663 usb_submit_urb(mixer->urb, GFP_KERNEL);
1664 return 0;
1665}
1666
1583int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) 1667int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif)
1584{ 1668{
1585 static snd_device_ops_t dev_ops = { 1669 static snd_device_ops_t dev_ops = {
@@ -1598,8 +1682,14 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif)
1598#ifdef IGNORE_CTL_ERROR 1682#ifdef IGNORE_CTL_ERROR
1599 mixer->ignore_ctl_error = 1; 1683 mixer->ignore_ctl_error = 1;
1600#endif 1684#endif
1685 mixer->id_elems = kcalloc(256, sizeof(*mixer->id_elems), GFP_KERNEL);
1686 if (!mixer->id_elems) {
1687 kfree(mixer);
1688 return -ENOMEM;
1689 }
1601 1690
1602 if ((err = snd_usb_mixer_controls(mixer)) < 0) { 1691 if ((err = snd_usb_mixer_controls(mixer)) < 0 ||
1692 (err = snd_usb_mixer_status_create(mixer)) < 0) {
1603 snd_usb_mixer_free(mixer); 1693 snd_usb_mixer_free(mixer);
1604 return err; 1694 return err;
1605 } 1695 }
@@ -1615,4 +1705,9 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif)
1615 1705
1616void snd_usb_mixer_disconnect(struct list_head *p) 1706void snd_usb_mixer_disconnect(struct list_head *p)
1617{ 1707{
1708 struct usb_mixer_interface *mixer;
1709
1710 mixer = list_entry(p, struct usb_mixer_interface, list);
1711 if (mixer->urb)
1712 usb_kill_urb(mixer->urb);
1618} 1713}