Commit 6aa909be authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net/jgarzik/net-drivers-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents afe1bcc5 7f6cf788
...@@ -2746,6 +2746,14 @@ E: wsalamon@tislabs.com ...@@ -2746,6 +2746,14 @@ E: wsalamon@tislabs.com
E: wsalamon@nai.com E: wsalamon@nai.com
D: portions of the Linux Security Module (LSM) framework and security modules D: portions of the Linux Security Module (LSM) framework and security modules
N: Duncan Sands
E: duncan.sands@wanadoo.fr
W: http://topo.math.u-psud.fr/~sands
D: Alcatel SpeedTouch USB driver
S: 69 rue Dunois
S: 75013 Paris
S: France
N: Robert Sanders N: Robert Sanders
E: gt8134b@prism.gatech.edu E: gt8134b@prism.gatech.edu
D: Dosemu D: Dosemu
......
...@@ -215,6 +215,14 @@ M: Juergen Fischer <fischer@norbit.de> ...@@ -215,6 +215,14 @@ M: Juergen Fischer <fischer@norbit.de>
L: linux-scsi@vger.kernel.org L: linux-scsi@vger.kernel.org
S: Maintained S: Maintained
ALCATEL SPEEDTOUCH USB DRIVER
P: Duncan Sands
M: duncan.sands@wanadoo.fr
L: linux-usb-users@lists.sourceforge.net
L: linux-usb-devel@lists.sourceforge.net
W: http://www.linux-usb.org/SpeedTouch/
S: Maintained
ALPHA PORT ALPHA PORT
P: Richard Henderson P: Richard Henderson
M: rth@twiddle.net M: rth@twiddle.net
......
obj-$(CONFIG_USB_CATC) += crc32.o obj-$(CONFIG_USB_CATC) += crc32.o
obj-$(CONFIG_USB_SPEEDTOUCH) += crc32.o
obj-$(CONFIG_USB_USBNET) += crc32.o
...@@ -606,6 +606,7 @@ static int acm_probe (struct usb_interface *intf, ...@@ -606,6 +606,7 @@ static int acm_probe (struct usb_interface *intf,
if (!acm->ctrlurb) { if (!acm->ctrlurb) {
err("out of memory"); err("out of memory");
kfree(acm); kfree(acm);
kfree(buf);
return -ENOMEM; return -ENOMEM;
} }
acm->readurb = usb_alloc_urb(0, GFP_KERNEL); acm->readurb = usb_alloc_urb(0, GFP_KERNEL);
...@@ -613,6 +614,7 @@ static int acm_probe (struct usb_interface *intf, ...@@ -613,6 +614,7 @@ static int acm_probe (struct usb_interface *intf,
err("out of memory"); err("out of memory");
usb_free_urb(acm->ctrlurb); usb_free_urb(acm->ctrlurb);
kfree(acm); kfree(acm);
kfree(buf);
return -ENOMEM; return -ENOMEM;
} }
acm->writeurb = usb_alloc_urb(0, GFP_KERNEL); acm->writeurb = usb_alloc_urb(0, GFP_KERNEL);
...@@ -621,6 +623,7 @@ static int acm_probe (struct usb_interface *intf, ...@@ -621,6 +623,7 @@ static int acm_probe (struct usb_interface *intf,
usb_free_urb(acm->readurb); usb_free_urb(acm->readurb);
usb_free_urb(acm->ctrlurb); usb_free_urb(acm->ctrlurb);
kfree(acm); kfree(acm);
kfree(buf);
return -ENOMEM; return -ENOMEM;
} }
......
...@@ -219,16 +219,25 @@ static void sg_complete (struct urb *urb, struct pt_regs *regs) ...@@ -219,16 +219,25 @@ static void sg_complete (struct urb *urb, struct pt_regs *regs)
spin_lock_irqsave (&io->lock, flags); spin_lock_irqsave (&io->lock, flags);
/* In 2.5 we require hcds' endpoint queues not to progress after fault /* In 2.5 we require hcds' endpoint queues not to progress after fault
* reports, until the competion callback (this!) returns. That lets * reports, until the completion callback (this!) returns. That lets
* device driver code (like this routine) unlink queued urbs first, * device driver code (like this routine) unlink queued urbs first,
* if it needs to, since the HC won't work on them at all. So it's * if it needs to, since the HC won't work on them at all. So it's
* not possible for page N+1 to overwrite page N, and so on. * not possible for page N+1 to overwrite page N, and so on.
*
* That's only for "hard" faults; "soft" faults (unlinks) sometimes
* complete before the HCD can get requests away from hardware,
* though never during cleanup after a hard fault.
*/ */
if (io->status && urb->actual_length) { if (io->status
err ("driver for bus %s dev %s ep %d-%s corrupted data!", && (io->status != -ECONNRESET
io->dev->bus->bus_name, io->dev->devpath, || urb->status != -ECONNRESET)
&& urb->actual_length) {
dev_err (io->dev->bus->controller,
"dev %s ep%d%s scatterlist error %d/%d\n",
io->dev->devpath,
usb_pipeendpoint (urb->pipe), usb_pipeendpoint (urb->pipe),
usb_pipein (urb->pipe) ? "in" : "out"); usb_pipein (urb->pipe) ? "in" : "out",
urb->status, io->status);
// BUG (); // BUG ();
} }
......
...@@ -195,7 +195,7 @@ int usb_submit_urb(struct urb *urb, int mem_flags) ...@@ -195,7 +195,7 @@ int usb_submit_urb(struct urb *urb, int mem_flags)
if (!urb || urb->hcpriv || !urb->complete) if (!urb || urb->hcpriv || !urb->complete)
return -EINVAL; return -EINVAL;
if (!(dev = urb->dev) || !dev->bus || dev->devnum <= 0) if (!(dev = urb->dev) || !dev->present || !dev->bus || dev->devnum <= 0)
return -ENODEV; return -ENODEV;
if (!(op = dev->bus->op) || !op->submit_urb) if (!(op = dev->bus->op) || !op->submit_urb)
return -ENODEV; return -ENODEV;
...@@ -376,7 +376,7 @@ int usb_submit_urb(struct urb *urb, int mem_flags) ...@@ -376,7 +376,7 @@ int usb_submit_urb(struct urb *urb, int mem_flags)
*/ */
int usb_unlink_urb(struct urb *urb) int usb_unlink_urb(struct urb *urb)
{ {
if (urb && urb->dev && urb->dev->bus && urb->dev->bus->op) if (urb && urb->dev && urb->dev->present && urb->dev->bus && urb->dev->bus->op)
return urb->dev->bus->op->unlink_urb(urb); return urb->dev->bus->op->unlink_urb(urb);
else else
return -ENODEV; return -ENODEV;
......
...@@ -679,6 +679,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus) ...@@ -679,6 +679,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus)
memset(dev, 0, sizeof(*dev)); memset(dev, 0, sizeof(*dev));
device_initialize(&dev->dev); device_initialize(&dev->dev);
dev->present = 1;
usb_bus_get(bus); usb_bus_get(bus);
...@@ -854,6 +855,10 @@ void usb_disconnect(struct usb_device **pdev) ...@@ -854,6 +855,10 @@ void usb_disconnect(struct usb_device **pdev)
} }
device_unregister(&dev->dev); device_unregister(&dev->dev);
/* mark the device as not present so any further urb submissions for
* this device will fail. */
dev->present = 0;
/* Decrement the reference count, it'll auto free everything when */ /* Decrement the reference count, it'll auto free everything when */
/* it hits 0 which could very well be now */ /* it hits 0 which could very well be now */
usb_put_dev(dev); usb_put_dev(dev);
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/reboot.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/version.h> #include <linux/version.h>
...@@ -306,6 +306,19 @@ static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap) ...@@ -306,6 +306,19 @@ static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap)
return 0; return 0;
} }
static int
ehci_reboot (struct notifier_block *self, unsigned long code, void *null)
{
struct ehci_hcd *ehci;
ehci = container_of (self, struct ehci_hcd, reboot_notifier);
/* make BIOS/etc use companion controller during reboot */
writel (0, &ehci->regs->configured_flag);
return 0;
}
/* called by khubd or root hub init threads */ /* called by khubd or root hub init threads */
static int ehci_start (struct usb_hcd *hcd) static int ehci_start (struct usb_hcd *hcd)
...@@ -464,6 +477,9 @@ static int ehci_start (struct usb_hcd *hcd) ...@@ -464,6 +477,9 @@ static int ehci_start (struct usb_hcd *hcd)
* are explicitly handed to companion controller(s), so no TT is * are explicitly handed to companion controller(s), so no TT is
* involved with the root hub. * involved with the root hub.
*/ */
ehci->reboot_notifier.notifier_call = ehci_reboot;
register_reboot_notifier (&ehci->reboot_notifier);
ehci->hcd.state = USB_STATE_READY; ehci->hcd.state = USB_STATE_READY;
writel (FLAG_CF, &ehci->regs->configured_flag); writel (FLAG_CF, &ehci->regs->configured_flag);
readl (&ehci->regs->command); /* unblock posted write */ readl (&ehci->regs->command); /* unblock posted write */
...@@ -520,6 +536,7 @@ static void ehci_stop (struct usb_hcd *hcd) ...@@ -520,6 +536,7 @@ static void ehci_stop (struct usb_hcd *hcd)
/* let companion controllers work when we aren't */ /* let companion controllers work when we aren't */
writel (0, &ehci->regs->configured_flag); writel (0, &ehci->regs->configured_flag);
unregister_reboot_notifier (&ehci->reboot_notifier);
remove_debug_files (ehci); remove_debug_files (ehci);
......
...@@ -81,8 +81,10 @@ struct ehci_hcd { /* one per controller */ ...@@ -81,8 +81,10 @@ struct ehci_hcd { /* one per controller */
struct pci_pool *sitd_pool; /* sitd per split iso urb */ struct pci_pool *sitd_pool; /* sitd per split iso urb */
struct timer_list watchdog; struct timer_list watchdog;
struct notifier_block reboot_notifier;
unsigned stamp; unsigned stamp;
/* irq statistics */
#ifdef EHCI_STATS #ifdef EHCI_STATS
struct ehci_stats stats; struct ehci_stats stats;
# define COUNT(x) do { (x)++; } while (0) # define COUNT(x) do { (x)++; } while (0)
......
...@@ -163,11 +163,10 @@ config USB_POWERMATE ...@@ -163,11 +163,10 @@ config USB_POWERMATE
tristate "Griffin PowerMate and Contour Jog support" tristate "Griffin PowerMate and Contour Jog support"
depends on USB && INPUT depends on USB && INPUT
---help--- ---help---
Say Y here if you want to use Griffin PowerMate or Contour Jog devices. Say Y here if you want to use Griffin PowerMate or Contour Jog devices.
These are stainless steel dials which can measure clockwise and These are aluminum dials which can measure clockwise and anticlockwise
anticlockwise rotation. The dial also acts as a pushbutton. The base rotation. The dial also acts as a pushbutton. The base contains an LED
contains an LED which can be instructed to pulse or to switch to a which can be instructed to pulse or to switch to a particular intensity.
particular intensity.
You can download userspace tools from http://sowerbutts.com/powermate/ You can download userspace tools from http://sowerbutts.com/powermate/
......
...@@ -355,7 +355,7 @@ static struct usb_device_id usb_kbd_id_table [] = { ...@@ -355,7 +355,7 @@ static struct usb_device_id usb_kbd_id_table [] = {
MODULE_DEVICE_TABLE (usb, usb_kbd_id_table); MODULE_DEVICE_TABLE (usb, usb_kbd_id_table);
static struct usb_driver usb_kbd_driver = { static struct usb_driver usb_kbd_driver = {
.name = "keyboard", .name = "usbkbd",
.probe = usb_kbd_probe, .probe = usb_kbd_probe,
.disconnect = usb_kbd_disconnect, .disconnect = usb_kbd_disconnect,
.id_table = usb_kbd_id_table, .id_table = usb_kbd_id_table,
......
...@@ -238,7 +238,7 @@ static struct usb_device_id usb_mouse_id_table [] = { ...@@ -238,7 +238,7 @@ static struct usb_device_id usb_mouse_id_table [] = {
MODULE_DEVICE_TABLE (usb, usb_mouse_id_table); MODULE_DEVICE_TABLE (usb, usb_mouse_id_table);
static struct usb_driver usb_mouse_driver = { static struct usb_driver usb_mouse_driver = {
.name = "usb_mouse", .name = "usbmouse",
.probe = usb_mouse_probe, .probe = usb_mouse_probe,
.disconnect = usb_mouse_disconnect, .disconnect = usb_mouse_disconnect,
.id_table = usb_mouse_id_table, .id_table = usb_mouse_id_table,
......
/* /*
* OmniVision OV511 Camera-to-USB Bridge Driver * OmniVision OV511 Camera-to-USB Bridge Driver
* *
* Copyright (c) 1999-2002 Mark W. McClelland * Copyright (c) 1999-2003 Mark W. McClelland
* Original decompression code Copyright 1998-2000 OmniVision Technologies * Original decompression code Copyright 1998-2000 OmniVision Technologies
* Many improvements by Bret Wallach <bwallac1@san.rr.com> * Many improvements by Bret Wallach <bwallac1@san.rr.com>
* Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000) * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
...@@ -60,7 +60,7 @@ ...@@ -60,7 +60,7 @@
/* /*
* Version Information * Version Information
*/ */
#define DRIVER_VERSION "v1.63 for Linux 2.5" #define DRIVER_VERSION "v1.64 for Linux 2.5"
#define EMAIL "mark@alpha.dyndns.org" #define EMAIL "mark@alpha.dyndns.org"
#define DRIVER_AUTHOR "Mark McClelland <mark@alpha.dyndns.org> & Bret Wallach \ #define DRIVER_AUTHOR "Mark McClelland <mark@alpha.dyndns.org> & Bret Wallach \
& Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \ & Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \
...@@ -137,7 +137,7 @@ MODULE_PARM_DESC(snapshot, "Enable snapshot mode"); ...@@ -137,7 +137,7 @@ MODULE_PARM_DESC(snapshot, "Enable snapshot mode");
MODULE_PARM(cams, "i"); MODULE_PARM(cams, "i");
MODULE_PARM_DESC(cams, "Number of simultaneous cameras"); MODULE_PARM_DESC(cams, "Number of simultaneous cameras");
MODULE_PARM(compress, "i"); MODULE_PARM(compress, "i");
MODULE_PARM_DESC(compress, "Turn on compression (not reliable yet)"); MODULE_PARM_DESC(compress, "Turn on compression");
MODULE_PARM(testpat, "i"); MODULE_PARM(testpat, "i");
MODULE_PARM_DESC(testpat, MODULE_PARM_DESC(testpat,
"Replace image with vertical bar testpattern (only partially working)"); "Replace image with vertical bar testpattern (only partially working)");
...@@ -1349,6 +1349,13 @@ ov51x_restart(struct usb_ov511 *ov) ...@@ -1349,6 +1349,13 @@ ov51x_restart(struct usb_ov511 *ov)
return 0; return 0;
} }
/* Sleeps until no frames are active. Returns !0 if got signal */
static int
ov51x_wait_frames_inactive(struct usb_ov511 *ov)
{
return wait_event_interruptible(ov->wq, ov->curframe < 0);
}
/* Resets the hardware snapshot button */ /* Resets the hardware snapshot button */
static void static void
ov51x_clear_snapshot(struct usb_ov511 *ov) ov51x_clear_snapshot(struct usb_ov511 *ov)
...@@ -2121,7 +2128,7 @@ sensor_get_exposure(struct usb_ov511 *ov, unsigned char *val) ...@@ -2121,7 +2128,7 @@ sensor_get_exposure(struct usb_ov511 *ov, unsigned char *val)
return 0; return 0;
} }
#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */ #endif /* CONFIG_VIDEO_PROC_FS */
/* Turns on or off the LED. Only has an effect with OV511+/OV518(+) */ /* Turns on or off the LED. Only has an effect with OV511+/OV518(+) */
static void static void
...@@ -2486,8 +2493,6 @@ mode_init_ov_sensor_regs(struct usb_ov511 *ov, int width, int height, ...@@ -2486,8 +2493,6 @@ mode_init_ov_sensor_regs(struct usb_ov511 *ov, int width, int height,
/******** Clock programming ********/ /******** Clock programming ********/
// FIXME: Test this with OV6630
/* The OV6620 needs special handling. This prevents the /* The OV6620 needs special handling. This prevents the
* severe banding that normally occurs */ * severe banding that normally occurs */
if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630)
...@@ -2995,6 +3000,7 @@ ov51x_set_default_params(struct usb_ov511 *ov) ...@@ -2995,6 +3000,7 @@ ov51x_set_default_params(struct usb_ov511 *ov)
ov->frame[i].format = force_palette; ov->frame[i].format = force_palette;
else else
ov->frame[i].format = VIDEO_PALETTE_YUV420; ov->frame[i].format = VIDEO_PALETTE_YUV420;
ov->frame[i].depth = get_depth(ov->frame[i].format); ov->frame[i].depth = get_depth(ov->frame[i].format);
} }
...@@ -3577,12 +3583,8 @@ ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n) ...@@ -3577,12 +3583,8 @@ ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
if (frame->scanstate == STATE_LINES) { if (frame->scanstate == STATE_LINES) {
int nextf; int nextf;
frame->grabstate = FRAME_DONE; // FIXME: Is this right? frame->grabstate = FRAME_DONE;
wake_up_interruptible(&frame->wq);
if (waitqueue_active(&frame->wq)) {
frame->grabstate = FRAME_DONE;
wake_up_interruptible(&frame->wq);
}
/* If next frame is ready or grabbing, /* If next frame is ready or grabbing,
* point to it */ * point to it */
...@@ -3747,12 +3749,8 @@ ov518_move_data(struct usb_ov511 *ov, unsigned char *in, int n) ...@@ -3747,12 +3749,8 @@ ov518_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
if (frame->scanstate == STATE_LINES) { if (frame->scanstate == STATE_LINES) {
int nextf; int nextf;
frame->grabstate = FRAME_DONE; // FIXME: Is this right? frame->grabstate = FRAME_DONE;
wake_up_interruptible(&frame->wq);
if (waitqueue_active(&frame->wq)) {
frame->grabstate = FRAME_DONE;
wake_up_interruptible(&frame->wq);
}
/* If next frame is ready or grabbing, /* If next frame is ready or grabbing,
* point to it */ * point to it */
...@@ -4228,7 +4226,7 @@ ov51x_alloc(struct usb_ov511 *ov) ...@@ -4228,7 +4226,7 @@ ov51x_alloc(struct usb_ov511 *ov)
} }
static void static void
ov51x_dealloc(struct usb_ov511 *ov, int now) ov51x_dealloc(struct usb_ov511 *ov)
{ {
PDEBUG(4, "entered"); PDEBUG(4, "entered");
down(&ov->buf_lock); down(&ov->buf_lock);
...@@ -4258,10 +4256,6 @@ ov51x_v4l1_open(struct inode *inode, struct file *file) ...@@ -4258,10 +4256,6 @@ ov51x_v4l1_open(struct inode *inode, struct file *file)
if (ov->user) if (ov->user)
goto out; goto out;
err = ov51x_alloc(ov);
if (err < 0)
goto out;
ov->sub_flag = 0; ov->sub_flag = 0;
/* In case app doesn't set them... */ /* In case app doesn't set them... */
...@@ -4283,9 +4277,13 @@ ov51x_v4l1_open(struct inode *inode, struct file *file) ...@@ -4283,9 +4277,13 @@ ov51x_v4l1_open(struct inode *inode, struct file *file)
goto out; goto out;
} }
err = ov51x_alloc(ov);
if (err < 0)
goto out;
err = ov51x_init_isoc(ov); err = ov51x_init_isoc(ov);
if (err) { if (err) {
ov51x_dealloc(ov, 0); ov51x_dealloc(ov);
goto out; goto out;
} }
...@@ -4319,7 +4317,7 @@ ov51x_v4l1_close(struct inode *inode, struct file *file) ...@@ -4319,7 +4317,7 @@ ov51x_v4l1_close(struct inode *inode, struct file *file)
ov51x_led_control(ov, 0); ov51x_led_control(ov, 0);
if (ov->dev) if (ov->dev)
ov51x_dealloc(ov, 0); ov51x_dealloc(ov);
up(&ov->lock); up(&ov->lock);
...@@ -4331,7 +4329,7 @@ ov51x_v4l1_close(struct inode *inode, struct file *file) ...@@ -4331,7 +4329,7 @@ ov51x_v4l1_close(struct inode *inode, struct file *file)
ov->cbuf = NULL; ov->cbuf = NULL;
up(&ov->cbuf_lock); up(&ov->cbuf_lock);
ov51x_dealloc(ov, 1); ov51x_dealloc(ov);
kfree(ov); kfree(ov);
ov = NULL; ov = NULL;
} }
...@@ -4449,7 +4447,7 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file, ...@@ -4449,7 +4447,7 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
case VIDIOCSPICT: case VIDIOCSPICT:
{ {
struct video_picture *p = arg; struct video_picture *p = arg;
int i; int i, rc;
PDEBUG(4, "VIDIOCSPICT"); PDEBUG(4, "VIDIOCSPICT");
...@@ -4469,10 +4467,9 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file, ...@@ -4469,10 +4467,9 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
if (p->palette != ov->frame[0].format) { if (p->palette != ov->frame[0].format) {
PDEBUG(4, "Detected format change"); PDEBUG(4, "Detected format change");
/* If we're collecting previous frame wait rc = ov51x_wait_frames_inactive(ov);
before changing modes */ if (rc)
interruptible_sleep_on(&ov->wq); return rc;
if (signal_pending(current)) return -EINTR;
mode_init_regs(ov, ov->frame[0].width, mode_init_regs(ov, ov->frame[0].width,
ov->frame[0].height, p->palette, ov->sub_flag); ov->frame[0].height, p->palette, ov->sub_flag);
...@@ -4530,7 +4527,7 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file, ...@@ -4530,7 +4527,7 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
case VIDIOCSWIN: case VIDIOCSWIN:
{ {
struct video_window *vw = arg; struct video_window *vw = arg;
int i, result; int i, rc;
PDEBUG(4, "VIDIOCSWIN: %dx%d", vw->width, vw->height); PDEBUG(4, "VIDIOCSWIN: %dx%d", vw->width, vw->height);
...@@ -4545,15 +4542,14 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file, ...@@ -4545,15 +4542,14 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
return -EINVAL; return -EINVAL;
#endif #endif
/* If we're collecting previous frame wait rc = ov51x_wait_frames_inactive(ov);
before changing modes */ if (rc)
interruptible_sleep_on(&ov->wq); return rc;
if (signal_pending(current)) return -EINTR;
result = mode_init_regs(ov, vw->width, vw->height, rc = mode_init_regs(ov, vw->width, vw->height,
ov->frame[0].format, ov->sub_flag); ov->frame[0].format, ov->sub_flag);
if (result < 0) if (rc < 0)
return result; return rc;
for (i = 0; i < OV511_NUMFRAMES; i++) { for (i = 0; i < OV511_NUMFRAMES; i++) {
ov->frame[i].width = vw->width; ov->frame[i].width = vw->width;
...@@ -4600,7 +4596,7 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file, ...@@ -4600,7 +4596,7 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
case VIDIOCMCAPTURE: case VIDIOCMCAPTURE:
{ {
struct video_mmap *vm = arg; struct video_mmap *vm = arg;
int ret, depth; int rc, depth;
unsigned int f = vm->frame; unsigned int f = vm->frame;
PDEBUG(4, "VIDIOCMCAPTURE: frame: %d, %dx%d, %s", f, vm->width, PDEBUG(4, "VIDIOCMCAPTURE: frame: %d, %dx%d, %s", f, vm->width,
...@@ -4642,14 +4638,14 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file, ...@@ -4642,14 +4638,14 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
(ov->frame[f].depth != depth)) { (ov->frame[f].depth != depth)) {
PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters"); PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters");
/* If we're collecting previous frame wait rc = ov51x_wait_frames_inactive(ov);
before changing modes */ if (rc)
interruptible_sleep_on(&ov->wq); return rc;
if (signal_pending(current)) return -EINTR;
ret = mode_init_regs(ov, vm->width, vm->height, rc = mode_init_regs(ov, vm->width, vm->height,
vm->format, ov->sub_flag); vm->format, ov->sub_flag);
#if 0 #if 0
if (ret < 0) { if (rc < 0) {
PDEBUG(1, "Got error while initializing regs "); PDEBUG(1, "Got error while initializing regs ");
return ret; return ret;
} }
...@@ -4702,18 +4698,15 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file, ...@@ -4702,18 +4698,15 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
return rc; return rc;
if (frame->grabstate == FRAME_ERROR) { if (frame->grabstate == FRAME_ERROR) {
int ret; if ((rc = ov51x_new_frame(ov, fnum)) < 0)
return rc;
if ((ret = ov51x_new_frame(ov, fnum)) < 0)
return ret;
goto redo; goto redo;
} }
/* Fall through */ /* Fall through */
case FRAME_DONE: case FRAME_DONE:
if (ov->snap_enabled && !frame->snapshot) { if (ov->snap_enabled && !frame->snapshot) {
int ret; if ((rc = ov51x_new_frame(ov, fnum)) < 0)
if ((ret = ov51x_new_frame(ov, fnum)) < 0) return rc;
return ret;
goto redo; goto redo;
} }
...@@ -6089,7 +6082,6 @@ ov518_configure(struct usb_ov511 *ov) ...@@ -6089,7 +6082,6 @@ ov518_configure(struct usb_ov511 *ov)
return -EBUSY; return -EBUSY;
} }
/**************************************************************************** /****************************************************************************
* *
* USB routines * USB routines
...@@ -6097,11 +6089,10 @@ ov518_configure(struct usb_ov511 *ov) ...@@ -6097,11 +6089,10 @@ ov518_configure(struct usb_ov511 *ov)
***************************************************************************/ ***************************************************************************/
static int static int
ov51x_probe(struct usb_interface *intf, ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
const struct usb_device_id *id)
{ {
struct usb_device *dev = interface_to_usbdev(intf); struct usb_device *dev = interface_to_usbdev(intf);
struct usb_interface_descriptor *interface; struct usb_interface_descriptor *idesc;
struct usb_ov511 *ov; struct usb_ov511 *ov;
int i; int i;
int registered = 0; int registered = 0;
...@@ -6112,12 +6103,11 @@ ov51x_probe(struct usb_interface *intf, ...@@ -6112,12 +6103,11 @@ ov51x_probe(struct usb_interface *intf,
if (dev->descriptor.bNumConfigurations != 1) if (dev->descriptor.bNumConfigurations != 1)
return -ENODEV; return -ENODEV;
interface = &intf->altsetting[0].desc; idesc = &intf->altsetting[0].desc;
/* Checking vendor/product should be enough, but what the hell */ if (idesc->bInterfaceClass != 0xFF)
if (interface->bInterfaceClass != 0xFF)
return -ENODEV; return -ENODEV;
if (interface->bInterfaceSubClass != 0x00) if (idesc->bInterfaceSubClass != 0x00)
return -ENODEV; return -ENODEV;
if ((ov = kmalloc(sizeof(*ov), GFP_KERNEL)) == NULL) { if ((ov = kmalloc(sizeof(*ov), GFP_KERNEL)) == NULL) {
...@@ -6128,7 +6118,7 @@ ov51x_probe(struct usb_interface *intf, ...@@ -6128,7 +6118,7 @@ ov51x_probe(struct usb_interface *intf,
memset(ov, 0, sizeof(*ov)); memset(ov, 0, sizeof(*ov));
ov->dev = dev; ov->dev = dev;
ov->iface = interface->bInterfaceNumber; ov->iface = idesc->bInterfaceNumber;
ov->led_policy = led; ov->led_policy = led;
ov->compress = compress; ov->compress = compress;
ov->lightfreq = lightfreq; ov->lightfreq = lightfreq;
...@@ -6272,7 +6262,7 @@ ov51x_probe(struct usb_interface *intf, ...@@ -6272,7 +6262,7 @@ ov51x_probe(struct usb_interface *intf,
error_out: error_out:
err("Camera initialization failed"); err("Camera initialization failed");
return -ENOMEM; return -EIO;
} }
static void static void
...@@ -6284,6 +6274,7 @@ ov51x_disconnect(struct usb_interface *intf) ...@@ -6284,6 +6274,7 @@ ov51x_disconnect(struct usb_interface *intf)
PDEBUG(3, ""); PDEBUG(3, "");
usb_set_intfdata (intf, NULL); usb_set_intfdata (intf, NULL);
if (!ov) if (!ov)
return; return;
...@@ -6298,10 +6289,9 @@ ov51x_disconnect(struct usb_interface *intf) ...@@ -6298,10 +6289,9 @@ ov51x_disconnect(struct usb_interface *intf)
/* This will cause the process to request another frame */ /* This will cause the process to request another frame */
for (n = 0; n < OV511_NUMFRAMES; n++) for (n = 0; n < OV511_NUMFRAMES; n++)
if (waitqueue_active(&ov->frame[n].wq)) wake_up_interruptible(&ov->frame[n].wq);
wake_up_interruptible(&ov->frame[n].wq);
if (waitqueue_active(&ov->wq)) wake_up_interruptible(&ov->wq);
wake_up_interruptible(&ov->wq);
ov->streaming = 0; ov->streaming = 0;
ov51x_unlink_isoc(ov); ov51x_unlink_isoc(ov);
...@@ -6317,7 +6307,7 @@ ov51x_disconnect(struct usb_interface *intf) ...@@ -6317,7 +6307,7 @@ ov51x_disconnect(struct usb_interface *intf)
ov->cbuf = NULL; ov->cbuf = NULL;
up(&ov->cbuf_lock); up(&ov->cbuf_lock);
ov51x_dealloc(ov, 1); ov51x_dealloc(ov);
kfree(ov); kfree(ov);
ov = NULL; ov = NULL;
} }
...@@ -6333,7 +6323,6 @@ static struct usb_driver ov511_driver = { ...@@ -6333,7 +6323,6 @@ static struct usb_driver ov511_driver = {
.disconnect = ov51x_disconnect .disconnect = ov51x_disconnect
}; };
/**************************************************************************** /****************************************************************************
* *
* Module routines * Module routines
......
...@@ -96,6 +96,15 @@ config USB_LCD ...@@ -96,6 +96,15 @@ config USB_LCD
config USB_SPEEDTOUCH config USB_SPEEDTOUCH
tristate "Alcatel Speedtouch ADSL USB Modem" tristate "Alcatel Speedtouch ADSL USB Modem"
depends on USB && ATM depends on USB && ATM
help
Say Y here if you have an Alcatel SpeedTouch USB or SpeedTouch 330
modem. In order to use your modem you will need to install some user
space tools, see <http://www.linux-usb.org/SpeedTouch/> for details.
This code is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called speedtch. If you want to compile it as
a module, say M here and read <file:Documentation/modules.txt>.
config USB_TEST config USB_TEST
tristate "USB testing driver (DEVELOPMENT)" tristate "USB testing driver (DEVELOPMENT)"
......
...@@ -71,6 +71,7 @@ ...@@ -71,6 +71,7 @@
* *
*/ */
#include <linux/crc32.h>
#include "atmsar.h" #include "atmsar.h"
/*********************** /***********************
...@@ -113,200 +114,22 @@ ...@@ -113,200 +114,22 @@
*dest++ = (unsigned char) (header >> 8); \ *dest++ = (unsigned char) (header >> 8); \
*dest++ = (unsigned char) (header & 0xff); *dest++ = (unsigned char) (header & 0xff);
/*
* CRC Routines from net/wan/sbni.c)
* table generated by Rocksoft^tm Model CRC Algorithm Table Generation Program V1.0
*/
#define CRC32_REMAINDER CBF43926
#define CRC32_INITIAL 0xffffffff
#define CRC32(c,crc) (crc32tab[((size_t)(crc>>24) ^ (c)) & 0xff] ^ (((crc) << 8)))
unsigned long crc32tab[256] = {
0x00000000L, 0x04C11DB7L, 0x09823B6EL, 0x0D4326D9L,
0x130476DCL, 0x17C56B6BL, 0x1A864DB2L, 0x1E475005L,
0x2608EDB8L, 0x22C9F00FL, 0x2F8AD6D6L, 0x2B4BCB61L,
0x350C9B64L, 0x31CD86D3L, 0x3C8EA00AL, 0x384FBDBDL,
0x4C11DB70L, 0x48D0C6C7L, 0x4593E01EL, 0x4152FDA9L,
0x5F15ADACL, 0x5BD4B01BL, 0x569796C2L, 0x52568B75L,
0x6A1936C8L, 0x6ED82B7FL, 0x639B0DA6L, 0x675A1011L,
0x791D4014L, 0x7DDC5DA3L, 0x709F7B7AL, 0x745E66CDL,
0x9823B6E0L, 0x9CE2AB57L, 0x91A18D8EL, 0x95609039L,
0x8B27C03CL, 0x8FE6DD8BL, 0x82A5FB52L, 0x8664E6E5L,
0xBE2B5B58L, 0xBAEA46EFL, 0xB7A96036L, 0xB3687D81L,
0xAD2F2D84L, 0xA9EE3033L, 0xA4AD16EAL, 0xA06C0B5DL,
0xD4326D90L, 0xD0F37027L, 0xDDB056FEL, 0xD9714B49L,
0xC7361B4CL, 0xC3F706FBL, 0xCEB42022L, 0xCA753D95L,
0xF23A8028L, 0xF6FB9D9FL, 0xFBB8BB46L, 0xFF79A6F1L,
0xE13EF6F4L, 0xE5FFEB43L, 0xE8BCCD9AL, 0xEC7DD02DL,
0x34867077L, 0x30476DC0L, 0x3D044B19L, 0x39C556AEL,
0x278206ABL, 0x23431B1CL, 0x2E003DC5L, 0x2AC12072L,
0x128E9DCFL, 0x164F8078L, 0x1B0CA6A1L, 0x1FCDBB16L,
0x018AEB13L, 0x054BF6A4L, 0x0808D07DL, 0x0CC9CDCAL,
0x7897AB07L, 0x7C56B6B0L, 0x71159069L, 0x75D48DDEL,
0x6B93DDDBL, 0x6F52C06CL, 0x6211E6B5L, 0x66D0FB02L,
0x5E9F46BFL, 0x5A5E5B08L, 0x571D7DD1L, 0x53DC6066L,
0x4D9B3063L, 0x495A2DD4L, 0x44190B0DL, 0x40D816BAL,
0xACA5C697L, 0xA864DB20L, 0xA527FDF9L, 0xA1E6E04EL,
0xBFA1B04BL, 0xBB60ADFCL, 0xB6238B25L, 0xB2E29692L,
0x8AAD2B2FL, 0x8E6C3698L, 0x832F1041L, 0x87EE0DF6L,
0x99A95DF3L, 0x9D684044L, 0x902B669DL, 0x94EA7B2AL,
0xE0B41DE7L, 0xE4750050L, 0xE9362689L, 0xEDF73B3EL,
0xF3B06B3BL, 0xF771768CL, 0xFA325055L, 0xFEF34DE2L,
0xC6BCF05FL, 0xC27DEDE8L, 0xCF3ECB31L, 0xCBFFD686L,
0xD5B88683L, 0xD1799B34L, 0xDC3ABDEDL, 0xD8FBA05AL,
0x690CE0EEL, 0x6DCDFD59L, 0x608EDB80L, 0x644FC637L,
0x7A089632L, 0x7EC98B85L, 0x738AAD5CL, 0x774BB0EBL,
0x4F040D56L, 0x4BC510E1L, 0x46863638L, 0x42472B8FL,
0x5C007B8AL, 0x58C1663DL, 0x558240E4L, 0x51435D53L,
0x251D3B9EL, 0x21DC2629L, 0x2C9F00F0L, 0x285E1D47L,
0x36194D42L, 0x32D850F5L, 0x3F9B762CL, 0x3B5A6B9BL,
0x0315D626L, 0x07D4CB91L, 0x0A97ED48L, 0x0E56F0FFL,
0x1011A0FAL, 0x14D0BD4DL, 0x19939B94L, 0x1D528623L,
0xF12F560EL, 0xF5EE4BB9L, 0xF8AD6D60L, 0xFC6C70D7L,
0xE22B20D2L, 0xE6EA3D65L, 0xEBA91BBCL, 0xEF68060BL,
0xD727BBB6L, 0xD3E6A601L, 0xDEA580D8L, 0xDA649D6FL,
0xC423CD6AL, 0xC0E2D0DDL, 0xCDA1F604L, 0xC960EBB3L,
0xBD3E8D7EL, 0xB9FF90C9L, 0xB4BCB610L, 0xB07DABA7L,
0xAE3AFBA2L, 0xAAFBE615L, 0xA7B8C0CCL, 0xA379DD7BL,
0x9B3660C6L, 0x9FF77D71L, 0x92B45BA8L, 0x9675461FL,
0x8832161AL, 0x8CF30BADL, 0x81B02D74L, 0x857130C3L,
0x5D8A9099L, 0x594B8D2EL, 0x5408ABF7L, 0x50C9B640L,
0x4E8EE645L, 0x4A4FFBF2L, 0x470CDD2BL, 0x43CDC09CL,
0x7B827D21L, 0x7F436096L, 0x7200464FL, 0x76C15BF8L,
0x68860BFDL, 0x6C47164AL, 0x61043093L, 0x65C52D24L,
0x119B4BE9L, 0x155A565EL, 0x18197087L, 0x1CD86D30L,
0x029F3D35L, 0x065E2082L, 0x0B1D065BL, 0x0FDC1BECL,
0x3793A651L, 0x3352BBE6L, 0x3E119D3FL, 0x3AD08088L,
0x2497D08DL, 0x2056CD3AL, 0x2D15EBE3L, 0x29D4F654L,
0xC5A92679L, 0xC1683BCEL, 0xCC2B1D17L, 0xC8EA00A0L,
0xD6AD50A5L, 0xD26C4D12L, 0xDF2F6BCBL, 0xDBEE767CL,
0xE3A1CBC1L, 0xE760D676L, 0xEA23F0AFL, 0xEEE2ED18L,
0xF0A5BD1DL, 0xF464A0AAL, 0xF9278673L, 0xFDE69BC4L,
0x89B8FD09L, 0x8D79E0BEL, 0x803AC667L, 0x84FBDBD0L,
0x9ABC8BD5L, 0x9E7D9662L, 0x933EB0BBL, 0x97FFAD0CL,
0xAFB010B1L, 0xAB710D06L, 0xA6322BDFL, 0xA2F33668L,
0xBCB4666DL, 0xB8757BDAL, 0xB5365D03L, 0xB1F740B4L
};
#ifdef CRCASM
unsigned long calc_crc (char *mem, int len, unsigned initial)
{
unsigned crc, dummy_len;
__asm__ ("xorl %%eax,%%eax\n\t" "1:\n\t" "movl %%edx,%%eax\n\t" "shrl $16,%%eax\n\t" "lodsb\n\t" "xorb %%ah,%%al\n\t" "andl $255,%%eax\n\t" "shll $8,%%edx\n\t" "xorl (%%edi,%%eax,4),%%edx\n\t" "loop 1b":"=d" (crc),
"=c"
(dummy_len)
: "S" (mem), "D" (&crc32tab[0]), "1" (len), "0" (initial)
: "eax");
return crc;
}
#else
unsigned long calc_crc (char *mem, int len, unsigned initial)
{
unsigned crc;
crc = initial;
for (; len; mem++, len--) {
crc = CRC32 (*mem, crc);
}
return (crc);
}
#endif
#define crc32( crc, mem, len) calc_crc(mem, len, crc);
/* initialization routines. not used at the moment
* I will avoid these as long as possible !!
*/
int open_atmsar (void)
{
return 0;
}
int remove_atmsar (void)
{
return 0;
}
/* ATOMIC version of alloc_tx */
struct sk_buff *atmsar_alloc_skb_wrapper (struct atm_vcc *vcc, unsigned int size)
{
struct sk_buff *skb;
if (atomic_read (&vcc->tx_inuse) && !atm_may_send (vcc, size)) {
PDEBUG ("Sorry: tx_inuse = %d, size = %d, sndbuf = %d\n",
atomic_read (&vcc->tx_inuse), size, vcc->sk->sndbuf);
return NULL;
}
skb = alloc_skb (size, GFP_ATOMIC);
if (!skb)
return NULL;
atomic_add (skb->truesize + ATM_PDU_OVHD, &vcc->tx_inuse);
return skb;
}
struct sk_buff *atmsar_alloc_tx (struct atmsar_vcc_data *vcc, unsigned int size)
{
struct sk_buff *tmp = NULL;
int bufsize = 0;
switch (vcc->type) {
case ATMSAR_TYPE_AAL0:
/* reserving adequate headroom */
bufsize =
size + (((size / 48) + 1) * ((vcc->flags & ATMSAR_USE_53BYTE_CELL) ? 5 : 4));
break;
case ATMSAR_TYPE_AAL1:
/* reserving adequate headroom */
bufsize =
size + (((size / 47) + 1) * ((vcc->flags & ATMSAR_USE_53BYTE_CELL) ? 5 : 4));
break;
case ATMSAR_TYPE_AAL2:
case ATMSAR_TYPE_AAL34:
/* not supported */
break;
case ATMSAR_TYPE_AAL5:
/* reserving adequate tailroom */
bufsize = size + (((size + 8 + 47) / 48) * 48);
break;
}
PDEBUG ("Requested size %d, Allocating size %d\n", size, bufsize);
tmp = vcc->alloc_tx (vcc->vcc, bufsize);
skb_put (tmp, bufsize);
return tmp;
}
struct atmsar_vcc_data *atmsar_open (struct atmsar_vcc_data **list, struct atm_vcc *vcc, uint type, struct atmsar_vcc_data *atmsar_open (struct atmsar_vcc_data **list, struct atm_vcc *vcc, uint type,
ushort vpi, ushort vci, unchar pti, unchar gfc, uint flags) ushort vpi, ushort vci, unchar pti, unchar gfc, uint flags)
{ {
struct atmsar_vcc_data *new; struct atmsar_vcc_data *new;
if (!vcc)
return NULL;
new = kmalloc (sizeof (struct atmsar_vcc_data), GFP_KERNEL); new = kmalloc (sizeof (struct atmsar_vcc_data), GFP_KERNEL);
if (!new) if (!new)
return NULL; return NULL;
if (!vcc)
return NULL;
memset (new, 0, sizeof (struct atmsar_vcc_data)); memset (new, 0, sizeof (struct atmsar_vcc_data));
new->vcc = vcc; new->vcc = vcc;
/*
* This gives problems with the ATM layer alloc_tx().
* It is not usable from interrupt context and for
* some reason this is used in interrupt context
* with br2684.c
*
if (vcc->alloc_tx)
new->alloc_tx = vcc->alloc_tx;
else
*/
new->alloc_tx = atmsar_alloc_skb_wrapper;
new->stats = vcc->stats; new->stats = vcc->stats;
new->type = type; new->type = type;
new->next = NULL; new->next = NULL;
...@@ -375,216 +198,6 @@ void atmsar_close (struct atmsar_vcc_data **list, struct atmsar_vcc_data *vcc) ...@@ -375,216 +198,6 @@ void atmsar_close (struct atmsar_vcc_data **list, struct atmsar_vcc_data *vcc)
kfree (vcc); kfree (vcc);
} }
/***********************
**
** ENCODE FUNCTIONS
**
***********************/
/* encapsulate in an AAL5 frame, which is then split into ATM cells */
unsigned int atmsar_encode (struct atmsar_vcc_data *ctx, char *source, char *target, unsigned int pdu_length)
{
unsigned int num_cells = (pdu_length + ATM_AAL5_TRAILER + ATM_CELL_PAYLOAD - 1) / ATM_CELL_PAYLOAD;
unsigned int num_pdu_cells = pdu_length / ATM_CELL_PAYLOAD + 1;
unsigned int aal5_length = num_cells * ATM_CELL_PAYLOAD;
unsigned int zero_padding = aal5_length - pdu_length - ATM_AAL5_TRAILER;
unsigned int final_length = num_cells * ATM_CELL_SIZE;
unsigned char aal5_trailer [ATM_AAL5_TRAILER];
unsigned char cell_header [ATM_CELL_HEADER];
u32 crc;
int i;
PDEBUG ("atmsar_encode entered\n");
PDEBUG ("pdu_length %d, num_cells %d, num_pdu_cells %d, aal5_length %d, zero_padding %d, final_length %d\n", pdu_length, num_cells, num_pdu_cells, aal5_length, zero_padding, final_length);
PDEBUG ("source 0x=%p, target 0x%p\n", source, target);
aal5_trailer [0] = 0; /* UU = 0 */
aal5_trailer [1] = 0; /* CPI = 0 */
aal5_trailer [2] = pdu_length >> 8;
aal5_trailer [3] = pdu_length;
crc = crc32 (~0, source, pdu_length);
for (i = 0; i < zero_padding; i++)
crc = CRC32 (0, crc);
crc = crc32 (crc, aal5_trailer, 4);
crc = ~crc;
aal5_trailer [4] = crc >> 24;
aal5_trailer [5] = crc >> 16;
aal5_trailer [6] = crc >> 8;
aal5_trailer [7] = crc;
cell_header [0] = ctx->atmHeader >> 24;
cell_header [1] = ctx->atmHeader >> 16;
cell_header [2] = ctx->atmHeader >> 8;
cell_header [3] = ctx->atmHeader;
cell_header [4] = 0xec;
for (i = 1; i < num_pdu_cells; i++) {
memcpy (target, cell_header, ATM_CELL_HEADER);
target += ATM_CELL_HEADER;
memcpy (target, source, ATM_CELL_PAYLOAD);
target += ATM_CELL_PAYLOAD;
source += ATM_CELL_PAYLOAD;
PDEBUG ("source 0x=%p, target 0x%p\n", source, target);
}
memcpy (target, cell_header, ATM_CELL_HEADER);
target += ATM_CELL_HEADER;
memcpy (target, source, pdu_length % ATM_CELL_PAYLOAD);
target += pdu_length % ATM_CELL_PAYLOAD;
if (num_pdu_cells < num_cells) {
memset (target, 0, zero_padding + ATM_AAL5_TRAILER - ATM_CELL_PAYLOAD);
target += zero_padding + ATM_AAL5_TRAILER - ATM_CELL_PAYLOAD;
memcpy (target, cell_header, ATM_CELL_HEADER);
target += ATM_CELL_HEADER;
zero_padding = ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER;
}
memset (target, 0, zero_padding);
target += zero_padding;
memcpy (target, aal5_trailer, ATM_AAL5_TRAILER);
/* set pti bit in last cell */
*(target + ATM_AAL5_TRAILER + 3 - ATM_CELL_SIZE) |= 0x2;
/* update stats */
if (ctx->stats)
atomic_inc (&ctx->stats->tx);
if (ctx->stats && (ctx->type <= ATMSAR_TYPE_AAL1))
atomic_add (num_cells, &(ctx->stats->tx));
return final_length;
}
struct sk_buff *atmsar_encode_rawcell (struct atmsar_vcc_data *ctx, struct sk_buff *skb)
{
int number_of_cells = (skb->len) / 48;
int total_length = number_of_cells * (ctx->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52);
unsigned char *source;
unsigned char *target;
struct sk_buff *out = NULL;
int i;
PDEBUG ("atmsar_encode_rawcell (0x%p, 0x%p) called\n", ctx, skb);
if (skb_cloned (skb)
|| (skb_headroom (skb) <
(number_of_cells * (ctx->flags & ATMSAR_USE_53BYTE_CELL ? 5 : 4)))) {
PDEBUG
("atmsar_encode_rawcell allocating new skb. ctx->alloc_tx = 0x%p, ctx->vcc = 0x%p\n",
ctx->alloc_tx, ctx->vcc);
/* get new skb */
out = ctx->alloc_tx (ctx->vcc, total_length);
if (!out)
return NULL;
skb_put (out, total_length);
source = skb->data;
target = out->data;
} else {
PDEBUG ("atmsar_encode_rawcell: sufficient headroom\n");
source = skb->data;
skb_push (skb, number_of_cells * ((ctx->flags & ATMSAR_USE_53BYTE_CELL) ? 5 : 4));
target = skb->data;
out = skb;
}
PDEBUG ("source 0x=%p, target 0x%p\n", source, target);
if (ctx->flags & ATMSAR_USE_53BYTE_CELL) {
for (i = 0; i < number_of_cells; i++) {
ADD_HEADER (target, ctx->atmHeader);
*target++ = (char) 0xEC;
memcpy (target, source, 48);
target += 48;
source += 48;
PDEBUG ("source 0x=%p, target 0x%p\n", source, target);
}
} else {
for (i = 0; i < number_of_cells; i++) {
ADD_HEADER (target, ctx->atmHeader);
memcpy (target, source, 48);
target += 48;
source += 48;
PDEBUG ("source 0x=%p, target 0x%p\n", source, target);
};
}
if (ctx->flags & ATMSAR_SET_PTI) {
/* setting pti bit in last cell */
*(target - (ctx->flags & ATMSAR_USE_53BYTE_CELL ? 50 : 49)) |= 0x2;
}
/* update stats */
if (ctx->stats && (ctx->type <= ATMSAR_TYPE_AAL1))
atomic_add (number_of_cells, &(ctx->stats->tx));
PDEBUG ("atmsar_encode_rawcell return 0x%p (length %d)\n", out, out->len);
return out;
}
struct sk_buff *atmsar_encode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff *skb)
{
int length, pdu_length;
unsigned char *trailer;
unsigned char *pad;
uint crc = 0xffffffff;
PDEBUG ("atmsar_encode_aal5 (0x%p, 0x%p) called\n", ctx, skb);
/* determine aal5 length */
pdu_length = skb->len;
length = ((pdu_length + 8 + 47) / 48) * 48;
if (skb_tailroom (skb) < (length - pdu_length)) {
struct sk_buff *out;
PDEBUG
("atmsar_encode_aal5 allocating new skb. ctx->alloc_tx = 0x%p, ctx->vcc = 0x%p\n",
ctx->alloc_tx, ctx->vcc);
/* get new skb */
out = ctx->alloc_tx (ctx->vcc, length);
if (!out)
return NULL;
PDEBUG ("out->data = 0x%p\n", out->data);
PDEBUG ("atmsar_encode_aal5 pdu length %d, allocated length %d\n", skb->len,
length);
memcpy (out->data, skb->data, skb->len);
skb_put (out, skb->len);
skb = out;
}
PDEBUG ("skb->data = 0x%p\n", skb->data);
/* note end of pdu and add length */
pad = skb_put (skb, length - pdu_length);
trailer = skb->tail - 8;
PDEBUG ("trailer = 0x%p\n", trailer);
/* zero padding space */
memset (pad, 0, length - pdu_length - 8);
/* add trailer */
*trailer++ = (unsigned char) 0; /* UU = 0 */
*trailer++ = (unsigned char) 0; /* CPI = 0 */
*trailer++ = (unsigned char) (pdu_length >> 8);
*trailer++ = (unsigned char) (pdu_length & 0xff);
crc = ~crc32 (crc, skb->data, length - 4);
*trailer++ = (unsigned char) (crc >> 24);
*trailer++ = (unsigned char) (crc >> 16);
*trailer++ = (unsigned char) (crc >> 8);
*trailer++ = (unsigned char) (crc & 0xff);
/* update stats */
if (ctx->stats)
atomic_inc (&ctx->stats->tx);
PDEBUG ("atmsar_encode_aal5 return 0x%p (length %d)\n", skb, skb->len);
return skb;
}
/*********************** /***********************
** **
...@@ -745,7 +358,7 @@ struct sk_buff *atmsar_decode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff ...@@ -745,7 +358,7 @@ struct sk_buff *atmsar_decode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff
skb_pull (skb, skb->len - pdu_length); skb_pull (skb, skb->len - pdu_length);
} }
crc = ~crc32 (crc, skb->data, pdu_length - 4); crc = ~crc32_be (crc, skb->data, pdu_length - 4);
/* check crc */ /* check crc */
if (pdu_crc != crc) { if (pdu_crc != crc) {
......
...@@ -58,7 +58,6 @@ struct atmsar_vcc_data { ...@@ -58,7 +58,6 @@ struct atmsar_vcc_data {
int type; int type;
/* connection specific non-atmsar data */ /* connection specific non-atmsar data */
struct sk_buff *(*alloc_tx) (struct atm_vcc * vcc, unsigned int size);
struct atm_vcc *vcc; struct atm_vcc *vcc;
struct k_atm_aal_stats *stats; struct k_atm_aal_stats *stats;
unsigned short mtu; /* max is actually 65k for AAL5... */ unsigned short mtu; /* max is actually 65k for AAL5... */
...@@ -81,15 +80,8 @@ extern struct atmsar_vcc_data *atmsar_open (struct atmsar_vcc_data **list, struc ...@@ -81,15 +80,8 @@ extern struct atmsar_vcc_data *atmsar_open (struct atmsar_vcc_data **list, struc
unchar gfc, uint flags); unchar gfc, uint flags);
extern void atmsar_close (struct atmsar_vcc_data **list, struct atmsar_vcc_data *vcc); extern void atmsar_close (struct atmsar_vcc_data **list, struct atmsar_vcc_data *vcc);
extern struct sk_buff *atmsar_encode_rawcell (struct atmsar_vcc_data *ctx, struct sk_buff *skb);
extern struct sk_buff *atmsar_encode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff *skb);
struct sk_buff *atmsar_decode_rawcell (struct atmsar_vcc_data *list, struct sk_buff *skb, struct sk_buff *atmsar_decode_rawcell (struct atmsar_vcc_data *list, struct sk_buff *skb,
struct atmsar_vcc_data **ctx); struct atmsar_vcc_data **ctx);
struct sk_buff *atmsar_decode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff *skb); struct sk_buff *atmsar_decode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff *skb);
struct sk_buff *atmsar_alloc_tx (struct atmsar_vcc_data *vcc, unsigned int size);
unsigned int atmsar_encode (struct atmsar_vcc_data *ctx, char *source, char *target, unsigned int pdu_length);
#endif /* _ATMSAR_H_ */ #endif /* _ATMSAR_H_ */
...@@ -61,6 +61,7 @@ ...@@ -61,6 +61,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/atm.h> #include <linux/atm.h>
#include <linux/atmdev.h> #include <linux/atmdev.h>
#include <linux/crc32.h>
#include "atmsar.h" #include "atmsar.h"
/* /*
...@@ -69,14 +70,15 @@ ...@@ -69,14 +70,15 @@
*/ */
#ifdef DEBUG #ifdef DEBUG
#define PDEBUG(arg...) printk(KERN_DEBUG "SpeedTouch USB: " arg) #define PDEBUG(arg...) printk(KERN_DEBUG __FILE__ ": " arg)
#else #else
#define PDEBUG(arg...) #define PDEBUG(arg...)
#endif #endif
#ifdef DEBUG_PACKET #ifdef DEBUG_PACKET
#define PACKETDEBUG(arg...) udsl_print_packet ( arg ) static int udsl_print_packet (const unsigned char *data, int len);
#define PACKETDEBUG(arg...) udsl_print_packet (arg)
#else #else
#define PACKETDEBUG(arg...) #define PACKETDEBUG(arg...)
#endif #endif
...@@ -88,15 +90,14 @@ ...@@ -88,15 +90,14 @@
#define SPEEDTOUCH_VENDORID 0x06b9 #define SPEEDTOUCH_VENDORID 0x06b9
#define SPEEDTOUCH_PRODUCTID 0x4061 #define SPEEDTOUCH_PRODUCTID 0x4061
#define UDSL_OBUF_SIZE 32768
#define UDSL_MINOR 48
#define UDSL_NUMBER_RCV_URBS 1 #define UDSL_NUMBER_RCV_URBS 1
#define UDSL_NUMBER_SND_URBS 1 #define UDSL_NUMBER_SND_URBS 1
#define UDSL_RECEIVE_BUFFER_SIZE 64*53 #define UDSL_NUMBER_SND_BUFS (2*UDSL_NUMBER_SND_URBS)
#define UDSL_RCV_BUFFER_SIZE (1*64) /* ATM cells */
#define UDSL_SND_BUFFER_SIZE (1*64) /* ATM cells */
/* max should be (1500 IP mtu + 2 ppp bytes + 32 * 5 cellheader overhead) for /* max should be (1500 IP mtu + 2 ppp bytes + 32 * 5 cellheader overhead) for
* PPPoA and (1500 + 14 + 32*5 cellheader overhead) for PPPoE */ * PPPoA and (1500 + 14 + 32*5 cellheader overhead) for PPPoE */
#define UDSL_MAX_AAL5_MRU 2048 #define UDSL_MAX_AAL5_MRU 2048
#define UDSL_SEND_CONTEXTS 8
#define UDSL_IOCTL_START 1 #define UDSL_IOCTL_START 1
#define UDSL_IOCTL_STOP 2 #define UDSL_IOCTL_STOP 2
...@@ -126,13 +127,31 @@ struct udsl_receiver { ...@@ -126,13 +127,31 @@ struct udsl_receiver {
struct udsl_instance_data *instance; struct udsl_instance_data *instance;
}; };
struct udsl_usb_send_data_context { struct udsl_send_buffer {
struct list_head list;
unsigned char *base;
unsigned char *free_start;
unsigned int free_cells;
};
struct udsl_sender {
struct list_head list;
struct udsl_send_buffer *buffer;
struct urb *urb; struct urb *urb;
struct sk_buff *skb;
struct atm_vcc *vcc;
struct udsl_instance_data *instance; struct udsl_instance_data *instance;
}; };
struct udsl_control {
struct atm_skb_data atm_data;
unsigned int num_cells;
unsigned int num_entire;
unsigned char cell_header [ATM_CELL_HEADER];
unsigned int pdu_padding;
unsigned char aal5_trailer [ATM_AAL5_TRAILER];
};
#define UDSL_SKB(x) ((struct udsl_control *)(x)->cb)
/* /*
* UDSL main driver data * UDSL main driver data
*/ */
...@@ -142,13 +161,10 @@ struct udsl_instance_data { ...@@ -142,13 +161,10 @@ struct udsl_instance_data {
/* usb device part */ /* usb device part */
struct usb_device *usb_dev; struct usb_device *usb_dev;
struct sk_buff_head sndqueue;
struct udsl_usb_send_data_context send_ctx [UDSL_NUMBER_SND_URBS];
int firmware_loaded; int firmware_loaded;
/* atm device part */ /* atm device part */
struct atm_dev *atm_dev; struct atm_dev *atm_dev;
struct atmsar_vcc_data *atmsar_vcc_list; struct atmsar_vcc_data *atmsar_vcc_list;
/* receiving */ /* receiving */
...@@ -161,18 +177,30 @@ struct udsl_instance_data { ...@@ -161,18 +177,30 @@ struct udsl_instance_data {
struct list_head completed_receivers; struct list_head completed_receivers;
struct tasklet_struct receive_tasklet; struct tasklet_struct receive_tasklet;
};
static const char udsl_driver_name [] = "Alcatel SpeedTouch USB"; /* sending */
struct udsl_sender all_senders [UDSL_NUMBER_SND_URBS];
struct udsl_send_buffer all_buffers [UDSL_NUMBER_SND_BUFS];
#ifdef DEBUG_PACKET struct sk_buff_head sndqueue;
static int udsl_print_packet (const unsigned char *data, int len);
#endif spinlock_t send_lock;
struct list_head spare_senders;
struct list_head spare_buffers;
struct tasklet_struct send_tasklet;
struct sk_buff *current_skb; /* being emptied */
struct udsl_send_buffer *current_buffer; /* being filled */
struct list_head filled_buffers;
};
static const char udsl_driver_name [] = "speedtch";
/* /*
* atm driver prototypes and stuctures * atm driver prototypes and stuctures
*/ */
static void udsl_atm_dev_close (struct atm_dev *dev);
static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci); static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci);
static void udsl_atm_close (struct atm_vcc *vcc); static void udsl_atm_close (struct atm_vcc *vcc);
static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg); static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg);
...@@ -180,6 +208,7 @@ static int udsl_atm_send (struct atm_vcc *vcc, struct sk_buff *skb); ...@@ -180,6 +208,7 @@ static int udsl_atm_send (struct atm_vcc *vcc, struct sk_buff *skb);
static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t *pos, char *page); static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t *pos, char *page);
static struct atmdev_ops udsl_atm_devops = { static struct atmdev_ops udsl_atm_devops = {
.dev_close = udsl_atm_dev_close,
.open = udsl_atm_open, .open = udsl_atm_open,
.close = udsl_atm_close, .close = udsl_atm_close,
.ioctl = udsl_atm_ioctl, .ioctl = udsl_atm_ioctl,
...@@ -187,20 +216,13 @@ static struct atmdev_ops udsl_atm_devops = { ...@@ -187,20 +216,13 @@ static struct atmdev_ops udsl_atm_devops = {
.proc_read = udsl_atm_proc_read, .proc_read = udsl_atm_proc_read,
}; };
struct udsl_atm_dev_data {
struct atmsar_vcc_data *atmsar_vcc;
};
/* /*
* usb driver prototypes and structures * usb driver prototypes and structures
*/ */
static int udsl_usb_probe (struct usb_interface *intf, static int udsl_usb_probe (struct usb_interface *intf,
const struct usb_device_id *id); const struct usb_device_id *id);
static void udsl_usb_disconnect (struct usb_interface *intf); static void udsl_usb_disconnect (struct usb_interface *intf);
static int udsl_usb_send_data (struct udsl_instance_data *instance, struct atm_vcc *vcc,
struct sk_buff *skb);
static int udsl_usb_ioctl (struct usb_interface *intf, unsigned int code, void *user_data); static int udsl_usb_ioctl (struct usb_interface *intf, unsigned int code, void *user_data);
static int udsl_usb_cancelsends (struct udsl_instance_data *instance, struct atm_vcc *vcc);
static struct usb_driver udsl_usb_driver = { static struct usb_driver udsl_usb_driver = {
.name = udsl_driver_name, .name = udsl_driver_name,
...@@ -211,6 +233,86 @@ static struct usb_driver udsl_usb_driver = { ...@@ -211,6 +233,86 @@ static struct usb_driver udsl_usb_driver = {
}; };
/*************
** encode **
*************/
static void udsl_groom_skb (struct atm_vcc *vcc, struct sk_buff *skb) {
struct udsl_control *ctrl = UDSL_SKB (skb);
unsigned int i, zero_padding;
unsigned char zero = 0;
u32 crc;
ctrl->atm_data.vcc = vcc;
ctrl->cell_header [0] = vcc->vpi >> 4;
ctrl->cell_header [1] = (vcc->vpi << 4) | (vcc->vci >> 12);
ctrl->cell_header [2] = vcc->vci >> 4;
ctrl->cell_header [3] = vcc->vci << 4;
ctrl->cell_header [4] = 0xec;
ctrl->num_cells = (skb->len + ATM_AAL5_TRAILER + ATM_CELL_PAYLOAD - 1) / ATM_CELL_PAYLOAD;
ctrl->num_entire = skb->len / ATM_CELL_PAYLOAD;
zero_padding = ctrl->num_cells * ATM_CELL_PAYLOAD - skb->len - ATM_AAL5_TRAILER;
if (ctrl->num_entire + 1 < ctrl->num_cells)
ctrl->pdu_padding = zero_padding - (ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER);
else
ctrl->pdu_padding = zero_padding;
ctrl->aal5_trailer [0] = 0; /* UU = 0 */
ctrl->aal5_trailer [1] = 0; /* CPI = 0 */
ctrl->aal5_trailer [2] = skb->len >> 8;
ctrl->aal5_trailer [3] = skb->len;
crc = crc32_be (~0, skb->data, skb->len);
for (i = 0; i < zero_padding; i++)
crc = crc32_be (crc, &zero, 1);
crc = crc32_be (crc, ctrl->aal5_trailer, 4);
crc = ~crc;
ctrl->aal5_trailer [4] = crc >> 24;
ctrl->aal5_trailer [5] = crc >> 16;
ctrl->aal5_trailer [6] = crc >> 8;
ctrl->aal5_trailer [7] = crc;
}
static char *udsl_write_cell (struct sk_buff *skb, char *target) {
struct udsl_control *ctrl = UDSL_SKB (skb);
ctrl->num_cells--;
memcpy (target, ctrl->cell_header, ATM_CELL_HEADER);
target += ATM_CELL_HEADER;
if (ctrl->num_entire) {
ctrl->num_entire--;
memcpy (target, skb->data, ATM_CELL_PAYLOAD);
target += ATM_CELL_PAYLOAD;
__skb_pull (skb, ATM_CELL_PAYLOAD);
return target;
}
memcpy (target, skb->data, skb->len);
target += skb->len;
__skb_pull (skb, skb->len);
memset (target, 0, ctrl->pdu_padding);
target += ctrl->pdu_padding;
if (ctrl->num_cells) {
ctrl->pdu_padding = ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER;
} else {
memcpy (target, ctrl->aal5_trailer, ATM_AAL5_TRAILER);
target += ATM_AAL5_TRAILER;
/* set pti bit in last cell */
*(target + 3 - ATM_CELL_SIZE) |= 0x2;
}
return target;
}
/************** /**************
** receive ** ** receive **
**************/ **************/
...@@ -221,19 +323,18 @@ static void udsl_complete_receive (struct urb *urb, struct pt_regs *regs) ...@@ -221,19 +323,18 @@ static void udsl_complete_receive (struct urb *urb, struct pt_regs *regs)
struct udsl_receiver *rcv; struct udsl_receiver *rcv;
unsigned long flags; unsigned long flags;
PDEBUG ("udsl_complete_receive entered\n");
if (!urb || !(rcv = urb->context) || !(instance = rcv->instance)) { if (!urb || !(rcv = urb->context) || !(instance = rcv->instance)) {
PDEBUG ("udsl_complete_receive: bad urb!\n"); PDEBUG ("udsl_complete_receive: bad urb!\n");
return; return;
} }
PDEBUG ("udsl_complete_receive entered (urb 0x%p, status %d)\n", urb, urb->status);
tasklet_schedule (&instance->receive_tasklet);
/* may not be in_interrupt() */ /* may not be in_interrupt() */
spin_lock_irqsave (&instance->completed_receivers_lock, flags); spin_lock_irqsave (&instance->completed_receivers_lock, flags);
list_add_tail (&rcv->list, &instance->completed_receivers); list_add_tail (&rcv->list, &instance->completed_receivers);
spin_unlock_irqrestore (&instance->completed_receivers_lock, flags); spin_unlock_irqrestore (&instance->completed_receivers_lock, flags);
PDEBUG ("udsl_complete_receive: scheduling tasklet\n");
tasklet_schedule (&instance->receive_tasklet);
} }
static void udsl_process_receive (unsigned long data) static void udsl_process_receive (unsigned long data)
...@@ -246,6 +347,7 @@ static void udsl_process_receive (unsigned long data) ...@@ -246,6 +347,7 @@ static void udsl_process_receive (unsigned long data)
struct urb *urb; struct urb *urb;
struct atmsar_vcc_data *atmsar_vcc = NULL; struct atmsar_vcc_data *atmsar_vcc = NULL;
struct sk_buff *new = NULL, *tmp = NULL; struct sk_buff *new = NULL, *tmp = NULL;
int err;
PDEBUG ("udsl_process_receive entered\n"); PDEBUG ("udsl_process_receive entered\n");
...@@ -315,12 +417,12 @@ static void udsl_process_receive (unsigned long data) ...@@ -315,12 +417,12 @@ static void udsl_process_receive (unsigned long data)
instance->usb_dev, instance->usb_dev,
usb_rcvbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_IN), usb_rcvbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_IN),
(unsigned char *) rcv->skb->data, (unsigned char *) rcv->skb->data,
UDSL_RECEIVE_BUFFER_SIZE, UDSL_RCV_BUFFER_SIZE * ATM_CELL_SIZE,
udsl_complete_receive, udsl_complete_receive,
rcv); rcv);
if (!usb_submit_urb (urb, GFP_ATOMIC)) if (!(err = usb_submit_urb (urb, GFP_ATOMIC)))
break; break;
PDEBUG ("udsl_process_receive: submission failed\n"); PDEBUG ("udsl_process_receive: submission failed (%d)\n", err);
/* fall through */ /* fall through */
default: /* error or urb unlinked */ default: /* error or urb unlinked */
PDEBUG ("udsl_process_receive: adding to spare_receivers\n"); PDEBUG ("udsl_process_receive: adding to spare_receivers\n");
...@@ -358,7 +460,7 @@ static void udsl_fire_receivers (struct udsl_instance_data *instance) ...@@ -358,7 +460,7 @@ static void udsl_fire_receivers (struct udsl_instance_data *instance)
instance->usb_dev, instance->usb_dev,
usb_rcvbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_IN), usb_rcvbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_IN),
(unsigned char *) rcv->skb->data, (unsigned char *) rcv->skb->data,
UDSL_RECEIVE_BUFFER_SIZE, UDSL_RCV_BUFFER_SIZE * ATM_CELL_SIZE,
udsl_complete_receive, udsl_complete_receive,
rcv); rcv);
...@@ -374,6 +476,210 @@ static void udsl_fire_receivers (struct udsl_instance_data *instance) ...@@ -374,6 +476,210 @@ static void udsl_fire_receivers (struct udsl_instance_data *instance)
} }
/***********
** send **
***********/
static void udsl_complete_send (struct urb *urb, struct pt_regs *regs)
{
struct udsl_instance_data *instance;
struct udsl_sender *snd;
unsigned long flags;
if (!urb || !(snd = urb->context) || !(instance = snd->instance)) {
PDEBUG ("udsl_complete_send: bad urb!\n");
return;
}
PDEBUG ("udsl_complete_send entered (urb 0x%p, status %d)\n", urb, urb->status);
tasklet_schedule (&instance->send_tasklet);
/* may not be in_interrupt() */
spin_lock_irqsave (&instance->send_lock, flags);
list_add (&snd->list, &instance->spare_senders);
list_add (&snd->buffer->list, &instance->spare_buffers);
spin_unlock_irqrestore (&instance->send_lock, flags);
}
static void udsl_process_send (unsigned long data)
{
struct udsl_send_buffer *buf;
unsigned int cells_to_write;
int err;
unsigned long flags;
unsigned int i;
struct udsl_instance_data *instance = (struct udsl_instance_data *) data;
struct sk_buff *skb;
struct udsl_sender *snd;
unsigned char *target;
PDEBUG ("udsl_process_send entered\n");
made_progress:
spin_lock_irqsave (&instance->send_lock, flags);
while (!list_empty (&instance->spare_senders)) {
if (!list_empty (&instance->filled_buffers)) {
buf = list_entry (instance->filled_buffers.next, struct udsl_send_buffer, list);
list_del (&buf->list);
PDEBUG ("sending filled buffer (0x%p)\n", buf);
} else if ((buf = instance->current_buffer)) {
instance->current_buffer = NULL;
PDEBUG ("sending current buffer (0x%p)\n", buf);
} else /* all buffers empty */
break;
snd = list_entry (instance->spare_senders.next, struct udsl_sender, list);
list_del (&snd->list);
spin_unlock_irqrestore (&instance->send_lock, flags);
snd->buffer = buf;
usb_fill_bulk_urb (snd->urb,
instance->usb_dev,
usb_sndbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_OUT),
buf->base,
(UDSL_SND_BUFFER_SIZE - buf->free_cells) * ATM_CELL_SIZE,
udsl_complete_send,
snd);
PDEBUG ("submitting urb 0x%p, contains %d cells\n", snd->urb, UDSL_SND_BUFFER_SIZE - buf->free_cells);
if ((err = usb_submit_urb(snd->urb, GFP_ATOMIC)) < 0) {
PDEBUG ("submission failed (%d)!\n", err);
spin_lock_irqsave (&instance->send_lock, flags);
list_add (&snd->list, &instance->spare_senders);
spin_unlock_irqrestore (&instance->send_lock, flags);
list_add (&buf->list, &instance->filled_buffers);
return;
}
spin_lock_irqsave (&instance->send_lock, flags);
} /* while */
spin_unlock_irqrestore (&instance->send_lock, flags);
if (!instance->current_skb && !(instance->current_skb = skb_dequeue (&instance->sndqueue))) {
PDEBUG ("done - no more skbs\n");
return;
}
skb = instance->current_skb;
if (!(buf = instance->current_buffer)) {
spin_lock_irqsave (&instance->send_lock, flags);
if (list_empty (&instance->spare_buffers)) {
instance->current_buffer = NULL;
spin_unlock_irqrestore (&instance->send_lock, flags);
PDEBUG ("done - no more buffers\n");
return;
}
buf = list_entry (instance->spare_buffers.next, struct udsl_send_buffer, list);
list_del (&buf->list);
spin_unlock_irqrestore (&instance->send_lock, flags);
buf->free_start = buf->base;
buf->free_cells = UDSL_SND_BUFFER_SIZE;
instance->current_buffer = buf;
}
cells_to_write = min (buf->free_cells, UDSL_SKB (skb)->num_cells);
target = buf->free_start;
PDEBUG ("writing %u cells from skb 0x%p to buffer 0x%p\n", cells_to_write, skb, buf);
for (i = 0; i < cells_to_write; i++)
target = udsl_write_cell (skb, target);
buf->free_start = target;
if (!(buf->free_cells -= cells_to_write)) {
list_add_tail (&buf->list, &instance->filled_buffers);
instance->current_buffer = NULL;
PDEBUG ("queued filled buffer\n");
}
PDEBUG ("buffer contains %d cells, %d left\n", UDSL_SND_BUFFER_SIZE - buf->free_cells, buf->free_cells);
if (!UDSL_SKB (skb)->num_cells) {
struct atm_vcc *vcc = UDSL_SKB (skb)->atm_data.vcc;
PDEBUG ("discarding empty skb\n");
if (vcc->pop)
vcc->pop (vcc, skb);
else
kfree_skb (skb);
instance->current_skb = NULL;
if (vcc->stats)
atomic_inc (&vcc->stats->tx);
}
goto made_progress;
}
static void udsl_cancel_send (struct udsl_instance_data *instance, struct atm_vcc *vcc)
{
unsigned long flags;
struct sk_buff *skb, *n;
PDEBUG ("udsl_cancel_send entered\n");
spin_lock_irqsave (&instance->sndqueue.lock, flags);
for (skb = instance->sndqueue.next, n = skb->next; skb != (struct sk_buff *)&instance->sndqueue; skb = n, n = skb->next)
if (UDSL_SKB (skb)->atm_data.vcc == vcc) {
PDEBUG ("popping skb 0x%p\n", skb);
__skb_unlink (skb, &instance->sndqueue);
if (vcc->pop)
vcc->pop (vcc, skb);
else
kfree_skb (skb);
}
spin_unlock_irqrestore (&instance->sndqueue.lock, flags);
tasklet_disable (&instance->send_tasklet);
if ((skb = instance->current_skb) && (UDSL_SKB (skb)->atm_data.vcc == vcc)) {
PDEBUG ("popping current skb (0x%p)\n", skb);
instance->current_skb = NULL;
if (vcc->pop)
vcc->pop (vcc, skb);
else
kfree_skb (skb);
}
tasklet_enable (&instance->send_tasklet);
PDEBUG ("udsl_cancel_send done\n");
}
static int udsl_atm_send (struct atm_vcc *vcc, struct sk_buff *skb)
{
struct udsl_instance_data *instance = vcc->dev->dev_data;
PDEBUG ("udsl_atm_send called (skb 0x%p, len %u)\n", skb, skb->len);
if (!instance) {
PDEBUG ("NULL instance!\n");
return -EINVAL;
}
if (!instance->firmware_loaded)
return -EAGAIN;
if (vcc->qos.aal != ATM_AAL5) {
PDEBUG ("unsupported ATM type %d!\n", vcc->qos.aal);
return -EINVAL;
}
if (skb->len > ATM_MAX_AAL5_PDU) {
PDEBUG ("packet too long (%d vs %d)!\n", skb->len, ATM_MAX_AAL5_PDU);
return -EINVAL;
}
PACKETDEBUG (skb->data, skb->len);
udsl_groom_skb (vcc, skb);
skb_queue_tail (&instance->sndqueue, skb);
tasklet_schedule (&instance->send_tasklet);
return 0;
}
/************ /************
** ATM ** ** ATM **
************/ ************/
...@@ -384,24 +690,21 @@ static void udsl_fire_receivers (struct udsl_instance_data *instance) ...@@ -384,24 +690,21 @@ static void udsl_fire_receivers (struct udsl_instance_data *instance)
* *
****************************************************************************/ ****************************************************************************/
static void udsl_atm_stopdevice (struct udsl_instance_data *instance) static void udsl_atm_dev_close (struct atm_dev *dev)
{ {
struct atm_vcc *walk; struct udsl_instance_data *instance = dev->dev_data;
struct atm_dev *atm_dev;
if (!instance->atm_dev) if (!instance) {
PDEBUG ("udsl_atm_dev_close: NULL instance!\n");
return; return;
}
atm_dev = instance->atm_dev; PDEBUG ("udsl_atm_dev_close: queue has %u elements\n", instance->sndqueue.qlen);
atm_dev->signal = ATM_PHY_SIG_LOST;
walk = atm_dev->vccs;
shutdown_atm_dev (atm_dev);
for (; walk; walk = walk->next)
wake_up (&walk->sleep);
instance->atm_dev = NULL; PDEBUG ("udsl_atm_dev_close: killing tasklet\n");
tasklet_kill (&instance->send_tasklet);
PDEBUG ("udsl_atm_dev_close: freeing instance\n");
kfree (instance);
} }
...@@ -410,17 +713,6 @@ static void udsl_atm_stopdevice (struct udsl_instance_data *instance) ...@@ -410,17 +713,6 @@ static void udsl_atm_stopdevice (struct udsl_instance_data *instance)
* ATM helper functions * ATM helper functions
* *
****************************************************************************/ ****************************************************************************/
static struct sk_buff *udsl_atm_alloc_tx (struct atm_vcc *vcc, unsigned int size)
{
struct atmsar_vcc_data *atmsar_vcc =
((struct udsl_atm_dev_data *) vcc->dev_data)->atmsar_vcc;
if (atmsar_vcc)
return atmsar_alloc_tx (atmsar_vcc, size);
printk (KERN_INFO
"SpeedTouch USB: udsl_atm_alloc_tx could not find correct alloc_tx function !\n");
return NULL;
}
static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t *pos, char *page) static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t *pos, char *page)
{ {
...@@ -438,14 +730,6 @@ static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t *pos, char *page) ...@@ -438,14 +730,6 @@ static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t *pos, char *page)
atm_dev->esi[0], atm_dev->esi[1], atm_dev->esi[2], atm_dev->esi[0], atm_dev->esi[1], atm_dev->esi[2],
atm_dev->esi[3], atm_dev->esi[4], atm_dev->esi[5]); atm_dev->esi[3], atm_dev->esi[4], atm_dev->esi[5]);
if (!left--)
return sprintf (page, "AAL0: tx %d ( %d err ), rx %d ( %d err, %d drop )\n",
atomic_read (&atm_dev->stats.aal0.tx),
atomic_read (&atm_dev->stats.aal0.tx_err),
atomic_read (&atm_dev->stats.aal0.rx),
atomic_read (&atm_dev->stats.aal0.rx_err),
atomic_read (&atm_dev->stats.aal0.rx_drop));
if (!left--) if (!left--)
return sprintf (page, "AAL5: tx %d ( %d err ), rx %d ( %d err, %d drop )\n", return sprintf (page, "AAL5: tx %d ( %d err ), rx %d ( %d err, %d drop )\n",
atomic_read (&atm_dev->stats.aal5.tx), atomic_read (&atm_dev->stats.aal5.tx),
...@@ -458,60 +742,6 @@ static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t *pos, char *page) ...@@ -458,60 +742,6 @@ static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t *pos, char *page)
} }
/***************************************************************************
*
* ATM DATA functions
*
****************************************************************************/
static int udsl_atm_send (struct atm_vcc *vcc, struct sk_buff *skb)
{
struct udsl_atm_dev_data *dev_data = vcc->dev_data;
struct udsl_instance_data *instance = vcc->dev->dev_data;
struct sk_buff *new = NULL;
int err;
PDEBUG ("udsl_atm_send called\n");
if (!dev_data || !instance) {
PDEBUG ("NULL data!\n");
return -EINVAL;
}
if (!instance->firmware_loaded)
return -EAGAIN;
switch (vcc->qos.aal) {
case ATM_AAL5:
new = atmsar_encode_aal5 (dev_data->atmsar_vcc, skb);
if (!new)
goto nomem;
if (new != skb) {
vcc->pop (vcc, skb);
skb = new;
}
new = atmsar_encode_rawcell (dev_data->atmsar_vcc, skb);
if (!new)
goto nomem;
if (new != skb) {
vcc->pop (vcc, skb);
skb = new;
}
err = udsl_usb_send_data (instance, vcc, skb);
PDEBUG ("udsl_atm_send successfull (%d)\n", err);
return err;
break;
default:
return -EINVAL;
}
PDEBUG ("udsl_atm_send unsuccessfull\n");
return 0;
nomem:
vcc->pop (vcc, skb);
return -ENOMEM;
}
/*************************************************************************** /***************************************************************************
* *
* SAR driver entries * SAR driver entries
...@@ -520,7 +750,6 @@ static int udsl_atm_send (struct atm_vcc *vcc, struct sk_buff *skb) ...@@ -520,7 +750,6 @@ static int udsl_atm_send (struct atm_vcc *vcc, struct sk_buff *skb)
static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci) static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci)
{ {
struct udsl_atm_dev_data *dev_data;
struct udsl_instance_data *instance = vcc->dev->dev_data; struct udsl_instance_data *instance = vcc->dev->dev_data;
PDEBUG ("udsl_atm_open called\n"); PDEBUG ("udsl_atm_open called\n");
...@@ -535,15 +764,12 @@ static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci) ...@@ -535,15 +764,12 @@ static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci)
return -EINVAL; return -EINVAL;
MOD_INC_USE_COUNT; MOD_INC_USE_COUNT;
dev_data = kmalloc (sizeof (struct udsl_atm_dev_data), GFP_KERNEL);
if (!dev_data)
return -ENOMEM;
dev_data->atmsar_vcc = vcc->dev_data =
atmsar_open (&(instance->atmsar_vcc_list), vcc, ATMSAR_TYPE_AAL5, vpi, vci, 0, 0, atmsar_open (&(instance->atmsar_vcc_list), vcc, ATMSAR_TYPE_AAL5, vpi, vci, 0, 0,
ATMSAR_USE_53BYTE_CELL | ATMSAR_SET_PTI); ATMSAR_USE_53BYTE_CELL | ATMSAR_SET_PTI);
if (!dev_data->atmsar_vcc) { if (!vcc->dev_data) {
kfree (dev_data); MOD_DEC_USE_COUNT;
return -ENOMEM; /* this is the only reason atmsar_open can fail... */ return -ENOMEM; /* this is the only reason atmsar_open can fail... */
} }
...@@ -552,10 +778,8 @@ static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci) ...@@ -552,10 +778,8 @@ static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci)
set_bit (ATM_VF_ADDR, &vcc->flags); set_bit (ATM_VF_ADDR, &vcc->flags);
set_bit (ATM_VF_PARTIAL, &vcc->flags); set_bit (ATM_VF_PARTIAL, &vcc->flags);
set_bit (ATM_VF_READY, &vcc->flags); set_bit (ATM_VF_READY, &vcc->flags);
vcc->dev_data = dev_data;
vcc->alloc_tx = udsl_atm_alloc_tx;
dev_data->atmsar_vcc->mtu = UDSL_MAX_AAL5_MRU; ((struct atmsar_vcc_data *)vcc->dev_data)->mtu = UDSL_MAX_AAL5_MRU;
if (instance->firmware_loaded) if (instance->firmware_loaded)
udsl_fire_receivers (instance); udsl_fire_receivers (instance);
...@@ -566,22 +790,20 @@ static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci) ...@@ -566,22 +790,20 @@ static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci)
static void udsl_atm_close (struct atm_vcc *vcc) static void udsl_atm_close (struct atm_vcc *vcc)
{ {
struct udsl_atm_dev_data *dev_data = vcc->dev_data;
struct udsl_instance_data *instance = vcc->dev->dev_data; struct udsl_instance_data *instance = vcc->dev->dev_data;
PDEBUG ("udsl_atm_close called\n"); PDEBUG ("udsl_atm_close called\n");
if (!dev_data || !instance) { if (!instance) {
PDEBUG ("NULL data!\n"); PDEBUG ("NULL instance!\n");
return; return;
} }
/* freeing resources */ /* freeing resources */
/* cancel all sends on this vcc */ /* cancel all sends on this vcc */
udsl_usb_cancelsends (instance, vcc); udsl_cancel_send (instance, vcc);
atmsar_close (&(instance->atmsar_vcc_list), dev_data->atmsar_vcc); atmsar_close (&(instance->atmsar_vcc_list), vcc->dev_data);
kfree (dev_data);
vcc->dev_data = NULL; vcc->dev_data = NULL;
clear_bit (ATM_VF_PARTIAL, &vcc->flags); clear_bit (ATM_VF_PARTIAL, &vcc->flags);
...@@ -611,131 +833,6 @@ static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg) ...@@ -611,131 +833,6 @@ static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg)
** USB ** ** USB **
************/ ************/
/***************************************************************************
*
* usb data functions
*
****************************************************************************/
struct udsl_cb {
struct atm_vcc *vcc;
};
static void udsl_usb_send_data_complete (struct urb *urb, struct pt_regs *regs)
{
struct udsl_usb_send_data_context *ctx = urb->context;
struct udsl_instance_data *instance = ctx->instance;
int err;
PDEBUG ("udsl_usb_send_data_completion (vcc = %p, skb = %p, status %d)\n", ctx->vcc,
ctx->skb, urb->status);
ctx->vcc->pop (ctx->vcc, ctx->skb);
if (!(ctx->skb = skb_dequeue (&(instance->sndqueue))))
return;
/* submit next skb */
ctx->vcc = ((struct udsl_cb *) (ctx->skb->cb))->vcc;
usb_fill_bulk_urb (urb,
instance->usb_dev,
usb_sndbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_OUT),
(unsigned char *) ctx->skb->data,
ctx->skb->len, udsl_usb_send_data_complete, ctx);
err = usb_submit_urb (urb, GFP_ATOMIC);
PDEBUG ("udsl_usb_send_data_completion (send packet %p with length %d), retval = %d\n",
ctx->skb, ctx->skb->len, err);
}
static int udsl_usb_cancelsends (struct udsl_instance_data *instance, struct atm_vcc *vcc)
{
int i;
for (i = 0; i < UDSL_NUMBER_SND_URBS; i++) {
if (!instance->send_ctx[i].skb)
continue;
if (instance->send_ctx[i].vcc == vcc) {
usb_unlink_urb (instance->send_ctx[i].urb);
usb_free_urb (instance->send_ctx[i].urb);
instance->send_ctx[i].vcc->pop (instance->send_ctx[i].vcc,
instance->send_ctx[i].skb);
instance->send_ctx[i].skb = NULL;
}
}
return 0;
}
/**** send ******/
static int udsl_usb_send_data (struct udsl_instance_data *instance, struct atm_vcc *vcc,
struct sk_buff *skb)
{
int err, i;
struct urb *urb;
unsigned long flags;
PDEBUG ("udsl_usb_send_data entered, sending packet %p with length %d\n", skb, skb->len);
PACKETDEBUG (skb->data, skb->len);
spin_lock_irqsave (&instance->sndqueue.lock, flags);
((struct udsl_cb *) skb->cb)->vcc = vcc;
/* we are already queueing */
if (!skb_queue_empty (&instance->sndqueue)) {
__skb_queue_tail (&instance->sndqueue, skb);
spin_unlock_irqrestore (&instance->sndqueue.lock, flags);
PDEBUG ("udsl_usb_send_data: already queing, skb (0x%p) queued\n", skb);
return 0;
}
for (i = 0; i < UDSL_NUMBER_SND_URBS; i++)
if (instance->send_ctx[i].skb == NULL)
break;
/* we must start queueing */
if (i == UDSL_NUMBER_SND_URBS) {
__skb_queue_tail (&instance->sndqueue, skb);
spin_unlock_irqrestore (&instance->sndqueue.lock, flags);
PDEBUG ("udsl_usb_send_data: skb (0x%p) queued\n", skb);
return 0;
}
/* init context */
urb = instance->send_ctx[i].urb;
instance->send_ctx[i].skb = skb;
instance->send_ctx[i].vcc = vcc;
instance->send_ctx[i].instance = instance;
spin_unlock_irqrestore (&instance->sndqueue.lock, flags);
/* submit packet */
usb_fill_bulk_urb (urb,
instance->usb_dev,
usb_sndbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_OUT),
(unsigned char *) skb->data,
skb->len,
udsl_usb_send_data_complete, &(instance->send_ctx[i])
);
err = usb_submit_urb (urb, GFP_KERNEL);
if (err != 0)
skb_unlink (skb);
PDEBUG ("udsl_usb_send_data done (retval = %d)\n", err);
return err;
}
/***************************************************************************
*
* usb driver entries
*
****************************************************************************/
static int udsl_usb_ioctl (struct usb_interface *intf, unsigned int code, void *user_data) static int udsl_usb_ioctl (struct usb_interface *intf, unsigned int code, void *user_data)
{ {
struct udsl_instance_data *instance = usb_get_intfdata (intf); struct udsl_instance_data *instance = usb_get_intfdata (intf);
...@@ -752,7 +849,7 @@ static int udsl_usb_ioctl (struct usb_interface *intf, unsigned int code, void * ...@@ -752,7 +849,7 @@ static int udsl_usb_ioctl (struct usb_interface *intf, unsigned int code, void *
instance->atm_dev->signal = ATM_PHY_SIG_FOUND; instance->atm_dev->signal = ATM_PHY_SIG_FOUND;
down (&instance->serialize); /* vs self */ down (&instance->serialize); /* vs self */
if (!instance->firmware_loaded) { if (!instance->firmware_loaded) {
usb_set_interface (instance->usb_dev, 1, 2); usb_set_interface (instance->usb_dev, 1, 1);
instance->firmware_loaded = 1; instance->firmware_loaded = 1;
} }
up (&instance->serialize); up (&instance->serialize);
...@@ -773,7 +870,7 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i ...@@ -773,7 +870,7 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i
struct udsl_instance_data *instance; struct udsl_instance_data *instance;
unsigned char mac_str [13]; unsigned char mac_str [13];
unsigned char mac [6]; unsigned char mac [6];
int i, err; int i;
PDEBUG ("Trying device with Vendor=0x%x, Product=0x%x, ifnum %d\n", PDEBUG ("Trying device with Vendor=0x%x, Product=0x%x, ifnum %d\n",
dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum); dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum);
...@@ -788,8 +885,7 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i ...@@ -788,8 +885,7 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i
/* instance init */ /* instance init */
if (!(instance = kmalloc (sizeof (struct udsl_instance_data), GFP_KERNEL))) { if (!(instance = kmalloc (sizeof (struct udsl_instance_data), GFP_KERNEL))) {
PDEBUG ("No memory for Instance data!\n"); PDEBUG ("No memory for Instance data!\n");
err = -ENOMEM; return -ENOMEM;
goto fail_instance;
} }
memset (instance, 0, sizeof (struct udsl_instance_data)); memset (instance, 0, sizeof (struct udsl_instance_data));
...@@ -808,46 +904,63 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i ...@@ -808,46 +904,63 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i
skb_queue_head_init (&instance->sndqueue); skb_queue_head_init (&instance->sndqueue);
/* receive urb init */ spin_lock_init (&instance->send_lock);
INIT_LIST_HEAD (&instance->spare_senders);
INIT_LIST_HEAD (&instance->spare_buffers);
tasklet_init (&instance->send_tasklet, udsl_process_send, (unsigned long) instance);
INIT_LIST_HEAD (&instance->filled_buffers);
/* receive init */
for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++) { for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++) {
struct udsl_receiver *rcv = &(instance->all_receivers[i]); struct udsl_receiver *rcv = &(instance->all_receivers[i]);
if (!(rcv->skb = dev_alloc_skb (UDSL_RECEIVE_BUFFER_SIZE))) { if (!(rcv->skb = dev_alloc_skb (UDSL_RCV_BUFFER_SIZE * ATM_CELL_SIZE))) {
PDEBUG ("No memory for skb %d!\n", i); PDEBUG ("No memory for skb %d!\n", i);
err = -ENOMEM; goto fail;
goto fail_urbs;
} }
if (!(rcv->urb = usb_alloc_urb (0, GFP_KERNEL))) { if (!(rcv->urb = usb_alloc_urb (0, GFP_KERNEL))) {
PDEBUG ("No memory for receive urb %d!\n", i); PDEBUG ("No memory for receive urb %d!\n", i);
err = -ENOMEM; goto fail;
goto fail_urbs;
} }
rcv->instance = instance; rcv->instance = instance;
list_add (&rcv->list, &instance->spare_receivers); list_add (&rcv->list, &instance->spare_receivers);
PDEBUG ("skb->truesize = %d (asked for %d)\n", rcv->skb->truesize, UDSL_RECEIVE_BUFFER_SIZE); PDEBUG ("skb->truesize = %d (asked for %d)\n", rcv->skb->truesize, UDSL_RCV_BUFFER_SIZE * ATM_CELL_SIZE);
} }
/* send init */
for (i = 0; i < UDSL_NUMBER_SND_URBS; i++) { for (i = 0; i < UDSL_NUMBER_SND_URBS; i++) {
struct udsl_usb_send_data_context *snd = &(instance->send_ctx[i]); struct udsl_sender *snd = &(instance->all_senders[i]);
if (!(snd->urb = usb_alloc_urb (0, GFP_KERNEL))) { if (!(snd->urb = usb_alloc_urb (0, GFP_KERNEL))) {
PDEBUG ("No memory for send urb %d!\n", i); PDEBUG ("No memory for send urb %d!\n", i);
err = -ENOMEM; goto fail;
goto fail_urbs;
} }
snd->instance = instance; snd->instance = instance;
list_add (&snd->list, &instance->spare_senders);
}
for (i = 0; i < UDSL_NUMBER_SND_BUFS; i++) {
struct udsl_send_buffer *buf = &(instance->all_buffers[i]);
if (!(buf->base = kmalloc (UDSL_SND_BUFFER_SIZE * ATM_CELL_SIZE, GFP_KERNEL))) {
PDEBUG ("No memory for send buffer %d!\n", i);
goto fail;
}
list_add (&buf->list, &instance->spare_buffers);
} }
/* atm init */ /* atm init */
if (!(instance->atm_dev = atm_dev_register (udsl_driver_name, &udsl_atm_devops, -1, 0))) { if (!(instance->atm_dev = atm_dev_register (udsl_driver_name, &udsl_atm_devops, -1, 0))) {
PDEBUG ("failed to register ATM device!\n"); PDEBUG ("failed to register ATM device!\n");
err = -ENOMEM; goto fail;
goto fail_atm;
} }
instance->atm_dev->ci_range.vpi_bits = ATM_CI_MAX; instance->atm_dev->ci_range.vpi_bits = ATM_CI_MAX;
...@@ -874,27 +987,25 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i ...@@ -874,27 +987,25 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i
return 0; return 0;
fail_atm: fail:
fail_urbs: for (i = 0; i < UDSL_NUMBER_SND_BUFS; i++)
for (i = 0; i < UDSL_NUMBER_SND_URBS; i++) { kfree (instance->all_buffers[i].base);
struct udsl_usb_send_data_context *snd = &(instance->send_ctx[i]);
if (snd->urb) for (i = 0; i < UDSL_NUMBER_SND_URBS; i++)
usb_free_urb (snd->urb); usb_free_urb (instance->all_senders[i].urb);
}
for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++) { for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++) {
struct udsl_receiver *rcv = &(instance->all_receivers[i]); struct udsl_receiver *rcv = &(instance->all_receivers[i]);
usb_free_urb (rcv->urb);
if (rcv->skb) if (rcv->skb)
kfree_skb (rcv->skb); kfree_skb (rcv->skb);
if (rcv->urb)
usb_free_urb (rcv->urb);
} }
kfree (instance); kfree (instance);
fail_instance:
return err; return -ENOMEM;
} }
static void udsl_usb_disconnect (struct usb_interface *intf) static void udsl_usb_disconnect (struct usb_interface *intf)
...@@ -903,7 +1014,7 @@ static void udsl_usb_disconnect (struct usb_interface *intf) ...@@ -903,7 +1014,7 @@ static void udsl_usb_disconnect (struct usb_interface *intf)
struct list_head *pos; struct list_head *pos;
unsigned long flags; unsigned long flags;
unsigned int count = 0; unsigned int count = 0;
int i; int result, i;
PDEBUG ("disconnecting\n"); PDEBUG ("disconnecting\n");
...@@ -916,8 +1027,9 @@ static void udsl_usb_disconnect (struct usb_interface *intf) ...@@ -916,8 +1027,9 @@ static void udsl_usb_disconnect (struct usb_interface *intf)
tasklet_disable (&instance->receive_tasklet); tasklet_disable (&instance->receive_tasklet);
/* receive finalize */
down (&instance->serialize); /* vs udsl_fire_receivers */ down (&instance->serialize); /* vs udsl_fire_receivers */
/* no need to take the spinlock - receive_tasklet is not running */ /* no need to take the spinlock */
list_for_each (pos, &instance->spare_receivers) list_for_each (pos, &instance->spare_receivers)
if (++count > UDSL_NUMBER_RCV_URBS) if (++count > UDSL_NUMBER_RCV_URBS)
panic (__FILE__ ": memory corruption detected at line %d!\n", __LINE__); panic (__FILE__ ": memory corruption detected at line %d!\n", __LINE__);
...@@ -929,7 +1041,8 @@ static void udsl_usb_disconnect (struct usb_interface *intf) ...@@ -929,7 +1041,8 @@ static void udsl_usb_disconnect (struct usb_interface *intf)
count = UDSL_NUMBER_RCV_URBS - count; count = UDSL_NUMBER_RCV_URBS - count;
for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++) for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++)
usb_unlink_urb (instance->all_receivers[i].urb); if ((result = usb_unlink_urb (instance->all_receivers[i].urb)) < 0)
PDEBUG ("udsl_usb_disconnect: usb_unlink_urb on receive urb %d returned %d\n", i, result);
/* wait for completion handlers to finish */ /* wait for completion handlers to finish */
do { do {
...@@ -946,12 +1059,11 @@ static void udsl_usb_disconnect (struct usb_interface *intf) ...@@ -946,12 +1059,11 @@ static void udsl_usb_disconnect (struct usb_interface *intf)
if (completed == count) if (completed == count)
break; break;
/* not all urbs completed */
yield (); yield ();
} while (1); } while (1);
PDEBUG ("udsl_usb_disconnect: flushing %u completed receivers\n", count); PDEBUG ("udsl_usb_disconnect: flushing\n");
/* no need to take the spinlock - no completion handlers running */ /* no need to take the spinlock */
INIT_LIST_HEAD (&instance->completed_receivers); INIT_LIST_HEAD (&instance->completed_receivers);
tasklet_enable (&instance->receive_tasklet); tasklet_enable (&instance->receive_tasklet);
...@@ -965,25 +1077,48 @@ static void udsl_usb_disconnect (struct usb_interface *intf) ...@@ -965,25 +1077,48 @@ static void udsl_usb_disconnect (struct usb_interface *intf)
kfree_skb (rcv->skb); kfree_skb (rcv->skb);
} }
for (i = 0; i < UDSL_NUMBER_SND_URBS; i++) { /* send finalize */
struct udsl_usb_send_data_context *ctx = &(instance->send_ctx[i]); tasklet_disable (&instance->send_tasklet);
usb_unlink_urb (ctx->urb); for (i = 0; i < UDSL_NUMBER_SND_URBS; i++)
if ((result = usb_unlink_urb (instance->all_senders[i].urb)) < 0)
PDEBUG ("udsl_usb_disconnect: usb_unlink_urb on send urb %d returned %d\n", i, result);
/* wait for completion handlers to finish */
do {
count = 0;
spin_lock_irqsave (&instance->send_lock, flags);
list_for_each (pos, &instance->spare_senders)
if (++count > UDSL_NUMBER_SND_URBS)
panic (__FILE__ ": memory corruption detected at line %d!\n", __LINE__);
spin_unlock_irqrestore (&instance->send_lock, flags);
if (ctx->skb) PDEBUG ("udsl_usb_disconnect: found %u spare senders\n", count);
ctx->vcc->pop (ctx->vcc, ctx->skb);
ctx->skb = NULL;
usb_free_urb (ctx->urb); if (count == UDSL_NUMBER_SND_URBS)
break;
} yield ();
} while (1);
PDEBUG ("udsl_usb_disconnect: flushing\n");
/* no need to take the spinlock */
INIT_LIST_HEAD (&instance->spare_senders);
INIT_LIST_HEAD (&instance->spare_buffers);
instance->current_buffer = NULL;
/* removing atm device */ tasklet_enable (&instance->send_tasklet);
if (instance->atm_dev)
udsl_atm_stopdevice (instance);
kfree (instance); PDEBUG ("udsl_usb_disconnect: freeing senders\n");
for (i = 0; i < UDSL_NUMBER_SND_URBS; i++)
usb_free_urb (instance->all_senders[i].urb);
PDEBUG ("udsl_usb_disconnect: freeing buffers\n");
for (i = 0; i < UDSL_NUMBER_SND_BUFS; i++)
kfree (instance->all_buffers[i].base);
/* atm finalize */
shutdown_atm_dev (instance->atm_dev);
} }
...@@ -995,8 +1130,15 @@ static void udsl_usb_disconnect (struct usb_interface *intf) ...@@ -995,8 +1130,15 @@ static void udsl_usb_disconnect (struct usb_interface *intf)
static int __init udsl_usb_init (void) static int __init udsl_usb_init (void)
{ {
struct sk_buff *skb; /* dummy for sizeof */
PDEBUG ("udsl_usb_init: driver version " DRIVER_VERSION "\n"); PDEBUG ("udsl_usb_init: driver version " DRIVER_VERSION "\n");
if (sizeof (struct udsl_control) > sizeof (skb->cb)) {
printk (KERN_ERR __FILE__ ": unusable with this kernel!\n");
return -EIO;
}
return usb_register (&udsl_usb_driver); return usb_register (&udsl_usb_driver);
} }
......
...@@ -130,6 +130,7 @@ static struct usb_device_id usb_klsi_table[] = { ...@@ -130,6 +130,7 @@ static struct usb_device_id usb_klsi_table[] = {
{ USB_DEVICE(0x03e8, 0x0008) }, /* AOX Endpoints USB Ethernet */ { USB_DEVICE(0x03e8, 0x0008) }, /* AOX Endpoints USB Ethernet */
{ USB_DEVICE(0x04bb, 0x0901) }, /* I-O DATA USB-ET/T */ { USB_DEVICE(0x04bb, 0x0901) }, /* I-O DATA USB-ET/T */
{ USB_DEVICE(0x0506, 0x03e8) }, /* 3Com 3C19250 */ { USB_DEVICE(0x0506, 0x03e8) }, /* 3Com 3C19250 */
{ USB_DEVICE(0x0506, 0x11f8) }, /* 3Com 3C460 */
{ USB_DEVICE(0x0557, 0x2002) }, /* ATEN USB Ethernet */ { USB_DEVICE(0x0557, 0x2002) }, /* ATEN USB Ethernet */
{ USB_DEVICE(0x0557, 0x4000) }, /* D-Link DSB-650C */ { USB_DEVICE(0x0557, 0x4000) }, /* D-Link DSB-650C */
{ USB_DEVICE(0x0565, 0x0002) }, /* Peracom Enet */ { USB_DEVICE(0x0565, 0x0002) }, /* Peracom Enet */
...@@ -712,7 +713,7 @@ static void kaweth_usb_transmit_complete(struct urb *urb, struct pt_regs *regs) ...@@ -712,7 +713,7 @@ static void kaweth_usb_transmit_complete(struct urb *urb, struct pt_regs *regs)
static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
{ {
struct kaweth_device *kaweth = net->priv; struct kaweth_device *kaweth = net->priv;
char *private_header; u16 *private_header;
int res; int res;
...@@ -744,7 +745,7 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) ...@@ -744,7 +745,7 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
} }
private_header = __skb_push(skb, 2); private_header = __skb_push(skb, 2);
*private_header = cpu_to_le16(skb->len); *private_header = cpu_to_le16(skb->len-2);
kaweth->tx_skb = skb; kaweth->tx_skb = skb;
usb_fill_bulk_urb(kaweth->tx_urb, usb_fill_bulk_urb(kaweth->tx_urb,
......
...@@ -133,6 +133,7 @@ struct usb_eth_dev { ...@@ -133,6 +133,7 @@ struct usb_eth_dev {
#define VENDOR_LANEED 0x056e #define VENDOR_LANEED 0x056e
#define VENDOR_LINKSYS 0x066b #define VENDOR_LINKSYS 0x066b
#define VENDOR_MELCO 0x0411 #define VENDOR_MELCO 0x0411
#define VENDOR_MOBILITY 0x1342
#define VENDOR_NETGEAR 0x0846 #define VENDOR_NETGEAR 0x0846
#define VENDOR_SMARTBRIDGES 0x08d1 #define VENDOR_SMARTBRIDGES 0x08d1
#define VENDOR_SMC 0x0707 #define VENDOR_SMC 0x0707
...@@ -167,7 +168,7 @@ PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x200c, ...@@ -167,7 +168,7 @@ PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x200c,
PEGASUS_DEV( "Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046, PEGASUS_DEV( "Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046,
DEFAULT_GPIO_RESET ) DEFAULT_GPIO_RESET )
PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046, PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046,
DEFAULT_GPIO_RESET ) DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet", PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet",
VENDOR_ADMTEK, 0x8511, VENDOR_ADMTEK, 0x8511,
DEFAULT_GPIO_RESET | PEGASUS_II ) DEFAULT_GPIO_RESET | PEGASUS_II )
...@@ -215,6 +216,8 @@ PEGASUS_DEV( "D-Link DSB-650", VENDOR_DLINK, 0xabc1, ...@@ -215,6 +216,8 @@ PEGASUS_DEV( "D-Link DSB-650", VENDOR_DLINK, 0xabc1,
DEFAULT_GPIO_RESET ) DEFAULT_GPIO_RESET )
PEGASUS_DEV( "GOLDPFEIL USB Adapter", VENDOR_ELCON, 0x0002, PEGASUS_DEV( "GOLDPFEIL USB Adapter", VENDOR_ELCON, 0x0002,
DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA ) DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA )
PEGASUS_DEV( "EasiDock Ethernet", VENDOR_MOBILITY, 0x0304,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "Elsa Micolink USB2Ethernet", VENDOR_ELSA, 0x3000, PEGASUS_DEV( "Elsa Micolink USB2Ethernet", VENDOR_ELSA, 0x3000,
DEFAULT_GPIO_RESET ) DEFAULT_GPIO_RESET )
PEGASUS_DEV( "Hawking UF100 10/100 Ethernet", VENDOR_HAWKING, 0x400c, PEGASUS_DEV( "Hawking UF100 10/100 Ethernet", VENDOR_HAWKING, 0x400c,
......
...@@ -297,10 +297,14 @@ config USB_SERIAL_KEYSPAN_USA19W ...@@ -297,10 +297,14 @@ config USB_SERIAL_KEYSPAN_USA19W
config USB_SERIAL_KEYSPAN_USA19QW config USB_SERIAL_KEYSPAN_USA19QW
bool "USB Keyspan USA-19QW Firmware" bool "USB Keyspan USA-19QW Firmware"
depends on USB_SERIAL_KEYSPAN depends on USB_SERIAL_KEYSPAN
help
Say Y here to include firmware for the USA-19QW converter.
config USB_SERIAL_KEYSPAN_USA19QI config USB_SERIAL_KEYSPAN_USA19QI
bool "USB Keyspan USA-19QI Firmware" bool "USB Keyspan USA-19QI Firmware"
depends on USB_SERIAL_KEYSPAN depends on USB_SERIAL_KEYSPAN
help
Say Y here to include firmware for the USA-19QI converter.
config USB_SERIAL_KEYSPAN_USA49W config USB_SERIAL_KEYSPAN_USA49W
bool "USB Keyspan USA-49W Firmware" bool "USB Keyspan USA-49W Firmware"
......
...@@ -141,7 +141,6 @@ static int __init usb_console_setup(struct console *co, char *options) ...@@ -141,7 +141,6 @@ static int __init usb_console_setup(struct console *co, char *options)
} }
port = &serial->port[0]; port = &serial->port[0];
down (&port->sem);
port->tty = NULL; port->tty = NULL;
info->port = port; info->port = port;
...@@ -158,8 +157,6 @@ static int __init usb_console_setup(struct console *co, char *options) ...@@ -158,8 +157,6 @@ static int __init usb_console_setup(struct console *co, char *options)
port->open_count = 0; port->open_count = 0;
} }
up (&port->sem);
if (retval) { if (retval) {
err ("could not open USB console port"); err ("could not open USB console port");
return retval; return retval;
...@@ -208,8 +205,6 @@ static void usb_console_write(struct console *co, const char *buf, unsigned coun ...@@ -208,8 +205,6 @@ static void usb_console_write(struct console *co, const char *buf, unsigned coun
if (count == 0) if (count == 0)
return; return;
down (&port->sem);
dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count); dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
if (!port->open_count) { if (!port->open_count) {
...@@ -224,7 +219,6 @@ static void usb_console_write(struct console *co, const char *buf, unsigned coun ...@@ -224,7 +219,6 @@ static void usb_console_write(struct console *co, const char *buf, unsigned coun
retval = usb_serial_generic_write(port, 0, buf, count); retval = usb_serial_generic_write(port, 0, buf, count);
exit: exit:
up (&port->sem);
dbg("%s - return value (if we had one): %d", __FUNCTION__, retval); dbg("%s - return value (if we had one): %d", __FUNCTION__, retval);
} }
......
...@@ -391,7 +391,11 @@ static LIST_HEAD(usb_serial_driver_list); ...@@ -391,7 +391,11 @@ static LIST_HEAD(usb_serial_driver_list);
struct usb_serial *usb_serial_get_by_minor (unsigned int minor) struct usb_serial *usb_serial_get_by_minor (unsigned int minor)
{ {
return serial_table[minor]; struct usb_serial *serial = serial_table[minor];
if (serial)
kobject_get (&serial->kobj);
return serial;
} }
static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_ports, unsigned int *minor) static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_ports, unsigned int *minor)
...@@ -468,7 +472,6 @@ static int serial_open (struct tty_struct *tty, struct file * filp) ...@@ -468,7 +472,6 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
port = &serial->port[portNumber]; port = &serial->port[portNumber];
tty->driver_data = port; tty->driver_data = port;
down (&port->sem);
port->tty = tty; port->tty = tty;
/* lock this module before we call it, /* lock this module before we call it,
...@@ -492,8 +495,6 @@ static int serial_open (struct tty_struct *tty, struct file * filp) ...@@ -492,8 +495,6 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
} }
} }
bailout: bailout:
up (&port->sem);
return retval; return retval;
} }
...@@ -516,6 +517,7 @@ static void __serial_close(struct usb_serial_port *port, struct file *filp) ...@@ -516,6 +517,7 @@ static void __serial_close(struct usb_serial_port *port, struct file *filp)
} }
module_put(port->serial->type->owner); module_put(port->serial->type->owner);
kobject_put(&port->serial->kobj);
} }
static void serial_close(struct tty_struct *tty, struct file * filp) static void serial_close(struct tty_struct *tty, struct file * filp)
...@@ -526,16 +528,12 @@ static void serial_close(struct tty_struct *tty, struct file * filp) ...@@ -526,16 +528,12 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
if (!serial) if (!serial)
return; return;
down (&port->sem);
dbg("%s - port %d", __FUNCTION__, port->number); dbg("%s - port %d", __FUNCTION__, port->number);
/* if disconnect beat us to the punch here, there's nothing to do */ /* if disconnect beat us to the punch here, there's nothing to do */
if (tty->driver_data) { if (tty->driver_data) {
__serial_close(port, filp); __serial_close(port, filp);
} }
up (&port->sem);
} }
static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count) static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
...@@ -547,8 +545,6 @@ static int serial_write (struct tty_struct * tty, int from_user, const unsigned ...@@ -547,8 +545,6 @@ static int serial_write (struct tty_struct * tty, int from_user, const unsigned
if (!serial) if (!serial)
return -ENODEV; return -ENODEV;
down (&port->sem);
dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count); dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
if (!port->open_count) { if (!port->open_count) {
...@@ -563,7 +559,6 @@ static int serial_write (struct tty_struct * tty, int from_user, const unsigned ...@@ -563,7 +559,6 @@ static int serial_write (struct tty_struct * tty, int from_user, const unsigned
retval = usb_serial_generic_write(port, from_user, buf, count); retval = usb_serial_generic_write(port, from_user, buf, count);
exit: exit:
up (&port->sem);
return retval; return retval;
} }
...@@ -576,8 +571,6 @@ static int serial_write_room (struct tty_struct *tty) ...@@ -576,8 +571,6 @@ static int serial_write_room (struct tty_struct *tty)
if (!serial) if (!serial)
return -ENODEV; return -ENODEV;
down (&port->sem);
dbg("%s - port %d", __FUNCTION__, port->number); dbg("%s - port %d", __FUNCTION__, port->number);
if (!port->open_count) { if (!port->open_count) {
...@@ -592,7 +585,6 @@ static int serial_write_room (struct tty_struct *tty) ...@@ -592,7 +585,6 @@ static int serial_write_room (struct tty_struct *tty)
retval = usb_serial_generic_write_room(port); retval = usb_serial_generic_write_room(port);
exit: exit:
up (&port->sem);
return retval; return retval;
} }
...@@ -605,8 +597,6 @@ static int serial_chars_in_buffer (struct tty_struct *tty) ...@@ -605,8 +597,6 @@ static int serial_chars_in_buffer (struct tty_struct *tty)
if (!serial) if (!serial)
return -ENODEV; return -ENODEV;
down (&port->sem);
dbg("%s = port %d", __FUNCTION__, port->number); dbg("%s = port %d", __FUNCTION__, port->number);
if (!port->open_count) { if (!port->open_count) {
...@@ -621,7 +611,6 @@ static int serial_chars_in_buffer (struct tty_struct *tty) ...@@ -621,7 +611,6 @@ static int serial_chars_in_buffer (struct tty_struct *tty)
retval = usb_serial_generic_chars_in_buffer(port); retval = usb_serial_generic_chars_in_buffer(port);
exit: exit:
up (&port->sem);
return retval; return retval;
} }
...@@ -633,8 +622,6 @@ static void serial_throttle (struct tty_struct * tty) ...@@ -633,8 +622,6 @@ static void serial_throttle (struct tty_struct * tty)
if (!serial) if (!serial)
return; return;
down (&port->sem);
dbg("%s - port %d", __FUNCTION__, port->number); dbg("%s - port %d", __FUNCTION__, port->number);
if (!port->open_count) { if (!port->open_count) {
...@@ -647,7 +634,6 @@ static void serial_throttle (struct tty_struct * tty) ...@@ -647,7 +634,6 @@ static void serial_throttle (struct tty_struct * tty)
serial->type->throttle(port); serial->type->throttle(port);
exit: exit:
up (&port->sem);
} }
static void serial_unthrottle (struct tty_struct * tty) static void serial_unthrottle (struct tty_struct * tty)
...@@ -658,8 +644,6 @@ static void serial_unthrottle (struct tty_struct * tty) ...@@ -658,8 +644,6 @@ static void serial_unthrottle (struct tty_struct * tty)
if (!serial) if (!serial)
return; return;
down (&port->sem);
dbg("%s - port %d", __FUNCTION__, port->number); dbg("%s - port %d", __FUNCTION__, port->number);
if (!port->open_count) { if (!port->open_count) {
...@@ -672,7 +656,6 @@ static void serial_unthrottle (struct tty_struct * tty) ...@@ -672,7 +656,6 @@ static void serial_unthrottle (struct tty_struct * tty)
serial->type->unthrottle(port); serial->type->unthrottle(port);
exit: exit:
up (&port->sem);
} }
static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
...@@ -684,8 +667,6 @@ static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned in ...@@ -684,8 +667,6 @@ static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned in
if (!serial) if (!serial)
return -ENODEV; return -ENODEV;
down (&port->sem);
dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd); dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);
if (!port->open_count) { if (!port->open_count) {
...@@ -700,7 +681,6 @@ static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned in ...@@ -700,7 +681,6 @@ static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned in
retval = -ENOIOCTLCMD; retval = -ENOIOCTLCMD;
exit: exit:
up (&port->sem);
return retval; return retval;
} }
...@@ -712,8 +692,6 @@ static void serial_set_termios (struct tty_struct *tty, struct termios * old) ...@@ -712,8 +692,6 @@ static void serial_set_termios (struct tty_struct *tty, struct termios * old)
if (!serial) if (!serial)
return; return;
down (&port->sem);
dbg("%s - port %d", __FUNCTION__, port->number); dbg("%s - port %d", __FUNCTION__, port->number);
if (!port->open_count) { if (!port->open_count) {
...@@ -726,7 +704,6 @@ static void serial_set_termios (struct tty_struct *tty, struct termios * old) ...@@ -726,7 +704,6 @@ static void serial_set_termios (struct tty_struct *tty, struct termios * old)
serial->type->set_termios(port, old); serial->type->set_termios(port, old);
exit: exit:
up (&port->sem);
} }
static void serial_break (struct tty_struct *tty, int break_state) static void serial_break (struct tty_struct *tty, int break_state)
...@@ -737,8 +714,6 @@ static void serial_break (struct tty_struct *tty, int break_state) ...@@ -737,8 +714,6 @@ static void serial_break (struct tty_struct *tty, int break_state)
if (!serial) if (!serial)
return; return;
down (&port->sem);
dbg("%s - port %d", __FUNCTION__, port->number); dbg("%s - port %d", __FUNCTION__, port->number);
if (!port->open_count) { if (!port->open_count) {
...@@ -751,7 +726,6 @@ static void serial_break (struct tty_struct *tty, int break_state) ...@@ -751,7 +726,6 @@ static void serial_break (struct tty_struct *tty, int break_state)
serial->type->break_ctl(port, break_state); serial->type->break_ctl(port, break_state);
exit: exit:
up (&port->sem);
} }
static void serial_shutdown (struct usb_serial *serial) static void serial_shutdown (struct usb_serial *serial)
...@@ -797,6 +771,7 @@ static int serial_read_proc (char *page, char **start, off_t off, int count, int ...@@ -797,6 +771,7 @@ static int serial_read_proc (char *page, char **start, off_t off, int count, int
begin += length; begin += length;
length = 0; length = 0;
} }
kobject_put(&serial->kobj);
} }
*eof = 1; *eof = 1;
done: done:
...@@ -833,6 +808,75 @@ void usb_serial_port_softint(void *private) ...@@ -833,6 +808,75 @@ void usb_serial_port_softint(void *private)
wake_up_interruptible(&tty->write_wait); wake_up_interruptible(&tty->write_wait);
} }
static void destroy_serial (struct kobject *kobj)
{
struct usb_serial *serial;
struct usb_serial_port *port;
int i;
dbg ("%s", __FUNCTION__);
serial = to_usb_serial(kobj);
/* fail all future close/read/write/ioctl/etc calls */
for (i = 0; i < serial->num_ports; ++i) {
port = &serial->port[i];
if (port->tty != NULL) {
port->tty->driver_data = NULL;
while (port->open_count > 0) {
__serial_close(port, NULL);
}
}
}
serial_shutdown (serial);
for (i = 0; i < serial->num_ports; ++i)
device_unregister(&serial->port[i].dev);
for (i = 0; i < serial->num_ports; ++i)
serial->port[i].open_count = 0;
for (i = 0; i < serial->num_bulk_in; ++i) {
port = &serial->port[i];
if (port->read_urb) {
usb_unlink_urb (port->read_urb);
usb_free_urb (port->read_urb);
}
if (port->bulk_in_buffer)
kfree (port->bulk_in_buffer);
}
for (i = 0; i < serial->num_bulk_out; ++i) {
port = &serial->port[i];
if (port->write_urb) {
usb_unlink_urb (port->write_urb);
usb_free_urb (port->write_urb);
}
if (port->bulk_out_buffer)
kfree (port->bulk_out_buffer);
}
for (i = 0; i < serial->num_interrupt_in; ++i) {
port = &serial->port[i];
if (port->interrupt_in_urb) {
usb_unlink_urb (port->interrupt_in_urb);
usb_free_urb (port->interrupt_in_urb);
}
if (port->interrupt_in_buffer)
kfree (port->interrupt_in_buffer);
}
/* return the minor range that this device had */
return_serial (serial);
usb_put_dev(serial->dev);
/* free up any memory that we allocated */
kfree (serial);
}
static struct kobj_type usb_serial_kobj_type = {
.release = destroy_serial,
};
static struct usb_serial * create_serial (struct usb_device *dev, static struct usb_serial * create_serial (struct usb_device *dev,
struct usb_interface *interface, struct usb_interface *interface,
struct usb_serial_device_type *type) struct usb_serial_device_type *type)
...@@ -845,12 +889,16 @@ static struct usb_serial * create_serial (struct usb_device *dev, ...@@ -845,12 +889,16 @@ static struct usb_serial * create_serial (struct usb_device *dev,
return NULL; return NULL;
} }
memset (serial, 0, sizeof(*serial)); memset (serial, 0, sizeof(*serial));
serial->dev = dev; serial->dev = usb_get_dev(dev);
serial->type = type; serial->type = type;
serial->interface = interface; serial->interface = interface;
serial->vendor = dev->descriptor.idVendor; serial->vendor = dev->descriptor.idVendor;
serial->product = dev->descriptor.idProduct; serial->product = dev->descriptor.idProduct;
/* initialize the kobject portion of the usb_device */
kobject_init(&serial->kobj);
serial->kobj.ktype = &usb_serial_kobj_type;
return serial; return serial;
} }
...@@ -1113,7 +1161,6 @@ int usb_serial_probe(struct usb_interface *interface, ...@@ -1113,7 +1161,6 @@ int usb_serial_probe(struct usb_interface *interface,
port->serial = serial; port->serial = serial;
port->magic = USB_SERIAL_PORT_MAGIC; port->magic = USB_SERIAL_PORT_MAGIC;
INIT_WORK(&port->work, usb_serial_port_softint, port); INIT_WORK(&port->work, usb_serial_port_softint, port);
init_MUTEX (&port->sem);
} }
/* if this device type has an attach function, call it */ /* if this device type has an attach function, call it */
...@@ -1189,67 +1236,14 @@ void usb_serial_disconnect(struct usb_interface *interface) ...@@ -1189,67 +1236,14 @@ void usb_serial_disconnect(struct usb_interface *interface)
{ {
struct usb_serial *serial = usb_get_intfdata (interface); struct usb_serial *serial = usb_get_intfdata (interface);
struct device *dev = &interface->dev; struct device *dev = &interface->dev;
struct usb_serial_port *port;
int i;
dbg ("%s", __FUNCTION__); dbg ("%s", __FUNCTION__);
usb_set_intfdata (interface, NULL); usb_set_intfdata (interface, NULL);
if (serial) { if (serial) {
/* fail all future close/read/write/ioctl/etc calls */ /* let the last holder of this object
for (i = 0; i < serial->num_ports; ++i) { * cause it to be cleaned up */
port = &serial->port[i]; kobject_put (&serial->kobj);
down (&port->sem);
if (port->tty != NULL) {
port->tty->driver_data = NULL;
while (port->open_count > 0) {
__serial_close(port, NULL);
}
}
up (&port->sem);
}
serial->dev = NULL;
serial_shutdown (serial);
for (i = 0; i < serial->num_ports; ++i)
device_unregister(&serial->port[i].dev);
for (i = 0; i < serial->num_ports; ++i)
serial->port[i].open_count = 0;
for (i = 0; i < serial->num_bulk_in; ++i) {
port = &serial->port[i];
if (port->read_urb) {
usb_unlink_urb (port->read_urb);
usb_free_urb (port->read_urb);
}
if (port->bulk_in_buffer)
kfree (port->bulk_in_buffer);
}
for (i = 0; i < serial->num_bulk_out; ++i) {
port = &serial->port[i];
if (port->write_urb) {
usb_unlink_urb (port->write_urb);
usb_free_urb (port->write_urb);
}
if (port->bulk_out_buffer)
kfree (port->bulk_out_buffer);
}
for (i = 0; i < serial->num_interrupt_in; ++i) {
port = &serial->port[i];
if (port->interrupt_in_urb) {
usb_unlink_urb (port->interrupt_in_urb);
usb_free_urb (port->interrupt_in_urb);
}
if (port->interrupt_in_buffer)
kfree (port->interrupt_in_buffer);
}
/* return the minor range that this device had */
return_serial (serial);
/* free up any memory that we allocated */
kfree (serial);
} }
dev_info(dev, "device disconnected\n"); dev_info(dev, "device disconnected\n");
} }
......
...@@ -89,7 +89,6 @@ ...@@ -89,7 +89,6 @@
* @write_wait: a wait_queue_head_t used by the port. * @write_wait: a wait_queue_head_t used by the port.
* @work: work queue entry for the line discipline waking up. * @work: work queue entry for the line discipline waking up.
* @open_count: number of times this port has been opened. * @open_count: number of times this port has been opened.
* @sem: struct semaphore used to lock this structure.
* *
* This structure is used by the usb-serial core and drivers for the specific * This structure is used by the usb-serial core and drivers for the specific
* ports of a device. * ports of a device.
...@@ -116,7 +115,6 @@ struct usb_serial_port { ...@@ -116,7 +115,6 @@ struct usb_serial_port {
wait_queue_head_t write_wait; wait_queue_head_t write_wait;
struct work_struct work; struct work_struct work;
int open_count; int open_count;
struct semaphore sem;
struct device dev; struct device dev;
}; };
#define to_usb_serial_port(d) container_of(d, struct usb_serial_port, dev) #define to_usb_serial_port(d) container_of(d, struct usb_serial_port, dev)
...@@ -164,8 +162,10 @@ struct usb_serial { ...@@ -164,8 +162,10 @@ struct usb_serial {
__u16 vendor; __u16 vendor;
__u16 product; __u16 product;
struct usb_serial_port port[MAX_NUM_PORTS]; struct usb_serial_port port[MAX_NUM_PORTS];
struct kobject kobj;
void * private; void * private;
}; };
#define to_usb_serial(d) container_of(d, struct usb_serial, kobj)
#define NUM_DONT_CARE (-1) #define NUM_DONT_CARE (-1)
......
...@@ -314,7 +314,7 @@ static int interpret_urb_result(struct us_data *us, unsigned int pipe, ...@@ -314,7 +314,7 @@ static int interpret_urb_result(struct us_data *us, unsigned int pipe,
return USB_STOR_XFER_ERROR; return USB_STOR_XFER_ERROR;
/* the transfer was cancelled, presumably by an abort */ /* the transfer was cancelled, presumably by an abort */
case -ENODEV: case -ECONNRESET:
US_DEBUGP("-- transfer cancelled\n"); US_DEBUGP("-- transfer cancelled\n");
return USB_STOR_XFER_ERROR; return USB_STOR_XFER_ERROR;
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/device.h> /* for struct device */ #include <linux/device.h> /* for struct device */
#include <linux/fs.h> /* for struct file_operations */ #include <linux/fs.h> /* for struct file_operations */
#include <linux/completion.h> /* for struct completion */ #include <linux/completion.h> /* for struct completion */
#include <linux/sched.h> /* for current && schedule_timeout */
static __inline__ void wait_ms(unsigned int ms) static __inline__ void wait_ms(unsigned int ms)
...@@ -239,6 +240,7 @@ struct usb_device { ...@@ -239,6 +240,7 @@ struct usb_device {
int have_langid; /* whether string_langid is valid yet */ int have_langid; /* whether string_langid is valid yet */
int string_langid; /* language ID for strings */ int string_langid; /* language ID for strings */
int present; /* if device is present or not */
void *hcpriv; /* Host Controller private data */ void *hcpriv; /* Host Controller private data */
......
...@@ -25,7 +25,7 @@ obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate/ ...@@ -25,7 +25,7 @@ obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate/
obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate/ obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate/
include $(TOPDIR)/drivers/net/Makefile.lib include $(TOPDIR)/drivers/net/Makefile.lib
include $(TOPDIR)/drivers/usb/class/Makefile.lib include $(TOPDIR)/drivers/usb/Makefile.lib
include $(TOPDIR)/fs/Makefile.lib include $(TOPDIR)/fs/Makefile.lib
include $(TOPDIR)/net/bluetooth/bnep/Makefile.lib include $(TOPDIR)/net/bluetooth/bnep/Makefile.lib
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment