Как обычно - ничего сверхестественного, только исправление обнаруженных ошибок. Особо выделяется, разве что, только серия патчей для архитектуры x86_64. Также Крис Райт (Chris Wright) сообщил об обновлении git-ветки 2.6.11.y, теперь ее можно обнаружить здесь: rsync://rsync.kernel.org/pub/scm/linux/kernel/git/gregkh/linux-2.6.11.y.git и/или просмотреть через веб-интерфейс.
Патч Linux 2.6.11 -> 2.6.11.11 (21 КБ). Патч относительно 2.6.11.10 следует далее вместе с описанием изменений.
Изменения:
[html]----------
Makefile | 2 -
arch/ppc64/kernel/pSeries_iommu.c | 55 +++++++++++++++++++++++++++++++
arch/x86_64/kernel/ptrace.c | 13 +++++--
arch/x86_64/mm/fault.c | 11 +++++-
arch/x86_64/mm/ioremap.c | 2 -
drivers/ide/ide-disk.c | 4 +-
drivers/net/3c59x.c | 9 +++--
drivers/usb/serial/visor.c | 38 +++++++++++++++------
drivers/video/matrox/matroxfb_accel.c | 14 ++++++--
drivers/video/matrox/matroxfb_base.h | 4 +-
fs/ext3/balloc.c | 3 +
include/asm-x86_64/processor.h | 4 +-
include/linux/err.h | 4 +-
mm/mmap.c | 59 +++++++++++++++++-----------------
net/bridge/netfilter/ebtables.c | 3 +
net/rose/rose_route.c | 3 +
sound/usb/usbaudio.c | 2 -
sound/usb/usx2y/usbusx2y.c | 11 ++++--
18 files changed, 173 insertions(+), 68 deletions(-)
Summary of changes from v2.6.11.10 to v2.6.11.11
==============================================
Andi Kleen:
o x86_64: Don't look up struct page pointer of physical address in iounmap
o x86_64: When checking vmalloc mappings don't use pte_page
o x86_64: Add a guard page at the end of the 47bit address space
o x86_64: Fix canonical checking for segment registers in ptrace
o x86_64: check if ptrace RIP is canonical
Bart De Schuymer:
o Fix smp race
Bartlomiej Zolnierkiewicz:
o ide-disk: Fix LBA8 DMA
Chris Wright:
o Linux 2.6.11.11
Daniel Ritz:
o 3c59x: only put the device into D3 when we're actually using WOL
Greg Kroah-Hartman:
o USB: fix bug in visor driver with throttle/unthrottle causing oopses
Gregor Jasny:
o usbusx2y: prevent oops & dead keyboard on usb unplugging while the device is being used
o usbaudio: prevent oops & dead keyboard on usb unplugging while the device is being used
Linus Torvalds:
o Fix get_unmapped_area sanity tests
Mingming Cao:
o ext3: fix race between ext3 make block reservation and reservation window discard
Olof Johansson:
o PPC64: Fix LPAR IOMMU setup code for p630
Petr Vandrovec:
o Fix matroxfb on big-endian hardware
Ralf Bächle:
o Fix minor security hole[/html]
Патч относительно 2.6.11.10:
[html]diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 11
-EXTRAVERSION = .10
+EXTRAVERSION = .11
NAME=Woozy Beaver
# *DOCUMENTATION*
diff --git a/arch/ppc64/kernel/pSeries_iommu.c b/arch/ppc64/kernel/pSeries_iommu.c
--- a/arch/ppc64/kernel/pSeries_iommu.c
+++ b/arch/ppc64/kernel/pSeries_iommu.c
@@ -401,6 +401,8 @@ static void iommu_bus_setup_pSeriesLP(st
struct device_node *dn, *pdn;
unsigned int *dma_window = NULL;
+ DBG("iommu_bus_setup_pSeriesLP, bus %p, bus->self %p\n", bus, bus->self);
+
dn = pci_bus_to_OF_node(bus);
/* Find nearest ibm,dma-window, walking up the device tree */
@@ -455,6 +457,56 @@ static void iommu_dev_setup_pSeries(stru
}
}
+static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev)
+{
+ struct device_node *pdn, *dn;
+ struct iommu_table *tbl;
+ int *dma_window = NULL;
+
+ DBG("iommu_dev_setup_pSeriesLP, dev %p (%s)\n", dev, dev->pretty_name);
+
+ /* dev setup for LPAR is a little tricky, since the device tree might
+ * contain the dma-window properties per-device and not neccesarily
+ * for the bus. So we need to search upwards in the tree until we
+ * either hit a dma-window property, OR find a parent with a table
+ * already allocated.
+ */
+ dn = pci_device_to_OF_node(dev);
+
+ for (pdn = dn; pdn && !pdn->iommu_table; pdn = pdn->parent) {
+ dma_window = (unsigned int *)get_property(pdn, "ibm,dma-window", NULL);
+ if (dma_window)
+ break;
+ }
+
+ /* Check for parent == NULL so we don't try to setup the empty EADS
+ * slots on POWER4 machines.
+ */
+ if (dma_window == NULL || pdn->parent == NULL) {
+ /* Fall back to regular (non-LPAR) dev setup */
+ DBG("No dma window for device, falling back to regular setup\n");
+ iommu_dev_setup_pSeries(dev);
+ return;
+ } else {
+ DBG("Found DMA window, allocating table\n");
+ }
+
+ if (!pdn->iommu_table) {
+ /* iommu_table_setparms_lpar needs bussubno. */
+ pdn->bussubno = pdn->phb->bus->number;
+
+ tbl = (struct iommu_table *)kmalloc(sizeof(struct iommu_table),
+ GFP_KERNEL);
+
+ iommu_table_setparms_lpar(pdn->phb, pdn, tbl, dma_window);
+
+ pdn->iommu_table = iommu_init_table(tbl);
+ }
+
+ if (pdn != dn)
+ dn->iommu_table = pdn->iommu_table;
+}
+
static void iommu_bus_setup_null(struct pci_bus *b) { }
static void iommu_dev_setup_null(struct pci_dev *d) { }
@@ -479,13 +531,14 @@ void iommu_init_early_pSeries(void)
ppc_md.tce_free = tce_free_pSeriesLP;
}
ppc_md.iommu_bus_setup = iommu_bus_setup_pSeriesLP;
+ ppc_md.iommu_dev_setup = iommu_dev_setup_pSeriesLP;
} else {
ppc_md.tce_build = tce_build_pSeries;
ppc_md.tce_free = tce_free_pSeries;
ppc_md.iommu_bus_setup = iommu_bus_setup_pSeries;
+ ppc_md.iommu_dev_setup = iommu_dev_setup_pSeries;
}
- ppc_md.iommu_dev_setup = iommu_dev_setup_pSeries;
pci_iommu_init();
}
diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c
--- a/arch/x86_64/kernel/ptrace.c
+++ b/arch/x86_64/kernel/ptrace.c
@@ -129,13 +129,13 @@ static int putreg(struct task_struct *ch
value &= 0xffff;
return 0;
case offsetof(struct user_regs_struct,fs_base):
- if (!((value >> 48) == 0 || (value >> 48) == 0xffff))
- return -EIO;
+ if (value >= TASK_SIZE)
+ return -EIO;
child->thread.fs = value;
return 0;
case offsetof(struct user_regs_struct,gs_base):
- if (!((value >> 48) == 0 || (value >> 48) == 0xffff))
- return -EIO;
+ if (value >= TASK_SIZE)
+ return -EIO;
child->thread.gs = value;
return 0;
case offsetof(struct user_regs_struct, eflags):
@@ -149,6 +149,11 @@ static int putreg(struct task_struct *ch
return -EIO;
value &= 0xffff;
break;
+ case offsetof(struct user_regs_struct, rip):
+ /* Check if the new RIP address is canonical */
+ if (value >= TASK_SIZE)
+ return -EIO;
+ break;
}
put_stack_long(child, regno - sizeof(struct pt_regs), value);
return 0;
diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c
--- a/arch/x86_64/mm/fault.c
+++ b/arch/x86_64/mm/fault.c
@@ -236,6 +236,8 @@ static noinline void pgtable_bad(unsigne
/*
* Handle a fault on the vmalloc or module mapping area
+ *
+ * This assumes no large pages in there.
*/
static int vmalloc_fault(unsigned long address)
{
@@ -274,7 +276,10 @@ static int vmalloc_fault(unsigned long a
if (!pte_present(*pte_ref))
return -1;
pte = pte_offset_kernel(pmd, address);
- if (!pte_present(*pte) || pte_page(*pte) != pte_page(*pte_ref))
+ /* Don't use pte_page here, because the mappings can point
+ outside mem_map, and the NUMA hash lookup cannot handle
+ that. */
+ if (!pte_present(*pte) || pte_pfn(*pte) != pte_pfn(*pte_ref))
BUG();
__flush_tlb_all();
return 0;
@@ -348,7 +353,9 @@ asmlinkage void do_page_fault(struct pt_
* protection error (error_code & 1) == 0.
*/
if (unlikely(address >= TASK_SIZE)) {
- if (!(error_code & 5)) {
+ if (!(error_code & 5) &&
+ ((address >= VMALLOC_START && address < VMALLOC_END) ||
+ (address >= MODULES_VADDR && address < MODULES_END))) {
if (vmalloc_fault(address) < 0)
goto bad_area_nosemaphore;
return;
diff --git a/arch/x86_64/mm/ioremap.c b/arch/x86_64/mm/ioremap.c
--- a/arch/x86_64/mm/ioremap.c
+++ b/arch/x86_64/mm/ioremap.c
@@ -266,7 +266,7 @@ void iounmap(volatile void __iomem *addr
if ((p->flags >> 20) &&
p->phys_addr + p->size - 1 < virt_to_phys(high_memory)) {
/* p->size includes the guard page, but cpa doesn't like that */
- change_page_attr(virt_to_page(__va(p->phys_addr)),
+ change_page_attr_addr((unsigned long)(__va(p->phys_addr)),
(p->size - PAGE_SIZE) >> PAGE_SHIFT,
PAGE_KERNEL);
global_flush_tlb();
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -133,6 +133,8 @@ static ide_startstop_t __ide_do_rw_disk(
if (hwif->no_lba48_dma && lba48 && dma) {
if (block + rq->nr_sectors > 1ULL << 28)
dma = 0;
+ else
+ lba48 = 0;
}
if (!dma) {
@@ -146,7 +148,7 @@ static ide_startstop_t __ide_do_rw_disk(
/* FIXME: SELECT_MASK(drive, 0) ? */
if (drive->select.b.lba) {
- if (drive->addressing == 1) {
+ if (lba48) {
task_ioreg_t tasklets[10];
pr_debug("%s: LBA=0x%012llx\n", drive->name, block);
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -1581,7 +1581,8 @@ vortex_up(struct net_device *dev)
if (VORTEX_PCI(vp)) {
pci_set_power_state(VORTEX_PCI(vp), PCI_D0); /* Go active */
- pci_restore_state(VORTEX_PCI(vp));
+ if (vp->pm_state_valid)
+ pci_restore_state(VORTEX_PCI(vp));
pci_enable_device(VORTEX_PCI(vp));
}
@@ -2741,6 +2742,7 @@ vortex_down(struct net_device *dev, int
outl(0, ioaddr + DownListPtr);
if (final_down && VORTEX_PCI(vp)) {
+ vp->pm_state_valid = 1;
pci_save_state(VORTEX_PCI(vp));
acpi_set_WOL(dev);
}
@@ -3243,9 +3245,10 @@ static void acpi_set_WOL(struct net_devi
outw(RxEnable, ioaddr + EL3_CMD);
pci_enable_wake(VORTEX_PCI(vp), 0, 1);
+
+ /* Change the power state to D3; RxEnable doesn't take effect. */
+ pci_set_power_state(VORTEX_PCI(vp), PCI_D3hot);
}
- /* Change the power state to D3; RxEnable doesn't take effect. */
- pci_set_power_state(VORTEX_PCI(vp), PCI_D3hot);
}
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -386,6 +386,7 @@ struct visor_private {
int bytes_in;
int bytes_out;
int outstanding_urbs;
+ int throttled;
};
/* number of outstanding urbs to prevent userspace DoS from happening */
@@ -415,6 +416,7 @@ static int visor_open (struct usb_serial
priv->bytes_in = 0;
priv->bytes_out = 0;
priv->outstanding_urbs = 0;
+ priv->throttled = 0;
spin_unlock_irqrestore(&priv->lock, flags);
/*
@@ -602,6 +604,7 @@ static void visor_read_bulk_callback (st
struct tty_struct *tty;
unsigned long flags;
int i;
+ int throttled;
int result;
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -627,18 +630,21 @@ static void visor_read_bulk_callback (st
}
spin_lock_irqsave(&priv->lock, flags);
priv->bytes_in += urb->actual_length;
+ throttled = priv->throttled;
spin_unlock_irqrestore(&priv->lock, flags);
- /* Continue trying to always read */
- usb_fill_bulk_urb (port->read_urb, port->serial->dev,
- usb_rcvbulkpipe(port->serial->dev,
- port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer,
- port->read_urb->transfer_buffer_length,
- visor_read_bulk_callback, port);
- result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
- if (result)
- dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
+ /* Continue trying to always read if we should */
+ if (!throttled) {
+ usb_fill_bulk_urb (port->read_urb, port->serial->dev,
+ usb_rcvbulkpipe(port->serial->dev,
+ port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer,
+ port->read_urb->transfer_buffer_length,
+ visor_read_bulk_callback, port);
+ result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ if (result)
+ dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
+ }
return;
}
@@ -683,16 +689,26 @@ exit:
static void visor_throttle (struct usb_serial_port *port)
{
+ struct visor_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+
dbg("%s - port %d", __FUNCTION__, port->number);
- usb_kill_urb(port->read_urb);
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->throttled = 1;
+ spin_unlock_irqrestore(&priv->lock, flags);
}
static void visor_unthrottle (struct usb_serial_port *port)
{
+ struct visor_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
int result;
dbg("%s - port %d", __FUNCTION__, port->number);
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->throttled = 0;
+ spin_unlock_irqrestore(&priv->lock, flags);
port->read_urb->dev = port->serial->dev;
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
diff --git a/drivers/video/matrox/matroxfb_accel.c b/drivers/video/matrox/matroxfb_accel.c
--- a/drivers/video/matrox/matroxfb_accel.c
+++ b/drivers/video/matrox/matroxfb_accel.c
@@ -438,13 +438,21 @@ static void matroxfb_1bpp_imageblit(WPMI
} else if (step == 1) {
/* Special case for 1..8bit widths */
while (height--) {
- mga_writel(mmio, 0, *chardata);
+#if defined(__BIG_ENDIAN)
+ fb_writel((*chardata) << 24, mmio.vaddr);
+#else
+ fb_writel(*chardata, mmio.vaddr);
+#endif
chardata++;
}
} else if (step == 2) {
/* Special case for 9..15bit widths */
while (height--) {
- mga_writel(mmio, 0, *(u_int16_t*)chardata);
+#if defined(__BIG_ENDIAN)
+ fb_writel((*(u_int16_t*)chardata) << 16, mmio.vaddr);
+#else
+ fb_writel(*(u_int16_t*)chardata, mmio.vaddr);
+#endif
chardata += 2;
}
} else {
@@ -454,7 +462,7 @@ static void matroxfb_1bpp_imageblit(WPMI
for (i = 0; i < step; i += 4) {
/* Hope that there are at least three readable bytes beyond the end of bitmap */
- mga_writel(mmio, 0, get_unaligned((u_int32_t*)(chardata + i)));
+ fb_writel(get_unaligned((u_int32_t*)(chardata + i)),mmio.vaddr);
}
chardata += step;
}
diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h
--- a/drivers/video/matrox/matroxfb_base.h
+++ b/drivers/video/matrox/matroxfb_base.h
@@ -170,14 +170,14 @@ static inline void mga_memcpy_toio(vaddr
if ((unsigned long)src & 3) {
while (len >= 4) {
- writel(get_unaligned((u32 *)src), addr);
+ fb_writel(get_unaligned((u32 *)src), addr);
addr++;
len -= 4;
src += 4;
}
} else {
while (len >= 4) {
- writel(*(u32 *)src, addr);
+ fb_writel(*(u32 *)src, addr);
addr++;
len -= 4;
src += 4;
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
--- a/fs/ext3/balloc.c
+++ b/fs/ext3/balloc.c
@@ -268,7 +268,8 @@ void ext3_discard_reservation(struct ino
if (!rsv_is_empty(&rsv->rsv_window)) {
spin_lock(rsv_lock);
- rsv_window_remove(inode->i_sb, rsv);
+ if (!rsv_is_empty(&rsv->rsv_window))
+ rsv_window_remove(inode->i_sb, rsv);
spin_unlock(rsv_lock);
}
}
diff --git a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h
--- a/include/asm-x86_64/processor.h
+++ b/include/asm-x86_64/processor.h
@@ -160,9 +160,9 @@ static inline void clear_in_cr4 (unsigne
/*
- * User space process size. 47bits.
+ * User space process size. 47bits minus one guard page.
*/
-#define TASK_SIZE (0x800000000000UL)
+#define TASK_SIZE (0x800000000000UL - 4096)
/* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
diff --git a/include/linux/err.h b/include/linux/err.h
--- a/include/linux/err.h
+++ b/include/linux/err.h
@@ -13,6 +13,8 @@
* This should be a per-architecture thing, to allow different
* error and pointer decisions.
*/
+#define IS_ERR_VALUE(x) unlikely((x) > (unsigned long)-1000L)
+
static inline void *ERR_PTR(long error)
{
return (void *) error;
@@ -25,7 +27,7 @@ static inline long PTR_ERR(const void *p
static inline long IS_ERR(const void *ptr)
{
- return unlikely((unsigned long)ptr > (unsigned long)-1000L);
+ return IS_ERR_VALUE((unsigned long)ptr);
}
#endif /* _LINUX_ERR_H */
diff --git a/mm/mmap.c b/mm/mmap.c
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1315,37 +1315,40 @@ unsigned long
get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
unsigned long pgoff, unsigned long flags)
{
- if (flags & MAP_FIXED) {
- unsigned long ret;
+ unsigned long ret;
- if (addr > TASK_SIZE - len)
- return -ENOMEM;
- if (addr & ~PAGE_MASK)
- return -EINVAL;
- if (file && is_file_hugepages(file)) {
- /*
- * Check if the given range is hugepage aligned, and
- * can be made suitable for hugepages.
- */
- ret = prepare_hugepage_range(addr, len);
- } else {
- /*
- * Ensure that a normal request is not falling in a
- * reserved hugepage range. For some archs like IA-64,
- * there is a separate region for hugepages.
- */
- ret = is_hugepage_only_range(addr, len);
- }
- if (ret)
- return -EINVAL;
- return addr;
- }
+ if (!(flags & MAP_FIXED)) {
+ unsigned long (*get_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
- if (file && file->f_op && file->f_op->get_unmapped_area)
- return file->f_op->get_unmapped_area(file, addr, len,
- pgoff, flags);
+ get_area = current->mm->get_unmapped_area;
+ if (file && file->f_op && file->f_op->get_unmapped_area)
+ get_area = file->f_op->get_unmapped_area;
+ addr = get_area(file, addr, len, pgoff, flags);
+ if (IS_ERR_VALUE(addr))
+ return addr;
+ }
- return current->mm->get_unmapped_area(file, addr, len, pgoff, flags);
+ if (addr > TASK_SIZE - len)
+ return -ENOMEM;
+ if (addr & ~PAGE_MASK)
+ return -EINVAL;
+ if (file && is_file_hugepages(file)) {
+ /*
+ * Check if the given range is hugepage aligned, and
+ * can be made suitable for hugepages.
+ */
+ ret = prepare_hugepage_range(addr, len);
+ } else {
+ /*
+ * Ensure that a normal request is not falling in a
+ * reserved hugepage range. For some archs like IA-64,
+ * there is a separate region for hugepages.
+ */
+ ret = is_hugepage_only_range(addr, len);
+ }
+ if (ret)
+ return -EINVAL;
+ return addr;
}
EXPORT_SYMBOL(get_unmapped_area);
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -179,9 +179,10 @@ unsigned int ebt_do_table (unsigned int
struct ebt_chainstack *cs;
struct ebt_entries *chaininfo;
char *base;
- struct ebt_table_info *private = table->private;
+ struct ebt_table_info *private;
read_lock_bh(&table->lock);
+ private = table->private;
cb_base = COUNTER_BASE(private->counters, private->nentries,
smp_processor_id());
if (private->chainstack)
diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c
--- a/net/rose/rose_route.c
+++ b/net/rose/rose_route.c
@@ -727,7 +727,8 @@ int rose_rt_ioctl(unsigned int cmd, void
}
if (rose_route.mask > 10) /* Mask can't be more than 10 digits */
return -EINVAL;
-
+ if (rose_route.ndigis > 8) /* No more than 8 digipeats */
+ return -EINVAL;
err = rose_add_node(&rose_route, dev);
dev_put(dev);
return err;
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -3276,7 +3276,7 @@ static void snd_usb_audio_disconnect(str
}
usb_chip[chip->index] = NULL;
up(®ister_mutex);
- snd_card_free_in_thread(card);
+ snd_card_free(card);
} else {
up(®ister_mutex);
}
diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c
--- a/sound/usb/usx2y/usbusx2y.c
+++ b/sound/usb/usx2y/usbusx2y.c
@@ -1,6 +1,11 @@
/*
* usbusy2y.c - ALSA USB US-428 Driver
*
+2005-04-14 Karsten Wiese
+ Version 0.8.7.2:
+ Call snd_card_free() instead of snd_card_free_in_thread() to prevent oops with dead keyboard symptom.
+ Tested ok with kernel 2.6.12-rc2.
+
2004-12-14 Karsten Wiese
Version 0.8.7.1:
snd_pcm_open for rawusb pcm-devices now returns -EBUSY if called without rawusb's hwdep device being open.
@@ -143,7 +148,7 @@
MODULE_AUTHOR("Karsten Wiese <annabellesgarden@yahoo.de>");
-MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.8.7.1");
+MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.8.7.2");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{TASCAM(0x1604), "NAME_ALLCAPS"(0x8001)(0x8005)(0x8007) }}");
@@ -430,8 +435,6 @@ static void usX2Y_usb_disconnect(struct
if (ptr) {
usX2Ydev_t* usX2Y = usX2Y((snd_card_t*)ptr);
struct list_head* p;
- if (usX2Y->chip_status == USX2Y_STAT_CHIP_HUP) // on 2.6.1 kernel snd_usbmidi_disconnect()
- return; // calls us back. better leave :) .
usX2Y->chip.shutdown = 1;
usX2Y->chip_status = USX2Y_STAT_CHIP_HUP;
usX2Y_unlinkSeq(&usX2Y->AS04);
@@ -443,7 +446,7 @@ static void usX2Y_usb_disconnect(struct
}
if (usX2Y->us428ctls_sharedmem)
wake_up(&usX2Y->us428ctls_wait_queue_head);
- snd_card_free_in_thread((snd_card_t*)ptr);
+ snd_card_free((snd_card_t*)ptr);
}
}
[/html]
|