diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-07 11:09:02 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-07 11:09:02 -0500 |
commit | 8f0cb147b2fb12427bf6abef7fed2b604557a41e (patch) | |
tree | fb5ba437ee74b900fab9686c8c7df18abcd7640b /sound/usb/usbaudio.c | |
parent | 8e33ba49765484bc6de3a2f8143733713fa93bc1 (diff) | |
parent | b00e8443c3eece823052d06ae1c7cb797ab0ddf5 (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa
Diffstat (limited to 'sound/usb/usbaudio.c')
-rw-r--r-- | sound/usb/usbaudio.c | 144 |
1 files changed, 75 insertions, 69 deletions
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 2ead878bcb8f..99dae024b640 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c | |||
@@ -41,7 +41,6 @@ | |||
41 | #include <sound/driver.h> | 41 | #include <sound/driver.h> |
42 | #include <linux/bitops.h> | 42 | #include <linux/bitops.h> |
43 | #include <linux/init.h> | 43 | #include <linux/init.h> |
44 | #include <linux/interrupt.h> | ||
45 | #include <linux/list.h> | 44 | #include <linux/list.h> |
46 | #include <linux/slab.h> | 45 | #include <linux/slab.h> |
47 | #include <linux/string.h> | 46 | #include <linux/string.h> |
@@ -185,7 +184,6 @@ struct snd_usb_substream { | |||
185 | unsigned int num_formats; /* number of supported audio formats (list) */ | 184 | unsigned int num_formats; /* number of supported audio formats (list) */ |
186 | struct list_head fmt_list; /* format list */ | 185 | struct list_head fmt_list; /* format list */ |
187 | spinlock_t lock; | 186 | spinlock_t lock; |
188 | struct tasklet_struct start_period_elapsed; /* for start trigger */ | ||
189 | 187 | ||
190 | struct snd_urb_ops ops; /* callbacks (must be filled at init) */ | 188 | struct snd_urb_ops ops; /* callbacks (must be filled at init) */ |
191 | }; | 189 | }; |
@@ -480,6 +478,28 @@ static int retire_playback_sync_urb_hs(snd_usb_substream_t *subs, | |||
480 | } | 478 | } |
481 | 479 | ||
482 | /* | 480 | /* |
481 | * Prepare urb for streaming before playback starts. | ||
482 | * | ||
483 | * We don't care about (or have) any data, so we just send a transfer delimiter. | ||
484 | */ | ||
485 | static int prepare_startup_playback_urb(snd_usb_substream_t *subs, | ||
486 | snd_pcm_runtime_t *runtime, | ||
487 | struct urb *urb) | ||
488 | { | ||
489 | unsigned int i; | ||
490 | snd_urb_ctx_t *ctx = urb->context; | ||
491 | |||
492 | urb->dev = ctx->subs->dev; | ||
493 | urb->number_of_packets = subs->packs_per_ms; | ||
494 | for (i = 0; i < subs->packs_per_ms; ++i) { | ||
495 | urb->iso_frame_desc[i].offset = 0; | ||
496 | urb->iso_frame_desc[i].length = 0; | ||
497 | } | ||
498 | urb->transfer_buffer_length = 0; | ||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | /* | ||
483 | * prepare urb for playback data pipe | 503 | * prepare urb for playback data pipe |
484 | * | 504 | * |
485 | * Since a URB can handle only a single linear buffer, we must use double | 505 | * Since a URB can handle only a single linear buffer, we must use double |
@@ -568,12 +588,8 @@ static int prepare_playback_urb(snd_usb_substream_t *subs, | |||
568 | subs->hwptr_done -= runtime->buffer_size; | 588 | subs->hwptr_done -= runtime->buffer_size; |
569 | spin_unlock_irqrestore(&subs->lock, flags); | 589 | spin_unlock_irqrestore(&subs->lock, flags); |
570 | urb->transfer_buffer_length = offs * stride; | 590 | urb->transfer_buffer_length = offs * stride; |
571 | if (period_elapsed) { | 591 | if (period_elapsed) |
572 | if (likely(subs->running)) | 592 | snd_pcm_period_elapsed(subs->pcm_substream); |
573 | snd_pcm_period_elapsed(subs->pcm_substream); | ||
574 | else | ||
575 | tasklet_hi_schedule(&subs->start_period_elapsed); | ||
576 | } | ||
577 | return 0; | 593 | return 0; |
578 | } | 594 | } |
579 | 595 | ||
@@ -588,22 +604,12 @@ static int retire_playback_urb(snd_usb_substream_t *subs, | |||
588 | return 0; | 604 | return 0; |
589 | } | 605 | } |
590 | 606 | ||
591 | /* | ||
592 | * Delay the snd_pcm_period_elapsed() call until after the start trigger | ||
593 | * callback so that we're not longer in the substream's lock. | ||
594 | */ | ||
595 | static void start_period_elapsed(unsigned long data) | ||
596 | { | ||
597 | snd_usb_substream_t *subs = (snd_usb_substream_t *)data; | ||
598 | snd_pcm_period_elapsed(subs->pcm_substream); | ||
599 | } | ||
600 | |||
601 | 607 | ||
602 | /* | 608 | /* |
603 | */ | 609 | */ |
604 | static struct snd_urb_ops audio_urb_ops[2] = { | 610 | static struct snd_urb_ops audio_urb_ops[2] = { |
605 | { | 611 | { |
606 | .prepare = prepare_playback_urb, | 612 | .prepare = prepare_startup_playback_urb, |
607 | .retire = retire_playback_urb, | 613 | .retire = retire_playback_urb, |
608 | .prepare_sync = prepare_playback_sync_urb, | 614 | .prepare_sync = prepare_playback_sync_urb, |
609 | .retire_sync = retire_playback_sync_urb, | 615 | .retire_sync = retire_playback_sync_urb, |
@@ -618,7 +624,7 @@ static struct snd_urb_ops audio_urb_ops[2] = { | |||
618 | 624 | ||
619 | static struct snd_urb_ops audio_urb_ops_high_speed[2] = { | 625 | static struct snd_urb_ops audio_urb_ops_high_speed[2] = { |
620 | { | 626 | { |
621 | .prepare = prepare_playback_urb, | 627 | .prepare = prepare_startup_playback_urb, |
622 | .retire = retire_playback_urb, | 628 | .retire = retire_playback_urb, |
623 | .prepare_sync = prepare_playback_sync_urb_hs, | 629 | .prepare_sync = prepare_playback_sync_urb_hs, |
624 | .retire_sync = retire_playback_sync_urb_hs, | 630 | .retire_sync = retire_playback_sync_urb_hs, |
@@ -692,9 +698,9 @@ static int snd_pcm_alloc_vmalloc_buffer(snd_pcm_substream_t *subs, size_t size) | |||
692 | if (runtime->dma_area) { | 698 | if (runtime->dma_area) { |
693 | if (runtime->dma_bytes >= size) | 699 | if (runtime->dma_bytes >= size) |
694 | return 0; /* already large enough */ | 700 | return 0; /* already large enough */ |
695 | vfree_nocheck(runtime->dma_area); | 701 | vfree(runtime->dma_area); |
696 | } | 702 | } |
697 | runtime->dma_area = vmalloc_nocheck(size); | 703 | runtime->dma_area = vmalloc(size); |
698 | if (! runtime->dma_area) | 704 | if (! runtime->dma_area) |
699 | return -ENOMEM; | 705 | return -ENOMEM; |
700 | runtime->dma_bytes = size; | 706 | runtime->dma_bytes = size; |
@@ -706,7 +712,7 @@ static int snd_pcm_free_vmalloc_buffer(snd_pcm_substream_t *subs) | |||
706 | { | 712 | { |
707 | snd_pcm_runtime_t *runtime = subs->runtime; | 713 | snd_pcm_runtime_t *runtime = subs->runtime; |
708 | if (runtime->dma_area) { | 714 | if (runtime->dma_area) { |
709 | vfree_nocheck(runtime->dma_area); | 715 | vfree(runtime->dma_area); |
710 | runtime->dma_area = NULL; | 716 | runtime->dma_area = NULL; |
711 | } | 717 | } |
712 | return 0; | 718 | return 0; |
@@ -838,8 +844,7 @@ static int wait_clear_urbs(snd_usb_substream_t *subs) | |||
838 | } | 844 | } |
839 | if (! alive) | 845 | if (! alive) |
840 | break; | 846 | break; |
841 | set_current_state(TASK_UNINTERRUPTIBLE); | 847 | schedule_timeout_uninterruptible(1); |
842 | schedule_timeout(1); | ||
843 | } while (time_before(jiffies, end_time)); | 848 | } while (time_before(jiffies, end_time)); |
844 | if (alive) | 849 | if (alive) |
845 | snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive); | 850 | snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive); |
@@ -864,25 +869,40 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(snd_pcm_substream_t *substream) | |||
864 | 869 | ||
865 | 870 | ||
866 | /* | 871 | /* |
867 | * start/stop substream | 872 | * start/stop playback substream |
868 | */ | 873 | */ |
869 | static int snd_usb_pcm_trigger(snd_pcm_substream_t *substream, int cmd) | 874 | static int snd_usb_pcm_playback_trigger(snd_pcm_substream_t *substream, |
875 | int cmd) | ||
870 | { | 876 | { |
871 | snd_usb_substream_t *subs = (snd_usb_substream_t *)substream->runtime->private_data; | 877 | snd_usb_substream_t *subs = substream->runtime->private_data; |
872 | int err; | ||
873 | 878 | ||
874 | switch (cmd) { | 879 | switch (cmd) { |
875 | case SNDRV_PCM_TRIGGER_START: | 880 | case SNDRV_PCM_TRIGGER_START: |
876 | err = start_urbs(subs, substream->runtime); | 881 | subs->ops.prepare = prepare_playback_urb; |
877 | break; | 882 | return 0; |
878 | case SNDRV_PCM_TRIGGER_STOP: | 883 | case SNDRV_PCM_TRIGGER_STOP: |
879 | err = deactivate_urbs(subs, 0, 0); | 884 | return deactivate_urbs(subs, 0, 0); |
880 | break; | ||
881 | default: | 885 | default: |
882 | err = -EINVAL; | 886 | return -EINVAL; |
883 | break; | 887 | } |
888 | } | ||
889 | |||
890 | /* | ||
891 | * start/stop capture substream | ||
892 | */ | ||
893 | static int snd_usb_pcm_capture_trigger(snd_pcm_substream_t *substream, | ||
894 | int cmd) | ||
895 | { | ||
896 | snd_usb_substream_t *subs = substream->runtime->private_data; | ||
897 | |||
898 | switch (cmd) { | ||
899 | case SNDRV_PCM_TRIGGER_START: | ||
900 | return start_urbs(subs, substream->runtime); | ||
901 | case SNDRV_PCM_TRIGGER_STOP: | ||
902 | return deactivate_urbs(subs, 0, 0); | ||
903 | default: | ||
904 | return -EINVAL; | ||
884 | } | 905 | } |
885 | return err < 0 ? err : 0; | ||
886 | } | 906 | } |
887 | 907 | ||
888 | 908 | ||
@@ -1044,7 +1064,7 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by | |||
1044 | u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; | 1064 | u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; |
1045 | u->urb->interval = 1 << subs->datainterval; | 1065 | u->urb->interval = 1 << subs->datainterval; |
1046 | u->urb->context = u; | 1066 | u->urb->context = u; |
1047 | u->urb->complete = snd_usb_complete_callback(snd_complete_urb); | 1067 | u->urb->complete = snd_complete_urb; |
1048 | } | 1068 | } |
1049 | 1069 | ||
1050 | if (subs->syncpipe) { | 1070 | if (subs->syncpipe) { |
@@ -1070,7 +1090,7 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by | |||
1070 | u->urb->number_of_packets = 1; | 1090 | u->urb->number_of_packets = 1; |
1071 | u->urb->interval = 1 << subs->syncinterval; | 1091 | u->urb->interval = 1 << subs->syncinterval; |
1072 | u->urb->context = u; | 1092 | u->urb->context = u; |
1073 | u->urb->complete = snd_usb_complete_callback(snd_complete_sync_urb); | 1093 | u->urb->complete = snd_complete_sync_urb; |
1074 | } | 1094 | } |
1075 | } | 1095 | } |
1076 | return 0; | 1096 | return 0; |
@@ -1414,7 +1434,7 @@ static int snd_usb_hw_free(snd_pcm_substream_t *substream) | |||
1414 | static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream) | 1434 | static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream) |
1415 | { | 1435 | { |
1416 | snd_pcm_runtime_t *runtime = substream->runtime; | 1436 | snd_pcm_runtime_t *runtime = substream->runtime; |
1417 | snd_usb_substream_t *subs = (snd_usb_substream_t *)runtime->private_data; | 1437 | snd_usb_substream_t *subs = runtime->private_data; |
1418 | 1438 | ||
1419 | if (! subs->cur_audiofmt) { | 1439 | if (! subs->cur_audiofmt) { |
1420 | snd_printk(KERN_ERR "usbaudio: no format is specified!\n"); | 1440 | snd_printk(KERN_ERR "usbaudio: no format is specified!\n"); |
@@ -1434,7 +1454,13 @@ static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream) | |||
1434 | deactivate_urbs(subs, 0, 1); | 1454 | deactivate_urbs(subs, 0, 1); |
1435 | wait_clear_urbs(subs); | 1455 | wait_clear_urbs(subs); |
1436 | 1456 | ||
1437 | return 0; | 1457 | /* for playback, submit the URBs now; otherwise, the first hwptr_done |
1458 | * updates for all URBs would happen at the same time when starting */ | ||
1459 | if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) { | ||
1460 | subs->ops.prepare = prepare_startup_playback_urb; | ||
1461 | return start_urbs(subs, runtime); | ||
1462 | } else | ||
1463 | return 0; | ||
1438 | } | 1464 | } |
1439 | 1465 | ||
1440 | static snd_pcm_hardware_t snd_usb_playback = | 1466 | static snd_pcm_hardware_t snd_usb_playback = |
@@ -1848,7 +1874,7 @@ static snd_pcm_ops_t snd_usb_playback_ops = { | |||
1848 | .hw_params = snd_usb_hw_params, | 1874 | .hw_params = snd_usb_hw_params, |
1849 | .hw_free = snd_usb_hw_free, | 1875 | .hw_free = snd_usb_hw_free, |
1850 | .prepare = snd_usb_pcm_prepare, | 1876 | .prepare = snd_usb_pcm_prepare, |
1851 | .trigger = snd_usb_pcm_trigger, | 1877 | .trigger = snd_usb_pcm_playback_trigger, |
1852 | .pointer = snd_usb_pcm_pointer, | 1878 | .pointer = snd_usb_pcm_pointer, |
1853 | .page = snd_pcm_get_vmalloc_page, | 1879 | .page = snd_pcm_get_vmalloc_page, |
1854 | }; | 1880 | }; |
@@ -1860,7 +1886,7 @@ static snd_pcm_ops_t snd_usb_capture_ops = { | |||
1860 | .hw_params = snd_usb_hw_params, | 1886 | .hw_params = snd_usb_hw_params, |
1861 | .hw_free = snd_usb_hw_free, | 1887 | .hw_free = snd_usb_hw_free, |
1862 | .prepare = snd_usb_pcm_prepare, | 1888 | .prepare = snd_usb_pcm_prepare, |
1863 | .trigger = snd_usb_pcm_trigger, | 1889 | .trigger = snd_usb_pcm_capture_trigger, |
1864 | .pointer = snd_usb_pcm_pointer, | 1890 | .pointer = snd_usb_pcm_pointer, |
1865 | .page = snd_pcm_get_vmalloc_page, | 1891 | .page = snd_pcm_get_vmalloc_page, |
1866 | }; | 1892 | }; |
@@ -2079,9 +2105,6 @@ static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat | |||
2079 | 2105 | ||
2080 | INIT_LIST_HEAD(&subs->fmt_list); | 2106 | INIT_LIST_HEAD(&subs->fmt_list); |
2081 | spin_lock_init(&subs->lock); | 2107 | spin_lock_init(&subs->lock); |
2082 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
2083 | tasklet_init(&subs->start_period_elapsed, start_period_elapsed, | ||
2084 | (unsigned long)subs); | ||
2085 | 2108 | ||
2086 | subs->stream = as; | 2109 | subs->stream = as; |
2087 | subs->direction = stream; | 2110 | subs->direction = stream; |
@@ -2755,9 +2778,9 @@ static int create_fixed_stream_quirk(snd_usb_audio_t *chip, | |||
2755 | /* | 2778 | /* |
2756 | * create a stream for an interface with proper descriptors | 2779 | * create a stream for an interface with proper descriptors |
2757 | */ | 2780 | */ |
2758 | static int create_standard_interface_quirk(snd_usb_audio_t *chip, | 2781 | static int create_standard_audio_quirk(snd_usb_audio_t *chip, |
2759 | struct usb_interface *iface, | 2782 | struct usb_interface *iface, |
2760 | const snd_usb_audio_quirk_t *quirk) | 2783 | const snd_usb_audio_quirk_t *quirk) |
2761 | { | 2784 | { |
2762 | struct usb_host_interface *alts; | 2785 | struct usb_host_interface *alts; |
2763 | struct usb_interface_descriptor *altsd; | 2786 | struct usb_interface_descriptor *altsd; |
@@ -2765,24 +2788,14 @@ static int create_standard_interface_quirk(snd_usb_audio_t *chip, | |||
2765 | 2788 | ||
2766 | alts = &iface->altsetting[0]; | 2789 | alts = &iface->altsetting[0]; |
2767 | altsd = get_iface_desc(alts); | 2790 | altsd = get_iface_desc(alts); |
2768 | switch (quirk->type) { | 2791 | err = parse_audio_endpoints(chip, altsd->bInterfaceNumber); |
2769 | case QUIRK_AUDIO_STANDARD_INTERFACE: | ||
2770 | err = parse_audio_endpoints(chip, altsd->bInterfaceNumber); | ||
2771 | if (!err) | ||
2772 | usb_set_interface(chip->dev, altsd->bInterfaceNumber, 0); /* reset the current interface */ | ||
2773 | break; | ||
2774 | case QUIRK_MIDI_STANDARD_INTERFACE: | ||
2775 | err = snd_usb_create_midi_interface(chip, iface, NULL); | ||
2776 | break; | ||
2777 | default: | ||
2778 | snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type); | ||
2779 | return -ENXIO; | ||
2780 | } | ||
2781 | if (err < 0) { | 2792 | if (err < 0) { |
2782 | snd_printk(KERN_ERR "cannot setup if %d: error %d\n", | 2793 | snd_printk(KERN_ERR "cannot setup if %d: error %d\n", |
2783 | altsd->bInterfaceNumber, err); | 2794 | altsd->bInterfaceNumber, err); |
2784 | return err; | 2795 | return err; |
2785 | } | 2796 | } |
2797 | /* reset the current interface */ | ||
2798 | usb_set_interface(chip->dev, altsd->bInterfaceNumber, 0); | ||
2786 | return 0; | 2799 | return 0; |
2787 | } | 2800 | } |
2788 | 2801 | ||
@@ -3044,7 +3057,7 @@ static int snd_usb_create_quirk(snd_usb_audio_t *chip, | |||
3044 | [QUIRK_MIDI_RAW] = snd_usb_create_midi_interface, | 3057 | [QUIRK_MIDI_RAW] = snd_usb_create_midi_interface, |
3045 | [QUIRK_MIDI_EMAGIC] = snd_usb_create_midi_interface, | 3058 | [QUIRK_MIDI_EMAGIC] = snd_usb_create_midi_interface, |
3046 | [QUIRK_MIDI_MIDITECH] = snd_usb_create_midi_interface, | 3059 | [QUIRK_MIDI_MIDITECH] = snd_usb_create_midi_interface, |
3047 | [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_interface_quirk, | 3060 | [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, |
3048 | [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, | 3061 | [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, |
3049 | [QUIRK_AUDIO_EDIROL_UA700_UA25] = create_ua700_ua25_quirk, | 3062 | [QUIRK_AUDIO_EDIROL_UA700_UA25] = create_ua700_ua25_quirk, |
3050 | [QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk, | 3063 | [QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk, |
@@ -3222,7 +3235,6 @@ static void *snd_usb_audio_probe(struct usb_device *dev, | |||
3222 | struct usb_interface *intf, | 3235 | struct usb_interface *intf, |
3223 | const struct usb_device_id *usb_id) | 3236 | const struct usb_device_id *usb_id) |
3224 | { | 3237 | { |
3225 | struct usb_host_config *config = dev->actconfig; | ||
3226 | const snd_usb_audio_quirk_t *quirk = (const snd_usb_audio_quirk_t *)usb_id->driver_info; | 3238 | const snd_usb_audio_quirk_t *quirk = (const snd_usb_audio_quirk_t *)usb_id->driver_info; |
3227 | int i, err; | 3239 | int i, err; |
3228 | snd_usb_audio_t *chip; | 3240 | snd_usb_audio_t *chip; |
@@ -3243,7 +3255,6 @@ static void *snd_usb_audio_probe(struct usb_device *dev, | |||
3243 | if (id == USB_ID(0x041e, 0x3000)) { | 3255 | if (id == USB_ID(0x041e, 0x3000)) { |
3244 | if (snd_usb_extigy_boot_quirk(dev, intf) < 0) | 3256 | if (snd_usb_extigy_boot_quirk(dev, intf) < 0) |
3245 | goto __err_val; | 3257 | goto __err_val; |
3246 | config = dev->actconfig; | ||
3247 | } | 3258 | } |
3248 | /* SB Audigy 2 NX needs its own boot-up magic, too */ | 3259 | /* SB Audigy 2 NX needs its own boot-up magic, too */ |
3249 | if (id == USB_ID(0x041e, 0x3020)) { | 3260 | if (id == USB_ID(0x041e, 0x3020)) { |
@@ -3272,11 +3283,6 @@ static void *snd_usb_audio_probe(struct usb_device *dev, | |||
3272 | /* it's a fresh one. | 3283 | /* it's a fresh one. |
3273 | * now look for an empty slot and create a new card instance | 3284 | * now look for an empty slot and create a new card instance |
3274 | */ | 3285 | */ |
3275 | /* first, set the current configuration for this device */ | ||
3276 | if (usb_reset_configuration(dev) < 0) { | ||
3277 | snd_printk(KERN_ERR "cannot reset configuration (value 0x%x)\n", get_cfg_desc(config)->bConfigurationValue); | ||
3278 | goto __error; | ||
3279 | } | ||
3280 | for (i = 0; i < SNDRV_CARDS; i++) | 3286 | for (i = 0; i < SNDRV_CARDS; i++) |
3281 | if (enable[i] && ! usb_chip[i] && | 3287 | if (enable[i] && ! usb_chip[i] && |
3282 | (vid[i] == -1 || vid[i] == USB_ID_VENDOR(id)) && | 3288 | (vid[i] == -1 || vid[i] == USB_ID_VENDOR(id)) && |