diff options
109 files changed, 1829 insertions, 1312 deletions
@@ -281,6 +281,14 @@ S: Code 930.5, Goddard Space Flight Center S: Greenbelt, Maryland 20771 S: USA +N: Daniele Bellucci +E: bellucda@tiscali.it +D: Various Janitor work. +W: http://web.tiscali.it/bellucda +S: Via Delle Palme, 9 +S: Terni 05100 +S: Italy + N: Randolph Bentson E: bentson@grieg.seaslug.org W: http://www.aa.net/~bentson/ diff --git a/Documentation/DocBook/writing_usb_driver.tmpl b/Documentation/DocBook/writing_usb_driver.tmpl index 8d971b0120fb..42acfcaa788f 100644 --- a/Documentation/DocBook/writing_usb_driver.tmpl +++ b/Documentation/DocBook/writing_usb_driver.tmpl @@ -111,12 +111,12 @@ </para> <programlisting> static struct usb_driver skel_driver = { - name: "skeleton", - probe: skel_probe, - disconnect: skel_disconnect, - fops: &skel_fops, - minor: USB_SKEL_MINOR_BASE, - id_table: skel_table, + .name = "skeleton", + .probe = skel_probe, + .disconnect = skel_disconnect, + .fops = &skel_fops, + .minor = USB_SKEL_MINOR_BASE, + .id_table = skel_table, }; </programlisting> <para> @@ -202,41 +202,21 @@ MODULE_DEVICE_TABLE (usb, skel_table); are passed to the function: </para> <programlisting> -static void * skel_probe(struct usb_device *dev, -unsigned int ifnum, const struct usb_device_id *id) +static int skel_probe(struct usb_interface *interface, + const struct usb_device_id *id) </programlisting> <para> The driver now needs to verify that this device is actually one that it - can accept. If not, or if any error occurs during initialization, a NULL - value is returned from the probe function. Otherwise a pointer to a - private data structure containing the driver's state for this device is - returned. That pointer is stored in the usb_device structure, and all - callbacks to the driver pass that pointer. + can accept. If so, it returns 0. + If not, or if any error occurs during initialization, an errorcode + (such as <literal>-ENOMEM<literal> or <literal>-ENODEV<literal>) + is returned from the probe function. </para> <para> In the skeleton driver, we determine what end points are marked as bulk-in and bulk-out. We create buffers to hold the data that will be sent and received from the device, and a USB urb to write data to the device is - initialized. Also, we register the device with the devfs subsystem, - allowing users of devfs to access our device. That registration looks like - the following: - </para> - <programlisting> -/* initialize the devfs node for this device and register it */ -sprintf(name, "skel%d", skel->minor); -skel->devfs = devfs_register (usb_devfs_handle, - name, - DEVFS_FL_DEFAULT, - USB_MAJOR, - USB_SKEL_MINOR_BASE + skel->minor, - S_IFCHR | S_IRUSR | S_IWUSR | - S_IRGRP | S_IWGRP | S_IROTH, - &skel_fops, - NULL); - </programlisting> - <para> - If the devfs_register function fails, we do not care, as the devfs - subsystem will report this to the user. + initialized. </para> <para> Conversely, when the device is removed from the USB bus, the disconnect @@ -254,23 +234,18 @@ devfs_unregister(skel->devfs); the device, any of the functions in the file_operations structure that were passed to the USB subsystem will be called from a user program trying to talk to the device. The first function called will be open, as the - program tries to open the device for I/O. Within the skeleton driver's - open function we increment the driver's usage count if it is a module with - a call to MODULE_INC_USE_COUNT. With this macro call, if the driver is - compiled as a module, the driver cannot be unloaded until a corresponding - MODULE_DEC_USE_COUNT macro is called. We also increment our private usage + program tries to open the device for I/O. We increment our private usage count and save off a pointer to our internal structure in the file structure. This is done so that future calls to file operations will - enable the driver to determine which device the user is addressing. All of - this is done with the following code: + enable the driver to determine which device the user is addressing. All + of this is done with the following code: </para> <programlisting> /* increment our usage count for the module */ -MOD_INC_USE_COUNT; ++skel->open_count; /* save our object in the file's private structure */ -file->private_data = skel; +file->private_data = dev; </programlisting> <para> After the open function is called, the read and write functions are called @@ -349,75 +324,47 @@ if (!retval) { </para> <para> When the user program releases the file handle that it has been using to - talk to the device, the release function in the driver is called. In this - function we decrement the module usage count with a call to - MOD_DEC_USE_COUNT (to match our previous call to MOD_INC_USE_COUNT). We - also determine if there are any other programs that are currently talking - to the device (a device may be opened by more than one program at one - time). If this is the last user of the device, then we shut down any - possible pending writes that might be currently occurring. This is all - done with: - </para> + talk to the device, the release function in the driver is called. In this + function we decrement our private usage count and wait for possible + pending writes: <programlisting> /* decrement our usage count for the device */ --skel->open_count; -if (skel->open_count <= 0) { - /* shutdown any bulk writes that might be going on */ - usb_unlink_urb (skel->write_urb); - skel->open_count = 0; -} -/* decrement our usage count for the module */ -MOD_DEC_USE_COUNT; </programlisting> <para> One of the more difficult problems that USB drivers must be able to handle smoothly is the fact that the USB device may be removed from the system at any point in time, even if a program is currently talking to it. It needs to be able to shut down any current reads and writes and notify the - user-space programs that the device is no longer there. The following - code is an example of how to do this: </para> + user-space programs that the device is no longer there. The following + code (function <function>skel_delete</function>) + is an example of how to do this: </para> <programlisting> -/* if the device is not opened, then we clean right now */ -if (skel->open_count) { - minor_table[skel->minor] = NULL; - if (skel->bulk_in_buffer != NULL) - kfree (skel->bulk_in_buffer); - if (skel->bulk_out_buffer != NULL) - kfree (skel->bulk_out_buffer); - if (skel->write_urb != NULL) - usb_free_urb (skel->write_urb); - kfree (skel); -} else { - skel->dev = NULL; - up (&skel->sem); +static inline void skel_delete (struct usb_skel *dev) +{ + if (dev->bulk_in_buffer != NULL) + kfree (dev->bulk_in_buffer); + if (dev->bulk_out_buffer != NULL) + usb_buffer_free (dev->udev, dev->bulk_out_size, + dev->bulk_out_buffer, + dev->write_urb->transfer_dma); + if (dev->write_urb != NULL) + usb_free_urb (dev->write_urb); + kfree (dev); } </programlisting> <para> - If a program currently has an open handle to the device, we only null the - usb_device structure in our local structure, as it has now gone away. For + If a program currently has an open handle to the device, we reset the flag + <literal>device_present</literal>. For every read, write, release and other functions that expect a device to be - present, the driver first checks to see if this usb_device structure is + present, the driver first checks this flag to see if the device is still present. If not, it releases that the device has disappeared, and a - -ENODEV error is returned to the user-space program. When the release - function is eventually called, it determines if there is no usb_device - structure and if not, it does the cleanup that the skel_disconnect + -ENODEV error is returned to the user-space program. When the release + function is eventually called, it determines if there is no device + and if not, it does the cleanup that the skel_disconnect function normally does if there are no open files on the device (see Listing 5). </para> - <programlisting> -if (skel->dev == NULL) { - /* the device was unplugged before the file was released */ - minor_table[skel->minor] = NULL; - if (skel->bulk_in_buffer != NULL) - kfree (skel->bulk_in_buffer); - if (skel->bulk_out_buffer != NULL) - kfree (skel->bulk_out_buffer); - if (skel->write_urb != NULL) - usb_free_urb (skel->write_urb); - kfree (skel); - goto exit; -} - </programlisting> </chapter> <chapter id="iso"> diff --git a/Documentation/usb/hotplug.txt b/Documentation/usb/hotplug.txt index 62d5860f324e..f53170665f37 100644 --- a/Documentation/usb/hotplug.txt +++ b/Documentation/usb/hotplug.txt @@ -122,17 +122,17 @@ Drivers that connect directly to the USB subsystem should be declared something like this: static struct usb_driver mydriver = { - name: "mydriver", - id_table: mydriver_id_table, - probe: my_probe, - disconnect: my_disconnect, + .name = "mydriver", + .id_table = mydriver_id_table, + .probe = my_probe, + .disconnect = my_disconnect, /* if using the usb chardev framework: - minor: MY_USB_MINOR_START, - fops: my_file_ops, + .minor = MY_USB_MINOR_START, + .fops = my_file_ops, if exposing any operations through usbdevfs: - ioctl: my_ioctl, + .ioctl = my_ioctl, */ } diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index b34ee99f5870..42c1e5663094 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -1731,7 +1731,7 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data) int __init amiga_floppy_init(void) { - int i; + int i, ret; if (!AMIGAHW_PRESENT(AMI_FLOPPY)) return -ENXIO; @@ -1743,41 +1743,39 @@ int __init amiga_floppy_init(void) * We request DSKPTR, DSKLEN and DSKDATA only, because the other * floppy registers are too spreaded over the custom register space */ + ret = -EBUSY; if (!request_mem_region(CUSTOM_PHYSADDR+0x20, 8, "amiflop [Paula]")) { printk("fd: cannot get floppy registers\n"); - unregister_blkdev(FLOPPY_MAJOR,"fd"); - return -EBUSY; + goto out_blkdev; } + + ret = -ENOMEM; if ((raw_buf = (char *)amiga_chip_alloc (RAW_BUF_SIZE, "Floppy")) == NULL) { printk("fd: cannot get chip mem buffer\n"); - release_mem_region(CUSTOM_PHYSADDR+0x20, 8); - unregister_blkdev(FLOPPY_MAJOR,"fd"); - return -ENOMEM; + goto out_memregion; } + + ret = -EBUSY; if (request_irq(IRQ_AMIGA_DSKBLK, fd_block_done, 0, "floppy_dma", NULL)) { printk("fd: cannot get irq for dma\n"); - amiga_chip_free(raw_buf); - release_mem_region(CUSTOM_PHYSADDR+0x20, 8); - unregister_blkdev(FLOPPY_MAJOR,"fd"); - return -EBUSY; + goto out_irq; } + if (request_irq(IRQ_AMIGA_CIAA_TB, ms_isr, 0, "floppy_timer", NULL)) { printk("fd: cannot get irq for timer\n"); - free_irq(IRQ_AMIGA_DSKBLK, NULL); - amiga_chip_free(raw_buf); - release_mem_region(CUSTOM_PHYSADDR+0x20, 8); - unregister_blkdev(FLOPPY_MAJOR,"fd"); - return -EBUSY; - } - if (fd_probe_drives() < 1) { /* No usable drives */ - free_irq(IRQ_AMIGA_CIAA_TB, NULL); - free_irq(IRQ_AMIGA_DSKBLK, NULL); - amiga_chip_free(raw_buf); - release_mem_region(CUSTOM_PHYSADDR+0x20, 8); - unregister_blkdev(FLOPPY_MAJOR,"fd"); - return -ENXIO; + goto out_irq2; } + + ret = -ENOMEM; + floppy_queue = blk_init_queue(do_fd_request, &amiflop_lock); + if (!floppy_queue) + goto out_queue; + + ret = -ENXIO; + if (fd_probe_drives() < 1) /* No usable drives */ + goto out_probe; + blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE, floppy_find, NULL, NULL); @@ -1804,17 +1802,6 @@ int __init amiga_floppy_init(void) post_write_timer.data = 0; post_write_timer.function = post_write; - floppy_queue = blk_init_queue(do_fd_request, &amiflop_lock); - if (!floppy_queue) { - free_irq(IRQ_AMIGA_CIAA_TB, NULL); - free_irq(IRQ_AMIGA_DSKBLK, NULL); - amiga_chip_free(raw_buf); - release_mem_region(CUSTOM_PHYSADDR+0x20, 8); - unregister_blkdev(FLOPPY_MAJOR,"fd"); - blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256); - return -ENOMEM; - } - for (i = 0; i < 128; i++) mfmdecode[i]=255; for (i = 0; i < 16; i++) @@ -1826,6 +1813,20 @@ int __init amiga_floppy_init(void) /* init ms timer */ ciaa.crb = 8; /* one-shot, stop */ return 0; + +out_probe: + blk_cleanup_queue(floppy_queue); +out_queue: + free_irq(IRQ_AMIGA_CIAA_TB, NULL); +out_irq2: + free_irq(IRQ_AMIGA_DSKBLK, NULL); +out_irq: + amiga_chip_free(raw_buf); +out_memregion: + release_mem_region(CUSTOM_PHYSADDR+0x20, 8); +out_blkdev: + unregister_blkdev(FLOPPY_MAJOR,"fd"); + return ret; } #ifdef MODULE diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index ab4f8a452f44..ce1948f7490f 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -1249,7 +1249,7 @@ static int __init ttusb_init(void) if ((err = usb_register(&ttusb_driver)) < 0) { printk("%s: usb_register failed! Error number %d", __FILE__, err); - return -1; + return err; } return 0; diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index bd556e7dfff4..2e3fabd23b9a 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -132,8 +132,8 @@ config TUN If you don't know what to use this for, you don't need it. config ETHERTAP - tristate "Ethertap network tap (OBSOLETE)" - depends on NETDEVICES && EXPERIMENTAL + tristate "Ethertap network tap" + depends on NETDEVICES && EXPERIMENTAL && NETLINK_DEV ---help--- If you say Y here (and have said Y to "Kernel/User network link driver", above) and create a character special file /dev/tap0 with diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 838c59729c71..46fe5a996a8e 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -89,7 +89,6 @@ extern int apne_probe(struct net_device *); extern int bionet_probe(struct net_device *); extern int pamsnet_probe(struct net_device *); extern int cs89x0_probe(struct net_device *dev); -extern int ethertap_probe(struct net_device *dev); extern int hplance_probe(struct net_device *dev); extern int bagetlance_probe(struct net_device *); extern int mvme147lance_probe(struct net_device *dev); @@ -387,17 +386,6 @@ static int __init ethif_probe(struct net_device *dev) return -ENODEV; } -#ifdef CONFIG_ETHERTAP -static struct net_device tap0_dev = { - .name = "tap0", - .base_addr = NETLINK_TAPBASE, - .next = NEXT_DEV, - .init = ethertap_probe, -}; -#undef NEXT_DEV -#define NEXT_DEV (&tap0_dev) -#endif - #ifdef CONFIG_SDLA extern int sdla_init(struct net_device *); static struct net_device sdla0_dev = { diff --git a/drivers/net/ethertap.c b/drivers/net/ethertap.c index 5f8162612c25..0656fefa9670 100644 --- a/drivers/net/ethertap.c +++ b/drivers/net/ethertap.c @@ -33,7 +33,6 @@ * Index to functions. */ -int ethertap_probe(struct net_device *dev); static int ethertap_open(struct net_device *dev); static int ethertap_start_xmit(struct sk_buff *skb, struct net_device *dev); static int ethertap_close(struct net_device *dev); @@ -45,7 +44,11 @@ static void set_multicast_list(struct net_device *dev); static int ethertap_debug; -static struct net_device *tap_map[32]; /* Returns the tap device for a given netlink */ +static int max_taps = 1; +MODULE_PARM(max_taps, "i"); +MODULE_PARM_DESC(max_taps,"Max number of ethernet tap devices"); + +static struct net_device **tap_map; /* Returns the tap device for a given netlink */ /* * Board-specific info in dev->priv. @@ -64,25 +67,29 @@ struct net_local * To call this a probe is a bit misleading, however for real * hardware it would have to check what was present. */ - -int __init ethertap_probe(struct net_device *dev) +static int __init ethertap_probe(int unit) { + struct net_device *dev; + int err = -ENOMEM; + + dev = alloc_netdev(sizeof(struct net_local), "tap%d", + ether_setup); + + if (!dev) + goto out; + SET_MODULE_OWNER(dev); + sprintf(dev->name, "tap%d", unit); + dev->base_addr = unit + NETLINK_TAPBASE; + + netdev_boot_setup_check(dev); + memcpy(dev->dev_addr, "\xFE\xFD\x00\x00\x00\x00", 6); if (dev->mem_start & 0xf) ethertap_debug = dev->mem_start & 0x7; /* - * Initialize the device structure. - */ - - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct net_local)); - - /* * The tap specific entries in the device structure. */ @@ -94,17 +101,19 @@ int __init ethertap_probe(struct net_device *dev) dev->set_multicast_list = set_multicast_list; #endif - /* - * Setup the generic properties - */ - - ether_setup(dev); - dev->tx_queue_len = 0; dev->flags|=IFF_NOARP; - tap_map[dev->base_addr]=dev; + err = register_netdev(dev); + if (err) + goto out_free; + + tap_map[unit]=dev; return 0; +out_free: + free_netdev(dev); +out: + return err; } /* @@ -116,11 +125,12 @@ static int ethertap_open(struct net_device *dev) struct net_local *lp = (struct net_local*)dev->priv; if (ethertap_debug > 2) - printk("%s: Doing ethertap_open()...", dev->name); + printk(KERN_DEBUG "%s: Doing ethertap_open()...", dev->name); lp->nl = netlink_kernel_create(dev->base_addr, ethertap_rx); if (lp->nl == NULL) return -ENOBUFS; + netif_start_queue(dev); return 0; } @@ -302,7 +312,7 @@ static void ethertap_rx(struct sock *sk, int len) } if (ethertap_debug > 3) - printk("%s: ethertap_rx()\n", dev->name); + printk(KERN_DEBUG "%s: ethertap_rx()\n", dev->name); while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) ethertap_rx_skb(skb, dev); @@ -314,7 +324,7 @@ static int ethertap_close(struct net_device *dev) struct sock *sk = lp->nl; if (ethertap_debug > 2) - printk("%s: Shutting down.\n", dev->name); + printk(KERN_DEBUG "%s: Shutting down.\n", dev->name); netif_stop_queue(dev); @@ -332,45 +342,49 @@ static struct net_device_stats *ethertap_get_stats(struct net_device *dev) return &lp->stats; } -#ifdef MODULE - -static int unit; -MODULE_PARM(unit,"i"); -MODULE_PARM_DESC(unit,"Ethertap device number"); -static struct net_device dev_ethertap = +int __init ethertap_init(void) { - .name = " ", - .init = ethertap_probe -}; + int i, err = 0; -int init_module(void) -{ - dev_ethertap.base_addr=unit+NETLINK_TAPBASE; - sprintf(dev_ethertap.name,"tap%d",unit); - if (dev_get(dev_ethertap.name)) - { - printk(KERN_INFO "%s already loaded.\n", dev_ethertap.name); - return -EBUSY; + /* netlink can only hande 16 entries unless modified */ + if (max_taps > MAX_LINKS - NETLINK_TAPBASE) + return -E2BIG; + + tap_map = kmalloc(sizeof(struct net_device *)*max_taps, GFP_KERNEL); + if (!tap_map) + return -ENOMEM; + + for (i = 0; i < max_taps; i++) { + err = ethertap_probe(i); + if (err) { + while (--i > 0) { + unregister_netdev(tap_map[i]); + free_netdev(tap_map[i]); + } + break; + } } - if (register_netdev(&dev_ethertap) != 0) - return -EIO; - return 0; + if (err) + kfree(tap_map); + return err; } +module_init(ethertap_init); -void cleanup_module(void) +void __exit ethertap_cleanup(void) { - tap_map[dev_ethertap.base_addr]=NULL; - unregister_netdev(&dev_ethertap); - - /* - * Free up the private structure. - */ - - kfree(dev_ethertap.priv); - dev_ethertap.priv = NULL; /* gets re-allocated by ethertap_probe */ + int i; + + for (i = 0; i < max_taps; i++) { + struct net_device *dev = tap_map[i]; + if (dev) { + tap_map[i] = NULL; + unregister_netdev(dev); + free_netdev(dev); + } + } + kfree(tap_map); } +module_exit(ethertap_cleanup); -#endif /* MODULE */ MODULE_LICENSE("GPL"); - diff --git a/drivers/usb/class/bluetty.c b/drivers/usb/class/bluetty.c index aa28e922bf67..d3764c8a8bd6 100644 --- a/drivers/usb/class/bluetty.c +++ b/drivers/usb/class/bluetty.c @@ -1,8 +1,8 @@ /* * bluetty.c Version 0.13 * - * Copyright (c) 2000, 2001 Greg Kroah-Hartman <greg@kroah.com> - * Copyright (c) 2000 Mark Douglas Corner <mcorner@umich.edu> + * Copyright (C) 2000, 2001 Greg Kroah-Hartman <greg@kroah.com> + * Copyright (C) 2000 Mark Douglas Corner <mcorner@umich.edu> * * USB Bluetooth TTY driver, based on the Bluetooth Spec version 1.0B * diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index a036b71d0216..d18dee9cbcbd 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -767,6 +767,7 @@ static struct tty_operations acm_ops = { static int __init acm_init(void) { + int retval; acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS); if (!acm_tty_driver) return -ENOMEM; @@ -783,15 +784,17 @@ static int __init acm_init(void) acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; tty_set_operations(acm_tty_driver, &acm_ops); - if (tty_register_driver(acm_tty_driver)) { + retval = tty_register_driver(acm_tty_driver); + if (retval) { put_tty_driver(acm_tty_driver); - return -1; + return retval; } - if (usb_register(&acm_driver) < 0) { + retval = usb_register(&acm_driver); + if (retval) { tty_unregister_driver(acm_tty_driver); put_tty_driver(acm_tty_driver); - return -1; + return retval; } info(DRIVER_VERSION ":" DRIVER_DESC); diff --git a/drivers/usb/class/usb-midi.c b/drivers/usb/class/usb-midi.c index 23da0eb2123d..8ffbd3cfa34a 100644 --- a/drivers/usb/class/usb-midi.c +++ b/drivers/usb/class/usb-midi.c @@ -2084,16 +2084,12 @@ static struct usb_driver usb_midi_driver = { /* ------------------------------------------------------------------------- */ -int __init usb_midi_init(void) +static int __init usb_midi_init(void) { - if ( usb_register(&usb_midi_driver) < 0 ) - return -1; - - return 0; - + return usb_register(&usb_midi_driver); } -void __exit usb_midi_exit(void) +static void __exit usb_midi_exit(void) { usb_deregister(&usb_midi_driver); } diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index d9fe5681d6a9..9cb8863fe8f9 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -1150,10 +1150,13 @@ static struct usb_driver usblp_driver = { static int __init usblp_init(void) { - if (usb_register(&usblp_driver)) - return -1; + int retval; + retval = usb_register(&usblp_driver); + if (retval) + goto out; info(DRIVER_VERSION ": " DRIVER_DESC); - return 0; +out: + return retval; } static void __exit usblp_exit(void) diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index 1ca974ab745a..fcf39a64411c 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -129,7 +129,7 @@ int usb_register_dev(struct usb_interface *intf, int retval = -EINVAL; int minor_base = class_driver->minor_base; int minor = 0; - char name[DEVICE_ID_SIZE]; + char name[BUS_ID_SIZE]; struct class_device *class_dev; char *temp; @@ -166,7 +166,7 @@ int usb_register_dev(struct usb_interface *intf, intf->minor = minor; /* handle the devfs registration */ - snprintf(name, DEVICE_ID_SIZE, class_driver->name, minor - minor_base); + snprintf(name, BUS_ID_SIZE, class_driver->name, minor - minor_base); devfs_mk_cdev(MKDEV(USB_MAJOR, minor), class_driver->mode, name); /* create a usb class device for this usb interface */ @@ -211,7 +211,7 @@ void usb_deregister_dev(struct usb_interface *intf, struct usb_class_driver *class_driver) { int minor_base = class_driver->minor_base; - char name[DEVICE_ID_SIZE]; + char name[BUS_ID_SIZE]; #ifdef CONFIG_USB_DYNAMIC_MINORS minor_base = 0; @@ -226,7 +226,7 @@ void usb_deregister_dev(struct usb_interface *intf, usb_minors[intf->minor] = NULL; spin_unlock (&minor_lock); - snprintf(name, DEVICE_ID_SIZE, class_driver->name, intf->minor - minor_base); + snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base); devfs_remove (name); if (intf->class_dev) { diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index d21a8a3b5633..dc3a0734aa3b 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -139,6 +139,7 @@ clean_2: return retval; } } + // hcd zeroed everything hcd->regs = base; hcd->region = region; @@ -165,6 +166,7 @@ clean_3: dev_err (hcd->controller, "can't reset\n"); goto clean_3; } + hcd->state = USB_STATE_HALT; pci_set_master (dev); #ifndef __sparc__ @@ -230,7 +232,8 @@ void usb_hcd_pci_remove (struct pci_dev *dev) BUG (); hub = hcd->self.root_hub; - hcd->state = USB_STATE_QUIESCING; + if (HCD_IS_RUNNING (hcd->state)) + hcd->state = USB_STATE_QUIESCING; dev_dbg (hcd->controller, "roothub graceful disconnect\n"); usb_disconnect (&hub); @@ -287,8 +290,8 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state) pci_save_state (dev, hcd->pci_state); /* driver may want to disable DMA etc */ + hcd->state = USB_STATE_QUIESCING; retval = hcd->driver->suspend (hcd, state); - hcd->state = USB_STATE_SUSPENDED; } pci_set_power_state (dev, state); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 12d9492f476f..2666066e785b 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -483,7 +483,7 @@ static void rh_report_status (unsigned long ptr) { struct urb *urb; struct usb_hcd *hcd; - int length; + int length = 0; unsigned long flags; urb = (struct urb *) ptr; @@ -499,7 +499,9 @@ static void rh_report_status (unsigned long ptr) return; } - length = hcd->driver->hub_status_data (hcd, urb->transfer_buffer); + if (!HCD_IS_SUSPENDED (hcd->state)) + length = hcd->driver->hub_status_data ( + hcd, urb->transfer_buffer); /* complete the status urb, or retrigger the timer */ spin_lock (&hcd_data_lock); @@ -1097,6 +1099,8 @@ done: static int hcd_get_frame_number (struct usb_device *udev) { struct usb_hcd *hcd = (struct usb_hcd *)udev->bus->hcpriv; + if (!HCD_IS_RUNNING (hcd->state)) + return -ESHUTDOWN; return hcd->driver->get_frame_number (hcd); } @@ -1193,6 +1197,12 @@ static int hcd_unlink_urb (struct urb *urb) goto done; } + /* running ~= hc unlink handshake works (irq, timer, etc) + * halted ~= no unlink handshake is needed + * suspended, resuming == should never happen + */ + WARN_ON (!HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_HALT); + if (!urb->hcpriv) { retval = -EINVAL; goto done; @@ -1208,6 +1218,17 @@ static int hcd_unlink_urb (struct urb *urb) goto done; } + /* PCI IRQ setup can easily be broken so that USB controllers + * never get completion IRQs ... maybe even the ones we need to + * finish unlinking the initial failed usb_set_address(). + */ + if (!hcd->saw_irq) { + dev_warn (hcd->controller, "Unlink after no-IRQ? " + "Different ACPI or APIC settings may help." + "\n"); + hcd->saw_irq = 1; + } + /* maybe set up to block until the urb's completion fires. the * lower level hcd code is always async, locking on urb->status * updates; an intercepted completion unblocks us. @@ -1287,6 +1308,8 @@ static void hcd_endpoint_disable (struct usb_device *udev, int endpoint) dev = udev->hcpriv; hcd = udev->bus->hcpriv; + WARN_ON (!HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_HALT); + local_irq_disable (); rescan: @@ -1483,6 +1506,7 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r) if (unlikely (hcd->state == USB_STATE_HALT)) /* irq sharing? */ return IRQ_NONE; + hcd->saw_irq = 1; hcd->driver->irq (hcd, r); if (hcd->state != start && hcd->state == USB_STATE_HALT) usb_hc_died (hcd); diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index a292015405b5..15cda7f94f24 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -73,6 +73,7 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */ * hardware info/state */ struct hc_driver *driver; /* hw-specific hooks */ + unsigned saw_irq : 1; int irq; /* irq allocated */ void *regs; /* device memory/io */ struct device *controller; /* handle to hardware */ @@ -89,13 +90,11 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */ int state; # define __ACTIVE 0x01 -# define __SLEEPY 0x02 # define __SUSPEND 0x04 # define __TRANSIENT 0x80 # define USB_STATE_HALT 0 # define USB_STATE_RUNNING (__ACTIVE) -# define USB_STATE_READY (__ACTIVE|__SLEEPY) # define USB_STATE_QUIESCING (__SUSPEND|__TRANSIENT|__ACTIVE) # define USB_STATE_RESUMING (__SUSPEND|__TRANSIENT) # define USB_STATE_SUSPENDED (__SUSPEND) diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index a623fd9c93c3..870900b513da 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -4,7 +4,7 @@ * inode.c -- Inode/Dentry functions for the USB device file system. * * Copyright (C) 2000 Thomas Sailer (sailer@ife.ee.ethz.ch) - * Copyright (c) 2001,2002 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2001,2002 Greg Kroah-Hartman (greg@kroah.com) * * 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 diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 48eecba1f67d..3990e5c6238c 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -246,21 +246,22 @@ static void sg_complete (struct urb *urb, struct pt_regs *regs) io->status = urb->status; /* the previous urbs, and this one, completed already. - * unlink the later ones so they won't rx/tx bad data, - * - * FIXME don't bother unlinking urbs that haven't yet been - * submitted; those non-error cases shouldn't be syslogged + * unlink pending urbs so they won't rx/tx bad data. */ for (i = 0, found = 0; i < io->entries; i++) { + if (!io->urbs [i]) + continue; if (found) { status = usb_unlink_urb (io->urbs [i]); - if (status && status != -EINPROGRESS) - err ("sg_complete, unlink --> %d", - status); + if (status != -EINPROGRESS && status != -EBUSY) + dev_err (&io->dev->dev, + "%s, unlink --> %d\n", + __FUNCTION__, status); } else if (urb == io->urbs [i]) found = 1; } } + urb->dev = 0; /* on the last completion, signal usb_sg_wait() */ io->bytes += urb->actual_length; @@ -356,7 +357,7 @@ int usb_sg_init ( goto nomem; } - io->urbs [i]->dev = dev; + io->urbs [i]->dev = 0; io->urbs [i]->pipe = pipe; io->urbs [i]->interval = period; io->urbs [i]->transfer_flags = urb_flags; @@ -448,6 +449,7 @@ void usb_sg_wait (struct usb_sg_request *io) for (i = 0; i < io->entries && !io->status; i++) { int retval; + io->urbs [i]->dev = io->dev; retval = usb_submit_urb (io->urbs [i], SLAB_ATOMIC); /* after we submit, let completions or cancelations fire; @@ -459,9 +461,9 @@ void usb_sg_wait (struct usb_sg_request *io) case -ENXIO: // hc didn't queue this one case -EAGAIN: case -ENOMEM: + io->urbs [i]->dev = 0; retval = 0; i--; - // FIXME: should it usb_sg_cancel() on INTERRUPT? yield (); break; @@ -477,8 +479,10 @@ void usb_sg_wait (struct usb_sg_request *io) /* fail any uncompleted urbs */ default: + io->urbs [i]->dev = 0; io->urbs [i]->status = retval; - dbg ("usb_sg_msg, submit --> %d", retval); + dev_dbg (&io->dev->dev, "%s, submit --> %d\n", + __FUNCTION__, retval); usb_sg_cancel (io); } spin_lock_irqsave (&io->lock, flags); @@ -521,9 +525,9 @@ void usb_sg_cancel (struct usb_sg_request *io) if (!io->urbs [i]->dev) continue; retval = usb_unlink_urb (io->urbs [i]); - if (retval && retval != -EINPROGRESS) - warn ("usb_sg_cancel, unlink --> %d", retval); - // FIXME don't warn on "not yet submitted" error + if (retval != -EINPROGRESS && retval != -EBUSY) + dev_warn (&io->dev->dev, "%s, unlink --> %d\n", + __FUNCTION__, retval); } } spin_unlock_irqrestore (&io->lock, flags); diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 05d4800cbe90..266bcfaf9fd7 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -991,8 +991,8 @@ int usb_set_address(struct usb_device *dev) * * This call is synchronous, and may not be used in an interrupt context. * - * Only hub drivers (including virtual root hub drivers for host - * controllers) should ever call this. + * Only the hub driver should ever call this; root hub registration + * uses it only indirectly. */ #define NEW_DEVICE_RETRYS 2 #define SET_ADDRESS_RETRYS 2 @@ -1417,11 +1417,46 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } +static int usb_device_suspend(struct device *dev, u32 state) +{ + struct usb_interface *intf; + struct usb_driver *driver; + + if ((dev->driver == &usb_generic_driver) || + (dev->driver_data == &usb_generic_driver_data)) + return 0; + + intf = to_usb_interface(dev); + driver = to_usb_driver(dev->driver); + + if (driver && driver->suspend) + return driver->suspend(intf, state); + return 0; +} + +static int usb_device_resume(struct device *dev) +{ + struct usb_interface *intf; + struct usb_driver *driver; + + if ((dev->driver == &usb_generic_driver) || + (dev->driver_data == &usb_generic_driver_data)) + return 0; + + intf = to_usb_interface(dev); + driver = to_usb_driver(dev->driver); + + if (driver && driver->resume) + return driver->resume(intf); + return 0; +} struct bus_type usb_bus_type = { .name = "usb", .match = usb_device_match, .hotplug = usb_hotplug, + .suspend = usb_device_suspend, + .resume = usb_device_resume, }; #ifndef MODULE @@ -1509,7 +1544,6 @@ EXPORT_SYMBOL(usb_match_id); EXPORT_SYMBOL(usb_find_interface); EXPORT_SYMBOL(usb_ifnum_to_if); -EXPORT_SYMBOL(usb_new_device); EXPORT_SYMBOL(usb_reset_device); EXPORT_SYMBOL(usb_disconnect); diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 5cef7cf0284e..f847d3814ae8 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -30,6 +30,7 @@ /* * Copyright (C) 2003 David Brownell + * Copyright (C) 2003 NetChip Technologies * * 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 @@ -49,6 +50,7 @@ #define DEBUG 1 // #define VERBOSE /* extra debug messages (success too) */ +#include <linux/version.h> #include <linux/config.h> #include <linux/module.h> #include <linux/pci.h> @@ -76,7 +78,7 @@ #define DRIVER_DESC "NetChip 2280 USB Peripheral Controller" -#define DRIVER_VERSION "May Day 2003" +#define DRIVER_VERSION "Bastille Day 2003" #define DMA_ADDR_INVALID (~(dma_addr_t)0) #define EP_DONTUSE 13 /* nonzero */ @@ -448,7 +450,7 @@ net2280_alloc_buffer ( struct net2280_ep *ep; ep = container_of (_ep, struct net2280_ep, ep); - if (!_ep || (!ep->desc && ep->num != 0)) + if (!_ep) return 0; *dma = DMA_ADDR_INVALID; @@ -1344,11 +1346,12 @@ show_registers (struct device *_dev, char *buf) s = "(none)"; /* Main Control Registers */ - t = snprintf (next, size, "%s " DRIVER_VERSION "\n" + t = snprintf (next, size, "%s version " DRIVER_VERSION + ", chiprev %04x\n" "devinit %03x fifoctl %08x gadget '%s'\n" "pci irqenb0 %02x irqenb1 %08x " "irqstat0 %04x irqstat1 %08x\n", - driver_name, + driver_name, dev->chiprev, readl (&dev->regs->devinit), readl (&dev->regs->fifoctl), s, @@ -1393,16 +1396,33 @@ show_registers (struct device *_dev, char *buf) continue; t1 = readl (&ep->regs->ep_cfg); + t2 = readl (&ep->regs->ep_rsp) & 0xff; t = snprintf (next, size, - "%s\tcfg %05x rsp %02x enb %02x ", - ep->ep.name, t1, - readl (&ep->regs->ep_rsp) & 0xff, + "%s\tcfg %05x rsp (%02x) %s%s%s%s%s%s%s%s" + "irqenb %02x\n", + ep->ep.name, t1, t2, + (t2 & (1 << CLEAR_NAK_OUT_PACKETS)) + ? "NAK " : "", + (t2 & (1 << CLEAR_EP_HIDE_STATUS_PHASE)) + ? "hide " : "", + (t2 & (1 << CLEAR_EP_FORCE_CRC_ERROR)) + ? "CRC " : "", + (t2 & (1 << CLEAR_INTERRUPT_MODE)) + ? "interrupt " : "", + (t2 & (1<<CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE)) + ? "status " : "", + (t2 & (1 << CLEAR_NAK_OUT_PACKETS_MODE)) + ? "NAKmode " : "", + (t2 & (1 << CLEAR_ENDPOINT_TOGGLE)) + ? "DATA1 " : "DATA0 ", + (t2 & (1 << CLEAR_ENDPOINT_HALT)) + ? "HALT " : "", readl (&ep->regs->ep_irqenb)); size -= t; next += t; t = snprintf (next, size, - "stat %08x avail %04x " + "\tstat %08x avail %04x " "(ep%d%s-%s)%s\n", readl (&ep->regs->ep_stat), readl (&ep->regs->ep_avail), @@ -1796,6 +1816,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) dev->ep [i].irqs = 0; /* hook up the driver ... */ + driver->driver.bus = 0; dev->driver = driver; dev->gadget.dev.driver = &driver->driver; retval = driver->bind (&dev->gadget); @@ -1807,10 +1828,6 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) return retval; } - // FIXME - // driver_register (&driver->driver); - // device_register (&dev->gadget.dev); - device_create_file (&dev->pdev->dev, &dev_attr_function); device_create_file (&dev->pdev->dev, &dev_attr_queues); @@ -1877,10 +1894,6 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) device_remove_file (&dev->pdev->dev, &dev_attr_function); device_remove_file (&dev->pdev->dev, &dev_attr_queues); - // FIXME - // device_unregister() - // driver_unregister (&driver->driver); - DEBUG (dev, "unregistered driver '%s'\n", driver->driver.name); return 0; } @@ -2049,9 +2062,9 @@ static void handle_ep_small (struct net2280_ep *ep) /* maybe advance queue to next request */ if (ep->num == 0) { - /* FIXME need mechanism (request flag?) so control OUT - * can decide to stall ep0 after that done() returns, - * from non-irq context + /* NOTE: net2280 could let gadget driver start the + * status stage later. since not all controllers let + * them control that, the api doesn't (yet) allow it. */ if (!ep->stopped) allow_status (ep); @@ -2174,6 +2187,8 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) /* watch control traffic at the token level, and force * synchronization before letting the status stage happen. + * FIXME ignore tokens we'll NAK, until driver responds. + * that'll mean a lot less irqs for some drivers. */ ep->is_in = (u.r.bRequestType & USB_DIR_IN) != 0; if (ep->is_in) @@ -2417,6 +2432,28 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) if ((tmp & (1 << DMA_SCATTER_GATHER_ENABLE)) == 0 || (tmp & (1 << DMA_ENABLE)) == 0) restart_dma (ep); +#ifdef USE_DMA_CHAINING + else if (ep->desc->bEndpointAddress & USB_DIR_IN) { + struct net2280_request *req; + u32 dmacount; + + /* the descriptor at the head of the chain + * may still have VALID_BIT clear; that's + * used to trigger changing DMA_FIFO_VALIDATE + * (affects automagic zlp writes). + */ + req = list_entry (ep->queue.next, + struct net2280_request, queue); + dmacount = req->td->dmacount; + dmacount &= __constant_cpu_to_le32 ( + (1 << VALID_BIT) + | DMA_BYTE_COUNT_MASK); + if (dmacount && (dmacount & valid_bit) == 0) { + stop_dma (ep->dma); + restart_dma (ep); + } + } +#endif } ep->irqs++; } @@ -2458,6 +2495,13 @@ static irqreturn_t net2280_irq (int irq, void *_dev, struct pt_regs * r) /*-------------------------------------------------------------------------*/ +static void gadget_release (struct device *_dev) +{ + struct net2280 *dev = dev_get_drvdata (_dev); + + kfree (dev); +} + /* tear down the binding between this driver and the pci device */ static void net2280_remove (struct pci_dev *pdev) @@ -2493,12 +2537,12 @@ static void net2280_remove (struct pci_dev *pdev) pci_resource_len (pdev, 0)); if (dev->enabled) pci_disable_device (pdev); + device_unregister (&dev->gadget.dev); device_remove_file (&pdev->dev, &dev_attr_registers); pci_set_drvdata (pdev, 0); - INFO (dev, "unbind from pci %s\n", pci_name(pdev)); + INFO (dev, "unbind\n"); - kfree (dev); the_controller = 0; } @@ -2518,7 +2562,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) * usb_gadget_driver_{register,unregister}() must change. */ if (the_controller) { - WARN (the_controller, "ignoring %s\n", pci_name(pdev)); + dev_warn (&pdev->dev, "ignoring\n"); return -EBUSY; } @@ -2534,9 +2578,11 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) dev->pdev = pdev; dev->gadget.ops = &net2280_ops; - strcpy (dev->gadget.dev.bus_id, pci_name(pdev)); + /* the "gadget" abstracts/virtualizes the controller */ + strcpy (dev->gadget.dev.bus_id, "gadget"); dev->gadget.dev.parent = &pdev->dev; dev->gadget.dev.dma_mask = pdev->dev.dma_mask; + dev->gadget.dev.release = gadget_release; dev->gadget.name = driver_name; /* now all the pci goodies ... */ @@ -2650,6 +2696,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) INFO (dev, "version: %s\n", bufp); the_controller = dev; + device_register (&dev->gadget.dev); device_create_file (&pdev->dev, &dev_attr_registers); return 0; diff --git a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/net2280.h index 34df5178b0ef..d6af2e86bdf8 100644 --- a/drivers/usb/gadget/net2280.h +++ b/drivers/usb/gadget/net2280.h @@ -389,6 +389,7 @@ struct net2280_ep_regs { /* [11.9] */ u32 ep_rsp; #define SET_NAK_OUT_PACKETS 15 #define SET_EP_HIDE_STATUS_PHASE 14 +#define SET_EP_FORCE_CRC_ERROR 13 #define SET_INTERRUPT_MODE 12 #define SET_CONTROL_STATUS_PHASE_HANDSHAKE 11 #define SET_NAK_OUT_PACKETS_MODE 10 @@ -396,6 +397,7 @@ struct net2280_ep_regs { /* [11.9] */ #define SET_ENDPOINT_HALT 8 #define CLEAR_NAK_OUT_PACKETS 7 #define CLEAR_EP_HIDE_STATUS_PHASE 6 +#define CLEAR_EP_FORCE_CRC_ERROR 5 #define CLEAR_INTERRUPT_MODE 4 #define CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE 3 #define CLEAR_NAK_OUT_PACKETS_MODE 2 @@ -476,6 +478,9 @@ set_idx_reg (struct net2280_regs *regs, u32 index, u32 value) #define REG_CHIPREV 0x03 /* in bcd */ #define REG_HS_NAK_RATE 0x0a /* NAK per N uframes */ +#define CHIPREV_1 0x0100 +#define CHIPREV_1A 0x0110 + #ifdef __KERNEL__ /* ep a-f highspeed and fullspeed maxpacket, addresses @@ -529,24 +534,6 @@ static inline void allow_status (struct net2280_ep *ep) ep->stopped = 1; } -static inline void set_halt (struct net2280_ep *ep) -{ - /* ep0 and bulk/intr endpoints */ - writel ( (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) - /* set NAK_OUT for erratum 0114 */ - | (1 << SET_NAK_OUT_PACKETS) - | (1 << SET_ENDPOINT_HALT) - , &ep->regs->ep_rsp); -} - -static inline void clear_halt (struct net2280_ep *ep) -{ - /* bulk/intr endpoints */ - writel ( (1 << CLEAR_ENDPOINT_HALT) - | (1 << CLEAR_ENDPOINT_TOGGLE) - , &ep->regs->ep_rsp); -} - /* count (<= 4) bytes in the next fifo write will be valid */ static inline void set_fifo_bytecount (struct net2280_ep *ep, unsigned count) { @@ -589,6 +576,28 @@ struct net2280 { // statistics... }; +static inline void set_halt (struct net2280_ep *ep) +{ + /* ep0 and bulk/intr endpoints */ + writel ( (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) + /* set NAK_OUT for erratum 0114 */ + | ((ep->dev->chiprev == CHIPREV_1) << SET_NAK_OUT_PACKETS) + | (1 << SET_ENDPOINT_HALT) + , &ep->regs->ep_rsp); +} + +static inline void clear_halt (struct net2280_ep *ep) +{ + /* ep0 and bulk/intr endpoints */ + writel ( (1 << CLEAR_ENDPOINT_HALT) + | (1 << CLEAR_ENDPOINT_TOGGLE) + /* unless the gadget driver left a short packet in the + * fifo, this reverses the erratum 0114 workaround. + */ + | ((ep->dev->chiprev == CHIPREV_1) << CLEAR_NAK_OUT_PACKETS) + , &ep->regs->ep_rsp); +} + #ifdef USE_RDK_LEDS static inline void net2280_led_init (struct net2280 *dev) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 2e1cc0fd8cf8..84cbc4ef2c3f 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -41,7 +41,6 @@ #include <linux/usb.h> #include <linux/moduleparam.h> -#include <linux/version.h> #include "../core/hcd.h" #include <asm/byteorder.h> @@ -232,7 +231,6 @@ static void ehci_ready (struct ehci_hcd *ehci) ehci->hcd.state = USB_STATE_HALT; return; } - ehci->hcd.state = USB_STATE_READY; } /*-------------------------------------------------------------------------*/ @@ -482,7 +480,7 @@ done2: ehci->reboot_notifier.notifier_call = ehci_reboot; register_reboot_notifier (&ehci->reboot_notifier); - ehci->hcd.state = USB_STATE_READY; + ehci->hcd.state = USB_STATE_RUNNING; writel (FLAG_CF, &ehci->regs->configured_flag); readl (&ehci->regs->command); /* unblock posted write */ @@ -626,7 +624,7 @@ static int ehci_resume (struct usb_hcd *hcd) /* resume HC and each port */ // restore pci FLADJ value // khubd and drivers will set HC running, if needed; - hcd->state = USB_STATE_READY; + hcd->state = USB_STATE_RUNNING; // FIXME Philips/Intel/... etc don't really have a "READY" // state ... turn on CMD_RUN too for (i = 0; i < ports; i++) { @@ -979,21 +977,12 @@ static const struct hc_driver ehci_driver = { /* EHCI spec says PCI is required. */ /* PCI driver selection metadata; PCI hotplugging uses this */ -static struct pci_device_id pci_ids [] = { { - +static const struct pci_device_id pci_ids [] = { { /* handle any USB 2.0 EHCI controller */ - - .class = ((PCI_CLASS_SERIAL_USB << 8) | 0x20), - .class_mask = ~0, + PCI_DEVICE_CLASS(((PCI_CLASS_SERIAL_USB << 8) | 0x20), ~0), .driver_data = (unsigned long) &ehci_driver, - - /* no matter who makes it */ - .vendor = PCI_ANY_ID, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - -}, { /* end: all zeroes */ } + }, + { /* end: all zeroes */ } }; MODULE_DEVICE_TABLE (pci, pci_ids); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 2c80903b68e0..3bc940ce138e 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -529,7 +529,7 @@ static int hc_start (struct ohci_hcd *ohci) /* connect the virtual root hub */ bus = hcd_to_bus (&ohci->hcd); bus->root_hub = udev = usb_alloc_dev (NULL, bus); - ohci->hcd.state = USB_STATE_READY; + ohci->hcd.state = USB_STATE_RUNNING; if (!udev) { disable (ohci); ohci->hc_control &= ~OHCI_CTRL_HCFS; diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index a30e55fd8b2b..a0820ee9f178 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -30,6 +30,15 @@ /*-------------------------------------------------------------------------*/ +static int +ohci_pci_reset (struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + + ohci->regs = hcd->regs; + return hc_reset (ohci); +} + static int __devinit ohci_pci_start (struct usb_hcd *hcd) { @@ -89,12 +98,6 @@ ohci_pci_start (struct usb_hcd *hcd) ohci_stop (hcd); return ret; } - ohci->regs = hcd->regs; - - if (hc_reset (ohci) < 0) { - ohci_stop (hcd); - return -ENODEV; - } if (hc_start (ohci) < 0) { ohci_err (ohci, "can't start\n"); @@ -264,7 +267,7 @@ static int ohci_pci_resume (struct usb_hcd *hcd) if (ohci->ed_bulktail) ohci->hc_control |= OHCI_CTRL_BLE; } - hcd->state = USB_STATE_READY; + hcd->state = USB_STATE_RUNNING; writel (ohci->hc_control, &ohci->regs->control); /* trigger a start-frame interrupt (why?) */ @@ -315,6 +318,7 @@ static const struct hc_driver ohci_pci_hc_driver = { /* * basic lifecycle operations */ + .reset = ohci_pci_reset, .start = ohci_pci_start, #ifdef CONFIG_PM .suspend = ohci_pci_suspend, @@ -351,18 +355,9 @@ static const struct hc_driver ohci_pci_hc_driver = { static const struct pci_device_id pci_ids [] = { { - /* handle any USB OHCI controller */ - .class = (PCI_CLASS_SERIAL_USB << 8) | 0x10, - .class_mask = ~0, + PCI_DEVICE_CLASS((PCI_CLASS_SERIAL_USB << 8) | 0x10, ~0), .driver_data = (unsigned long) &ohci_pci_hc_driver, - - /* no matter who makes it */ - .vendor = PCI_ANY_ID, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, { /* end: all zeroes */ } }; MODULE_DEVICE_TABLE (pci, pci_ids); diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index e44e9f931fa9..0d1e63469030 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -1013,10 +1013,22 @@ dl_done_list (struct ohci_hcd *ohci, struct td *td, struct pt_regs *regs) if (list_empty (&ed->td_list)) ed_deschedule (ohci, ed); /* ... reenabling halted EDs only after fault cleanup */ - else if (!(ed->hwINFO & ED_DEQUEUE)) { + else if ((ed->hwINFO & (ED_SKIP | ED_DEQUEUE)) == ED_SKIP) { td = list_entry (ed->td_list.next, struct td, td_list); - if (!(td->hwINFO & TD_DONE)) + if (!(td->hwINFO & TD_DONE)) { ed->hwINFO &= ~ED_SKIP; + /* ... hc may need waking-up */ + switch (ed->type) { + case PIPE_CONTROL: + writel (OHCI_CLF, + &ohci->regs->cmdstatus); + break; + case PIPE_BULK: + writel (OHCI_BLF, + &ohci->regs->cmdstatus); + break; + } + } } td = td_next; diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index bd6066098682..5811fd1ae415 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -2099,7 +2099,7 @@ static void start_hc(struct uhci_hcd *uhci) uhci->state_end = jiffies + HZ; outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD); - uhci->hcd.state = USB_STATE_READY; + uhci->hcd.state = USB_STATE_RUNNING; } /* @@ -2143,6 +2143,20 @@ static void release_uhci(struct uhci_hcd *uhci) #endif } +static int uhci_reset(struct usb_hcd *hcd) +{ + struct uhci_hcd *uhci = hcd_to_uhci(hcd); + + uhci->io_addr = (unsigned long) hcd->regs; + + /* Maybe kick BIOS off this hardware. Then reset, so we won't get + * interrupts from any previous setup. + */ + pci_write_config_word(hcd->pdev, USBLEGSUP, USBLEGSUP_DEFAULT); + reset_hc(uhci); + return 0; +} + /* * Allocate a frame list, and then setup the skeleton * @@ -2159,7 +2173,7 @@ static void release_uhci(struct uhci_hcd *uhci) * - The fourth queue is the bandwidth reclamation queue, which loops back * to the high speed control queue. */ -static int __devinit uhci_start(struct usb_hcd *hcd) +static int uhci_start(struct usb_hcd *hcd) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); int retval = -EBUSY; @@ -2171,7 +2185,6 @@ static int __devinit uhci_start(struct usb_hcd *hcd) struct proc_dir_entry *ent; #endif - uhci->io_addr = (unsigned long) hcd->regs; io_size = pci_resource_len(hcd->pdev, hcd->region); #ifdef CONFIG_PROC_FS @@ -2188,10 +2201,6 @@ static int __devinit uhci_start(struct usb_hcd *hcd) uhci->proc_entry = ent; #endif - /* Reset here so we don't get any interrupts from an old setup */ - /* or broken setup */ - reset_hc(uhci); - uhci->fsbr = 0; uhci->fsbrtimeout = 0; @@ -2343,9 +2352,6 @@ static int __devinit uhci_start(struct usb_hcd *hcd) init_stall_timer(hcd); - /* disable legacy emulation */ - pci_write_config_word(hcd->pdev, USBLEGSUP, USBLEGSUP_DEFAULT); - udev->speed = USB_SPEED_FULL; if (usb_register_root_hub(udev, &hcd->pdev->dev) != 0) { @@ -2446,7 +2452,7 @@ static int uhci_resume(struct usb_hcd *hcd) reset_hc(uhci); start_hc(uhci); } - uhci->hcd.state = USB_STATE_READY; + uhci->hcd.state = USB_STATE_RUNNING; return 0; } #endif @@ -2484,6 +2490,7 @@ static const struct hc_driver uhci_driver = { .flags = HCD_USB11, /* Basic lifecycle operations */ + .reset = uhci_reset, .start = uhci_start, #ifdef CONFIG_PM .suspend = uhci_suspend, @@ -2504,18 +2511,9 @@ static const struct hc_driver uhci_driver = { }; static const struct pci_device_id uhci_pci_ids[] = { { - /* handle any USB UHCI controller */ - .class = ((PCI_CLASS_SERIAL_USB << 8) | 0x00), - .class_mask = ~0, + PCI_DEVICE_CLASS(((PCI_CLASS_SERIAL_USB << 8) | 0x00), ~0), .driver_data = (unsigned long) &uhci_driver, - - /* no matter who makes it */ - .vendor = PCI_ANY_ID, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, { /* end: all zeroes */ } }; diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c index 90cb83693bfa..5d1ff8bbd012 100644 --- a/drivers/usb/image/mdc800.c +++ b/drivers/usb/image/mdc800.c @@ -977,8 +977,9 @@ static struct usb_driver mdc800_usb_driver = #define try_free_mem(A) if (A != 0) { kfree (A); A=0; } #define try_free_urb(A) if (A != 0) { usb_free_urb (A); A=0; } -int __init usb_mdc800_init (void) +static int __init usb_mdc800_init (void) { + int retval = -ENODEV; /* Allocate Memory */ try (mdc800=kmalloc (sizeof (struct mdc800_data), GFP_KERNEL)); @@ -1005,7 +1006,8 @@ int __init usb_mdc800_init (void) try (mdc800->write_urb=usb_alloc_urb (0, GFP_KERNEL)); /* Register the driver */ - if (usb_register (&mdc800_usb_driver) < 0) + retval = usb_register(&mdc800_usb_driver); + if (retval) goto cleanup_on_fail; info (DRIVER_VERSION ":" DRIVER_DESC); @@ -1031,11 +1033,11 @@ cleanup_on_fail: kfree (mdc800); } mdc800=0; - return -1; + return retval; } -void __exit usb_mdc800_cleanup (void) +static void __exit usb_mdc800_cleanup (void) { usb_deregister (&mdc800_usb_driver); diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 80822ed23a6c..c7e883316218 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1328,6 +1328,7 @@ void hid_init_reports(struct hid_device *hid) #define USB_DEVICE_ID_ATEN_CS124U 0x2202 #define USB_DEVICE_ID_ATEN_2PORTKVM 0x2204 #define USB_DEVICE_ID_ATEN_4PORTKVM 0x2205 +#define USB_DEVICE_ID_ATEN_4PORTKVMC 0x2208 #define USB_VENDOR_ID_TOPMAX 0x0663 #define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103 @@ -1386,6 +1387,7 @@ struct hid_blacklist { { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_HIDDEV }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_HIDDEV }, { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD }, @@ -1691,11 +1693,20 @@ static struct usb_driver hid_driver = { static int __init hid_init(void) { - hiddev_init(); - usb_register(&hid_driver); + int retval; + retval = hiddev_init(); + if (retval) + goto hiddev_init_fail; + retval = usb_register(&hid_driver); + if (retval) + goto usb_register_fail; info(DRIVER_VERSION ":" DRIVER_DESC); return 0; +usb_register_fail: + hiddev_exit(); +hiddev_init_fail: + return retval; } static void __exit hid_exit(void) diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index 6d0d97ceadf6..c85528623cfa 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c @@ -795,8 +795,7 @@ static /* const */ struct usb_driver hiddev_driver = { int __init hiddev_init(void) { devfs_mk_dir("usb/hid"); - usb_register(&hiddev_driver); - return 0; + return usb_register(&hiddev_driver); } void __exit hiddev_exit(void) diff --git a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c index d1e9ba6801d7..84ca1106ade7 100644 --- a/drivers/usb/input/kbtab.c +++ b/drivers/usb/input/kbtab.c @@ -216,9 +216,13 @@ static struct usb_driver kbtab_driver = { static int __init kbtab_init(void) { - usb_register(&kbtab_driver); + int retval; + retval = usb_register(&kbtab_driver); + if (retval) + goto out; info(DRIVER_VERSION ":" DRIVER_DESC); - return 0; +out: + return retval; } static void __exit kbtab_exit(void) diff --git a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c index 10a5889d6431..64c4c331046c 100644 --- a/drivers/usb/input/powermate.c +++ b/drivers/usb/input/powermate.c @@ -433,14 +433,12 @@ static struct usb_driver powermate_driver = { .id_table = powermate_devices, }; -int powermate_init(void) +static int __init powermate_init(void) { - if (usb_register(&powermate_driver) < 0) - return -1; - return 0; + return usb_register(&powermate_driver); } -void powermate_cleanup(void) +static void __exit powermate_cleanup(void) { usb_deregister(&powermate_driver); } diff --git a/drivers/usb/media/dabusb.c b/drivers/usb/media/dabusb.c index 61fbbfc317ef..140beb0f180f 100644 --- a/drivers/usb/media/dabusb.c +++ b/drivers/usb/media/dabusb.c @@ -29,7 +29,6 @@ #include <linux/module.h> #include <linux/socket.h> -#include <linux/miscdevice.h> #include <linux/list.h> #include <linux/vmalloc.h> #include <linux/slab.h> @@ -819,6 +818,7 @@ static struct usb_driver dabusb_driver = { static int __init dabusb_init (void) { + int retval; unsigned u; /* initialize struct */ @@ -836,14 +836,16 @@ static int __init dabusb_init (void) } /* register misc device */ - if (usb_register(&dabusb_driver)) - return -1; + retval = usb_register(&dabusb_driver); + if (retval) + goto out; dbg("dabusb_init: driver registered"); info(DRIVER_VERSION ":" DRIVER_DESC); - return 0; +out: + return retval; } static void __exit dabusb_cleanup (void) diff --git a/drivers/usb/media/dsbr100.c b/drivers/usb/media/dsbr100.c index 2f0a232775eb..cdeb6756f396 100644 --- a/drivers/usb/media/dsbr100.c +++ b/drivers/usb/media/dsbr100.c @@ -354,15 +354,23 @@ static int usb_dsbr100_close(struct inode *inode, struct file *file) static int __init dsbr100_init(void) { + int retval; usb_dsbr100_radio.priv = NULL; - usb_register(&usb_dsbr100_driver); - if (video_register_device(&usb_dsbr100_radio, VFL_TYPE_RADIO, - radio_nr)==-1) { + retval = usb_register(&usb_dsbr100_driver); + if (retval) + goto failed_usb_register; + retval = video_register_device(&usb_dsbr100_radio, VFL_TYPE_RADIO, + radio_nr); + if (retval) { warn("Couldn't register video device"); - return -EINVAL; + goto failed_video_register; } info(DRIVER_VERSION ":" DRIVER_DESC); return 0; +failed_video_register: + usb_deregister(&usb_dsbr100_driver); +failed_usb_register: + return retval; } static void __exit dsbr100_exit(void) diff --git a/drivers/usb/media/ov511.c b/drivers/usb/media/ov511.c index c1d6b2c710d2..cde6a020ad20 100644 --- a/drivers/usb/media/ov511.c +++ b/drivers/usb/media/ov511.c @@ -4592,7 +4592,7 @@ ov51x_v4l1_ioctl(struct inode *inode, struct file *file, return rc; } -static int +static ssize_t ov51x_v4l1_read(struct file *file, char *buf, size_t cnt, loff_t *ppos) { struct video_device *vdev = file->private_data; @@ -6115,13 +6115,16 @@ ov511_deregister_decomp_module(int ov518, int mmx) static int __init usb_ov511_init(void) { + int retval; - if (usb_register(&ov511_driver) < 0) - return -1; + retval = usb_register(&ov511_driver); + if (retval) + goto out; info(DRIVER_VERSION " : " DRIVER_DESC); - return 0; +out: + return retval; } static void __exit diff --git a/drivers/usb/media/pwc-if.c b/drivers/usb/media/pwc-if.c index 639b2802943a..9fe1ee6511f6 100644 --- a/drivers/usb/media/pwc-if.c +++ b/drivers/usb/media/pwc-if.c @@ -129,7 +129,7 @@ static struct { static int pwc_video_open(struct inode *inode, struct file *file); static int pwc_video_close(struct inode *inode, struct file *file); -static int pwc_video_read(struct file *file, char *buf, +static ssize_t pwc_video_read(struct file *file, char *buf, size_t count, loff_t *ppos); static unsigned int pwc_video_poll(struct file *file, poll_table *wait); static int pwc_video_ioctl(struct inode *inode, struct file *file, @@ -1116,7 +1116,7 @@ static int pwc_video_close(struct inode *inode, struct file *file) device is tricky anyhow. */ -static int pwc_video_read(struct file *file, char *buf, +static ssize_t pwc_video_read(struct file *file, char *buf, size_t count, loff_t *ppos) { struct video_device *vdev = file->private_data; @@ -1124,7 +1124,7 @@ static int pwc_video_read(struct file *file, char *buf, int noblock = file->f_flags & O_NONBLOCK; DECLARE_WAITQUEUE(wait, current); - Trace(TRACE_READ, "video_read(0x%p, %p, %d) called.\n", vdev, buf, count); + Trace(TRACE_READ, "video_read(0x%p, %p, %Zd) called.\n", vdev, buf, count); if (vdev == NULL) return -EFAULT; pdev = vdev->priv; diff --git a/drivers/usb/media/se401.c b/drivers/usb/media/se401.c index 9be1d6e76a75..88810cc91e58 100644 --- a/drivers/usb/media/se401.c +++ b/drivers/usb/media/se401.c @@ -30,16 +30,10 @@ static const char version[] = "0.24"; #include <linux/config.h> #include <linux/module.h> #include <linux/init.h> -#include <linux/fs.h> #include <linux/vmalloc.h> #include <linux/slab.h> -#include <linux/proc_fs.h> #include <linux/pagemap.h> #include <linux/usb.h> -#include <asm/io.h> -#include <asm/semaphore.h> -#include <linux/mm.h> - #include "se401.h" static int flickerless=0; @@ -126,131 +120,6 @@ static void rvfree(void *mem, unsigned long size) /**************************************************************************** * - * /proc interface - * - ***************************************************************************/ - -#warning please convert me from procfs to sysfs -#undef CONFIG_VIDEO_PROC_FS - -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) - -static struct proc_dir_entry *se401_proc_entry = NULL; -extern struct proc_dir_entry *video_proc_entry; - -#define YES_NO(x) ((x) ? "yes" : "no") - -static int se401_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - char *out = page; - int i, len; - struct usb_se401 *se401 = data; - - /* Stay under PAGE_SIZE or else bla bla bla.... */ - - out+=sprintf(out, "driver_version : %s\n", version); - out+=sprintf(out, "model : %s\n", se401->camera_name); - out+=sprintf(out, "in use : %s\n", YES_NO (se401->user)); - out+=sprintf(out, "streaming : %s\n", YES_NO (se401->streaming)); - out+=sprintf(out, "button state : %s\n", YES_NO (se401->button)); - out+=sprintf(out, "button pressed : %s\n", YES_NO (se401->buttonpressed)); - out+=sprintf(out, "num_frames : %d\n", SE401_NUMFRAMES); - - out+=sprintf(out, "Sizes :"); - for (i=0; i<se401->sizes; i++) { - out+=sprintf(out, " %dx%d", se401->width[i], - se401->height[i]); - } - out+=sprintf(out, "\n"); - - out+=sprintf(out, "Frames total : %d\n", se401->readcount); - out+=sprintf(out, "Frames read : %d\n", se401->framecount); - out+=sprintf(out, "Packets dropped : %d\n", se401->dropped); - out+=sprintf(out, "Decoding Errors : %d\n", se401->error); - - len = out - page; - len -= off; - if (len < count) { - *eof = 1; - if (len <= 0) - return 0; - } else - len = count; - - *start = page + off; - - return len; -} - -static int se401_write_proc(struct file *file, const char *buffer, - unsigned long count, void *data) -{ - return -EINVAL; -} - -static void create_proc_se401_cam (struct usb_se401 *se401) -{ - char name[7]; - struct proc_dir_entry *ent; - - if (!se401_proc_entry || !se401) - return; - - sprintf (name, "video%d", se401->vdev.minor); - - ent = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, - se401_proc_entry); - - if (!ent) - return; - - ent->data = se401; - ent->read_proc = se401_read_proc; - ent->write_proc = se401_write_proc; - se401->proc_entry = ent; -} - -static void destroy_proc_se401_cam (struct usb_se401 *se401) -{ - /* One to much, just to be sure :) */ - char name[9]; - - if (!se401 || !se401->proc_entry) - return; - - sprintf(name, "video%d", se401->vdev.minor); - remove_proc_entry(name, se401_proc_entry); - se401->proc_entry = NULL; -} - -static void proc_se401_create (void) -{ - if (video_proc_entry == NULL) { - err("/proc/video/ doesn't exist"); - return; - } - - se401_proc_entry=create_proc_entry("se401", S_IFDIR, video_proc_entry); - - if (se401_proc_entry) - se401_proc_entry->owner = THIS_MODULE; - else - err("Unable to initialize /proc/video/se401"); -} - -static void proc_se401_destroy(void) -{ - if (se401_proc_entry == NULL) - return; - - remove_proc_entry("se401", video_proc_entry); -} -#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */ - - -/**************************************************************************** - * * se401 register read/write functions * ***************************************************************************/ @@ -1252,7 +1121,7 @@ static int se401_ioctl(struct inode *inode, struct file *file, return video_usercopy(inode, file, cmd, arg, se401_do_ioctl); } -static int se401_read(struct file *file, char *buf, +static ssize_t se401_read(struct file *file, char *buf, size_t count, loff_t *ppos) { int realcount=count, ret=0; @@ -1517,9 +1386,6 @@ static int se401_probe(struct usb_interface *intf, err("video_register_device failed"); return -EIO; } -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) - create_proc_se401_cam(se401); -#endif info("registered new video device: video%d", se401->vdev.minor); usb_set_intfdata (intf, se401); @@ -1544,9 +1410,6 @@ static void se401_disconnect(struct usb_interface *intf) wake_up_interruptible(&se401->wq); se401->removed = 1; } -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) - destroy_proc_se401_cam(se401); -#endif } } @@ -1568,29 +1431,19 @@ static struct usb_driver se401_driver = { static int __init usb_se401_init(void) { -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) - proc_se401_create(); -#endif - info("SE401 usb camera driver version %s registering", version); if (flickerless) if (flickerless!=50 && flickerless!=60) { info("Invallid flickerless value, use 0, 50 or 60."); return -1; } - if (usb_register(&se401_driver) < 0) - return -1; - return 0; + return usb_register(&se401_driver); } static void __exit usb_se401_exit(void) { usb_deregister(&se401_driver); info("SE401 driver deregistered"); - -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) - proc_se401_destroy(); -#endif } module_init(usb_se401_init); diff --git a/drivers/usb/media/se401.h b/drivers/usb/media/se401.h index c8f97d089216..2e5846f1eb20 100644 --- a/drivers/usb/media/se401.h +++ b/drivers/usb/media/se401.h @@ -224,9 +224,6 @@ struct usb_se401 { wait_queue_head_t wq; /* Processes waiting */ - /* proc interface */ - struct proc_dir_entry *proc_entry; /* /proc/se401/videoX */ - int nullpackets; }; diff --git a/drivers/usb/media/stv680.c b/drivers/usb/media/stv680.c index b1d44efb72bb..0ebbb29549e7 100644 --- a/drivers/usb/media/stv680.c +++ b/drivers/usb/media/stv680.c @@ -61,14 +61,9 @@ #include <linux/config.h> #include <linux/module.h> #include <linux/init.h> -#include <linux/fs.h> #include <linux/vmalloc.h> #include <linux/slab.h> -#include <linux/proc_fs.h> #include <linux/pagemap.h> -#include <linux/smp_lock.h> -#include <linux/sched.h> -#include <linux/signal.h> #include <linux/errno.h> #include <linux/videodev.h> #include <linux/usb.h> @@ -515,124 +510,57 @@ exit: /***************** last of pencam routines *******************/ -/******************************************************************** - * /proc interface - *******************************************************************/ - -#warning please convert me from procfs to sysfs -#undef CONFIG_VIDEO_PROC_FS - -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) - -static struct proc_dir_entry *stv680_proc_entry = NULL; -extern struct proc_dir_entry *video_proc_entry; - -#define YES_NO(x) ((x) ? "yes" : "no") -#define ON_OFF(x) ((x) ? "(auto) on" : "(auto) off") - -static int stv680_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) +/**************************************************************************** + * sysfs + ***************************************************************************/ +static inline struct usb_stv *cd_to_stv(struct class_device *cd) { - char *out = page; - int len; - struct usb_stv *stv680 = data; - - /* Stay under PAGE_SIZE or else bla bla bla.... */ - - out += sprintf (out, "driver_version : %s\n", DRIVER_VERSION); - out += sprintf (out, "model : %s\n", stv680->camera_name); - out += sprintf (out, "in use : %s\n", YES_NO (stv680->user)); - out += sprintf (out, "streaming : %s\n", YES_NO (stv680->streaming)); - out += sprintf (out, "num_frames : %d\n", STV680_NUMFRAMES); - - out += sprintf (out, "Current size : %ix%i\n", stv680->vwidth, stv680->vheight); - if (swapRGB_on == 0) - out += sprintf (out, "swapRGB : %s\n", ON_OFF (swapRGB)); - else if (swapRGB_on == 1) - out += sprintf (out, "swapRGB : (forced) on\n"); - else if (swapRGB_on == -1) - out += sprintf (out, "swapRGB : (forced) off\n"); - - out += sprintf (out, "Palette : %i", stv680->palette); - - out += sprintf (out, "\n"); - - out += sprintf (out, "Frames total : %d\n", stv680->readcount); - out += sprintf (out, "Frames read : %d\n", stv680->framecount); - out += sprintf (out, "Packets dropped : %d\n", stv680->dropped); - out += sprintf (out, "Decoding Errors : %d\n", stv680->error); - - len = out - page; - len -= off; - if (len < count) { - *eof = 1; - if (len <= 0) - return 0; - } else - len = count; - - *start = page + off; - return len; + struct video_device *vdev = to_video_device(cd); + return video_get_drvdata(vdev); } -static int create_proc_stv680_cam (struct usb_stv *stv680) +#define stv680_file(name, variable, field) \ +static ssize_t show_##name(struct class_device *class_dev, char *buf) \ +{ \ + struct video_device *vdev = to_video_device(class_dev); \ + struct usb_stv *stv = video_get_drvdata(vdev); \ + return sprintf(buf, field, stv->variable); \ +} \ +static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); + +stv680_file(model, camera_name, "%s\n"); +stv680_file(in_use, user, "%d\n"); +stv680_file(streaming, streaming, "%d\n"); +stv680_file(palette, palette, "%i\n"); +stv680_file(frames_total, readcount, "%d\n"); +stv680_file(frames_read, framecount, "%d\n"); +stv680_file(packets_dropped, dropped, "%d\n"); +stv680_file(decoding_errors, error, "%d\n"); + +static void stv680_create_sysfs_files(struct video_device *vdev) { - char name[9]; - struct proc_dir_entry *ent; - - if (!stv680_proc_entry || !stv680) - return -1; - - sprintf (name, "video%d", stv680->vdev.minor); - - ent = create_proc_entry (name, S_IFREG | S_IRUGO | S_IWUSR, stv680_proc_entry); - if (!ent) - return -1; - - ent->data = stv680; - ent->read_proc = stv680_read_proc; - stv680->proc_entry = ent; - return 0; + video_device_create_file(vdev, &class_device_attr_model); + video_device_create_file(vdev, &class_device_attr_in_use); + video_device_create_file(vdev, &class_device_attr_streaming); + video_device_create_file(vdev, &class_device_attr_palette); + video_device_create_file(vdev, &class_device_attr_frames_total); + video_device_create_file(vdev, &class_device_attr_frames_read); + video_device_create_file(vdev, &class_device_attr_packets_dropped); + video_device_create_file(vdev, &class_device_attr_decoding_errors); } -static void destroy_proc_stv680_cam (struct usb_stv *stv680) +static void stv680_remove_sysfs_files(struct video_device *vdev) { - /* One to much, just to be sure :) */ - char name[9]; - - if (!stv680 || !stv680->proc_entry) - return; - - sprintf (name, "video%d", stv680->vdev.minor); - remove_proc_entry (name, stv680_proc_entry); - stv680->proc_entry = NULL; + video_device_remove_file(vdev, &class_device_attr_model); + video_device_remove_file(vdev, &class_device_attr_in_use); + video_device_remove_file(vdev, &class_device_attr_streaming); + video_device_remove_file(vdev, &class_device_attr_palette); + video_device_remove_file(vdev, &class_device_attr_frames_total); + video_device_remove_file(vdev, &class_device_attr_frames_read); + video_device_remove_file(vdev, &class_device_attr_packets_dropped); + video_device_remove_file(vdev, &class_device_attr_decoding_errors); } -static int proc_stv680_create (void) -{ - if (video_proc_entry == NULL) { - PDEBUG (0, "STV(e): /proc/video/ doesn't exist!"); - return -1; - } - stv680_proc_entry = create_proc_entry ("stv680", S_IFDIR, video_proc_entry); - - if (stv680_proc_entry) { - stv680_proc_entry->owner = THIS_MODULE; - } else { - PDEBUG (0, "STV(e): Unable to initialize /proc/video/stv680"); - return -1; - } - return 0; -} - -static void proc_stv680_destroy (void) -{ - if (stv680_proc_entry == NULL) - return; - - remove_proc_entry ("stv680", video_proc_entry); -} -#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */ - /******************************************************************** * Camera control *******************************************************************/ @@ -1123,7 +1051,7 @@ static int stv680_newframe (struct usb_stv *stv680, int framenr) static int stv_open (struct inode *inode, struct file *file) { struct video_device *dev = video_devdata(file); - struct usb_stv *stv680 = (struct usb_stv *) dev; + struct usb_stv *stv680 = video_get_drvdata(dev); int err = 0; /* we are called with the BKL held */ @@ -1147,7 +1075,7 @@ static int stv_open (struct inode *inode, struct file *file) static int stv_close (struct inode *inode, struct file *file) { struct video_device *dev = file->private_data; - struct usb_stv *stv680 = (struct usb_stv *) dev; + struct usb_stv *stv680 = video_get_drvdata(dev); int i; for (i = 0; i < STV680_NUMFRAMES; i++) @@ -1174,7 +1102,7 @@ static int stv680_do_ioctl (struct inode *inode, struct file *file, unsigned int cmd, void *arg) { struct video_device *vdev = file->private_data; - struct usb_stv *stv680 = (struct usb_stv *) vdev; + struct usb_stv *stv680 = video_get_drvdata(vdev); if (!stv680->udev) return -EIO; @@ -1350,7 +1278,7 @@ static int stv680_ioctl(struct inode *inode, struct file *file, static int stv680_mmap (struct file *file, struct vm_area_struct *vma) { struct video_device *dev = file->private_data; - struct usb_stv *stv680 = (struct usb_stv *) dev; + struct usb_stv *stv680 = video_get_drvdata(dev); unsigned long start = vma->vm_start; unsigned long size = vma->vm_end-vma->vm_start; unsigned long page, pos; @@ -1385,13 +1313,13 @@ static int stv680_mmap (struct file *file, struct vm_area_struct *vma) return 0; } -static int stv680_read (struct file *file, char *buf, +static ssize_t stv680_read (struct file *file, char *buf, size_t count, loff_t *ppos) { struct video_device *dev = file->private_data; unsigned long int realcount = count; int ret = 0; - struct usb_stv *stv680 = (struct usb_stv *) dev; + struct usb_stv *stv680 = video_get_drvdata(dev); unsigned long int i; if (STV680_NUMFRAMES != 2) { @@ -1448,14 +1376,17 @@ static struct video_device stv680_template = { .type = VID_TYPE_CAPTURE, .hardware = VID_HARDWARE_SE401, .fops = &stv680_fops, + .release = video_device_release, + .minor = -1, }; static int stv680_probe (struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev(intf); struct usb_host_interface *interface; - struct usb_stv *stv680; + struct usb_stv *stv680 = NULL; char *camera_name = NULL; + int retval = 0; /* We don't handle multi-config cameras */ if (dev->descriptor.bNumConfigurations != 1) { @@ -1471,12 +1402,14 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id } else { PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 values."); PDEBUG (0, "STV(e): Check that the STV0680 camera is connected to the computer."); - return -ENODEV; + retval = -ENODEV; + goto error; } /* We found one */ if ((stv680 = kmalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) { PDEBUG (0, "STV(e): couldn't kmalloc stv680 struct."); - return -ENOMEM; + retval = -ENOMEM; + goto error; } memset (stv680, 0, sizeof (*stv680)); @@ -1484,24 +1417,34 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id stv680->udev = dev; stv680->camera_name = camera_name; - memcpy (&stv680->vdev, &stv680_template, sizeof (stv680_template)); - memcpy (stv680->vdev.name, stv680->camera_name, strlen (stv680->camera_name)); + stv680->vdev = video_device_alloc(); + if (!stv680->vdev) { + retval = -ENOMEM; + goto error; + } + memcpy(stv680->vdev, &stv680_template, sizeof(stv680_template)); + stv680->vdev->dev = &intf->dev; + video_set_drvdata(stv680->vdev, stv680); + + memcpy (stv680->vdev->name, stv680->camera_name, strlen (stv680->camera_name)); init_waitqueue_head (&stv680->wq); init_MUTEX (&stv680->lock); wmb (); - if (video_register_device (&stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { - kfree (stv680); + if (video_register_device (stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { PDEBUG (0, "STV(e): video_register_device failed"); - return -EIO; + retval = -EIO; + goto error; } -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) - create_proc_stv680_cam (stv680); -#endif - PDEBUG (0, "STV(i): registered new video device: video%d", stv680->vdev.minor); + PDEBUG (0, "STV(i): registered new video device: video%d", stv680->vdev->minor); usb_set_intfdata (intf, stv680); + stv680_create_sysfs_files(stv680->vdev); return 0; + +error: + kfree(stv680); + return retval; } static inline void usb_stv680_remove_disconnected (struct usb_stv *stv680) @@ -1528,9 +1471,6 @@ static inline void usb_stv680_remove_disconnected (struct usb_stv *stv680) } PDEBUG (0, "STV(i): %s disconnected", stv680->camera_name); -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) - destroy_proc_stv680_cam (stv680); -#endif /* Free the memory */ kfree (stv680); } @@ -1543,7 +1483,11 @@ static void stv680_disconnect (struct usb_interface *intf) if (stv680) { /* We don't want people trying to open up the device */ - video_unregister_device (&stv680->vdev); + if (stv680->vdev) { + stv680_remove_sysfs_files(stv680->vdev); + video_unregister_device(stv680->vdev); + stv680->vdev = NULL; + } if (!stv680->user) { usb_stv680_remove_disconnected (stv680); } else { @@ -1566,10 +1510,6 @@ static struct usb_driver stv680_driver = { static int __init usb_stv680_init (void) { -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) - if (proc_stv680_create () < 0) - return -1; -#endif if (usb_register (&stv680_driver) < 0) { PDEBUG (0, "STV(e): Could not setup STV0680 driver"); return -1; @@ -1584,10 +1524,6 @@ static void __exit usb_stv680_exit (void) { usb_deregister (&stv680_driver); PDEBUG (0, "STV(i): driver deregistered"); - -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) - proc_stv680_destroy (); -#endif } module_init (usb_stv680_init); diff --git a/drivers/usb/media/stv680.h b/drivers/usb/media/stv680.h index a1de6a4ecf73..7e0e314dcf12 100644 --- a/drivers/usb/media/stv680.h +++ b/drivers/usb/media/stv680.h @@ -89,7 +89,7 @@ struct stv680_frame { /* this is almost the video structure uvd_t, with extra parameters for stv */ struct usb_stv { - struct video_device vdev; + struct video_device *vdev; struct usb_device *udev; @@ -142,7 +142,6 @@ struct usb_stv { wait_queue_head_t wq; /* Processes waiting */ - struct proc_dir_entry *proc_entry; /* /proc/stv680/videoX */ int nullpackets; }; diff --git a/drivers/usb/media/usbvideo.c b/drivers/usb/media/usbvideo.c index a0745a30e499..d74858de9ce2 100644 --- a/drivers/usb/media/usbvideo.c +++ b/drivers/usb/media/usbvideo.c @@ -37,24 +37,9 @@ static int video_nr = -1; MODULE_PARM(video_nr, "i"); -#warning please convert me from procfs to sysfs -#define USES_PROC_FS 0 /* * Local prototypes. */ -#if USES_PROC_FS -static void usbvideo_procfs_level1_create(struct usbvideo *ut); -static void usbvideo_procfs_level1_destroy(struct usbvideo *ut); -static void usbvideo_procfs_level2_create(struct uvd *uvd); -static void usbvideo_procfs_level2_destroy(struct uvd *uvd); -static int usbvideo_default_procfs_read_proc( - char *page, char **start, off_t off, int count, - int *eof, void *data); -static int usbvideo_default_procfs_write_proc( - struct file *file, const char *buffer, - unsigned long count, void *data); -#endif - static void usbvideo_Disconnect(struct usb_interface *intf); static void usbvideo_CameraRelease(struct uvd *uvd); @@ -813,24 +798,7 @@ int usbvideo_register( cams->cb.startDataPump = usbvideo_StartDataPump; if (cams->cb.stopDataPump == NULL) cams->cb.stopDataPump = usbvideo_StopDataPump; -#if USES_PROC_FS - /* - * If both /proc fs callbacks are NULL then we assume that the driver - * does not need procfs services at all. Leave them NULL. - */ - cams->uses_procfs = (cams->cb.procfs_read != NULL) || (cams->cb.procfs_write == NULL); - if (cams->uses_procfs) { - if (cams->cb.procfs_read == NULL) - cams->cb.procfs_read = usbvideo_default_procfs_read_proc; - if (cams->cb.procfs_write == NULL) - cams->cb.procfs_write = usbvideo_default_procfs_write_proc; - } -#else /* !USES_PROC_FS */ - /* Report a warning so that user knows why there is no /proc entries */ - if ((cams->cb.procfs_read != NULL) || (cams->cb.procfs_write == NULL)) { - dbg("%s: /proc fs support requested but not configured!", __FUNCTION__); - } -#endif + cams->num_cameras = num_cams; cams->cam = (struct uvd *) &cams[1]; cams->md_module = md; @@ -871,13 +839,6 @@ int usbvideo_register( cams->usbdrv.disconnect = cams->cb.disconnect; cams->usbdrv.id_table = id_table; -#if USES_PROC_FS - if (cams->uses_procfs) { - dbg("%s: Creating /proc filesystem entries.", __FUNCTION__); - usbvideo_procfs_level1_create(cams); - } -#endif - /* * Update global handle to usbvideo. This is very important * because probe() can be called before usb_register() returns. @@ -920,13 +881,6 @@ void usbvideo_Deregister(struct usbvideo **pCams) return; } -#if USES_PROC_FS - if (cams->uses_procfs) { - dbg("%s: Deregistering filesystem entries.", __FUNCTION__); - usbvideo_procfs_level1_destroy(cams); - } -#endif - dbg("%s: Deregistering %s driver.", __FUNCTION__, cams->drvName); usb_deregister(&cams->usbdrv); @@ -1041,14 +995,6 @@ static void usbvideo_CameraRelease(struct uvd *uvd) return; } -#if USES_PROC_FS - assert(uvd->handle != NULL); - if (uvd->handle->uses_procfs) { - dbg("%s: Removing /proc/%s/ filesystem entries.", __FUNCTION__, uvd->handle->drvName); - usbvideo_procfs_level2_destroy(uvd); - } -#endif - RingQueue_Free(&uvd->dp); if (VALID_CALLBACK(uvd, userFree)) GET_CALLBACK(uvd, userFree)(uvd); @@ -1200,17 +1146,6 @@ int usbvideo_RegisterVideoDevice(struct uvd *uvd) (uvd->handle != NULL) ? uvd->handle->drvName : "???", uvd->vdev.minor, tmp2, tmp1); -#if USES_PROC_FS - assert(uvd->handle != NULL); - if (uvd->handle->uses_procfs) { - if (uvd->debug > 0) { - info("%s: Creating /proc/video/%s/ filesystem entries.", - __FUNCTION__, uvd->handle->drvName); - } - usbvideo_procfs_level2_create(uvd); - } -#endif - usb_get_dev(uvd->dev); return 0; } @@ -1665,7 +1600,7 @@ static ssize_t usbvideo_v4l_read(struct file *file, char *buf, return -EFAULT; if (uvd->debug >= 1) - info("%s: %d. bytes, noblock=%d.", __FUNCTION__, count, noblock); + info("%s: %Zd. bytes, noblock=%d.", __FUNCTION__, count, noblock); down(&uvd->lock); @@ -1783,7 +1718,7 @@ static ssize_t usbvideo_v4l_read(struct file *file, char *buf, /* Update last read position */ frame->seqRead_Index += count; if (uvd->debug >= 1) { - err("%s: {copy} count used=%d, new seqRead_Index=%ld", + err("%s: {copy} count used=%Zd, new seqRead_Index=%ld", __FUNCTION__, count, frame->seqRead_Index); } @@ -2345,130 +2280,4 @@ static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd, } } -/* - * /proc interface - * - * We will be creating directories and entries under /proc/video using - * external 'video_proc_entry' directory which is exported by videodev.o - * module. Within that directory we will create $driver/ directory to - * uniquely and uniformly refer to our specific $driver. Within that - * directory we will finally create an entry that is named after the - * video device node - video3, for example. The format of that file - * is determined by callbacks that the minidriver may provide. If no - * callbacks are provided (neither read nor write) then we don't create - * the entry. - * - * Here is a sample directory entry: /proc/video/ibmcam/video3 - * - * The "file" video3 (in example above) is readable and writeable, in - * theory. If the minidriver provides callbacks to do reading and - * writing then both those procedures are supported. However if the - * driver leaves callbacks in default (NULL) state the default - * read and write handlers are used. The default read handler reports - * that the driver does not support /proc fs. The default write handler - * returns error code on any write attempt. - */ - -#if USES_PROC_FS - -extern struct proc_dir_entry *video_proc_entry; - -static void usbvideo_procfs_level1_create(struct usbvideo *ut) -{ - if (ut == NULL) { - err("%s: ut == NULL", __FUNCTION__); - return; - } - if (video_proc_entry == NULL) { - err("%s: /proc/video/ doesn't exist.", __FUNCTION__); - return; - } - ut->procfs_dEntry = create_proc_entry(ut->drvName, S_IFDIR, video_proc_entry); - if (ut->procfs_dEntry != NULL) { - if (ut->md_module != NULL) - ut->procfs_dEntry->owner = ut->md_module; - } else { - err("%s: Unable to initialize /proc/video/%s", __FUNCTION__, ut->drvName); - } -} - -static void usbvideo_procfs_level1_destroy(struct usbvideo *ut) -{ - if (ut == NULL) { - err("%s: ut == NULL", __FUNCTION__); - return; - } - if (ut->procfs_dEntry != NULL) { - remove_proc_entry(ut->drvName, video_proc_entry); - ut->procfs_dEntry = NULL; - } -} - -static void usbvideo_procfs_level2_create(struct uvd *uvd) -{ - if (uvd == NULL) { - err("%s: uvd == NULL", __FUNCTION__); - return; - } - assert(uvd->handle != NULL); - if (uvd->handle->procfs_dEntry == NULL) { - err("%s: uvd->handle->procfs_dEntry == NULL", __FUNCTION__); - return; - } - - sprintf(uvd->videoName, "video%d", uvd->vdev.minor); - uvd->procfs_vEntry = create_proc_entry( - uvd->videoName, - S_IFREG | S_IRUGO | S_IWUSR, - uvd->handle->procfs_dEntry); - if (uvd->procfs_vEntry != NULL) { - uvd->procfs_vEntry->data = uvd; - uvd->procfs_vEntry->read_proc = uvd->handle->cb.procfs_read; - uvd->procfs_vEntry->write_proc = uvd->handle->cb.procfs_write; - } else { - err("%s: Failed to create entry \"%s\"", __FUNCTION__, uvd->videoName); - } -} - -static void usbvideo_procfs_level2_destroy(struct uvd *uvd) -{ - if (uvd == NULL) { - err("%s: uvd == NULL", __FUNCTION__); - return; - } - if (uvd->procfs_vEntry != NULL) { - remove_proc_entry(uvd->videoName, uvd->procfs_vEntry); - uvd->procfs_vEntry = NULL; - } -} - -static int usbvideo_default_procfs_read_proc( - char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - char *out = page; - int len; - - /* Stay under PAGE_SIZE or else */ - out += sprintf(out, "This driver does not support /proc services.\n"); - len = out - page; - len -= off; - if (len < count) { - *eof = 1; - if (len <= 0) - return 0; - } else - len = count; - *start = page + off; - return len; -} - -static int usbvideo_default_procfs_write_proc( - struct file *file, const char *buffer, - unsigned long count, void *data) -{ - return -EINVAL; -} - -#endif /* USES_PROC_FS */ MODULE_LICENSE("GPL"); diff --git a/drivers/usb/media/usbvideo.h b/drivers/usb/media/usbvideo.h index 091ac84e1058..6c390a1f981b 100644 --- a/drivers/usb/media/usbvideo.h +++ b/drivers/usb/media/usbvideo.h @@ -17,14 +17,12 @@ #define usbvideo_h #include <linux/config.h> -#include <linux/proc_fs.h> #include <linux/videodev.h> #include <linux/usb.h> /* Most helpful debugging aid */ #define assert(expr) ((void) ((expr) ? 0 : (err("assert failed at line %d",__LINE__)))) -#define USES_PROC_FS (defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)) #define USBVIDEO_REPORT_STATS 1 /* Set to 0 to block statistics on close */ /* Bit flags (options) */ @@ -244,7 +242,6 @@ struct uvd { struct video_capability vcap; /* Video capabilities */ struct video_channel vchan; /* May be used for tuner support */ struct usbvideo_statistics stats; - struct proc_dir_entry *procfs_vEntry; /* /proc/video/MYDRIVER/video2 */ char videoName[32]; /* Holds name like "video7" */ }; @@ -266,8 +263,6 @@ struct usbvideo_cb { int (*getFPS)(struct uvd *); int (*overlayHook)(struct uvd *, struct usbvideo_frame *); int (*getFrame)(struct uvd *, int); - int (*procfs_read)(char *page,char **start,off_t off,int count,int *eof,void *data); - int (*procfs_write)(struct file *file,const char *buffer,unsigned long count,void *data); int (*startDataPump)(struct uvd *uvd); void (*stopDataPump)(struct uvd *uvd); int (*setVideoMode)(struct uvd *uvd, struct video_window *vw); @@ -281,8 +276,6 @@ struct usbvideo { struct usbvideo_cb cb; /* Table of callbacks (virtual methods) */ struct video_device vdt; /* Video device template */ struct uvd *cam; /* Array of camera structures */ - int uses_procfs; /* Non-zero if we create /proc entries */ - struct proc_dir_entry *procfs_dEntry; /* /proc/video/MYDRIVER */ struct module *md_module; /* Minidriver module */ }; diff --git a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c index 5fb2f3966286..eb3394eec2b1 100644 --- a/drivers/usb/media/vicam.c +++ b/drivers/usb/media/vicam.c @@ -1388,11 +1388,13 @@ vicam_disconnect(struct usb_interface *intf) static int __init usb_vicam_init(void) { + int retval; DBG(KERN_INFO "ViCam-based WebCam driver startup\n"); vicam_create_proc_root(); - if (usb_register(&vicam_driver) != 0) + retval = usb_register(&vicam_driver); + if (retval) printk(KERN_WARNING "usb_register failed!\n"); - return 0; + return retval; } static void __exit diff --git a/drivers/usb/misc/brlvger.c b/drivers/usb/misc/brlvger.c index 3ad25fb4e294..353eb125582c 100644 --- a/drivers/usb/misc/brlvger.c +++ b/drivers/usb/misc/brlvger.c @@ -249,17 +249,20 @@ static struct usb_driver brlvger_driver = static int __init brlvger_init (void) { + int retval; printk(BANNER); if(stall_tries < 1 || write_repeats < 1) return -EINVAL; - if (usb_register(&brlvger_driver)) { + retval = usb_register(&brlvger_driver); + if (retval) { err("USB registration failed"); - return -ENOSYS; + goto out; } - return 0; +out: + return retval; } static void diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c index 8c1f86f35f0a..e90a334f7287 100644 --- a/drivers/usb/misc/rio500.c +++ b/drivers/usb/misc/rio500.c @@ -33,7 +33,6 @@ #include <linux/signal.h> #include <linux/sched.h> #include <linux/errno.h> -#include <linux/miscdevice.h> #include <linux/random.h> #include <linux/poll.h> #include <linux/init.h> @@ -531,12 +530,15 @@ static struct usb_driver rio_driver = { static int __init usb_rio_init(void) { - if (usb_register(&rio_driver) < 0) - return -1; + int retval; + retval = usb_register(&rio_driver); + if (retval) + goto out; info(DRIVER_VERSION ":" DRIVER_DESC); - return 0; +out: + return retval; } diff --git a/drivers/usb/misc/tiglusb.c b/drivers/usb/misc/tiglusb.c index c77d60ed51b4..5ee81f7d9577 100644 --- a/drivers/usb/misc/tiglusb.c +++ b/drivers/usb/misc/tiglusb.c @@ -24,7 +24,6 @@ #include <linux/module.h> #include <linux/socket.h> -#include <linux/miscdevice.h> #include <linux/slab.h> #include <linux/init.h> #include <asm/uaccess.h> diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c index 2d83f587e8e6..9ff010f1a93b 100644 --- a/drivers/usb/misc/usblcd.c +++ b/drivers/usb/misc/usblcd.c @@ -342,18 +342,21 @@ static struct usb_driver lcd_driver = { .id_table = id_table, }; -int usb_lcd_init(void) +static int __init usb_lcd_init(void) { - if (usb_register(&lcd_driver) < 0) - return -1; + int retval; + retval = usb_register(&lcd_driver); + if (retval) + goto out; info("%s (C) Adams IT Services http://www.usblcd.de", DRIVER_VERSION); info("USBLCD support registered."); - return 0; +out: + return retval; } -void usb_lcd_cleanup(void) +static void __exit usb_lcd_cleanup(void) { struct lcd_usb_data *lcd = &lcd_instance; diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 652a4028f517..82e90c3614e9 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -435,7 +435,7 @@ static int is_good_config (char *buf, int len) return 0; } - le32_to_cpus (&config->wTotalLength); + le16_to_cpus (&config->wTotalLength); if (config->wTotalLength == len) /* read it all */ return 1; return config->wTotalLength >= TBUF_SIZE; /* max partial read */ diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c index 18b37c9e3394..12b36214308d 100644 --- a/drivers/usb/misc/uss720.c +++ b/drivers/usb/misc/uss720.c @@ -653,11 +653,14 @@ MODULE_LICENSE("GPL"); static int __init uss720_init(void) { - if (usb_register(&uss720_driver) < 0) - return -1; + int retval; + retval = usb_register(&uss720_driver); + if (retval) + goto out; info(DRIVER_VERSION ":" DRIVER_DESC); - return 0; +out: + return retval; } static void __exit uss720_cleanup(void) diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig index 6711a8364525..028b3f9c468e 100644 --- a/drivers/usb/net/Kconfig +++ b/drivers/usb/net/Kconfig @@ -7,7 +7,7 @@ comment "USB Network adaptors" comment "Networking support is needed for USB Networking device support" depends on USB && !NET -config USB_AX8817X +config USB_AX8817X_STANDALONE tristate "USB ASIX AX8817X Ethernet device support (EXPERIMENTAL)" depends on USB && NET && EXPERIMENTAL ---help--- @@ -121,15 +121,15 @@ config USB_RTL8150 module, say M here and read <file:Documentation/modules.txt>. config USB_USBNET - tristate "Host-to-Host Networking for Cables and Smart Devices" + tristate "Multi-purpose USB Networking Framework" depends on USB && NET ---help--- This driver supports several kinds of network links over USB, with "minidrivers" built around a common network driver core - that supports deep queues for efficient transfers. - - Typically, these links involves only two network hosts. The - host runs "usbnet", and the other end of the link might be: + that supports deep queues for efficient transfers. (This gives + better performance with small packets and at high speeds). + + The USB host runs "usbnet", and the other end of the link might be: - Another USB host, when using USB "network" or "data transfer" cables. These are often used to network laptops to PCs, like @@ -141,6 +141,9 @@ config USB_USBNET others), and devices that interoperate using the standard CDC-Ethernet specification (including many cable modems). + - Network adapter hardware (like those for 10/100 Ethernet) which + uses this driver framework. + The link will appear with a name like "usb0", when the link is a two-node link, or "eth0" for most CDC-Ethernet devices. Those two-node links are most easily managed with Ethernet Bridging @@ -266,3 +269,29 @@ config USB_CDCETHER IEEE 802 "local assignment" bit is set in the address, a "usbX" name is used instead. +comment "USB Network Adapters" + depends on USB_USBNET + +config USB_AX8817X + boolean "ASIX AX88172 Based USB 2.0 Ethernet Devices" + depends on USB_USBNET && EXPERIMENTAL + default y + help + + This option adds support for ASIX AX88172 based USB 2.0 + 10/100 Ethernet devices. + + This driver should work with at least the following devices: + * ASIX AX88172 + * D-Link DUB-E100 + * Hawking UF200 + * Linksys USB200M + * Netgear FA120 + * Intellinet + * ST Lab USB Ethernet + * TrendNet TU2-ET100 + + This driver creates an interface named "ethX", where X depends on + what other networking devices you have in use. + + diff --git a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile index dde3b3e8cfd7..3956f8655d7d 100644 --- a/drivers/usb/net/Makefile +++ b/drivers/usb/net/Makefile @@ -2,7 +2,7 @@ # Makefile for USB Network drivers # -obj-$(CONFIG_USB_AX8817X) += ax8817x.o +obj-$(CONFIG_USB_AX8817X_STANDALONE) += ax8817x.o obj-$(CONFIG_USB_CATC) += catc.o obj-$(CONFIG_USB_KAWETH) += kaweth.o obj-$(CONFIG_USB_PEGASUS) += pegasus.o diff --git a/drivers/usb/net/Makefile.mii b/drivers/usb/net/Makefile.mii index 30885e3f4639..34c2f5585d10 100644 --- a/drivers/usb/net/Makefile.mii +++ b/drivers/usb/net/Makefile.mii @@ -4,3 +4,4 @@ obj-$(CONFIG_USB_AX8817X) += mii.o obj-$(CONFIG_USB_PEGASUS) += mii.o +obj-$(CONFIG_USB_USBNET) += mii.o diff --git a/drivers/usb/net/ax8817x.c b/drivers/usb/net/ax8817x.c index e51336b7ceb0..e73ba35f691c 100644 --- a/drivers/usb/net/ax8817x.c +++ b/drivers/usb/net/ax8817x.c @@ -75,7 +75,6 @@ #include <linux/mii.h> #include <linux/crc32.h> #include <asm/uaccess.h> -#include <linux/version.h> /* Version Information */ #define DRIVER_VERSION "v2.0.2" diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 6f197ad3588b..ed8dac545173 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -1,7 +1,9 @@ /* - * USB Host-to-Host Links - * Copyright (C) 2000-2002 by David Brownell <dbrownell@users.sourceforge.net> + * USB Networking Links + * Copyright (C) 2000-2003 by David Brownell <dbrownell@users.sourceforge.net> * Copyright (C) 2002 Pavel Machek <pavel@ucw.cz> + * Copyright (C) 2003 David Hollis <dhollis@davehollis.com> + * Copyright (c) 2002-2003 TiVo Inc. * * 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 @@ -19,63 +21,38 @@ */ /* - * This is used for "USB networking", connecting USB hosts as peers. - * - * It can be used with USB "network cables", for IP-over-USB communications; - * Ethernet speeds without the Ethernet. USB devices (including some PDAs) - * can support such links directly, replacing device-specific protocols - * with Internet standard ones. - * - * The links can be bridged using the Ethernet bridging (net/bridge) - * support as appropriate. Devices currently supported include: + * This is a generic "USB networking" framework that works with several + * kinds of full and high speed networking devices: * + * + USB host-to-host "network cables", used for IP-over-USB links. + * These are often used for Laplink style connectivity products. * - AnchorChip 2720 * - Belkin, eTEK (interops with Win32 drivers) - * - EPSON USB clients * - GeneSys GL620USB-A * - NetChip 1080 (interoperates with NetChip Win32 drivers) * - Prolific PL-2301/2302 (replaces "plusb" driver) - * - PXA-250 or SA-1100 Linux PDAs like iPaq, Yopy, and Zaurus - * - * USB devices can implement their side of this protocol at the cost - * of two bulk endpoints; it's not restricted to "cable" applications. - * See the SA1110, Zaurus, or EPSON device/client support in this driver; - * slave/target drivers such as "usb-eth" (on most SA-1100 PDAs) are - * used inside USB slave/target devices. - * - * - * Status: - * - * - AN2720 ... not widely available, but reportedly works well * - * - Belkin/eTEK ... no known issues + * + Smart USB devices can support such links directly, using Internet + * standard protocols instead of proprietary host-to-device links. + * - Linux PDAs like iPaq, Yopy, and Zaurus + * - The BLOB boot loader (for diskless booting) + * - Linux "gadgets", perhaps using PXA-2xx or Net2280 controllers + * - Devices using EPSON's sample USB firmware + * - CDC-Ethernet class devices, such as many cable modems * - * - Both GeneSys and PL-230x use interrupt transfers for driver-to-driver - * handshaking; it'd be worth implementing those as "carrier detect". - * Prefer generic hooks, not minidriver-specific hacks. + * + Adapters to networks such as Ethernet. + * - AX8817X based USB 2.0 products * - * - For Netchip, should use keventd to poll via control requests to detect - * hardware level "carrier detect". + * Links to these devices can be bridged using Linux Ethernet bridging. + * With minor exceptions, these all use similar USB framing for network + * traffic, but need different protocols for control traffic. * - * - PL-230x ... the initialization protocol doesn't seem to match chip data - * sheets, sometimes it's not needed and sometimes it hangs. Prolific has - * not responded to repeated support/information requests. - * - * - SA-1100 PDAs ... the standard ARM Linux SA-1100 support works nicely, - * as found in www.handhelds.org and other kernels. The Sharp/Lineo - * kernels use different drivers, which also talk to this code. - * - * Interop with more Win32 drivers may be a good thing. - * - * Seems like reporting "peer connected" (carrier present) events may end - * up going through the netlink event system, not hotplug ... so new links - * would likely be handled with a link monitoring thread in some daemon. - * - * There are reports that bridging gives lower-than-usual throughput. - * - * Need smarter hotplug policy scripts ... ones that know how to arrange - * bridging with "brctl", and can handle static and dynamic ("pump") setups. - * Use those eventual "peer connected" events, and zeroconf. + * USB devices can implement their side of this protocol at the cost + * of two bulk endpoints; it's not restricted to "cable" applications. + * See the SA1110, Zaurus, or EPSON device/client support in this driver; + * slave/target drivers such as "usb-eth" (on most SA-1100 PDAs) or + * "g_ether" (in the Linux "gadget" framework) implement that behavior + * within devices. * * * CHANGELOG: @@ -126,6 +103,7 @@ * vs pxa25x, and CDC Ethernet. Throttle down log floods on * disconnect; other cleanups. (db) Flush net1080 fifos * after several sequential framing errors. (Johannes Erdfelt) + * 22-aug-2003 AX8817X support (Dave Hollis). * *-------------------------------------------------------------------------*/ @@ -139,9 +117,11 @@ #include <linux/random.h> #include <linux/ethtool.h> #include <linux/workqueue.h> +#include <linux/mii.h> #include <asm/uaccess.h> #include <asm/unaligned.h> + // #define DEBUG // error path messages, extra info // #define VERBOSE // more; success messages #define REALLY_QUEUE @@ -157,7 +137,7 @@ #include <linux/dma-mapping.h> -#define DRIVER_VERSION "25-Apr-2003" +#define DRIVER_VERSION "25-Aug-2003" /*-------------------------------------------------------------------------*/ @@ -218,6 +198,8 @@ struct usbnet { int msg_level; unsigned long data [5]; + struct mii_if_info mii; + // various kinds of pending driver work struct sk_buff_head rxq; struct sk_buff_head txq; @@ -399,6 +381,275 @@ static const struct driver_info an2720_info = { #endif /* CONFIG_USB_AN2720 */ + +#ifdef CONFIG_USB_AX8817X +#define NEED_MII +/* ASIX AX8817X based USB 2.0 Ethernet Devices */ + +#define HAVE_HARDWARE + +#include <linux/crc32.h> + +#define AX_CMD_SET_SW_MII 0x06 +#define AX_CMD_READ_MII_REG 0x07 +#define AX_CMD_WRITE_MII_REG 0x08 +#define AX_CMD_SET_HW_MII 0x0a +#define AX_CMD_WRITE_RX_CTL 0x10 +#define AX_CMD_READ_IPG012 0x11 +#define AX_CMD_WRITE_IPG0 0x12 +#define AX_CMD_WRITE_IPG1 0x13 +#define AX_CMD_WRITE_IPG2 0x14 +#define AX_CMD_WRITE_MULTI_FILTER 0x16 +#define AX_CMD_READ_NODE_ID 0x17 +#define AX_CMD_READ_PHY_ID 0x19 +#define AX_CMD_WRITE_MEDIUM_MODE 0x1b +#define AX_CMD_WRITE_GPIOS 0x1f + +#define AX_MCAST_FILTER_SIZE 8 +#define AX_MAX_MCAST 64 + +static int ax8817x_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, + u16 size, void *data) +{ + return usb_control_msg( + dev->udev, + usb_rcvctrlpipe(dev->udev, 0), + cmd, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, + index, + data, + size, + CONTROL_TIMEOUT_JIFFIES); +} + +static int ax8817x_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, + u16 size, void *data) +{ + return usb_control_msg( + dev->udev, + usb_sndctrlpipe(dev->udev, 0), + cmd, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, + index, + data, + size, + CONTROL_TIMEOUT_JIFFIES); +} + +static void ax8817x_async_cmd_callback(struct urb *urb, struct pt_regs *regs) +{ + struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; + + if (urb->status < 0) + printk(KERN_DEBUG "ax8817x_async_cmd_callback() failed with %d", + urb->status); + + kfree(req); + usb_free_urb(urb); +} + +static void ax8817x_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, + u16 size, void *data) +{ + struct usb_ctrlrequest *req; + int status; + struct urb *urb; + + if ((urb = usb_alloc_urb(0, GFP_ATOMIC)) == NULL) { + devdbg(dev, "Error allocating URB in write_cmd_async!"); + return; + } + + if ((req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC)) == NULL) { + deverr(dev, "Failed to allocate memory for control request"); + usb_free_urb(urb); + return; + } + + req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; + req->bRequest = cmd; + req->wValue = cpu_to_le16(value); + req->wIndex = cpu_to_le16(index); + req->wLength = cpu_to_le16(size); + + usb_fill_control_urb(urb, dev->udev, + usb_sndctrlpipe(dev->udev, 0), + (void *)req, data, size, + ax8817x_async_cmd_callback, req); + + if((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) + deverr(dev, "Error submitting the control message: status=%d", status); +} + +static void ax8817x_set_multicast(struct net_device *net) +{ + struct usbnet *dev = (struct usbnet *) net->priv; + u8 rx_ctl = 0x8c; + + if (net->flags & IFF_PROMISC) { + rx_ctl |= 0x01; + } else if (net->flags & IFF_ALLMULTI + || net->mc_count > AX_MAX_MCAST) { + rx_ctl |= 0x02; + } else if (net->mc_count == 0) { + /* just broadcast and directed */ + } else { + struct dev_mc_list *mc_list = net->mc_list; + u8 *multi_filter; + u32 crc_bits; + int i; + + multi_filter = kmalloc(AX_MCAST_FILTER_SIZE, GFP_ATOMIC); + if (multi_filter == NULL) { + /* Oops, couldn't allocate a buffer for setting the multicast + filter. Try all multi mode. */ + rx_ctl |= 0x02; + } else { + memset(multi_filter, 0, AX_MCAST_FILTER_SIZE); + + /* Build the multicast hash filter. */ + for (i = 0; i < net->mc_count; i++) { + crc_bits = + ether_crc(ETH_ALEN, + mc_list->dmi_addr) >> 26; + multi_filter[crc_bits >> 3] |= + 1 << (crc_bits & 7); + mc_list = mc_list->next; + } + + ax8817x_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, + AX_MCAST_FILTER_SIZE, multi_filter); + + rx_ctl |= 0x10; + } + } + + ax8817x_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); +} + +static int ax8817x_mdio_read(struct net_device *netdev, int phy_id, int loc) +{ + struct usbnet *dev = netdev->priv; + u16 res; + u8 buf[4]; + + ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, &buf); + ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, (__u16)loc, 2, (u16 *)&res); + ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf); + + return res & 0xffff; +} + +static void ax8817x_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) +{ + struct usbnet *dev = netdev->priv; + u16 res = val; + u8 buf[4]; + + ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, &buf); + ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, (u16 *)&res); + ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf); +} + +static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf) +{ + int ret; + u8 buf[6]; + u16 *buf16 = (u16 *) buf; + int i; + + dev->in = usb_rcvbulkpipe(dev->udev, 3); + dev->out = usb_sndbulkpipe(dev->udev, 2); + + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x80, 0, 0, buf)) < 0) { + dbg("send AX_CMD_WRITE_RX_CTL failed: %d", ret); + return ret; + } + + /* Get the MAC address */ + memset(buf, 0, ETH_ALEN); + if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, 6, buf)) < 0) { + dbg("read AX_CMD_READ_NODE_ID failed: %d", ret); + return ret; + } + memcpy(dev->net->dev_addr, buf, ETH_ALEN); + + /* Get IPG values */ + if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_IPG012, 0, 0, 3, buf)) < 0) { + dbg("Error reading IPG values: %d", ret); + return ret; + } + + for(i = 0;i < 3;i++) { + ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0 + i, 0, 0, 1, &buf[i]); + } + + /* Get the PHY id */ + if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf)) < 0) { + dbg("error on read AX_CMD_READ_PHY_ID: %02x", ret); + return ret; + } else if (ret < 2) { + /* this should always return 2 bytes */ + dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x", ret); + return -EIO; + } + + /* Initialize MII structure */ + dev->mii.dev = dev->net; + dev->mii.mdio_read = ax8817x_mdio_read; + dev->mii.mdio_write = ax8817x_mdio_write; + dev->mii.phy_id_mask = 0x3f; + dev->mii.reg_num_mask = 0x1f; + dev->mii.phy_id = buf[1]; + + if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, &buf)) < 0) { + dbg("Failed to go to software MII mode: %02x", ret); + return ret; + } + + *buf16 = cpu_to_le16(BMCR_RESET); + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, + dev->mii.phy_id, MII_BMCR, 2, buf16)) < 0) { + dbg("Failed to write MII reg - MII_BMCR: %02x", ret); + return ret; + } + + /* Advertise that we can do full-duplex pause */ + *buf16 = cpu_to_le16(ADVERTISE_ALL | ADVERTISE_CSMA | 0x0400); + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, + dev->mii.phy_id, MII_ADVERTISE, + 2, buf16)) < 0) { + dbg("Failed to write MII_REG advertisement: %02x", ret); + return ret; + } + + *buf16 = cpu_to_le16(BMCR_ANENABLE | BMCR_ANRESTART); + if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, + dev->mii.phy_id, MII_BMCR, + 2, buf16)) < 0) { + dbg("Failed to write MII reg autonegotiate: %02x", ret); + return ret; + } + + if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf)) < 0) { + dbg("Failed to set hardware MII: %02x", ret); + return ret; + } + + dev->net->set_multicast_list = ax8817x_set_multicast; + + return 0; +} + +static const struct driver_info ax8817x_info = { + .description = "ASIX AX8817x USB 2.0 Ethernet", + .bind = ax8817x_bind, + .flags = FLAG_ETHER, +}; +#endif /* CONFIG_USB_AX8817X */ + #ifdef CONFIG_USB_BELKIN @@ -470,7 +721,7 @@ struct ether_desc { u8 bNumberPowerFilters; } __attribute__ ((packed)); -struct cdc_info { +struct cdc_state { struct header_desc *header; struct union_desc *u; struct ether_desc *ether; @@ -513,7 +764,7 @@ static int cdc_bind (struct usbnet *dev, struct usb_interface *intf) u8 *buf = intf->altsetting->extra; int len = intf->altsetting->extralen; struct usb_interface_descriptor *d; - struct cdc_info *info = (void *) &dev->data; + struct cdc_state *info = (void *) &dev->data; int status; if (sizeof dev->data < sizeof *info) @@ -522,12 +773,15 @@ static int cdc_bind (struct usbnet *dev, struct usb_interface *intf) /* expect strict spec conformance for the descriptors, but * cope with firmware which stores them in the wrong place */ - if (len == 0 && dev->udev->config->extralen) { - /* Motorola SB4100 (and maybe others) put - * CDC descriptors here + if (len == 0 && dev->udev->actconfig->extralen) { + /* Motorola SB4100 (and others: Brad Hards says it's + * from a Broadcom design) put CDC descriptors here */ - buf = dev->udev->config->extra; - len = dev->udev->config->extralen; + buf = dev->udev->actconfig->extra; + len = dev->udev->actconfig->extralen; + if (len) + dev_dbg (&intf->dev, + "CDC descriptors on config\n"); } memset (info, 0, sizeof *info); @@ -542,48 +796,92 @@ static int cdc_bind (struct usbnet *dev, struct usb_interface *intf) */ switch (buf [2]) { case 0x00: /* Header, mostly useless */ - if (info->header) + if (info->header) { + dev_dbg (&intf->dev, "extra CDC header\n"); goto bad_desc; + } info->header = (void *) buf; - if (info->header->bLength != sizeof *info->header) + if (info->header->bLength != sizeof *info->header) { + dev_dbg (&intf->dev, "CDC header len %u\n", + info->header->bLength); goto bad_desc; + } break; case 0x06: /* Union (groups interfaces) */ - if (info->u) + if (info->u) { + dev_dbg (&intf->dev, "extra CDC union\n"); goto bad_desc; + } info->u = (void *) buf; - if (info->u->bLength != sizeof *info->u) + if (info->u->bLength != sizeof *info->u) { + dev_dbg (&intf->dev, "CDC union len %u\n", + info->u->bLength); goto bad_desc; - d = &intf->altsetting->desc; - if (info->u->bMasterInterface0 != d->bInterfaceNumber) - goto bad_desc; - info->data = dev->udev->actconfig->interface[0]; - if (intf != (info->data + info->u->bMasterInterface0)) + } + + /* we need a master/control interface (what we're + * probed with) and a slave/data interface; union + * descriptors sort this all out. + */ + info->control = usb_ifnum_to_if(dev->udev, + info->u->bMasterInterface0); + info->data = usb_ifnum_to_if(dev->udev, + info->u->bSlaveInterface0); + if (!info->control || !info->data) { + dev_dbg (&intf->dev, + "master #%u/%p slave #%u/%p\n", + info->u->bMasterInterface0 + info->control, + info->u->bSlaveInterface0, + info->data); goto bad_desc; + } + if (info->control != intf) { + dev_dbg (&intf->dev, "bogus CDC Union\n"); + /* Ambit USB Cable Modem (and maybe others) + * interchanges master and slave interface. + */ + if (info->data == intf) { + info->data = info->control; + info->control = intf; + } else + goto bad_desc; + } /* a data interface altsetting does the real i/o */ - info->data += info->u->bSlaveInterface0; d = &info->data->altsetting->desc; - if (info->u->bSlaveInterface0 != d->bInterfaceNumber - || d->bInterfaceClass != USB_CLASS_CDC_DATA) + if (d->bInterfaceClass != USB_CLASS_CDC_DATA) { + dev_dbg (&intf->dev, "slave class %u\n", + d->bInterfaceClass); goto bad_desc; + } if (usb_interface_claimed (info->data)) return -EBUSY; break; case 0x0F: /* Ethernet Networking */ - if (info->ether) + if (info->ether) { + dev_dbg (&intf->dev, "extra CDC ether\n"); goto bad_desc; + } info->ether = (void *) buf; - if (info->ether->bLength != sizeof *info->ether) + if (info->ether->bLength != sizeof *info->ether) { + dev_dbg (&intf->dev, "CDC ether len %u\n", + info->u->bLength); goto bad_desc; + } break; } next_desc: len -= buf [0]; /* bLength */ buf += buf [0]; } - if (!info->header || !info ->u || !info->ether) + if (!info->header || !info ->u || !info->ether) { + dev_dbg (&intf->dev, "missing cdc %s%s%sdescriptor\n", + info->header ? "" : "header ", + info->u ? "" : "union ", + info->ether ? "" : "ether "); goto bad_desc; + } #ifdef CONFIG_USB_ZAURUS /* Zaurus ethernet addresses aren't unique ... */ @@ -624,7 +922,7 @@ bad_desc: static void cdc_unbind (struct usbnet *dev, struct usb_interface *intf) { - struct cdc_info *info = (void *) &dev->data; + struct cdc_state *info = (void *) &dev->data; /* disconnect master --> disconnect slave */ if (intf == info->control && info->data) { @@ -2091,16 +2389,23 @@ static int usbnet_open (struct net_device *net) } netif_start_queue (net); - if (dev->msg_level >= 2) + if (dev->msg_level >= 2) { + char *framing; + + if (dev->driver_info->flags & FLAG_FRAMING_NC) + framing = "NetChip"; + else if (dev->driver_info->flags & FLAG_FRAMING_GL) + framing = "GeneSys"; + else if (dev->driver_info->flags & FLAG_FRAMING_Z) + framing = "Zaurus"; + else + framing = "simple"; + devinfo (dev, "open: enable queueing " "(rx %d, tx %d) mtu %d %s framing", RX_QLEN (dev), TX_QLEN (dev), dev->net->mtu, - (info->flags & (FLAG_FRAMING_NC | FLAG_FRAMING_GL)) - ? ((info->flags & FLAG_FRAMING_NC) - ? "NetChip" - : "GeneSys") - : "raw" - ); + framing); + } // delay posting reads until we're fully open tasklet_schedule (&dev->bh); @@ -2173,12 +2478,20 @@ usbnet_ethtool_ioctl (struct net_device *net, void __user *useraddr) static int usbnet_ioctl (struct net_device *net, struct ifreq *rq, int cmd) { - switch (cmd) { - case SIOCETHTOOL: + if (cmd == SIOCETHTOOL) return usbnet_ethtool_ioctl (net, (void __user *)rq->ifr_data); - default: - return -EOPNOTSUPP; + +#ifdef NEED_MII + { + struct usbnet *dev = (struct usbnet *)net->priv; + + if (dev->mii.mdio_read != NULL && dev->mii.mdio_write != NULL) + return generic_mii_ioctl(&dev->mii, + (struct mii_ioctl_data *) &rq->ifr_data, + cmd, NULL); } +#endif + return -EOPNOTSUPP; } /*-------------------------------------------------------------------------*/ @@ -2342,7 +2655,7 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) if (!((skb->len + sizeof *trailer) & 0x01)) *skb_put (skb, 1) = PAD_BYTE; trailer = (struct nc_trailer *) skb_put (skb, sizeof *trailer); - } + } #endif /* CONFIG_USB_NET1080 */ usb_fill_bulk_urb (urb, dev->udev, dev->out, @@ -2670,6 +2983,30 @@ static const struct usb_device_id products [] = { }, #endif +#ifdef CONFIG_USB_AX8817X +{ + // Linksys USB200M + USB_DEVICE (0x077b, 0x2226), + .driver_info = (unsigned long) &ax8817x_info, +}, { + // Netgear FA120 + USB_DEVICE (0x0846, 0x1040), + .driver_info = (unsigned long) &ax8817x_info, +}, { + // DLink DUB-E100 + USB_DEVICE (0x2001, 0x1a00), + .driver_info = (unsigned long) &ax8817x_info, +}, { + // Intellinet, ST Lab USB Ethernet + USB_DEVICE (0x0b95, 0x1720), + .driver_info = (unsigned long) &ax8817x_info, +}, { + // Hawking UF200, TrendNet TU2-ET100 + USB_DEVICE (0x07b8, 0x420a), + .driver_info = (unsigned long) &ax8817x_info, +}, +#endif + #ifdef CONFIG_USB_EPSON2888 { USB_DEVICE (0x0525, 0x2888), // EPSON USB client @@ -2834,18 +3171,19 @@ static struct usb_driver usbnet_driver = { static int __init usbnet_init (void) { - // compiler should optimize this out - if (sizeof (((struct sk_buff *)0)->cb) < sizeof (struct skb_data)) - BUG (); + // compiler should optimize these out + BUG_ON (sizeof (((struct sk_buff *)0)->cb) + < sizeof (struct skb_data)); +#ifdef CONFIG_USB_CDCETHER + BUG_ON ((sizeof (((struct usbnet *)0)->data) + < sizeof (struct cdc_state))); +#endif get_random_bytes (node_id, sizeof node_id); node_id [0] &= 0xfe; // clear multicast bit node_id [0] |= 0x02; // set local assignment bit (IEEE802) - if (usb_register (&usbnet_driver) < 0) - return -1; - - return 0; + return usb_register(&usbnet_driver); } module_init (usbnet_init); diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index 5a3ea9065627..114973af8f4c 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -602,10 +602,19 @@ static int belkin_sa_ioctl (struct usb_serial_port *port, struct file * file, un static int __init belkin_sa_init (void) { - usb_serial_register (&belkin_device); - usb_register (&belkin_driver); + int retval; + retval = usb_serial_register(&belkin_device); + if (retval) + goto failed_usb_serial_register; + retval = usb_register(&belkin_driver); + if (retval) + goto failed_usb_register; info(DRIVER_DESC " " DRIVER_VERSION); return 0; +failed_usb_register: + usb_serial_deregister(&belkin_device); +failed_usb_serial_register: + return retval; } diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index 34bcc2670617..de7ac68e1821 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -101,10 +101,11 @@ static struct usb_serial_device_type cyberjack_device = { }; struct cyberjack_private { - short rdtodo; /* Bytes still to read */ + spinlock_t lock; /* Lock for SMP */ + short rdtodo; /* Bytes still to read */ unsigned char wrbuf[5*64]; /* Buffer for collecting data to write */ - short wrfilled; /* Overall data size we already got */ - short wrsent; /* Data akready sent */ + short wrfilled; /* Overall data size we already got */ + short wrsent; /* Data akready sent */ }; /* do some startup allocations not currently performed by usb_serial_probe() */ @@ -120,6 +121,7 @@ static int cyberjack_startup (struct usb_serial *serial) return -ENOMEM; /* set initial values */ + spin_lock_init(&priv->lock); priv->rdtodo = 0; priv->wrfilled = 0; priv->wrsent = 0; @@ -146,6 +148,7 @@ static void cyberjack_shutdown (struct usb_serial *serial) static int cyberjack_open (struct usb_serial_port *port, struct file *filp) { struct cyberjack_private *priv; + unsigned long flags; int result = 0; if (port_paranoia_check (port, __FUNCTION__)) @@ -160,9 +163,11 @@ static int cyberjack_open (struct usb_serial_port *port, struct file *filp) port->tty->low_latency = 1; priv = usb_get_serial_port_data(port); + spin_lock_irqsave(&priv->lock, flags); priv->rdtodo = 0; priv->wrfilled = 0; priv->wrsent = 0; + spin_unlock_irqrestore(&priv->lock, flags); /* shutdown any bulk reads that might be going on */ usb_unlink_urb (port->write_urb); @@ -194,6 +199,7 @@ static int cyberjack_write (struct usb_serial_port *port, int from_user, const u { struct usb_serial *serial = port->serial; struct cyberjack_private *priv = usb_get_serial_port_data(port); + unsigned long flags; int result; int wrexpected; @@ -210,15 +216,19 @@ static int cyberjack_write (struct usb_serial_port *port, int from_user, const u return (0); } + spin_lock_irqsave(&priv->lock, flags); + if( (count+priv->wrfilled)>sizeof(priv->wrbuf) ) { /* To much data for buffer. Reset buffer. */ priv->wrfilled=0; + spin_unlock_irqrestore(&priv->lock, flags); return (0); } /* Copy data */ if (from_user) { if (copy_from_user(priv->wrbuf+priv->wrfilled, buf, count)) { + spin_unlock_irqrestore(&priv->lock, flags); return -EFAULT; } } else { @@ -261,6 +271,7 @@ static int cyberjack_write (struct usb_serial_port *port, int from_user, const u /* Throw away data. No better idea what to do with it. */ priv->wrfilled=0; priv->wrsent=0; + spin_unlock_irqrestore(&priv->lock, flags); return 0; } @@ -275,6 +286,8 @@ static int cyberjack_write (struct usb_serial_port *port, int from_user, const u } } + spin_unlock_irqrestore(&priv->lock, flags); + return (count); } @@ -282,8 +295,10 @@ static void cyberjack_read_int_callback( struct urb *urb, struct pt_regs *regs ) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct cyberjack_private *priv = usb_get_serial_port_data(port); + unsigned long flags; struct usb_serial *serial; unsigned char *data = urb->transfer_buffer; + int result; if (port_paranoia_check (port, __FUNCTION__)) return; @@ -302,21 +317,20 @@ static void cyberjack_read_int_callback( struct urb *urb, struct pt_regs *regs ) /* React only to interrupts signaling a bulk_in transfer */ if( (urb->actual_length==4) && (data[0]==0x01) ) { - short old_rdtodo = priv->rdtodo; + short old_rdtodo; int result; /* This is a announcement of coming bulk_ins. */ unsigned short size = ((unsigned short)data[3]<<8)+data[2]+3; - if( (size>259) || (size==0) ) { - dbg( "Bad announced bulk_in data length: %d", size ); - /* Dunno what is most reliable to do here. */ - /* return; */ - } + spin_lock_irqsave(&priv->lock, flags); + + old_rdtodo = priv->rdtodo; if( (old_rdtodo+size)<(old_rdtodo) ) { dbg( "To many bulk_in urbs to do." ); - return; + spin_unlock_irqrestore(&priv->lock, flags); + goto resubmit; } /* "+=" is probably more fault tollerant than "=" */ @@ -324,23 +338,34 @@ static void cyberjack_read_int_callback( struct urb *urb, struct pt_regs *regs ) dbg("%s - rdtodo: %d", __FUNCTION__, priv->rdtodo); + spin_unlock_irqrestore(&priv->lock, flags); + if( !old_rdtodo ) { port->read_urb->dev = port->serial->dev; - result = usb_submit_urb(port->read_urb, GFP_ATOMIC); + result = usb_submit_urb(port->read_urb, GFP_KERNEL); if( result ) err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); dbg("%s - usb_submit_urb(read urb)", __FUNCTION__); } } + +resubmit: + port->interrupt_in_urb->dev = port->serial->dev; + result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); + if (result) + err(" usb_submit_urb(read int) failed"); + dbg("%s - usb_submit_urb(int urb)", __FUNCTION__); } static void cyberjack_read_bulk_callback (struct urb *urb, struct pt_regs *regs) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct cyberjack_private *priv = usb_get_serial_port_data(port); + unsigned long flags; struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; + short todo; int i; int result; @@ -372,18 +397,22 @@ static void cyberjack_read_bulk_callback (struct urb *urb, struct pt_regs *regs) tty_flip_buffer_push(tty); } + spin_lock_irqsave(&priv->lock, flags); + /* Reduce urbs to do by one. */ priv->rdtodo-=urb->actual_length; /* Just to be sure */ - if ( priv->rdtodo<0 ) - priv->rdtodo = 0; + if ( priv->rdtodo<0 ) priv->rdtodo = 0; + todo = priv->rdtodo; - dbg("%s - rdtodo: %d", __FUNCTION__, priv->rdtodo); + spin_unlock_irqrestore(&priv->lock, flags); + + dbg("%s - rdtodo: %d", __FUNCTION__, todo); /* Continue to read if we have still urbs to do. */ - if( priv->rdtodo /* || (urb->actual_length==port->bulk_in_endpointAddress)*/ ) { + if( todo /* || (urb->actual_length==port->bulk_in_endpointAddress)*/ ) { port->read_urb->dev = port->serial->dev; - result = usb_submit_urb(port->read_urb, GFP_ATOMIC); + result = usb_submit_urb(port->read_urb, GFP_KERNEL); if (result) err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); dbg("%s - usb_submit_urb(read urb)", __FUNCTION__); @@ -394,6 +423,7 @@ static void cyberjack_write_bulk_callback (struct urb *urb, struct pt_regs *regs { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct cyberjack_private *priv = usb_get_serial_port_data(port); + unsigned long flags; struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); dbg("%s - port %d", __FUNCTION__, port->number); @@ -408,12 +438,15 @@ static void cyberjack_write_bulk_callback (struct urb *urb, struct pt_regs *regs return; } + spin_lock_irqsave(&priv->lock, flags); + /* only do something if we have more data to send */ if( priv->wrfilled ) { int length, blksize, result; if (port->write_urb->status == -EINPROGRESS) { dbg("%s - already writing", __FUNCTION__); + spin_unlock_irqrestore(&priv->lock, flags); return; } @@ -459,18 +492,28 @@ static void cyberjack_write_bulk_callback (struct urb *urb, struct pt_regs *regs } exit: + spin_unlock_irqrestore(&priv->lock, flags); schedule_work(&port->work); } static int __init cyberjack_init (void) { - usb_serial_register (&cyberjack_device); - usb_register (&cyberjack_driver); + int retval; + retval = usb_serial_register(&cyberjack_device); + if (retval) + goto failed_usb_serial_register; + retval = usb_register(&cyberjack_driver); + if (retval) + goto failed_usb_register; info(DRIVER_VERSION " " DRIVER_AUTHOR); info(DRIVER_DESC); return 0; +failed_usb_register: + usb_serial_deregister(&cyberjack_device); +failed_usb_serial_register: + return retval; } static void __exit cyberjack_exit (void) diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 82e0f411e9e0..d9abf8afdcad 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -2045,11 +2045,24 @@ opcode, line, status, val ); static int __init digi_init (void) { - usb_serial_register (&digi_acceleport_2_device); - usb_serial_register (&digi_acceleport_4_device); - usb_register (&digi_driver); + int retval; + retval = usb_serial_register(&digi_acceleport_2_device); + if (retval) + goto failed_acceleport_2_device; + retval = usb_serial_register(&digi_acceleport_4_device); + if (retval) + goto failed_acceleport_4_device; + retval = usb_register(&digi_driver); + if (retval) + goto failed_usb_register; info(DRIVER_VERSION ":" DRIVER_DESC); return 0; +failed_usb_register: + usb_serial_deregister(&digi_acceleport_4_device); +failed_acceleport_4_device: + usb_serial_deregister(&digi_acceleport_2_device); +failed_acceleport_2_device: + return retval; } diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index ea0c762ea5db..69b798b77ce5 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -558,7 +558,7 @@ static void empeg_set_termios (struct usb_serial_port *port, struct termios *old static int __init empeg_init (void) { struct urb *urb; - int i; + int i, retval; /* create our write urb pool and transfer buffers */ spin_lock_init (&write_urb_pool_lock); @@ -570,7 +570,6 @@ static int __init empeg_init (void) continue; } - urb->transfer_buffer = NULL; urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); if (!urb->transfer_buffer) { err("%s - out of memory for urb buffers.", @@ -579,12 +578,27 @@ static int __init empeg_init (void) } } - usb_serial_register (&empeg_device); - usb_register (&empeg_driver); + retval = usb_serial_register(&empeg_device); + if (retval) + goto failed_usb_serial_register; + retval = usb_register(&empeg_driver); + if (retval) + goto failed_usb_register; info(DRIVER_VERSION ":" DRIVER_DESC); return 0; +failed_usb_register: + usb_serial_deregister(&empeg_device); +failed_usb_serial_register: + for (i = 0; i < NUM_URBS; ++i) { + if (write_urb_pool[i]) { + if (write_urb_pool[i]->transfer_buffer) + kfree(write_urb_pool[i]->transfer_buffer); + usb_free_urb(write_urb_pool[i]); + } + } + return retval; } @@ -593,7 +607,7 @@ static void __exit empeg_exit (void) int i; unsigned long flags; - usb_register (&empeg_driver); + usb_deregister(&empeg_driver); usb_serial_deregister (&empeg_device); spin_lock_irqsave (&write_urb_pool_lock, flags); diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 57a96c219d4d..ef813e60a286 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -17,6 +17,11 @@ * See http://ftdi-usb-sio.sourceforge.net for upto date testing info * and extra documentation * + * (19/Aug/2003) Ian Abbott + * Freed urb's transfer buffer in write bulk callback. + * Omitted some paranoid checks in write bulk callback that don't matter. + * Scheduled work in write bulk callback regardless of port's open count. + * * (05/Aug/2003) Ian Abbott * Added VID/PID for ID TECH IDT1221U USB to RS-232 adapter. * VID/PID provided by Steve Briggs. @@ -1391,31 +1396,21 @@ static int ftdi_write (struct usb_serial_port *port, int from_user, static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; - struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); - dbg("%s", __FUNCTION__); + /* free up the transfer buffer, as usb_free_urb() does not do this */ + kfree (urb->transfer_buffer); if (port_paranoia_check (port, __FUNCTION__)) return; + dbg("%s - port %d", __FUNCTION__, port->number); + if (urb->status) { dbg("nonzero write bulk status received: %d", urb->status); return; } - if (!serial) { - dbg("%s - bad serial pointer, exiting", __FUNCTION__); - return; - } - - /* Have to check for validity of queueing up the tasks */ - dbg("%s - port->open_count = %d", __FUNCTION__, port->open_count); - - if (port->open_count > 0){ - schedule_work(&port->work); - } - - return; + schedule_work(&port->work); } /* ftdi_write_bulk_callback */ @@ -1999,17 +1994,42 @@ static void ftdi_unthrottle (struct usb_serial_port *port) static int __init ftdi_init (void) { + int retval; dbg("%s", __FUNCTION__); - usb_serial_register (&ftdi_SIO_device); - usb_serial_register (&ftdi_8U232AM_device); - usb_serial_register (&ftdi_FT232BM_device); - usb_serial_register (&ftdi_USB_UIRT_device); - usb_serial_register (&ftdi_HE_TIRA1_device); - usb_register (&ftdi_driver); + retval = usb_serial_register(&ftdi_SIO_device); + if (retval) + goto failed_SIO_register; + retval = usb_serial_register(&ftdi_8U232AM_device); + if (retval) + goto failed_8U232AM_register; + retval = usb_serial_register(&ftdi_FT232BM_device); + if (retval) + goto failed_FT232BM_register; + retval = usb_serial_register(&ftdi_USB_UIRT_device); + if (retval) + goto failed_USB_UIRT_register; + retval = usb_serial_register(&ftdi_HE_TIRA1_device); + if (retval) + goto failed_HE_TIRA1_register; + retval = usb_register(&ftdi_driver); + if (retval) + goto failed_usb_register; info(DRIVER_VERSION ":" DRIVER_DESC); return 0; +failed_usb_register: + usb_serial_deregister(&ftdi_HE_TIRA1_device); +failed_HE_TIRA1_register: + usb_serial_deregister(&ftdi_USB_UIRT_device); +failed_USB_UIRT_register: + usb_serial_deregister(&ftdi_FT232BM_device); +failed_FT232BM_register: + usb_serial_deregister(&ftdi_8U232AM_device); +failed_8U232AM_register: + usb_serial_deregister(&ftdi_SIO_device); +failed_SIO_register: + return retval; } diff --git a/drivers/usb/serial/io_16654.h b/drivers/usb/serial/io_16654.h index b2019d6683bf..a53abc9530ff 100644 --- a/drivers/usb/serial/io_16654.h +++ b/drivers/usb/serial/io_16654.h @@ -2,7 +2,7 @@ * * 16654.H Definitions for 16C654 UART used on EdgePorts * - * Copyright (c) 1998 Inside Out Networks, Inc. + * Copyright (C) 1998 Inside Out Networks, Inc. * 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 @@ -142,14 +142,14 @@ #define LSR_FIFO_ERR 0x80 // Rx Fifo contains at least 1 erred char -#define MSR_DELTA_CTS 0x01 // CTS changed from last read -#define MSR_DELTA_DSR 0x02 // DSR changed from last read -#define MSR_DELTA_RI 0x04 // RI changed from 0 -> 1 -#define MSR_DELTA_CD 0x08 // CD changed from last read -#define MSR_CTS 0x10 // Current state of CTS -#define MSR_DSR 0x20 // Current state of DSR -#define MSR_RI 0x40 // Current state of RI -#define MSR_CD 0x80 // Current state of CD +#define EDGEPORT_MSR_DELTA_CTS 0x01 // CTS changed from last read +#define EDGEPORT_MSR_DELTA_DSR 0x02 // DSR changed from last read +#define EDGEPORT_MSR_DELTA_RI 0x04 // RI changed from 0 -> 1 +#define EDGEPORT_MSR_DELTA_CD 0x08 // CD changed from last read +#define EDGEPORT_MSR_CTS 0x10 // Current state of CTS +#define EDGEPORT_MSR_DSR 0x20 // Current state of DSR +#define EDGEPORT_MSR_RI 0x40 // Current state of RI +#define EDGEPORT_MSR_CD 0x80 // Current state of CD diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index ace685491dc9..628f4408c6b2 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -1,8 +1,8 @@ /* * Edgeport USB Serial Converter driver * - * Copyright(c) 2000 Inside Out Networks, All rights reserved. - * Copyright(c) 2001-2002 Greg Kroah-Hartman <greg@kroah.com> + * Copyright (C) 2000 Inside Out Networks, All rights reserved. + * Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com> * * 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 @@ -1806,10 +1806,10 @@ static int edge_tiocmget(struct usb_serial_port *port, struct file *file) mcr = edge_port->shadowMCR; result = ((mcr & MCR_DTR) ? TIOCM_DTR: 0) /* 0x002 */ | ((mcr & MCR_RTS) ? TIOCM_RTS: 0) /* 0x004 */ - | ((msr & MSR_CTS) ? TIOCM_CTS: 0) /* 0x020 */ - | ((msr & MSR_CD) ? TIOCM_CAR: 0) /* 0x040 */ - | ((msr & MSR_RI) ? TIOCM_RI: 0) /* 0x080 */ - | ((msr & MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */ + | ((msr & EDGEPORT_MSR_CTS) ? TIOCM_CTS: 0) /* 0x020 */ + | ((msr & EDGEPORT_MSR_CD) ? TIOCM_CAR: 0) /* 0x040 */ + | ((msr & EDGEPORT_MSR_RI) ? TIOCM_RI: 0) /* 0x080 */ + | ((msr & EDGEPORT_MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */ dbg("%s -- %x", __FUNCTION__, result); @@ -2221,20 +2221,20 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr) dbg("%s %02x", __FUNCTION__, newMsr); - if (newMsr & (MSR_DELTA_CTS | MSR_DELTA_DSR | MSR_DELTA_RI | MSR_DELTA_CD)) { + if (newMsr & (EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR | EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD)) { icount = &edge_port->icount; /* update input line counters */ - if (newMsr & MSR_DELTA_CTS) { + if (newMsr & EDGEPORT_MSR_DELTA_CTS) { icount->cts++; } - if (newMsr & MSR_DELTA_DSR) { + if (newMsr & EDGEPORT_MSR_DELTA_DSR) { icount->dsr++; } - if (newMsr & MSR_DELTA_CD) { + if (newMsr & EDGEPORT_MSR_DELTA_CD) { icount->dcd++; } - if (newMsr & MSR_DELTA_RI) { + if (newMsr & EDGEPORT_MSR_DELTA_RI) { icount->rng++; } wake_up_interruptible(&edge_port->delta_msr_wait); @@ -3051,15 +3051,36 @@ static void edge_shutdown (struct usb_serial *serial) * edgeport_init * This is called by the module subsystem, or on startup to initialize us ****************************************************************************/ -int __init edgeport_init(void) +static int __init edgeport_init(void) { - usb_serial_register (&edgeport_1port_device); - usb_serial_register (&edgeport_2port_device); - usb_serial_register (&edgeport_4port_device); - usb_serial_register (&edgeport_8port_device); - usb_register (&io_driver); + int retval; + retval = usb_serial_register(&edgeport_1port_device); + if (retval) + goto failed_1port_device_register; + retval = usb_serial_register(&edgeport_2port_device); + if (retval) + goto failed_2port_device_register; + retval = usb_serial_register(&edgeport_4port_device); + if (retval) + goto failed_4port_device_register; + retval = usb_serial_register(&edgeport_8port_device); + if (retval) + goto failed_8port_device_register; + retval = usb_register(&io_driver); + if (retval) + goto failed_usb_register; info(DRIVER_DESC " " DRIVER_VERSION); return 0; +failed_usb_register: + usb_serial_deregister(&edgeport_8port_device); +failed_8port_device_register: + usb_serial_deregister(&edgeport_4port_device); +failed_4port_device_register: + usb_serial_deregister(&edgeport_2port_device); +failed_2port_device_register: + usb_serial_deregister(&edgeport_1port_device); +failed_1port_device_register: + return retval; } @@ -3068,7 +3089,7 @@ int __init edgeport_init(void) * edgeport_exit * Called when the driver is about to be unloaded. ****************************************************************************/ -void __exit edgeport_exit (void) +static void __exit edgeport_exit (void) { usb_deregister (&io_driver); usb_serial_deregister (&edgeport_1port_device); diff --git a/drivers/usb/serial/io_edgeport.h b/drivers/usb/serial/io_edgeport.h index b2bd77c9d292..386139d45cf7 100644 --- a/drivers/usb/serial/io_edgeport.h +++ b/drivers/usb/serial/io_edgeport.h @@ -2,7 +2,7 @@ * * io_edgeport.h Edgeport Linux Interface definitions * - * Copyright (c) 2000 Inside Out Networks, Inc. + * Copyright (C) 2000 Inside Out Networks, Inc. * * 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 diff --git a/drivers/usb/serial/io_fw_boot.h b/drivers/usb/serial/io_fw_boot.h index bdc6ebf1420f..fa06c7335b98 100644 --- a/drivers/usb/serial/io_fw_boot.h +++ b/drivers/usb/serial/io_fw_boot.h @@ -1,7 +1,7 @@ //************************************************************** //* Edgeport/4 Binary Image //* Generated by HEX2C v1.06 -//* Copyright(c) 1998 Inside Out Networks, All rights reserved. +//* Copyright (C) 1998 Inside Out Networks, All rights reserved. //* 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 diff --git a/drivers/usb/serial/io_fw_boot2.h b/drivers/usb/serial/io_fw_boot2.h index 9dc0fe082ac5..84a777f07d9b 100644 --- a/drivers/usb/serial/io_fw_boot2.h +++ b/drivers/usb/serial/io_fw_boot2.h @@ -1,7 +1,7 @@ //************************************************************** //* Edgeport/4 Binary Image //* Generated by HEX2C v1.06 -//* Copyright(c) 1998 Inside Out Networks, All rights reserved. +//* Copyright (C) 1998 Inside Out Networks, All rights reserved. //* 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 diff --git a/drivers/usb/serial/io_fw_down.h b/drivers/usb/serial/io_fw_down.h index 7475f1e95908..d1edada4e274 100644 --- a/drivers/usb/serial/io_fw_down.h +++ b/drivers/usb/serial/io_fw_down.h @@ -1,7 +1,7 @@ //************************************************************** //* Edgeport/4 Binary Image //* Generated by HEX2C v1.06 -//* Copyright(c) 1998 Inside Out Networks, All rights reserved. +//* Copyright (C) 1998 Inside Out Networks, All rights reserved. //* 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 diff --git a/drivers/usb/serial/io_fw_down2.h b/drivers/usb/serial/io_fw_down2.h index bdca56e2c150..22e3eb9a90e5 100644 --- a/drivers/usb/serial/io_fw_down2.h +++ b/drivers/usb/serial/io_fw_down2.h @@ -1,7 +1,7 @@ //************************************************************** //* Edgeport/4 Binary Image //* Generated by HEX2C v1.06 -//* Copyright(c) 1998 Inside Out Networks, All rights reserved. +//* Copyright (C) 1998 Inside Out Networks, All rights reserved. //* 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 diff --git a/drivers/usb/serial/io_fw_down3.h b/drivers/usb/serial/io_fw_down3.h index 56d319f0163d..20eecb39d6d7 100644 --- a/drivers/usb/serial/io_fw_down3.h +++ b/drivers/usb/serial/io_fw_down3.h @@ -1,7 +1,7 @@ //************************************************************** //* Edgeport Binary Image (for TI based products) //* Generated by TIBin2C v1.00 -//* Copyright(c) 2001 Inside Out Networks, All rights reserved. +//* Copyright (C) 2001 Inside Out Networks, All rights reserved. //************************************************************** diff --git a/drivers/usb/serial/io_ionsp.h b/drivers/usb/serial/io_ionsp.h index 944fc04f1946..092e03d2dfc4 100644 --- a/drivers/usb/serial/io_ionsp.h +++ b/drivers/usb/serial/io_ionsp.h @@ -2,7 +2,7 @@ * * IONSP.H Definitions for I/O Networks Serial Protocol * - * Copyright (c) 1997-1998 Inside Out Networks, Inc. + * Copyright (C) 1997-1998 Inside Out Networks, Inc. * * 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 diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 19d64c19e2a2..ebf315bb8485 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -1,8 +1,8 @@ /* * Edgeport USB Serial Converter driver * - * Copyright(c) 2000-2002 Inside Out Networks, All rights reserved. - * Copyright(c) 2001-2002 Greg Kroah-Hartman <greg@kroah.com> + * Copyright (C) 2000-2002 Inside Out Networks, All rights reserved. + * Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com> * * 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 @@ -127,6 +127,7 @@ static struct usb_device_id edgeport_1port_id_table [] = { static struct usb_device_id edgeport_2port_id_table [] = { { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2C) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2I) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_BOOT) }, @@ -145,6 +146,7 @@ static struct usb_device_id edgeport_2port_id_table [] = { static struct usb_device_id id_table_combined [] = { { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_1) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2C) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2I) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421_BOOT) }, @@ -1575,17 +1577,17 @@ static void handle_new_msr (struct edgeport_port *edge_port, __u8 msr) dbg ("%s - %02x", __FUNCTION__, msr); - if (msr & (MSR_DELTA_CTS | MSR_DELTA_DSR | MSR_DELTA_RI | MSR_DELTA_CD)) { + if (msr & (EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR | EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD)) { icount = &edge_port->icount; /* update input line counters */ - if (msr & MSR_DELTA_CTS) + if (msr & EDGEPORT_MSR_DELTA_CTS) icount->cts++; - if (msr & MSR_DELTA_DSR) + if (msr & EDGEPORT_MSR_DELTA_DSR) icount->dsr++; - if (msr & MSR_DELTA_CD) + if (msr & EDGEPORT_MSR_DELTA_CD) icount->dcd++; - if (msr & MSR_DELTA_RI) + if (msr & EDGEPORT_MSR_DELTA_RI) icount->rng++; wake_up_interruptible (&edge_port->delta_msr_wait); } @@ -2447,10 +2449,10 @@ static int edge_tiocmget(struct usb_serial_port *port, struct file *file) mcr = edge_port->shadow_mcr; result = ((mcr & MCR_DTR) ? TIOCM_DTR: 0) /* 0x002 */ | ((mcr & MCR_RTS) ? TIOCM_RTS: 0) /* 0x004 */ - | ((msr & MSR_CTS) ? TIOCM_CTS: 0) /* 0x020 */ - | ((msr & MSR_CD) ? TIOCM_CAR: 0) /* 0x040 */ - | ((msr & MSR_RI) ? TIOCM_RI: 0) /* 0x080 */ - | ((msr & MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */ + | ((msr & EDGEPORT_MSR_CTS) ? TIOCM_CTS: 0) /* 0x020 */ + | ((msr & EDGEPORT_MSR_CD) ? TIOCM_CAR: 0) /* 0x040 */ + | ((msr & EDGEPORT_MSR_RI) ? TIOCM_RI: 0) /* 0x080 */ + | ((msr & EDGEPORT_MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */ dbg("%s -- %x", __FUNCTION__, result); @@ -2679,11 +2681,24 @@ static struct usb_serial_device_type edgeport_2port_device = { static int __init edgeport_init(void) { - usb_serial_register (&edgeport_1port_device); - usb_serial_register (&edgeport_2port_device); - usb_register (&io_driver); + int retval; + retval = usb_serial_register(&edgeport_1port_device); + if (retval) + goto failed_1port_device_register; + retval = usb_serial_register(&edgeport_2port_device); + if (retval) + goto failed_2port_device_register; + retval = usb_register(&io_driver); + if (retval) + goto failed_usb_register; info(DRIVER_DESC " " DRIVER_VERSION); return 0; +failed_usb_register: + usb_serial_deregister(&edgeport_2port_device); +failed_2port_device_register: + usb_serial_deregister(&edgeport_1port_device); +failed_1port_device_register: + return retval; } static void __exit edgeport_exit (void) diff --git a/drivers/usb/serial/io_ti.h b/drivers/usb/serial/io_ti.h index 82a06c8b444c..cab84f2256b9 100644 --- a/drivers/usb/serial/io_ti.h +++ b/drivers/usb/serial/io_ti.h @@ -1,6 +1,6 @@ /***************************************************************************** * - * Copyright (c) 1997-2002 Inside Out Networks, Inc. + * Copyright (C) 1997-2002 Inside Out Networks, Inc. * * 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 diff --git a/drivers/usb/serial/io_usbvend.h b/drivers/usb/serial/io_usbvend.h index 37fe6744a92c..26a8c5a18ccf 100644 --- a/drivers/usb/serial/io_usbvend.h +++ b/drivers/usb/serial/io_usbvend.h @@ -7,7 +7,7 @@ * ************************************************************************ * - * Copyright (c) 1998 Inside Out Networks, Inc. + * Copyright (C) 1998 Inside Out Networks, Inc. * 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 @@ -118,6 +118,7 @@ #define ION_DEVICE_ID_TI_EDGEPORT_1 0x0215 /* Edgeport/1 RS232 */ #define ION_DEVICE_ID_TI_EDGEPORT_42 0x0217 /* Edgeport/42 4 hub 2 RS232 */ #define ION_DEVICE_ID_TI_EDGEPORT_22 0x021A /* Edgeport/22 Edgeport/22I is an Edgeport/4 with ports 1&2 RS422 and ports 3&4 RS232 */ +#define ION_DEVICE_ID_TI_EDGEPORT_2C 0x021B /* Edgeport/2c RS232 */ #define ION_DEVICE_ID_TI_EDGEPORT_421_BOOT 0x0240 /* Edgeport/421 in boot mode */ #define ION_DEVICE_ID_TI_EDGEPORT_421_DOWN 0x0241 /* Edgeport/421 in download mode first interface is 2 RS232 (Note that the second interface of this multi interface device should be a standard USB class 7 printer port) */ diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 78668e5fee94..62eec9f28d18 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -570,16 +570,25 @@ static void ipaq_shutdown(struct usb_serial *serial) static int __init ipaq_init(void) { + int retval; spin_lock_init(&write_list_lock); - usb_serial_register(&ipaq_device); + retval = usb_serial_register(&ipaq_device); + if (retval) + goto failed_usb_serial_register; info(DRIVER_DESC " " DRIVER_VERSION); if (vendor) { ipaq_id_table[0].idVendor = vendor; ipaq_id_table[0].idProduct = product; } - usb_register(&ipaq_driver); - + retval = usb_register(&ipaq_driver); + if (retval) + goto failed_usb_register; + return 0; +failed_usb_register: + usb_serial_deregister(&ipaq_device); +failed_usb_serial_register: + return retval; } diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index aaee94c86f45..77cb6b950a2f 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -609,10 +609,19 @@ static void ir_set_termios (struct usb_serial_port *port, struct termios *old_te static int __init ir_init (void) { - usb_serial_register (&ir_device); - usb_register (&ir_driver); + int retval; + retval = usb_serial_register(&ir_device); + if (retval) + goto failed_usb_serial_register; + retval = usb_register(&ir_driver); + if (retval) + goto failed_usb_register; info(DRIVER_DESC " " DRIVER_VERSION); return 0; +failed_usb_register: + usb_serial_deregister(&ir_device); +failed_usb_serial_register: + return retval; } diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 24da7b9372eb..3ae64c8048c3 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -197,15 +197,36 @@ struct keyspan_port_private { /* Functions used by new usb-serial code. */ static int __init keyspan_init (void) { - usb_serial_register (&keyspan_pre_device); - usb_serial_register (&keyspan_1port_device); - usb_serial_register (&keyspan_2port_device); - usb_serial_register (&keyspan_4port_device); - usb_register (&keyspan_driver); + int retval; + retval = usb_serial_register(&keyspan_pre_device); + if (retval) + goto failed_pre_device_register; + retval = usb_serial_register(&keyspan_1port_device); + if (retval) + goto failed_1port_device_register; + retval = usb_serial_register(&keyspan_2port_device); + if (retval) + goto failed_2port_device_register; + retval = usb_serial_register(&keyspan_4port_device); + if (retval) + goto failed_4port_device_register; + retval = usb_register(&keyspan_driver); + if (retval) + goto failed_usb_register; info(DRIVER_VERSION ":" DRIVER_DESC); return 0; +failed_usb_register: + usb_serial_deregister(&keyspan_4port_device); +failed_4port_device_register: + usb_serial_deregister(&keyspan_2port_device); +failed_2port_device_register: + usb_serial_deregister(&keyspan_1port_device); +failed_1port_device_register: + usb_serial_deregister(&keyspan_pre_device); +failed_pre_device_register: + return retval; } static void __exit keyspan_exit (void) diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 9fd076f7c258..36d8e6a8f5ae 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -1,9 +1,9 @@ /* * USB Keyspan PDA / Xircom / Entregra Converter driver * - * Copyright (c) 1999 - 2001 Greg Kroah-Hartman <greg@kroah.com> - * Copyright (c) 1999, 2000 Brian Warner <warner@lothar.com> - * Copyright (c) 2000 Al Borchers <borchers@steinerpoint.com> + * Copyright (C) 1999 - 2001 Greg Kroah-Hartman <greg@kroah.com> + * Copyright (C) 1999, 2000 Brian Warner <warner@lothar.com> + * Copyright (C) 2000 Al Borchers <borchers@steinerpoint.com> * * 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 @@ -876,16 +876,39 @@ static struct usb_serial_device_type keyspan_pda_device = { static int __init keyspan_pda_init (void) { - usb_serial_register (&keyspan_pda_device); + int retval; + retval = usb_serial_register(&keyspan_pda_device); + if (retval) + goto failed_pda_register; #ifdef KEYSPAN - usb_serial_register (&keyspan_pda_fake_device); + retval = usb_serial_register(&keyspan_pda_fake_device); + if (retval) + goto failed_pda_fake_register; #endif #ifdef XIRCOM - usb_serial_register (&xircom_pgs_fake_device); + retval = usb_serial_register(&xircom_pgs_fake_device); + if (retval) + goto failed_xircom_register; #endif - usb_register (&keyspan_pda_driver); + retval = usb_register(&keyspan_pda_driver); + if (retval) + goto failed_usb_register; info(DRIVER_DESC " " DRIVER_VERSION); return 0; +failed_usb_register: +#ifdef XIRCOM + usb_serial_deregister(&xircom_pgs_fake_device); +failed_xircom_register: +#endif /* XIRCOM */ +#ifdef KEYSPAN + usb_serial_deregister(&keyspan_pda_fake_device); +#endif +#ifdef KEYSPAN +failed_pda_fake_register: +#endif + usb_serial_deregister(&keyspan_pda_device); +failed_pda_register: + return retval; } diff --git a/drivers/usb/serial/keyspan_pda_fw.h b/drivers/usb/serial/keyspan_pda_fw.h index d73c548c3286..f253accd231c 100644 --- a/drivers/usb/serial/keyspan_pda_fw.h +++ b/drivers/usb/serial/keyspan_pda_fw.h @@ -1,7 +1,7 @@ /* * USB Keyspan PDA Firmware * - * Copyright (c) 1999, 2000 Brian Warner <warner@lothar.com> + * Copyright (C) 1999, 2000 Brian Warner <warner@lothar.com> * * 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 diff --git a/drivers/usb/serial/keyspan_usa26msg.h b/drivers/usb/serial/keyspan_usa26msg.h index cac3d501f523..f859c22d4153 100644 --- a/drivers/usb/serial/keyspan_usa26msg.h +++ b/drivers/usb/serial/keyspan_usa26msg.h @@ -1,7 +1,7 @@ /* usa26msg.h - Copyright (c) 1998-2000 InnoSys Incorporated. All Rights Reserved + Copyright (C) 1998-2000 InnoSys Incorporated. All Rights Reserved This file is available under a BSD-style copyright Keyspan USB Async Firmware to run on Anchor EZ-USB @@ -15,7 +15,7 @@ disclaimer. The following copyright notice must appear immediately at the beginning of all source files: - Copyright (c) 1998-2000 InnoSys Incorporated. All Rights Reserved + Copyright (C) 1998-2000 InnoSys Incorporated. All Rights Reserved This file is available under a BSD-style copyright diff --git a/drivers/usb/serial/keyspan_usa28msg.h b/drivers/usb/serial/keyspan_usa28msg.h index d76eb72878e1..24d5f7a8d119 100644 --- a/drivers/usb/serial/keyspan_usa28msg.h +++ b/drivers/usb/serial/keyspan_usa28msg.h @@ -1,7 +1,7 @@ /* usa28msg.h - Copyright (c) 1998-2000 InnoSys Incorporated. All Rights Reserved + Copyright (C) 1998-2000 InnoSys Incorporated. All Rights Reserved This file is available under a BSD-style copyright Keyspan USB Async Firmware to run on Anchor EZ-USB @@ -15,7 +15,7 @@ disclaimer. The following copyright notice must appear immediately at the beginning of all source files: - Copyright (c) 1998-2000 InnoSys Incorporated. All Rights Reserved + Copyright (C) 1998-2000 InnoSys Incorporated. All Rights Reserved This file is available under a BSD-style copyright diff --git a/drivers/usb/serial/keyspan_usa49msg.h b/drivers/usb/serial/keyspan_usa49msg.h index 320b2cc76874..7c369adad804 100644 --- a/drivers/usb/serial/keyspan_usa49msg.h +++ b/drivers/usb/serial/keyspan_usa49msg.h @@ -1,7 +1,7 @@ /* usa49msg.h - Copyright (c) 1998-2000 InnoSys Incorporated. All Rights Reserved + Copyright (C) 1998-2000 InnoSys Incorporated. All Rights Reserved This file is available under a BSD-style copyright Keyspan USB Async Firmware to run on Anchor EZ-USB @@ -15,7 +15,7 @@ disclaimer. The following copyright notice must appear immediately at the beginning of all source files: - Copyright (c) 1998-2000 InnoSys Incorporated. All Rights Reserved + Copyright (C) 1998-2000 InnoSys Incorporated. All Rights Reserved This file is available under a BSD-style copyright diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 9b96313df476..1ebc09851dcd 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -1037,11 +1037,20 @@ static void klsi_105_unthrottle (struct usb_serial_port *port) static int __init klsi_105_init (void) { - usb_serial_register (&kl5kusb105d_device); - usb_register (&kl5kusb105d_driver); + int retval; + retval = usb_serial_register(&kl5kusb105d_device); + if (retval) + goto failed_usb_serial_register; + retval = usb_register(&kl5kusb105d_driver); + if (retval) + goto failed_usb_register; info(DRIVER_DESC " " DRIVER_VERSION); return 0; +failed_usb_register: + usb_serial_deregister(&kl5kusb105d_device); +failed_usb_serial_register: + return retval; } diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index fef3420b6672..cb588ec79c5a 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -743,13 +743,22 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file *file, static int __init kobil_init (void) { - usb_serial_register (&kobil_device); - usb_register (&kobil_driver); + int retval; + retval = usb_serial_register(&kobil_device); + if (retval) + goto failed_usb_serial_register; + retval = usb_register(&kobil_driver); + if (retval) + goto failed_usb_register; info(DRIVER_VERSION " " DRIVER_AUTHOR); info(DRIVER_DESC); return 0; +failed_usb_register: + usb_serial_deregister(&kobil_device); +failed_usb_serial_register: + return retval; } diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 60da81c8c8bc..2264cf6e195b 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -850,10 +850,19 @@ static int mct_u232_ioctl (struct usb_serial_port *port, struct file * file, static int __init mct_u232_init (void) { - usb_serial_register (&mct_u232_device); - usb_register (&mct_u232_driver); + int retval; + retval = usb_serial_register(&mct_u232_device); + if (retval) + goto failed_usb_serial_register; + retval = usb_register(&mct_u232_driver); + if (retval) + goto failed_usb_register; info(DRIVER_DESC " " DRIVER_VERSION); return 0; +failed_usb_register: + usb_serial_deregister(&mct_u232_device); +failed_usb_serial_register: + return retval; } diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index b770f74e09e1..eacc85983a77 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -375,10 +375,19 @@ static void omninet_shutdown (struct usb_serial *serial) static int __init omninet_init (void) { - usb_serial_register (&zyxel_omninet_device); - usb_register (&omninet_driver); + int retval; + retval = usb_serial_register(&zyxel_omninet_device); + if (retval) + goto failed_usb_serial_register; + retval = usb_register(&omninet_driver); + if (retval) + goto failed_usb_register; info(DRIVER_VERSION ":" DRIVER_DESC); return 0; +failed_usb_register: + usb_serial_deregister(&zyxel_omninet_device); +failed_usb_serial_register: + return retval; } diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 88af8911b95d..40e3d42dbabd 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -768,10 +768,19 @@ static void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs) static int __init pl2303_init (void) { - usb_serial_register (&pl2303_device); - usb_register (&pl2303_driver); + int retval; + retval = usb_serial_register(&pl2303_device); + if (retval) + goto failed_usb_serial_register; + retval = usb_register(&pl2303_driver); + if (retval) + goto failed_usb_register; info(DRIVER_DESC " " DRIVER_VERSION); return 0; +failed_usb_register: + usb_serial_deregister(&pl2303_device); +failed_usb_serial_register: + return retval; } diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index cb6e9ab24fb4..9f894ddcae7b 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -1,8 +1,8 @@ /* * Safe Encapsulated USB Serial Driver * - * Copyright (c) 2001 Lineo - * Copyright (c) 2001 Hewlett-Packard + * Copyright (C) 2001 Lineo + * Copyright (C) 2001 Hewlett-Packard * * 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 @@ -422,7 +422,7 @@ static struct usb_serial_device_type safe_device = { static int __init safe_init (void) { - int i; + int i, retval; info (DRIVER_VERSION " " DRIVER_AUTHOR); info (DRIVER_DESC); @@ -441,10 +441,18 @@ static int __init safe_init (void) } } - usb_serial_register (&safe_device); - usb_register (&safe_driver); + retval = usb_serial_register(&safe_device); + if (retval) + goto failed_usb_serial_register; + retval = usb_register(&safe_driver); + if (retval) + goto failed_usb_register; return 0; +failed_usb_register: + usb_serial_deregister(&safe_device); +failed_usb_serial_register: + return retval; } static void __exit safe_exit (void) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 86253ae30fe6..37554c1ea836 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -2,8 +2,8 @@ * USB Serial Converter driver * * Copyright (C) 1999 - 2003 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2000 Peter Berger (pberger@brimson.com) - * Copyright (c) 2000 Al Borchers (borchers@steinerpoint.com) + * Copyright (C) 2000 Peter Berger (pberger@brimson.com) + * Copyright (C) 2000 Al Borchers (borchers@steinerpoint.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version @@ -871,7 +871,8 @@ static void destroy_serial (struct kobject *kobj) /* the ports are cleaned up and released in port_release() */ for (i = 0; i < serial->num_ports; ++i) - device_unregister(&serial->port[i]->dev); + if (serial->port[i]->dev.parent != NULL) + device_unregister(&serial->port[i]->dev); /* If this is a "fake" port, we have to clean it up here, as it will * not get cleaned up in port_release() as it was never registered with diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 9ac26dbd5a27..d13f690214ba 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -225,11 +225,16 @@ static struct usb_device_id id_table [] = { .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID), .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID) }, + { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID), + .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NX60_ID), .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NZ90V_ID), .driver_info = (kernel_ulong_t)&palm_os_4_probe }, + { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID), + .driver_info = (kernel_ulong_t)&palm_os_4_probe }, + { USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID), + .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { }, /* optional parameter entry */ { } /* Terminating entry */ }; @@ -258,6 +263,8 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NX60_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NZ90V_ID) }, + { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID) }, + { USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID) }, { }, /* optional parameter entry */ { } /* Terminating entry */ }; @@ -649,7 +656,7 @@ static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_i transfer_buffer = kmalloc (sizeof (*connection_info), GFP_KERNEL); if (!transfer_buffer) { - dev_err(dev, "%s - kmalloc(%d) failed.\n", __FUNCTION__, + dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __FUNCTION__, sizeof(*connection_info)); return -ENOMEM; } @@ -735,7 +742,7 @@ static int palm_os_4_probe (struct usb_serial *serial, const struct usb_device_i transfer_buffer = kmalloc (sizeof (*connection_info), GFP_KERNEL); if (!transfer_buffer) { - dev_err(dev, "%s - kmalloc(%d) failed.\n", __FUNCTION__, + dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __FUNCTION__, sizeof(*connection_info)); return -ENOMEM; } @@ -956,7 +963,7 @@ static void visor_set_termios (struct usb_serial_port *port, struct termios *old static int __init visor_init (void) { - int i; + int i, retval; /* Only if parameters were passed to us */ if ((vendor>0) && (product>0)) { struct usb_device_id usb_dev_temp[]= @@ -983,12 +990,24 @@ static int __init visor_init (void) info("Adding Palm OS protocol 4.x support for unknown device: 0x%x/0x%x", vendor, product); } - usb_serial_register (&handspring_device); - usb_serial_register (&clie_3_5_device); - usb_register (&visor_driver); + retval = usb_serial_register(&handspring_device); + if (retval) + goto failed_handspring_register; + retval = usb_serial_register(&clie_3_5_device); + if (retval) + goto failed_clie_3_5_register; + retval = usb_register(&visor_driver); + if (retval) + goto failed_usb_register; info(DRIVER_DESC " " DRIVER_VERSION); return 0; +failed_usb_register: + usb_serial_deregister(&clie_3_5_device); +failed_clie_3_5_register: + usb_serial_deregister(&handspring_device); +failed_handspring_register: + return retval; } diff --git a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h index 7f36db2254ee..f26c81c7ebe9 100644 --- a/drivers/usb/serial/visor.h +++ b/drivers/usb/serial/visor.h @@ -41,6 +41,12 @@ #define SONY_CLIE_NX60_ID 0x00DA #define SONY_CLIE_NZ90V_ID 0x00E9 +#define SAMSUNG_VENDOR_ID 0x04E8 +#define SAMSUNG_SCH_I330_ID 0x8001 + +#define GARMIN_VENDOR_ID 0x091E +#define GARMIN_IQUE_3600_ID 0x0004 + /**************************************************************************** * Handspring Visor Vendor specific request codes (bRequest values) * A big thank you to Handspring for providing the following information. diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index f71d9e638e48..9e7d48c92c9f 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -1486,11 +1486,24 @@ static void rx_data_softint(void *private) *****************************************************************************/ static int __init whiteheat_init (void) { - usb_serial_register (&whiteheat_fake_device); - usb_serial_register (&whiteheat_device); - usb_register (&whiteheat_driver); + int retval; + retval = usb_serial_register(&whiteheat_fake_device); + if (retval) + goto failed_fake_register; + retval = usb_serial_register(&whiteheat_device); + if (retval) + goto failed_device_register; + retval = usb_register(&whiteheat_driver); + if (retval) + goto failed_usb_register; info(DRIVER_DESC " " DRIVER_VERSION); return 0; +failed_usb_register: + usb_serial_deregister(&whiteheat_device); +failed_device_register: + usb_serial_deregister(&whiteheat_fake_device); +failed_fake_register: + return retval; } diff --git a/drivers/usb/serial/xircom_pgs_fw.h b/drivers/usb/serial/xircom_pgs_fw.h index 423d2caa170b..3ff74a6d71a9 100644 --- a/drivers/usb/serial/xircom_pgs_fw.h +++ b/drivers/usb/serial/xircom_pgs_fw.h @@ -1,8 +1,8 @@ /* * USB Xircom PGS Firmware * - * Copyright (c) 1999, 2000 Brian Warner <warner@lothar.com> - * Copyright (c) 2001 Cristian M. Craciunescu <cristi@dnt.ro> + * Copyright (C) 1999, 2000 Brian Warner <warner@lothar.com> + * Copyright (C) 2001 Cristian M. Craciunescu <cristi@dnt.ro> * * 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 diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c index 70b87e654e31..d623eaaefdf0 100644 --- a/drivers/usb/storage/isd200.c +++ b/drivers/usb/storage/isd200.c @@ -272,8 +272,9 @@ struct isd200_config { struct isd200_info { struct inquiry_data InquiryData; - struct hd_driveid drive; + struct hd_driveid *id; struct isd200_config ConfigData; + unsigned char *RegsBuf; unsigned char ATARegs[8]; unsigned char DeviceHead; unsigned char DeviceFlags; @@ -473,7 +474,7 @@ static int isd200_action( struct us_data *us, int action, ata.generic.RegisterSelect = REG_COMMAND; ata.write.CommandByte = WIN_IDENTIFY; srb->sc_data_direction = SCSI_DATA_READ; - srb->request_buffer = (void *)&info->drive; + srb->request_buffer = (void *) info->id; srb->request_bufflen = sizeof(struct hd_driveid); break; @@ -513,11 +514,12 @@ int isd200_read_regs( struct us_data *us ) US_DEBUGP("Entering isd200_IssueATAReadRegs\n"); transferStatus = isd200_action( us, ACTION_READ_STATUS, - info->ATARegs, sizeof(info->ATARegs) ); + info->RegsBuf, sizeof(info->ATARegs) ); if (transferStatus != ISD200_TRANSPORT_GOOD) { US_DEBUGP(" Error reading ATA registers\n"); retStatus = ISD200_ERROR; } else { + memcpy(info->ATARegs, info->RegsBuf, sizeof(info->ATARegs)); US_DEBUGP(" Got ATA Register[IDE_ERROR_OFFSET] = 0x%x\n", info->ATARegs[IDE_ERROR_OFFSET]); } @@ -835,9 +837,9 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave, int detect ) { int status = ISD200_GOOD; - unsigned char *regs = us->iobuf; unsigned long endTime; struct isd200_info *info = (struct isd200_info *)us->extra; + unsigned char *regs = info->RegsBuf; int recheckAsMaster = FALSE; if ( detect ) @@ -984,6 +986,7 @@ int isd200_get_inquiry_data( struct us_data *us ) { struct isd200_info *info = (struct isd200_info *)us->extra; int retStatus = ISD200_GOOD; + struct hd_driveid *id = info->id; US_DEBUGP("Entering isd200_get_inquiry_data\n"); @@ -1000,7 +1003,7 @@ int isd200_get_inquiry_data( struct us_data *us ) /* this must be an ATA device */ /* perform an ATA Command Identify */ transferStatus = isd200_action( us, ACTION_IDENTIFY, - &info->drive, + id, sizeof(struct hd_driveid) ); if (transferStatus != ISD200_TRANSPORT_GOOD) { /* Error issuing ATA Command Identify */ @@ -1010,35 +1013,35 @@ int isd200_get_inquiry_data( struct us_data *us ) /* ATA Command Identify successful */ int i; __u16 *src, *dest; - ide_fix_driveid(&info->drive); + ide_fix_driveid(id); US_DEBUGP(" Identify Data Structure:\n"); - US_DEBUGP(" config = 0x%x\n", info->drive.config); - US_DEBUGP(" cyls = 0x%x\n", info->drive.cyls); - US_DEBUGP(" heads = 0x%x\n", info->drive.heads); - US_DEBUGP(" track_bytes = 0x%x\n", info->drive.track_bytes); - US_DEBUGP(" sector_bytes = 0x%x\n", info->drive.sector_bytes); - US_DEBUGP(" sectors = 0x%x\n", info->drive.sectors); - US_DEBUGP(" serial_no[0] = 0x%x\n", info->drive.serial_no[0]); - US_DEBUGP(" buf_type = 0x%x\n", info->drive.buf_type); - US_DEBUGP(" buf_size = 0x%x\n", info->drive.buf_size); - US_DEBUGP(" ecc_bytes = 0x%x\n", info->drive.ecc_bytes); - US_DEBUGP(" fw_rev[0] = 0x%x\n", info->drive.fw_rev[0]); - US_DEBUGP(" model[0] = 0x%x\n", info->drive.model[0]); - US_DEBUGP(" max_multsect = 0x%x\n", info->drive.max_multsect); - US_DEBUGP(" dword_io = 0x%x\n", info->drive.dword_io); - US_DEBUGP(" capability = 0x%x\n", info->drive.capability); - US_DEBUGP(" tPIO = 0x%x\n", info->drive.tPIO); - US_DEBUGP(" tDMA = 0x%x\n", info->drive.tDMA); - US_DEBUGP(" field_valid = 0x%x\n", info->drive.field_valid); - US_DEBUGP(" cur_cyls = 0x%x\n", info->drive.cur_cyls); - US_DEBUGP(" cur_heads = 0x%x\n", info->drive.cur_heads); - US_DEBUGP(" cur_sectors = 0x%x\n", info->drive.cur_sectors); - US_DEBUGP(" cur_capacity = 0x%x\n", (info->drive.cur_capacity1 << 16) + info->drive.cur_capacity0 ); - US_DEBUGP(" multsect = 0x%x\n", info->drive.multsect); - US_DEBUGP(" lba_capacity = 0x%x\n", info->drive.lba_capacity); - US_DEBUGP(" command_set_1 = 0x%x\n", info->drive.command_set_1); - US_DEBUGP(" command_set_2 = 0x%x\n", info->drive.command_set_2); + US_DEBUGP(" config = 0x%x\n", id->config); + US_DEBUGP(" cyls = 0x%x\n", id->cyls); + US_DEBUGP(" heads = 0x%x\n", id->heads); + US_DEBUGP(" track_bytes = 0x%x\n", id->track_bytes); + US_DEBUGP(" sector_bytes = 0x%x\n", id->sector_bytes); + US_DEBUGP(" sectors = 0x%x\n", id->sectors); + US_DEBUGP(" serial_no[0] = 0x%x\n", id->serial_no[0]); + US_DEBUGP(" buf_type = 0x%x\n", id->buf_type); + US_DEBUGP(" buf_size = 0x%x\n", id->buf_size); + US_DEBUGP(" ecc_bytes = 0x%x\n", id->ecc_bytes); + US_DEBUGP(" fw_rev[0] = 0x%x\n", id->fw_rev[0]); + US_DEBUGP(" model[0] = 0x%x\n", id->model[0]); + US_DEBUGP(" max_multsect = 0x%x\n", id->max_multsect); + US_DEBUGP(" dword_io = 0x%x\n", id->dword_io); + US_DEBUGP(" capability = 0x%x\n", id->capability); + US_DEBUGP(" tPIO = 0x%x\n", id->tPIO); + US_DEBUGP(" tDMA = 0x%x\n", id->tDMA); + US_DEBUGP(" field_valid = 0x%x\n", id->field_valid); + US_DEBUGP(" cur_cyls = 0x%x\n", id->cur_cyls); + US_DEBUGP(" cur_heads = 0x%x\n", id->cur_heads); + US_DEBUGP(" cur_sectors = 0x%x\n", id->cur_sectors); + US_DEBUGP(" cur_capacity = 0x%x\n", (id->cur_capacity1 << 16) + id->cur_capacity0 ); + US_DEBUGP(" multsect = 0x%x\n", id->multsect); + US_DEBUGP(" lba_capacity = 0x%x\n", id->lba_capacity); + US_DEBUGP(" command_set_1 = 0x%x\n", id->command_set_1); + US_DEBUGP(" command_set_2 = 0x%x\n", id->command_set_2); memset(&info->InquiryData, 0, sizeof(info->InquiryData)); @@ -1054,30 +1057,30 @@ int isd200_get_inquiry_data( struct us_data *us ) /* The length must be at least 36 (5 + 31) */ info->InquiryData.AdditionalLength = 0x1F; - if (info->drive.command_set_1 & COMMANDSET_MEDIA_STATUS) { + if (id->command_set_1 & COMMANDSET_MEDIA_STATUS) { /* set the removable bit */ info->InquiryData.DeviceTypeModifier = DEVICE_REMOVABLE; info->DeviceFlags |= DF_REMOVABLE_MEDIA; } /* Fill in vendor identification fields */ - src = (__u16*)info->drive.model; + src = (__u16*)id->model; dest = (__u16*)info->InquiryData.VendorId; for (i=0;i<4;i++) dest[i] = be16_to_cpu(src[i]); - src = (__u16*)(info->drive.model+8); + src = (__u16*)(id->model+8); dest = (__u16*)info->InquiryData.ProductId; for (i=0;i<8;i++) dest[i] = be16_to_cpu(src[i]); - src = (__u16*)info->drive.fw_rev; + src = (__u16*)id->fw_rev; dest = (__u16*)info->InquiryData.ProductRevisionLevel; for (i=0;i<2;i++) dest[i] = be16_to_cpu(src[i]); /* determine if it supports Media Status Notification */ - if (info->drive.command_set_2 & COMMANDSET_MEDIA_STATUS) { + if (id->command_set_2 & COMMANDSET_MEDIA_STATUS) { US_DEBUGP(" Device supports Media Status Notification\n"); /* Indicate that it is enabled, even though it is not @@ -1101,11 +1104,9 @@ int isd200_get_inquiry_data( struct us_data *us ) US_DEBUGP("Protocol changed to: %s\n", us->protocol_name); /* Free driver structure */ - if (us->extra != NULL) { - kfree(us->extra); - us->extra = NULL; - us->extra_destructor = NULL; - } + us->extra_destructor(info); + us->extra = NULL; + us->extra_destructor = NULL; } } @@ -1182,6 +1183,7 @@ int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us, union ata_cdb * ataCdb) { struct isd200_info *info = (struct isd200_info *)us->extra; + struct hd_driveid *id = info->id; int sendToTransport = TRUE; unsigned char sectnum, head; unsigned short cylinder; @@ -1254,12 +1256,12 @@ int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us, US_DEBUGP(" ATA OUT - SCSIOP_READ_CAPACITY\n"); - if (info->drive.capability & CAPABILITY_LBA ) { - capacity = info->drive.lba_capacity - 1; + if (id->capability & CAPABILITY_LBA ) { + capacity = id->lba_capacity - 1; } else { - capacity = (info->drive.heads * - info->drive.cyls * - info->drive.sectors) - 1; + capacity = (id->heads * + id->cyls * + id->sectors) - 1; } readCapacityData.LogicalBlockAddress = cpu_to_be32(capacity); readCapacityData.BytesPerBlock = cpu_to_be32(0x200); @@ -1280,16 +1282,16 @@ int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us, lba = cpu_to_be32(lba); blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8]; - if (info->drive.capability & CAPABILITY_LBA) { + if (id->capability & CAPABILITY_LBA) { sectnum = (unsigned char)(lba); cylinder = (unsigned short)(lba>>8); head = ATA_ADDRESS_DEVHEAD_LBA_MODE | (unsigned char)(lba>>24 & 0x0F); } else { - sectnum = (unsigned char)((lba % info->drive.sectors) + 1); - cylinder = (unsigned short)(lba / (info->drive.sectors * - info->drive.heads)); - head = (unsigned char)((lba / info->drive.sectors) % - info->drive.heads); + sectnum = (unsigned char)((lba % id->sectors) + 1); + cylinder = (unsigned short)(lba / (id->sectors * + id->heads)); + head = (unsigned char)((lba / id->sectors) % + id->heads); } ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; @@ -1313,14 +1315,14 @@ int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us, lba = cpu_to_be32(lba); blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8]; - if (info->drive.capability & CAPABILITY_LBA) { + if (id->capability & CAPABILITY_LBA) { sectnum = (unsigned char)(lba); cylinder = (unsigned short)(lba>>8); head = ATA_ADDRESS_DEVHEAD_LBA_MODE | (unsigned char)(lba>>24 & 0x0F); } else { - sectnum = (unsigned char)((lba % info->drive.sectors) + 1); - cylinder = (unsigned short)(lba / (info->drive.sectors * info->drive.heads)); - head = (unsigned char)((lba / info->drive.sectors) % info->drive.heads); + sectnum = (unsigned char)((lba % id->sectors) + 1); + cylinder = (unsigned short)(lba / (id->sectors * id->heads)); + head = (unsigned char)((lba / id->sectors) % id->heads); } ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; @@ -1398,6 +1400,21 @@ int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us, /************************************************************************** + * isd200_free_info + * + * Frees the driver structure. + */ +void isd200_free_info_ptrs(void *info_) +{ + struct isd200_info *info = (struct isd200_info *) info_; + + if (info) { + kfree(info->id); + kfree(info->RegsBuf); + } +} + +/************************************************************************** * isd200_init_info * * Allocates (if necessary) and initializes the driver structure. @@ -1408,18 +1425,31 @@ int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us, int isd200_init_info(struct us_data *us) { int retStatus = ISD200_GOOD; + struct isd200_info *info; - if (!us->extra) { - us->extra = (void *) kmalloc(sizeof(struct isd200_info), GFP_KERNEL); - if (!us->extra) { - US_DEBUGP("ERROR - kmalloc failure\n"); + info = (struct isd200_info *) + kmalloc(sizeof(struct isd200_info), GFP_KERNEL); + if (!info) + retStatus = ISD200_ERROR; + else { + memset(info, 0, sizeof(struct isd200_info)); + info->id = (struct hd_driveid *) + kmalloc(sizeof(struct hd_driveid), GFP_KERNEL); + info->RegsBuf = (unsigned char *) + kmalloc(sizeof(info->ATARegs), GFP_KERNEL); + if (!info->id || !info->RegsBuf) { + isd200_free_info_ptrs(info); + kfree(info); retStatus = ISD200_ERROR; - } + } else + memset(info->id, 0, sizeof(struct hd_driveid)); } if (retStatus == ISD200_GOOD) { - memset(us->extra, 0, sizeof(struct isd200_info)); - } + us->extra = info; + us->extra_destructor = isd200_free_info_ptrs; + } else + US_DEBUGP("ERROR - kmalloc failure\n"); return(retStatus); } diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c index 9fb7b9ce6970..6385cb4f0819 100644 --- a/drivers/usb/storage/sddr09.c +++ b/drivers/usb/storage/sddr09.c @@ -34,6 +34,7 @@ #include "debug.h" #include "sddr09.h" +#include <linux/version.h> #include <linux/sched.h> #include <linux/errno.h> #include <linux/slab.h> diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 8959498ee2d0..81e6c62a28ee 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -942,11 +942,11 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) memcpy(bcb->CDB, srb->cmnd, bcb->Length); /* send it to out endpoint */ - US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n", + US_DEBUGP("Bulk Command S 0x%x T 0x%x L %d F %d Trg %d LUN %d CL %d\n", le32_to_cpu(bcb->Signature), bcb->Tag, + le32_to_cpu(bcb->DataTransferLength), bcb->Flags, (bcb->Lun >> 4), (bcb->Lun & 0x0F), - le32_to_cpu(bcb->DataTransferLength), - bcb->Flags, bcb->Length); + bcb->Length); result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb, US_BULK_CB_WRAP_LEN, NULL); US_DEBUGP("Bulk command transfer result=%d\n", result); @@ -999,7 +999,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) return USB_STOR_TRANSPORT_ERROR; /* check bulk status */ - US_DEBUGP("Bulk status Sig 0x%x T 0x%x R %d Stat 0x%x\n", + US_DEBUGP("Bulk Status S 0x%x T 0x%x R %d Stat 0x%x\n", le32_to_cpu(bcs->Signature), bcs->Tag, bcs->Residue, bcs->Status); if ((bcs->Signature != cpu_to_le32(US_BULK_CS_SIGN) && diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index b6d69d047d39..eaf8d42ff1c9 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -264,7 +264,7 @@ UNUSUAL_DEV( 0x054c, 0x002d, 0x0100, 0x0100, UNUSUAL_DEV( 0x054c, 0x002e, 0x0106, 0x0310, "Sony", "Handycam", - US_SC_SCSI, US_PR_CB, NULL, + US_SC_SCSI, US_PR_DEVICE, NULL, US_FL_SINGLE_LUN | US_FL_MODE_XLATE), UNUSUAL_DEV( 0x054c, 0x0032, 0x0000, 0x9999, diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 01413b6212db..0a1a22b1cba9 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -1006,20 +1006,23 @@ static void storage_disconnect(struct usb_interface *intf) * Initialization and registration ***********************************************************************/ -int __init usb_stor_init(void) +static int __init usb_stor_init(void) { + int retval; printk(KERN_INFO "Initializing USB Mass Storage driver...\n"); - /* register the driver, return -1 if error */ - if (usb_register(&usb_storage_driver) < 0) - return -1; + /* register the driver, return usb_register return code if error */ + retval = usb_register(&usb_storage_driver); + if (retval) + goto out; /* we're all set */ printk(KERN_INFO "USB Mass Storage support registered.\n"); - return 0; +out: + return retval; } -void __exit usb_stor_exit(void) +static void __exit usb_stor_exit(void) { US_DEBUGP("usb_stor_exit() called\n"); diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h index 0a969d577ed2..2615d0f3fa16 100644 --- a/drivers/usb/storage/usb.h +++ b/drivers/usb/storage/usb.h @@ -48,7 +48,6 @@ #include <linux/blkdev.h> #include <linux/smp_lock.h> #include <linux/completion.h> -#include <linux/version.h> #include "scsi.h" #include "hosts.h" diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index a4cb3f94c577..7400113b1b0e 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -1,7 +1,7 @@ /* * USB Skeleton driver - 1.1 * - * Copyright (c) 2001-2003 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2001-2003 Greg Kroah-Hartman (greg@kroah.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -295,7 +295,7 @@ static int skel_release (struct inode *inode, struct file *file) if (atomic_read (&dev->write_busy)) wait_for_completion (&dev->write_finished); - dev->open = 0; + --dev->open; if (!dev->present) { /* the device was unplugged before the file was released */ @@ -677,10 +677,10 @@ static int __init usb_skel_init(void) /* register this driver with the USB subsystem */ result = usb_register(&skel_driver); - if (result < 0) { + if (result) { err("usb_register failed. Error number %d", result); - return -1; + return result; } info(DRIVER_DESC " " DRIVER_VERSION); diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 153a4b0ff288..10114ce265da 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,3 +1,14 @@ +Version 0.91 +------------ +Fix oops in reopen_files when invalid dentry. drop dentry on server rename +and on revalidate errors. Fix cases where pid is now tgid. Fix return code +on create hard link when server does not support them. + +Version 0.90 +------------ +Fix scheduling while atomic error in getting inode info on newly created file. +Fix truncate of existing files opened with O_CREAT but not O_TRUNC set. + Version 0.89 ------------ Fix oops on write to dead tcp session. Remove error log write for case when file open diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 9643932c9df2..ef523c53f680 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1,7 +1,7 @@ /* * fs/cifs/cifssmb.c * - * Copyright (c) International Business Machines Corp., 2002 + * Copyright (C) International Business Machines Corp., 2002,2003 * Author(s): Steve French (sfrench@us.ibm.com) * * Contains the routines for constructing the SMB PDUs themselves @@ -656,7 +656,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, pSMB->AndXCommand = 0xFF; /* none */ pSMB->Fid = smb_file_id; /* netfid stays le */ - pSMB->Locks[0].Pid = cpu_to_le16(current->pid); + pSMB->Locks[0].Pid = cpu_to_le16(current->tgid); pSMB->Locks[0].Length = cpu_to_le64(len); pSMB->Locks[0].Offset = cpu_to_le64(offset); pSMB->ByteCount = sizeof (LOCKING_ANDX_RANGE); diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 7795f24d90b4..8873ca0447c9 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -3,7 +3,7 @@ * * vfs operations that deal with dentries * - * Copyright (c) International Business Machines Corp., 2002 + * Copyright (C) International Business Machines Corp., 2002,2003 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -134,6 +134,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, struct inode *newinode = NULL; struct cifsFileInfo * pCifsFile = NULL; struct cifsInodeInfo * pCifsInode; + int disposition = FILE_OVERWRITE_IF; xid = GetXid(); @@ -151,6 +152,16 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, desiredAccess = GENERIC_WRITE; else if ((nd->intent.open.flags & O_ACCMODE) == O_RDWR) desiredAccess = GENERIC_ALL; + + if((nd->intent.open.flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) + disposition = FILE_CREATE; + else if((nd->intent.open.flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) + disposition = FILE_OVERWRITE_IF; + else if((nd->intent.open.flags & O_CREAT) == O_CREAT) + disposition = FILE_OPEN_IF; + else { + cFYI(1,("Create flag not set in create function")); + } } /* BB add processing to set equivalent of mode - e.g. via CreateX with ACLs */ @@ -158,7 +169,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, oplock = REQ_OPLOCK; buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); - rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OVERWRITE_IF, + rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, CREATE_NOT_DIR, &fileHandle, &oplock, buf, cifs_sb->local_nls); if (rc) { @@ -205,7 +216,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, memset((char *)pCifsFile, 0, sizeof (struct cifsFileInfo)); pCifsFile->netfid = fileHandle; - pCifsFile->pid = current->pid; + pCifsFile->pid = current->tgid; pCifsFile->pInode = newinode; /* pCifsFile->pfile = file; */ /* put in at open time */ write_lock(&GlobalSMBSeslock); @@ -297,6 +308,9 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name (" parent inode = 0x%p name is: %s and dentry = 0x%p", parent_dir_inode, direntry->d_name.name, direntry)); + if(nd) { /* BB removeme */ + cFYI(1,("In lookup nd flags 0x%x open intent flags 0x%x",nd->flags,nd->intent.open.flags)); + } /* BB removeme BB */ /* BB Add check of incoming data - e.g. frame not longer than maximum SMB - let server check the namelen BB */ /* check whether path exists */ diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 49f9c88c65cc..247a39b899b3 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -3,7 +3,7 @@ * * vfs operations that deal with files * - * Copyright (c) International Business Machines Corp., 2002 + * Copyright (C) International Business Machines Corp., 2002,2003 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -144,6 +144,10 @@ cifs_open(struct inode *inode, struct file *file) list_add(&pCifsFile->tlist,&pTcon->openFileList); pCifsInode = CIFS_I(file->f_dentry->d_inode); if(pCifsInode) { + list_add(&pCifsFile->flist,&pCifsInode->openFileList); + write_unlock(&GlobalSMBSeslock); + write_unlock(&file->f_owner.lock); + if (pTcon->ses->capabilities & CAP_UNIX) rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode, full_path, inode->i_sb); @@ -151,16 +155,16 @@ cifs_open(struct inode *inode, struct file *file) rc = cifs_get_inode_info(&file->f_dentry->d_inode, full_path, buf, inode->i_sb); - list_add(&pCifsFile->flist,&pCifsInode->openFileList); if(oplock == OPLOCK_EXCLUSIVE) { pCifsInode->clientCanCacheAll = TRUE; pCifsInode->clientCanCacheRead = TRUE; cFYI(1,("Exclusive Oplock granted on inode %p",file->f_dentry->d_inode)); } else if(oplock == OPLOCK_READ) pCifsInode->clientCanCacheRead = TRUE; + } else { + write_unlock(&GlobalSMBSeslock); + write_unlock(&file->f_owner.lock); } - write_unlock(&GlobalSMBSeslock); - write_unlock(&file->f_owner.lock); if(file->f_flags & O_CREAT) { /* time to set mode which we can not set earlier due to problems creating new read-only files */ @@ -221,16 +225,21 @@ int reopen_files(struct cifsTconInfo * pTcon, struct nls_table * nlsinfo) if(file) { file->private_data = NULL; read_unlock(&GlobalSMBSeslock); - rc = cifs_open(file->f_dentry->d_inode,file); - read_lock(&GlobalSMBSeslock); - if(rc) { - cFYI(1,("reconnecting file %s failed with %d", - file->f_dentry->d_name.name,rc)); + if(file->f_dentry == 0) { + cFYI(1,("Null dentry for file %p",file)); + read_lock(&GlobalSMBSeslock); } else { - cFYI(1,("reconnection of %s succeeded", - file->f_dentry->d_name.name)); - } - } + rc = cifs_open(file->f_dentry->d_inode,file); + read_lock(&GlobalSMBSeslock); + if(rc) { + cFYI(1,("reconnecting file %s failed with %d", + file->f_dentry->d_name.name,rc)); + } else { + cFYI(1,("reconnection of %s succeeded", + file->f_dentry->d_name.name)); + } + } + } } } read_unlock(&GlobalSMBSeslock); diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 62625e532132..3625916ca351 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1,7 +1,7 @@ /* * fs/cifs/inode.c * - * Copyright (c) International Business Machines Corp., 2002 + * Copyright (C) International Business Machines Corp., 2002,2003 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -345,6 +345,8 @@ cifs_unlink(struct inode *inode, struct dentry *direntry) if (!rc) { direntry->d_inode->i_nlink--; + } else if (rc == -ENOENT) { + d_drop(direntry); } else if (rc == -ETXTBSY) { int oplock = FALSE; __u16 netfid; @@ -585,12 +587,24 @@ cifs_revalidate(struct dentry *direntry) } } - if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) - cifs_get_inode_info_unix(&direntry->d_inode, full_path, + if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) { + rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path, direntry->d_sb); - else - cifs_get_inode_info(&direntry->d_inode, full_path, NULL, + if(rc) { + cFYI(1,("error on getting revalidate info %d",rc)); +/* if(rc != -ENOENT) + rc = 0; */ /* BB should we cache info on certain errors? */ + } + } else { + rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL, direntry->d_sb); + if(rc) { + cFYI(1,("error on getting revalidate info %d",rc)); +/* if(rc != -ENOENT) + rc = 0; */ /* BB should we cache info on certain errors? */ + } + } + /* should we remap certain errors, access denied?, to zero */ /* BB if not oplocked, invalidate inode pages if mtime has changed */ diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 9717910ee514..93c200f49f51 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -1,7 +1,7 @@ /* * fs/cifs/link.c * - * Copyright (c) International Business Machines Corp., 2002 + * Copyright (C) International Business Machines Corp., 2002,2003 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -51,9 +51,12 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX) rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName, cifs_sb_target->local_nls); - else + else { rc = CIFSCreateHardLink(xid, pTcon, fromName, toName, cifs_sb_target->local_nls); + if(rc == -EIO) + rc = -EOPNOTSUPP; + } /* if (!rc) */ { diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index b9a5137df6d7..65d84985a3ce 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -1,7 +1,7 @@ /* * fs/cifs/misc.c * - * Copyright (c) International Business Machines Corp., 2002 + * Copyright (c) International Business Machines Corp., 2002,2003 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -213,7 +213,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , buffer->Command = smb_command; buffer->Flags = 0x00; /* case sensitive */ buffer->Flags2 = SMBFLG2_KNOWS_LONG_NAMES; - tmp = cpu_to_le32(current->pid); + tmp = cpu_to_le32(current->tgid); buffer->Pid = tmp & 0xFFFF; tmp >>= 16; buffer->PidHigh = tmp & 0xFFFF; diff --git a/include/linux/usb.h b/include/linux/usb.h index df3ba0f3b90e..471c37f5188b 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -410,6 +410,8 @@ static inline int usb_make_path (struct usb_device *dev, char *buf, size_t size) * the "usbfs" filesystem. This lets devices provide ways to * expose information to user space regardless of where they * do (or don't) show up otherwise in the filesystem. + * @suspend: Called when the device is going to be suspended by the system. + * @resume: Called when the device is being resumed by the system. * @id_table: USB drivers use ID table to support hotplugging. * Export this with MODULE_DEVICE_TABLE(usb,...). This must be set * or your driver's probe function will never get called. @@ -445,6 +447,9 @@ struct usb_driver { int (*ioctl) (struct usb_interface *intf, unsigned int code, void *buf); + int (*suspend) (struct usb_interface *intf, u32 state); + int (*resume) (struct usb_interface *intf); + const struct usb_device_id *id_table; struct device_driver driver; diff --git a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h index a603cbde201e..c98a95dbe250 100644 --- a/include/linux/usb_gadget.h +++ b/include/linux/usb_gadget.h @@ -313,8 +313,8 @@ usb_ep_free_buffer (struct usb_ep *ep, void *buf, dma_addr_t dma, unsigned len) * arranges to poll once per interval, and the gadget driver usually will * have queued some data to transfer at that time. * - * Returns zero, or a negative error code. Endpoints that are not enabled, - * or which are enabled but halted, report errors; errors will also be + * Returns zero, or a negative error code. Endpoints that are not enabled + * report errors; errors will also be * reported when the usb peripheral is disconnected. */ static inline int @@ -352,6 +352,11 @@ static inline int usb_ep_dequeue (struct usb_ep *ep, struct usb_request *req) * clears this feature; drivers may need to empty the endpoint's request * queue first, to make sure no inappropriate transfers happen. * + * Note that while an endpoint CLEAR_FEATURE will be invisible to the + * gadget driver, a SET_INTERFACE will not be. To reset endpoints for the + * current altsetting, see usb_ep_clear_halt(). When switching altsettings, + * it's simplest to use usb_ep_enable() or usb_ep_disable() for the endpoints. + * * Returns zero, or a negative error code. On success, this call sets * underlying hardware state that blocks data transfers. */ @@ -365,12 +370,14 @@ usb_ep_set_halt (struct usb_ep *ep) * usb_ep_clear_halt - clears endpoint halt, and resets toggle * @ep:the bulk or interrupt endpoint being reset * - * use this when responding to the standard usb "set interface" request, + * Use this when responding to the standard usb "set interface" request, * for endpoints that aren't reconfigured, after clearing any other state * in the endpoint's i/o queue. * - * returns zero, or a negative error code. on success, this call clears + * Returns zero, or a negative error code. On success, this call clears * the underlying hardware state reflecting endpoint halt and data toggle. + * Note that some hardware can't support this request (like pxa2xx_udc), + * and accordingly can't correctly implement interface altsettings. */ static inline int usb_ep_clear_halt (struct usb_ep *ep) @@ -562,7 +569,8 @@ usb_gadget_clear_selfpowered (struct usb_gadget *gadget) * queues a response to ep0, or returns negative to stall. * @disconnect: Invoked after all transfers have been stopped, * when the host is disconnected. May be called in_interrupt; this - * may not sleep. + * may not sleep. Some devices can't detect disconnect, so this might + * not be called except as part of controller shutdown. * @unbind: Invoked when the driver is unbound from a gadget, * usually from rmmod (after a disconnect is reported). * Called in a context that permits sleeping. @@ -603,7 +611,9 @@ usb_gadget_clear_selfpowered (struct usb_gadget *gadget) * not provide those callbacks. However, some may need to change modes * when the host is not longer directing those activities. For example, * local controls (buttons, dials, etc) may need to be re-enabled since - * the (remote) host can't do that any longer. + * the (remote) host can't do that any longer; or an error state might + * be cleared, to make the device behave identically whether or not + * power is maintained. */ struct usb_gadget_driver { char *function; diff --git a/include/linux/videodev.h b/include/linux/videodev.h index 9e7dacaff115..8abbd9e9e596 100644 --- a/include/linux/videodev.h +++ b/include/linux/videodev.h @@ -63,6 +63,12 @@ video_device_create_file(struct video_device *vfd, { class_device_create_file(&vfd->class_dev, attr); } +static inline void +video_device_remove_file(struct video_device *vfd, + struct class_device_attribute *attr) +{ + class_device_remove_file(&vfd->class_dev, attr); +} /* helper functions to alloc / release struct video_device, the later can be used for video_device->release() */ diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index c9f456eaa745..715919c77234 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -230,12 +230,18 @@ static struct icmp_control icmp_pointers[NR_ICMP_TYPES+1]; static DEFINE_PER_CPU(struct socket *, __icmp_socket) = NULL; #define icmp_socket __get_cpu_var(__icmp_socket) -static __inline__ void icmp_xmit_lock(void) +static __inline__ int icmp_xmit_lock(void) { local_bh_disable(); - if (unlikely(!spin_trylock(&icmp_socket->sk->sk_lock.slock))) - BUG(); + if (unlikely(!spin_trylock(&icmp_socket->sk->sk_lock.slock))) { + /* This can happen if the output path signals a + * dst_link_failure() for an outgoing ICMP packet. + */ + local_bh_enable(); + return 1; + } + return 0; } static void icmp_xmit_unlock(void) @@ -376,7 +382,8 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) if (ip_options_echo(&icmp_param->replyopts, skb)) goto out; - icmp_xmit_lock(); + if (icmp_xmit_lock()) + return; icmp_param->data.icmph.checksum = 0; icmp_out_count(icmp_param->data.icmph.type); @@ -488,7 +495,8 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info) } } - icmp_xmit_lock(); + if (icmp_xmit_lock()) + return; /* * Construct source address and options. diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index b5bfc900281b..272dab8ded25 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -141,7 +141,7 @@ static void send_reset(struct sk_buff *oldskb, int local) nskb->nf_debug = 0; #endif nskb->nfmark = 0; -#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) +#ifdef CONFIG_BRIDGE_NETFILTER nf_bridge_put(nskb->nf_bridge); nskb->nf_bridge = NULL; #endif diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index e23847781517..fed773b5f439 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -40,6 +40,7 @@ #include <linux/netdevice.h> #include <linux/rtnetlink.h> #include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <linux/smp_lock.h> #include <linux/notifier.h> #include <linux/security.h> @@ -964,62 +965,108 @@ int netlink_post(int unit, struct sk_buff *skb) #endif - #ifdef CONFIG_PROC_FS -static int netlink_read_proc(char *buffer, char **start, off_t offset, - int length, int *eof, void *data) +static struct sock *netlink_seq_socket_idx(struct seq_file *seq, loff_t pos) { - off_t pos=0; - off_t begin=0; - int len=0; int i; struct sock *s; struct hlist_node *node; - - len+= sprintf(buffer,"sk Eth Pid Groups " - "Rmem Wmem Dump Locks\n"); - + loff_t off = 0; + for (i=0; i<MAX_LINKS; i++) { - read_lock(&nl_table_lock); sk_for_each(s, node, &nl_table[i]) { - struct netlink_opt *nlk = nlk_sk(s); - - len+=sprintf(buffer+len,"%p %-3d %-6d %08x %-8d %-8d %p %d", - s, - s->sk_protocol, - nlk->pid, - nlk->groups, - atomic_read(&s->sk_rmem_alloc), - atomic_read(&s->sk_wmem_alloc), - nlk->cb, - atomic_read(&s->sk_refcnt) - ); - - buffer[len++]='\n'; - - pos=begin+len; - if(pos<offset) { - len=0; - begin=pos; + if (off == pos) { + seq->private = (void *) i; + return s; } - if(pos>offset+length) { - read_unlock(&nl_table_lock); - goto done; + ++off; + } + } + return NULL; +} + +static void *netlink_seq_start(struct seq_file *seq, loff_t *pos) +{ + read_lock(&nl_table_lock); + return *pos ? netlink_seq_socket_idx(seq, *pos - 1) : (void *) 1; +} + +static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct sock *s; + + ++*pos; + + if (v == (void *) 1) + return netlink_seq_socket_idx(seq, 0); + + s = sk_next(v); + if (!s) { + int i = (int) seq->private; + + while (++i < MAX_LINKS) { + s = sk_head(&nl_table[i]); + if (s) { + seq->private = (void *) i; + break; } } - read_unlock(&nl_table_lock); } - *eof = 1; - -done: - *start=buffer+(offset-begin); - len-=(offset-begin); - if(len>length) - len=length; - if(len<0) - len=0; - return len; + return s; } + +static void netlink_seq_stop(struct seq_file *seq, void *v) +{ + read_unlock(&nl_table_lock); +} + + +static int netlink_seq_show(struct seq_file *seq, void *v) +{ + if (v == (void *)1) + seq_puts(seq, + "sk Eth Pid Groups " + "Rmem Wmem Dump Locks\n"); + else { + struct sock *s = v; + struct netlink_opt *nlk = nlk_sk(s); + + seq_printf(seq, "%p %-3d %-6d %08x %-8d %-8d %p %d\n", + s, + s->sk_protocol, + nlk->pid, + nlk->groups, + atomic_read(&s->sk_rmem_alloc), + atomic_read(&s->sk_wmem_alloc), + nlk->cb, + atomic_read(&s->sk_refcnt) + ); + + } + return 0; +} + +struct seq_operations netlink_seq_ops = { + .start = netlink_seq_start, + .next = netlink_seq_next, + .stop = netlink_seq_stop, + .show = netlink_seq_show, +}; + + +static int netlink_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &netlink_seq_ops); +} + +static struct file_operations netlink_seq_fops = { + .owner = THIS_MODULE, + .open = netlink_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + #endif int netlink_register_notifier(struct notifier_block *nb) @@ -1069,7 +1116,7 @@ static int __init netlink_proto_init(void) } sock_register(&netlink_family_ops); #ifdef CONFIG_PROC_FS - create_proc_read_entry("net/netlink", 0, 0, netlink_read_proc, NULL); + proc_net_fops_create("netlink", 0, &netlink_seq_fops); #endif /* The netlink device handler may be needed early. */ rtnetlink_init(); @@ -1079,7 +1126,7 @@ static int __init netlink_proto_init(void) static void __exit netlink_proto_exit(void) { sock_unregister(PF_NETLINK); - remove_proc_entry("net/netlink", NULL); + proc_net_remove("netlink"); } core_initcall(netlink_proto_init); |
