Commit 7f6cf788 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://linuxusb.bkbits.net/linus-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents c0630ba1 7730f361
......@@ -2746,6 +2746,14 @@ E: wsalamon@tislabs.com
E: wsalamon@nai.com
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
E: gt8134b@prism.gatech.edu
D: Dosemu
......
......@@ -215,6 +215,14 @@ M: Juergen Fischer <fischer@norbit.de>
L: linux-scsi@vger.kernel.org
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
P: Richard Henderson
M: rth@twiddle.net
......
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,
if (!acm->ctrlurb) {
err("out of memory");
kfree(acm);
kfree(buf);
return -ENOMEM;
}
acm->readurb = usb_alloc_urb(0, GFP_KERNEL);
......@@ -613,6 +614,7 @@ static int acm_probe (struct usb_interface *intf,
err("out of memory");
usb_free_urb(acm->ctrlurb);
kfree(acm);
kfree(buf);
return -ENOMEM;
}
acm->writeurb = usb_alloc_urb(0, GFP_KERNEL);
......@@ -621,6 +623,7 @@ static int acm_probe (struct usb_interface *intf,
usb_free_urb(acm->readurb);
usb_free_urb(acm->ctrlurb);
kfree(acm);
kfree(buf);
return -ENOMEM;
}
......
......@@ -219,16 +219,25 @@ static void sg_complete (struct urb *urb, struct pt_regs *regs)
spin_lock_irqsave (&io->lock, flags);
/* 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,
* 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.
*
* 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) {
err ("driver for bus %s dev %s ep %d-%s corrupted data!",
io->dev->bus->bus_name, io->dev->devpath,
if (io->status
&& (io->status != -ECONNRESET
|| 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_pipein (urb->pipe) ? "in" : "out");
usb_pipein (urb->pipe) ? "in" : "out",
urb->status, io->status);
// BUG ();
}
......
......@@ -195,7 +195,7 @@ int usb_submit_urb(struct urb *urb, int mem_flags)
if (!urb || urb->hcpriv || !urb->complete)
return -EINVAL;
if (!(dev = urb->dev) || !dev->bus || dev->devnum <= 0)
if (!(dev = urb->dev) || !dev->present || !dev->bus || dev->devnum <= 0)
return -ENODEV;
if (!(op = dev->bus->op) || !op->submit_urb)
return -ENODEV;
......@@ -376,7 +376,7 @@ int usb_submit_urb(struct urb *urb, int mem_flags)
*/
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);
else
return -ENODEV;
......
......@@ -679,6 +679,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus)
memset(dev, 0, sizeof(*dev));
device_initialize(&dev->dev);
dev->present = 1;
usb_bus_get(bus);
......@@ -854,6 +855,10 @@ void usb_disconnect(struct usb_device **pdev)
}
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 */
/* it hits 0 which could very well be now */
usb_put_dev(dev);
......
......@@ -37,7 +37,7 @@
#include <linux/timer.h>
#include <linux/list.h>
#include <linux/interrupt.h>
#include <linux/reboot.h>
#include <linux/usb.h>
#include <linux/version.h>
......@@ -306,6 +306,19 @@ static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap)
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 */
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
* involved with the root hub.
*/
ehci->reboot_notifier.notifier_call = ehci_reboot;
register_reboot_notifier (&ehci->reboot_notifier);
ehci->hcd.state = USB_STATE_READY;
writel (FLAG_CF, &ehci->regs->configured_flag);
readl (&ehci->regs->command); /* unblock posted write */
......@@ -520,6 +536,7 @@ static void ehci_stop (struct usb_hcd *hcd)
/* let companion controllers work when we aren't */
writel (0, &ehci->regs->configured_flag);
unregister_reboot_notifier (&ehci->reboot_notifier);
remove_debug_files (ehci);
......
......@@ -81,8 +81,10 @@ struct ehci_hcd { /* one per controller */
struct pci_pool *sitd_pool; /* sitd per split iso urb */
struct timer_list watchdog;
struct notifier_block reboot_notifier;
unsigned stamp;
/* irq statistics */
#ifdef EHCI_STATS
struct ehci_stats stats;
# define COUNT(x) do { (x)++; } while (0)
......
......@@ -163,11 +163,10 @@ config USB_POWERMATE
tristate "Griffin PowerMate and Contour Jog support"
depends on USB && INPUT
---help---
Say Y here if you want to use Griffin PowerMate or Contour Jog devices.
These are stainless steel dials which can measure clockwise and
anticlockwise rotation. The dial also acts as a pushbutton. The base
contains an LED which can be instructed to pulse or to switch to a
particular intensity.
Say Y here if you want to use Griffin PowerMate or Contour Jog devices.
These are aluminum dials which can measure clockwise and anticlockwise
rotation. The dial also acts as a pushbutton. The base contains an LED
which can be instructed to pulse or to switch to a particular intensity.
You can download userspace tools from http://sowerbutts.com/powermate/
......
......@@ -355,7 +355,7 @@ static struct usb_device_id usb_kbd_id_table [] = {
MODULE_DEVICE_TABLE (usb, usb_kbd_id_table);
static struct usb_driver usb_kbd_driver = {
.name = "keyboard",
.name = "usbkbd",
.probe = usb_kbd_probe,
.disconnect = usb_kbd_disconnect,
.id_table = usb_kbd_id_table,
......
......@@ -238,7 +238,7 @@ static struct usb_device_id usb_mouse_id_table [] = {
MODULE_DEVICE_TABLE (usb, usb_mouse_id_table);
static struct usb_driver usb_mouse_driver = {
.name = "usb_mouse",
.name = "usbmouse",
.probe = usb_mouse_probe,
.disconnect = usb_mouse_disconnect,
.id_table = usb_mouse_id_table,
......
/*
* 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
* Many improvements by Bret Wallach <bwallac1@san.rr.com>
* Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
......@@ -60,7 +60,7 @@
/*
* 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 DRIVER_AUTHOR "Mark McClelland <mark@alpha.dyndns.org> & Bret Wallach \
& Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \
......@@ -137,7 +137,7 @@ MODULE_PARM_DESC(snapshot, "Enable snapshot mode");
MODULE_PARM(cams, "i");
MODULE_PARM_DESC(cams, "Number of simultaneous cameras");
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_DESC(testpat,
"Replace image with vertical bar testpattern (only partially working)");
......@@ -1349,6 +1349,13 @@ ov51x_restart(struct usb_ov511 *ov)
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 */
static void
ov51x_clear_snapshot(struct usb_ov511 *ov)
......@@ -2121,7 +2128,7 @@ sensor_get_exposure(struct usb_ov511 *ov, unsigned char *val)
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(+) */
static void
......@@ -2486,8 +2493,6 @@ mode_init_ov_sensor_regs(struct usb_ov511 *ov, int width, int height,
/******** Clock programming ********/
// FIXME: Test this with OV6630
/* The OV6620 needs special handling. This prevents the
* severe banding that normally occurs */
if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630)
......@@ -2995,6 +3000,7 @@ ov51x_set_default_params(struct usb_ov511 *ov)
ov->frame[i].format = force_palette;
else
ov->frame[i].format = VIDEO_PALETTE_YUV420;
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)
if (frame->scanstate == STATE_LINES) {
int nextf;
frame->grabstate = FRAME_DONE; // FIXME: Is this right?
if (waitqueue_active(&frame->wq)) {
frame->grabstate = FRAME_DONE;
wake_up_interruptible(&frame->wq);
}
frame->grabstate = FRAME_DONE;
wake_up_interruptible(&frame->wq);
/* If next frame is ready or grabbing,
* point to it */
......@@ -3747,12 +3749,8 @@ ov518_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
if (frame->scanstate == STATE_LINES) {
int nextf;
frame->grabstate = FRAME_DONE; // FIXME: Is this right?
if (waitqueue_active(&frame->wq)) {
frame->grabstate = FRAME_DONE;
wake_up_interruptible(&frame->wq);
}
frame->grabstate = FRAME_DONE;
wake_up_interruptible(&frame->wq);
/* If next frame is ready or grabbing,
* point to it */
......@@ -4228,7 +4226,7 @@ ov51x_alloc(struct usb_ov511 *ov)
}
static void
ov51x_dealloc(struct usb_ov511 *ov, int now)
ov51x_dealloc(struct usb_ov511 *ov)
{
PDEBUG(4, "entered");
down(&ov->buf_lock);
......@@ -4258,10 +4256,6 @@ ov51x_v4l1_open(struct inode *inode, struct file *file)
if (ov->user)
goto out;
err = ov51x_alloc(ov);
if (err < 0)
goto out;
ov->sub_flag = 0;
/* In case app doesn't set them... */
......@@ -4283,9 +4277,13 @@ ov51x_v4l1_open(struct inode *inode, struct file *file)
goto out;
}
err = ov51x_alloc(ov);
if (err < 0)
goto out;
err = ov51x_init_isoc(ov);
if (err) {
ov51x_dealloc(ov, 0);
ov51x_dealloc(ov);
goto out;
}
......@@ -4319,7 +4317,7 @@ ov51x_v4l1_close(struct inode *inode, struct file *file)
ov51x_led_control(ov, 0);
if (ov->dev)
ov51x_dealloc(ov, 0);
ov51x_dealloc(ov);
up(&ov->lock);
......@@ -4331,7 +4329,7 @@ ov51x_v4l1_close(struct inode *inode, struct file *file)
ov->cbuf = NULL;
up(&ov->cbuf_lock);
ov51x_dealloc(ov, 1);
ov51x_dealloc(ov);
kfree(ov);
ov = NULL;
}
......@@ -4449,7 +4447,7 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
case VIDIOCSPICT:
{
struct video_picture *p = arg;
int i;
int i, rc;
PDEBUG(4, "VIDIOCSPICT");
......@@ -4469,10 +4467,9 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
if (p->palette != ov->frame[0].format) {
PDEBUG(4, "Detected format change");
/* If we're collecting previous frame wait
before changing modes */
interruptible_sleep_on(&ov->wq);
if (signal_pending(current)) return -EINTR;
rc = ov51x_wait_frames_inactive(ov);
if (rc)
return rc;
mode_init_regs(ov, ov->frame[0].width,
ov->frame[0].height, p->palette, ov->sub_flag);
......@@ -4530,7 +4527,7 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
case VIDIOCSWIN:
{
struct video_window *vw = arg;
int i, result;
int i, rc;
PDEBUG(4, "VIDIOCSWIN: %dx%d", vw->width, vw->height);
......@@ -4545,15 +4542,14 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
return -EINVAL;
#endif
/* If we're collecting previous frame wait
before changing modes */
interruptible_sleep_on(&ov->wq);
if (signal_pending(current)) return -EINTR;
rc = ov51x_wait_frames_inactive(ov);
if (rc)
return rc;
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);
if (result < 0)
return result;
if (rc < 0)
return rc;
for (i = 0; i < OV511_NUMFRAMES; i++) {
ov->frame[i].width = vw->width;
......@@ -4600,7 +4596,7 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
case VIDIOCMCAPTURE:
{
struct video_mmap *vm = arg;
int ret, depth;
int rc, depth;
unsigned int f = vm->frame;
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,
(ov->frame[f].depth != depth)) {
PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters");
/* If we're collecting previous frame wait
before changing modes */
interruptible_sleep_on(&ov->wq);
if (signal_pending(current)) return -EINTR;
ret = mode_init_regs(ov, vm->width, vm->height,
rc = ov51x_wait_frames_inactive(ov);
if (rc)
return rc;
rc = mode_init_regs(ov, vm->width, vm->height,
vm->format, ov->sub_flag);
#if 0
if (ret < 0) {
if (rc < 0) {
PDEBUG(1, "Got error while initializing regs ");
return ret;
}
......@@ -4702,18 +4698,15 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
return rc;
if (frame->grabstate == FRAME_ERROR) {
int ret;
if ((ret = ov51x_new_frame(ov, fnum)) < 0)
return ret;
if ((rc = ov51x_new_frame(ov, fnum)) < 0)
return rc;
goto redo;
}
/* Fall through */
case FRAME_DONE:
if (ov->snap_enabled && !frame->snapshot) {
int ret;
if ((ret = ov51x_new_frame(ov, fnum)) < 0)
return ret;
if ((rc = ov51x_new_frame(ov, fnum)) < 0)
return rc;
goto redo;
}
......@@ -6089,7 +6082,6 @@ ov518_configure(struct usb_ov511 *ov)
return -EBUSY;
}
/****************************************************************************
*
* USB routines
......@@ -6097,11 +6089,10 @@ ov518_configure(struct usb_ov511 *ov)
***************************************************************************/
static int
ov51x_probe(struct usb_interface *intf,
const struct usb_device_id *id)
ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
struct usb_interface_descriptor *interface;
struct usb_interface_descriptor *idesc;
struct usb_ov511 *ov;
int i;
int registered = 0;
......@@ -6112,12 +6103,11 @@ ov51x_probe(struct usb_interface *intf,
if (dev->descriptor.bNumConfigurations != 1)
return -ENODEV;
interface = &intf->altsetting[0].desc;
idesc = &intf->altsetting[0].desc;
/* Checking vendor/product should be enough, but what the hell */
if (interface->bInterfaceClass != 0xFF)
if (idesc->bInterfaceClass != 0xFF)
return -ENODEV;
if (interface->bInterfaceSubClass != 0x00)
if (idesc->bInterfaceSubClass != 0x00)
return -ENODEV;
if ((ov = kmalloc(sizeof(*ov), GFP_KERNEL)) == NULL) {
......@@ -6128,7 +6118,7 @@ ov51x_probe(struct usb_interface *intf,
memset(ov, 0, sizeof(*ov));
ov->dev = dev;
ov->iface = interface->bInterfaceNumber;
ov->iface = idesc->bInterfaceNumber;
ov->led_policy = led;
ov->compress = compress;
ov->lightfreq = lightfreq;
......@@ -6272,7 +6262,7 @@ ov51x_probe(struct usb_interface *intf,
error_out:
err("Camera initialization failed");
return -ENOMEM;
return -EIO;
}
static void
......@@ -6284,6 +6274,7 @@ ov51x_disconnect(struct usb_interface *intf)
PDEBUG(3, "");
usb_set_intfdata (intf, NULL);
if (!ov)
return;
......@@ -6298,10 +6289,9 @@ ov51x_disconnect(struct usb_interface *intf)
/* This will cause the process to request another frame */
for (n = 0; n < OV511_NUMFRAMES; n++)
if (waitqueue_active(&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->frame[n].wq);
wake_up_interruptible(&ov->wq);
ov->streaming = 0;
ov51x_unlink_isoc(ov);
......@@ -6317,7 +6307,7 @@ ov51x_disconnect(struct usb_interface *intf)
ov->cbuf = NULL;
up(&ov->cbuf_lock);
ov51x_dealloc(ov, 1);
ov51x_dealloc(ov);
kfree(ov);
ov = NULL;
}
......@@ -6333,7 +6323,6 @@ static struct usb_driver ov511_driver = {
.disconnect = ov51x_disconnect
};
/****************************************************************************
*
* Module routines
......
......@@ -96,6 +96,15 @@ config USB_LCD
config USB_SPEEDTOUCH
tristate "Alcatel Speedtouch ADSL USB Modem"
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
tristate "USB testing driver (DEVELOPMENT)"
......
......@@ -71,6 +71,7 @@
*
*/
#include <linux/crc32.h>
#include "atmsar.h"
/***********************
......@@ -113,200 +114,22 @@
*dest++ = (unsigned char) (header >> 8); \
*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,
ushort vpi, ushort vci, unchar pti, unchar gfc, uint flags)
{
struct atmsar_vcc_data *new;
if (!vcc)
return NULL;
new = kmalloc (sizeof (struct atmsar_vcc_data), GFP_KERNEL);
if (!new)
return NULL;
if (!vcc)
return NULL;
memset (new, 0, sizeof (struct atmsar_vcc_data));
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->type = type;
new->next = NULL;
......@@ -375,216 +198,6 @@ void atmsar_close (struct atmsar_vcc_data **list, struct atmsar_vcc_data *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
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 */
if (pdu_crc != crc) {
......
......@@ -58,7 +58,6 @@ struct atmsar_vcc_data {
int type;
/* connection specific non-atmsar data */
struct sk_buff *(*alloc_tx) (struct atm_vcc * vcc, unsigned int size);
struct atm_vcc *vcc;
struct k_atm_aal_stats *stats;
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
unchar gfc, uint flags);
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 atmsar_vcc_data **ctx);
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_ */
......@@ -61,6 +61,7 @@
#include <linux/interrupt.h>
#include <linux/atm.h>
#include <linux/atmdev.h>
#include <linux/crc32.h>
#include "atmsar.h"
/*
......@@ -69,14 +70,15 @@
*/
#ifdef DEBUG
#define PDEBUG(arg...) printk(KERN_DEBUG "SpeedTouch USB: " arg)
#define PDEBUG(arg...) printk(KERN_DEBUG __FILE__ ": " arg)
#else
#define PDEBUG(arg...)
#endif
#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
#define PACKETDEBUG(arg...)
#endif
......@@ -88,15 +90,14 @@
#define SPEEDTOUCH_VENDORID 0x06b9
#define SPEEDTOUCH_PRODUCTID 0x4061
#define UDSL_OBUF_SIZE 32768
#define UDSL_MINOR 48
#define UDSL_NUMBER_RCV_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
* PPPoA and (1500 + 14 + 32*5 cellheader overhead) for PPPoE */
#define UDSL_MAX_AAL5_MRU 2048
#define UDSL_SEND_CONTEXTS 8
#define UDSL_IOCTL_START 1
#define UDSL_IOCTL_STOP 2
......@@ -126,13 +127,31 @@ struct udsl_receiver {
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 sk_buff *skb;
struct atm_vcc *vcc;
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
*/
......@@ -142,13 +161,10 @@ struct udsl_instance_data {
/* usb device part */
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;
/* atm device part */
struct atm_dev *atm_dev;
struct atmsar_vcc_data *atmsar_vcc_list;
/* receiving */
......@@ -161,18 +177,30 @@ struct udsl_instance_data {
struct list_head completed_receivers;
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
static int udsl_print_packet (const unsigned char *data, int len);
#endif
struct sk_buff_head sndqueue;
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
*/
static void udsl_atm_dev_close (struct atm_dev *dev);
static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci);
static void udsl_atm_close (struct atm_vcc *vcc);
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);
static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t *pos, char *page);
static struct atmdev_ops udsl_atm_devops = {
.dev_close = udsl_atm_dev_close,
.open = udsl_atm_open,
.close = udsl_atm_close,
.ioctl = udsl_atm_ioctl,
......@@ -187,20 +216,13 @@ static struct atmdev_ops udsl_atm_devops = {
.proc_read = udsl_atm_proc_read,
};
struct udsl_atm_dev_data {
struct atmsar_vcc_data *atmsar_vcc;
};
/*
* usb driver prototypes and structures
*/
static int udsl_usb_probe (struct usb_interface *intf,
const struct usb_device_id *id);
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_cancelsends (struct udsl_instance_data *instance, struct atm_vcc *vcc);
static struct usb_driver udsl_usb_driver = {
.name = udsl_driver_name,
......@@ -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 **
**************/
......@@ -221,19 +323,18 @@ static void udsl_complete_receive (struct urb *urb, struct pt_regs *regs)
struct udsl_receiver *rcv;
unsigned long flags;
PDEBUG ("udsl_complete_receive entered\n");
if (!urb || !(rcv = urb->context) || !(instance = rcv->instance)) {
PDEBUG ("udsl_complete_receive: bad urb!\n");
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() */
spin_lock_irqsave (&instance->completed_receivers_lock, flags);
list_add_tail (&rcv->list, &instance->completed_receivers);
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)
......@@ -246,6 +347,7 @@ static void udsl_process_receive (unsigned long data)
struct urb *urb;
struct atmsar_vcc_data *atmsar_vcc = NULL;
struct sk_buff *new = NULL, *tmp = NULL;
int err;
PDEBUG ("udsl_process_receive entered\n");
......@@ -315,12 +417,12 @@ static void udsl_process_receive (unsigned long data)
instance->usb_dev,
usb_rcvbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_IN),
(unsigned char *) rcv->skb->data,
UDSL_RECEIVE_BUFFER_SIZE,
UDSL_RCV_BUFFER_SIZE * ATM_CELL_SIZE,
udsl_complete_receive,
rcv);
if (!usb_submit_urb (urb, GFP_ATOMIC))
if (!(err = usb_submit_urb (urb, GFP_ATOMIC)))
break;
PDEBUG ("udsl_process_receive: submission failed\n");
PDEBUG ("udsl_process_receive: submission failed (%d)\n", err);
/* fall through */
default: /* error or urb unlinked */
PDEBUG ("udsl_process_receive: adding to spare_receivers\n");
......@@ -358,7 +460,7 @@ static void udsl_fire_receivers (struct udsl_instance_data *instance)
instance->usb_dev,
usb_rcvbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_IN),
(unsigned char *) rcv->skb->data,
UDSL_RECEIVE_BUFFER_SIZE,
UDSL_RCV_BUFFER_SIZE * ATM_CELL_SIZE,
udsl_complete_receive,
rcv);
......@@ -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 **
************/
......@@ -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 atm_dev *atm_dev;
struct udsl_instance_data *instance = dev->dev_data;
if (!instance->atm_dev)
if (!instance) {
PDEBUG ("udsl_atm_dev_close: NULL instance!\n");
return;
}
atm_dev = instance->atm_dev;
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);
PDEBUG ("udsl_atm_dev_close: queue has %u elements\n", instance->sndqueue.qlen);
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)
* 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)
{
......@@ -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[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--)
return sprintf (page, "AAL5: tx %d ( %d err ), rx %d ( %d err, %d drop )\n",
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)
}
/***************************************************************************
*
* 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
......@@ -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)
{
struct udsl_atm_dev_data *dev_data;
struct udsl_instance_data *instance = vcc->dev->dev_data;
PDEBUG ("udsl_atm_open called\n");
......@@ -535,15 +764,12 @@ static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci)
return -EINVAL;
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_USE_53BYTE_CELL | ATMSAR_SET_PTI);
if (!dev_data->atmsar_vcc) {
kfree (dev_data);
if (!vcc->dev_data) {
MOD_DEC_USE_COUNT;
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)
set_bit (ATM_VF_ADDR, &vcc->flags);
set_bit (ATM_VF_PARTIAL, &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)
udsl_fire_receivers (instance);
......@@ -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)
{
struct udsl_atm_dev_data *dev_data = vcc->dev_data;
struct udsl_instance_data *instance = vcc->dev->dev_data;
PDEBUG ("udsl_atm_close called\n");
if (!dev_data || !instance) {
PDEBUG ("NULL data!\n");
if (!instance) {
PDEBUG ("NULL instance!\n");
return;
}
/* freeing resources */
/* 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);
kfree (dev_data);
atmsar_close (&(instance->atmsar_vcc_list), vcc->dev_data);
vcc->dev_data = NULL;
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)
** 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)
{
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 *
instance->atm_dev->signal = ATM_PHY_SIG_FOUND;
down (&instance->serialize); /* vs self */
if (!instance->firmware_loaded) {
usb_set_interface (instance->usb_dev, 1, 2);
usb_set_interface (instance->usb_dev, 1, 1);
instance->firmware_loaded = 1;
}
up (&instance->serialize);
......@@ -773,7 +870,7 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i
struct udsl_instance_data *instance;
unsigned char mac_str [13];
unsigned char mac [6];
int i, err;
int i;
PDEBUG ("Trying device with Vendor=0x%x, Product=0x%x, ifnum %d\n",
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
/* instance init */
if (!(instance = kmalloc (sizeof (struct udsl_instance_data), GFP_KERNEL))) {
PDEBUG ("No memory for Instance data!\n");
err = -ENOMEM;
goto fail_instance;
return -ENOMEM;
}
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
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++) {
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);
err = -ENOMEM;
goto fail_urbs;
goto fail;
}
if (!(rcv->urb = usb_alloc_urb (0, GFP_KERNEL))) {
PDEBUG ("No memory for receive urb %d!\n", i);
err = -ENOMEM;
goto fail_urbs;
goto fail;
}
rcv->instance = instance;
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++) {
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))) {
PDEBUG ("No memory for send urb %d!\n", i);
err = -ENOMEM;
goto fail_urbs;
goto fail;
}
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 */
if (!(instance->atm_dev = atm_dev_register (udsl_driver_name, &udsl_atm_devops, -1, 0))) {
PDEBUG ("failed to register ATM device!\n");
err = -ENOMEM;
goto fail_atm;
goto fail;
}
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
return 0;
fail_atm:
fail_urbs:
for (i = 0; i < UDSL_NUMBER_SND_URBS; i++) {
struct udsl_usb_send_data_context *snd = &(instance->send_ctx[i]);
fail:
for (i = 0; i < UDSL_NUMBER_SND_BUFS; i++)
kfree (instance->all_buffers[i].base);
if (snd->urb)
usb_free_urb (snd->urb);
}
for (i = 0; i < UDSL_NUMBER_SND_URBS; i++)
usb_free_urb (instance->all_senders[i].urb);
for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++) {
struct udsl_receiver *rcv = &(instance->all_receivers[i]);
usb_free_urb (rcv->urb);
if (rcv->skb)
kfree_skb (rcv->skb);
if (rcv->urb)
usb_free_urb (rcv->urb);
}
kfree (instance);
fail_instance:
return err;
return -ENOMEM;
}
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;
unsigned long flags;
unsigned int count = 0;
int i;
int result, i;
PDEBUG ("disconnecting\n");
......@@ -916,8 +1027,9 @@ static void udsl_usb_disconnect (struct usb_interface *intf)
tasklet_disable (&instance->receive_tasklet);
/* receive finalize */
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)
if (++count > UDSL_NUMBER_RCV_URBS)
panic (__FILE__ ": memory corruption detected at line %d!\n", __LINE__);
......@@ -929,7 +1041,8 @@ static void udsl_usb_disconnect (struct usb_interface *intf)
count = UDSL_NUMBER_RCV_URBS - count;
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 */
do {
......@@ -946,12 +1059,11 @@ static void udsl_usb_disconnect (struct usb_interface *intf)
if (completed == count)
break;
/* not all urbs completed */
yield ();
} while (1);
PDEBUG ("udsl_usb_disconnect: flushing %u completed receivers\n", count);
/* no need to take the spinlock - no completion handlers running */
PDEBUG ("udsl_usb_disconnect: flushing\n");
/* no need to take the spinlock */
INIT_LIST_HEAD (&instance->completed_receivers);
tasklet_enable (&instance->receive_tasklet);
......@@ -965,25 +1077,48 @@ static void udsl_usb_disconnect (struct usb_interface *intf)
kfree_skb (rcv->skb);
}
for (i = 0; i < UDSL_NUMBER_SND_URBS; i++) {
struct udsl_usb_send_data_context *ctx = &(instance->send_ctx[i]);
/* send finalize */
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)
ctx->vcc->pop (ctx->vcc, ctx->skb);
ctx->skb = NULL;
PDEBUG ("udsl_usb_disconnect: found %u spare senders\n", count);
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 */
if (instance->atm_dev)
udsl_atm_stopdevice (instance);
tasklet_enable (&instance->send_tasklet);
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)
static int __init udsl_usb_init (void)
{
struct sk_buff *skb; /* dummy for sizeof */
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);
}
......
......@@ -130,6 +130,7 @@ static struct usb_device_id usb_klsi_table[] = {
{ USB_DEVICE(0x03e8, 0x0008) }, /* AOX Endpoints USB Ethernet */
{ USB_DEVICE(0x04bb, 0x0901) }, /* I-O DATA USB-ET/T */
{ USB_DEVICE(0x0506, 0x03e8) }, /* 3Com 3C19250 */
{ USB_DEVICE(0x0506, 0x11f8) }, /* 3Com 3C460 */
{ USB_DEVICE(0x0557, 0x2002) }, /* ATEN USB Ethernet */
{ USB_DEVICE(0x0557, 0x4000) }, /* D-Link DSB-650C */
{ USB_DEVICE(0x0565, 0x0002) }, /* Peracom Enet */
......@@ -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)
{
struct kaweth_device *kaweth = net->priv;
char *private_header;
u16 *private_header;
int res;
......@@ -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 = cpu_to_le16(skb->len);
*private_header = cpu_to_le16(skb->len-2);
kaweth->tx_skb = skb;
usb_fill_bulk_urb(kaweth->tx_urb,
......
......@@ -133,6 +133,7 @@ struct usb_eth_dev {
#define VENDOR_LANEED 0x056e
#define VENDOR_LINKSYS 0x066b
#define VENDOR_MELCO 0x0411
#define VENDOR_MOBILITY 0x1342
#define VENDOR_NETGEAR 0x0846
#define VENDOR_SMARTBRIDGES 0x08d1
#define VENDOR_SMC 0x0707
......@@ -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,
DEFAULT_GPIO_RESET )
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",
VENDOR_ADMTEK, 0x8511,
DEFAULT_GPIO_RESET | PEGASUS_II )
......@@ -215,6 +216,8 @@ PEGASUS_DEV( "D-Link DSB-650", VENDOR_DLINK, 0xabc1,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "GOLDPFEIL USB Adapter", VENDOR_ELCON, 0x0002,
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,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "Hawking UF100 10/100 Ethernet", VENDOR_HAWKING, 0x400c,
......
......@@ -297,10 +297,14 @@ config USB_SERIAL_KEYSPAN_USA19W
config USB_SERIAL_KEYSPAN_USA19QW
bool "USB Keyspan USA-19QW Firmware"
depends on USB_SERIAL_KEYSPAN
help
Say Y here to include firmware for the USA-19QW converter.
config USB_SERIAL_KEYSPAN_USA19QI
bool "USB Keyspan USA-19QI Firmware"
depends on USB_SERIAL_KEYSPAN
help
Say Y here to include firmware for the USA-19QI converter.
config USB_SERIAL_KEYSPAN_USA49W
bool "USB Keyspan USA-49W Firmware"
......
......@@ -141,7 +141,6 @@ static int __init usb_console_setup(struct console *co, char *options)
}
port = &serial->port[0];
down (&port->sem);
port->tty = NULL;
info->port = port;
......@@ -158,8 +157,6 @@ static int __init usb_console_setup(struct console *co, char *options)
port->open_count = 0;
}
up (&port->sem);
if (retval) {
err ("could not open USB console port");
return retval;
......@@ -208,8 +205,6 @@ static void usb_console_write(struct console *co, const char *buf, unsigned coun
if (count == 0)
return;
down (&port->sem);
dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
if (!port->open_count) {
......@@ -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);
exit:
up (&port->sem);
dbg("%s - return value (if we had one): %d", __FUNCTION__, retval);
}
......
......@@ -391,7 +391,11 @@ static LIST_HEAD(usb_serial_driver_list);
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)
......@@ -468,7 +472,6 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
port = &serial->port[portNumber];
tty->driver_data = port;
down (&port->sem);
port->tty = tty;
/* lock this module before we call it,
......@@ -492,8 +495,6 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
}
}
bailout:
up (&port->sem);
return retval;
}
......@@ -516,6 +517,7 @@ static void __serial_close(struct usb_serial_port *port, struct file *filp)
}
module_put(port->serial->type->owner);
kobject_put(&port->serial->kobj);
}
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)
return;
down (&port->sem);
dbg("%s - port %d", __FUNCTION__, port->number);
/* if disconnect beat us to the punch here, there's nothing to do */
if (tty->driver_data) {
__serial_close(port, filp);
}
up (&port->sem);
}
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
if (!serial)
return -ENODEV;
down (&port->sem);
dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
if (!port->open_count) {
......@@ -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);
exit:
up (&port->sem);
return retval;
}
......@@ -576,8 +571,6 @@ static int serial_write_room (struct tty_struct *tty)
if (!serial)
return -ENODEV;
down (&port->sem);
dbg("%s - port %d", __FUNCTION__, port->number);
if (!port->open_count) {
......@@ -592,7 +585,6 @@ static int serial_write_room (struct tty_struct *tty)
retval = usb_serial_generic_write_room(port);
exit:
up (&port->sem);
return retval;
}
......@@ -605,8 +597,6 @@ static int serial_chars_in_buffer (struct tty_struct *tty)
if (!serial)
return -ENODEV;
down (&port->sem);
dbg("%s = port %d", __FUNCTION__, port->number);
if (!port->open_count) {
......@@ -621,7 +611,6 @@ static int serial_chars_in_buffer (struct tty_struct *tty)
retval = usb_serial_generic_chars_in_buffer(port);
exit:
up (&port->sem);
return retval;
}
......@@ -633,8 +622,6 @@ static void serial_throttle (struct tty_struct * tty)
if (!serial)
return;
down (&port->sem);
dbg("%s - port %d", __FUNCTION__, port->number);
if (!port->open_count) {
......@@ -647,7 +634,6 @@ static void serial_throttle (struct tty_struct * tty)
serial->type->throttle(port);
exit:
up (&port->sem);
}
static void serial_unthrottle (struct tty_struct * tty)
......@@ -658,8 +644,6 @@ static void serial_unthrottle (struct tty_struct * tty)
if (!serial)
return;
down (&port->sem);
dbg("%s - port %d", __FUNCTION__, port->number);
if (!port->open_count) {
......@@ -672,7 +656,6 @@ static void serial_unthrottle (struct tty_struct * tty)
serial->type->unthrottle(port);
exit:
up (&port->sem);
}
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
if (!serial)
return -ENODEV;
down (&port->sem);
dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);
if (!port->open_count) {
......@@ -700,7 +681,6 @@ static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned in
retval = -ENOIOCTLCMD;
exit:
up (&port->sem);
return retval;
}
......@@ -712,8 +692,6 @@ static void serial_set_termios (struct tty_struct *tty, struct termios * old)
if (!serial)
return;
down (&port->sem);
dbg("%s - port %d", __FUNCTION__, port->number);
if (!port->open_count) {
......@@ -726,7 +704,6 @@ static void serial_set_termios (struct tty_struct *tty, struct termios * old)
serial->type->set_termios(port, old);
exit:
up (&port->sem);
}
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)
return;
down (&port->sem);
dbg("%s - port %d", __FUNCTION__, port->number);
if (!port->open_count) {
......@@ -751,7 +726,6 @@ static void serial_break (struct tty_struct *tty, int break_state)
serial->type->break_ctl(port, break_state);
exit:
up (&port->sem);
}
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
begin += length;
length = 0;
}
kobject_put(&serial->kobj);
}
*eof = 1;
done:
......@@ -833,6 +808,75 @@ void usb_serial_port_softint(void *private)
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,
struct usb_interface *interface,
struct usb_serial_device_type *type)
......@@ -845,12 +889,16 @@ static struct usb_serial * create_serial (struct usb_device *dev,
return NULL;
}
memset (serial, 0, sizeof(*serial));
serial->dev = dev;
serial->dev = usb_get_dev(dev);
serial->type = type;
serial->interface = interface;
serial->vendor = dev->descriptor.idVendor;
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;
}
......@@ -1113,7 +1161,6 @@ int usb_serial_probe(struct usb_interface *interface,
port->serial = serial;
port->magic = USB_SERIAL_PORT_MAGIC;
INIT_WORK(&port->work, usb_serial_port_softint, port);
init_MUTEX (&port->sem);
}
/* if this device type has an attach function, call it */
......@@ -1189,67 +1236,14 @@ void usb_serial_disconnect(struct usb_interface *interface)
{
struct usb_serial *serial = usb_get_intfdata (interface);
struct device *dev = &interface->dev;
struct usb_serial_port *port;
int i;
dbg ("%s", __FUNCTION__);
usb_set_intfdata (interface, NULL);
if (serial) {
/* fail all future close/read/write/ioctl/etc calls */
for (i = 0; i < serial->num_ports; ++i) {
port = &serial->port[i];
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);
/* let the last holder of this object
* cause it to be cleaned up */
kobject_put (&serial->kobj);
}
dev_info(dev, "device disconnected\n");
}
......
......@@ -89,7 +89,6 @@
* @write_wait: a wait_queue_head_t used by the port.
* @work: work queue entry for the line discipline waking up.
* @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
* ports of a device.
......@@ -116,7 +115,6 @@ struct usb_serial_port {
wait_queue_head_t write_wait;
struct work_struct work;
int open_count;
struct semaphore sem;
struct device dev;
};
#define to_usb_serial_port(d) container_of(d, struct usb_serial_port, dev)
......@@ -164,8 +162,10 @@ struct usb_serial {
__u16 vendor;
__u16 product;
struct usb_serial_port port[MAX_NUM_PORTS];
struct kobject kobj;
void * private;
};
#define to_usb_serial(d) container_of(d, struct usb_serial, kobj)
#define NUM_DONT_CARE (-1)
......
......@@ -314,7 +314,7 @@ static int interpret_urb_result(struct us_data *us, unsigned int pipe,
return USB_STOR_XFER_ERROR;
/* the transfer was cancelled, presumably by an abort */
case -ENODEV:
case -ECONNRESET:
US_DEBUGP("-- transfer cancelled\n");
return USB_STOR_XFER_ERROR;
......
......@@ -17,6 +17,7 @@
#include <linux/device.h> /* for struct device */
#include <linux/fs.h> /* for struct file_operations */
#include <linux/completion.h> /* for struct completion */
#include <linux/sched.h> /* for current && schedule_timeout */
static __inline__ void wait_ms(unsigned int ms)
......@@ -239,6 +240,7 @@ struct usb_device {
int have_langid; /* whether string_langid is valid yet */
int string_langid; /* language ID for strings */
int present; /* if device is present or not */
void *hcpriv; /* Host Controller private data */
......
......@@ -25,7 +25,7 @@ obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate/
obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate/
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)/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