diff --git a/Makefile b/Makefile index 9fea153..9ab20b8 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 36 -EXTRAVERSION = +EXTRAVERSION = .6 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff --git a/arch/i386/kernel/acpi.c b/arch/i386/kernel/acpi.c index 557a73f..ad489cb 100644 --- a/arch/i386/kernel/acpi.c +++ b/arch/i386/kernel/acpi.c @@ -440,7 +440,7 @@ acpi_boot_init (void) return result; } -#ifdef CONFIG_X86_IOAPIC +#ifdef CONFIG_X86_IO_APIC check_acpi_pci(); #endif diff --git a/arch/ppc/platforms/chrp_setup.c b/arch/ppc/platforms/chrp_setup.c index 0ffbbd2..28747db 100644 --- a/arch/ppc/platforms/chrp_setup.c +++ b/arch/ppc/platforms/chrp_setup.c @@ -121,7 +121,7 @@ chrp_show_cpuinfo(struct seq_file *m) seq_printf(m, "machine\t\t: CHRP %s\n", model); /* longtrail (goldengate) stuff */ - if (!strncmp(model, "IBM,LongTrail", 13)) { + if (model && !strncmp(model, "IBM,LongTrail", 13)) { /* VLSI VAS96011/12 `Golden Gate 2' */ /* Memory banks */ sdramen = (in_le32((unsigned *)(gg2_pci_config_base+ @@ -210,14 +210,20 @@ static void __init sio_fixup_irq(const char *name, u8 device, u8 level, static void __init sio_init(void) { struct device_node *root; + const char *model; - if ((root = find_path_device("/")) && - !strncmp(get_property(root, "model", NULL), "IBM,LongTrail", 13)) { + root = find_path_device("/"); + if (!root) + return; + + model = get_property(root, "model", NULL); + if (model && !strncmp(model, "IBM,LongTrail", 13)) { /* logical device 0 (KBC/Keyboard) */ sio_fixup_irq("keyboard", 0, 1, 2); /* select logical device 1 (KBC/Mouse) */ sio_fixup_irq("mouse", 1, 12, 2); } + } diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c index 8cea16c..67f6515 100644 --- a/arch/sparc/kernel/sys_sparc.c +++ b/arch/sparc/kernel/sys_sparc.c @@ -235,8 +235,7 @@ static unsigned long do_mmap2(unsigned long addr, unsigned long len, len = PAGE_ALIGN(len); if (ARCH_SUN4C_SUN4 && (len > 0x20000000 || - ((flags & MAP_FIXED) && - addr < 0xe0000000 && addr + len > 0x20000000))) + (addr < 0xe0000000 && addr + len > 0x20000000))) goto out_putf; /* See asm-sparc/uaccess.h */ diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c index 03750c8..9eccd43 100644 --- a/arch/sparc64/kernel/sys_sparc.c +++ b/arch/sparc64/kernel/sys_sparc.c @@ -300,12 +300,11 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, if (current->thread.flags & SPARC_FLAG_32BIT) { if (len > 0xf0000000UL || - ((flags & MAP_FIXED) && addr > 0xf0000000UL - len)) + (addr > 0xf0000000UL - len)) goto out_putf; } else { if (len > -PAGE_OFFSET || - ((flags & MAP_FIXED) && - addr < PAGE_OFFSET && addr + len > -PAGE_OFFSET)) + (addr < PAGE_OFFSET && addr + len > -PAGE_OFFSET)) goto out_putf; } diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 2510040..3bda6ad 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -90,7 +90,7 @@ acpi_power_get_context ( } *resource = (struct acpi_power_resource *) acpi_driver_data(device); - if (!resource) + if (!*resource) return_VALUE(-ENODEV); return_VALUE(0); diff --git a/drivers/char/drm-4.0/vm.c b/drivers/char/drm-4.0/vm.c index f25aaa5..ef50f2d 100644 --- a/drivers/char/drm-4.0/vm.c +++ b/drivers/char/drm-4.0/vm.c @@ -256,6 +256,7 @@ int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) vma->vm_ops = &drm_vm_dma_ops; vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */ + vma->vm_flags |= VM_DONTEXPAND; #if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */ /* In Linux 2.2.3 and above, this is @@ -358,6 +359,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) return -EINVAL; /* This should never happen. */ } vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */ + vma->vm_flags |= VM_DONTEXPAND; #if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */ /* In Linux 2.2.3 and above, this is diff --git a/drivers/char/drm/drm_vm.h b/drivers/char/drm/drm_vm.h index 4eadbf0..337a1a8 100644 --- a/drivers/char/drm/drm_vm.h +++ b/drivers/char/drm/drm_vm.h @@ -342,6 +342,7 @@ int DRM(mmap_dma)(struct file *filp, struct vm_area_struct *vma) vma->vm_ops = &DRM(vm_dma_ops); vma->vm_flags |= VM_RESERVED; /* Don't swap */ + vma->vm_flags |= VM_DONTEXPAND; vma->vm_file = filp; /* Needed for drm_vm_open() */ DRM(vm_open)(vma); return 0; @@ -475,6 +476,7 @@ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma) return -EINVAL; /* This should never happen. */ } vma->vm_flags |= VM_RESERVED; /* Don't swap */ + vma->vm_flags |= VM_DONTEXPAND; vma->vm_file = filp; /* Needed for drm_vm_open() */ DRM(vm_open)(vma); diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index 341b8e0..b67e8d6 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -1763,7 +1763,7 @@ int MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port) if(copy_from_user(&dltmp, (void *)arg, sizeof(struct dl_str))) return -EFAULT; - if(dltmp.cardno < 0 || dltmp.cardno >= MAX_BOARDS) + if(dltmp.cardno < 0 || dltmp.cardno >= MAX_BOARDS || dltmp.len < 0) return -EINVAL; switch(cmd) @@ -2874,6 +2874,8 @@ static int moxaloadbios(int cardno, unsigned char *tmp, int len) unsigned long baseAddr; int i; + if(len < 0 || len > sizeof(moxaBuff)) + return -EINVAL; if(copy_from_user(moxaBuff, tmp, len)) return -EFAULT; baseAddr = moxaBaseAddr[cardno]; @@ -2921,7 +2923,7 @@ static int moxaload320b(int cardno, unsigned char * tmp, int len) unsigned long baseAddr; int i; - if(len > sizeof(moxaBuff)) + if(len < 0 || len > sizeof(moxaBuff)) return -EINVAL; if(copy_from_user(moxaBuff, tmp, len)) return -EFAULT; @@ -2941,6 +2943,8 @@ static int moxaloadcode(int cardno, unsigned char * tmp, int len) unsigned long baseAddr, ofsAddr; int retval, port, i; + if(len < 0 || len > sizeof(moxaBuff)) + return -EINVAL; if(copy_from_user(moxaBuff, tmp, len)) return -EFAULT; baseAddr = moxaBaseAddr[cardno]; diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index f49861a..e4dff5e 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -517,7 +517,7 @@ static struct vortex_chip_info { {"3c920B-EMB-WNM (ATI Radeon 9100 IGP)", PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_MII|HAS_HWCKSM, 128, }, {"3c980 Cyclone", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM|EXTRA_PREAMBLE, 128, }, {"3c980C Python-T", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, }, diff --git a/drivers/net/pppox.c b/drivers/net/pppox.c index 7830e4d..4883c0f 100644 --- a/drivers/net/pppox.c +++ b/drivers/net/pppox.c @@ -67,7 +67,7 @@ void pppox_unbind_sock(struct sock *sk) { /* Clear connection to ppp device, if attached. */ - if (sk->state & (PPPOX_BOUND|PPPOX_ZOMBIE)) { + if (sk->state & (PPPOX_BOUND | PPPOX_CONNECTED | PPPOX_ZOMBIE)) { ppp_unregister_channel(&sk->protinfo.pppox->chan); sk->state = PPPOX_DEAD; } diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 2862039..e24e13f 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -2282,7 +2282,7 @@ EXPORT_SYMBOL(init_airo_card); static int waitbusy (struct airo_info *ai) { int delay = 0; - while ((IN4500 (ai, COMMAND) & COMMAND_BUSY) & (delay < 10000)) { + while ((IN4500 (ai, COMMAND) & COMMAND_BUSY) && (delay < 10000)) { udelay (10); if (++delay % 20) OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY); diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 57d0a40..c6d7bdf 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -683,6 +683,8 @@ static int aac_cfg_release(struct inode * inode, struct file * file ) static int aac_cfg_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg ) { struct aac_dev *dev = aac_devices[MINOR(inode->i_rdev)]; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; return aac_do_ioctl(dev, cmd, (void *)arg); } diff --git a/drivers/sound/via82cxxx_audio.c b/drivers/sound/via82cxxx_audio.c index 864f164..db5da3c 100644 --- a/drivers/sound/via82cxxx_audio.c +++ b/drivers/sound/via82cxxx_audio.c @@ -2111,6 +2111,7 @@ static struct page * via_mm_nopage (struct vm_area_struct * vma, { struct via_info *card = vma->vm_private_data; struct via_channel *chan = &card->ch_out; + unsigned long max_bufs; struct page *dmapage; unsigned long pgoff; int rd, wr; @@ -2135,14 +2136,11 @@ static struct page * via_mm_nopage (struct vm_area_struct * vma, rd = card->ch_in.is_mapped; wr = card->ch_out.is_mapped; -#ifndef VIA_NDEBUG - { - unsigned long max_bufs = chan->frag_number; - if (rd && wr) max_bufs *= 2; - /* via_dsp_mmap() should ensure this */ - assert (pgoff < max_bufs); - } -#endif + max_bufs = chan->frag_number; + if (rd && wr) + max_bufs *= 2; + if (pgoff >= max_bufs) + return NOPAGE_SIGBUS; /* if full-duplex (read+write) and we have two sets of bufs, * then the playback buffers come first, sez soundcard.c */ diff --git a/drivers/usb/pwc-if.c b/drivers/usb/pwc-if.c index e458515..a1c3989 100644 --- a/drivers/usb/pwc-if.c +++ b/drivers/usb/pwc-if.c @@ -1055,11 +1055,16 @@ static int pwc_video_open(struct video_device *vdev, int mode) return 0; } +static void pwc_cleanup(struct pwc_device *pdev) +{ + video_unregister_device(&pdev->vdev); +} + /* Note that all cleanup is done in the reverse order as in _open */ static void pwc_video_close(struct video_device *vdev) { struct pwc_device *pdev; - int i; + int i, hint; Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev); @@ -1083,8 +1088,9 @@ static void pwc_video_close(struct video_device *vdev) pwc_isoc_cleanup(pdev); pwc_free_buffers(pdev); + lock_kernel(); /* Turn off LEDS and power down camera, but only when not unplugged */ - if (pdev->error_status != EPIPE) { + if (!pdev->unplugged) { if (pwc_set_leds(pdev, 0, 0) < 0) Info("Failed to set LED on/off time.\n"); if (power_save) { @@ -1092,9 +1098,18 @@ static void pwc_video_close(struct video_device *vdev) if (i < 0) Err("Failed to power down camera (%d)\n", i); } + pdev->vopen = 0; + Trace(TRACE_OPEN, "<< video_close()\n"); + } else { + pwc_cleanup(pdev); + /* Free memory (don't set pdev to 0 just yet) */ + kfree(pdev); + /* search device_hint[] table if we occupy a slot, by any chance */ + for (hint = 0; hint < MAX_DEV_HINTS; hint++) + if (device_hint[hint].pdev == pdev) + device_hint[hint].pdev = NULL; } - pdev->vopen = 0; - Trace(TRACE_OPEN, "<< video_close()\n"); + unlock_kernel(); } /* @@ -1897,19 +1912,20 @@ static void usb_pwc_disconnect(struct usb_device *udev, void *ptr) /* Alert waiting processes */ wake_up_interruptible(&pdev->frameq); /* Wait until device is closed */ - while (pdev->vopen) - schedule(); - /* Device is now closed, so we can safely unregister it */ - Trace(TRACE_PROBE, "Unregistering video device in disconnect().\n"); - video_unregister_device(&pdev->vdev); - - /* Free memory (don't set pdev to 0 just yet) */ - kfree(pdev); - - /* search device_hint[] table if we occupy a slot, by any chance */ - for (hint = 0; hint < MAX_DEV_HINTS; hint++) - if (device_hint[hint].pdev == pdev) - device_hint[hint].pdev = NULL; + if(pdev->vopen) { + pdev->unplugged = 1; + } else { + /* Device is closed, so we can safely unregister it */ + Trace(TRACE_PROBE, "Unregistering video device in disconnect().\n"); + pwc_cleanup(pdev); + /* Free memory (don't set pdev to 0 just yet) */ + kfree(pdev); + + /* search device_hint[] table if we occupy a slot, by any chance */ + for (hint = 0; hint < MAX_DEV_HINTS; hint++) + if (device_hint[hint].pdev == pdev) + device_hint[hint].pdev = NULL; + } unlock_kernel(); } diff --git a/drivers/usb/pwc.h b/drivers/usb/pwc.h index b020769..999daf2 100644 --- a/drivers/usb/pwc.h +++ b/drivers/usb/pwc.h @@ -141,6 +141,7 @@ struct pwc_device char vsnapshot; /* snapshot mode */ char vsync; /* used by isoc handler */ char vmirror; /* for ToUCaM series */ + char unplugged; /* The image acquisition requires 3 to 4 steps: 1. data is gathered in short packets from the USB controller diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 636e024..0279485 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -1,17 +1,20 @@ /* * Prolific PL2303 USB to serial adaptor driver * - * Copyright (C) 2001-2003 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2003 IBM Corp. * * Original driver for 2.2.x by anonymous * - * 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 free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. * * See Documentation/usb/usb-serial.txt for more information on using this driver + * + * 2008_Feb)22 dn + * Back-port pl2303.c from linux-2.6.24.1. davidn@davidnewall.com. + * * 2003_Apr_24 gkh * Added line error reporting support. Hopefully it is correct... * @@ -33,6 +36,9 @@ * */ +/* TODO first char received is lost on second open of device. anecdotal evidence + * TODO suggests this might be on all even opens of device. dn. */ + #include #include #include @@ -59,30 +65,64 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.10.1" /* Takes from 2.6's */ #define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver" +#define PL2303_CLOSING_WAIT (30*HZ) +#define PL2303_BUF_SIZE 1024 +#define PL2303_TMP_BUF_SIZE 1024 + +struct pl2303_buf { + unsigned int buf_size; + char *buf_buf; + char *buf_get; + char *buf_put; +}; static struct usb_device_id id_table [] = { { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, + { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) }, { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) }, { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) }, { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) }, + { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) }, { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) }, + { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) }, { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) }, { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) }, + { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) }, { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) }, { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) }, { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) }, { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) }, + { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) }, + { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) }, + { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) }, + { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) }, + { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) }, + { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) }, + { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) }, + { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) }, + { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) }, + { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) }, + { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) }, + { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) }, + { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) }, + { USB_DEVICE(HL340_VENDOR_ID, HL340_PRODUCT_ID) }, + { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) }, { } /* Terminating entry */ }; -MODULE_DEVICE_TABLE (usb, id_table); - +MODULE_DEVICE_TABLE(usb, id_table); #define SET_LINE_REQUEST_TYPE 0x21 #define SET_LINE_REQUEST 0x20 @@ -129,33 +169,12 @@ static void pl2303_read_bulk_callback (struct urb *urb); static void pl2303_write_bulk_callback (struct urb *urb); static int pl2303_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count); +static int pl2303_write_room(struct usb_serial_port *port); static void pl2303_break_ctl(struct usb_serial_port *port,int break_state); static int pl2303_startup (struct usb_serial *serial); static void pl2303_shutdown (struct usb_serial *serial); -/* All of the device info needed for the PL2303 SIO serial converter */ -static struct usb_serial_device_type pl2303_device = { - .owner = THIS_MODULE, - .name = "PL-2303", - .id_table = id_table, - .num_interrupt_in = NUM_DONT_CARE, - .num_bulk_in = 1, - .num_bulk_out = 1, - .num_ports = 1, - .open = pl2303_open, - .close = pl2303_close, - .write = pl2303_write, - .ioctl = pl2303_ioctl, - .break_ctl = pl2303_break_ctl, - .set_termios = pl2303_set_termios, - .read_bulk_callback = pl2303_read_bulk_callback, - .read_int_callback = pl2303_read_int_callback, - .write_bulk_callback = pl2303_write_bulk_callback, - .startup = pl2303_startup, - .shutdown = pl2303_shutdown, -}; - enum pl2303_type { type_0, /* don't know the difference between type 0 and */ type_1, /* type 1, until someone from prolific tells us... */ @@ -164,6 +183,8 @@ enum pl2303_type { struct pl2303_private { spinlock_t lock; + struct pl2303_buf *buf; + int write_urb_in_use; wait_queue_head_t delta_msr_wait; u8 line_control; u8 line_status; @@ -171,8 +192,177 @@ struct pl2303_private { enum pl2303_type type; }; +/* + * pl2303_buf_alloc + * + * Allocate a circular buffer and all associated memory. + */ +static struct pl2303_buf *pl2303_buf_alloc(unsigned int size) +{ + struct pl2303_buf *pb; + + if (size == 0) + return NULL; + + pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL); + if (pb == NULL) + return NULL; + + pb->buf_buf = kmalloc(size, GFP_KERNEL); + if (pb->buf_buf == NULL) { + kfree(pb); + return NULL; + } + + pb->buf_size = size; + pb->buf_get = pb->buf_put = pb->buf_buf; + + return pb; +} + +/* + * pl2303_buf_free + * + * Free the buffer and all associated memory. + */ +static void pl2303_buf_free(struct pl2303_buf *pb) +{ + if (pb) { + kfree(pb->buf_buf); + kfree(pb); + } +} + +/* + * pl2303_buf_clear + * + * Clear out all data in the circular buffer. + */ +static void pl2303_buf_clear(struct pl2303_buf *pb) +{ + if (pb != NULL) + pb->buf_get = pb->buf_put; + /* equivalent to a get of all data available */ +} + +/* + * pl2303_buf_data_avail + * + * Return the number of bytes of data available in the circular + * buffer. + */ +static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb) +{ + if (pb == NULL) + return 0; + + return ((pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size); +} + +/* + * pl2303_buf_space_avail + * + * Return the number of bytes of space available in the circular + * buffer. + */ +static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb) +{ + if (pb == NULL) + return 0; + + return ((pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size); +} + +static int copy(char *dest, int from_user, const char *source, unsigned count) +{ + if (!from_user) + memcpy (dest, source, count); + else if (copy_from_user (dest, source, count)) + return -EFAULT; + return count; +} + +/* + * pl2303_buf_put + * + * Copy data data from a user buffer and put it into the circular buffer. + * Restrict to the amount of space available. + * + * Return the number of bytes copied. + */ +static unsigned int pl2303_buf_put(struct pl2303_buf *pb, int from_user, + const char *buf, unsigned int count) +{ + unsigned int len; + + if (pb == NULL) + return 0; + + len = pl2303_buf_space_avail(pb); + if (count > len) + count = len; -static int pl2303_startup (struct usb_serial *serial) + if (count == 0) + return 0; + + len = pb->buf_buf + pb->buf_size - pb->buf_put; + if (count > len) { + if (copy(pb->buf_put, from_user, buf, len) < 0 || + copy(pb->buf_buf, from_user, buf+len, count - len) < 0) + return -EFAULT; + pb->buf_put = pb->buf_buf + count - len; + } else { + if (copy(pb->buf_put, from_user, buf, count) < 0) + return -EFAULT; + if (count < len) + pb->buf_put += count; + else /* count == len */ + pb->buf_put = pb->buf_buf; + } + + return count; +} + +/* + * pl2303_buf_get + * + * Get data from the circular buffer and copy to the given buffer. + * Restrict to the amount of data available. + * + * Return the number of bytes copied. + */ +static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf, + unsigned int count) +{ + unsigned int len; + + if (pb == NULL) + return 0; + + len = pl2303_buf_data_avail(pb); + if (count > len) + count = len; + + if (count == 0) + return 0; + + len = pb->buf_buf + pb->buf_size - pb->buf_get; + if (count > len) { + memcpy(buf, pb->buf_get, len); + memcpy(buf+len, pb->buf_buf, count - len); + pb->buf_get = pb->buf_buf + count - len; + } else { + memcpy(buf, pb->buf_get, count); + if (count < len) + pb->buf_get += count; + else /* count == len */ + pb->buf_get = pb->buf_buf; + } + + return count; +} + +static int pl2303_startup(struct usb_serial *serial) { struct pl2303_private *priv; enum pl2303_type type = type_0; @@ -191,65 +381,136 @@ static int pl2303_startup (struct usb_serial *serial) for (i = 0; i < serial->num_ports; ++i) { priv = kmalloc (sizeof (struct pl2303_private), GFP_KERNEL); if (!priv) - return -ENOMEM; + goto cleanup; memset (priv, 0x00, sizeof (struct pl2303_private)); spin_lock_init(&priv->lock); + priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE); + if (priv->buf == NULL) { + kfree(priv); + goto cleanup; + } init_waitqueue_head(&priv->delta_msr_wait); usb_set_serial_port_data(&serial->port[i], priv); priv->type = type; } return 0; + +cleanup: + for (--i; i>=0; --i) { + priv = usb_get_serial_port_data(&serial->port[i]); + pl2303_buf_free(priv->buf); + kfree(priv); + usb_set_serial_port_data(&serial->port[i], NULL); + } + return -ENOMEM; } -static int set_control_lines (struct usb_device *dev, u8 value) +static int set_control_lines(struct usb_device *dev, u8 value) { int retval; - retval = usb_control_msg (dev, usb_sndctrlpipe (dev, 0), - SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE, - value, 0, NULL, 0, 100); + retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE, + value, 0, NULL, 0, 100); dbg("%s - value = %d, retval = %d", __FUNCTION__, value, retval); return retval; } -static int pl2303_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count) +static void pl2303_send(struct usb_serial_port *port) { - int result; + int count, result; + struct pl2303_private *priv = usb_get_serial_port_data(port); + unsigned long flags; - dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count); + dbg("%s - port %d", __FUNCTION__, port->number); - if (!count) - return count; + spin_lock_irqsave(&priv->lock, flags); - if (port->write_urb->status == -EINPROGRESS) { - dbg("%s - already writing", __FUNCTION__); - return 0; + if (priv->write_urb_in_use) { + spin_unlock_irqrestore(&priv->lock, flags); + return; } - count = (count > port->bulk_out_size) ? port->bulk_out_size : count; - if (from_user) { - if (copy_from_user (port->write_urb->transfer_buffer, buf, count)) - return -EFAULT; - } else { - memcpy (port->write_urb->transfer_buffer, buf, count); + count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer, + port->bulk_out_size); + + if (count == 0) { + spin_unlock_irqrestore(&priv->lock, flags); + return; } - + + priv->write_urb_in_use = 1; + + spin_unlock_irqrestore(&priv->lock, flags); + usb_serial_debug_data (__FILE__, __FUNCTION__, count, port->write_urb->transfer_buffer); port->write_urb->transfer_buffer_length = count; port->write_urb->dev = port->serial->dev; result = usb_submit_urb (port->write_urb); - if (result) + if (result) { err("%s - failed submitting write urb, error %d", __FUNCTION__, result); - else - result = count; + priv->write_urb_in_use = 0; + // TODO: reschedule pl2303_send + } - return result; + wake_up_interruptible(&port->tty->write_wait); /* this, at very least, wakes up pl2303_close */ } +static int pl2303_write(struct usb_serial_port *port, int from_user, + const unsigned char *buf, int count) +{ + struct pl2303_private *priv = usb_get_serial_port_data(port); + unsigned long flags; + + dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count); + + if (!count) + return count; + + spin_lock_irqsave(&priv->lock, flags); + count = pl2303_buf_put(priv->buf, from_user, buf, count); + spin_unlock_irqrestore(&priv->lock, flags); + pl2303_send(port); -static void pl2303_set_termios (struct usb_serial_port *port, struct termios *old_termios) + return count; +} + +static int pl2303_write_room(struct usb_serial_port *port) +{ + struct pl2303_private *priv = usb_get_serial_port_data(port); + int room = 0; + unsigned long flags; + + dbg("%s - port %d", __FUNCTION__, port->number); + + spin_lock_irqsave(&priv->lock, flags); + room = pl2303_buf_space_avail(priv->buf); + spin_unlock_irqrestore(&priv->lock, flags); + + dbg("%s - returns %d", __FUNCTION__, room); + return room; +} + +static int pl2303_chars_in_buffer(struct usb_serial_port *port) +{ + struct pl2303_private *priv = usb_get_serial_port_data(port); + int chars = 0; + unsigned long flags; + + dbg("%s - port %d", __FUNCTION__, port->number); + + spin_lock_irqsave(&priv->lock, flags); + chars = pl2303_buf_data_avail(priv->buf); + spin_unlock_irqrestore(&priv->lock, flags); + + dbg("%s - returns %d", __FUNCTION__, chars); + return chars; +} + +static void pl2303_set_termios(struct usb_serial_port *port, + struct termios *old_termios) { struct usb_serial *serial = port->serial; struct pl2303_private *priv = usb_get_serial_port_data(port); @@ -278,6 +539,7 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol cflag = port->tty->termios->c_cflag; /* check that they really want us to change something */ + /* important to do this as even a null change can corrupt data in transit */ if (old_termios) { if ((cflag == old_termios->c_cflag) && (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) { @@ -292,13 +554,12 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol return; } memset (buf, 0x00, 0x07); - - i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0), - GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, - 0, 0, buf, 7, 100); - dbg ("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i, - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); + i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, + 0, 0, buf, 7, 100); + dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i, + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); if (cflag & CSIZE) { switch (cflag & CSIZE) { @@ -311,28 +572,7 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol dbg("%s - data bits = %d", __FUNCTION__, buf[6]); } - baud = 0; - switch (cflag & CBAUD) { - case B0: baud = 0; break; - case B75: baud = 75; break; - case B150: baud = 150; break; - case B300: baud = 300; break; - case B600: baud = 600; break; - case B1200: baud = 1200; break; - case B1800: baud = 1800; break; - case B2400: baud = 2400; break; - case B4800: baud = 4800; break; - case B9600: baud = 9600; break; - case B19200: baud = 19200; break; - case B38400: baud = 38400; break; - case B57600: baud = 57600; break; - case B115200: baud = 115200; break; - case B230400: baud = 230400; break; - case B460800: baud = 460800; break; - default: - err ("pl2303 driver does not support the baudrate requested (fix it)"); - break; - } + baud = tty_get_baud_rate(port->tty); dbg("%s - baud = %d", __FUNCTION__, baud); if (baud) { buf[0] = baud & 0xff; @@ -370,10 +610,10 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol dbg("%s - parity = none", __FUNCTION__); } - i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0), - SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE, - 0, 0, buf, 7, 100); - dbg ("0x21:0x20:0:0 %d", i); + i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE, + 0, 0, buf, 7, 100); + dbg("0x21:0x20:0:0 %d", i); /* change control lines if we are switching to or from B0 */ spin_lock_irqsave(&priv->lock, flags); @@ -389,13 +629,13 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol } else { spin_unlock_irqrestore(&priv->lock, flags); } - + buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0; - i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0), - GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, - 0, 0, buf, 7, 100); - dbg ("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i, + i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, + 0, 0, buf, 7, 100); + dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); if (cflag & CRTSCTS) { @@ -404,24 +644,121 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol index = 0x61; else index = 0x41; - i = usb_control_msg(serial->dev, + i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE, 0x0, index, NULL, 0, 100); - dbg ("0x40:0x1:0x0:0x%x %d", index, i); + dbg("0x40:0x1:0x0:0x%x %d", index, i); + } else { + i = usb_control_msg(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + VENDOR_WRITE_REQUEST, + VENDOR_WRITE_REQUEST_TYPE, + 0x0, 0x0, NULL, 0, 100); + dbg ("0x40:0x1:0x0:0x0 %d", i); } - kfree (buf); -} + /* FIXME: Need to read back resulting baud rate */ +// 2.6 if (baud) +// 2.6 tty_encode_baud_rate(port->tty, baud, baud); + kfree(buf); +} -static int pl2303_open (struct usb_serial_port *port, struct file *filp) +static void pl2303_close(struct usb_serial_port *port, struct file *filp) +{ + struct pl2303_private *priv = usb_get_serial_port_data(port); + struct usb_serial *serial; + unsigned long flags; + unsigned int c_cflag; + int result, bps; + long timeout; + wait_queue_t wait; + + if (port_paranoia_check (port, __FUNCTION__)) + return; + serial = get_usb_serial (port, __FUNCTION__); + if (!serial) + return; + + dbg("%s - port %d", __FUNCTION__, port->number); + + /* wait for data to drain from the buffer */ + spin_lock_irqsave(&priv->lock, flags); + timeout = PL2303_CLOSING_WAIT; + init_waitqueue_entry(&wait, current); + add_wait_queue(&port->tty->write_wait, &wait); + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); + if (pl2303_buf_data_avail(priv->buf) == 0 || + timeout == 0 || signal_pending(current)) + break; + spin_unlock_irqrestore(&priv->lock, flags); + timeout = schedule_timeout(timeout); + spin_lock_irqsave(&priv->lock, flags); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&port->tty->write_wait, &wait); + /* clear out any remaining data in the buffer */ + pl2303_buf_clear(priv->buf); + spin_unlock_irqrestore(&priv->lock, flags); + + /* wait for characters to drain from the device */ + /* (this is long enough for the entire 256 byte */ + /* pl2303 hardware buffer to drain with no flow */ + /* control for data rates of 1200 bps or more, */ + /* for lower rates we should really know how much */ + /* data is in the buffer to compute a delay */ + /* that is not unnecessarily long) */ + bps = tty_get_baud_rate(port->tty); + if (bps > 1200) + timeout = max((HZ*2560)/bps,HZ/10); + else + timeout = 2*HZ; + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(timeout); + + if (serial->dev) { + if (port->tty) { + c_cflag = port->tty->termios->c_cflag; + if (c_cflag & HUPCL) { + /* drop DTR and RTS */ + spin_lock_irqsave(&priv->lock, flags); + priv->line_control = 0; + spin_unlock_irqrestore(&priv->lock, flags); + set_control_lines(port->serial->dev, 0); + } + } + + /* shutdown our urbs */ + dbg("%s - shutting down urbs", __FUNCTION__); + result = usb_unlink_urb (port->write_urb); + if (result) + dbg("%s - usb_unlink_urb (write_urb)" + " failed with reason: %d", __FUNCTION__, + result); + + result = usb_unlink_urb (port->read_urb); + if (result) + dbg("%s - usb_unlink_urb (read_urb) " + "failed with reason: %d", __FUNCTION__, + result); + + result = usb_unlink_urb (port->interrupt_in_urb); + if (result) + dbg("%s - usb_unlink_urb (interrupt_in_urb)" + " failed with reason: %d", __FUNCTION__, + result); + } +} + +static int pl2303_open(struct usb_serial_port *port, struct file *filp) { struct termios tmp_termios; struct usb_serial *serial = port->serial; + struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned char *buf; - struct pl2303_private *priv = port->private; int result; if (port_paranoia_check (port, __FUNCTION__)) @@ -429,8 +766,10 @@ static int pl2303_open (struct usb_serial_port *port, struct file *filp) dbg("%s - port %d", __FUNCTION__, port->number); - usb_clear_halt(serial->dev, port->write_urb->pipe); - usb_clear_halt(serial->dev, port->read_urb->pipe); + if (priv->type != HX) { + usb_clear_halt(serial->dev, port->write_urb->pipe); + usb_clear_halt(serial->dev, port->read_urb->pipe); + } buf = kmalloc(10, GFP_KERNEL); if (buf==NULL) @@ -456,7 +795,7 @@ static int pl2303_open (struct usb_serial_port *port, struct file *filp) FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0); SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0, 1); SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 1, 0); - + if (priv->type == HX) { /* HX chip */ SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x44); @@ -471,7 +810,7 @@ static int pl2303_open (struct usb_serial_port *port, struct file *filp) /* Setup termios */ if (port->tty) { - pl2303_set_termios (port, &tmp_termios); + pl2303_set_termios(port, &tmp_termios); } //FIXME: need to assert RTS and DTR if CRTSCTS off @@ -481,7 +820,7 @@ static int pl2303_open (struct usb_serial_port *port, struct file *filp) result = usb_submit_urb (port->read_urb); if (result) { err("%s - failed submitting read urb, error %d", __FUNCTION__, result); - pl2303_close (port, NULL); + pl2303_close(port, NULL); return -EPROTO; } @@ -490,105 +829,35 @@ static int pl2303_open (struct usb_serial_port *port, struct file *filp) result = usb_submit_urb (port->interrupt_in_urb); if (result) { err("%s - failed submitting interrupt urb, error %d", __FUNCTION__, result); - pl2303_close (port, NULL); + pl2303_close(port, NULL); return -EPROTO; } return 0; } - -static void pl2303_close (struct usb_serial_port *port, struct file *filp) -{ - struct usb_serial *serial; - struct pl2303_private *priv; - unsigned long flags; - unsigned int c_cflag; - int result; - - if (port_paranoia_check (port, __FUNCTION__)) - return; - serial = get_usb_serial (port, __FUNCTION__); - if (!serial) - return; - - dbg("%s - port %d", __FUNCTION__, port->number); - - if (serial->dev) { - if (port->tty) { - c_cflag = port->tty->termios->c_cflag; - if (c_cflag & HUPCL) { - /* drop DTR and RTS */ - priv = usb_get_serial_port_data(port); - spin_lock_irqsave(&priv->lock, flags); - priv->line_control = 0; - spin_unlock_irqrestore (&priv->lock, flags); - set_control_lines (port->serial->dev, 0); - } - } - - /* shutdown our urbs */ - dbg("%s - shutting down urbs", __FUNCTION__); - result = usb_unlink_urb (port->write_urb); - if (result) - dbg("%s - usb_unlink_urb (write_urb)" - " failed with reason: %d", __FUNCTION__, - result); - - result = usb_unlink_urb (port->read_urb); - if (result) - dbg("%s - usb_unlink_urb (read_urb) " - "failed with reason: %d", __FUNCTION__, - result); - - result = usb_unlink_urb (port->interrupt_in_urb); - if (result) - dbg("%s - usb_unlink_urb (interrupt_in_urb)" - " failed with reason: %d", __FUNCTION__, - result); - } -} - -static int set_modem_info (struct usb_serial_port *port, unsigned int cmd, unsigned int *value) +static int pl2303_tiocmset(struct usb_serial_port *port, struct file *file, + unsigned int set, unsigned int clear) { struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned long flags; - unsigned int arg; u8 control; - if (copy_from_user(&arg, value, sizeof(int))) - return -EFAULT; - - spin_lock_irqsave (&priv->lock, flags); - switch (cmd) { - case TIOCMBIS: - if (arg & TIOCM_RTS) - priv->line_control |= CONTROL_RTS; - if (arg & TIOCM_DTR) - priv->line_control |= CONTROL_DTR; - break; - - case TIOCMBIC: - if (arg & TIOCM_RTS) - priv->line_control &= ~CONTROL_RTS; - if (arg & TIOCM_DTR) - priv->line_control &= ~CONTROL_DTR; - break; - - case TIOCMSET: - /* turn off RTS and DTR and then only turn - on what was asked to */ - priv->line_control &= ~(CONTROL_RTS | CONTROL_DTR); - priv->line_control |= ((arg & TIOCM_RTS) ? CONTROL_RTS : 0); - priv->line_control |= ((arg & TIOCM_DTR) ? CONTROL_DTR : 0); - break; - } + spin_lock_irqsave(&priv->lock, flags); + if (set & TIOCM_RTS) + priv->line_control |= CONTROL_RTS; + if (set & TIOCM_DTR) + priv->line_control |= CONTROL_DTR; + if (clear & TIOCM_RTS) + priv->line_control &= ~CONTROL_RTS; + if (clear & TIOCM_DTR) + priv->line_control &= ~CONTROL_DTR; control = priv->line_control; - spin_unlock_irqrestore (&priv->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); - return set_control_lines (port->serial->dev, control); + return set_control_lines(port->serial->dev, control); } -static int get_modem_info (struct usb_serial_port *port, unsigned int *value) +static int pl2303_tiocmget(struct usb_serial_port *port, struct file *file) { struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned long flags; @@ -596,10 +865,11 @@ static int get_modem_info (struct usb_serial_port *port, unsigned int *value) unsigned int status; unsigned int result; - spin_lock_irqsave (&priv->lock, flags); + dbg("%s (%d)", __FUNCTION__, port->number); + spin_lock_irqsave(&priv->lock, flags); mcr = priv->line_control; status = priv->line_status; - spin_unlock_irqrestore (&priv->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0) | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0) @@ -610,9 +880,7 @@ static int get_modem_info (struct usb_serial_port *port, unsigned int *value) dbg("%s - result = %x", __FUNCTION__, result); - if (copy_to_user(value, &result, sizeof(int))) - return -EFAULT; - return 0; + return result; } static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) @@ -623,22 +891,22 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) unsigned int status; unsigned int changed; - spin_lock_irqsave (&priv->lock, flags); + spin_lock_irqsave(&priv->lock, flags); prevstatus = priv->line_status; - spin_unlock_irqrestore (&priv->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); while (1) { interruptible_sleep_on(&priv->delta_msr_wait); /* see if a signal did it */ if (signal_pending(current)) return -ERESTARTSYS; - - spin_lock_irqsave (&priv->lock, flags); + + spin_lock_irqsave(&priv->lock, flags); status = priv->line_status; - spin_unlock_irqrestore (&priv->lock, flags); - + spin_unlock_irqrestore(&priv->lock, flags); + changed=prevstatus^status; - + if (((arg & TIOCM_RNG) && (changed & UART_RING)) || ((arg & TIOCM_DSR) && (changed & UART_DSR)) || ((arg & TIOCM_CD) && (changed & UART_DCD)) || @@ -651,26 +919,44 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) return 0; } -static int pl2303_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg) +static int pl2303_ioctl(struct usb_serial_port *port, struct file *file, + unsigned int cmd, unsigned long arg) { + int value; dbg("%s (%d) cmd = 0x%04x", __FUNCTION__, port->number, cmd); switch (cmd) { - case TIOCMGET: dbg("%s (%d) TIOCMGET", __FUNCTION__, port->number); - return get_modem_info (port, (unsigned int *)arg); + value = pl2303_tiocmget(port, file); + if (copy_to_user((unsigned int *)arg, &value, sizeof(int))) + return -EFAULT; + return 0; case TIOCMBIS: + dbg("%s (%d) TIOCMBIS", __FUNCTION__, port->number); + if (copy_from_user(&value, (unsigned int *)arg, sizeof(int))) + return -EFAULT; + return pl2303_tiocmset(port, file, value, 0); + case TIOCMBIC: + dbg("%s (%d) TIOCMBIC", __FUNCTION__, port->number); + if (copy_from_user(&value, (unsigned int *)arg, sizeof(int))) + return -EFAULT; + return pl2303_tiocmset(port, file, 0, value); + case TIOCMSET: - dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__, port->number); - return set_modem_info(port, cmd, (unsigned int *) arg); + dbg("%s (%d) TIOCMSET", __FUNCTION__, port->number); + if (copy_from_user(&value, (unsigned int *)arg, sizeof(int))) + return -EFAULT; + /* turn off RTS and DTR and then only turn + on what was asked to */ + return pl2303_tiocmset(port, file, value, value^(TIOCM_RTS|TIOCM_DTR)); case TIOCMIWAIT: dbg("%s (%d) TIOCMIWAIT", __FUNCTION__, port->number); return wait_modem_info(port, arg); - + default: dbg("%s not supported = 0x%04x", __FUNCTION__, cmd); break; @@ -679,7 +965,7 @@ static int pl2303_ioctl (struct usb_serial_port *port, struct file *file, unsign return -ENOIOCTLCMD; } -static void pl2303_break_ctl (struct usb_serial_port *port, int break_state) +static void pl2303_break_ctl(struct usb_serial_port *port, int break_state) { struct usb_serial *serial = port->serial; u16 state; @@ -693,41 +979,75 @@ static void pl2303_break_ctl (struct usb_serial_port *port, int break_state) state = BREAK_ON; dbg("%s - turning break %s", __FUNCTION__, state==BREAK_OFF ? "off" : "on"); - result = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0), - BREAK_REQUEST, BREAK_REQUEST_TYPE, state, - 0, NULL, 0, 100); + result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + BREAK_REQUEST, BREAK_REQUEST_TYPE, state, + 0, NULL, 0, 100); if (result) dbg("%s - error sending break = %d", __FUNCTION__, result); } - -static void pl2303_shutdown (struct usb_serial *serial) +static void pl2303_shutdown(struct usb_serial *serial) { int i; + struct pl2303_private *priv; dbg("%s", __FUNCTION__); for (i = 0; i < serial->num_ports; ++i) { - kfree (usb_get_serial_port_data(&serial->port[i])); - usb_set_serial_port_data(&serial->port[i], NULL); - } + priv = usb_get_serial_port_data(&serial->port[i]); + if (priv) { + pl2303_buf_free(priv->buf); + kfree(priv); + usb_set_serial_port_data(&serial->port[i], NULL); + } + } } +static void pl2303_update_line_status(struct usb_serial_port *port, + unsigned char *data, + unsigned int actual_length) +{ + struct pl2303_private *priv = usb_get_serial_port_data(port); + unsigned long flags; + u8 status_idx = UART_STATE; + u8 length = UART_STATE + 1; + u16 idv, idp; + + idv = le16_to_cpu(port->serial->dev->descriptor.idVendor); + idp = le16_to_cpu(port->serial->dev->descriptor.idProduct); + -static void pl2303_read_int_callback (struct urb *urb) + if (idv == SIEMENS_VENDOR_ID) { + if (idp == SIEMENS_PRODUCT_ID_X65 || + idp == SIEMENS_PRODUCT_ID_SX1 || + idp == SIEMENS_PRODUCT_ID_X75) { + + length = 1; + status_idx = 0; + } + } + + if (actual_length < length) + return; + + /* Save off the uart status for others to look at */ + spin_lock_irqsave(&priv->lock, flags); + priv->line_status = data[status_idx]; + spin_unlock_irqrestore(&priv->lock, flags); + wake_up_interruptible(&priv->delta_msr_wait); +} + +static void pl2303_read_int_callback(struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *) urb->context; - struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); - struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned char *data = urb->transfer_buffer; - unsigned long flags; - u8 uart_state; + int status = urb->status; dbg("%s (%d)", __FUNCTION__, port->number); /* ints auto restart... */ - switch (urb->status) { + switch (status) { case 0: /* success */ break; @@ -735,68 +1055,51 @@ static void pl2303_read_int_callback (struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); + dbg("%s - urb shutting down with status: %d", __FUNCTION__, + status); return; default: - dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); - return; - } - - if (!serial) { + dbg("%s - nonzero urb status received: %d", __FUNCTION__, + status); return; } usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, urb->transfer_buffer); - - if (urb->actual_length < UART_STATE) - return; - - /* Save off the uart status for others to look at */ - uart_state = data[UART_STATE]; - spin_lock_irqsave(&priv->lock, flags); - uart_state |= (priv->line_status & UART_STATE_TRANSIENT_MASK); - priv->line_status = uart_state; - spin_unlock_irqrestore(&priv->lock, flags); - wake_up_interruptible (&priv->delta_msr_wait); - - return; + pl2303_update_line_status(port, data, urb->actual_length); } - -static void pl2303_read_bulk_callback (struct urb *urb) +static void pl2303_read_bulk_callback(struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *) urb->context; - struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); struct pl2303_private *priv = usb_get_serial_port_data(port); struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; unsigned long flags; int i; int result; - u8 status; + int status = urb->status; + u8 line_status; char tty_flag; - if (port_paranoia_check (port, __FUNCTION__)) - return; - dbg("%s - port %d", __FUNCTION__, port->number); - if (!serial) { + if (!get_usb_serial (port, __FUNCTION__)) { dbg("%s - bad serial pointer, exiting", __FUNCTION__); return; } - if (urb->status) { - dbg("%s - urb->status = %d", __FUNCTION__, urb->status); + if (status) { + dbg("%s - urb status = %d", __FUNCTION__, status); if (!port->open_count) { dbg("%s - port is closed, exiting.", __FUNCTION__); return; } - if (urb->status == -EPROTO) { - /* PL2303 mysteriously fails with -EPROTO reschedule the read */ - dbg("%s - caught -EPROTO, resubmitting the urb", __FUNCTION__); - urb->status = 0; - urb->dev = serial->dev; + if (status == -EPROTO) { + /* PL2303 mysteriously fails with -EPROTO reschedule + * the read */ + dbg("%s - caught -EPROTO, resubmitting the urb", + __FUNCTION__); + urb->dev = port->serial->dev; result = usb_submit_urb(urb); if (result) err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); @@ -812,39 +1115,38 @@ static void pl2303_read_bulk_callback (struct urb *urb) tty_flag = TTY_NORMAL; spin_lock_irqsave(&priv->lock, flags); - status = priv->line_status; + line_status = priv->line_status; priv->line_status &= ~UART_STATE_TRANSIENT_MASK; spin_unlock_irqrestore(&priv->lock, flags); - wake_up_interruptible (&priv->delta_msr_wait); //AF from 2.6 + wake_up_interruptible(&priv->delta_msr_wait); /* break takes precedence over parity, */ /* which takes precedence over framing errors */ - if (status & UART_BREAK_ERROR ) + if (line_status & UART_BREAK_ERROR ) tty_flag = TTY_BREAK; - else if (status & UART_PARITY_ERROR) + else if (line_status & UART_PARITY_ERROR) tty_flag = TTY_PARITY; - else if (status & UART_FRAME_ERROR) + else if (line_status & UART_FRAME_ERROR) tty_flag = TTY_FRAME; dbg("%s - tty_flag = %d", __FUNCTION__, tty_flag); tty = port->tty; if (tty && urb->actual_length) { /* overrun is special, not associated with a char */ - if (status & UART_OVERRUN_ERROR) + if (line_status & UART_OVERRUN_ERROR) tty_insert_flip_char(tty, 0, TTY_OVERRUN); for (i = 0; i < urb->actual_length; ++i) { - if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + if (tty->flip.count >= TTY_FLIPBUF_SIZE) tty_flip_buffer_push(tty); - } - tty_insert_flip_char (tty, data[i], tty_flag); + tty_insert_flip_char(tty, data[i], tty_flag); } - tty_flip_buffer_push (tty); + tty_flip_buffer_push(tty); } /* Schedule the next read _if_ we are still open */ if (port->open_count) { - urb->dev = serial->dev; + urb->dev = port->serial->dev; result = usb_submit_urb(urb); if (result) err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); @@ -853,60 +1155,96 @@ static void pl2303_read_bulk_callback (struct urb *urb) return; } - - -static void pl2303_write_bulk_callback (struct urb *urb) +static void pl2303_write_bulk_callback(struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *) urb->context; + struct pl2303_private *priv = usb_get_serial_port_data(port); int result; + int status = urb->status; if (port_paranoia_check (port, __FUNCTION__)) return; - + dbg("%s - port %d", __FUNCTION__, port->number); - - if (urb->status) { + + switch (status) { + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", __FUNCTION__, + status); + priv->write_urb_in_use = 0; + return; + default: /* error in the urb, so we have to resubmit it */ - if (serial_paranoia_check (port->serial, __FUNCTION__)) { + if (serial_paranoia_check (port->serial, __FUNCTION__)) return; - } dbg("%s - Overflow in write", __FUNCTION__); - dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); + dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, + status); port->write_urb->transfer_buffer_length = 1; port->write_urb->dev = port->serial->dev; result = usb_submit_urb (port->write_urb); if (result) err("%s - failed resubmitting write urb, error %d", __FUNCTION__, result); - - return; + else + return; } - queue_task(&port->tqueue, &tq_immediate); - mark_bh(IMMEDIATE_BH); + priv->write_urb_in_use = 0; - return; + /* send any buffered data */ + pl2303_send(port); } +/* All of the device info needed for the PL2303 SIO serial converter */ +static struct usb_serial_device_type pl2303_device = { + .owner = THIS_MODULE, + .name = "PL-2303", + .id_table = id_table, + .num_interrupt_in = NUM_DONT_CARE, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .open = pl2303_open, + .close = pl2303_close, + .write = pl2303_write, + .ioctl = pl2303_ioctl, + .break_ctl = pl2303_break_ctl, + .set_termios = pl2303_set_termios, +// 2.6 .tiocmget = pl2303_tiocmget, +// 2.6 .tiocmset = pl2303_tiocmset, + .read_bulk_callback = pl2303_read_bulk_callback, + .read_int_callback = pl2303_read_int_callback, + .write_bulk_callback = pl2303_write_bulk_callback, + .write_room = pl2303_write_room, + .chars_in_buffer = pl2303_chars_in_buffer, + .startup = pl2303_startup, + .shutdown = pl2303_shutdown, +}; -static int __init pl2303_init (void) +static int __init pl2303_init(void) { int retval; + retval = usb_serial_register(&pl2303_device); if (retval) goto failed_usb_serial_register; - info(DRIVER_DESC " " DRIVER_VERSION); + info(DRIVER_DESC); return 0; failed_usb_serial_register: return retval; } - -static void __exit pl2303_exit (void) +static void __exit pl2303_exit(void) { - usb_serial_deregister (&pl2303_device); + usb_serial_deregister(&pl2303_device); } - module_init(pl2303_init); module_exit(pl2303_exit); diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 971c5bb..237a41f 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -9,7 +9,10 @@ */ #define PL2303_VENDOR_ID 0x067b #define PL2303_PRODUCT_ID 0x2303 -#define PL2303_PRODUCT_ID_RSAQ2 0x04bb +#define PL2303_PRODUCT_ID_RSAQ2 0x04bb +#define PL2303_PRODUCT_ID_DCU11 0x1234 +#define PL2303_PRODUCT_ID_PHAROS 0xaaa0 +#define PL2303_PRODUCT_ID_RSAQ3 0xaaa2 #define ATEN_VENDOR_ID 0x0557 #define ATEN_VENDOR_ID2 0x0547 @@ -17,18 +20,22 @@ #define IODATA_VENDOR_ID 0x04bb #define IODATA_PRODUCT_ID 0x0a03 +#define IODATA_PRODUCT_ID_RSAQ5 0x0a0e #define ELCOM_VENDOR_ID 0x056e #define ELCOM_PRODUCT_ID 0x5003 +#define ELCOM_PRODUCT_ID_UCSGT 0x5004 #define ITEGNO_VENDOR_ID 0x0eba #define ITEGNO_PRODUCT_ID 0x1080 +#define ITEGNO_PRODUCT_ID_2080 0x2080 #define MA620_VENDOR_ID 0x0df7 #define MA620_PRODUCT_ID 0x0620 #define RATOC_VENDOR_ID 0x0584 #define RATOC_PRODUCT_ID 0xb000 +#define RATOC_PRODUCT_ID_USB60F 0xb020 #define TRIPP_VENDOR_ID 0x2478 #define TRIPP_PRODUCT_ID 0x2008 @@ -41,3 +48,67 @@ #define SITECOM_VENDOR_ID 0x6189 #define SITECOM_PRODUCT_ID 0x2068 + +/* Alcatel OT535/735 USB cable */ +#define ALCATEL_VENDOR_ID 0x11f7 +#define ALCATEL_PRODUCT_ID 0x02df + +/* Samsung I330 phone cradle */ +#define SAMSUNG_VENDOR_ID 0x04e8 +#define SAMSUNG_PRODUCT_ID 0x8001 + +#define SIEMENS_VENDOR_ID 0x11f5 +#define SIEMENS_PRODUCT_ID_SX1 0x0001 +#define SIEMENS_PRODUCT_ID_X65 0x0003 +#define SIEMENS_PRODUCT_ID_X75 0x0004 +#define SIEMENS_PRODUCT_ID_EF81 0x0005 + +#define SYNTECH_VENDOR_ID 0x0745 +#define SYNTECH_PRODUCT_ID 0x0001 + +/* Nokia CA-42 Cable */ +#define NOKIA_CA42_VENDOR_ID 0x078b +#define NOKIA_CA42_PRODUCT_ID 0x1234 + +/* CA-42 CLONE Cable www.ca-42.com chipset: Prolific Technology Inc */ +#define CA_42_CA42_VENDOR_ID 0x10b5 +#define CA_42_CA42_PRODUCT_ID 0xac70 + +#define SAGEM_VENDOR_ID 0x079b +#define SAGEM_PRODUCT_ID 0x0027 + +/* Leadtek GPS 9531 (ID 0413:2101) */ +#define LEADTEK_VENDOR_ID 0x0413 +#define LEADTEK_9531_PRODUCT_ID 0x2101 + +/* USB GSM cable from Speed Dragon Multimedia, Ltd */ +#define SPEEDDRAGON_VENDOR_ID 0x0e55 +#define SPEEDDRAGON_PRODUCT_ID 0x110b + +/* DATAPILOT Universal-2 Phone Cable */ +#define DATAPILOT_U2_VENDOR_ID 0x0731 +#define DATAPILOT_U2_PRODUCT_ID 0x2003 + +/* Belkin "F5U257" Serial Adapter */ +#define BELKIN_VENDOR_ID 0x050d +#define BELKIN_PRODUCT_ID 0x0257 + +/* Alcor Micro Corp. USB 2.0 TO RS-232 */ +#define ALCOR_VENDOR_ID 0x058F +#define ALCOR_PRODUCT_ID 0x9720 + +/* Willcom WS002IN Data Driver (by NetIndex Inc.) */ +#define WS002IN_VENDOR_ID 0x11f6 +#define WS002IN_PRODUCT_ID 0x2001 + +/* Corega CG-USBRS232R Serial Adapter */ +#define COREGA_VENDOR_ID 0x07aa +#define COREGA_PRODUCT_ID 0x002a + +/* HL HL-340 (ID: 4348:5523) */ +#define HL340_VENDOR_ID 0x4348 +#define HL340_PRODUCT_ID 0x5523 + +/* Y.C. Cable U.S.A., Inc - USB to RS-232 */ +#define YCCABLE_VENDOR_ID 0x05ad +#define YCCABLE_PRODUCT_ID 0x0fba diff --git a/fs/bad_inode.c b/fs/bad_inode.c index 850ba5e..b6b1d7d 100644 --- a/fs/bad_inode.c +++ b/fs/bad_inode.c @@ -9,6 +9,76 @@ #include #include #include +#include + +static loff_t bad_file_llseek(struct file *file, loff_t offset, int origin) +{ + return -EIO; +} + +static ssize_t bad_file_read(struct file *filp, char __user *buf, + size_t size, loff_t *ppos) +{ + return -EIO; +} + +static ssize_t bad_file_write(struct file *filp, const char __user *buf, + size_t siz, loff_t *ppos) +{ + return -EIO; +} + +static int bad_file_readdir(struct file *filp, void *dirent, filldir_t filldir) +{ + return -EIO; +} + +static unsigned int bad_file_poll(struct file *filp, poll_table *wait) +{ + return POLLERR; +} + +static int bad_file_ioctl (struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + return -EIO; +} + +static int bad_file_mmap(struct file *file, struct vm_area_struct *vma) +{ + return -EIO; +} + +static int bad_file_open(struct inode *inode, struct file *filp) +{ + return -EIO; +} + +static int bad_file_flush(struct file *file) +{ + return -EIO; +} + +static int bad_file_release(struct inode *inode, struct file *filp) +{ + return -EIO; +} + +static int bad_file_fsync(struct file *file, struct dentry *dentry, + int datasync) +{ + return -EIO; +} + +static int bad_file_fasync(int fd, struct file *filp, int on) +{ + return -EIO; +} + +static int bad_file_lock(struct file *file, int cmd, struct file_lock *fl) +{ + return -EIO; +} /* * The follow_link operation is special: it must behave as a no-op @@ -20,46 +90,107 @@ static int bad_follow_link(struct dentry *dent, struct nameidata *nd) return vfs_follow_link(nd, ERR_PTR(-EIO)); } -static int return_EIO(void) +static struct file_operations bad_file_ops = +{ + llseek: bad_file_llseek, + read: bad_file_read, + write: bad_file_write, + readdir: bad_file_readdir, + poll: bad_file_poll, + ioctl: bad_file_ioctl, + mmap: bad_file_mmap, + open: bad_file_open, + flush: bad_file_flush, + release: bad_file_release, + fsync: bad_file_fsync, + fasync: bad_file_fasync, + lock: bad_file_lock, +}; + +static int bad_inode_create (struct inode *dir, struct dentry *dentry, + int mode) { return -EIO; } + +static struct dentry *bad_inode_lookup(struct inode *dir, + struct dentry *dentry) +{ + return ERR_PTR(-EIO); +} -#define EIO_ERROR ((void *) (return_EIO)) +static int bad_inode_link (struct dentry *old_dentry, struct inode *dir, + struct dentry *dentry) +{ + return -EIO; +} -static struct file_operations bad_file_ops = +static int bad_inode_unlink(struct inode *dir, struct dentry *dentry) { - llseek: EIO_ERROR, - read: EIO_ERROR, - write: EIO_ERROR, - readdir: EIO_ERROR, - poll: EIO_ERROR, - ioctl: EIO_ERROR, - mmap: EIO_ERROR, - open: EIO_ERROR, - flush: EIO_ERROR, - release: EIO_ERROR, - fsync: EIO_ERROR, - fasync: EIO_ERROR, - lock: EIO_ERROR, -}; + return -EIO; +} + +static int bad_inode_symlink (struct inode *dir, struct dentry *dentry, + const char *symname) +{ + return -EIO; +} + +static int bad_inode_mkdir(struct inode *dir, struct dentry *dentry, + int mode) +{ + return -EIO; +} + +static int bad_inode_rmdir (struct inode *dir, struct dentry *dentry) +{ + return -EIO; +} + +static int bad_inode_mknod (struct inode *dir, struct dentry *dentry, + int mode, int rdev) +{ + return -EIO; +} + +static int bad_inode_rename (struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + return -EIO; +} + +static int bad_inode_readlink(struct dentry *dentry, char __user *buffer, + int buflen) +{ + return -EIO; +} + +static int bad_inode_permission(struct inode *inode, int mask) +{ + return -EIO; +} + +static int bad_inode_revalidate(struct dentry *dentry) +{ + return -EIO; +} struct inode_operations bad_inode_ops = { - create: EIO_ERROR, - lookup: EIO_ERROR, - link: EIO_ERROR, - unlink: EIO_ERROR, - symlink: EIO_ERROR, - mkdir: EIO_ERROR, - rmdir: EIO_ERROR, - mknod: EIO_ERROR, - rename: EIO_ERROR, - readlink: EIO_ERROR, + create: bad_inode_create, + lookup: bad_inode_lookup, + link: bad_inode_link, + unlink: bad_inode_unlink, + symlink: bad_inode_symlink, + mkdir: bad_inode_mkdir, + rmdir: bad_inode_rmdir, + mknod: bad_inode_mknod, + rename: bad_inode_rename, + readlink: bad_inode_readlink, follow_link: bad_follow_link, - truncate: EIO_ERROR, - permission: EIO_ERROR, - revalidate: EIO_ERROR, + /* truncate returns void */ + permission: bad_inode_permission, + revalidate: bad_inode_revalidate, }; diff --git a/fs/dnotify.c b/fs/dnotify.c index 7ccdb31..1602277 100644 --- a/fs/dnotify.c +++ b/fs/dnotify.c @@ -19,6 +19,7 @@ #include #include #include +#include extern void send_sigio(struct fown_struct *fown, int fd, int band); @@ -68,6 +69,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) struct dnotify_struct **prev; struct inode *inode; fl_owner_t id = current->files; + struct file *f; if ((arg & ~DN_MULTISHOT) == 0) { dnotify_flush(filp, id); @@ -93,6 +95,16 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) } prev = &odn->dn_next; } + + /* we'd lost the race with close(), sod off silently */ + read_lock(¤t->files->file_lock); + f = fcheck(fd); + read_unlock(¤t->files->file_lock); + if (f != filp) { + kmem_cache_free(dn_cache, dn); + goto out; + } + filp->f_owner.pid = current->pid; filp->f_owner.uid = current->uid; filp->f_owner.euid = current->euid; diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index 58b76dd..593b660 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -240,12 +240,13 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir) loff_t pos = filp->f_pos; struct inode *inode = filp->f_dentry->d_inode; struct super_block *sb = inode->i_sb; - unsigned offset = pos & ~PAGE_CACHE_MASK; + unsigned int offset = pos & ~PAGE_CACHE_MASK; unsigned long n = pos >> PAGE_CACHE_SHIFT; unsigned long npages = dir_pages(inode); unsigned chunk_mask = ~(ext2_chunk_size(inode)-1); unsigned char *types = NULL; int need_revalidate = (filp->f_version != inode->i_version); + int ret = 0; if (pos > inode->i_size - EXT2_DIR_REC_LEN(1)) goto done; @@ -258,8 +259,14 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir) ext2_dirent *de; struct page *page = ext2_get_page(inode, n); - if (IS_ERR(page)) - continue; + if (IS_ERR(page)) { + ext2_error(sb, __FUNCTION__, + "bad page in #%lu", + inode->i_ino); + filp->f_pos += PAGE_CACHE_SIZE - offset; + ret = -EIO; + goto done; + } kaddr = page_address(page); if (need_revalidate) { offset = ext2_validate_entry(kaddr, offset, chunk_mask); @@ -267,7 +274,7 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir) } de = (ext2_dirent *)(kaddr+offset); limit = kaddr + PAGE_CACHE_SIZE - EXT2_DIR_REC_LEN(1); - for ( ;(char*)de <= limit; de = ext2_next_entry(de)) + for ( ;(char*)de <= limit; de = ext2_next_entry(de)) { if (de->inode) { int over; unsigned char d_type = DT_UNKNOWN; @@ -284,14 +291,15 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir) goto done; } } + filp->f_pos += le16_to_cpu(de->rec_len); + } ext2_put_page(page); } done: - filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset; filp->f_version = inode->i_version; UPDATE_ATIME(inode); - return 0; + return ret; } /* @@ -336,7 +344,16 @@ struct ext2_dir_entry_2 * ext2_find_entry (struct inode * dir, } if (++n >= npages) n = 0; + /* next page is past the blocks we've got */ + if (unlikely(n > (dir->i_blocks >> (PAGE_CACHE_SHIFT - 9)))) { + ext2_error(dir->i_sb, __FUNCTION__, + "dir %lu size %lld exceeds block count %llu", + dir->i_ino, dir->i_size, + (unsigned long long)dir->i_blocks); + goto out; + } } while (n != start); +out: return NULL; found: diff --git a/fs/fcntl.c b/fs/fcntl.c index 9447229..abadfdf 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -283,7 +283,7 @@ static long do_fcntl(unsigned int fd, unsigned int cmd, break; case F_SETLK: case F_SETLKW: - err = fcntl_setlk(fd, cmd, (struct flock *) arg); + err = fcntl_setlk(fd, filp, cmd, (struct flock *) arg); break; case F_GETOWN: /* @@ -369,10 +369,12 @@ asmlinkage long sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg err = fcntl_getlk64(fd, (struct flock64 *) arg); break; case F_SETLK64: - err = fcntl_setlk64(fd, cmd, (struct flock64 *) arg); + err = fcntl_setlk64(fd, filp, cmd, + (struct flock64 *) arg); break; case F_SETLKW64: - err = fcntl_setlk64(fd, cmd, (struct flock64 *) arg); + err = fcntl_setlk64(fd, filp, cmd, + (struct flock64 *) arg); break; default: err = do_fcntl(fd, cmd, arg, filp); diff --git a/fs/intermezzo/dcache.c b/fs/intermezzo/dcache.c index 12184ae..61e8e9e 100644 --- a/fs/intermezzo/dcache.c +++ b/fs/intermezzo/dcache.c @@ -248,7 +248,7 @@ inline struct presto_dentry_data *izo_alloc_ddata(void) /* This uses the BKL! */ int presto_set_dd(struct dentry * dentry) { - struct presto_file_set *fset; + struct presto_file_set *fset = NULL; struct presto_dentry_data *dd; int is_under_d_izo; int error=0; @@ -325,9 +325,11 @@ out_unlock: dentry->d_fsdata); unlock_kernel(); - filter_setup_dentry_ops(fset->fset_cache->cache_filter, - dentry->d_op, &presto_dentry_ops); - dentry->d_op = filter_c2udops(fset->fset_cache->cache_filter); + if (fset) { + filter_setup_dentry_ops(fset->fset_cache->cache_filter, + dentry->d_op, &presto_dentry_ops); + dentry->d_op = filter_c2udops(fset->fset_cache->cache_filter); + } return error; } diff --git a/fs/locks.c b/fs/locks.c index 2f21d25..412e91b 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1477,9 +1477,10 @@ out: /* Apply the lock described by l to an open file descriptor. * This implements both the F_SETLK and F_SETLKW commands of fcntl(). */ -int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l) +int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, + struct flock *l) { - struct file *filp; + struct file *f; struct file_lock *file_lock = locks_alloc_lock(); struct flock flock; struct inode *inode; @@ -1498,11 +1499,6 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l) /* Get arguments and validate them ... */ - error = -EBADF; - filp = fget(fd); - if (!filp) - goto out; - error = -EINVAL; inode = filp->f_dentry->d_inode; @@ -1515,23 +1511,23 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l) if (mapping->i_mmap_shared != NULL) { error = -EAGAIN; - goto out_putf; + goto out; } } error = flock_to_posix_lock(filp, file_lock, &flock); if (error) - goto out_putf; + goto out; error = -EBADF; switch (flock.l_type) { case F_RDLCK: if (!(filp->f_mode & FMODE_READ)) - goto out_putf; + goto out; break; case F_WRLCK: if (!(filp->f_mode & FMODE_WRITE)) - goto out_putf; + goto out; break; case F_UNLCK: break; @@ -1549,23 +1545,29 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l) } } if (!(filp->f_mode & 3)) - goto out_putf; + goto out; break; #endif default: error = -EINVAL; - goto out_putf; + goto out; } +do_it: if (filp->f_op && filp->f_op->lock != NULL) { error = filp->f_op->lock(filp, cmd, file_lock); if (error < 0) - goto out_putf; + goto out; } error = posix_lock_file(filp, file_lock, cmd == F_SETLKW); - -out_putf: - fput(filp); + read_lock(¤t->files->file_lock); + f = fcheck(fd); + read_unlock(¤t->files->file_lock); + /* lost race with close, kill stuck lock if close didn't get it */ + if (!error && flock.l_type != F_UNLCK && filp != f) { + file_lock->fl_type = F_UNLCK; + goto do_it; + } out: locks_free_lock(file_lock); return error; @@ -1633,9 +1635,10 @@ out: /* Apply the lock described by l to an open file descriptor. * This implements both the F_SETLK and F_SETLKW commands of fcntl(). */ -int fcntl_setlk64(unsigned int fd, unsigned int cmd, struct flock64 *l) +int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, + struct flock64 *l) { - struct file *filp; + struct file *f; struct file_lock *file_lock = locks_alloc_lock(); struct flock64 flock; struct inode *inode; @@ -1654,11 +1657,6 @@ int fcntl_setlk64(unsigned int fd, unsigned int cmd, struct flock64 *l) /* Get arguments and validate them ... */ - error = -EBADF; - filp = fget(fd); - if (!filp) - goto out; - error = -EINVAL; inode = filp->f_dentry->d_inode; @@ -1671,23 +1669,23 @@ int fcntl_setlk64(unsigned int fd, unsigned int cmd, struct flock64 *l) if (mapping->i_mmap_shared != NULL) { error = -EAGAIN; - goto out_putf; + goto out; } } error = flock64_to_posix_lock(filp, file_lock, &flock); if (error) - goto out_putf; + goto out; error = -EBADF; switch (flock.l_type) { case F_RDLCK: if (!(filp->f_mode & FMODE_READ)) - goto out_putf; + goto out; break; case F_WRLCK: if (!(filp->f_mode & FMODE_WRITE)) - goto out_putf; + goto out; break; case F_UNLCK: break; @@ -1695,18 +1693,24 @@ int fcntl_setlk64(unsigned int fd, unsigned int cmd, struct flock64 *l) case F_EXLCK: default: error = -EINVAL; - goto out_putf; + goto out; } +do_it: if (filp->f_op && filp->f_op->lock != NULL) { error = filp->f_op->lock(filp, cmd, file_lock); if (error < 0) - goto out_putf; + goto out; } error = posix_lock_file(filp, file_lock, cmd == F_SETLKW64); - -out_putf: - fput(filp); + read_lock(¤t->files->file_lock); + f = fcheck(fd); + read_unlock(¤t->files->file_lock); + /* lost race with close, kill stuck lock if close didn't get it */ + if (!error && flock.l_type != F_UNLCK && filp != f) { + file_lock->fl_type = F_UNLCK; + goto do_it; + } out: locks_free_lock(file_lock); return error; diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c index 7d9bc34..dd8cb1a 100644 --- a/fs/ncpfs/mmap.c +++ b/fs/ncpfs/mmap.c @@ -47,9 +47,6 @@ static struct page* ncp_file_mmap_nopage(struct vm_area_struct *area, pos = address - area->vm_start + (area->vm_pgoff << PAGE_SHIFT); count = PAGE_SIZE; - if (address + PAGE_SIZE > area->vm_end) { - count = area->vm_end - address; - } /* what we can read in one go */ bufsize = NCP_SERVER(inode)->buffer_size; diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h index 81afef2..4ccfc5d 100644 --- a/include/asm-i386/processor.h +++ b/include/asm-i386/processor.h @@ -234,8 +234,9 @@ static inline void clear_in_cr4 (unsigned long mask) #define getCx86(reg) ({ outb((reg), 0x22); inb(0x23); }) #define setCx86(reg, data) do { \ + unsigned char _tmp_data = (data); \ outb((reg), 0x22); \ - outb((data), 0x23); \ + outb(_tmp_data, 0x23); \ } while (0) /* @@ -494,7 +495,7 @@ struct extended_sigtable { /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */ static inline void rep_nop(void) { - __asm__ __volatile__("rep;nop" ::: "memory"); + __asm__ __volatile__("rep;nop": : :"memory"); } #define cpu_relax() rep_nop() diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 92a6a70..e2ddf28 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -41,6 +41,7 @@ #endif #endif +#ifdef __KERNEL__ #if __GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 2 #error "GCC >= 4.2 miscompiles kernel 2.4, do not use it!" #error "While the resulting kernel may boot, you will encounter random bugs" @@ -48,6 +49,7 @@ #error "To build with another version, for instance 3.3, please do" #error " make bzImage CC=gcc-3.3 " #endif +#endif /* no checker support, so we unconditionally define this as (null) */ #define __user diff --git a/include/linux/fs.h b/include/linux/fs.h index c59e01d..feac534 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -658,10 +658,12 @@ extern struct list_head file_lock_list; #include extern int fcntl_getlk(unsigned int, struct flock *); -extern int fcntl_setlk(unsigned int, unsigned int, struct flock *); +extern int fcntl_setlk(unsigned int, struct file *, unsigned int, + struct flock *); extern int fcntl_getlk64(unsigned int, struct flock64 *); -extern int fcntl_setlk64(unsigned int, unsigned int, struct flock64 *); +extern int fcntl_setlk64(unsigned int, struct file *, unsigned int, + struct flock64 *); /* fs/locks.c */ extern void locks_init_lock(struct file_lock *); diff --git a/include/linux/signal.h b/include/linux/signal.h index c4e6eb3..e7878d9 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -160,8 +160,8 @@ static inline void sigfillset(sigset_t *set) default: memset(set, -1, sizeof(sigset_t)); break; - case 2: set->sig[1] = -1; - case 1: set->sig[0] = -1; + case 2: set->sig[1] = (unsigned long)-1; + case 1: set->sig[0] = (unsigned long)-1; break; } } @@ -204,7 +204,7 @@ static inline void siginitsetinv(sigset_t *set, unsigned long mask) default: memset(&set->sig[1], -1, sizeof(long)*(_NSIG_WORDS-1)); break; - case 2: set->sig[1] = -1; + case 2: set->sig[1] = (unsigned long)-1; case 1: ; } } diff --git a/include/linux/videodev.h b/include/linux/videodev.h index 258ec3e..62b694c 100644 --- a/include/linux/videodev.h +++ b/include/linux/videodev.h @@ -421,7 +421,7 @@ struct video_code #define VID_HARDWARE_VICAM 34 #define VID_HARDWARE_SF16FMR2 35 #define VID_HARDWARE_W9968CF 36 -#define VID_HARDWARE_SAA7114H 36 +#define VID_HARDWARE_SAA7114H 37 #endif /* __LINUX_VIDEODEV_H */ diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index f9fcb3b..71ac51c 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -1034,8 +1034,8 @@ static int __init ic_dynamic(void) jiff = jiffies + (d->next ? CONF_INTER_TIMEOUT : timeout); while (time_before(jiffies, jiff) && !ic_got_reply) { - barrier(); - cpu_relax(); + __set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); } #ifdef IPCONFIG_DHCP /* DHCP isn't done until we get a DHCPACK. */ diff --git a/net/ipv4/netfilter/ip_nat_snmp_basic.c b/net/ipv4/netfilter/ip_nat_snmp_basic.c index efc651c..87d71d4 100644 --- a/net/ipv4/netfilter/ip_nat_snmp_basic.c +++ b/net/ipv4/netfilter/ip_nat_snmp_basic.c @@ -232,6 +232,11 @@ static unsigned char asn1_length_decode(struct asn1_ctx *ctx, } } } + + /* don't trust len bigger than ctx buffer */ + if (*len > ctx->end - ctx->pointer) + return 0; + return 1; } @@ -248,7 +253,11 @@ static unsigned char asn1_header_decode(struct asn1_ctx *ctx, if (!asn1_length_decode(ctx, &def, &len)) return 0; - + + /* primitive shall be definite, indefinite shall be constructed */ + if (*con == ASN1_PRI && !def) + return 0; + if (def) *eoc = ctx->pointer + len; else @@ -433,6 +442,11 @@ static unsigned char asn1_oid_decode(struct asn1_ctx *ctx, unsigned long *optr; size = eoc - ctx->pointer + 1; + + /* first subid actually encodes first two subids */ + if (size < 2 || size > ULONG_MAX/sizeof(unsigned long)) + return 0; + *oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC); if (*oid == NULL) { if (net_ratelimit()) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 142eacc..daa40d5 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -142,6 +142,10 @@ static __inline__ void tcp_event_ack_sent(struct sock *sk) tcp_clear_xmit_timer(sk, TCP_TIME_DACK); } +/* from 2.6's ALIGN, used in tcp_select_window() */ +#define ALIGN_WIN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1) +#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) + /* Chose a new window to advertise, update state in tcp_opt for the * socket, and return result with RFC1323 scaling applied. The return * value can be stuffed directly into th->window for an outgoing @@ -162,7 +166,7 @@ static __inline__ u16 tcp_select_window(struct sock *sk) * * Relax Will Robinson. */ - new_win = cur_win; + new_win = ALIGN_WIN(cur_win, 1 << tp->rcv_wscale); } tp->rcv_wnd = new_win; tp->rcv_wup = tp->rcv_nxt; diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 0808d45..204cbb4 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -410,9 +410,9 @@ int ipip6_rcv(struct sk_buff *skb) } icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0); - kfree_skb(skb); read_unlock(&ipip6_lock); out: + kfree_skb(skb); return 0; }