Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 4 Jun 2010 22:22:31 +0000 (15:22 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 4 Jun 2010 22:22:31 +0000 (15:22 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6:
  USB: unbind all interfaces before rebinding them
  USB: serial: digi_acceleport: Eliminate a NULL pointer dereference
  usb: fix ehci_hcd build failure when both generic-OF and xilinx is selected
  USB: cdc-acm: fix resource reclaim in error path of acm_probe
  USB: ftdi_sio: fix DTR/RTS line modes
  USB: s3c-hsotg: Ensure FIFOs are fully flushed after layout
  USB: s3c-hsotg: SoftDisconnect minimum 3ms
  USB: s3c-hsotg: Ensure TX FIFO addresses setup when initialising FIFOs
  USB: s3c_hsotg: define USB_GADGET_DUALSPEED in Kconfig
  USB: s3c: Enable soft disconnect during initialization
  USB: xhci: Print NEC firmware version.
  USB: xhci: Wait for host to start running.
  USB: xhci: Wait for controller to be ready after reset.
  USB: isp1362: fix inw warning on Blackfin systems
  USB: mos7840: fix null-pointer dereference

46 files changed:
Documentation/feature-removal-schedule.txt
arch/frv/mm/fault.c
arch/m32r/mm/fault.c
arch/mn10300/mm/fault.c
arch/um/kernel/skas/uaccess.c
arch/xtensa/mm/fault.c
drivers/acpi/ec.c
drivers/acpi/internal.h
drivers/acpi/processor_idle.c
drivers/acpi/sleep.c
drivers/char/Kconfig
drivers/misc/vmware_balloon.c
drivers/mmc/host/omap.c
drivers/rtc/rtc-s3c.c
drivers/sfi/sfi_core.c
drivers/usb/gadget/f_audio.c
drivers/video/Kconfig
drivers/video/fb_defio.c
fs/binfmt_flat.c
fs/compat.c
include/linux/personality.h
include/linux/syscalls.h
include/linux/usb/audio-v2.h
include/linux/usb/audio.h
kernel/cgroup.c
kernel/exec_domain.c
kernel/softirq.c
kernel/timer.c
lib/atomic64_test.c
mm/vmscan.c
sound/pci/asihpi/asihpi.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_realtek.c
sound/soc/imx/Kconfig
sound/usb/Makefile
sound/usb/card.c
sound/usb/card.h
sound/usb/clock.c [new file with mode: 0644]
sound/usb/clock.h [new file with mode: 0644]
sound/usb/endpoint.c
sound/usb/format.c
sound/usb/mixer.c
sound/usb/mixer.h
sound/usb/mixer_maps.c
sound/usb/pcm.c
sound/usb/usbaudio.h

index 672be0109d02617dfa03536c9a4fae7ad4ae4831..c268783bc4e7c18c2e4db792c3fba83d6bc44c71 100644 (file)
@@ -578,15 +578,6 @@ Who:       Avi Kivity <avi@redhat.com>
 
 ----------------------------
 
-What:  "acpi=ht" boot option
-When:  2.6.35
-Why:   Useful in 2003, implementation is a hack.
-       Generally invoked by accident today.
-       Seen as doing more harm than good.
-Who:   Len Brown <len.brown@intel.com>
-
-----------------------------
-
 What:  iwlwifi 50XX module parameters
 When:  2.6.40
 Why:   The "..50" modules parameters were used to configure 5000 series and
index 30f5d100a81c15038f79f88672db560cf4f950a5..a325d57a83d5fdae12d8323480564d8204e86117 100644 (file)
@@ -257,10 +257,10 @@ asmlinkage void do_page_fault(int datammu, unsigned long esr0, unsigned long ear
  */
  out_of_memory:
        up_read(&mm->mmap_sem);
-       printk("VM: killing process %s\n", current->comm);
-       if (user_mode(__frame))
-               do_group_exit(SIGKILL);
-       goto no_context;
+       if (!user_mode(__frame))
+               goto no_context;
+       pagefault_out_of_memory();
+       return;
 
  do_sigbus:
        up_read(&mm->mmap_sem);
index 28ee389e5f5a3e43d39f8d5f1cdccf45923785d3..b8ec002aef8e321349f17b9255b70762b4b029ce 100644 (file)
@@ -188,7 +188,6 @@ good_area:
        if ((error_code & ACE_INSTRUCTION) && !(vma->vm_flags & VM_EXEC))
          goto bad_area;
 
-survive:
        /*
         * If for any reason at all we couldn't handle the fault,
         * make sure we exit gracefully rather than endlessly redo
@@ -271,15 +270,10 @@ no_context:
  */
 out_of_memory:
        up_read(&mm->mmap_sem);
-       if (is_global_init(tsk)) {
-               yield();
-               down_read(&mm->mmap_sem);
-               goto survive;
-       }
-       printk("VM: killing process %s\n", tsk->comm);
-       if (error_code & ACE_USERMODE)
-               do_group_exit(SIGKILL);
-       goto no_context;
+       if (!(error_code & ACE_USERMODE))
+               goto no_context;
+       pagefault_out_of_memory();
+       return;
 
 do_sigbus:
        up_read(&mm->mmap_sem);
index 53bb17d0f0687764ab1d8a4e05d6cdfc81c03e25..81f153fa51b4a6ecb07111f1d20383fbf0b6eaf2 100644 (file)
@@ -338,11 +338,10 @@ no_context:
  */
 out_of_memory:
        up_read(&mm->mmap_sem);
-       monitor_signal(regs);
-       printk(KERN_ALERT "VM: killing process %s\n", tsk->comm);
-       if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_USR)
-               do_exit(SIGKILL);
-       goto no_context;
+       if ((fault_code & MMUFCR_xFC_ACCESS) != MMUFCR_xFC_ACCESS_USR)
+               goto no_context;
+       pagefault_out_of_memory();
+       return;
 
 do_sigbus:
        up_read(&mm->mmap_sem);
index e22c96993db3b07545e107adb57f2ef1d8ddb608..696634214dc65551557ab88535b40557fed4eb7c 100644 (file)
@@ -81,7 +81,7 @@ static int do_op_one_page(unsigned long addr, int len, int is_write,
 
        current->thread.fault_catcher = NULL;
 
-       kunmap_atomic(page, KM_UML_USERCOPY);
+       kunmap_atomic((void *)addr, KM_UML_USERCOPY);
 
        return n;
 }
index bc0733359a8852a12288f083c2420f4c9734948e..e367e30264366d82c17dc66d157a2aa2534388bc 100644 (file)
@@ -105,7 +105,6 @@ good_area:
         * make sure we exit gracefully rather than endlessly redo
         * the fault.
         */
-survive:
        fault = handle_mm_fault(mm, vma, address, is_write ? FAULT_FLAG_WRITE : 0);
        if (unlikely(fault & VM_FAULT_ERROR)) {
                if (fault & VM_FAULT_OOM)
@@ -146,15 +145,10 @@ bad_area:
         */
 out_of_memory:
        up_read(&mm->mmap_sem);
-       if (is_global_init(current)) {
-               yield();
-               down_read(&mm->mmap_sem);
-               goto survive;
-       }
-       printk("VM: killing process %s\n", current->comm);
-       if (user_mode(regs))
-               do_group_exit(SIGKILL);
-       bad_page_fault(regs, address, SIGKILL);
+       if (!user_mode(regs))
+               bad_page_fault(regs, address, SIGKILL);
+       else
+               pagefault_out_of_memory();
        return;
 
 do_sigbus:
index e61d4f8e62a54a42dd8f39b5c9647b2a08449e07..5f2027d782e8134642d777225f4c37f6120b214f 100644 (file)
@@ -79,7 +79,7 @@ enum {
        EC_FLAGS_GPE_STORM,             /* GPE storm detected */
        EC_FLAGS_HANDLERS_INSTALLED,    /* Handlers for GPE and
                                         * OpReg are installed */
-       EC_FLAGS_FROZEN,                /* Transactions are suspended */
+       EC_FLAGS_BLOCKED,               /* Transactions are blocked */
 };
 
 /* If we find an EC via the ECDT, we need to keep a ptr to its context */
@@ -293,7 +293,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
        if (t->rdata)
                memset(t->rdata, 0, t->rlen);
        mutex_lock(&ec->lock);
-       if (test_bit(EC_FLAGS_FROZEN, &ec->flags)) {
+       if (test_bit(EC_FLAGS_BLOCKED, &ec->flags)) {
                status = -EINVAL;
                goto unlock;
        }
@@ -459,7 +459,7 @@ int ec_transaction(u8 command,
 
 EXPORT_SYMBOL(ec_transaction);
 
-void acpi_ec_suspend_transactions(void)
+void acpi_ec_block_transactions(void)
 {
        struct acpi_ec *ec = first_ec;
 
@@ -468,11 +468,11 @@ void acpi_ec_suspend_transactions(void)
 
        mutex_lock(&ec->lock);
        /* Prevent transactions from being carried out */
-       set_bit(EC_FLAGS_FROZEN, &ec->flags);
+       set_bit(EC_FLAGS_BLOCKED, &ec->flags);
        mutex_unlock(&ec->lock);
 }
 
-void acpi_ec_resume_transactions(void)
+void acpi_ec_unblock_transactions(void)
 {
        struct acpi_ec *ec = first_ec;
 
@@ -481,10 +481,20 @@ void acpi_ec_resume_transactions(void)
 
        mutex_lock(&ec->lock);
        /* Allow transactions to be carried out again */
-       clear_bit(EC_FLAGS_FROZEN, &ec->flags);
+       clear_bit(EC_FLAGS_BLOCKED, &ec->flags);
        mutex_unlock(&ec->lock);
 }
 
+void acpi_ec_unblock_transactions_early(void)
+{
+       /*
+        * Allow transactions to happen again (this function is called from
+        * atomic context during wakeup, so we don't need to acquire the mutex).
+        */
+       if (first_ec)
+               clear_bit(EC_FLAGS_BLOCKED, &first_ec->flags);
+}
+
 static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data)
 {
        int result;
index e28411367239a117f48f2773f489aa41919bcf1f..f8f190ec066e7a266101b0783a97e8f274f5a639 100644 (file)
@@ -49,8 +49,9 @@ void acpi_early_processor_set_pdc(void);
 int acpi_ec_init(void);
 int acpi_ec_ecdt_probe(void);
 int acpi_boot_ec_enable(void);
-void acpi_ec_suspend_transactions(void);
-void acpi_ec_resume_transactions(void);
+void acpi_ec_block_transactions(void);
+void acpi_ec_unblock_transactions(void);
+void acpi_ec_unblock_transactions_early(void);
 
 /*--------------------------------------------------------------------------
                                   Suspend/Resume
index 2e8c27d48f2b75f59f0e76436ae94db5f61466a7..b1b385692f46e09f05dd55882ed3ea9c73039b74 100644 (file)
@@ -80,7 +80,7 @@ module_param(nocst, uint, 0000);
 static unsigned int latency_factor __read_mostly = 2;
 module_param(latency_factor, uint, 0644);
 
-static s64 us_to_pm_timer_ticks(s64 t)
+static u64 us_to_pm_timer_ticks(s64 t)
 {
        return div64_u64(t * PM_TIMER_FREQUENCY, 1000000);
 }
@@ -731,10 +731,10 @@ static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset)
 
                seq_puts(seq, "demotion[--] ");
 
-               seq_printf(seq, "latency[%03d] usage[%08d] duration[%020llu]\n",
+               seq_printf(seq, "latency[%03d] usage[%08d] duration[%020Lu]\n",
                           pr->power.states[i].latency,
                           pr->power.states[i].usage,
-                          (unsigned long long)pr->power.states[i].time);
+                          us_to_pm_timer_ticks(pr->power.states[i].time));
        }
 
       end:
@@ -861,7 +861,6 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
        ktime_t  kt1, kt2;
        s64 idle_time_ns;
        s64 idle_time;
-       s64 sleep_ticks = 0;
 
        pr = __get_cpu_var(processors);
 
@@ -906,8 +905,6 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
        idle_time = idle_time_ns;
        do_div(idle_time, NSEC_PER_USEC);
 
-       sleep_ticks = us_to_pm_timer_ticks(idle_time);
-
        /* Tell the scheduler how much we idled: */
        sched_clock_idle_wakeup_event(idle_time_ns);
 
@@ -918,7 +915,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
        cx->usage++;
 
        lapic_timer_state_broadcast(pr, cx, 0);
-       cx->time += sleep_ticks;
+       cx->time += idle_time;
        return idle_time;
 }
 
@@ -940,7 +937,6 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
        ktime_t  kt1, kt2;
        s64 idle_time_ns;
        s64 idle_time;
-       s64 sleep_ticks = 0;
 
 
        pr = __get_cpu_var(processors);
@@ -1022,11 +1018,10 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
                spin_unlock(&c3_lock);
        }
        kt2 = ktime_get_real();
-       idle_time_ns = ktime_to_us(ktime_sub(kt2, kt1));
+       idle_time_ns = ktime_to_ns(ktime_sub(kt2, kt1));
        idle_time = idle_time_ns;
        do_div(idle_time, NSEC_PER_USEC);
 
-       sleep_ticks = us_to_pm_timer_ticks(idle_time);
        /* Tell the scheduler how much we idled: */
        sched_clock_idle_wakeup_event(idle_time_ns);
 
@@ -1037,7 +1032,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
        cx->usage++;
 
        lapic_timer_state_broadcast(pr, cx, 0);
-       cx->time += sleep_ticks;
+       cx->time += idle_time;
        return idle_time;
 }
 
index 4ab2275b4461e797bf374880c97c24db72dba386..3fb4bdea7e06e59edcd5591897179895ce12807c 100644 (file)
@@ -94,11 +94,13 @@ void __init acpi_old_suspend_ordering(void)
 }
 
 /**
- *     acpi_pm_disable_gpes - Disable the GPEs.
+ * acpi_pm_freeze - Disable the GPEs and suspend EC transactions.
  */
-static int acpi_pm_disable_gpes(void)
+static int acpi_pm_freeze(void)
 {
        acpi_disable_all_gpes();
+       acpi_os_wait_events_complete(NULL);
+       acpi_ec_block_transactions();
        return 0;
 }
 
@@ -126,7 +128,8 @@ static int acpi_pm_prepare(void)
        int error = __acpi_pm_prepare();
 
        if (!error)
-               acpi_disable_all_gpes();
+               acpi_pm_freeze();
+
        return error;
 }
 
@@ -256,6 +259,8 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
         * acpi_leave_sleep_state will reenable specific GPEs later
         */
        acpi_disable_all_gpes();
+       /* Allow EC transactions to happen. */
+       acpi_ec_unblock_transactions_early();
 
        local_irq_restore(flags);
        printk(KERN_DEBUG "Back to C!\n");
@@ -267,6 +272,12 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
        return ACPI_SUCCESS(status) ? 0 : -EFAULT;
 }
 
+static void acpi_suspend_finish(void)
+{
+       acpi_ec_unblock_transactions();
+       acpi_pm_finish();
+}
+
 static int acpi_suspend_state_valid(suspend_state_t pm_state)
 {
        u32 acpi_state;
@@ -288,7 +299,7 @@ static struct platform_suspend_ops acpi_suspend_ops = {
        .begin = acpi_suspend_begin,
        .prepare_late = acpi_pm_prepare,
        .enter = acpi_suspend_enter,
-       .wake = acpi_pm_finish,
+       .wake = acpi_suspend_finish,
        .end = acpi_pm_end,
 };
 
@@ -314,9 +325,9 @@ static int acpi_suspend_begin_old(suspend_state_t pm_state)
 static struct platform_suspend_ops acpi_suspend_ops_old = {
        .valid = acpi_suspend_state_valid,
        .begin = acpi_suspend_begin_old,
-       .prepare_late = acpi_pm_disable_gpes,
+       .prepare_late = acpi_pm_freeze,
        .enter = acpi_suspend_enter,
-       .wake = acpi_pm_finish,
+       .wake = acpi_suspend_finish,
        .end = acpi_pm_end,
        .recover = acpi_pm_finish,
 };
@@ -433,6 +444,7 @@ static int acpi_hibernation_enter(void)
 static void acpi_hibernation_finish(void)
 {
        hibernate_nvs_free();
+       acpi_ec_unblock_transactions();
        acpi_pm_finish();
 }
 
@@ -453,19 +465,13 @@ static void acpi_hibernation_leave(void)
        }
        /* Restore the NVS memory area */
        hibernate_nvs_restore();
+       /* Allow EC transactions to happen. */
+       acpi_ec_unblock_transactions_early();
 }
 
-static int acpi_pm_pre_restore(void)
-{
-       acpi_disable_all_gpes();
-       acpi_os_wait_events_complete(NULL);
-       acpi_ec_suspend_transactions();
-       return 0;
-}
-
-static void acpi_pm_restore_cleanup(void)
+static void acpi_pm_thaw(void)
 {
-       acpi_ec_resume_transactions();
+       acpi_ec_unblock_transactions();
        acpi_enable_all_runtime_gpes();
 }
 
@@ -477,8 +483,8 @@ static struct platform_hibernation_ops acpi_hibernation_ops = {
        .prepare = acpi_pm_prepare,
        .enter = acpi_hibernation_enter,
        .leave = acpi_hibernation_leave,
-       .pre_restore = acpi_pm_pre_restore,
-       .restore_cleanup = acpi_pm_restore_cleanup,
+       .pre_restore = acpi_pm_freeze,
+       .restore_cleanup = acpi_pm_thaw,
 };
 
 /**
@@ -510,12 +516,9 @@ static int acpi_hibernation_begin_old(void)
 
 static int acpi_hibernation_pre_snapshot_old(void)
 {
-       int error = acpi_pm_disable_gpes();
-
-       if (!error)
-               hibernate_nvs_save();
-
-       return error;
+       acpi_pm_freeze();
+       hibernate_nvs_save();
+       return 0;
 }
 
 /*
@@ -527,11 +530,11 @@ static struct platform_hibernation_ops acpi_hibernation_ops_old = {
        .end = acpi_pm_end,
        .pre_snapshot = acpi_hibernation_pre_snapshot_old,
        .finish = acpi_hibernation_finish,
-       .prepare = acpi_pm_disable_gpes,
+       .prepare = acpi_pm_freeze,
        .enter = acpi_hibernation_enter,
        .leave = acpi_hibernation_leave,
-       .pre_restore = acpi_pm_pre_restore,
-       .restore_cleanup = acpi_pm_restore_cleanup,
+       .pre_restore = acpi_pm_freeze,
+       .restore_cleanup = acpi_pm_thaw,
        .recover = acpi_pm_finish,
 };
 #endif /* CONFIG_HIBERNATION */
index f09fc0e2062dfdf9b0d2c4d816cd4fada77c4628..7cfcc629a7fd0f89bf56995652aff7d888379549 100644 (file)
@@ -1123,6 +1123,7 @@ source "drivers/s390/char/Kconfig"
 
 config RAMOOPS
        tristate "Log panic/oops to a RAM buffer"
+       depends on HAS_IOMEM
        default n
        help
          This enables panic and oops messages to be logged to a circular
index db9cd0240c6f3f84bc89c65b1e5b8750ce4db116..2a1e804a71aa2466199119f2206133fdb409d932 100644 (file)
@@ -45,7 +45,7 @@
 
 MODULE_AUTHOR("VMware, Inc.");
 MODULE_DESCRIPTION("VMware Memory Control (Balloon) Driver");
-MODULE_VERSION("1.2.1.0-K");
+MODULE_VERSION("1.2.1.1-k");
 MODULE_ALIAS("dmi:*:svnVMware*:*");
 MODULE_ALIAS("vmware_vmmemctl");
 MODULE_LICENSE("GPL");
@@ -101,6 +101,8 @@ MODULE_LICENSE("GPL");
 /* Maximum number of page allocations without yielding processor */
 #define VMW_BALLOON_YIELD_THRESHOLD    1024
 
+/* Maximum number of refused pages we accumulate during inflation cycle */
+#define VMW_BALLOON_MAX_REFUSED                16
 
 /*
  * Hypervisor communication port definitions.
@@ -183,6 +185,7 @@ struct vmballoon {
 
        /* transient list of non-balloonable pages */
        struct list_head refused_pages;
+       unsigned int n_refused_pages;
 
        /* balloon size in pages */
        unsigned int size;
@@ -428,14 +431,21 @@ static int vmballoon_reserve_page(struct vmballoon *b, bool can_sleep)
                /* inform monitor */
                locked = vmballoon_send_lock_page(b, page_to_pfn(page));
                if (!locked) {
+                       STATS_INC(b->stats.refused_alloc);
+
                        if (b->reset_required) {
                                __free_page(page);
                                return -EIO;
                        }
 
-                       /* place on list of non-balloonable pages, retry allocation */
+                       /*
+                        * Place page on the list of non-balloonable pages
+                        * and retry allocation, unless we already accumulated
+                        * too many of them, in which case take a breather.
+                        */
                        list_add(&page->lru, &b->refused_pages);
-                       STATS_INC(b->stats.refused_alloc);
+                       if (++b->n_refused_pages >= VMW_BALLOON_MAX_REFUSED)
+                               return -EIO;
                }
        } while (!locked);
 
@@ -483,6 +493,8 @@ static void vmballoon_release_refused_pages(struct vmballoon *b)
                __free_page(page);
                STATS_INC(b->stats.refused_free);
        }
+
+       b->n_refused_pages = 0;
 }
 
 /*
index 2b281680e3206da99f9e991d69f12c5edef92754..d98ddcfac5e5cb2e0ddf1fd32fac9318cc09b29b 100644 (file)
@@ -1157,7 +1157,6 @@ static void mmc_omap_start_request(struct mmc_omap_host *host,
        mmc_omap_start_command(host, req->cmd);
        if (host->dma_in_use)
                omap_start_dma(host->dma_ch);
-       BUG_ON(irqs_disabled());
 }
 
 static void mmc_omap_request(struct mmc_host *mmc, struct mmc_request *req)
index e5972b2c17b7be04be983a4460ca5aec5c7063d2..70b68d35f9694c804272c1bca502253f15a563c9 100644 (file)
@@ -495,8 +495,6 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
        pr_debug("s3c2410_rtc: RTCCON=%02x\n",
                 readb(s3c_rtc_base + S3C2410_RTCCON));
 
-       s3c_rtc_setfreq(&pdev->dev, 1);
-
        device_init_wakeup(&pdev->dev, 1);
 
        /* register RTC and exit */
@@ -510,14 +508,17 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
                goto err_nortc;
        }
 
+       s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data;
+
        if (s3c_rtc_cpu_type == TYPE_S3C64XX)
                rtc->max_user_freq = 32768;
        else
                rtc->max_user_freq = 128;
 
-       s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data;
-
        platform_set_drvdata(pdev, rtc);
+
+       s3c_rtc_setfreq(&pdev->dev, 1);
+
        return 0;
 
  err_nortc:
index 005195958647b03acded28a822bfd7374744d210..ceba593dc84fbcb994f1fb4968cab3b4adf05b83 100644 (file)
@@ -441,8 +441,10 @@ struct sfi_table_attr __init *sfi_sysfs_install_table(u64 pa)
 
        ret = sysfs_create_bin_file(tables_kobj,
                                  &tbl_attr->attr);
-       if (ret)
+       if (ret) {
                kfree(tbl_attr);
+               tbl_attr = NULL;
+       }
 
        sfi_unmap_table(th);
        return tbl_attr;
index 43bf44514c417d0431b52604569bef796871248b..b91115f84b137e69b539b6c09a6f76de2afc3dc0 100644 (file)
@@ -101,7 +101,7 @@ static struct uac_feature_unit_descriptor_0 feature_unit_desc = {
 static struct usb_audio_control mute_control = {
        .list = LIST_HEAD_INIT(mute_control.list),
        .name = "Mute Control",
-       .type = UAC_MUTE_CONTROL,
+       .type = UAC_FU_MUTE,
        /* Todo: add real Mute control code */
        .set = generic_set_cmd,
        .get = generic_get_cmd,
@@ -110,7 +110,7 @@ static struct usb_audio_control mute_control = {
 static struct usb_audio_control volume_control = {
        .list = LIST_HEAD_INIT(volume_control.list),
        .name = "Volume Control",
-       .type = UAC_VOLUME_CONTROL,
+       .type = UAC_FU_VOLUME,
        /* Todo: add real Volume control code */
        .set = generic_set_cmd,
        .get = generic_get_cmd,
index 1e6fec487973c45a0407326f09a62f6015c39589..3d94a1471724ff620ba580808be1ceec0d868b15 100644 (file)
@@ -8,6 +8,9 @@ menu "Graphics support"
 config HAVE_FB_ATMEL
        bool
 
+config HAVE_FB_IMX
+       bool
+
 source "drivers/char/agp/Kconfig"
 
 source "drivers/gpu/vga/Kconfig"
@@ -400,9 +403,6 @@ config FB_SA1100
          If you plan to use the LCD display with your SA-1100 system, say
          Y here.
 
-config HAVE_FB_IMX
-       bool
-
 config FB_IMX
        tristate "Motorola i.MX LCD support"
        depends on FB && (HAVE_FB_IMX || ARCH_MX1 || ARCH_MX2)
index 073c9b408cf7ce1ceff2b5eb52c6f49510273291..6b93ef93cb12c08179c973e31bf97ff27eb4d56b 100644 (file)
@@ -100,6 +100,16 @@ static int fb_deferred_io_mkwrite(struct vm_area_struct *vma,
        /* protect against the workqueue changing the page list */
        mutex_lock(&fbdefio->lock);
 
+       /*
+        * We want the page to remain locked from ->page_mkwrite until
+        * the PTE is marked dirty to avoid page_mkclean() being called
+        * before the PTE is updated, which would leave the page ignored
+        * by defio.
+        * Do this by locking the page here and informing the caller
+        * about it with VM_FAULT_LOCKED.
+        */
+       lock_page(page);
+
        /* we loop through the pagelist before adding in order
        to keep the pagelist sorted */
        list_for_each_entry(cur, &fbdefio->pagelist, lru) {
@@ -121,7 +131,7 @@ page_already_added:
 
        /* come back after delay to process the deferred IO */
        schedule_delayed_work(&info->deferred_work, fbdefio->delay);
-       return 0;
+       return VM_FAULT_LOCKED;
 }
 
 static const struct vm_operations_struct fb_deferred_io_vm_ops = {
@@ -155,41 +165,25 @@ static void fb_deferred_io_work(struct work_struct *work)
 {
        struct fb_info *info = container_of(work, struct fb_info,
                                                deferred_work.work);
+       struct list_head *node, *next;
+       struct page *cur;
        struct fb_deferred_io *fbdefio = info->fbdefio;
-       struct page *page, *tmp_page;
-       struct list_head *node, *tmp_node;
-       struct list_head non_dirty;
-
-       INIT_LIST_HEAD(&non_dirty);
 
        /* here we mkclean the pages, then do all deferred IO */
        mutex_lock(&fbdefio->lock);
-       list_for_each_entry_safe(page, tmp_page, &fbdefio->pagelist, lru) {
-               lock_page(page);
-               /*
-                * The workqueue callback can be triggered after a
-                * ->page_mkwrite() call but before the PTE has been marked
-                * dirty. In this case page_mkclean() won't "rearm" the page.
-                *
-                * To avoid this, remove those "non-dirty" pages from the
-                * pagelist before calling the driver's callback, then add
-                * them back to get processed on the next work iteration.
-                * At that time, their PTEs will hopefully be dirty for real.
-                */
-               if (!page_mkclean(page))
-                       list_move_tail(&page->lru, &non_dirty);
-               unlock_page(page);
+       list_for_each_entry(cur, &fbdefio->pagelist, lru) {
+               lock_page(cur);
+               page_mkclean(cur);
+               unlock_page(cur);
        }
 
        /* driver's callback with pagelist */
        fbdefio->deferred_io(info, &fbdefio->pagelist);
 
-       /* clear the list... */
-       list_for_each_safe(node, tmp_node, &fbdefio->pagelist) {
+       /* clear the list */
+       list_for_each_safe(node, next, &fbdefio->pagelist) {
                list_del(node);
        }
-       /* ... and add back the "non-dirty" pages to the list */
-       list_splice_tail(&non_dirty, &fbdefio->pagelist);
        mutex_unlock(&fbdefio->lock);
 }
 
@@ -218,7 +212,6 @@ EXPORT_SYMBOL_GPL(fb_deferred_io_open);
 void fb_deferred_io_cleanup(struct fb_info *info)
 {
        struct fb_deferred_io *fbdefio = info->fbdefio;
-       struct list_head *node, *tmp_node;
        struct page *page;
        int i;
 
@@ -226,13 +219,6 @@ void fb_deferred_io_cleanup(struct fb_info *info)
        cancel_delayed_work(&info->deferred_work);
        flush_scheduled_work();
 
-       /*  the list may have still some non-dirty pages at this point */
-       mutex_lock(&fbdefio->lock);
-       list_for_each_safe(node, tmp_node, &fbdefio->pagelist) {
-               list_del(node);
-       }
-       mutex_unlock(&fbdefio->lock);
-
        /* clear out the mapping that we setup */
        for (i = 0 ; i < info->fix.smem_len; i += PAGE_SIZE) {
                page = fb_deferred_io_page(info, i);
index 49566c1687d84943d9187a12ff2d1490c8ec6ad2..b6ab27ccf214fc8c406a9ef70e91d7930af0eaec 100644 (file)
 #endif
 
 /*
- * User data (stack, data section and bss) needs to be aligned
- * for the same reasons as SLAB memory is, and to the same amount.
- * Avoid duplicating architecture specific code by using the same
- * macro as with SLAB allocation:
+ * User data (data section and bss) needs to be aligned.
+ * We pick 0x20 here because it is the max value elf2flt has always
+ * used in producing FLAT files, and because it seems to be large
+ * enough to make all the gcc alignment related tests happy.
+ */
+#define FLAT_DATA_ALIGN        (0x20)
+
+/*
+ * User data (stack) also needs to be aligned.
+ * Here we can be a bit looser than the data sections since this
+ * needs to only meet arch ABI requirements.
  */
 #ifdef ARCH_SLAB_MINALIGN
-#define FLAT_DATA_ALIGN        (ARCH_SLAB_MINALIGN)
+#define FLAT_STACK_ALIGN       (ARCH_SLAB_MINALIGN)
 #else
-#define FLAT_DATA_ALIGN        (sizeof(void *))
+#define FLAT_STACK_ALIGN       (sizeof(void *))
 #endif
 
 #define RELOC_FAILED 0xff00ff01                /* Relocation incorrect somewhere */
@@ -129,7 +136,7 @@ static unsigned long create_flat_tables(
 
        sp = (unsigned long *)p;
        sp -= (envc + argc + 2) + 1 + (flat_argvp_envp_on_stack() ? 2 : 0);
-       sp = (unsigned long *) ((unsigned long)sp & -FLAT_DATA_ALIGN);
+       sp = (unsigned long *) ((unsigned long)sp & -FLAT_STACK_ALIGN);
        argv = sp + 1 + (flat_argvp_envp_on_stack() ? 2 : 0);
        envp = argv + (argc + 1);
 
@@ -589,7 +596,7 @@ static int load_flat_file(struct linux_binprm * bprm,
                if (IS_ERR_VALUE(result)) {
                        printk("Unable to read data+bss, errno %d\n", (int)-result);
                        do_munmap(current->mm, textpos, text_len);
-                       do_munmap(current->mm, realdatastart, data_len + extra);
+                       do_munmap(current->mm, realdatastart, len);
                        ret = result;
                        goto err;
                }
@@ -876,7 +883,7 @@ static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        stack_len = TOP_OF_ARGS - bprm->p;             /* the strings */
        stack_len += (bprm->argc + 1) * sizeof(char *); /* the argv array */
        stack_len += (bprm->envc + 1) * sizeof(char *); /* the envp array */
-       stack_len += FLAT_DATA_ALIGN - 1;  /* reserve for upcoming alignment */
+       stack_len += FLAT_STACK_ALIGN - 1;  /* reserve for upcoming alignment */
        
        res = load_flat_file(bprm, &libinfo, 0, &stack_len);
        if (IS_ERR_VALUE(res))
index f0b391c50552dc986f93afe1e4c56ce3b777a600..6490d2134ff3e73656b29b6ad5473e339870ae8d 100644 (file)
@@ -626,7 +626,7 @@ ssize_t compat_rw_copy_check_uvector(int type,
                tot_len += len;
                if (tot_len < tmp) /* maths overflow on the compat_ssize_t */
                        goto out;
-               if (!access_ok(vrfy_dir(type), buf, len)) {
+               if (!access_ok(vrfy_dir(type), compat_ptr(buf), len)) {
                        ret = -EFAULT;
                        goto out;
                }
index 126120819a0dba4aeb931094094c27d3d80f9aa0..eec3bae164d451a38b23906a283af54965074ec0 100644 (file)
@@ -12,7 +12,7 @@ struct pt_regs;
 
 extern int             register_exec_domain(struct exec_domain *);
 extern int             unregister_exec_domain(struct exec_domain *);
-extern int             __set_personality(unsigned long);
+extern int             __set_personality(unsigned int);
 
 #endif /* __KERNEL__ */
 
index a1a86a53bc735c13cdda531309aa6c8158231909..7f614ce274a9198e969d573834d8782f95b8e6a3 100644 (file)
@@ -289,7 +289,7 @@ asmlinkage long sys_capget(cap_user_header_t header,
                                cap_user_data_t dataptr);
 asmlinkage long sys_capset(cap_user_header_t header,
                                const cap_user_data_t data);
-asmlinkage long sys_personality(u_long personality);
+asmlinkage long sys_personality(unsigned int personality);
 
 asmlinkage long sys_sigpending(old_sigset_t __user *set);
 asmlinkage long sys_sigprocmask(int how, old_sigset_t __user *set,
index 92f1d99f0f172c377dee4a33a7c6587d7e562bba..383b94ba8c2002f4f07e73eedbf8adb92a6211e1 100644 (file)
 /* v1.0 and v2.0 of this standard have many things in common. For the rest
  * of the definitions, please refer to audio.h */
 
+static inline bool uac2_control_is_readable(u32 bmControls, u8 control)
+{
+       return (bmControls >> (control * 2)) & 0x1;
+}
+
+static inline bool uac2_control_is_writeable(u32 bmControls, u8 control)
+{
+       return (bmControls >> (control * 2)) & 0x2;
+}
+
 /* 4.7.2.1 Clock Source Descriptor */
 
 struct uac_clock_source_descriptor {
@@ -31,6 +41,13 @@ struct uac_clock_source_descriptor {
        __u8 iClockSource;
 } __attribute__((packed));
 
+/* bmAttribute fields */
+#define UAC_CLOCK_SOURCE_TYPE_EXT      0x0
+#define UAC_CLOCK_SOURCE_TYPE_INT_FIXED        0x1
+#define UAC_CLOCK_SOURCE_TYPE_INT_VAR  0x2
+#define UAC_CLOCK_SOURCE_TYPE_INT_PROG 0x3
+#define UAC_CLOCK_SOURCE_SYNCED_TO_SOF (1 << 2)
+
 /* 4.7.2.2 Clock Source Descriptor */
 
 struct uac_clock_selector_descriptor {
@@ -39,8 +56,20 @@ struct uac_clock_selector_descriptor {
        __u8 bDescriptorSubtype;
        __u8 bClockID;
        __u8 bNrInPins;
-       __u8 bmControls;
        __u8 baCSourceID[];
+       /* bmControls, bAssocTerminal and iClockSource omitted */
+} __attribute__((packed));
+
+/* 4.7.2.3 Clock Multiplier Descriptor */
+
+struct uac_clock_multiplier_descriptor {
+       __u8 bLength;
+       __u8 bDescriptorType;
+       __u8 bDescriptorSubtype;
+       __u8 bClockID;
+       __u8 bCSourceID;
+       __u8 bmControls;
+       __u8 iClockMultiplier;
 } __attribute__((packed));
 
 /* 4.7.2.4 Input terminal descriptor */
index 5d646c3887524febf0d39f81d2e7c4a832f875fe..c51200c715e504a951a5b18a74a599abbede08a1 100644 (file)
 #define UAC_FORMAT_TYPE                        0x02
 #define UAC_FORMAT_SPECIFIC            0x03
 
+/* A.7 Processing Unit Process Types */
+#define UAC_PROCESS_UNDEFINED          0x00
+#define UAC_PROCESS_UP_DOWNMIX         0x01
+#define UAC_PROCESS_DOLBY_PROLOGIC     0x02
+#define UAC_PROCESS_STEREO_EXTENDER    0x03
+#define UAC_PROCESS_REVERB             0x04
+#define UAC_PROCESS_CHORUS             0x05
+#define UAC_PROCESS_DYN_RANGE_COMP     0x06
+
 /* A.8 Audio Class-Specific Endpoint Descriptor Subtypes */
 #define UAC_EP_GENERAL                 0x01
 
 
 #define UAC_GET_STAT                   0xff
 
+/* A.10 Control Selector Codes */
+
+/* A.10.1 Terminal Control Selectors */
+#define UAC_TERM_COPY_PROTECT          0x01
+
+/* A.10.2 Feature Unit Control Selectors */
+#define UAC_FU_MUTE                    0x01
+#define UAC_FU_VOLUME                  0x02
+#define UAC_FU_BASS                    0x03
+#define UAC_FU_MID                     0x04
+#define UAC_FU_TREBLE                  0x05
+#define UAC_FU_GRAPHIC_EQUALIZER       0x06
+#define UAC_FU_AUTOMATIC_GAIN          0x07
+#define UAC_FU_DELAY                   0x08
+#define UAC_FU_BASS_BOOST              0x09
+#define UAC_FU_LOUDNESS                        0x0a
+
+#define UAC_CONTROL_BIT(CS)    (1 << ((CS) - 1))
+
+/* A.10.3.1 Up/Down-mix Processing Unit Controls Selectors */
+#define UAC_UD_ENABLE                  0x01
+#define UAC_UD_MODE_SELECT             0x02
+
+/* A.10.3.2 Dolby Prologic (tm) Processing Unit Controls Selectors */
+#define UAC_DP_ENABLE                  0x01
+#define UAC_DP_MODE_SELECT             0x02
+
+/* A.10.3.3 3D Stereo Extender Processing Unit Control Selectors */
+#define UAC_3D_ENABLE                  0x01
+#define UAC_3D_SPACE                   0x02
+
+/* A.10.3.4 Reverberation Processing Unit Control Selectors */
+#define UAC_REVERB_ENABLE              0x01
+#define UAC_REVERB_LEVEL               0x02
+#define UAC_REVERB_TIME                        0x03
+#define UAC_REVERB_FEEDBACK            0x04
+
+/* A.10.3.5 Chorus Processing Unit Control Selectors */
+#define UAC_CHORUS_ENABLE              0x01
+#define UAC_CHORUS_LEVEL               0x02
+#define UAC_CHORUS_RATE                        0x03
+#define UAC_CHORUS_DEPTH               0x04
+
+/* A.10.3.6 Dynamic Range Compressor Unit Control Selectors */
+#define UAC_DCR_ENABLE                 0x01
+#define UAC_DCR_RATE                   0x02
+#define UAC_DCR_MAXAMPL                        0x03
+#define UAC_DCR_THRESHOLD              0x04
+#define UAC_DCR_ATTACK_TIME            0x05
+#define UAC_DCR_RELEASE_TIME           0x06
+
+/* A.10.4 Extension Unit Control Selectors */
+#define UAC_XU_ENABLE                  0x01
+
 /* MIDI - A.1 MS Class-Specific Interface Descriptor Subtypes */
 #define UAC_MS_HEADER                  0x01
 #define UAC_MIDI_IN_JACK               0x02
@@ -244,7 +307,7 @@ struct uac_selector_unit_descriptor {
 static inline __u8 uac_selector_unit_iSelector(struct uac_selector_unit_descriptor *desc)
 {
        __u8 *raw = (__u8 *) desc;
-       return raw[9 + desc->bLength - 1];
+       return raw[desc->bLength - 1];
 }
 
 /* 4.3.2.5 Feature Unit Descriptor */
@@ -463,31 +526,6 @@ struct uac_iso_endpoint_descriptor {
 #define UAC_EP_CS_ATTR_PITCH_CONTROL   0x02
 #define UAC_EP_CS_ATTR_FILL_MAX                0x80
 
-/* A.10.2 Feature Unit Control Selectors */
-
-#define UAC_FU_CONTROL_UNDEFINED       0x00
-#define UAC_MUTE_CONTROL               0x01
-#define UAC_VOLUME_CONTROL             0x02
-#define UAC_BASS_CONTROL               0x03
-#define UAC_MID_CONTROL                        0x04
-#define UAC_TREBLE_CONTROL             0x05
-#define UAC_GRAPHIC_EQUALIZER_CONTROL  0x06
-#define UAC_AUTOMATIC_GAIN_CONTROL     0x07
-#define UAC_DELAY_CONTROL              0x08
-#define UAC_BASS_BOOST_CONTROL         0x09
-#define UAC_LOUDNESS_CONTROL           0x0a
-
-#define UAC_FU_MUTE            (1 << (UAC_MUTE_CONTROL - 1))
-#define UAC_FU_VOLUME          (1 << (UAC_VOLUME_CONTROL - 1))
-#define UAC_FU_BASS            (1 << (UAC_BASS_CONTROL - 1))
-#define UAC_FU_MID             (1 << (UAC_MID_CONTROL - 1))
-#define UAC_FU_TREBLE          (1 << (UAC_TREBLE_CONTROL - 1))
-#define UAC_FU_GRAPHIC_EQ      (1 << (UAC_GRAPHIC_EQUALIZER_CONTROL - 1))
-#define UAC_FU_AUTO_GAIN       (1 << (UAC_AUTOMATIC_GAIN_CONTROL - 1))
-#define UAC_FU_DELAY           (1 << (UAC_DELAY_CONTROL - 1))
-#define UAC_FU_BASS_BOOST      (1 << (UAC_BASS_BOOST_CONTROL - 1))
-#define UAC_FU_LOUDNESS                (1 << (UAC_LOUDNESS_CONTROL - 1))
-
 /* status word format (3.7.1.1) */
 
 #define UAC1_STATUS_TYPE_ORIG_MASK             0x0f
index 422cb19f156ef9b7a6f5ab8968ade8a618ea5d88..3ac6f5b0a64b7448aceac7407c04cf7109f7ef5d 100644 (file)
@@ -4598,7 +4598,7 @@ static int alloc_css_id(struct cgroup_subsys *ss, struct cgroup *parent,
        parent_css = parent->subsys[subsys_id];
        child_css = child->subsys[subsys_id];
        parent_id = parent_css->id;
-       depth = parent_id->depth;
+       depth = parent_id->depth + 1;
 
        child_id = get_new_cssid(ss, depth);
        if (IS_ERR(child_id))
index c35452cadded85de8e4505def877b3c5561c991f..dd62f8e714ca52d2fed7a7b14b03a6ee9a53d2f1 100644 (file)
@@ -27,7 +27,7 @@ static struct exec_domain *exec_domains = &default_exec_domain;
 static DEFINE_RWLOCK(exec_domains_lock);
 
 
-static u_long ident_map[32] = {
+static unsigned long ident_map[32] = {
        0,      1,      2,      3,      4,      5,      6,      7,
        8,      9,      10,     11,     12,     13,     14,     15,
        16,     17,     18,     19,     20,     21,     22,     23,
@@ -56,10 +56,10 @@ default_handler(int segment, struct pt_regs *regp)
 }
 
 static struct exec_domain *
-lookup_exec_domain(u_long personality)
+lookup_exec_domain(unsigned int personality)
 {
-       struct exec_domain *    ep;
-       u_long                  pers = personality(personality);
+       unsigned int pers = personality(personality);
+       struct exec_domain *ep;
 
        read_lock(&exec_domains_lock);
        for (ep = exec_domains; ep; ep = ep->next) {
@@ -70,7 +70,7 @@ lookup_exec_domain(u_long personality)
 
 #ifdef CONFIG_MODULES
        read_unlock(&exec_domains_lock);
-       request_module("personality-%ld", pers);
+       request_module("personality-%d", pers);
        read_lock(&exec_domains_lock);
 
        for (ep = exec_domains; ep; ep = ep->next) {
@@ -135,7 +135,7 @@ unregister:
 }
 
 int
-__set_personality(u_long personality)
+__set_personality(unsigned int personality)
 {
        struct exec_domain      *ep, *oep;
 
@@ -188,9 +188,9 @@ static int __init proc_execdomains_init(void)
 module_init(proc_execdomains_init);
 #endif
 
-SYSCALL_DEFINE1(personality, u_long, personality)
+SYSCALL_DEFINE1(personality, unsigned int, personality)
 {
-       u_long old = current->personality;
+       unsigned int old = current->personality;
 
        if (personality != 0xffffffff) {
                set_personality(personality);
@@ -198,7 +198,7 @@ SYSCALL_DEFINE1(personality, u_long, personality)
                        return -EINVAL;
        }
 
-       return (long)old;
+       return old;
 }
 
 
index 825e1126008f374e5d9d2650a5bb29fe2106424d..07b4f1b1a73a9b6a309a3e7fe249c813007b5d17 100644 (file)
@@ -850,7 +850,7 @@ static __init int spawn_ksoftirqd(void)
        void *cpu = (void *)(long)smp_processor_id();
        int err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
 
-       BUG_ON(err == NOTIFY_BAD);
+       BUG_ON(err != NOTIFY_OK);
        cpu_callback(&cpu_nfb, CPU_ONLINE, cpu);
        register_cpu_notifier(&cpu_nfb);
        return 0;
index 2454172a80d3c6131313007d08f91f12eb85c107..ee305c8d4e18eb038a54f0f9aea8eb2f353b1f44 100644 (file)
@@ -1717,7 +1717,7 @@ void __init init_timers(void)
 
        init_timer_stats();
 
-       BUG_ON(err == NOTIFY_BAD);
+       BUG_ON(err != NOTIFY_OK);
        register_cpu_notifier(&timers_nb);
        open_softirq(TIMER_SOFTIRQ, run_timer_softirq);
 }
index 9087d71537ddef84c011b86988e17202b007a291..250ed11d3ed2b83b8e2a87845fe97a7db096b33c 100644 (file)
@@ -113,7 +113,8 @@ static __init int test_atomic64(void)
        r += one;
        BUG_ON(v.counter != r);
 
-#if defined(CONFIG_X86) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(_ASM_GENERIC_ATOMIC64_H)
+#if defined(CONFIG_X86) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || \
+    defined(CONFIG_S390) || defined(_ASM_GENERIC_ATOMIC64_H)
        INIT(onestwos);
        BUG_ON(atomic64_dec_if_positive(&v) != (onestwos - 1));
        r -= one;
index 915dceb487c11b1f1783df86908ba5e6e7317769..9c7e57cc63a34f7231b77a7d8b395d3157a34ba6 100644 (file)
@@ -1724,13 +1724,13 @@ static void shrink_zone(int priority, struct zone *zone,
  * If a zone is deemed to be full of pinned pages then just give it a light
  * scan then give up on it.
  */
-static int shrink_zones(int priority, struct zonelist *zonelist,
+static bool shrink_zones(int priority, struct zonelist *zonelist,
                                        struct scan_control *sc)
 {
        enum zone_type high_zoneidx = gfp_zone(sc->gfp_mask);
        struct zoneref *z;
        struct zone *zone;
-       int progress = 0;
+       bool all_unreclaimable = true;
 
        for_each_zone_zonelist_nodemask(zone, z, zonelist, high_zoneidx,
                                        sc->nodemask) {
@@ -1757,9 +1757,9 @@ static int shrink_zones(int priority, struct zonelist *zonelist,
                }
 
                shrink_zone(priority, zone, sc);
-               progress = 1;
+               all_unreclaimable = false;
        }
-       return progress;
+       return all_unreclaimable;
 }
 
 /*
@@ -1782,7 +1782,7 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
                                        struct scan_control *sc)
 {
        int priority;
-       unsigned long ret = 0;
+       bool all_unreclaimable;
        unsigned long total_scanned = 0;
        struct reclaim_state *reclaim_state = current->reclaim_state;
        unsigned long lru_pages = 0;
@@ -1813,7 +1813,7 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
                sc->nr_scanned = 0;
                if (!priority)
                        disable_swap_token();
-               ret = shrink_zones(priority, zonelist, sc);
+               all_unreclaimable = shrink_zones(priority, zonelist, sc);
                /*
                 * Don't shrink slabs when reclaiming memory from
                 * over limit cgroups
@@ -1826,10 +1826,8 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
                        }
                }
                total_scanned += sc->nr_scanned;
-               if (sc->nr_reclaimed >= sc->nr_to_reclaim) {
-                       ret = sc->nr_reclaimed;
+               if (sc->nr_reclaimed >= sc->nr_to_reclaim)
                        goto out;
-               }
 
                /*
                 * Try to write back as many pages as we just scanned.  This
@@ -1849,9 +1847,7 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
                    priority < DEF_PRIORITY - 2)
                        congestion_wait(BLK_RW_ASYNC, HZ/10);
        }
-       /* top priority shrink_zones still had more to do? don't OOM, then */
-       if (ret && scanning_global_lru(sc))
-               ret = sc->nr_reclaimed;
+
 out:
        /*
         * Now that we've scanned all the zones at this priority level, note
@@ -1877,7 +1873,14 @@ out:
        delayacct_freepages_end();
        put_mems_allowed();
 
-       return ret;
+       if (sc->nr_reclaimed)
+               return sc->nr_reclaimed;
+
+       /* top priority shrink_zones still had more to do? don't OOM, then */
+       if (scanning_global_lru(sc) && !all_unreclaimable)
+               return 1;
+
+       return 0;
 }
 
 unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
index f74c7372b3d14d3ba553cc8b904dd75585b28bd3..1db586af4f9c8189fda494d2aead7f9c6c22f954 100644 (file)
@@ -2578,6 +2578,9 @@ static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)
        if (err)
                return -err;
 
+       memset(&prev_ctl, 0, sizeof(prev_ctl));
+       prev_ctl.control_type = -1;
+
        for (idx = 0; idx < 2000; idx++) {
                err = hpi_mixer_get_control_by_index(
                                ss, asihpi->h_mixer,
index dc79564fea30d2e17fef0b9abfc51b0ec636c73f..1df25cf5ce38c35f0d04fdddd43be9ea1d23c3f4 100644 (file)
@@ -1913,11 +1913,11 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
        if (WARN_ONCE(!azx_dev->period_bytes,
                      "hda-intel: zero azx_dev->period_bytes"))
                return -1; /* this shouldn't happen! */
-       if (wallclk <= azx_dev->period_wallclk &&
+       if (wallclk < (azx_dev->period_wallclk * 5) / 4 &&
            pos % azx_dev->period_bytes > azx_dev->period_bytes / 2)
                /* NG - it's below the first next period boundary */
                return bdl_pos_adj[chip->dev_index] ? 0 : -1;
-       azx_dev->start_wallclk = wallclk;
+       azx_dev->start_wallclk += wallclk;
        return 1; /* OK, it's fine */
 }
 
@@ -2288,6 +2288,8 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = {
        SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
+       SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB),
+       SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS M2V", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba A100-259", POS_FIX_LPIB),
@@ -2296,6 +2298,7 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = {
        SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1565, 0x8218, "Biostar Microtech", POS_FIX_LPIB),
+       SND_PCI_QUIRK(0x1849, 0x0888, "775Dual-VSTA", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x8086, 0x2503, "DG965OT AAD63733-203", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x8086, 0xd601, "eMachines T5212", POS_FIX_LPIB),
        {}
index 17d4548cc353f72402693b0b39461226467a00d9..d792cddbf4c2eeb87e7e18ec812ce2c217a84b7b 100644 (file)
@@ -9476,6 +9476,7 @@ static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
        SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24),
        SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24),
        SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
+       SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31),
        SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
        SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
        SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
index eba9b9d257a109b3e4554581cc97f9d6fe839035..252defea93b5f2fdc4e64ad9ae4c484e2b8d9eca 100644 (file)
@@ -13,9 +13,18 @@ config SND_MXC_SOC_SSI
 
 config SND_MXC_SOC_WM1133_EV1
        tristate "Audio on the the i.MX31ADS with WM1133-EV1 fitted"
-       depends on SND_IMX_SOC && EXPERIMENTAL
+       depends on SND_IMX_SOC && MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL
        select SND_SOC_WM8350
        select SND_MXC_SOC_SSI
        help
          Enable support for audio on the i.MX31ADS with the WM1133-EV1
          PMIC board with WM8835x fitted.
+
+config SND_SOC_PHYCORE_AC97
+       tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards"
+       depends on MACH_PCM043 || MACH_PCA100
+       select SND_MXC_SOC_SSI
+       select SND_SOC_WM9712
+       help
+         Say Y if you want to add support for SoC audio on Phytec phyCORE
+         and phyCARD boards in AC97 mode
index e7ac7f493a8fa1d0874ca9992ee180679390ec69..1e362bf8834f4e5fdfc6da32cf33a96f53ef7c85 100644 (file)
@@ -11,7 +11,8 @@ snd-usb-audio-objs :=         card.o \
                        endpoint.o \
                        urb.o \
                        pcm.o \
-                       helper.o
+                       helper.o \
+                       clock.o
 
 snd-usbmidi-lib-objs := midi.o
 
index da1346bd4856893a5e2449abfe0d6cd1e6293ea5..7a8ac1d81be7fc7e1a176ad432cd43a841a9e74d 100644 (file)
@@ -236,7 +236,6 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
        }
 
        case UAC_VERSION_2: {
-               struct uac_clock_source_descriptor *cs;
                struct usb_interface_assoc_descriptor *assoc =
                        usb_ifnum_to_if(dev, ctrlif)->intf_assoc;
 
@@ -245,21 +244,6 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
                        return -EINVAL;
                }
 
-               /* FIXME: for now, we expect there is at least one clock source
-                * descriptor and we always take the first one.
-                * We should properly support devices with multiple clock sources,
-                * clock selectors and sample rate conversion units. */
-
-               cs = snd_usb_find_csint_desc(host_iface->extra, host_iface->extralen,
-                                               NULL, UAC2_CLOCK_SOURCE);
-
-               if (!cs) {
-                       snd_printk(KERN_ERR "CLOCK_SOURCE descriptor not found\n");
-                       return -EINVAL;
-               }
-
-               chip->clock_id = cs->bClockID;
-
                for (i = 0; i < assoc->bInterfaceCount; i++) {
                        int intf = assoc->bFirstInterface + i;
 
@@ -481,6 +465,8 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
                        goto __error;
        }
 
+       chip->ctrl_intf = alts;
+
        if (err > 0) {
                /* create normal USB audio interfaces */
                if (snd_usb_create_streams(chip, ifnum) < 0 ||
index ed92420c10957150f30db2891191ffe60bf4b0c3..1febf2f23754afc63eb5469450ac8da6a97f23b3 100644 (file)
@@ -25,6 +25,7 @@ struct audioformat {
        unsigned int rate_min, rate_max;        /* min/max rates */
        unsigned int nr_rates;          /* number of rate table entries */
        unsigned int *rate_table;       /* rate table */
+       unsigned char clock;            /* associated clock */
 };
 
 struct snd_usb_substream;
diff --git a/sound/usb/clock.c b/sound/usb/clock.c
new file mode 100644 (file)
index 0000000..b7aadd6
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ *   Clock domain and sample rate management functions
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <linux/bitops.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/usb.h>
+#include <linux/moduleparam.h>
+#include <linux/mutex.h>
+#include <linux/usb/audio.h>
+#include <linux/usb/audio-v2.h>
+
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+
+#include "usbaudio.h"
+#include "card.h"
+#include "midi.h"
+#include "mixer.h"
+#include "proc.h"
+#include "quirks.h"
+#include "endpoint.h"
+#include "helper.h"
+#include "debug.h"
+#include "pcm.h"
+#include "urb.h"
+#include "format.h"
+
+static struct uac_clock_source_descriptor *
+       snd_usb_find_clock_source(struct usb_host_interface *ctrl_iface,
+                                 int clock_id)
+{
+       struct uac_clock_source_descriptor *cs = NULL;
+
+       while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra,
+                                            ctrl_iface->extralen,
+                                            cs, UAC2_CLOCK_SOURCE))) {
+               if (cs->bClockID == clock_id)
+                       return cs;
+       }
+
+       return NULL;
+}
+
+static struct uac_clock_selector_descriptor *
+       snd_usb_find_clock_selector(struct usb_host_interface *ctrl_iface,
+                                   int clock_id)
+{
+       struct uac_clock_selector_descriptor *cs = NULL;
+
+       while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra,
+                                            ctrl_iface->extralen,
+                                            cs, UAC2_CLOCK_SELECTOR))) {
+               if (cs->bClockID == clock_id)
+                       return cs;
+       }
+
+       return NULL;
+}
+
+static struct uac_clock_multiplier_descriptor *
+       snd_usb_find_clock_multiplier(struct usb_host_interface *ctrl_iface,
+                                     int clock_id)
+{
+       struct uac_clock_multiplier_descriptor *cs = NULL;
+
+       while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra,
+                                            ctrl_iface->extralen,
+                                            cs, UAC2_CLOCK_MULTIPLIER))) {
+               if (cs->bClockID == clock_id)
+                       return cs;
+       }
+
+       return NULL;
+}
+
+static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id)
+{
+       unsigned char buf;
+       int ret;
+
+       ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
+                             UAC2_CS_CUR,
+                             USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+                             UAC2_CX_CLOCK_SELECTOR << 8, selector_id << 8,
+                             &buf, sizeof(buf), 1000);
+
+       if (ret < 0)
+               return ret;
+
+       return buf;
+}
+
+static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id)
+{
+       int err;
+       unsigned char data;
+       struct usb_device *dev = chip->dev;
+
+       err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
+                             USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+                             UAC2_CS_CONTROL_CLOCK_VALID << 8, source_id << 8,
+                             &data, sizeof(data), 1000);
+
+       if (err < 0) {
+               snd_printk(KERN_WARNING "%s(): cannot get clock validity for id %d\n",
+                          __func__, source_id);
+               return err;
+       }
+
+       return !!data;
+}
+
+/* Try to find the clock source ID of a given clock entity */
+
+static int __uac_clock_find_source(struct snd_usb_audio *chip,
+                                  struct usb_host_interface *host_iface,
+                                  int entity_id, unsigned long *visited)
+{
+       struct uac_clock_source_descriptor *source;
+       struct uac_clock_selector_descriptor *selector;
+       struct uac_clock_multiplier_descriptor *multiplier;
+
+       entity_id &= 0xff;
+
+       if (test_and_set_bit(entity_id, visited)) {
+               snd_printk(KERN_WARNING
+                       "%s(): recursive clock topology detected, id %d.\n",
+                       __func__, entity_id);
+               return -EINVAL;
+       }
+
+       /* first, see if the ID we're looking for is a clock source already */
+       source = snd_usb_find_clock_source(host_iface, entity_id);
+       if (source)
+               return source->bClockID;
+
+       selector = snd_usb_find_clock_selector(host_iface, entity_id);
+       if (selector) {
+               int ret;
+
+               /* the entity ID we are looking for is a selector.
+                * find out what it currently selects */
+               ret = uac_clock_selector_get_val(chip, selector->bClockID);
+               if (ret < 0)
+                       return ret;
+
+               if (ret > selector->bNrInPins || ret < 1) {
+                       printk(KERN_ERR
+                               "%s(): selector reported illegal value, id %d, ret %d\n",
+                               __func__, selector->bClockID, ret);
+
+                       return -EINVAL;
+               }
+
+               return __uac_clock_find_source(chip, host_iface,
+                                              selector->baCSourceID[ret-1],
+                                              visited);
+       }
+
+       /* FIXME: multipliers only act as pass-thru element for now */
+       multiplier = snd_usb_find_clock_multiplier(host_iface, entity_id);
+       if (multiplier)
+               return __uac_clock_find_source(chip, host_iface,
+                                              multiplier->bCSourceID, visited);
+
+       return -EINVAL;
+}
+
+int snd_usb_clock_find_source(struct snd_usb_audio *chip,
+                             struct usb_host_interface *host_iface,
+                             int entity_id)
+{
+       DECLARE_BITMAP(visited, 256);
+       memset(visited, 0, sizeof(visited));
+       return __uac_clock_find_source(chip, host_iface, entity_id, visited);
+}
+
+static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface,
+                             struct usb_host_interface *alts,
+                             struct audioformat *fmt, int rate)
+{
+       struct usb_device *dev = chip->dev;
+       unsigned int ep;
+       unsigned char data[3];
+       int err, crate;
+
+       ep = get_endpoint(alts, 0)->bEndpointAddress;
+
+       /* if endpoint doesn't have sampling rate control, bail out */
+       if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE)) {
+               snd_printk(KERN_WARNING "%d:%d:%d: endpoint lacks sample rate attribute bit, cannot set.\n",
+                                  dev->devnum, iface, fmt->altsetting);
+               return 0;
+       }
+
+       data[0] = rate;
+       data[1] = rate >> 8;
+       data[2] = rate >> 16;
+       if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
+                                  USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+                                  UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
+                                  data, sizeof(data), 1000)) < 0) {
+               snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n",
+                          dev->devnum, iface, fmt->altsetting, rate, ep);
+               return err;
+       }
+
+       if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR,
+                                  USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN,
+                                  UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
+                                  data, sizeof(data), 1000)) < 0) {
+               snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n",
+                          dev->devnum, iface, fmt->altsetting, ep);
+               return 0; /* some devices don't support reading */
+       }
+
+       crate = data[0] | (data[1] << 8) | (data[2] << 16);
+       if (crate != rate) {
+               snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate);
+               // runtime->rate = crate;
+       }
+
+       return 0;
+}
+
+static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface,
+                             struct usb_host_interface *alts,
+                             struct audioformat *fmt, int rate)
+{
+       struct usb_device *dev = chip->dev;
+       unsigned char data[4];
+       int err, crate;
+       int clock = snd_usb_clock_find_source(chip, chip->ctrl_intf, fmt->clock);
+
+       if (clock < 0)
+               return clock;
+
+       if (!uac_clock_source_is_valid(chip, clock)) {
+               snd_printk(KERN_ERR "%d:%d:%d: clock source %d is not valid, cannot use\n",
+                          dev->devnum, iface, fmt->altsetting, clock);
+               return -ENXIO;
+       }
+
+       data[0] = rate;
+       data[1] = rate >> 8;
+       data[2] = rate >> 16;
+       data[3] = rate >> 24;
+       if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR,
+                                  USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+                                  UAC2_CS_CONTROL_SAM_FREQ << 8, clock << 8,
+                                  data, sizeof(data), 1000)) < 0) {
+               snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2)\n",
+                          dev->devnum, iface, fmt->altsetting, rate);
+               return err;
+       }
+
+       if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
+                                  USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+                                  UAC2_CS_CONTROL_SAM_FREQ << 8, clock << 8,
+                                  data, sizeof(data), 1000)) < 0) {
+               snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n",
+                          dev->devnum, iface, fmt->altsetting);
+               return err;
+       }
+
+       crate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
+       if (crate != rate)
+               snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate);
+
+       return 0;
+}
+
+int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,
+                            struct usb_host_interface *alts,
+                            struct audioformat *fmt, int rate)
+{
+       struct usb_interface_descriptor *altsd = get_iface_desc(alts);
+
+       switch (altsd->bInterfaceProtocol) {
+       case UAC_VERSION_1:
+               return set_sample_rate_v1(chip, iface, alts, fmt, rate);
+
+       case UAC_VERSION_2:
+               return set_sample_rate_v2(chip, iface, alts, fmt, rate);
+       }
+
+       return -EINVAL;
+}
+
diff --git a/sound/usb/clock.h b/sound/usb/clock.h
new file mode 100644 (file)
index 0000000..beb2536
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef __USBAUDIO_CLOCK_H
+#define __USBAUDIO_CLOCK_H
+
+int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,
+                            struct usb_host_interface *alts,
+                            struct audioformat *fmt, int rate);
+
+int snd_usb_clock_find_source(struct snd_usb_audio *chip,
+                             struct usb_host_interface *host_iface,
+                             int entity_id);
+
+#endif /* __USBAUDIO_CLOCK_H */
index 28ee1ce3971a7fd063fdfc0f80a8f73696bb9b4b..9593b91452b97f9564989d4ab1df7a32905b4e64 100644 (file)
@@ -190,6 +190,38 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
        return attributes;
 }
 
+static struct uac2_input_terminal_descriptor *
+       snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface,
+                                              int terminal_id)
+{
+       struct uac2_input_terminal_descriptor *term = NULL;
+
+       while ((term = snd_usb_find_csint_desc(ctrl_iface->extra,
+                                              ctrl_iface->extralen,
+                                              term, UAC_INPUT_TERMINAL))) {
+               if (term->bTerminalID == terminal_id)
+                       return term;
+       }
+
+       return NULL;
+}
+
+static struct uac2_output_terminal_descriptor *
+       snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface,
+                                               int terminal_id)
+{
+       struct uac2_output_terminal_descriptor *term = NULL;
+
+       while ((term = snd_usb_find_csint_desc(ctrl_iface->extra,
+                                              ctrl_iface->extralen,
+                                              term, UAC_OUTPUT_TERMINAL))) {
+               if (term->bTerminalID == terminal_id)
+                       return term;
+       }
+
+       return NULL;
+}
+
 int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
 {
        struct usb_device *dev;
@@ -199,7 +231,7 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
        int i, altno, err, stream;
        int format = 0, num_channels = 0;
        struct audioformat *fp = NULL;
-       int num, protocol;
+       int num, protocol, clock = 0;
        struct uac_format_type_i_continuous_descriptor *fmt;
 
        dev = chip->dev;
@@ -263,6 +295,8 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                }
 
                case UAC_VERSION_2: {
+                       struct uac2_input_terminal_descriptor *input_term;
+                       struct uac2_output_terminal_descriptor *output_term;
                        struct uac_as_header_descriptor_v2 *as =
                                snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL);
 
@@ -281,7 +315,25 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                        num_channels = as->bNrChannels;
                        format = le32_to_cpu(as->bmFormats);
 
-                       break;
+                       /* lookup the terminal associated to this interface
+                        * to extract the clock */
+                       input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
+                                                                           as->bTerminalLink);
+                       if (input_term) {
+                               clock = input_term->bCSourceID;
+                               break;
+                       }
+
+                       output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
+                                                                             as->bTerminalLink);
+                       if (output_term) {
+                               clock = output_term->bCSourceID;
+                               break;
+                       }
+
+                       snd_printk(KERN_ERR "%d:%u:%d : bogus bTerminalLink %d\n",
+                                  dev->devnum, iface_no, altno, as->bTerminalLink);
+                       continue;
                }
 
                default:
@@ -338,6 +390,7 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                        fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1)
                                        * (fp->maxpacksize & 0x7ff);
                fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no);
+               fp->clock = clock;
 
                /* some quirks for attributes here */
 
index fe29d61de19bc80bdc0dbdc2fe209fd3fd71b21e..5367cd1e52d9dac9231077e829ca3e0869175de4 100644 (file)
@@ -29,6 +29,7 @@
 #include "quirks.h"
 #include "helper.h"
 #include "debug.h"
+#include "clock.h"
 
 /*
  * parse the audio format type I descriptor
@@ -215,15 +216,17 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,
        struct usb_device *dev = chip->dev;
        unsigned char tmp[2], *data;
        int i, nr_rates, data_size, ret = 0;
+       int clock = snd_usb_clock_find_source(chip, chip->ctrl_intf, fp->clock);
 
        /* get the number of sample rates first by only fetching 2 bytes */
        ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE,
                              USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
-                             UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8,
+                             UAC2_CS_CONTROL_SAM_FREQ << 8, clock << 8,
                              tmp, sizeof(tmp), 1000);
 
        if (ret < 0) {
-               snd_printk(KERN_ERR "unable to retrieve number of sample rates\n");
+               snd_printk(KERN_ERR "%s(): unable to retrieve number of sample rates (clock %d)\n",
+                               __func__, clock);
                goto err;
        }
 
@@ -237,12 +240,13 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,
 
        /* now get the full information */
        ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE,
-                              USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
-                              UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8,
-                              data, data_size, 1000);
+                             USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+                             UAC2_CS_CONTROL_SAM_FREQ << 8, clock << 8,
+                             data, data_size, 1000);
 
        if (ret < 0) {
-               snd_printk(KERN_ERR "unable to retrieve sample rate range\n");
+               snd_printk(KERN_ERR "%s(): unable to retrieve sample rate range (clock %d)\n",
+                               __func__, clock);
                ret = -EINVAL;
                goto err_free;
        }
index 03ce971e002760e84b2d36565ee0cbfa56bebd50..a060d005e20921089309569a9e8ebb9c9115b455 100644 (file)
@@ -78,39 +78,6 @@ enum {
        USB_MIXER_U16,
 };
 
-enum {
-       USB_PROC_UPDOWN = 1,
-       USB_PROC_UPDOWN_SWITCH = 1,
-       USB_PROC_UPDOWN_MODE_SEL = 2,
-
-       USB_PROC_PROLOGIC = 2,
-       USB_PROC_PROLOGIC_SWITCH = 1,
-       USB_PROC_PROLOGIC_MODE_SEL = 2,
-
-       USB_PROC_3DENH = 3,
-       USB_PROC_3DENH_SWITCH = 1,
-       USB_PROC_3DENH_SPACE = 2,
-
-       USB_PROC_REVERB = 4,
-       USB_PROC_REVERB_SWITCH = 1,
-       USB_PROC_REVERB_LEVEL = 2,
-       USB_PROC_REVERB_TIME = 3,
-       USB_PROC_REVERB_DELAY = 4,
-
-       USB_PROC_CHORUS = 5,
-       USB_PROC_CHORUS_SWITCH = 1,
-       USB_PROC_CHORUS_LEVEL = 2,
-       USB_PROC_CHORUS_RATE = 3,
-       USB_PROC_CHORUS_DEPTH = 4,
-
-       USB_PROC_DCR = 6,
-       USB_PROC_DCR_SWITCH = 1,
-       USB_PROC_DCR_RATIO = 2,
-       USB_PROC_DCR_MAX_AMP = 3,
-       USB_PROC_DCR_THRESHOLD = 4,
-       USB_PROC_DCR_ATTACK = 5,
-       USB_PROC_DCR_RELEASE = 6,
-};
 
 /*E-mu 0202(0404) eXtension Unit(XU) control*/
 enum {
@@ -198,22 +165,24 @@ static int check_mapped_selector_name(struct mixer_build *state, int unitid,
 
 /*
  * find an audio control unit with the given unit id
- * this doesn't return any clock related units, so they need to be handled elsewhere
  */
 static void *find_audio_control_unit(struct mixer_build *state, unsigned char unit)
 {
-       unsigned char *p;
+       /* we just parse the header */
+       struct uac_feature_unit_descriptor *hdr = NULL;
 
-       p = NULL;
-       while ((p = snd_usb_find_desc(state->buffer, state->buflen, p,
-                                     USB_DT_CS_INTERFACE)) != NULL) {
-               if (p[0] >= 4 && p[2] >= UAC_INPUT_TERMINAL && p[2] <= UAC2_EXTENSION_UNIT_V2 && p[3] == unit)
-                       return p;
+       while ((hdr = snd_usb_find_desc(state->buffer, state->buflen, hdr,
+                                       USB_DT_CS_INTERFACE)) != NULL) {
+               if (hdr->bLength >= 4 &&
+                   hdr->bDescriptorSubtype >= UAC_INPUT_TERMINAL &&
+                   hdr->bDescriptorSubtype <= UAC2_SAMPLE_RATE_CONVERTER &&
+                   hdr->bUnitID == unit)
+                       return hdr;
        }
+
        return NULL;
 }
 
-
 /*
  * copy a string with the given id
  */
@@ -344,8 +313,8 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v
                              buf, sizeof(buf), 1000);
 
        if (ret < 0) {
-               snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
-                           request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type);
+               snd_printk(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
+                          request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type);
                return ret;
        }
 
@@ -462,6 +431,16 @@ static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
                             int index, int value)
 {
        int err;
+       unsigned int read_only = (channel == 0) ?
+               cval->master_readonly :
+               cval->ch_readonly & (1 << (channel - 1));
+
+       if (read_only) {
+               snd_printdd(KERN_INFO "%s(): channel %d of control %d is read_only\n",
+                           __func__, channel, cval->control);
+               return 0;
+       }
+
        err = snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, (cval->control << 8) | channel,
                            value);
        if (err < 0)
@@ -631,6 +610,7 @@ static int get_term_name(struct mixer_build *state, struct usb_audio_term *iterm
  */
 static int check_input_term(struct mixer_build *state, int id, struct usb_audio_term *term)
 {
+       int err;
        void *p1;
 
        memset(term, 0, sizeof(*term));
@@ -651,6 +631,11 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_
                                term->channels = d->bNrChannels;
                                term->chconfig = le32_to_cpu(d->bmChannelConfig);
                                term->name = d->iTerminal;
+
+                               /* call recursively to get the clock selectors */
+                               err = check_input_term(state, d->bCSourceID, term);
+                               if (err < 0)
+                                       return err;
                        }
                        return 0;
                case UAC_FEATURE_UNIT: {
@@ -667,7 +652,8 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_
                        term->name = uac_mixer_unit_iMixer(d);
                        return 0;
                }
-               case UAC_SELECTOR_UNIT: {
+               case UAC_SELECTOR_UNIT:
+               case UAC2_CLOCK_SELECTOR: {
                        struct uac_selector_unit_descriptor *d = p1;
                        /* call recursively to retrieve the channel info */
                        if (check_input_term(state, d->baSourceID[0], term) < 0)
@@ -690,6 +676,13 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_
                        term->name = uac_processing_unit_iProcessing(d, state->mixer->protocol);
                        return 0;
                }
+               case UAC2_CLOCK_SOURCE: {
+                       struct uac_clock_source_descriptor *d = p1;
+                       term->type = d->bDescriptorSubtype << 16; /* virtual type */
+                       term->id = id;
+                       term->name = d->iClockSource;
+                       return 0;
+               }
                default:
                        return -ENODEV;
                }
@@ -709,16 +702,20 @@ struct usb_feature_control_info {
 };
 
 static struct usb_feature_control_info audio_feature_info[] = {
-       { "Mute",               USB_MIXER_INV_BOOLEAN },
-       { "Volume",             USB_MIXER_S16 },
+       { "Mute",                       USB_MIXER_INV_BOOLEAN },
+       { "Volume",                     USB_MIXER_S16 },
        { "Tone Control - Bass",        USB_MIXER_S8 },
        { "Tone Control - Mid",         USB_MIXER_S8 },
        { "Tone Control - Treble",      USB_MIXER_S8 },
        { "Graphic Equalizer",          USB_MIXER_S8 }, /* FIXME: not implemeted yet */
-       { "Auto Gain Control",  USB_MIXER_BOOLEAN },
-       { "Delay Control",      USB_MIXER_U16 },
-       { "Bass Boost",         USB_MIXER_BOOLEAN },
-       { "Loudness",           USB_MIXER_BOOLEAN },
+       { "Auto Gain Control",          USB_MIXER_BOOLEAN },
+       { "Delay Control",              USB_MIXER_U16 },
+       { "Bass Boost",                 USB_MIXER_BOOLEAN },
+       { "Loudness",                   USB_MIXER_BOOLEAN },
+       /* UAC2 specific */
+       { "Input Gain Control",         USB_MIXER_U16 },
+       { "Input Gain Pad Control",     USB_MIXER_BOOLEAN },
+       { "Phase Inverter Control",     USB_MIXER_BOOLEAN },
 };
 
 
@@ -958,7 +955,7 @@ static size_t append_ctl_name(struct snd_kcontrol *kctl, const char *str)
 static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
                              unsigned int ctl_mask, int control,
                              struct usb_audio_term *iterm, int unitid,
-                             int read_only)
+                             int readonly_mask)
 {
        struct uac_feature_unit_descriptor *desc = raw_desc;
        unsigned int len = 0;
@@ -970,7 +967,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
 
        control++; /* change from zero-based to 1-based value */
 
-       if (control == UAC_GRAPHIC_EQUALIZER_CONTROL) {
+       if (control == UAC_FU_GRAPHIC_EQUALIZER) {
                /* FIXME: not supported yet */
                return;
        }
@@ -989,20 +986,25 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
        cval->control = control;
        cval->cmask = ctl_mask;
        cval->val_type = audio_feature_info[control-1].type;
-       if (ctl_mask == 0)
+       if (ctl_mask == 0) {
                cval->channels = 1;     /* master channel */
-       else {
+               cval->master_readonly = readonly_mask;
+       } else {
                int i, c = 0;
                for (i = 0; i < 16; i++)
                        if (ctl_mask & (1 << i))
                                c++;
                cval->channels = c;
+               cval->ch_readonly = readonly_mask;
        }
 
        /* get min/max values */
        get_min_max(cval, 0);
 
-       if (read_only)
+       /* if all channels in the mask are marked read-only, make the control
+        * read-only. set_cur_mix_value() will check the mask again and won't
+        * issue write commands to read-only channels. */
+       if (cval->channels == readonly_mask)
                kctl = snd_ctl_new1(&usb_feature_unit_ctl_ro, cval);
        else
                kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval);
@@ -1021,8 +1023,8 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
                                kctl->id.name, sizeof(kctl->id.name));
 
        switch (control) {
-       case UAC_MUTE_CONTROL:
-       case UAC_VOLUME_CONTROL:
+       case UAC_FU_MUTE:
+       case UAC_FU_VOLUME:
                /* determine the control name.  the rule is:
                 * - if a name id is given in descriptor, use it.
                 * - if the connected input can be determined, then use the name
@@ -1049,9 +1051,9 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
                                len = append_ctl_name(kctl, " Playback");
                        }
                }
-               append_ctl_name(kctl, control == UAC_MUTE_CONTROL ?
+               append_ctl_name(kctl, control == UAC_FU_MUTE ?
                                " Switch" : " Volume");
-               if (control == UAC_VOLUME_CONTROL) {
+               if (control == UAC_FU_VOLUME) {
                        kctl->tlv.c = mixer_vol_tlv;
                        kctl->vd[0].access |= 
                                SNDRV_CTL_ELEM_ACCESS_TLV_READ |
@@ -1150,7 +1152,7 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void
                snd_printk(KERN_INFO
                           "usbmixer: master volume quirk for PCM2702 chip\n");
                /* disable non-functional volume control */
-               master_bits &= ~UAC_FU_VOLUME;
+               master_bits &= ~UAC_CONTROL_BIT(UAC_FU_VOLUME);
                break;
        }
        if (channels > 0)
@@ -1188,19 +1190,22 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void
 
                        for (j = 0; j < channels; j++) {
                                unsigned int mask = snd_usb_combine_bytes(bmaControls + csize * (j+1), csize);
-                               if (mask & (1 << (i * 2))) {
+                               if (uac2_control_is_readable(mask, i)) {
                                        ch_bits |= (1 << j);
-                                       if (~mask & (1 << ((i * 2) + 1)))
+                                       if (!uac2_control_is_writeable(mask, i))
                                                ch_read_only |= (1 << j);
                                }
                        }
 
-                       /* FIXME: the whole unit is read-only if any of the channels is marked read-only */
+                       /* NOTE: build_feature_ctl() will mark the control read-only if all channels
+                        * are marked read-only in the descriptors. Otherwise, the control will be
+                        * reported as writeable, but the driver will not actually issue a write
+                        * command for read-only channels */
                        if (ch_bits & 1) /* the first channel must be set (for ease of programming) */
-                               build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid, !!ch_read_only);
-                       if (master_bits & (1 << i * 2))
+                               build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid, ch_read_only);
+                       if (uac2_control_is_readable(master_bits, i))
                                build_feature_ctl(state, _ftr, 0, i, &iterm, unitid,
-                                                 ~master_bits & (1 << ((i * 2) + 1)));
+                                                 !uac2_control_is_writeable(master_bits, i));
                }
        }
 
@@ -1392,51 +1397,51 @@ struct procunit_info {
 };
 
 static struct procunit_value_info updown_proc_info[] = {
-       { USB_PROC_UPDOWN_SWITCH, "Switch", USB_MIXER_BOOLEAN },
-       { USB_PROC_UPDOWN_MODE_SEL, "Mode Select", USB_MIXER_U8, 1 },
+       { UAC_UD_ENABLE, "Switch", USB_MIXER_BOOLEAN },
+       { UAC_UD_MODE_SELECT, "Mode Select", USB_MIXER_U8, 1 },
        { 0 }
 };
 static struct procunit_value_info prologic_proc_info[] = {
-       { USB_PROC_PROLOGIC_SWITCH, "Switch", USB_MIXER_BOOLEAN },
-       { USB_PROC_PROLOGIC_MODE_SEL, "Mode Select", USB_MIXER_U8, 1 },
+       { UAC_DP_ENABLE, "Switch", USB_MIXER_BOOLEAN },
+       { UAC_DP_MODE_SELECT, "Mode Select", USB_MIXER_U8, 1 },
        { 0 }
 };
 static struct procunit_value_info threed_enh_proc_info[] = {
-       { USB_PROC_3DENH_SWITCH, "Switch", USB_MIXER_BOOLEAN },
-       { USB_PROC_3DENH_SPACE, "Spaciousness", USB_MIXER_U8 },
+       { UAC_3D_ENABLE, "Switch", USB_MIXER_BOOLEAN },
+       { UAC_3D_SPACE, "Spaciousness", USB_MIXER_U8 },
        { 0 }
 };
 static struct procunit_value_info reverb_proc_info[] = {
-       { USB_PROC_REVERB_SWITCH, "Switch", USB_MIXER_BOOLEAN },
-       { USB_PROC_REVERB_LEVEL, "Level", USB_MIXER_U8 },
-       { USB_PROC_REVERB_TIME, "Time", USB_MIXER_U16 },
-       { USB_PROC_REVERB_DELAY, "Delay", USB_MIXER_U8 },
+       { UAC_REVERB_ENABLE, "Switch", USB_MIXER_BOOLEAN },
+       { UAC_REVERB_LEVEL, "Level", USB_MIXER_U8 },
+       { UAC_REVERB_TIME, "Time", USB_MIXER_U16 },
+       { UAC_REVERB_FEEDBACK, "Feedback", USB_MIXER_U8 },
        { 0 }
 };
 static struct procunit_value_info chorus_proc_info[] = {
-       { USB_PROC_CHORUS_SWITCH, "Switch", USB_MIXER_BOOLEAN },
-       { USB_PROC_CHORUS_LEVEL, "Level", USB_MIXER_U8 },
-       { USB_PROC_CHORUS_RATE, "Rate", USB_MIXER_U16 },
-       { USB_PROC_CHORUS_DEPTH, "Depth", USB_MIXER_U16 },
+       { UAC_CHORUS_ENABLE, "Switch", USB_MIXER_BOOLEAN },
+       { UAC_CHORUS_LEVEL, "Level", USB_MIXER_U8 },
+       { UAC_CHORUS_RATE, "Rate", USB_MIXER_U16 },
+       { UAC_CHORUS_DEPTH, "Depth", USB_MIXER_U16 },
        { 0 }
 };
 static struct procunit_value_info dcr_proc_info[] = {
-       { USB_PROC_DCR_SWITCH, "Switch", USB_MIXER_BOOLEAN },
-       { USB_PROC_DCR_RATIO, "Ratio", USB_MIXER_U16 },
-       { USB_PROC_DCR_MAX_AMP, "Max Amp", USB_MIXER_S16 },
-       { USB_PROC_DCR_THRESHOLD, "Threshold", USB_MIXER_S16 },
-       { USB_PROC_DCR_ATTACK, "Attack Time", USB_MIXER_U16 },
-       { USB_PROC_DCR_RELEASE, "Release Time", USB_MIXER_U16 },
+       { UAC_DCR_ENABLE, "Switch", USB_MIXER_BOOLEAN },
+       { UAC_DCR_RATE, "Ratio", USB_MIXER_U16 },
+       { UAC_DCR_MAXAMPL, "Max Amp", USB_MIXER_S16 },
+       { UAC_DCR_THRESHOLD, "Threshold", USB_MIXER_S16 },
+       { UAC_DCR_ATTACK_TIME, "Attack Time", USB_MIXER_U16 },
+       { UAC_DCR_RELEASE_TIME, "Release Time", USB_MIXER_U16 },
        { 0 }
 };
 
 static struct procunit_info procunits[] = {
-       { USB_PROC_UPDOWN, "Up Down", updown_proc_info },
-       { USB_PROC_PROLOGIC, "Dolby Prologic", prologic_proc_info },
-       { USB_PROC_3DENH, "3D Stereo Extender", threed_enh_proc_info },
-       { USB_PROC_REVERB, "Reverb", reverb_proc_info },
-       { USB_PROC_CHORUS, "Chorus", chorus_proc_info },
-       { USB_PROC_DCR, "DCR", dcr_proc_info },
+       { UAC_PROCESS_UP_DOWNMIX, "Up Down", updown_proc_info },
+       { UAC_PROCESS_DOLBY_PROLOGIC, "Dolby Prologic", prologic_proc_info },
+       { UAC_PROCESS_STEREO_EXTENDER, "3D Stereo Extender", threed_enh_proc_info },
+       { UAC_PROCESS_REVERB, "Reverb", reverb_proc_info },
+       { UAC_PROCESS_CHORUS, "Chorus", chorus_proc_info },
+       { UAC_PROCESS_DYN_RANGE_COMP, "DCR", dcr_proc_info },
        { 0 },
 };
 /*
@@ -1524,7 +1529,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw
                cval->channels = 1;
 
                /* get min/max values */
-               if (type == USB_PROC_UPDOWN && cval->control == USB_PROC_UPDOWN_MODE_SEL) {
+               if (type == UAC_PROCESS_UP_DOWNMIX && cval->control == UAC_UD_MODE_SELECT) {
                        __u8 *control_spec = uac_processing_unit_specific(desc, state->mixer->protocol);
                        /* FIXME: hard-coded */
                        cval->min = 1;
@@ -1619,7 +1624,7 @@ static int mixer_ctl_selector_get(struct snd_kcontrol *kcontrol, struct snd_ctl_
        struct usb_mixer_elem_info *cval = kcontrol->private_data;
        int val, err;
 
-       err = get_cur_ctl_value(cval, 0, &val);
+       err = get_cur_ctl_value(cval, cval->control << 8, &val);
        if (err < 0) {
                if (cval->mixer->ignore_ctl_error) {
                        ucontrol->value.enumerated.item[0] = 0;
@@ -1638,7 +1643,7 @@ static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
        struct usb_mixer_elem_info *cval = kcontrol->private_data;
        int val, oval, err;
 
-       err = get_cur_ctl_value(cval, 0, &oval);
+       err = get_cur_ctl_value(cval, cval->control << 8, &oval);
        if (err < 0) {
                if (cval->mixer->ignore_ctl_error)
                        return 0;
@@ -1647,7 +1652,7 @@ static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
        val = ucontrol->value.enumerated.item[0];
        val = get_abs_value(cval, val);
        if (val != oval) {
-               set_cur_ctl_value(cval, 0, val);
+               set_cur_ctl_value(cval, cval->control << 8, val);
                return 1;
        }
        return 0;
@@ -1729,6 +1734,11 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void
        cval->res = 1;
        cval->initialized = 1;
 
+       if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR)
+               cval->control = UAC2_CX_CLOCK_SELECTOR;
+       else
+               cval->control = 0;
+
        namelist = kmalloc(sizeof(char *) * desc->bNrInPins, GFP_KERNEL);
        if (! namelist) {
                snd_printk(KERN_ERR "cannot malloc\n");
@@ -1778,7 +1788,9 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void
                if (! len)
                        strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name));
 
-               if ((state->oterm.type & 0xff00) == 0x0100)
+               if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR)
+                       append_ctl_name(kctl, " Clock Source");
+               else if ((state->oterm.type & 0xff00) == 0x0100)
                        append_ctl_name(kctl, " Capture Source");
                else
                        append_ctl_name(kctl, " Playback Source");
@@ -1812,10 +1824,12 @@ static int parse_audio_unit(struct mixer_build *state, int unitid)
 
        switch (p1[2]) {
        case UAC_INPUT_TERMINAL:
+       case UAC2_CLOCK_SOURCE:
                return 0; /* NOP */
        case UAC_MIXER_UNIT:
                return parse_audio_mixer_unit(state, unitid, p1);
        case UAC_SELECTOR_UNIT:
+       case UAC2_CLOCK_SELECTOR:
                return parse_audio_selector_unit(state, unitid, p1);
        case UAC_FEATURE_UNIT:
                return parse_audio_feature_unit(state, unitid, p1);
@@ -1912,6 +1926,11 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
                        err = parse_audio_unit(&state, desc->bSourceID);
                        if (err < 0)
                                return err;
+
+                       /* for UAC2, use the same approach to also add the clock selectors */
+                       err = parse_audio_unit(&state, desc->bCSourceID);
+                       if (err < 0)
+                               return err;
                }
        }
 
index 130123854a6cfc37dc2c16cd88281222fa021300..a7cf1007fbb07478fa6a81280174aa919ac8ec4e 100644 (file)
@@ -34,6 +34,8 @@ struct usb_mixer_elem_info {
        unsigned int id;
        unsigned int control;   /* CS or ICN (high byte) */
        unsigned int cmask; /* channel mask bitmap: 0 = master */
+       unsigned int ch_readonly;
+       unsigned int master_readonly;
        int channels;
        int val_type;
        int min, max, res;
index d93fc89beba8aee1040164bccff3935f0a78524d..f1324c423835c8ade54cdb30730e7999b3cec853 100644 (file)
@@ -85,8 +85,8 @@ static struct usbmix_name_map extigy_map[] = {
        /* 16: MU (w/o controls) */
        { 17, NULL, 1 }, /* DISABLED: PU-switch (any effect?) */
        { 17, "Channel Routing", 2 },   /* PU: mode select */
-       { 18, "Tone Control - Bass", UAC_BASS_CONTROL }, /* FU */
-       { 18, "Tone Control - Treble", UAC_TREBLE_CONTROL }, /* FU */
+       { 18, "Tone Control - Bass", UAC_FU_BASS }, /* FU */
+       { 18, "Tone Control - Treble", UAC_FU_TREBLE }, /* FU */
        { 18, "Master Playback" }, /* FU; others */
        /* 19: OT speaker */
        /* 20: OT headphone */
index 056587de7be41876047296cba15a8ea96bd384a9..456829882f4061aca8e97f9d53d07f29d309bd1e 100644 (file)
@@ -31,6 +31,7 @@
 #include "urb.h"
 #include "helper.h"
 #include "pcm.h"
+#include "clock.h"
 
 /*
  * return the current pcm pointer.  just based on the hwptr_done value.
@@ -181,103 +182,6 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
        return -EINVAL;
 }
 
-static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface,
-                             struct usb_host_interface *alts,
-                             struct audioformat *fmt, int rate)
-{
-       struct usb_device *dev = chip->dev;
-       unsigned int ep;
-       unsigned char data[3];
-       int err, crate;
-
-       ep = get_endpoint(alts, 0)->bEndpointAddress;
-       /* if endpoint doesn't have sampling rate control, bail out */
-       if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE)) {
-               snd_printk(KERN_WARNING "%d:%d:%d: endpoint lacks sample rate attribute bit, cannot set.\n",
-                                  dev->devnum, iface, fmt->altsetting);
-               return 0;
-       }
-
-       data[0] = rate;
-       data[1] = rate >> 8;
-       data[2] = rate >> 16;
-       if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
-                                  USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
-                                  UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
-                                  data, sizeof(data), 1000)) < 0) {
-               snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n",
-                          dev->devnum, iface, fmt->altsetting, rate, ep);
-               return err;
-       }
-       if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR,
-                                  USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
-                                  UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
-                                  data, sizeof(data), 1000)) < 0) {
-               snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n",
-                          dev->devnum, iface, fmt->altsetting, ep);
-               return 0; /* some devices don't support reading */
-       }
-       crate = data[0] | (data[1] << 8) | (data[2] << 16);
-       if (crate != rate) {
-               snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate);
-               // runtime->rate = crate;
-       }
-
-       return 0;
-}
-
-static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface,
-                             struct usb_host_interface *alts,
-                             struct audioformat *fmt, int rate)
-{
-       struct usb_device *dev = chip->dev;
-       unsigned char data[4];
-       int err, crate;
-
-       data[0] = rate;
-       data[1] = rate >> 8;
-       data[2] = rate >> 16;
-       data[3] = rate >> 24;
-       if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR,
-                                  USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
-                                  UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8,
-                                  data, sizeof(data), 1000)) < 0) {
-               snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2)\n",
-                          dev->devnum, iface, fmt->altsetting, rate);
-               return err;
-       }
-       if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
-                                  USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
-                                  UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8,
-                                  data, sizeof(data), 1000)) < 0) {
-               snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n",
-                          dev->devnum, iface, fmt->altsetting);
-               return err;
-       }
-       crate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
-       if (crate != rate)
-               snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate);
-
-       return 0;
-}
-
-int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,
-                            struct usb_host_interface *alts,
-                            struct audioformat *fmt, int rate)
-{
-       struct usb_interface_descriptor *altsd = get_iface_desc(alts);
-
-       switch (altsd->bInterfaceProtocol) {
-       case UAC_VERSION_1:
-               return set_sample_rate_v1(chip, iface, alts, fmt, rate);
-
-       case UAC_VERSION_2:
-               return set_sample_rate_v2(chip, iface, alts, fmt, rate);
-       }
-
-       return -EINVAL;
-}
-
 /*
  * find a matching format and set up the interface
  */
index 06ebf24d3a4d504e61840f5abca7a30a87b5d5e1..24d3319cc34d0985ace0270be5b7894a3b086c21 100644 (file)
@@ -40,9 +40,6 @@ struct snd_usb_audio {
        int num_interfaces;
        int num_suspended_intf;
 
-       /* for audio class v2 */
-       int clock_id;
-
        struct list_head pcm_list;      /* list of pcm streams */
        int pcm_devs;
 
@@ -53,6 +50,8 @@ struct snd_usb_audio {
        int setup;                      /* from the 'device_setup' module param */
        int nrpacks;                    /* from the 'nrpacks' module param */
        int async_unlink;               /* from the 'async_unlink' module param */
+
+       struct usb_host_interface *ctrl_intf;   /* the audio control interface */
 };
 
 /*