diff --git a/arch/powerpc/kernel/ppc32.h b/arch/powerpc/kernel/ppc32.h index 90e5627..fda05e2 100644 --- a/arch/powerpc/kernel/ppc32.h +++ b/arch/powerpc/kernel/ppc32.h @@ -135,4 +135,6 @@ struct ucontext32 { struct mcontext32 uc_mcontext; }; +extern int copy_siginfo_to_user32(struct compat_siginfo __user *d, siginfo_t *s); + #endif /* _PPC64_PPC32_H */ diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c index 4c1de6a..9d30e10 100644 --- a/arch/powerpc/kernel/ptrace32.c +++ b/arch/powerpc/kernel/ptrace32.c @@ -29,12 +29,15 @@ #include #include #include +#include #include #include #include #include +#include "ppc32.h" + /* * does not yet catch signals sent when the child dies. * in exit.c or in signal.c. @@ -64,6 +67,27 @@ static long compat_ptrace_old(struct task_struct *child, long request, return -EPERM; } +static int compat_ptrace_getsiginfo(struct task_struct *child, compat_siginfo_t __user *data) +{ + siginfo_t lastinfo; + int error = -ESRCH; + + read_lock(&tasklist_lock); + if (likely(child->sighand != NULL)) { + error = -EINVAL; + spin_lock_irq(&child->sighand->siglock); + if (likely(child->last_siginfo != NULL)) { + lastinfo = *child->last_siginfo; + error = 0; + } + spin_unlock_irq(&child->sighand->siglock); + } + read_unlock(&tasklist_lock); + if (!error) + return copy_siginfo_to_user32(data, &lastinfo); + return error; +} + long compat_arch_ptrace(struct task_struct *child, compat_long_t request, compat_ulong_t caddr, compat_ulong_t cdata) { @@ -282,6 +306,9 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, 0, PT_REGS_COUNT * sizeof(compat_long_t), compat_ptr(data)); + case PTRACE_GETSIGINFO: + return compat_ptrace_getsiginfo(child, compat_ptr(data)); + case PTRACE_GETFPREGS: case PTRACE_SETFPREGS: case PTRACE_GETVRREGS: diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index 794895c..f96b2e4 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c @@ -39,7 +39,7 @@ EXPORT_SYMBOL(__phys_addr); int page_is_ram(unsigned long pagenr) { - unsigned long addr, end; + resource_size_t addr, end; int i; /* @@ -109,7 +109,8 @@ static int ioremap_change_attr(unsigned long vaddr, unsigned long size, static void __iomem *__ioremap(resource_size_t phys_addr, unsigned long size, enum ioremap_mode mode) { - unsigned long pfn, offset, last_addr, vaddr; + unsigned long pfn, offset, vaddr; + resource_size_t last_addr; struct vm_struct *area; pgprot_t prot; diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c index 1fa8681..a845062 100644 --- a/drivers/acpi/bay.c +++ b/drivers/acpi/bay.c @@ -299,16 +299,20 @@ static int bay_add(acpi_handle handle, int id) */ pdev->dev.uevent_suppress = 0; - if (acpi_bay_add_fs(new_bay)) { - platform_device_unregister(new_bay->pdev); - goto bay_add_err; - } - /* register for events on this device */ status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, bay_notify, new_bay); if (ACPI_FAILURE(status)) { - printk(KERN_ERR PREFIX "Error installing bay notify handler\n"); + printk(KERN_INFO PREFIX "Error installing bay notify handler\n"); + platform_device_unregister(new_bay->pdev); + goto bay_add_err; + } + + if (acpi_bay_add_fs(new_bay)) { + acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + bay_notify); + platform_device_unregister(new_bay->pdev); + goto bay_add_err; } /* if we are on a dock station, we should register for dock diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 1bcecc7..a32aed9 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -359,10 +359,17 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) if (flag & ACPI_TRIPS_CRITICAL) { status = acpi_evaluate_integer(tz->device->handle, "_CRT", NULL, &tz->trips.critical.temperature); - if (ACPI_FAILURE(status)) { + /* + * Treat freezing temperatures as invalid as well; some + * BIOSes return really low values and cause reboots at startup. + * Below zero (Celcius) values clearly aren't right for sure.. + * ... so lets discard those as invalid. + */ + if (ACPI_FAILURE(status) || + tz->trips.critical.temperature <= 2732) { tz->trips.critical.flags.valid = 0; ACPI_EXCEPTION((AE_INFO, status, - "No critical threshold")); + "No or invalid critical threshold")); return -ENODEV; } else { tz->trips.critical.flags.valid = 1; @@ -884,10 +891,15 @@ static void acpi_thermal_check(void *data) static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf) { struct acpi_thermal *tz = thermal->devdata; + int result; if (!tz) return -EINVAL; + result = acpi_thermal_get_temperature(tz); + if (result) + return result; + return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(tz->temperature)); } diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c index 8dd3942..ce6fdec 100644 --- a/drivers/input/mouse/appletouch.c +++ b/drivers/input/mouse/appletouch.c @@ -589,6 +589,21 @@ static void atp_close(struct input_dev *input) dev->open = 0; } +static int atp_handle_geyser(struct atp *dev) +{ + struct usb_device *udev = dev->udev; + + if (!atp_is_fountain(dev)) { + /* switch to raw sensor mode */ + if (atp_geyser_init(udev)) + return -EIO; + + printk(KERN_INFO "appletouch: Geyser mode initialized.\n"); + } + + return 0; +} + static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id) { struct atp *dev; @@ -633,14 +648,6 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id else dev->datalen = 81; - if (!atp_is_fountain(dev)) { - /* switch to raw sensor mode */ - if (atp_geyser_init(udev)) - goto err_free_devs; - - printk(KERN_INFO "appletouch: Geyser mode initialized.\n"); - } - dev->urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->urb) goto err_free_devs; @@ -654,6 +661,10 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id usb_rcvintpipe(udev, int_in_endpointAddr), dev->data, dev->datalen, atp_complete, dev, 1); + error = atp_handle_geyser(dev); + if (error) + goto err_free_buffer; + usb_make_path(udev, dev->phys, sizeof(dev->phys)); strlcat(dev->phys, "/input0", sizeof(dev->phys)); @@ -744,6 +755,20 @@ static void atp_disconnect(struct usb_interface *iface) printk(KERN_INFO "input: appletouch disconnected\n"); } +static int atp_recover(struct atp *dev) +{ + int error; + + error = atp_handle_geyser(dev); + if (error) + return error; + + if (dev->open && usb_submit_urb(dev->urb, GFP_ATOMIC)) + return -EIO; + + return 0; +} + static int atp_suspend(struct usb_interface *iface, pm_message_t message) { struct atp *dev = usb_get_intfdata(iface); @@ -764,12 +789,20 @@ static int atp_resume(struct usb_interface *iface) return 0; } +static int atp_reset_resume(struct usb_interface *iface) +{ + struct atp *dev = usb_get_intfdata(iface); + + return atp_recover(dev); +} + static struct usb_driver atp_driver = { .name = "appletouch", .probe = atp_probe, .disconnect = atp_disconnect, .suspend = atp_suspend, .resume = atp_resume, + .reset_resume = atp_reset_resume, .id_table = atp_table, }; diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 60931ac..17a3568 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -63,7 +63,7 @@ static inline void i8042_write_command(int val) outb(val, I8042_COMMAND_REG); } -#if defined(__i386__) || defined(__x86_64__) +#ifdef CONFIG_X86 #include @@ -193,6 +193,20 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { }, }, { + .ident = "Fujitsu-Siemens Amilo Pro 2030", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "AMILO PRO V2030"), + }, + }, + { + .ident = "Fujitsu-Siemens Amilo Pro 2010", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro V2010"), + }, + }, + { /* * No data is coming from the touchscreen unless KBC * is in legacy mode. @@ -284,17 +298,36 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "3000 N100"), }, }, + { + .ident = "Acer Aspire 1360", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"), + }, + }, { } }; - - +#ifdef CONFIG_PNP +static struct dmi_system_id __initdata i8042_dmi_nopnp_table[] = { + { + .ident = "Intel MBO Desktop D845PESV", + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "D845PESV"), + DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), + }, + }, + { + .ident = "Gericom Bellagio", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Gericom"), + DMI_MATCH(DMI_PRODUCT_NAME, "N34AS6"), + }, + }, + { } +}; #endif -#ifdef CONFIG_X86 - -#include - /* * Some Wistron based laptops need us to explicitly enable the 'Dritek * keyboard extension' to make their extra keys start generating scancodes. @@ -342,7 +375,6 @@ static struct dmi_system_id __initdata i8042_dmi_dritek_table[] = { #endif /* CONFIG_X86 */ - #ifdef CONFIG_PNP #include @@ -452,6 +484,11 @@ static int __init i8042_pnp_init(void) int pnp_data_busted = 0; int err; +#ifdef CONFIG_X86 + if (dmi_check_system(i8042_dmi_nopnp_table)) + i8042_nopnp = 1; +#endif + if (i8042_nopnp) { printk(KERN_INFO "i8042: PNP detection disabled\n"); return 0; @@ -577,15 +614,13 @@ static int __init i8042_platform_init(void) i8042_reset = 1; #endif -#if defined(__i386__) || defined(__x86_64__) +#ifdef CONFIG_X86 if (dmi_check_system(i8042_dmi_noloop_table)) i8042_noloop = 1; if (dmi_check_system(i8042_dmi_nomux_table)) i8042_nomux = 1; -#endif -#ifdef CONFIG_X86 if (dmi_check_system(i8042_dmi_dritek_table)) i8042_dritek = 1; #endif /* CONFIG_X86 */ diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 65a74cf..f3228ae 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -938,8 +938,12 @@ static int i8042_resume(struct platform_device *dev) i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS; i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT); if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { - printk(KERN_ERR "i8042: Can't write CTR to resume\n"); - return -EIO; + printk(KERN_WARNING "i8042: Can't write CTR to resume, retrying...\n"); + msleep(50); + if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { + printk(KERN_ERR "i8042: CTR write retry failed\n"); + return -EIO; + } } if (i8042_mux_present) { diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index c3ded21..28b52c8 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -2864,7 +2864,9 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, switch(key->alg) { case ALG_WEP: - break; + /* XXX: fix hardware encryption, its not working. For now + * allow software encryption */ + /* break; */ case ALG_TKIP: case ALG_CCMP: return -EOPNOTSUPP; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index e887aa4..8d55044 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1675,6 +1675,7 @@ static void __init quirk_disable_all_msi(struct pci_dev *dev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_disable_all_msi); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS400_200, quirk_disable_all_msi); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS480, quirk_disable_all_msi); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3336, quirk_disable_all_msi); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3351, quirk_disable_all_msi); /* Disable MSI on chipsets that are known to not support it */ diff --git a/drivers/ps3/ps3-lpm.c b/drivers/ps3/ps3-lpm.c index 6c9592c..85edf94 100644 --- a/drivers/ps3/ps3-lpm.c +++ b/drivers/ps3/ps3-lpm.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index 9f04192..2d0ee60 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -3168,6 +3168,23 @@ megaraid_mbox_support_random_del(adapter_t *adapter) uint8_t raw_mbox[sizeof(mbox_t)]; int rval; + /* + * Newer firmware on Dell CERC expect a different + * random deletion handling, so disable it. + */ + if (adapter->pdev->vendor == PCI_VENDOR_ID_AMI && + adapter->pdev->device == PCI_DEVICE_ID_AMI_MEGARAID3 && + adapter->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL && + adapter->pdev->subsystem_device == PCI_SUBSYS_ID_CERC_ATA100_4CH && + (adapter->fw_version[0] > '6' || + (adapter->fw_version[0] == '6' && + adapter->fw_version[2] > '6') || + (adapter->fw_version[0] == '6' + && adapter->fw_version[2] == '6' + && adapter->fw_version[3] > '1'))) { + con_log(CL_DLEVEL1, ("megaraid: disable random deletion\n")); + return 0; + } mbox = (mbox_t *)raw_mbox; diff --git a/drivers/scsi/megaraid/megaraid_mbox.h b/drivers/scsi/megaraid/megaraid_mbox.h index 626459d..c1d86d9 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.h +++ b/drivers/scsi/megaraid/megaraid_mbox.h @@ -88,6 +88,7 @@ #define PCI_SUBSYS_ID_PERC3_QC 0x0471 #define PCI_SUBSYS_ID_PERC3_DC 0x0493 #define PCI_SUBSYS_ID_PERC3_SC 0x0475 +#define PCI_SUBSYS_ID_CERC_ATA100_4CH 0x0511 #define MBOX_MAX_SCSI_CMDS 128 // number of cmds reserved for kernel diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index dfc5418..c06d0ea 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -47,6 +47,9 @@ static const struct usb_device_id usb_quirk_list[] = { /* Edirol SD-20 */ { USB_DEVICE(0x0582, 0x0027), .driver_info = USB_QUIRK_RESET_RESUME }, + /* appletouch */ + { USB_DEVICE(0x05ac, 0x021a), .driver_info = USB_QUIRK_RESET_RESUME }, + /* M-Systems Flash Disk Pioneers */ { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME }, diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 4e065e5..fe930d5 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -621,7 +621,7 @@ static int ehci_hub_control ( } break; case USB_PORT_FEAT_C_SUSPEND: - /* we auto-clear this feature */ + clear_bit(wIndex, &ehci->port_c_suspend); break; case USB_PORT_FEAT_POWER: if (HCS_PPC (ehci->hcs_params)) @@ -700,7 +700,7 @@ static int ehci_hub_control ( /* resume completed? */ else if (time_after_eq(jiffies, ehci->reset_done[wIndex])) { - status |= 1 << USB_PORT_FEAT_C_SUSPEND; + set_bit(wIndex, &ehci->port_c_suspend); ehci->reset_done[wIndex] = 0; /* stop resume signaling */ @@ -777,6 +777,8 @@ static int ehci_hub_control ( status |= 1 << USB_PORT_FEAT_RESET; if (temp & PORT_POWER) status |= 1 << USB_PORT_FEAT_POWER; + if (test_bit(wIndex, &ehci->port_c_suspend)) + status |= 1 << USB_PORT_FEAT_C_SUSPEND; #ifndef EHCI_VERBOSE_DEBUG if (status & ~0xffff) /* only if wPortChange is interesting */ diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 888e81e..4769ba2 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -97,6 +97,8 @@ struct ehci_hcd { /* one per controller */ dedicated to the companion controller */ unsigned long owned_ports; /* which ports are owned by the companion during a bus suspend */ + unsigned long port_c_suspend; /* which ports have + the change-suspend feature turned on */ /* per-HC memory pools (could be per-bus, but ...) */ struct dma_pool *qh_pool; /* qh per active urb */ diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 53f3cf6..98f0e87 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -1208,7 +1208,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, */ media = b->media; - if (!FAT_VALID_MEDIA(media)) { + if (!fat_valid_media(media)) { if (!silent) printk(KERN_ERR "FAT: invalid media value (0x%02x)\n", media); diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index a38c718..cd931ef 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c @@ -407,22 +407,6 @@ void journal_commit_transaction(journal_t *journal) jbd_debug (3, "JBD: commit phase 2\n"); /* - * First, drop modified flag: all accesses to the buffers - * will be tracked for a new trasaction only -bzzz - */ - spin_lock(&journal->j_list_lock); - if (commit_transaction->t_buffers) { - new_jh = jh = commit_transaction->t_buffers->b_tnext; - do { - J_ASSERT_JH(new_jh, new_jh->b_modified == 1 || - new_jh->b_modified == 0); - new_jh->b_modified = 0; - new_jh = new_jh->b_tnext; - } while (new_jh != jh); - } - spin_unlock(&journal->j_list_lock); - - /* * Now start flushing things to disk, in the order they appear * on the transaction lists. Data blocks go first. */ @@ -488,6 +472,9 @@ void journal_commit_transaction(journal_t *journal) */ commit_transaction->t_state = T_COMMIT; + J_ASSERT(commit_transaction->t_nr_buffers <= + commit_transaction->t_outstanding_credits); + descriptor = NULL; bufs = 0; while (commit_transaction->t_buffers) { diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index 2c9e8f5..7665e01 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c @@ -609,6 +609,12 @@ repeat: goto done; /* + * this is the first time this transaction is touching this buffer, + * reset the modified flag + */ + jh->b_modified = 0; + + /* * If there is already a copy-out version of this buffer, then we don't * need to make another one */ @@ -820,9 +826,16 @@ int journal_get_create_access(handle_t *handle, struct buffer_head *bh) if (jh->b_transaction == NULL) { jh->b_transaction = transaction; + + /* first access by this transaction */ + jh->b_modified = 0; + JBUFFER_TRACE(jh, "file as BJ_Reserved"); __journal_file_buffer(jh, transaction, BJ_Reserved); } else if (jh->b_transaction == journal->j_committing_transaction) { + /* first access by this transaction */ + jh->b_modified = 0; + JBUFFER_TRACE(jh, "set next transaction"); jh->b_next_transaction = transaction; } @@ -1222,6 +1235,7 @@ int journal_forget (handle_t *handle, struct buffer_head *bh) struct journal_head *jh; int drop_reserve = 0; int err = 0; + int was_modified = 0; BUFFER_TRACE(bh, "entry"); @@ -1240,6 +1254,9 @@ int journal_forget (handle_t *handle, struct buffer_head *bh) goto not_jbd; } + /* keep track of wether or not this transaction modified us */ + was_modified = jh->b_modified; + /* * The buffer's going from the transaction, we must drop * all references -bzzz @@ -1257,7 +1274,12 @@ int journal_forget (handle_t *handle, struct buffer_head *bh) JBUFFER_TRACE(jh, "belongs to current transaction: unfile"); - drop_reserve = 1; + /* + * we only want to drop a reference if this transaction + * modified the buffer + */ + if (was_modified) + drop_reserve = 1; /* * We are no longer going to journal this buffer. @@ -1297,7 +1319,13 @@ int journal_forget (handle_t *handle, struct buffer_head *bh) if (jh->b_next_transaction) { J_ASSERT(jh->b_next_transaction == transaction); jh->b_next_transaction = NULL; - drop_reserve = 1; + + /* + * only drop a reference if this transaction modified + * the buffer + */ + if (was_modified) + drop_reserve = 1; } } @@ -1620,12 +1648,42 @@ out: return; } +/* + * journal_try_to_free_buffers() could race with journal_commit_transaction() + * The latter might still hold the a count on buffers when inspecting + * them on t_syncdata_list or t_locked_list. + * + * journal_try_to_free_buffers() will call this function to + * wait for the current transaction to finish syncing data buffers, before + * tryinf to free that buffer. + * + * Called with journal->j_state_lock held. + */ +static void journal_wait_for_transaction_sync_data(journal_t *journal) +{ + transaction_t *transaction = NULL; + tid_t tid; + + spin_lock(&journal->j_state_lock); + transaction = journal->j_committing_transaction; + + if (!transaction) { + spin_unlock(&journal->j_state_lock); + return; + } + + tid = transaction->t_tid; + spin_unlock(&journal->j_state_lock); + log_wait_commit(journal, tid); +} /** * int journal_try_to_free_buffers() - try to free page buffers. * @journal: journal for operation * @page: to try and free - * @unused_gfp_mask: unused + * @gfp_mask: we use the mask to detect how hard should we try to release + * buffers. If __GFP_WAIT and __GFP_FS is set, we wait for commit code to + * release the buffers. * * * For all the buffers on this page, @@ -1654,9 +1712,11 @@ out: * journal_try_to_free_buffer() is changing its state. But that * cannot happen because we never reallocate freed data as metadata * while the data is part of a transaction. Yes? + * + * Return 0 on failure, 1 on success */ int journal_try_to_free_buffers(journal_t *journal, - struct page *page, gfp_t unused_gfp_mask) + struct page *page, gfp_t gfp_mask) { struct buffer_head *head; struct buffer_head *bh; @@ -1685,7 +1745,28 @@ int journal_try_to_free_buffers(journal_t *journal, if (buffer_jbd(bh)) goto busy; } while ((bh = bh->b_this_page) != head); + ret = try_to_free_buffers(page); + + /* + * There are a number of places where journal_try_to_free_buffers() + * could race with journal_commit_transaction(), the later still + * holds the reference to the buffers to free while processing them. + * try_to_free_buffers() failed to free those buffers. Some of the + * caller of releasepage() request page buffers to be dropped, otherwise + * treat the fail-to-free as errors (such as generic_file_direct_IO()) + * + * So, if the caller of try_to_release_page() wants the synchronous + * behaviour(i.e make sure buffers are dropped upon return), + * let's wait for the current transaction to finish flush of + * dirty data buffers, then try to free those buffers again, + * with the journal locked. + */ + if (ret == 0 && (gfp_mask & __GFP_WAIT) && (gfp_mask & __GFP_FS)) { + journal_wait_for_transaction_sync_data(journal); + ret = try_to_free_buffers(page); + } + busy: return ret; } @@ -2069,7 +2150,7 @@ void __journal_refile_buffer(struct journal_head *jh) jh->b_transaction = jh->b_next_transaction; jh->b_next_transaction = NULL; __journal_file_buffer(jh, jh->b_transaction, - was_dirty ? BJ_Metadata : BJ_Reserved); + jh->b_modified ? BJ_Metadata : BJ_Reserved); J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING); if (was_dirty) diff --git a/fs/namei.c b/fs/namei.c index 8cf9bb9..a6fdd95 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -514,7 +514,14 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, s */ result = d_lookup(parent, name); if (!result) { - struct dentry * dentry = d_alloc(parent, name); + struct dentry *dentry; + + /* Don't create child dentry for a dead directory. */ + result = ERR_PTR(-ENOENT); + if (IS_DEADDIR(dir)) + goto out_unlock; + + dentry = d_alloc(parent, name); result = ERR_PTR(-ENOMEM); if (dentry) { result = dir->i_op->lookup(dir, dentry, nd); @@ -523,6 +530,7 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, s else result = dentry; } +out_unlock: mutex_unlock(&dir->i_mutex); return result; } @@ -1313,7 +1321,14 @@ static struct dentry *__lookup_hash(struct qstr *name, dentry = cached_lookup(base, name, nd); if (!dentry) { - struct dentry *new = d_alloc(base, name); + struct dentry *new; + + /* Don't create child dentry for a dead directory. */ + dentry = ERR_PTR(-ENOENT); + if (IS_DEADDIR(inode)) + goto out; + + new = d_alloc(base, name); dentry = ERR_PTR(-ENOMEM); if (!new) goto out; @@ -1904,18 +1919,22 @@ struct dentry *lookup_create(struct nameidata *nd, int is_dir) if (IS_ERR(dentry)) goto fail; + if (dentry->d_inode) + goto eexist; /* * Special case - lookup gave negative, but... we had foo/bar/ * From the vfs_mknod() POV we just have a negative dentry - * all is fine. Let's be bastards - you had / on the end, you've * been asking for (non-existent) directory. -ENOENT for you. */ - if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode) - goto enoent; + if (unlikely(!is_dir && nd->last.name[nd->last.len])) { + dput(dentry); + dentry = ERR_PTR(-ENOENT); + } return dentry; -enoent: +eexist: dput(dentry); - dentry = ERR_PTR(-ENOENT); + dentry = ERR_PTR(-EEXIST); fail: return dentry; } diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 6f88d7c..f83fb73 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -57,8 +57,6 @@ static int enable_ino64 = NFS_64_BIT_INODE_NUMBERS_ENABLED; static void nfs_invalidate_inode(struct inode *); static int nfs_update_inode(struct inode *, struct nfs_fattr *); -static void nfs_zap_acl_cache(struct inode *); - static struct kmem_cache * nfs_inode_cachep; static inline unsigned long @@ -167,7 +165,7 @@ void nfs_zap_mapping(struct inode *inode, struct address_space *mapping) } } -static void nfs_zap_acl_cache(struct inode *inode) +void nfs_zap_acl_cache(struct inode *inode) { void (*clear_acl_cache)(struct inode *); diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 9319927..4c62be1 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -153,6 +153,7 @@ extern void nfs_clear_inode(struct inode *); #ifdef CONFIG_NFS_V4 extern void nfs4_clear_inode(struct inode *); #endif +void nfs_zap_acl_cache(struct inode *inode); /* super.c */ extern struct file_system_type nfs_xdev_fs_type; diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index 9b73625..423842f 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c @@ -5,6 +5,8 @@ #include #include +#include "internal.h" + #define NFSDBG_FACILITY NFSDBG_PROC ssize_t nfs3_listxattr(struct dentry *dentry, char *buffer, size_t size) @@ -205,6 +207,8 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) status = nfs_revalidate_inode(server, inode); if (status < 0) return ERR_PTR(status); + if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL) + nfs_zap_acl_cache(inode); acl = nfs3_get_cached_acl(inode, type); if (acl != ERR_PTR(-EAGAIN)) return acl; @@ -319,9 +323,8 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, dprintk("NFS call setacl\n"); msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_SETACL]; status = rpc_call_sync(server->client_acl, &msg, 0); - spin_lock(&inode->i_lock); - NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ACCESS; - spin_unlock(&inode->i_lock); + nfs_access_zap_cache(inode); + nfs_zap_acl_cache(inode); dprintk("NFS reply setacl: %d\n", status); /* pages may have been allocated at the xdr layer. */ diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 7ce0786..3a2ff77 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -52,6 +52,7 @@ #include "nfs4_fs.h" #include "delegation.h" #include "iostat.h" +#include "internal.h" #define NFSDBG_FACILITY NFSDBG_PROC @@ -2707,6 +2708,8 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) ret = nfs_revalidate_inode(server, inode); if (ret < 0) return ret; + if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL) + nfs_zap_acl_cache(inode); ret = nfs4_read_cached_acl(inode, buf, buflen); if (ret != -ENOENT) return ret; @@ -2734,7 +2737,8 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl nfs_inode_return_delegation(inode); buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); - nfs_zap_caches(inode); + nfs_access_zap_cache(inode); + nfs_zap_acl_cache(inode); return ret; } diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c index 5567ec0..7965118 100644 --- a/fs/partitions/msdos.c +++ b/fs/partitions/msdos.c @@ -18,7 +18,7 @@ * * Re-organised Feb 1998 Russell King */ - +#include #include "check.h" #include "msdos.h" @@ -419,6 +419,7 @@ int msdos_partition(struct parsed_partitions *state, struct block_device *bdev) Sector sect; unsigned char *data; struct partition *p; + struct fat_boot_sector *fb; int slot; data = read_dev_sector(bdev, 0, §); @@ -444,8 +445,21 @@ int msdos_partition(struct parsed_partitions *state, struct block_device *bdev) p = (struct partition *) (data + 0x1be); for (slot = 1; slot <= 4; slot++, p++) { if (p->boot_ind != 0 && p->boot_ind != 0x80) { - put_dev_sector(sect); - return 0; + /* + * Even without a valid boot inidicator value + * its still possible this is valid FAT filesystem + * without a partition table. + */ + fb = (struct fat_boot_sector *) data; + if (slot == 1 && fb->reserved && fb->fats + && fat_valid_media(fb->media)) { + printk("\n"); + put_dev_sector(sect); + return 1; + } else { + put_dev_sector(sect); + return 0; + } } } diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c index 3f13d49..35e5c6e 100644 --- a/fs/romfs/inode.c +++ b/fs/romfs/inode.c @@ -418,7 +418,8 @@ static int romfs_readpage(struct file *file, struct page * page) { struct inode *inode = page->mapping->host; - loff_t offset, avail, readlen; + loff_t offset, size; + unsigned long filled; void *buf; int result = -EIO; @@ -430,21 +431,29 @@ romfs_readpage(struct file *file, struct page * page) /* 32 bit warning -- but not for us :) */ offset = page_offset(page); - if (offset < i_size_read(inode)) { - avail = inode->i_size-offset; - readlen = min_t(unsigned long, avail, PAGE_SIZE); - if (romfs_copyfrom(inode, buf, ROMFS_I(inode)->i_dataoffset+offset, readlen) == readlen) { - if (readlen < PAGE_SIZE) { - memset(buf + readlen,0,PAGE_SIZE-readlen); - } - SetPageUptodate(page); - result = 0; + size = i_size_read(inode); + filled = 0; + result = 0; + if (offset < size) { + unsigned long readlen; + + size -= offset; + readlen = size > PAGE_SIZE ? PAGE_SIZE : size; + + filled = romfs_copyfrom(inode, buf, ROMFS_I(inode)->i_dataoffset+offset, readlen); + + if (filled != readlen) { + SetPageError(page); + filled = 0; + result = -EIO; } } - if (result) { - memset(buf, 0, PAGE_SIZE); - SetPageError(page); - } + + if (filled < PAGE_SIZE) + memset(buf + filled, 0, PAGE_SIZE-filled); + + if (!result) + SetPageUptodate(page); flush_dcache_page(page); unlock_page(page); diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h index f950921..20277ad 100644 --- a/include/linux/msdos_fs.h +++ b/include/linux/msdos_fs.h @@ -58,7 +58,11 @@ #define MSDOS_DOTDOT ".. " /* "..", padded to MSDOS_NAME chars */ /* media of boot sector */ -#define FAT_VALID_MEDIA(x) ((0xF8 <= (x) && (x) <= 0xFF) || (x) == 0xF0) +static inline int fat_valid_media(u8 media) +{ + return 0xf8 <= media || media == 0xf0; +} + #define FAT_FIRST_ENT(s, x) ((MSDOS_SB(s)->fat_bits == 32 ? 0x0FFFFF00 : \ MSDOS_SB(s)->fat_bits == 16 ? 0xFF00 : 0xF00) | (x)) diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h index 0148058..771e4b3 100644 --- a/include/sound/ac97_codec.h +++ b/include/sound/ac97_codec.h @@ -504,6 +504,7 @@ struct snd_ac97 { unsigned short pcmreg[3]; // PCM registers unsigned short codec_cfg[3]; // CODEC_CFG bits unsigned char swap_mic_linein; // AD1986/AD1986A only + unsigned char lo_as_master; /* LO as master */ } ad18xx; unsigned int dev_flags; /* device specific */ } spec; diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 7b7b9b1..10ee28e 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1670,6 +1670,7 @@ struct snd_emu_chip_details { unsigned char spi_dac; /* SPI interface for DAC */ unsigned char i2c_adc; /* I2C interface for ADC */ unsigned char adc_1361t; /* Use Philips 1361T ADC */ + unsigned char invert_shared_spdif; /* analog/digital switch inverted */ const char *driver; const char *name; const char *id; /* for backward compatibility - can be NULL if not needed */ diff --git a/mm/filemap.c b/mm/filemap.c index 703f2c8..d721ad5 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2574,9 +2574,8 @@ out: * Otherwise return zero. * * The @gfp_mask argument specifies whether I/O may be performed to release - * this page (__GFP_IO), and whether the call may block (__GFP_WAIT). + * this page (__GFP_IO), and whether the call may block (__GFP_WAIT & __GFP_FS). * - * NOTE: @gfp_mask may go away, and this function may become non-blocking. */ int try_to_release_page(struct page *page, gfp_t gfp_mask) { diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index 347e935..2f0ffc3 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -507,6 +507,11 @@ static int bnep_session(void *arg) /* Delete network device */ unregister_netdev(dev); + /* Wakeup user-space polling for socket errors */ + s->sock->sk->sk_err = EUNATCH; + + wake_up_interruptible(s->sock->sk->sk_sleep); + /* Release the socket */ fput(s->sock->file); diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 519cdb9..96434d7 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -581,6 +581,12 @@ static int hidp_session(void *arg) hid_free_device(session->hid); } + /* Wakeup user-space polling for socket errors */ + session->intr_sock->sk->sk_err = EUNATCH; + session->ctrl_sock->sk->sk_err = EUNATCH; + + hidp_schedule(session); + fput(session->intr_sock->file); wait_event_timeout(*(ctrl_sk->sk_sleep), @@ -879,6 +885,10 @@ int hidp_del_connection(struct hidp_conndel_req *req) skb_queue_purge(&session->ctrl_transmit); skb_queue_purge(&session->intr_transmit); + /* Wakeup user-space polling for socket errors */ + session->intr_sock->sk->sk_err = EUNATCH; + session->ctrl_sock->sk->sk_err = EUNATCH; + /* Kill session thread */ atomic_inc(&session->terminate); hidp_schedule(session); diff --git a/sound/core/init.c b/sound/core/init.c index e3338d6..6200f42 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -311,6 +311,9 @@ int snd_card_disconnect(struct snd_card *card) struct file *file; int err; + if (!card) + return -EINVAL; + spin_lock(&card->files_lock); if (card->shutdown) { spin_unlock(&card->files_lock); @@ -322,6 +325,7 @@ int snd_card_disconnect(struct snd_card *card) /* phase 1: disable fops (user space) operations for ALSA API */ mutex_lock(&snd_card_mutex); snd_cards[card->number] = NULL; + snd_cards_lock &= ~(1 << card->number); mutex_unlock(&snd_card_mutex); /* phase 2: replace file->f_op with special dummy operations */ @@ -360,6 +364,15 @@ int snd_card_disconnect(struct snd_card *card) snd_printk(KERN_ERR "not all devices for card %i can be disconnected\n", card->number); snd_info_card_disconnect(card); +#ifndef CONFIG_SYSFS_DEPRECATED + if (card->card_dev) { + device_unregister(card->card_dev); + card->card_dev = NULL; + } +#endif +#ifdef CONFIG_PM + wake_up(&card->power_sleep); +#endif return 0; } @@ -401,33 +414,14 @@ static int snd_card_do_free(struct snd_card *card) snd_printk(KERN_WARNING "unable to free card info\n"); /* Not fatal error */ } -#ifndef CONFIG_SYSFS_DEPRECATED - if (card->card_dev) - device_unregister(card->card_dev); -#endif kfree(card); return 0; } -static int snd_card_free_prepare(struct snd_card *card) -{ - if (card == NULL) - return -EINVAL; - (void) snd_card_disconnect(card); - mutex_lock(&snd_card_mutex); - snd_cards[card->number] = NULL; - snd_cards_lock &= ~(1 << card->number); - mutex_unlock(&snd_card_mutex); -#ifdef CONFIG_PM - wake_up(&card->power_sleep); -#endif - return 0; -} - int snd_card_free_when_closed(struct snd_card *card) { int free_now = 0; - int ret = snd_card_free_prepare(card); + int ret = snd_card_disconnect(card); if (ret) return ret; @@ -447,7 +441,7 @@ EXPORT_SYMBOL(snd_card_free_when_closed); int snd_card_free(struct snd_card *card) { - int ret = snd_card_free_prepare(card); + int ret = snd_card_disconnect(card); if (ret) return ret; diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 75daed2..581aa2c 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -1257,6 +1257,8 @@ static void snd_mixer_oss_build(struct snd_mixer_oss *mixer) { SOUND_MIXER_DIGITAL3, "Digital", 2 }, { SOUND_MIXER_PHONEIN, "Phone", 0 }, { SOUND_MIXER_PHONEOUT, "Master Mono", 0 }, + { SOUND_MIXER_PHONEOUT, "Speaker", 0 }, /*fallback*/ + { SOUND_MIXER_PHONEOUT, "Mono", 0 }, /*fallback*/ { SOUND_MIXER_PHONEOUT, "Phone", 0 }, /* fallback */ { SOUND_MIXER_VIDEO, "Video", 0 }, { SOUND_MIXER_RADIO, "Radio", 0 }, diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c index ab570a0..2490259 100644 --- a/sound/core/seq/oss/seq_oss_synth.c +++ b/sound/core/seq/oss/seq_oss_synth.c @@ -599,6 +599,9 @@ snd_seq_oss_synth_make_info(struct seq_oss_devinfo *dp, int dev, struct synth_in { struct seq_oss_synth *rec; + if (dev < 0 || dev >= dp->max_synthdev) + return -ENXIO; + if (dp->synths[dev].is_midi) { struct midi_info minf; snd_seq_oss_midi_make_info(dp, dp->synths[dev].midi_mapped, &minf); diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 50c637e..3d70241 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -1960,6 +1960,9 @@ static int snd_ac97_ad1888_lohpsel_get(struct snd_kcontrol *kcontrol, struct snd val = ac97->regs[AC97_AD_MISC]; ucontrol->value.integer.value[0] = !(val & AC97_AD198X_LOSEL); + if (ac97->spec.ad18xx.lo_as_master) + ucontrol->value.integer.value[0] = + !ucontrol->value.integer.value[0]; return 0; } @@ -1968,8 +1971,10 @@ static int snd_ac97_ad1888_lohpsel_put(struct snd_kcontrol *kcontrol, struct snd struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); unsigned short val; - val = !ucontrol->value.integer.value[0] - ? (AC97_AD198X_LOSEL | AC97_AD198X_HPSEL) : 0; + val = !ucontrol->value.integer.value[0]; + if (ac97->spec.ad18xx.lo_as_master) + val = !val; + val = val ? (AC97_AD198X_LOSEL | AC97_AD198X_HPSEL) : 0; return snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD198X_LOSEL | AC97_AD198X_HPSEL, val); } @@ -2020,7 +2025,7 @@ static void ad1888_update_jacks(struct snd_ac97 *ac97) { unsigned short val = 0; /* clear LODIS if shared jack is to be used for Surround out */ - if (is_shared_linein(ac97)) + if (!ac97->spec.ad18xx.lo_as_master && is_shared_linein(ac97)) val |= (1 << 12); /* clear CLDIS if shared jack is to be used for C/LFE out */ if (is_shared_micin(ac97)) @@ -2056,9 +2061,13 @@ static const struct snd_kcontrol_new snd_ac97_ad1888_controls[] = { static int patch_ad1888_specific(struct snd_ac97 *ac97) { - /* rename 0x04 as "Master" and 0x02 as "Master Surround" */ - snd_ac97_rename_vol_ctl(ac97, "Master Playback", "Master Surround Playback"); - snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Master Playback"); + if (!ac97->spec.ad18xx.lo_as_master) { + /* rename 0x04 as "Master" and 0x02 as "Master Surround" */ + snd_ac97_rename_vol_ctl(ac97, "Master Playback", + "Master Surround Playback"); + snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", + "Master Playback"); + } return patch_build_controls(ac97, snd_ac97_ad1888_controls, ARRAY_SIZE(snd_ac97_ad1888_controls)); } @@ -2077,16 +2086,27 @@ static int patch_ad1888(struct snd_ac97 * ac97) patch_ad1881(ac97); ac97->build_ops = &patch_ad1888_build_ops; - /* Switch FRONT/SURROUND LINE-OUT/HP-OUT default connection */ - /* it seems that most vendors connect line-out connector to headphone out of AC'97 */ + + /* + * LO can be used as a real line-out on some devices, + * and we need to revert the front/surround mixer switches + */ + if (ac97->subsystem_vendor == 0x1043 && + ac97->subsystem_device == 0x1193) /* ASUS A9T laptop */ + ac97->spec.ad18xx.lo_as_master = 1; + + misc = snd_ac97_read(ac97, AC97_AD_MISC); /* AD-compatible mode */ /* Stereo mutes enabled */ - misc = snd_ac97_read(ac97, AC97_AD_MISC); - snd_ac97_write_cache(ac97, AC97_AD_MISC, misc | - AC97_AD198X_LOSEL | - AC97_AD198X_HPSEL | - AC97_AD198X_MSPLT | - AC97_AD198X_AC97NC); + misc |= AC97_AD198X_MSPLT | AC97_AD198X_AC97NC; + if (!ac97->spec.ad18xx.lo_as_master) + /* Switch FRONT/SURROUND LINE-OUT/HP-OUT default connection */ + /* it seems that most vendors connect line-out connector to + * headphone out of AC'97 + */ + misc |= AC97_AD198X_LOSEL | AC97_AD198X_HPSEL; + + snd_ac97_write_cache(ac97, AC97_AD_MISC, misc); ac97->flags |= AC97_STEREO_MUTES; return 0; } diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index d0330d8..df278ba 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -1527,6 +1527,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { .ca0151_chip = 1, .spk71 = 1, .spdif_bug = 1, + .invert_shared_spdif = 1, /* digital/analog switch swapped */ .adc_1361t = 1, /* 24 bit capture instead of 16bit. Fixes ALSA bug#324 */ .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .revision = 0x04, diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index fd22120..9f77692 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -1578,6 +1578,10 @@ static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0; else ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0; + if (emu->card_capabilities->invert_shared_spdif) + ucontrol->value.integer.value[0] = + !ucontrol->value.integer.value[0]; + return 0; } @@ -1586,15 +1590,18 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, { unsigned long flags; struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); - unsigned int reg, val; + unsigned int reg, val, sw; int change = 0; + sw = ucontrol->value.integer.value[0]; + if (emu->card_capabilities->invert_shared_spdif) + sw = !sw; spin_lock_irqsave(&emu->reg_lock, flags); if ( emu->card_capabilities->i2c_adc) { /* Do nothing for Audigy 2 ZS Notebook */ } else if (emu->audigy) { reg = inl(emu->port + A_IOCFG); - val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0; + val = sw ? A_IOCFG_GPOUT0 : 0; change = (reg & A_IOCFG_GPOUT0) != val; if (change) { reg &= ~A_IOCFG_GPOUT0; @@ -1603,7 +1610,7 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, } } reg = inl(emu->port + HCFG); - val = ucontrol->value.integer.value[0] ? HCFG_GPOUT0 : 0; + val = sw ? HCFG_GPOUT0 : 0; change |= (reg & HCFG_GPOUT0) != val; if (change) { reg &= ~HCFG_GPOUT0; diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index c864928..d7cba53 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -1563,6 +1563,7 @@ static const char *ad1981_models[AD1981_MODELS] = { static struct snd_pci_quirk ad1981_cfg_tbl[] = { SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD), + SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD), /* All HP models */ SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP), SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA), @@ -2557,7 +2558,7 @@ static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, { struct ad198x_spec *spec = codec->spec; hda_nid_t nid; - int idx, err; + int i, idx, err; char name[32]; if (! pin) @@ -2565,16 +2566,26 @@ static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, idx = ad1988_pin_idx(pin); nid = ad1988_idx_to_dac(codec, idx); - /* specify the DAC as the extra output */ - if (! spec->multiout.hp_nid) - spec->multiout.hp_nid = nid; - else - spec->multiout.extra_out_nid[0] = nid; - /* control HP volume/switch on the output mixer amp */ - sprintf(name, "%s Playback Volume", pfx); - if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) - return err; + /* check whether the corresponding DAC was already taken */ + for (i = 0; i < spec->autocfg.line_outs; i++) { + hda_nid_t pin = spec->autocfg.line_out_pins[i]; + hda_nid_t dac = ad1988_idx_to_dac(codec, ad1988_pin_idx(pin)); + if (dac == nid) + break; + } + if (i >= spec->autocfg.line_outs) { + /* specify the DAC as the extra output */ + if (!spec->multiout.hp_nid) + spec->multiout.hp_nid = nid; + else + spec->multiout.extra_out_nid[0] = nid; + /* control HP volume/switch on the output mixer amp */ + sprintf(name, "%s Playback Volume", pfx); + err = add_control(spec, AD_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + } nid = ad1988_mixer_nids[idx]; sprintf(name, "%s Playback Switch", pfx); if ((err = add_control(spec, AD_CTL_BIND_MUTE, name, diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index f48838a..d0bc988 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -1762,8 +1762,10 @@ static int check_hw_params_convention(struct snd_usb_substream *subs) channels = kcalloc(MAX_MASK, sizeof(u32), GFP_KERNEL); rates = kcalloc(MAX_MASK, sizeof(u32), GFP_KERNEL); - if (!channels || !rates) + if (!channels || !rates) { + err = -ENOMEM; goto __out; + } list_for_each(p, &subs->fmt_list) { struct audioformat *f; @@ -1916,7 +1918,10 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre 1000 * MIN_PACKS_URB, /*(nrpacks * MAX_URBS) * 1000*/ UINT_MAX); - if (check_hw_params_convention(subs)) { + err = check_hw_params_convention(subs); + if (err < 0) + return err; + else if (err) { hwc_debug("setting extra hw constraints...\n"); if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, hw_rule_rate, subs, @@ -2463,11 +2468,12 @@ static int parse_audio_format_i_type(struct snd_usb_audio *chip, struct audiofor } break; case USB_AUDIO_FORMAT_PCM8: - /* Dallas DS4201 workaround */ + pcm_format = SNDRV_PCM_FORMAT_U8; + + /* Dallas DS4201 workaround: it advertises U8 format, but really + supports S8. */ if (chip->usb_id == USB_ID(0x04fa, 0x4201)) pcm_format = SNDRV_PCM_FORMAT_S8; - else - pcm_format = SNDRV_PCM_FORMAT_U8; break; case USB_AUDIO_FORMAT_IEEE_FLOAT: pcm_format = SNDRV_PCM_FORMAT_FLOAT_LE; @@ -2671,12 +2677,23 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) int format; struct audioformat *fp; unsigned char *fmt, *csep; + int num; dev = chip->dev; /* parse the interface's altsettings */ iface = usb_ifnum_to_if(dev, iface_no); - for (i = 0; i < iface->num_altsetting; i++) { + + num = iface->num_altsetting; + + /* + * Dallas DS4201 workaround: It presents 5 altsettings, but the last + * one misses syncpipe, and does not produce any sound. + */ + if (chip->usb_id == USB_ID(0x04fa, 0x4201)) + num = 4; + + for (i = 0; i < num; i++) { alts = &iface->altsetting[i]; altsd = get_iface_desc(alts); /* skip invalid one */ @@ -3406,7 +3423,6 @@ static void snd_usb_audio_create_proc(struct snd_usb_audio *chip) static int snd_usb_audio_free(struct snd_usb_audio *chip) { - usb_chip[chip->index] = NULL; kfree(chip); return 0; } @@ -3600,8 +3616,8 @@ static void *snd_usb_audio_probe(struct usb_device *dev, snd_card_set_dev(chip->card, &intf->dev); break; } - if (! chip) { - snd_printk(KERN_ERR "no available usb audio device\n"); + if (!chip) { + printk(KERN_ERR "no available usb audio device\n"); goto __error; } } @@ -3671,6 +3687,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr) list_for_each(p, &chip->mixer_list) { snd_usb_mixer_disconnect(p); } + usb_chip[chip->index] = NULL; mutex_unlock(®ister_mutex); snd_card_free_when_closed(card); } else { diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index 938dff5..82a8d14 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -39,6 +39,30 @@ .idProduct = prod, \ .bInterfaceClass = USB_CLASS_VENDOR_SPEC +/* Creative/E-Mu devices */ +{ + USB_DEVICE(0x041e, 0x3010), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "Creative Labs", + .product_name = "Sound Blaster MP3+", + .ifnum = QUIRK_NO_INTERFACE + } +}, +{ + /* E-Mu 0202 USB */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x041e, + .idProduct = 0x3f02, + .bInterfaceClass = USB_CLASS_AUDIO, +}, +{ + /* E-Mu 0404 USB */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x041e, + .idProduct = 0x3f04, + .bInterfaceClass = USB_CLASS_AUDIO, +}, + /* * Logitech QuickCam: bDeviceClass is vendor-specific, so generic interface * class matches do not take effect without an explicit ID match. @@ -97,19 +121,7 @@ .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL }, -/* E-Mu devices */ -{ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x041e, - .idProduct = 0x3f02, - .bInterfaceClass = USB_CLASS_AUDIO, -}, -{ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x041e, - .idProduct = 0x3f04, - .bInterfaceClass = USB_CLASS_AUDIO, -}, + /* * Yamaha devices */ @@ -1165,19 +1177,6 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, -{ - USB_DEVICE(0x582, 0x00a6), - .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { - .vendor_name = "Roland", - .product_name = "Juno-G", - .ifnum = 0, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const struct snd_usb_midi_endpoint_info) { - .out_cables = 0x0001, - .in_cables = 0x0001 - } - } -}, { /* * This quirk is for the "Advanced" modes of the Edirol UA-25. * If the switch is not in an advanced setting, the UA-25 has @@ -1336,6 +1335,19 @@ YAMAHA_DEVICE(0x7010, "UB99"), }, /* TODO: add Edirol MD-P1 support */ { + USB_DEVICE(0x582, 0x00a6), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "Roland", + .product_name = "Juno-G", + .ifnum = 0, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const struct snd_usb_midi_endpoint_info) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + } +}, +{ /* Roland SH-201 */ USB_DEVICE(0x0582, 0x00ad), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { @@ -1719,17 +1731,6 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, -{ - /* Creative Sound Blaster MP3+ */ - USB_DEVICE(0x041e, 0x3010), - .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { - .vendor_name = "Creative Labs", - .product_name = "Sound Blaster MP3+", - .ifnum = QUIRK_NO_INTERFACE - } - -}, - /* Emagic devices */ { USB_DEVICE(0x086a, 0x0001),