Commit f4e1c439 authored by Linus Torvalds's avatar Linus Torvalds

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

into home.transmeta.com:/home/torvalds/v2.5/linux
parents c4c88b92 868cac6d
......@@ -33,12 +33,6 @@ if [ "$CONFIG_USB" = "y" -o "$CONFIG_USB" = "m" ]; then
source drivers/usb/serial/Config.in
comment 'USB Miscellaneous drivers'
dep_tristate ' EMI 2|6 USB Audio interface support' CONFIG_USB_EMI26 $CONFIG_USB_AUDIO
dep_tristate ' Texas Instruments Graph Link USB (aka SilverLink) cable support' CONFIG_USB_TIGL $CONFIG_USB
dep_tristate ' USB Auerswald ISDN support (EXPERIMENTAL)' CONFIG_USB_AUERSWALD $CONFIG_USB $CONFIG_EXPERIMENTAL
dep_tristate ' USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB $CONFIG_EXPERIMENTAL
dep_tristate ' Tieman Voyager USB Braille display support (EXPERIMENTAL)' CONFIG_USB_BRLVGER $CONFIG_USB $CONFIG_EXPERIMENTAL
source drivers/usb/misc/Config.in
fi
endmenu
......@@ -57,7 +57,9 @@ obj-$(CONFIG_USB_SERIAL) += serial/
obj-$(CONFIG_USB_AUERSWALD) += misc/
obj-$(CONFIG_USB_BRLVGER) += misc/
obj-$(CONFIG_USB_EMI26) += misc/
obj-$(CONFIG_USB_LCD) += misc/
obj-$(CONFIG_USB_RIO500) += misc/
obj-$(CONFIG_USB_SPEEDTOUCH) += misc/
obj-$(CONFIG_USB_TIGL) += misc/
obj-$(CONFIG_USB_USS720) += misc/
......
......@@ -7,7 +7,7 @@ obj-$(CONFIG_USB_ACM) += cdc-acm.o
obj-$(CONFIG_USB_AUDIO) += audio.o
obj-$(CONFIG_USB_BLUETOOTH_TTY) += bluetty.o
obj-$(CONFIG_USB_MIDI) += usb-midi.o
obj-$(CONFIG_USB_PRINTER) += printer.o
obj-$(CONFIG_USB_PRINTER) += usblp.o
include $(TOPDIR)/Rules.make
/*
* printer.c Version 0.12
* usblp.c Version 0.12
*
* Copyright (c) 1999 Michael Gee <michael@linuxspecific.com>
* Copyright (c) 1999 Pavel Machek <pavel@suse.cz>
......
......@@ -289,7 +289,7 @@ static int rh_string (
// language ids
if (id == 0) {
*data++ = 4; *data++ = 3; /* 4 bytes string data */
*data++ = 0; *data++ = 0; /* some language id */
*data++ = 0x09; *data++ = 0x04; /* MSFT-speak for "en-us" */
return 4;
// serial number
......@@ -585,9 +585,7 @@ void usb_bus_init (struct usb_bus *bus)
{
memset (&bus->devmap, 0, sizeof(struct usb_devmap));
#ifdef DEVNUM_ROUND_ROBIN
bus->devnum_next = 1;
#endif /* DEVNUM_ROUND_ROBIN */
bus->root_hub = NULL;
bus->hcpriv = NULL;
......@@ -738,10 +736,10 @@ EXPORT_SYMBOL (usb_register_root_hub);
/*-------------------------------------------------------------------------*/
/**
* usb_calc_bus_time: approximate periodic transaction time in nanoseconds
* usb_calc_bus_time - approximate periodic transaction time in nanoseconds
* @speed: from dev->speed; USB_SPEED_{LOW,FULL,HIGH}
* @is_input: true iff the transaction sends data to the host
* @is_isoc: true for isochronous transactions, false for interrupt ones
* @isoc: true for isochronous transactions, false for interrupt ones
* @bytecount: how many bytes in the transaction.
*
* Returns approximate bus time in nanoseconds for a periodic transaction.
......@@ -1286,8 +1284,8 @@ EXPORT_SYMBOL (usb_hcd_operations);
* This hands the URB from HCD to its USB device driver, using its
* completion function. The HCD has freed all per-urb resources
* (and is done using urb->hcpriv). It also released all HCD locks;
* the device driver won't cause deadlocks if it resubmits this URB,
* and won't confuse things by modifying and resubmitting this one.
* the device driver won't cause problems if it frees, modifies,
* or resubmits this URB.
* Bandwidth and other resources will be deallocated.
*
* HCDs must not use this for periodic URBs that are still scheduled
......
......@@ -19,6 +19,31 @@
#ifdef __KERNEL__
/* This file contains declarations of usbcore internals that are mostly
* used or exposed by Host Controller Drivers.
*/
/*
* USB Packet IDs (PIDs)
*/
#define USB_PID_UNDEF_0 0xf0
#define USB_PID_OUT 0xe1
#define USB_PID_ACK 0xd2
#define USB_PID_DATA0 0xc3
#define USB_PID_PING 0xb4 /* USB 2.0 */
#define USB_PID_SOF 0xa5
#define USB_PID_NYET 0x96 /* USB 2.0 */
#define USB_PID_DATA2 0x87 /* USB 2.0 */
#define USB_PID_SPLIT 0x78 /* USB 2.0 */
#define USB_PID_IN 0x69
#define USB_PID_NAK 0x5a
#define USB_PID_DATA1 0x4b
#define USB_PID_PREAMBLE 0x3c /* Token mode */
#define USB_PID_ERR 0x3c /* USB 2.0: handshake mode */
#define USB_PID_SETUP 0x2d
#define USB_PID_STALL 0x1e
#define USB_PID_MDATA 0x0f /* USB 2.0 */
/*-------------------------------------------------------------------------*/
/*
......@@ -234,13 +259,11 @@ extern int usb_new_device(struct usb_device *dev);
extern void usb_connect(struct usb_device *dev);
extern void usb_disconnect(struct usb_device **);
#ifndef _LINUX_HUB_H
/* exported to hub driver ONLY to support usb_reset_device () */
extern int usb_get_configuration(struct usb_device *dev);
extern void usb_set_maxpacket(struct usb_device *dev);
extern void usb_destroy_configuration(struct usb_device *dev);
extern int usb_set_address(struct usb_device *dev);
#endif /* _LINUX_HUB_H */
/*-------------------------------------------------------------------------*/
......@@ -354,10 +377,48 @@ extern struct usb_interface *usb_ifnum_to_if (struct usb_device *dev,
extern int usb_find_interface_driver (struct usb_device *dev,
struct usb_interface *interface);
#define usb_endpoint_halt(dev, ep, out) ((dev)->halted[out] |= (1 << (ep)))
#define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN))
/* for probe/disconnect with correct module usage counting */
void *usb_bind_driver(struct usb_driver *driver, struct usb_interface *intf);
void usb_unbind_driver(struct usb_device *device, struct usb_interface *intf);
extern struct list_head usb_driver_list;
/*
* USB device fs stuff
*/
#ifdef CONFIG_USB_DEVICEFS
/*
* these are expected to be called from the USB core/hub thread
* with the kernel lock held
*/
extern void usbfs_add_bus(struct usb_bus *bus);
extern void usbfs_remove_bus(struct usb_bus *bus);
extern void usbfs_add_device(struct usb_device *dev);
extern void usbfs_remove_device(struct usb_device *dev);
extern void usbfs_update_special (void);
extern int usbfs_init(void);
extern void usbfs_cleanup(void);
#else /* CONFIG_USB_DEVICEFS */
static inline void usbfs_add_bus(struct usb_bus *bus) {}
static inline void usbfs_remove_bus(struct usb_bus *bus) {}
static inline void usbfs_add_device(struct usb_device *dev) {}
static inline void usbfs_remove_device(struct usb_device *dev) {}
static inline void usbfs_update_special (void) {}
static inline int usbfs_init(void) { return 0; }
static inline void usbfs_cleanup(void) { }
#endif /* CONFIG_USB_DEVICEFS */
/*-------------------------------------------------------------------------*/
/* hub.h ... DeviceRemovable in 2.4.2-ac11, gone in 2.4.10 */
......
......@@ -261,9 +261,8 @@ static int usb_hub_configure(struct usb_hub *hub,
{
struct usb_device *dev = hub->dev;
struct usb_hub_status hubstatus;
char portstr[USB_MAXCHILDREN + 1];
unsigned int pipe;
int i, maxp, ret;
int maxp, ret;
hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
if (!hub->descriptor) {
......@@ -294,9 +293,17 @@ static int usb_hub_configure(struct usb_hub *hub,
le16_to_cpus(&hub->descriptor->wHubCharacteristics);
if (hub->descriptor->wHubCharacteristics & HUB_CHAR_COMPOUND)
dbg("part of a compound device");
else
if (hub->descriptor->wHubCharacteristics & HUB_CHAR_COMPOUND) {
int i;
char portstr [USB_MAXCHILDREN + 1];
for (i = 0; i < dev->maxchild; i++)
portstr[i] = hub->descriptor->DeviceRemovable
[((i + 1) / 8)] & (1 << ((i + 1) % 8))
? 'F' : 'R';
portstr[dev->maxchild] = 0;
dbg("compound device; port removable status: %s", portstr);
} else
dbg("standalone hub");
switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) {
......@@ -371,14 +378,6 @@ static int usb_hub_configure(struct usb_hub *hub,
dbg("hub controller current requirement: %dmA",
hub->descriptor->bHubContrCurrent);
for (i = 0; i < dev->maxchild; i++)
portstr[i] = hub->descriptor->DeviceRemovable
[((i + 1) / 8)] & (1 << ((i + 1) % 8))
? 'F' : 'R';
portstr[dev->maxchild] = 0;
dbg("port removable status: %s", portstr);
ret = usb_get_hub_status(dev, &hubstatus);
if (ret < 0) {
err("Unable to get hub status (err = %d)", ret);
......
......@@ -88,15 +88,17 @@ struct urb * usb_get_urb(struct urb *urb)
/*-------------------------------------------------------------------*/
/**
* usb_submit_urb - asynchronously issue a transfer request for an endpoint
* usb_submit_urb - issue an asynchronous transfer request for an endpoint
* @urb: pointer to the urb describing the request
* @mem_flags: the type of memory to allocate, see kmalloc() for a list
* of valid options for this.
*
* This submits a transfer request, and transfers control of the URB
* describing that request to the USB subsystem. Request completion will
* indicated later, asynchronously, by calling the completion handler.
* This call may be issued in interrupt context.
* be indicated later, asynchronously, by calling the completion handler.
* The three types of completion are success, error, and unlink
* (also called "request cancellation").
* URBs may be submitted in interrupt context.
*
* The caller must have correctly initialized the URB before submitting
* it. Functions such as usb_fill_bulk_urb() and usb_fill_control_urb() are
......@@ -148,20 +150,19 @@ struct urb * usb_get_urb(struct urb *urb)
*
* Memory Flags:
*
* General rules for how to decide which mem_flags to use:
*
* Basically the rules are the same as for kmalloc. There are four
* The general rules for how to decide which mem_flags to use
* are the same as for kmalloc. There are four
* different possible values; GFP_KERNEL, GFP_NOFS, GFP_NOIO and
* GFP_ATOMIC.
*
* GFP_NOFS is not ever used, as it has not been implemented yet.
*
* There are three situations you must use GFP_ATOMIC.
* a) you are inside a completion handler, an interrupt, bottom half,
* tasklet or timer.
* b) you are holding a spinlock or rwlock (does not apply to
* semaphores)
* c) current->state != TASK_RUNNING, this is the case only after
* GFP_ATOMIC is used when
* (a) you are inside a completion handler, an interrupt, bottom half,
* tasklet or timer, or
* (b) you are holding a spinlock or rwlock (does not apply to
* semaphores), or
* (c) current->state != TASK_RUNNING, this is the case only after
* you've changed it.
*
* GFP_NOIO is used in the block io path and error handling of storage
......@@ -169,17 +170,17 @@ struct urb * usb_get_urb(struct urb *urb)
*
* All other situations use GFP_KERNEL.
*
* Specfic rules for how to decide which mem_flags to use:
*
* - start_xmit, timeout, and receive methods of network drivers must
* use GFP_ATOMIC (spinlock)
* - queuecommand methods of scsi drivers must use GFP_ATOMIC (spinlock)
* - If you use a kernel thread with a network driver you must use
* GFP_NOIO, unless b) or c) apply
* - After you have done a down() you use GFP_KERNEL, unless b) or c)
* apply or your are in a storage driver's block io path
* - probe and disconnect use GFP_KERNEL unless b) or c) apply
* - Changing firmware on a running storage or net device uses
* Some more specific rules for mem_flags can be inferred, such as
* (1) start_xmit, timeout, and receive methods of network drivers must
* use GFP_ATOMIC (they are called with a spinlock held);
* (2) queuecommand methods of scsi drivers must use GFP_ATOMIC (also
* called with a spinlock held);
* (3) If you use a kernel thread with a network driver you must use
* GFP_NOIO, unless (b) or (c) apply;
* (4) after you have done a down() you can use GFP_KERNEL, unless (b) or (c)
* apply or your are in a storage driver's block io path;
* (5) USB probe and disconnect can use GFP_KERNEL unless (b) or (c) apply; and
* (6) changing firmware on a running storage or net device uses
* GFP_NOIO, unless b) or c) apply
*
*/
......
......@@ -1057,56 +1057,6 @@ int usb_get_current_frame_number(struct usb_device *dev)
}
/*-------------------------------------------------------------------*/
/* for returning string descriptors in UTF-16LE */
static int ascii2utf (char *ascii, __u8 *utf, int utfmax)
{
int retval;
for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) {
*utf++ = *ascii++ & 0x7f;
*utf++ = 0;
}
return retval;
}
/*
* root_hub_string is used by each host controller's root hub code,
* so that they're identified consistently throughout the system.
*/
int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len)
{
char buf [30];
// assert (len > (2 * (sizeof (buf) + 1)));
// assert (strlen (type) <= 8);
// language ids
if (id == 0) {
*data++ = 4; *data++ = 3; /* 4 bytes data */
*data++ = 0; *data++ = 0; /* some language id */
return 4;
// serial number
} else if (id == 1) {
sprintf (buf, "%x", serial);
// product description
} else if (id == 2) {
sprintf (buf, "USB %s Root Hub", type);
// id 3 == vendor description
// unsupported IDs --> "stall"
} else
return 0;
data [0] = 2 + ascii2utf (buf, data + 2, len - 2);
data [1] = 3;
return data [0];
}
/*
* __usb_get_extra_descriptor() finds a descriptor of specific type in the
* extra field of the interface and endpoint descriptor structs.
......@@ -1221,16 +1171,13 @@ void usb_connect(struct usb_device *dev)
* won't have seen this, but not so for reinit ...
*/
dev->descriptor.bMaxPacketSize0 = 8; /* Start off at 8 bytes */
#ifndef DEVNUM_ROUND_ROBIN
devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1);
#else /* round_robin alloc of devnums */
/* Try to allocate the next devnum beginning at bus->devnum_next. */
devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, dev->bus->devnum_next);
if (devnum >= 128)
devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1);
dev->bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1);
#endif /* round_robin alloc of devnums */
if (devnum < 128) {
set_bit(devnum, dev->bus->devmap.devicemap);
......@@ -1649,7 +1596,6 @@ EXPORT_SYMBOL(usb_interface_claimed);
EXPORT_SYMBOL(usb_driver_release_interface);
EXPORT_SYMBOL(usb_match_id);
EXPORT_SYMBOL(usb_root_hub_string);
EXPORT_SYMBOL(usb_new_device);
EXPORT_SYMBOL(usb_reset_device);
EXPORT_SYMBOL(usb_connect);
......
......@@ -21,6 +21,8 @@
*
*-------------------------------------------------------------------------*/
/* FIXME: reuse the root hub framework in usbcore, shrinking this code. */
#ifdef DEBUG
#undef DEBUG
#endif
......@@ -229,6 +231,52 @@ static int rh_init_int_timer (struct urb * urb)
/*-------------------------------------------------------------------------*/
/* for returning string descriptors in UTF-16LE */
static int ascii2utf (char *ascii, __u8 *utf, int utfmax)
{
int retval;
for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) {
*utf++ = *ascii++ & 0x7f;
*utf++ = 0;
}
return retval;
}
static int root_hub_string (int id, int serial, char *type, __u8 *data, int len)
{
char buf [30];
// assert (len > (2 * (sizeof (buf) + 1)));
// assert (strlen (type) <= 8);
// language ids
if (id == 0) {
*data++ = 4; *data++ = 3; /* 4 bytes data */
*data++ = 0; *data++ = 0; /* some language id */
return 4;
// serial number
} else if (id == 1) {
sprintf (buf, "%x", serial);
// product description
} else if (id == 2) {
sprintf (buf, "USB %s Root Hub", type);
// id 3 == vendor description
// unsupported IDs --> "stall"
} else
return 0;
data [0] = 2 + ascii2utf (buf, data + 2, len - 2);
data [1] = 3;
return data [0];
}
/*-------------------------------------------------------------------------*/
/* helper macro */
#define OK(x) len = (x); break
......@@ -409,7 +457,7 @@ static int rh_submit_urb (struct urb * urb)
OK (len);
case (0x03): /* string descriptors */
len = usb_root_hub_string (wValue & 0xff, (int) (long) 0,
len = root_hub_string (wValue & 0xff, (int) (long) 0,
"SL811HS", data, wLength);
if (len > 0) {
data_buf = data;
......
......@@ -4,6 +4,9 @@
#include <linux/list.h>
#include <linux/usb.h>
#define usb_packetid(pipe) (usb_pipein(pipe) ? USB_PID_IN : USB_PID_OUT)
#define PIPE_DEVEP_MASK 0x0007ff00
/*
* Universal Host Controller Interface data structures and defines
*/
......
......@@ -115,6 +115,7 @@ static struct usb_device_id scanner_device_ids [] = {
{ USB_DEVICE(0x03f0, 0x0101) }, /* 4100C */
{ USB_DEVICE(0x03f0, 0x0105) }, /* 4200C */
{ USB_DEVICE(0x03f0, 0x0305) }, /* 4300C */
{ USB_DEVICE(0x03f0, 0x0705) }, /* 4400C */
{ USB_DEVICE(0x03f0, 0x0102) }, /* PhotoSmart S20 */
{ USB_DEVICE(0x03f0, 0x0401) }, /* 5200C */
// { USB_DEVICE(0x03f0, 0x0701) }, /* 5300C - NOT SUPPORTED - see http://www.neatech.nl/oss/HP5300C/ */
......@@ -187,8 +188,12 @@ static struct usb_device_id scanner_device_ids [] = {
{ USB_DEVICE(0x04b8, 0x010b) }, /* Perfection 1240U */
{ USB_DEVICE(0x04b8, 0x010c) }, /* Perfection 640U */
{ USB_DEVICE(0x04b8, 0x010e) }, /* Expression 1680 */
{ USB_DEVICE(0x04a9, 0x2204) }, /* FB630U */
{ USB_DEVICE(0x04b8, 0x0110) }, /* Perfection 1650 */
{ USB_DEVICE(0x04b8, 0x0112) }, /* Perfection 2450 - GT-9700 for the Japanese mkt */
{ USB_DEVICE(0x04b8, 0x0114) }, /* Perfection 660 */
{ USB_DEVICE(0x04b8, 0x011b) }, /* Perfection 2400 Photo */
{ USB_DEVICE(0x04b8, 0x011e) }, /* Perfection 1660 Photo */
/* Umax */
{ USB_DEVICE(0x1606, 0x0010) }, /* Astra 1220U */
{ USB_DEVICE(0x1606, 0x0030) }, /* Astra 2000U */
......
......@@ -78,7 +78,7 @@ enum {
};
/*
* This structure lives in uvd_t->user field.
* This structure lives in uvd->user field.
*/
typedef struct {
int initialized; /* Had we already sent init sequence? */
......@@ -249,7 +249,7 @@ static videosize_t ibmcam_size_to_videosize(int size)
* History:
* 1/21/00 Created.
*/
static ParseState_t ibmcam_find_header(uvd_t *uvd) /* FIXME: Add frame here */
static ParseState_t ibmcam_find_header(struct uvd *uvd) /* FIXME: Add frame here */
{
usbvideo_frame_t *frame;
ibmcam_t *icam;
......@@ -398,7 +398,7 @@ case IBMCAM_MODEL_4:
* 12-Oct-2000 Reworked to reflect interlaced nature of the data.
*/
static ParseState_t ibmcam_parse_lines(
uvd_t *uvd,
struct uvd *uvd,
usbvideo_frame_t *frame,
long *pcopylen)
{
......@@ -663,7 +663,7 @@ static ParseState_t ibmcam_parse_lines(
* lost resolution.
*/
static ParseState_t ibmcam_model2_320x240_parse_lines(
uvd_t *uvd,
struct uvd *uvd,
usbvideo_frame_t *frame,
long *pcopylen)
{
......@@ -817,7 +817,7 @@ static ParseState_t ibmcam_model2_320x240_parse_lines(
}
static ParseState_t ibmcam_model3_parse_lines(
uvd_t *uvd,
struct uvd *uvd,
usbvideo_frame_t *frame,
long *pcopylen)
{
......@@ -962,7 +962,7 @@ static ParseState_t ibmcam_model3_parse_lines(
* 10-Feb-2001 Created.
*/
static ParseState_t ibmcam_model4_128x96_parse_lines(
uvd_t *uvd,
struct uvd *uvd,
usbvideo_frame_t *frame,
long *pcopylen)
{
......@@ -1049,7 +1049,7 @@ static ParseState_t ibmcam_model4_128x96_parse_lines(
* History:
* 1/21/00 Created.
*/
void ibmcam_ProcessIsocData(uvd_t *uvd, usbvideo_frame_t *frame)
void ibmcam_ProcessIsocData(struct uvd *uvd, usbvideo_frame_t *frame)
{
ParseState_t newstate;
long copylen = 0;
......@@ -1128,7 +1128,7 @@ void ibmcam_ProcessIsocData(uvd_t *uvd, usbvideo_frame_t *frame)
* 1/27/00 Added check for dev == NULL; this happens if camera is unplugged.
*/
static int ibmcam_veio(
uvd_t *uvd,
struct uvd *uvd,
unsigned char req,
unsigned short value,
unsigned short index)
......@@ -1195,7 +1195,7 @@ static int ibmcam_veio(
* History:
* 1/18/00 Created.
*/
static int ibmcam_calculate_fps(uvd_t *uvd)
static int ibmcam_calculate_fps(struct uvd *uvd)
{
return 3 + framerate*4 + framerate/2;
}
......@@ -1209,33 +1209,33 @@ static int ibmcam_calculate_fps(uvd_t *uvd)
* History:
* 1/2/00 Created.
*/
static void ibmcam_send_FF_04_02(uvd_t *uvd)
static void ibmcam_send_FF_04_02(struct uvd *uvd)
{
ibmcam_veio(uvd, 0, 0x00FF, 0x0127);
ibmcam_veio(uvd, 0, 0x0004, 0x0124);
ibmcam_veio(uvd, 0, 0x0002, 0x0124);
}
static void ibmcam_send_00_04_06(uvd_t *uvd)
static void ibmcam_send_00_04_06(struct uvd *uvd)
{
ibmcam_veio(uvd, 0, 0x0000, 0x0127);
ibmcam_veio(uvd, 0, 0x0004, 0x0124);
ibmcam_veio(uvd, 0, 0x0006, 0x0124);
}
static void ibmcam_send_x_00(uvd_t *uvd, unsigned short x)
static void ibmcam_send_x_00(struct uvd *uvd, unsigned short x)
{
ibmcam_veio(uvd, 0, x, 0x0127);
ibmcam_veio(uvd, 0, 0x0000, 0x0124);
}
static void ibmcam_send_x_00_05(uvd_t *uvd, unsigned short x)
static void ibmcam_send_x_00_05(struct uvd *uvd, unsigned short x)
{
ibmcam_send_x_00(uvd, x);
ibmcam_veio(uvd, 0, 0x0005, 0x0124);
}
static void ibmcam_send_x_00_05_02(uvd_t *uvd, unsigned short x)
static void ibmcam_send_x_00_05_02(struct uvd *uvd, unsigned short x)
{
ibmcam_veio(uvd, 0, x, 0x0127);
ibmcam_veio(uvd, 0, 0x0000, 0x0124);
......@@ -1243,7 +1243,7 @@ static void ibmcam_send_x_00_05_02(uvd_t *uvd, unsigned short x)
ibmcam_veio(uvd, 0, 0x0002, 0x0124);
}
static void ibmcam_send_x_01_00_05(uvd_t *uvd, unsigned short x)
static void ibmcam_send_x_01_00_05(struct uvd *uvd, unsigned short x)
{
ibmcam_veio(uvd, 0, x, 0x0127);
ibmcam_veio(uvd, 0, 0x0001, 0x0124);
......@@ -1251,7 +1251,7 @@ static void ibmcam_send_x_01_00_05(uvd_t *uvd, unsigned short x)
ibmcam_veio(uvd, 0, 0x0005, 0x0124);
}
static void ibmcam_send_x_00_05_02_01(uvd_t *uvd, unsigned short x)
static void ibmcam_send_x_00_05_02_01(struct uvd *uvd, unsigned short x)
{
ibmcam_veio(uvd, 0, x, 0x0127);
ibmcam_veio(uvd, 0, 0x0000, 0x0124);
......@@ -1260,7 +1260,7 @@ static void ibmcam_send_x_00_05_02_01(uvd_t *uvd, unsigned short x)
ibmcam_veio(uvd, 0, 0x0001, 0x0124);
}
static void ibmcam_send_x_00_05_02_08_01(uvd_t *uvd, unsigned short x)
static void ibmcam_send_x_00_05_02_08_01(struct uvd *uvd, unsigned short x)
{
ibmcam_veio(uvd, 0, x, 0x0127);
ibmcam_veio(uvd, 0, 0x0000, 0x0124);
......@@ -1270,7 +1270,7 @@ static void ibmcam_send_x_00_05_02_08_01(uvd_t *uvd, unsigned short x)
ibmcam_veio(uvd, 0, 0x0001, 0x0124);
}
static void ibmcam_Packet_Format1(uvd_t *uvd, unsigned char fkey, unsigned char val)
static void ibmcam_Packet_Format1(struct uvd *uvd, unsigned char fkey, unsigned char val)
{
ibmcam_send_x_01_00_05(uvd, unknown_88);
ibmcam_send_x_00_05(uvd, fkey);
......@@ -1284,20 +1284,20 @@ static void ibmcam_Packet_Format1(uvd_t *uvd, unsigned char fkey, unsigned char
ibmcam_send_FF_04_02(uvd);
}
static void ibmcam_PacketFormat2(uvd_t *uvd, unsigned char fkey, unsigned char val)
static void ibmcam_PacketFormat2(struct uvd *uvd, unsigned char fkey, unsigned char val)
{
ibmcam_send_x_01_00_05 (uvd, unknown_88);
ibmcam_send_x_00_05 (uvd, fkey);
ibmcam_send_x_00_05_02 (uvd, val);
}
static void ibmcam_model2_Packet2(uvd_t *uvd)
static void ibmcam_model2_Packet2(struct uvd *uvd)
{
ibmcam_veio(uvd, 0, 0x00ff, 0x012d);
ibmcam_veio(uvd, 0, 0xfea3, 0x0124);
}
static void ibmcam_model2_Packet1(uvd_t *uvd, unsigned short v1, unsigned short v2)
static void ibmcam_model2_Packet1(struct uvd *uvd, unsigned short v1, unsigned short v2)
{
ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
ibmcam_veio(uvd, 0, 0x00ff, 0x012e);
......@@ -1318,7 +1318,7 @@ static void ibmcam_model2_Packet1(uvd_t *uvd, unsigned short v1, unsigned short
* 00_0096_0127
* 00_fea8_0124
*/
static void ibmcam_model3_Packet1(uvd_t *uvd, unsigned short v1, unsigned short v2)
static void ibmcam_model3_Packet1(struct uvd *uvd, unsigned short v1, unsigned short v2)
{
ibmcam_veio(uvd, 0, 0x0078, 0x012d);
ibmcam_veio(uvd, 0, v1, 0x012f);
......@@ -1327,7 +1327,7 @@ static void ibmcam_model3_Packet1(uvd_t *uvd, unsigned short v1, unsigned short
ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
}
static void ibmcam_model4_BrightnessPacket(uvd_t *uvd, int i)
static void ibmcam_model4_BrightnessPacket(struct uvd *uvd, int i)
{
ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
ibmcam_veio(uvd, 0, 0x0026, 0x012f);
......@@ -1353,7 +1353,7 @@ static void ibmcam_model4_BrightnessPacket(uvd_t *uvd, int i)
* History:
* 1/2/00 Created.
*/
static void ibmcam_adjust_contrast(uvd_t *uvd)
static void ibmcam_adjust_contrast(struct uvd *uvd)
{
unsigned char a_contrast = uvd->vpic.contrast >> 12;
unsigned char new_contrast;
......@@ -1428,7 +1428,7 @@ static void ibmcam_adjust_contrast(uvd_t *uvd)
* 1/5/00 Created.
* 2/20/00 Added support for Model 2 cameras.
*/
static void ibmcam_change_lighting_conditions(uvd_t *uvd)
static void ibmcam_change_lighting_conditions(struct uvd *uvd)
{
static const char proc[] = "ibmcam_change_lighting_conditions";
......@@ -1474,7 +1474,7 @@ static void ibmcam_change_lighting_conditions(uvd_t *uvd)
* range [0..6], where 0 is most smooth and 6 is most sharp (raw image, I guess).
* Recommended value is 4. Cameras model 2 do not have this feature at all.
*/
static void ibmcam_set_sharpness(uvd_t *uvd)
static void ibmcam_set_sharpness(struct uvd *uvd)
{
static const char proc[] = "ibmcam_set_sharpness";
......@@ -1543,7 +1543,7 @@ static void ibmcam_set_sharpness(uvd_t *uvd)
*
* This procedure changes brightness of the picture.
*/
static void ibmcam_set_brightness(uvd_t *uvd)
static void ibmcam_set_brightness(struct uvd *uvd)
{
static const char proc[] = "ibmcam_set_brightness";
static const unsigned short n = 1;
......@@ -1608,7 +1608,7 @@ static void ibmcam_set_brightness(uvd_t *uvd)
}
}
static void ibmcam_set_hue(uvd_t *uvd)
static void ibmcam_set_hue(struct uvd *uvd)
{
switch (IBMCAM_T(uvd)->camera_model) {
case IBMCAM_MODEL_2:
......@@ -1704,14 +1704,14 @@ static void ibmcam_set_hue(uvd_t *uvd)
* This procedure gets called from V4L interface to update picture settings.
* Here we change brightness and contrast.
*/
static void ibmcam_adjust_picture(uvd_t *uvd)
static void ibmcam_adjust_picture(struct uvd *uvd)
{
ibmcam_adjust_contrast(uvd);
ibmcam_set_brightness(uvd);
ibmcam_set_hue(uvd);
}
static int ibmcam_model1_setup(uvd_t *uvd)
static int ibmcam_model1_setup(struct uvd *uvd)
{
const int ntries = 5;
int i;
......@@ -1908,7 +1908,7 @@ static int ibmcam_model1_setup(uvd_t *uvd)
return (CAMERA_IS_OPERATIONAL(uvd) ? 0 : -EFAULT);
}
static int ibmcam_model2_setup(uvd_t *uvd)
static int ibmcam_model2_setup(struct uvd *uvd)
{
ibmcam_veio(uvd, 0, 0x0000, 0x0100); /* LED on */
ibmcam_veio(uvd, 1, 0x0000, 0x0116);
......@@ -1966,7 +1966,7 @@ static int ibmcam_model2_setup(uvd_t *uvd)
* This code adds finishing touches to the video data interface.
* Here we configure the frame rate and turn on the LED.
*/
static void ibmcam_model1_setup_after_video_if(uvd_t *uvd)
static void ibmcam_model1_setup_after_video_if(struct uvd *uvd)
{
unsigned short internal_frame_rate;
......@@ -1978,7 +1978,7 @@ static void ibmcam_model1_setup_after_video_if(uvd_t *uvd)
ibmcam_veio(uvd, 0, 0xc0, 0x010c);
}
static void ibmcam_model2_setup_after_video_if(uvd_t *uvd)
static void ibmcam_model2_setup_after_video_if(struct uvd *uvd)
{
unsigned short setup_model2_rg2, setup_model2_sat, setup_model2_yb;
......@@ -2154,7 +2154,7 @@ static void ibmcam_model2_setup_after_video_if(uvd_t *uvd)
usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
}
static void ibmcam_model4_setup_after_video_if(uvd_t *uvd)
static void ibmcam_model4_setup_after_video_if(struct uvd *uvd)
{
switch (uvd->videosize) {
case VIDEOSIZE_128x96:
......@@ -2704,7 +2704,7 @@ static void ibmcam_model4_setup_after_video_if(uvd_t *uvd)
usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
}
static void ibmcam_model3_setup_after_video_if(uvd_t *uvd)
static void ibmcam_model3_setup_after_video_if(struct uvd *uvd)
{
int i;
/*
......@@ -3485,7 +3485,7 @@ static void ibmcam_model3_setup_after_video_if(uvd_t *uvd)
* This code tells camera to stop streaming. The interface remains
* configured and bandwidth - claimed.
*/
static void ibmcam_video_stop(uvd_t *uvd)
static void ibmcam_video_stop(struct uvd *uvd)
{
switch (IBMCAM_T(uvd)->camera_model) {
case IBMCAM_MODEL_1:
......@@ -3546,7 +3546,7 @@ case IBMCAM_MODEL_4:
* History:
* 1/2/00 Created.
*/
static void ibmcam_reinit_iso(uvd_t *uvd, int do_stop)
static void ibmcam_reinit_iso(struct uvd *uvd, int do_stop)
{
switch (IBMCAM_T(uvd)->camera_model) {
case IBMCAM_MODEL_1:
......@@ -3570,7 +3570,7 @@ static void ibmcam_reinit_iso(uvd_t *uvd, int do_stop)
}
}
static void ibmcam_video_start(uvd_t *uvd)
static void ibmcam_video_start(struct uvd *uvd)
{
ibmcam_change_lighting_conditions(uvd);
ibmcam_set_sharpness(uvd);
......@@ -3580,7 +3580,7 @@ static void ibmcam_video_start(uvd_t *uvd)
/*
* Return negative code on failure, 0 on success.
*/
static int ibmcam_setup_on_open(uvd_t *uvd)
static int ibmcam_setup_on_open(struct uvd *uvd)
{
int setup_ok = 0; /* Success by default */
/* Send init sequence only once, it's large! */
......@@ -3602,7 +3602,7 @@ static int ibmcam_setup_on_open(uvd_t *uvd)
return setup_ok;
}
static void ibmcam_configure_video(uvd_t *uvd)
static void ibmcam_configure_video(struct uvd *uvd)
{
if (uvd == NULL)
return;
......@@ -3658,7 +3658,7 @@ static void ibmcam_configure_video(uvd_t *uvd)
*/
static void *ibmcam_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *devid)
{
uvd_t *uvd = NULL;
struct uvd *uvd = NULL;
int i, nas, model=0, canvasX=0, canvasY=0;
int actInterface=-1, inactInterface=-1, maxPS=0;
unsigned char video_ep = 0;
......@@ -3868,7 +3868,7 @@ static void *ibmcam_probe(struct usb_device *dev, unsigned int ifnum, const stru
MOD_INC_USE_COUNT;
uvd = usbvideo_AllocateDevice(cams);
if (uvd != NULL) {
/* Here uvd is a fully allocated uvd_t object */
/* Here uvd is a fully allocated uvd object */
uvd->flags = flags;
uvd->debug = debug;
uvd->dev = dev;
......
......@@ -15,7 +15,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include "usbvideo.h"
......@@ -29,7 +29,7 @@
#define MAX_CAMERAS 1
#define DRIVER_VERSION "v1.3"
#define DRIVER_VERSION "v1.4"
#define DRIVER_DESC "Konica Webcam driver"
enum ctrl_req {
......@@ -117,6 +117,10 @@ struct konicawc {
int maxline; /* number of lines per frame */
int yplanesz; /* Number of bytes in the Y plane */
unsigned int buttonsts:1;
#ifdef CONFIG_INPUT
struct input_dev input;
char input_physname[64];
#endif
};
......@@ -125,7 +129,7 @@ struct konicawc {
#define konicawc_set_value(uvd, value, index) konicawc_ctrl_msg(uvd, USB_DIR_OUT, 2, value, index, NULL, 0)
static int konicawc_ctrl_msg(uvd_t *uvd, u8 dir, u8 request, u16 value, u16 index, void *buf, int len)
static int konicawc_ctrl_msg(struct uvd *uvd, u8 dir, u8 request, u16 value, u16 index, void *buf, int len)
{
int retval = usb_control_msg(uvd->dev,
dir ? usb_rcvctrlpipe(uvd->dev, 0) : usb_sndctrlpipe(uvd->dev, 0),
......@@ -134,21 +138,21 @@ static int konicawc_ctrl_msg(uvd_t *uvd, u8 dir, u8 request, u16 value, u16 inde
}
static inline void konicawc_camera_on(uvd_t *uvd)
static inline void konicawc_camera_on(struct uvd *uvd)
{
DEBUG(0, "camera on");
konicawc_set_misc(uvd, 0x2, 1, 0x0b);
}
static inline void konicawc_camera_off(uvd_t *uvd)
static inline void konicawc_camera_off(struct uvd *uvd)
{
DEBUG(0, "camera off");
konicawc_set_misc(uvd, 0x2, 0, 0x0b);
}
static void konicawc_set_camera_size(uvd_t *uvd)
static void konicawc_set_camera_size(struct uvd *uvd)
{
struct konicawc *cam = (struct konicawc *)uvd->user_data;
......@@ -162,7 +166,7 @@ static void konicawc_set_camera_size(uvd_t *uvd)
}
static int konicawc_setup_on_open(uvd_t *uvd)
static int konicawc_setup_on_open(struct uvd *uvd)
{
struct konicawc *cam = (struct konicawc *)uvd->user_data;
......@@ -188,7 +192,7 @@ static int konicawc_setup_on_open(uvd_t *uvd)
}
static void konicawc_adjust_picture(uvd_t *uvd)
static void konicawc_adjust_picture(struct uvd *uvd)
{
struct konicawc *cam = (struct konicawc *)uvd->user_data;
......@@ -214,7 +218,7 @@ static void konicawc_adjust_picture(uvd_t *uvd)
}
static int konicawc_compress_iso(uvd_t *uvd, struct urb *dataurb, struct urb *stsurb)
static int konicawc_compress_iso(struct uvd *uvd, struct urb *dataurb, struct urb *stsurb)
{
char *cdata;
int i, totlen = 0;
......@@ -258,7 +262,7 @@ static int konicawc_compress_iso(uvd_t *uvd, struct urb *dataurb, struct urb *st
*/
if(sts < 0x80) {
button = sts & 0x40;
button = !!(sts & 0x40);
sts &= ~0x40;
}
......@@ -268,6 +272,10 @@ static int konicawc_compress_iso(uvd_t *uvd, struct urb *dataurb, struct urb *st
if(button != cam->buttonsts) {
DEBUG(2, "button: %sclicked", button ? "" : "un");
cam->buttonsts = button;
#ifdef CONFIG_INPUT
input_report_key(&cam->input, BTN_0, cam->buttonsts);
input_sync(&cam->input);
#endif
}
if(sts == 0x01) { /* drop frame */
......@@ -308,7 +316,7 @@ static int konicawc_compress_iso(uvd_t *uvd, struct urb *dataurb, struct urb *st
}
static void resubmit_urb(uvd_t *uvd, struct urb *urb)
static void resubmit_urb(struct uvd *uvd, struct urb *urb)
{
int i, ret;
for (i = 0; i < FRAMES_PER_DESC; i++) {
......@@ -326,7 +334,7 @@ static void resubmit_urb(uvd_t *uvd, struct urb *urb)
static void konicawc_isoc_irq(struct urb *urb)
{
uvd_t *uvd = urb->context;
struct uvd *uvd = urb->context;
struct konicawc *cam = (struct konicawc *)uvd->user_data;
/* We don't want to do anything if we are about to be removed! */
......@@ -367,7 +375,7 @@ static void konicawc_isoc_irq(struct urb *urb)
}
static int konicawc_start_data(uvd_t *uvd)
static int konicawc_start_data(struct uvd *uvd)
{
struct usb_device *dev = uvd->dev;
int i, errFlag;
......@@ -445,7 +453,7 @@ static int konicawc_start_data(uvd_t *uvd)
}
static void konicawc_stop_data(uvd_t *uvd)
static void konicawc_stop_data(struct uvd *uvd)
{
int i, j;
struct konicawc *cam;
......@@ -480,7 +488,7 @@ static void konicawc_stop_data(uvd_t *uvd)
}
static void konicawc_process_isoc(uvd_t *uvd, usbvideo_frame_t *frame)
static void konicawc_process_isoc(struct uvd *uvd, usbvideo_frame_t *frame)
{
struct konicawc *cam = (struct konicawc *)uvd->user_data;
int maxline = cam->maxline;
......@@ -554,14 +562,105 @@ static void konicawc_process_isoc(uvd_t *uvd, usbvideo_frame_t *frame)
}
static int konicawc_calculate_fps(uvd_t *uvd)
static int konicawc_find_fps(int size, int fps)
{
int i;
fps *= 3;
DEBUG(1, "konica_find_fps: size = %d fps = %d", size, fps);
if(fps <= spd_to_fps[size][0])
return 0;
if(fps >= spd_to_fps[size][MAX_SPEED])
return MAX_SPEED;
for(i = 0; i < MAX_SPEED; i++) {
if((fps >= spd_to_fps[size][i]) && (fps <= spd_to_fps[size][i+1])) {
DEBUG(2, "fps %d between %d and %d", fps, i, i+1);
if( (fps - spd_to_fps[size][i]) < (spd_to_fps[size][i+1] - fps))
return i;
else
return i+1;
}
}
return MAX_SPEED+1;
}
static int konicawc_set_video_mode(struct uvd *uvd, struct video_window *vw)
{
struct konicawc *cam = (struct konicawc *)uvd->user_data;
int newspeed = cam->speed;
int newsize;
int x = vw->width;
int y = vw->height;
int fps = vw->flags;
if(x > 0 && y > 0) {
DEBUG(2, "trying to find size %d,%d", x, y);
for(newsize = 0; newsize <= MAX_FRAME_SIZE; newsize++) {
if((camera_sizes[newsize].width == x) && (camera_sizes[newsize].height == y))
break;
}
} else {
newsize = cam->size;
}
if(newsize > MAX_FRAME_SIZE) {
DEBUG(1, "couldnt find size %d,%d", x, y);
return -EINVAL;
}
if(fps > 0) {
DEBUG(1, "trying to set fps to %d", fps);
newspeed = konicawc_find_fps(newsize, fps);
DEBUG(1, "find_fps returned %d (%d)", newspeed, spd_to_fps[newsize][newspeed]);
}
if(newspeed > MAX_SPEED)
return -EINVAL;
DEBUG(1, "setting size to %d speed to %d", newsize, newspeed);
if((newsize == cam->size) && (newspeed == cam->speed)) {
DEBUG(1, "Nothing to do");
return 0;
}
DEBUG(0, "setting to %dx%d @ %d fps", camera_sizes[newsize].width,
camera_sizes[newsize].height, spd_to_fps[newsize][newspeed]/3);
konicawc_stop_data(uvd);
uvd->ifaceAltActive = spd_to_iface[newspeed];
DEBUG(1, "new interface = %d", uvd->ifaceAltActive);
cam->speed = newspeed;
if(cam->size != newsize) {
cam->size = newsize;
konicawc_set_camera_size(uvd);
}
/* Flush the input queue and clear any current frame in progress */
RingQueue_Flush(&uvd->dp);
cam->lastframe = -2;
if(uvd->curframe != -1) {
uvd->frame[uvd->curframe].curline = 0;
uvd->frame[uvd->curframe].seqRead_Length = 0;
uvd->frame[uvd->curframe].seqRead_Index = 0;
}
konicawc_start_data(uvd);
return 0;
}
static int konicawc_calculate_fps(struct uvd *uvd)
{
struct konicawc *cam = uvd->user_data;
return spd_to_fps[cam->size][cam->speed]/3;
}
static void konicawc_configure_video(uvd_t *uvd)
static void konicawc_configure_video(struct uvd *uvd)
{
struct konicawc *cam = (struct konicawc *)uvd->user_data;
u8 buf[2];
......@@ -594,10 +693,10 @@ static void konicawc_configure_video(uvd_t *uvd)
uvd->vcap.type = VID_TYPE_CAPTURE;
uvd->vcap.channels = 1;
uvd->vcap.audios = 0;
uvd->vcap.minwidth = camera_sizes[cam->size].width;
uvd->vcap.minheight = camera_sizes[cam->size].height;
uvd->vcap.maxwidth = camera_sizes[cam->size].width;
uvd->vcap.maxheight = camera_sizes[cam->size].height;
uvd->vcap.minwidth = camera_sizes[SIZE_160X120].width;
uvd->vcap.minheight = camera_sizes[SIZE_160X120].height;
uvd->vcap.maxwidth = camera_sizes[SIZE_320X240].width;
uvd->vcap.maxheight = camera_sizes[SIZE_320X240].height;
memset(&uvd->vchan, 0, sizeof(uvd->vchan));
uvd->vchan.flags = 0 ;
......@@ -620,11 +719,11 @@ static void konicawc_configure_video(uvd_t *uvd)
static void *konicawc_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *devid)
{
uvd_t *uvd = NULL;
struct uvd *uvd = NULL;
int i, nas;
int actInterface=-1, inactInterface=-1, maxPS=0;
unsigned char video_ep = 0;
DEBUG(1, "konicawc_probe(%p,%u.)", dev, ifnum);
/* We don't handle multi-config cameras */
......@@ -696,7 +795,7 @@ static void *konicawc_probe(struct usb_device *dev, unsigned int ifnum, const st
uvd = usbvideo_AllocateDevice(cams);
if (uvd != NULL) {
struct konicawc *cam = (struct konicawc *)(uvd->user_data);
/* Here uvd is a fully allocated uvd_t object */
/* Here uvd is a fully allocated uvd object */
for(i = 0; i < USBVIDEO_NUMSBUF; i++) {
cam->sts_urb[i] = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
if(cam->sts_urb[i] == NULL) {
......@@ -723,29 +822,50 @@ static void *konicawc_probe(struct usb_device *dev, unsigned int ifnum, const st
uvd->iso_packet_len = maxPS;
uvd->paletteBits = 1L << VIDEO_PALETTE_YUV420P;
uvd->defaultPalette = VIDEO_PALETTE_YUV420P;
uvd->canvas = VIDEOSIZE(cam->width, cam->height);
uvd->videosize = uvd->canvas;
uvd->canvas = VIDEOSIZE(320, 240);
uvd->videosize = VIDEOSIZE(cam->width, cam->height);
/* Initialize konicawc specific data */
konicawc_configure_video(uvd);
i = usbvideo_RegisterVideoDevice(uvd);
uvd->max_frame_size = (cam->width * cam->height * 3)/2;
uvd->max_frame_size = (320 * 240 * 3)/2;
if (i != 0) {
err("usbvideo_RegisterVideoDevice() failed.");
uvd = NULL;
}
#ifdef CONFIG_INPUT
/* Register input device for button */
memset(&cam->input, 0, sizeof(struct input_dev));
cam->input.name = "Konicawc snapshot button";
cam->input.private = cam;
cam->input.evbit[0] = BIT(EV_KEY);
cam->input.keybit[LONG(BTN_0)] = BIT(BTN_0);
cam->input.id.bustype = BUS_USB;
cam->input.id.vendor = dev->descriptor.idVendor;
cam->input.id.product = dev->descriptor.idProduct;
cam->input.id.version = dev->descriptor.bcdDevice;
input_register_device(&cam->input);
usb_make_path(dev, cam->input_physname, 56);
strcat(cam->input_physname, "/input0");
cam->input.phys = cam->input_physname;
info("konicawc: %s on %s\n", cam->input.name, cam->input.phys);
#endif
}
MOD_DEC_USE_COUNT;
return uvd;
}
static void konicawc_free_uvd(uvd_t *uvd)
static void konicawc_free_uvd(struct uvd *uvd)
{
int i;
struct konicawc *cam = (struct konicawc *)uvd->user_data;
#ifdef CONFIG_INPUT
input_unregister_device(&cam->input);
#endif
for (i=0; i < USBVIDEO_NUMSBUF; i++) {
usb_free_urb(cam->sts_urb[i]);
cam->sts_urb[i] = NULL;
......@@ -768,6 +888,7 @@ static int __init konicawc_init(void)
cbTbl.setupOnOpen = konicawc_setup_on_open;
cbTbl.processData = konicawc_process_isoc;
cbTbl.getFPS = konicawc_calculate_fps;
cbTbl.setVideoMode = konicawc_set_video_mode;
cbTbl.startDataPump = konicawc_start_data;
cbTbl.stopDataPump = konicawc_stop_data;
cbTbl.adjustPicture = konicawc_adjust_picture;
......
......@@ -103,7 +103,7 @@ MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)
* 02-Nov-2000 First (mostly dummy) version.
* 06-Nov-2000 Rewrote to dump all data into frame.
*/
void ultracam_ProcessIsocData(uvd_t *uvd, usbvideo_frame_t *frame)
void ultracam_ProcessIsocData(struct uvd *uvd, usbvideo_frame_t *frame)
{
int n;
......@@ -140,7 +140,7 @@ void ultracam_ProcessIsocData(uvd_t *uvd, usbvideo_frame_t *frame)
* 1/27/00 Added check for dev == NULL; this happens if camera is unplugged.
*/
static int ultracam_veio(
uvd_t *uvd,
struct uvd *uvd,
unsigned char req,
unsigned short value,
unsigned short index,
......@@ -193,7 +193,7 @@ static int ultracam_veio(
/*
* ultracam_calculate_fps()
*/
static int ultracam_calculate_fps(uvd_t *uvd)
static int ultracam_calculate_fps(struct uvd *uvd)
{
return 3 + framerate*4 + framerate/2;
}
......@@ -201,14 +201,14 @@ static int ultracam_calculate_fps(uvd_t *uvd)
/*
* ultracam_adjust_contrast()
*/
static void ultracam_adjust_contrast(uvd_t *uvd)
static void ultracam_adjust_contrast(struct uvd *uvd)
{
}
/*
* ultracam_change_lighting_conditions()
*/
static void ultracam_change_lighting_conditions(uvd_t *uvd)
static void ultracam_change_lighting_conditions(struct uvd *uvd)
{
}
......@@ -219,7 +219,7 @@ static void ultracam_change_lighting_conditions(uvd_t *uvd)
* range [0..6], where 0 is most smooth and 6 is most sharp (raw image, I guess).
* Recommended value is 4. Cameras model 2 do not have this feature at all.
*/
static void ultracam_set_sharpness(uvd_t *uvd)
static void ultracam_set_sharpness(struct uvd *uvd)
{
}
......@@ -228,11 +228,11 @@ static void ultracam_set_sharpness(uvd_t *uvd)
*
* This procedure changes brightness of the picture.
*/
static void ultracam_set_brightness(uvd_t *uvd)
static void ultracam_set_brightness(struct uvd *uvd)
{
}
static void ultracam_set_hue(uvd_t *uvd)
static void ultracam_set_hue(struct uvd *uvd)
{
}
......@@ -242,7 +242,7 @@ static void ultracam_set_hue(uvd_t *uvd)
* This procedure gets called from V4L interface to update picture settings.
* Here we change brightness and contrast.
*/
static void ultracam_adjust_picture(uvd_t *uvd)
static void ultracam_adjust_picture(struct uvd *uvd)
{
ultracam_adjust_contrast(uvd);
ultracam_set_brightness(uvd);
......@@ -255,7 +255,7 @@ static void ultracam_adjust_picture(uvd_t *uvd)
* This code tells camera to stop streaming. The interface remains
* configured and bandwidth - claimed.
*/
static void ultracam_video_stop(uvd_t *uvd)
static void ultracam_video_stop(struct uvd *uvd)
{
}
......@@ -266,24 +266,24 @@ static void ultracam_video_stop(uvd_t *uvd)
* resets the video pipe. This sequence was observed to reinit the
* camera or, at least, to initiate ISO data stream.
*/
static void ultracam_reinit_iso(uvd_t *uvd, int do_stop)
static void ultracam_reinit_iso(struct uvd *uvd, int do_stop)
{
}
static void ultracam_video_start(uvd_t *uvd)
static void ultracam_video_start(struct uvd *uvd)
{
ultracam_change_lighting_conditions(uvd);
ultracam_set_sharpness(uvd);
ultracam_reinit_iso(uvd, 0);
}
static int ultracam_resetPipe(uvd_t *uvd)
static int ultracam_resetPipe(struct uvd *uvd)
{
usb_clear_halt(uvd->dev, uvd->video_endp);
return 0;
}
static int ultracam_alternateSetting(uvd_t *uvd, int setting)
static int ultracam_alternateSetting(struct uvd *uvd, int setting)
{
static const char proc[] = "ultracam_alternateSetting";
int i;
......@@ -299,7 +299,7 @@ static int ultracam_alternateSetting(uvd_t *uvd, int setting)
/*
* Return negative code on failure, 0 on success.
*/
static int ultracam_setup_on_open(uvd_t *uvd)
static int ultracam_setup_on_open(struct uvd *uvd)
{
int setup_ok = 0; /* Success by default */
/* Send init sequence only once, it's large! */
......@@ -487,7 +487,7 @@ static int ultracam_setup_on_open(uvd_t *uvd)
return setup_ok;
}
static void ultracam_configure_video(uvd_t *uvd)
static void ultracam_configure_video(struct uvd *uvd)
{
if (uvd == NULL)
return;
......@@ -539,7 +539,7 @@ static void ultracam_configure_video(uvd_t *uvd)
*/
static void *ultracam_probe(struct usb_device *dev, unsigned int ifnum ,const struct usb_device_id *devid)
{
uvd_t *uvd = NULL;
struct uvd *uvd = NULL;
int i, nas;
int actInterface=-1, inactInterface=-1, maxPS=0;
unsigned char video_ep = 0;
......@@ -628,7 +628,7 @@ static void *ultracam_probe(struct usb_device *dev, unsigned int ifnum ,const st
MOD_INC_USE_COUNT;
uvd = usbvideo_AllocateDevice(cams);
if (uvd != NULL) {
/* Here uvd is a fully allocated uvd_t object */
/* Here uvd is a fully allocated uvd object */
uvd->flags = flags;
uvd->debug = debug;
uvd->dev = dev;
......
......@@ -44,8 +44,8 @@ MODULE_PARM(video_nr, "i");
#if USES_PROC_FS
static void usbvideo_procfs_level1_create(usbvideo_t *ut);
static void usbvideo_procfs_level1_destroy(usbvideo_t *ut);
static void usbvideo_procfs_level2_create(uvd_t *uvd);
static void usbvideo_procfs_level2_destroy(uvd_t *uvd);
static void usbvideo_procfs_level2_create(struct uvd *uvd);
static void usbvideo_procfs_level2_destroy(struct uvd *uvd);
static int usbvideo_default_procfs_read_proc(
char *page, char **start, off_t off, int count,
int *eof, void *data);
......@@ -55,7 +55,7 @@ static int usbvideo_default_procfs_write_proc(
#endif
static void usbvideo_Disconnect(struct usb_device *dev, void *ptr);
static void usbvideo_CameraRelease(uvd_t *uvd);
static void usbvideo_CameraRelease(struct uvd *uvd);
static int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg);
......@@ -65,11 +65,11 @@ static int usbvideo_v4l_read(struct file *file, char *buf,
size_t count, loff_t *ppos);
static int usbvideo_v4l_close(struct inode *inode, struct file *file);
static int usbvideo_StartDataPump(uvd_t *uvd);
static void usbvideo_StopDataPump(uvd_t *uvd);
static int usbvideo_GetFrame(uvd_t *uvd, int frameNum);
static int usbvideo_NewFrame(uvd_t *uvd, int framenum);
static void usbvideo_SoftwareContrastAdjustment(uvd_t *uvd,
static int usbvideo_StartDataPump(struct uvd *uvd);
static void usbvideo_StopDataPump(struct uvd *uvd);
static int usbvideo_GetFrame(struct uvd *uvd, int frameNum);
static int usbvideo_NewFrame(struct uvd *uvd, int framenum);
static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd,
usbvideo_frame_t *frame);
/*******************************/
......@@ -135,9 +135,21 @@ static void RingQueue_Initialize(RingQueue_t *rq)
static void RingQueue_Allocate(RingQueue_t *rq, int rqLen)
{
/* Make sure the requested size is a power of 2 and
round up if necessary. This allows index wrapping
using masks rather than modulo */
int i = 1;
assert(rq != NULL);
assert(rqLen > 0);
while(rqLen >> i)
i++;
if(rqLen != 1 << (i-1))
rqLen = 1 << i;
rq->length = rqLen;
rq->ri = rq->wi = 0;
rq->queue = usbvideo_rvmalloc(rq->length);
assert(rq->queue != NULL);
}
......@@ -161,12 +173,32 @@ static void RingQueue_Free(RingQueue_t *rq)
int RingQueue_Dequeue(RingQueue_t *rq, unsigned char *dst, int len)
{
int i;
int rql, toread;
assert(rq != NULL);
assert(dst != NULL);
for (i=0; i < len; i++) {
dst[i] = rq->queue[rq->ri];
RING_QUEUE_DEQUEUE_BYTES(rq,1);
rql = RingQueue_GetLength(rq);
if(!rql)
return 0;
/* Clip requested length to available data */
if(len > rql)
len = rql;
toread = len;
if(rq->ri > rq->wi) {
/* Read data from tail */
int read = (toread < (rq->length - rq->ri)) ? toread : rq->length - rq->ri;
memcpy(dst, rq->queue + rq->ri, read);
toread -= read;
dst += read;
rq->ri = (rq->ri + read) & (rq->length-1);
}
if(toread) {
/* Read data from head */
memcpy(dst, rq->queue + rq->ri, toread);
rq->ri = (rq->ri + toread) & (rq->length-1);
}
return len;
}
......@@ -194,7 +226,7 @@ int RingQueue_Enqueue(RingQueue_t *rq, const unsigned char *cdata, int n)
if (m > q_avail)
m = q_avail;
memmove(rq->queue + rq->wi, cdata, m);
memcpy(rq->queue + rq->wi, cdata, m);
RING_QUEUE_ADVANCE_INDEX(rq, wi, m);
cdata += m;
enqueued += m;
......@@ -205,24 +237,6 @@ int RingQueue_Enqueue(RingQueue_t *rq, const unsigned char *cdata, int n)
EXPORT_SYMBOL(RingQueue_Enqueue);
int RingQueue_GetLength(const RingQueue_t *rq)
{
int ri, wi;
assert(rq != NULL);
ri = rq->ri;
wi = rq->wi;
if (ri == wi)
return 0;
else if (ri < wi)
return wi - ri;
else
return wi + (rq->length - ri);
}
EXPORT_SYMBOL(RingQueue_GetLength);
static void RingQueue_InterruptibleSleepOn(RingQueue_t *rq)
{
assert(rq != NULL);
......@@ -238,6 +252,16 @@ void RingQueue_WakeUpInterruptible(RingQueue_t *rq)
EXPORT_SYMBOL(RingQueue_WakeUpInterruptible);
void RingQueue_Flush(RingQueue_t *rq)
{
assert(rq != NULL);
rq->ri = 0;
rq->wi = 0;
}
EXPORT_SYMBOL(RingQueue_Flush);
/*
* usbvideo_VideosizeToString()
*
......@@ -266,7 +290,7 @@ static void usbvideo_VideosizeToString(char *buf, int bufLen, videosize_t vs)
* History:
* 01-Feb-2000 Created.
*/
static void usbvideo_OverlayChar(uvd_t *uvd, usbvideo_frame_t *frame,
static void usbvideo_OverlayChar(struct uvd *uvd, usbvideo_frame_t *frame,
int x, int y, int ch)
{
static const unsigned short digits[16] = {
......@@ -321,7 +345,7 @@ static void usbvideo_OverlayChar(uvd_t *uvd, usbvideo_frame_t *frame,
* History:
* 01-Feb-2000 Created.
*/
static void usbvideo_OverlayString(uvd_t *uvd, usbvideo_frame_t *frame,
static void usbvideo_OverlayString(struct uvd *uvd, usbvideo_frame_t *frame,
int x, int y, const char *str)
{
while (*str) {
......@@ -339,7 +363,7 @@ static void usbvideo_OverlayString(uvd_t *uvd, usbvideo_frame_t *frame,
* History:
* 01-Feb-2000 Created.
*/
static void usbvideo_OverlayStats(uvd_t *uvd, usbvideo_frame_t *frame)
static void usbvideo_OverlayStats(struct uvd *uvd, usbvideo_frame_t *frame)
{
const int y_diff = 8;
char tmp[16];
......@@ -374,7 +398,7 @@ static void usbvideo_OverlayStats(uvd_t *uvd, usbvideo_frame_t *frame)
q_used = RingQueue_GetLength(&uvd->dp);
if ((uvd->dp.ri + q_used) >= uvd->dp.length) {
u_hi = uvd->dp.length;
u_lo = (q_used + uvd->dp.ri) % uvd->dp.length;
u_lo = (q_used + uvd->dp.ri) & (uvd->dp.length-1);
} else {
u_hi = (q_used + uvd->dp.ri);
u_lo = -1;
......@@ -462,7 +486,7 @@ static void usbvideo_OverlayStats(uvd_t *uvd, usbvideo_frame_t *frame)
* History:
* 14-Jan-2000 Corrected default multiplier.
*/
static void usbvideo_ReportStatistics(const uvd_t *uvd)
static void usbvideo_ReportStatistics(const struct uvd *uvd)
{
if ((uvd != NULL) && (uvd->stats.urb_count > 0)) {
unsigned long allPackets, badPackets, goodPackets, percent;
......@@ -590,20 +614,19 @@ EXPORT_SYMBOL(usbvideo_DrawLine);
* History:
* 01-Feb-2000 Created.
*/
void usbvideo_TestPattern(uvd_t *uvd, int fullframe, int pmode)
void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode)
{
static const char proc[] = "usbvideo_TestPattern";
usbvideo_frame_t *frame;
int num_cell = 0;
int scan_length = 0;
static int num_pass = 0;
if (uvd == NULL) {
err("%s: uvd == NULL", proc);
err("%s: uvd == NULL", __FUNCTION__);
return;
}
if ((uvd->curframe < 0) || (uvd->curframe >= USBVIDEO_NUMFRAMES)) {
err("%s: uvd->curframe=%d.", proc, uvd->curframe);
err("%s: uvd->curframe=%d.", __FUNCTION__, uvd->curframe);
return;
}
......@@ -707,37 +730,35 @@ EXPORT_SYMBOL(usbvideo_SayAndWait);
/* ******************************************************************** */
static void usbvideo_ClientIncModCount(uvd_t *uvd)
static void usbvideo_ClientIncModCount(struct uvd *uvd)
{
static const char proc[] = "usbvideo_ClientIncModCount";
if (uvd == NULL) {
err("%s: uvd == NULL", proc);
err("%s: uvd == NULL", __FUNCTION__);
return;
}
if (uvd->handle == NULL) {
err("%s: uvd->handle == NULL", proc);
err("%s: uvd->handle == NULL", __FUNCTION__);
return;
}
if (uvd->handle->md_module == NULL) {
err("%s: uvd->handle->md_module == NULL", proc);
err("%s: uvd->handle->md_module == NULL", __FUNCTION__);
return;
}
__MOD_INC_USE_COUNT(uvd->handle->md_module);
}
static void usbvideo_ClientDecModCount(uvd_t *uvd)
static void usbvideo_ClientDecModCount(struct uvd *uvd)
{
static const char proc[] = "usbvideo_ClientDecModCount";
if (uvd == NULL) {
err("%s: uvd == NULL", proc);
err("%s: uvd == NULL", __FUNCTION__);
return;
}
if (uvd->handle == NULL) {
err("%s: uvd->handle == NULL", proc);
err("%s: uvd->handle == NULL", __FUNCTION__);
return;
}
if (uvd->handle->md_module == NULL) {
err("%s: uvd->handle->md_module == NULL", proc);
err("%s: uvd->handle->md_module == NULL", __FUNCTION__);
return;
}
__MOD_DEC_USE_COUNT(uvd->handle->md_module);
......@@ -752,30 +773,29 @@ int usbvideo_register(
struct module *md,
const struct usb_device_id *id_table)
{
static const char proc[] = "usbvideo_register";
usbvideo_t *cams;
int i, base_size;
/* Check parameters for sanity */
if ((num_cams <= 0) || (pCams == NULL) || (cbTbl == NULL)) {
err("%s: Illegal call", proc);
err("%s: Illegal call", __FUNCTION__);
return -EINVAL;
}
/* Check registration callback - must be set! */
if (cbTbl->probe == NULL) {
err("%s: probe() is required!", proc);
err("%s: probe() is required!", __FUNCTION__);
return -EINVAL;
}
base_size = num_cams * sizeof(uvd_t) + sizeof(usbvideo_t);
base_size = num_cams * sizeof(struct uvd) + sizeof(usbvideo_t);
cams = (usbvideo_t *) kmalloc(base_size, GFP_KERNEL);
if (cams == NULL) {
err("Failed to allocate %d. bytes for usbvideo_t", base_size);
return -ENOMEM;
}
dbg("%s: Allocated $%p (%d. bytes) for %d. cameras",
proc, cams, base_size, num_cams);
__FUNCTION__, cams, base_size, num_cams);
memset(cams, 0, base_size);
/* Copy callbacks, apply defaults for those that are not set */
......@@ -807,14 +827,14 @@ int usbvideo_register(
}
#endif
cams->num_cameras = num_cams;
cams->cam = (uvd_t *) &cams[1];
cams->cam = (struct uvd *) &cams[1];
cams->md_module = md;
if (cams->md_module == NULL)
warn("%s: module == NULL!", proc);
warn("%s: module == NULL!", __FUNCTION__);
init_MUTEX(&cams->lock); /* to 1 == available */
for (i = 0; i < num_cams; i++) {
uvd_t *up = &cams->cam[i];
struct uvd *up = &cams->cam[i];
up->handle = cams;
......@@ -825,11 +845,11 @@ int usbvideo_register(
if (up->user_data == NULL) {
up->user_size = 0;
err("%s: Failed to allocate user_data (%d. bytes)",
proc, up->user_size);
__FUNCTION__, up->user_size);
return -ENOMEM;
}
dbg("%s: Allocated cams[%d].user_data=$%p (%d. bytes)",
proc, i, up->user_data, up->user_size);
__FUNCTION__, i, up->user_data, up->user_size);
}
}
......@@ -844,7 +864,7 @@ int usbvideo_register(
#if USES_PROC_FS
if (cams->uses_procfs) {
dbg("%s: Creating /proc filesystem entries.", proc);
dbg("%s: Creating /proc filesystem entries.", __FUNCTION__);
usbvideo_procfs_level1_create(cams);
}
#endif
......@@ -871,33 +891,32 @@ EXPORT_SYMBOL(usbvideo_register);
*/
void usbvideo_Deregister(usbvideo_t **pCams)
{
static const char proc[] = "usbvideo_deregister";
usbvideo_t *cams;
int i;
if (pCams == NULL) {
err("%s: pCams == NULL", proc);
err("%s: pCams == NULL", __FUNCTION__);
return;
}
cams = *pCams;
if (cams == NULL) {
err("%s: cams == NULL", proc);
err("%s: cams == NULL", __FUNCTION__);
return;
}
#if USES_PROC_FS
if (cams->uses_procfs) {
dbg("%s: Deregistering filesystem entries.", proc);
dbg("%s: Deregistering filesystem entries.", __FUNCTION__);
usbvideo_procfs_level1_destroy(cams);
}
#endif
dbg("%s: Deregistering %s driver.", proc, cams->drvName);
dbg("%s: Deregistering %s driver.", __FUNCTION__, cams->drvName);
usb_deregister(&cams->usbdrv);
dbg("%s: Deallocating cams=$%p (%d. cameras)", proc, cams, cams->num_cameras);
dbg("%s: Deallocating cams=$%p (%d. cameras)", __FUNCTION__, cams, cams->num_cameras);
for (i=0; i < cams->num_cameras; i++) {
uvd_t *up = &cams->cam[i];
struct uvd *up = &cams->cam[i];
int warning = 0;
if (up->user_data != NULL) {
......@@ -909,16 +928,16 @@ void usbvideo_Deregister(usbvideo_t **pCams)
}
if (warning) {
err("%s: Warning: user_data=$%p user_size=%d.",
proc, up->user_data, up->user_size);
__FUNCTION__, up->user_data, up->user_size);
} else {
dbg("%s: Freeing %d. $%p->user_data=$%p",
proc, i, up, up->user_data);
__FUNCTION__, i, up, up->user_data);
kfree(up->user_data);
}
}
/* Whole array was allocated in one chunk */
dbg("%s: Freed %d uvd_t structures",
proc, cams->num_cameras);
dbg("%s: Freed %d uvd structures",
__FUNCTION__, cams->num_cameras);
kfree(cams);
*pCams = NULL;
}
......@@ -949,17 +968,16 @@ EXPORT_SYMBOL(usbvideo_Deregister);
*/
static void usbvideo_Disconnect(struct usb_device *dev, void *ptr)
{
static const char proc[] = "usbvideo_Disconnect";
uvd_t *uvd = (uvd_t *) ptr;
struct uvd *uvd = (struct uvd *) ptr;
int i;
if ((dev == NULL) || (uvd == NULL)) {
err("%s($%p,$%p): Illegal call.", proc, dev, ptr);
err("%s($%p,$%p): Illegal call.", __FUNCTION__, dev, ptr);
return;
}
usbvideo_ClientIncModCount(uvd);
if (uvd->debug > 0)
info("%s(%p,%p.)", proc, dev, ptr);
info("%s(%p,%p.)", __FUNCTION__, dev, ptr);
down(&uvd->lock);
uvd->remove_pending = 1; /* Now all ISO data will be ignored */
......@@ -975,10 +993,10 @@ static void usbvideo_Disconnect(struct usb_device *dev, void *ptr)
video_unregister_device(&uvd->vdev);
if (uvd->debug > 0)
info("%s: Video unregistered.", proc);
info("%s: Video unregistered.", __FUNCTION__);
if (uvd->user)
info("%s: In use, disconnect pending.", proc);
info("%s: In use, disconnect pending.", __FUNCTION__);
else
usbvideo_CameraRelease(uvd);
up(&uvd->lock);
......@@ -990,25 +1008,24 @@ static void usbvideo_Disconnect(struct usb_device *dev, void *ptr)
/*
* usbvideo_CameraRelease()
*
* This code does final release of uvd_t. This happens
* This code does final release of uvd. This happens
* after the device is disconnected -and- all clients
* closed their files.
*
* History:
* 27-Jan-2000 Created.
*/
static void usbvideo_CameraRelease(uvd_t *uvd)
static void usbvideo_CameraRelease(struct uvd *uvd)
{
static const char proc[] = "usbvideo_CameraRelease";
if (uvd == NULL) {
err("%s: Illegal call", proc);
err("%s: Illegal call", __FUNCTION__);
return;
}
#if USES_PROC_FS
assert(uvd->handle != NULL);
if (uvd->handle->uses_procfs) {
dbg("%s: Removing /proc/%s/ filesystem entries.", proc, uvd->handle->drvName);
dbg("%s: Removing /proc/%s/ filesystem entries.", __FUNCTION__, uvd->handle->drvName);
usbvideo_procfs_level2_destroy(uvd);
}
#endif
......@@ -1039,7 +1056,7 @@ static int usbvideo_find_struct(usbvideo_t *cams)
}
down(&cams->lock);
for (u = 0; u < cams->num_cameras; u++) {
uvd_t *uvd = &cams->cam[u];
struct uvd *uvd = &cams->cam[u];
if (!uvd->uvd_used) /* This one is free */
{
uvd->uvd_used = 1; /* In use now */
......@@ -1069,10 +1086,10 @@ static struct video_device usbvideo_template = {
.fops = &usbvideo_fops,
};
uvd_t *usbvideo_AllocateDevice(usbvideo_t *cams)
struct uvd *usbvideo_AllocateDevice(usbvideo_t *cams)
{
int i, devnum;
uvd_t *uvd = NULL;
struct uvd *uvd = NULL;
if (cams == NULL) {
err("No usbvideo_t handle?");
......@@ -1120,24 +1137,23 @@ uvd_t *usbvideo_AllocateDevice(usbvideo_t *cams)
EXPORT_SYMBOL(usbvideo_AllocateDevice);
int usbvideo_RegisterVideoDevice(uvd_t *uvd)
int usbvideo_RegisterVideoDevice(struct uvd *uvd)
{
static const char proc[] = "usbvideo_RegisterVideoDevice";
char tmp1[20], tmp2[20]; /* Buffers for printing */
if (uvd == NULL) {
err("%s: Illegal call.", proc);
err("%s: Illegal call.", __FUNCTION__);
return -EINVAL;
}
if (uvd->video_endp == 0) {
info("%s: No video endpoint specified; data pump disabled.", proc);
info("%s: No video endpoint specified; data pump disabled.", __FUNCTION__);
}
if (uvd->paletteBits == 0) {
err("%s: No palettes specified!", proc);
err("%s: No palettes specified!", __FUNCTION__);
return -EINVAL;
}
if (uvd->defaultPalette == 0) {
info("%s: No default palette!", proc);
info("%s: No default palette!", __FUNCTION__);
}
uvd->max_frame_size = VIDEOSIZE_X(uvd->canvas) *
......@@ -1147,17 +1163,17 @@ int usbvideo_RegisterVideoDevice(uvd_t *uvd)
if (uvd->debug > 0) {
info("%s: iface=%d. endpoint=$%02x paletteBits=$%08lx",
proc, uvd->iface, uvd->video_endp, uvd->paletteBits);
__FUNCTION__, uvd->iface, uvd->video_endp, uvd->paletteBits);
}
if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
err("%s: video_register_device failed", proc);
err("%s: video_register_device failed", __FUNCTION__);
return -EPIPE;
}
if (uvd->debug > 1) {
info("%s: video_register_device() successful", proc);
info("%s: video_register_device() successful", __FUNCTION__);
}
if (uvd->dev == NULL) {
err("%s: uvd->dev == NULL", proc);
err("%s: uvd->dev == NULL", __FUNCTION__);
return -EINVAL;
}
......@@ -1170,7 +1186,7 @@ int usbvideo_RegisterVideoDevice(uvd_t *uvd)
if (uvd->handle->uses_procfs) {
if (uvd->debug > 0) {
info("%s: Creating /proc/video/%s/ filesystem entries.",
proc, uvd->handle->drvName);
__FUNCTION__, uvd->handle->drvName);
}
usbvideo_procfs_level2_create(uvd);
}
......@@ -1186,7 +1202,7 @@ EXPORT_SYMBOL(usbvideo_RegisterVideoDevice);
static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma)
{
uvd_t *uvd = file->private_data;
struct uvd *uvd = file->private_data;
unsigned long start = vma->vm_start;
unsigned long size = vma->vm_end-vma->vm_start;
unsigned long page, pos;
......@@ -1230,20 +1246,19 @@ static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma)
*/
static int usbvideo_v4l_open(struct inode *inode, struct file *file)
{
static const char proc[] = "usbvideo_v4l_open";
struct video_device *dev = video_devdata(file);
uvd_t *uvd = (uvd_t *) dev;
struct uvd *uvd = (struct uvd *) dev;
const int sb_size = FRAMES_PER_DESC * uvd->iso_packet_len;
int i, errCode = 0;
if (uvd->debug > 1)
info("%s($%p", proc, dev);
info("%s($%p)", __FUNCTION__, dev);
usbvideo_ClientIncModCount(uvd);
down(&uvd->lock);
if (uvd->user) {
err("%s: Someone tried to open an already opened device!", proc);
err("%s: Someone tried to open an already opened device!", __FUNCTION__);
errCode = -EBUSY;
} else {
/* Clear statistics */
......@@ -1256,10 +1271,10 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file)
/* Allocate memory for the frame buffers */
uvd->fbuf_size = USBVIDEO_NUMFRAMES * uvd->max_frame_size;
uvd->fbuf = usbvideo_rvmalloc(uvd->fbuf_size);
RingQueue_Allocate(&uvd->dp, 128*1024); /* FIXME #define */
RingQueue_Allocate(&uvd->dp, RING_QUEUE_SIZE);
if ((uvd->fbuf == NULL) ||
(!RingQueue_IsAllocated(&uvd->dp))) {
err("%s: Failed to allocate fbuf or dp", proc);
err("%s: Failed to allocate fbuf or dp", __FUNCTION__);
errCode = -ENOMEM;
} else {
/* Allocate all buffers */
......@@ -1305,19 +1320,19 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file)
if (errCode == 0) {
if (VALID_CALLBACK(uvd, setupOnOpen)) {
if (uvd->debug > 1)
info("%s: setupOnOpen callback", proc);
info("%s: setupOnOpen callback", __FUNCTION__);
errCode = GET_CALLBACK(uvd, setupOnOpen)(uvd);
if (errCode < 0) {
err("%s: setupOnOpen callback failed (%d.).",
proc, errCode);
__FUNCTION__, errCode);
} else if (uvd->debug > 1) {
info("%s: setupOnOpen callback successful", proc);
info("%s: setupOnOpen callback successful", __FUNCTION__);
}
}
if (errCode == 0) {
uvd->settingsAdjusted = 0;
if (uvd->debug > 1)
info("%s: Open succeeded.", proc);
info("%s: Open succeeded.", __FUNCTION__);
uvd->user++;
file->private_data = uvd;
}
......@@ -1327,7 +1342,7 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file)
if (errCode != 0)
usbvideo_ClientDecModCount(uvd);
if (uvd->debug > 0)
info("%s: Returning %d.", proc, errCode);
info("%s: Returning %d.", __FUNCTION__, errCode);
return errCode;
}
......@@ -1345,13 +1360,12 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file)
*/
static int usbvideo_v4l_close(struct inode *inode, struct file *file)
{
static const char proc[] = "usbvideo_v4l_close";
struct video_device *dev = file->private_data;
uvd_t *uvd = (uvd_t *) dev;
struct uvd *uvd = (struct uvd *) dev;
int i;
if (uvd->debug > 1)
info("%s($%p)", proc, dev);
info("%s($%p)", __FUNCTION__, dev);
down(&uvd->lock);
GET_CALLBACK(uvd, stopDataPump)(uvd);
......@@ -1378,7 +1392,7 @@ static int usbvideo_v4l_close(struct inode *inode, struct file *file)
usbvideo_ClientDecModCount(uvd);
if (uvd->debug > 1)
info("%s: Completed.", proc);
info("%s: Completed.", __FUNCTION__);
file->private_data = NULL;
return 0;
}
......@@ -1394,7 +1408,7 @@ static int usbvideo_v4l_close(struct inode *inode, struct file *file)
static int usbvideo_v4l_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
{
uvd_t *uvd = file->private_data;
struct uvd *uvd = file->private_data;
if (!CAMERA_IS_OPERATIONAL(uvd))
return -EIO;
......@@ -1444,6 +1458,10 @@ static int usbvideo_v4l_do_ioctl(struct inode *inode, struct file *file,
{
struct video_window *vw = arg;
if(VALID_CALLBACK(uvd, setVideoMode)) {
return GET_CALLBACK(uvd, setVideoMode)(uvd, vw);
}
if (vw->flags)
return -EINVAL;
if (vw->clipcount)
......@@ -1461,8 +1479,8 @@ static int usbvideo_v4l_do_ioctl(struct inode *inode, struct file *file,
vw->x = 0;
vw->y = 0;
vw->width = VIDEOSIZE_X(uvd->canvas);
vw->height = VIDEOSIZE_Y(uvd->canvas);
vw->width = VIDEOSIZE_X(uvd->videosize);
vw->height = VIDEOSIZE_Y(uvd->videosize);
vw->chromakey = 0;
if (VALID_CALLBACK(uvd, getFPS))
vw->flags = GET_CALLBACK(uvd, getFPS)(uvd);
......@@ -1619,8 +1637,7 @@ static int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
static int usbvideo_v4l_read(struct file *file, char *buf,
size_t count, loff_t *ppos)
{
static const char proc[] = "usbvideo_v4l_read";
uvd_t *uvd = file->private_data;
struct uvd *uvd = file->private_data;
int noblock = file->f_flags & O_NONBLOCK;
int frmx = -1, i;
usbvideo_frame_t *frame;
......@@ -1629,7 +1646,7 @@ static int usbvideo_v4l_read(struct file *file, char *buf,
return -EFAULT;
if (uvd->debug >= 1)
info("%s: %d. bytes, noblock=%d.", proc, count, noblock);
info("%s: %d. bytes, noblock=%d.", __FUNCTION__, count, noblock);
down(&uvd->lock);
......@@ -1676,7 +1693,7 @@ static int usbvideo_v4l_read(struct file *file, char *buf,
*/
if (frmx == -1) {
if (uvd->defaultPalette == 0) {
err("%s: No default palette; don't know what to do!", proc);
err("%s: No default palette; don't know what to do!", __FUNCTION__);
count = -EFAULT;
goto read_done;
}
......@@ -1748,7 +1765,7 @@ static int usbvideo_v4l_read(struct file *file, char *buf,
frame->seqRead_Index += count;
if (uvd->debug >= 1) {
err("%s: {copy} count used=%d, new seqRead_Index=%ld",
proc, count, frame->seqRead_Index);
__FUNCTION__, count, frame->seqRead_Index);
}
/* Finally check if the frame is done with and "release" it */
......@@ -1759,7 +1776,7 @@ static int usbvideo_v4l_read(struct file *file, char *buf,
/* Mark it as available to be used again. */
uvd->frame[frmx].frameState = FrameState_Unused;
if (usbvideo_NewFrame(uvd, (frmx + 1) % USBVIDEO_NUMFRAMES)) {
err("%s: usbvideo_NewFrame failed.", proc);
err("%s: usbvideo_NewFrame failed.", __FUNCTION__);
}
}
read_done:
......@@ -1770,7 +1787,7 @@ static int usbvideo_v4l_read(struct file *file, char *buf,
/*
* Make all of the blocks of data contiguous
*/
static int usbvideo_CompressIsochronous(uvd_t *uvd, struct urb *urb)
static int usbvideo_CompressIsochronous(struct uvd *uvd, struct urb *urb)
{
char *cdata;
int i, totlen = 0;
......@@ -1803,7 +1820,7 @@ static int usbvideo_CompressIsochronous(uvd_t *uvd, struct urb *urb)
static void usbvideo_IsocIrq(struct urb *urb)
{
int i, ret, len;
uvd_t *uvd = urb->context;
struct uvd *uvd = urb->context;
/* We don't want to do anything if we are about to be removed! */
if (!CAMERA_IS_OPERATIONAL(uvd))
......@@ -1860,17 +1877,16 @@ static void usbvideo_IsocIrq(struct urb *urb)
* of hardcoded values. Simplified by using for loop,
* allowed any number of URBs.
*/
static int usbvideo_StartDataPump(uvd_t *uvd)
static int usbvideo_StartDataPump(struct uvd *uvd)
{
static const char proc[] = "usbvideo_StartDataPump";
struct usb_device *dev = uvd->dev;
int i, errFlag;
if (uvd->debug > 1)
info("%s($%p)", proc, uvd);
info("%s($%p)", __FUNCTION__, uvd);
if (!CAMERA_IS_OPERATIONAL(uvd)) {
err("%s: Camera is not operational",proc);
err("%s: Camera is not operational", __FUNCTION__);
return -EFAULT;
}
uvd->curframe = -1;
......@@ -1878,14 +1894,14 @@ static int usbvideo_StartDataPump(uvd_t *uvd)
/* Alternate interface 1 is is the biggest frame size */
i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive);
if (i < 0) {
err("%s: usb_set_interface error", proc);
err("%s: usb_set_interface error", __FUNCTION__);
uvd->last_error = i;
return -EBUSY;
}
if (VALID_CALLBACK(uvd, videoStart))
GET_CALLBACK(uvd, videoStart)(uvd);
else
err("%s: videoStart not set", proc);
err("%s: videoStart not set", __FUNCTION__);
/* We double buffer the Iso lists */
for (i=0; i < USBVIDEO_NUMSBUF; i++) {
......@@ -1910,12 +1926,12 @@ static int usbvideo_StartDataPump(uvd_t *uvd)
for (i=0; i < USBVIDEO_NUMSBUF; i++) {
errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
if (errFlag)
err("%s: usb_submit_isoc(%d) ret %d", proc, i, errFlag);
err("%s: usb_submit_isoc(%d) ret %d", __FUNCTION__, i, errFlag);
}
uvd->streaming = 1;
if (uvd->debug > 1)
info("%s: streaming=1 video_endp=$%02x", proc, uvd->video_endp);
info("%s: streaming=1 video_endp=$%02x", __FUNCTION__, uvd->video_endp);
return 0;
}
......@@ -1929,13 +1945,12 @@ static int usbvideo_StartDataPump(uvd_t *uvd)
* 22-Jan-2000 Corrected order of actions to work after surprise removal.
* 27-Jan-2000 Used uvd->iface, uvd->ifaceAltInactive instead of hardcoded values.
*/
static void usbvideo_StopDataPump(uvd_t *uvd)
static void usbvideo_StopDataPump(struct uvd *uvd)
{
static const char proc[] = "usbvideo_StopDataPump";
int i, j;
if (uvd->debug > 1)
info("%s($%p)", proc, uvd);
info("%s($%p)", __FUNCTION__, uvd);
if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
return;
......@@ -1944,10 +1959,10 @@ static void usbvideo_StopDataPump(uvd_t *uvd)
for (i=0; i < USBVIDEO_NUMSBUF; i++) {
j = usb_unlink_urb(uvd->sbuf[i].urb);
if (j < 0)
err("%s: usb_unlink_urb() error %d.", proc, j);
err("%s: usb_unlink_urb() error %d.", __FUNCTION__, j);
}
if (uvd->debug > 1)
info("%s: streaming=0", proc);
info("%s: streaming=0", __FUNCTION__);
uvd->streaming = 0;
if (!uvd->remove_pending) {
......@@ -1955,12 +1970,12 @@ static void usbvideo_StopDataPump(uvd_t *uvd)
if (VALID_CALLBACK(uvd, videoStop))
GET_CALLBACK(uvd, videoStop)(uvd);
else
err("%s: videoStop not set" ,proc);
err("%s: videoStop not set", __FUNCTION__);
/* Set packet size to 0 */
j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive);
if (j < 0) {
err("%s: usb_set_interface() error %d.", proc, j);
err("%s: usb_set_interface() error %d.", __FUNCTION__, j);
uvd->last_error = j;
}
}
......@@ -1973,7 +1988,7 @@ static void usbvideo_StopDataPump(uvd_t *uvd)
* 29-Mar-00 Added copying of previous frame into the current one.
* 6-Aug-00 Added model 3 video sizes, removed redundant width, height.
*/
static int usbvideo_NewFrame(uvd_t *uvd, int framenum)
static int usbvideo_NewFrame(struct uvd *uvd, int framenum)
{
usbvideo_frame_t *frame;
int n;
......@@ -2049,7 +2064,7 @@ static int usbvideo_NewFrame(uvd_t *uvd, int framenum)
* FLAGS_NO_DECODING set. Therefore, any regular build of any driver
* based on usbvideo can use this feature at any time.
*/
static void usbvideo_CollectRawData(uvd_t *uvd, usbvideo_frame_t *frame)
static void usbvideo_CollectRawData(struct uvd *uvd, usbvideo_frame_t *frame)
{
int n;
......@@ -2079,18 +2094,17 @@ static void usbvideo_CollectRawData(uvd_t *uvd, usbvideo_frame_t *frame)
}
}
static int usbvideo_GetFrame(uvd_t *uvd, int frameNum)
static int usbvideo_GetFrame(struct uvd *uvd, int frameNum)
{
static const char proc[] = "usbvideo_GetFrame";
usbvideo_frame_t *frame = &uvd->frame[frameNum];
if (uvd->debug >= 2)
info("%s($%p,%d.)", proc, uvd, frameNum);
info("%s($%p,%d.)", __FUNCTION__, uvd, frameNum);
switch (frame->frameState) {
case FrameState_Unused:
if (uvd->debug >= 2)
info("%s: FrameState_Unused", proc);
info("%s: FrameState_Unused", __FUNCTION__);
return -EINVAL;
case FrameState_Ready:
case FrameState_Grabbing:
......@@ -2100,7 +2114,7 @@ static int usbvideo_GetFrame(uvd_t *uvd, int frameNum)
redo:
if (!CAMERA_IS_OPERATIONAL(uvd)) {
if (uvd->debug >= 2)
info("%s: Camera is not operational (1)", proc);
info("%s: Camera is not operational (1)", __FUNCTION__);
return -EIO;
}
ntries = 0;
......@@ -2109,24 +2123,24 @@ static int usbvideo_GetFrame(uvd_t *uvd, int frameNum)
signalPending = signal_pending(current);
if (!CAMERA_IS_OPERATIONAL(uvd)) {
if (uvd->debug >= 2)
info("%s: Camera is not operational (2)", proc);
info("%s: Camera is not operational (2)", __FUNCTION__);
return -EIO;
}
assert(uvd->fbuf != NULL);
if (signalPending) {
if (uvd->debug >= 2)
info("%s: Signal=$%08x", proc, signalPending);
info("%s: Signal=$%08x", __FUNCTION__, signalPending);
if (uvd->flags & FLAGS_RETRY_VIDIOCSYNC) {
usbvideo_TestPattern(uvd, 1, 0);
uvd->curframe = -1;
uvd->stats.frame_num++;
if (uvd->debug >= 2)
info("%s: Forced test pattern screen", proc);
info("%s: Forced test pattern screen", __FUNCTION__);
return 0;
} else {
/* Standard answer: Interrupted! */
if (uvd->debug >= 2)
info("%s: Interrupted!", proc);
info("%s: Interrupted!", __FUNCTION__);
return -EINTR;
}
} else {
......@@ -2136,17 +2150,17 @@ static int usbvideo_GetFrame(uvd_t *uvd, int frameNum)
else if (VALID_CALLBACK(uvd, processData))
GET_CALLBACK(uvd, processData)(uvd, frame);
else
err("%s: processData not set", proc);
err("%s: processData not set", __FUNCTION__);
}
} while (frame->frameState == FrameState_Grabbing);
if (uvd->debug >= 2) {
info("%s: Grabbing done; state=%d. (%lu. bytes)",
proc, frame->frameState, frame->seqRead_Length);
__FUNCTION__, frame->frameState, frame->seqRead_Length);
}
if (frame->frameState == FrameState_Error) {
int ret = usbvideo_NewFrame(uvd, frameNum);
if (ret < 0) {
err("%s: usbvideo_NewFrame() failed (%d.)", proc, ret);
err("%s: usbvideo_NewFrame() failed (%d.)", __FUNCTION__, ret);
return ret;
}
goto redo;
......@@ -2178,7 +2192,7 @@ static int usbvideo_GetFrame(uvd_t *uvd, int frameNum)
}
frame->frameState = FrameState_Done_Hold;
if (uvd->debug >= 2)
info("%s: Entered FrameState_Done_Hold state.", proc);
info("%s: Entered FrameState_Done_Hold state.", __FUNCTION__);
return 0;
case FrameState_Done_Hold:
......@@ -2189,12 +2203,12 @@ static int usbvideo_GetFrame(uvd_t *uvd, int frameNum)
* it will be released back into the wild to roam freely.
*/
if (uvd->debug >= 2)
info("%s: FrameState_Done_Hold state.", proc);
info("%s: FrameState_Done_Hold state.", __FUNCTION__);
return 0;
}
/* Catch-all for other cases. We shall not be here. */
err("%s: Invalid state %d.", proc, frame->frameState);
err("%s: Invalid state %d.", __FUNCTION__, frame->frameState);
frame->frameState = FrameState_Unused;
return 0;
}
......@@ -2212,7 +2226,7 @@ static int usbvideo_GetFrame(uvd_t *uvd, int frameNum)
* line above then we just copy next line. Similarly, if we need to
* create a last line then preceding line is used.
*/
void usbvideo_DeinterlaceFrame(uvd_t *uvd, usbvideo_frame_t *frame)
void usbvideo_DeinterlaceFrame(struct uvd *uvd, usbvideo_frame_t *frame)
{
if ((uvd == NULL) || (frame == NULL))
return;
......@@ -2282,16 +2296,15 @@ EXPORT_SYMBOL(usbvideo_DeinterlaceFrame);
* History:
* 09-Feb-2001 Created.
*/
static void usbvideo_SoftwareContrastAdjustment(uvd_t *uvd,
static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd,
usbvideo_frame_t *frame)
{
static const char proc[] = "usbvideo_SoftwareContrastAdjustment";
int i, j, v4l_linesize;
signed long adj;
const int ccm = 128; /* Color correction median - see below */
if ((uvd == NULL) || (frame == NULL)) {
err("%s: Illegal call.", proc);
err("%s: Illegal call.", __FUNCTION__);
return;
}
adj = (uvd->vpic.contrast - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
......@@ -2343,14 +2356,12 @@ extern struct proc_dir_entry *video_proc_entry;
static void usbvideo_procfs_level1_create(usbvideo_t *ut)
{
static const char proc[] = "usbvideo_procfs_level1_create";
if (ut == NULL) {
err("%s: ut == NULL", proc);
err("%s: ut == NULL", __FUNCTION__);
return;
}
if (video_proc_entry == NULL) {
err("%s: /proc/video/ doesn't exist.", proc);
err("%s: /proc/video/ doesn't exist.", __FUNCTION__);
return;
}
ut->procfs_dEntry = create_proc_entry(ut->drvName, S_IFDIR, video_proc_entry);
......@@ -2358,16 +2369,14 @@ static void usbvideo_procfs_level1_create(usbvideo_t *ut)
if (ut->md_module != NULL)
ut->procfs_dEntry->owner = ut->md_module;
} else {
err("%s: Unable to initialize /proc/video/%s", proc, ut->drvName);
err("%s: Unable to initialize /proc/video/%s", __FUNCTION__, ut->drvName);
}
}
static void usbvideo_procfs_level1_destroy(usbvideo_t *ut)
{
static const char proc[] = "usbvideo_procfs_level1_destroy";
if (ut == NULL) {
err("%s: ut == NULL", proc);
err("%s: ut == NULL", __FUNCTION__);
return;
}
if (ut->procfs_dEntry != NULL) {
......@@ -2376,17 +2385,15 @@ static void usbvideo_procfs_level1_destroy(usbvideo_t *ut)
}
}
static void usbvideo_procfs_level2_create(uvd_t *uvd)
static void usbvideo_procfs_level2_create(struct uvd *uvd)
{
static const char proc[] = "usbvideo_procfs_level2_create";
if (uvd == NULL) {
err("%s: uvd == NULL", proc);
err("%s: uvd == NULL", __FUNCTION__);
return;
}
assert(uvd->handle != NULL);
if (uvd->handle->procfs_dEntry == NULL) {
err("%s: uvd->handle->procfs_dEntry == NULL", proc);
err("%s: uvd->handle->procfs_dEntry == NULL", __FUNCTION__);
return;
}
......@@ -2400,16 +2407,14 @@ static void usbvideo_procfs_level2_create(uvd_t *uvd)
uvd->procfs_vEntry->read_proc = uvd->handle->cb.procfs_read;
uvd->procfs_vEntry->write_proc = uvd->handle->cb.procfs_write;
} else {
err("%s: Failed to create entry \"%s\"", proc, uvd->videoName);
err("%s: Failed to create entry \"%s\"", __FUNCTION__, uvd->videoName);
}
}
static void usbvideo_procfs_level2_destroy(uvd_t *uvd)
static void usbvideo_procfs_level2_destroy(struct uvd *uvd)
{
static const char proc[] = "usbvideo_procfs_level2_destroy";
if (uvd == NULL) {
err("%s: uvd == NULL", proc);
err("%s: uvd == NULL", __FUNCTION__);
return;
}
if (uvd->procfs_vEntry != NULL) {
......
......@@ -113,9 +113,10 @@ typedef unsigned long videosize_t;
mr = LIMIT_RGB(mm_r); \
}
#define RING_QUEUE_ADVANCE_INDEX(rq,ind,n) (rq)->ind = ((rq)->ind + (n)) % (rq)->length
#define RING_QUEUE_SIZE (128*1024) /* Must be a power of 2 */
#define RING_QUEUE_ADVANCE_INDEX(rq,ind,n) (rq)->ind = ((rq)->ind + (n)) & ((rq)->length-1)
#define RING_QUEUE_DEQUEUE_BYTES(rq,n) RING_QUEUE_ADVANCE_INDEX(rq,ri,n)
#define RING_QUEUE_PEEK(rq,ofs) ((rq)->queue[((ofs) + (rq)->ri) % (rq)->length])
#define RING_QUEUE_PEEK(rq,ofs) ((rq)->queue[((ofs) + (rq)->ri) & ((rq)->length-1)])
typedef struct {
unsigned char *queue; /* Data from the Isoc data pump */
......@@ -202,7 +203,7 @@ typedef struct {
struct s_usbvideo_t;
typedef struct {
struct uvd {
struct video_device vdev; /* Must be the first field! */
struct usb_device *dev;
struct s_usbvideo_t *handle; /* Points back to the usbvideo_t */
......@@ -247,7 +248,7 @@ typedef struct {
usbvideo_statistics_t stats;
struct proc_dir_entry *procfs_vEntry; /* /proc/video/MYDRIVER/video2 */
char videoName[32]; /* Holds name like "video7" */
} uvd_t;
};
/*
* usbvideo callbacks (virtual methods). They are set when usbvideo
......@@ -256,21 +257,22 @@ typedef struct {
*/
typedef struct {
void *(*probe)(struct usb_device *, unsigned int,const struct usb_device_id *);
void (*userFree)(uvd_t *);
void (*userFree)(struct uvd *);
void (*disconnect)(struct usb_device *, void *);
int (*setupOnOpen)(uvd_t *);
void (*videoStart)(uvd_t *);
void (*videoStop)(uvd_t *);
void (*processData)(uvd_t *, usbvideo_frame_t *);
void (*postProcess)(uvd_t *, usbvideo_frame_t *);
void (*adjustPicture)(uvd_t *);
int (*getFPS)(uvd_t *);
int (*overlayHook)(uvd_t *, usbvideo_frame_t *);
int (*getFrame)(uvd_t *, int);
int (*setupOnOpen)(struct uvd *);
void (*videoStart)(struct uvd *);
void (*videoStop)(struct uvd *);
void (*processData)(struct uvd *, usbvideo_frame_t *);
void (*postProcess)(struct uvd *, usbvideo_frame_t *);
void (*adjustPicture)(struct uvd *);
int (*getFPS)(struct uvd *);
int (*overlayHook)(struct uvd *, usbvideo_frame_t *);
int (*getFrame)(struct uvd *, int);
int (*procfs_read)(char *page,char **start,off_t off,int count,int *eof,void *data);
int (*procfs_write)(struct file *file,const char *buffer,unsigned long count,void *data);
int (*startDataPump)(uvd_t *uvd);
void (*stopDataPump)(uvd_t *uvd);
int (*startDataPump)(struct uvd *uvd);
void (*stopDataPump)(struct uvd *uvd);
int (*setVideoMode)(struct uvd *uvd, struct video_window *vw);
} usbvideo_cb_t;
struct s_usbvideo_t {
......@@ -280,7 +282,7 @@ struct s_usbvideo_t {
struct semaphore lock; /* Mutex protecting camera structures */
usbvideo_cb_t cb; /* Table of callbacks (virtual methods) */
struct video_device vdt; /* Video device template */
uvd_t *cam; /* Array of camera structures */
struct uvd *cam; /* Array of camera structures */
int uses_procfs; /* Non-zero if we create /proc entries */
struct proc_dir_entry *procfs_dEntry; /* /proc/video/MYDRIVER */
struct module *md_module; /* Minidriver module */
......@@ -288,7 +290,7 @@ struct s_usbvideo_t {
typedef struct s_usbvideo_t usbvideo_t;
/*
* This macro retrieves callback address from the uvd_t object.
* This macro retrieves callback address from the struct uvd object.
* No validity checks are done here, so be sure to check the
* callback beforehand with VALID_CALLBACK.
*/
......@@ -306,8 +308,18 @@ typedef struct s_usbvideo_t usbvideo_t;
int RingQueue_Dequeue(RingQueue_t *rq, unsigned char *dst, int len);
int RingQueue_Enqueue(RingQueue_t *rq, const unsigned char *cdata, int n);
int RingQueue_GetLength(const RingQueue_t *rq);
void RingQueue_WakeUpInterruptible(RingQueue_t *rq);
void RingQueue_Flush(RingQueue_t *rq);
static inline int RingQueue_GetLength(const RingQueue_t *rq)
{
return (rq->wi - rq->ri + rq->length) & (rq->length-1);
}
static inline int RingQueue_GetFreeSpace(const RingQueue_t *rq)
{
return rq->length - RingQueue_GetLength(rq);
}
void usbvideo_DrawLine(
usbvideo_frame_t *frame,
......@@ -316,7 +328,7 @@ void usbvideo_DrawLine(
unsigned char cr, unsigned char cg, unsigned char cb);
void usbvideo_HexDump(const unsigned char *data, int len);
void usbvideo_SayAndWait(const char *what);
void usbvideo_TestPattern(uvd_t *uvd, int fullframe, int pmode);
void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode);
/* Memory allocation routines */
unsigned long usbvideo_kvirt_to_pa(unsigned long adr);
......@@ -329,13 +341,13 @@ int usbvideo_register(
const usbvideo_cb_t *cbTable,
struct module *md,
const struct usb_device_id *id_table);
uvd_t *usbvideo_AllocateDevice(usbvideo_t *cams);
int usbvideo_RegisterVideoDevice(uvd_t *uvd);
struct uvd *usbvideo_AllocateDevice(usbvideo_t *cams);
int usbvideo_RegisterVideoDevice(struct uvd *uvd);
void usbvideo_Deregister(usbvideo_t **uvt);
int usbvideo_v4l_initialize(struct video_device *dev);
void usbvideo_DeinterlaceFrame(uvd_t *uvd, usbvideo_frame_t *frame);
void usbvideo_DeinterlaceFrame(struct uvd *uvd, usbvideo_frame_t *frame);
/*
* This code performs bounds checking - use it when working with
......
......@@ -84,3 +84,31 @@ CONFIG_USB_USS720
inserted in and removed from the running kernel whenever you want).
The module will be called uss720.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_USB_SPEEDTCH
This driver provides support for the Alcatel SpeedTouch ADSL USB
modem.
The driver requires the ATM interface and ATM SAR so you need to
enable ATM (under Networking options) and the ATM SAR option. You
will also need PPP over ATM (under Network device support).
This driver is a slightly revised version of Johan Verrept's 1.5
SpeedTouch Driver which has been altered to work on the 2.5 series
kernels.
To use the device you also need a user-mode daemon that downloads
the firmware and (re)initializes the modem. The offical version is
a closed source one from Alcatel that you can get at
<http://www.alcateldsl.com/support.htm>.
A piece of code has recently been sent to linux-usb-devel which
allows the open source user space driver's firmware program
modem_run to be used with this driver instead. You will still
need the Alcatel daemon package to extract the modem firmware from
it (or the windows drivers instead).
For more information, see Johan Verrept's webpages at
<http://linux-usb.sourceforge.net/SpeedTouch/>.
#
# USB Miscellaneous driver configuration
#
comment 'USB Miscellaneous drivers'
dep_tristate ' EMI 2|6 USB Audio interface support' CONFIG_USB_EMI26 $CONFIG_USB_AUDIO
dep_tristate ' Texas Instruments Graph Link USB (aka SilverLink) cable support' CONFIG_USB_TIGL $CONFIG_USB
dep_tristate ' USB Auerswald ISDN support (EXPERIMENTAL)' CONFIG_USB_AUERSWALD $CONFIG_USB $CONFIG_EXPERIMENTAL
dep_tristate ' USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB $CONFIG_EXPERIMENTAL
dep_tristate ' Tieman Voyager USB Braille display support (EXPERIMENTAL)' CONFIG_USB_BRLVGER $CONFIG_USB $CONFIG_EXPERIMENTAL
dep_tristate ' USB LCD driver support' CONFIG_USB_LCD $CONFIG_USB
dep_tristate ' Alcatel Speedtouch ADSL USB Modem' CONFIG_USB_SPEEDTOUCH $CONFIG_USB
......@@ -3,10 +3,14 @@
# (the ones that don't fit into any other categories)
#
export-objs := atmsar.o
obj-$(CONFIG_USB_AUERSWALD) += auerswald.o
obj-$(CONFIG_USB_BRLVGER) += brlvger.o
obj-$(CONFIG_USB_EMI26) += emi26.o
obj-$(CONFIG_USB_LCD) += usblcd.o
obj-$(CONFIG_USB_RIO500) += rio500.o
obj-$(CONFIG_USB_SPEEDTOUCH) += speedtouch.o atmsar.o
obj-$(CONFIG_USB_TIGL) += tiglusb.o
obj-$(CONFIG_USB_USS720) += uss720.o
......
/*
* General SAR library for ATM devices.
*
* Written By Johan Verrept ( Johan.Verrept@advalvas.be )
*
* Copyright (c) 2000, Johan Verrept
*
* This code falls under the GNU General Public License, see COPYING for details
*
* This package is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Version 0.2.4A:
- Version for inclusion in 2.5 series kernel
- Modifcations by Richard Purdie (rpurdie@rpsys.net)
- replaced "sarlib" with "atmsar"
- adaptations for inclusion in kernel tree
Version 0.2.4:
- Fixed wrong buffer overrun check in atmsar_decode_rawcell()
reported by Stephen Robinson <stephen.robinson@zen.co.uk>
- Fixed bug when input skb did not contain a multple of 52/53 bytes.
(would happen when the speedtouch device resynced)
also reported by Stephen Robinson <stephen.robinson@zen.co.uk>
Version 0.2.3:
- Fixed wrong allocation size. caused memory corruption in some
cases. Reported by Vladimir Dergachev <volodya@mindspring.com>
- Added some comments
Version 0.2.2:
- Fixed CRCASM (patch from Linus Flannagan <linusf@netservices.eng.net>)
- Fixed problem when user did NOT use the ATMSAR_USE_53BYTE_CELL flag.
(reported by Piers Scannell <email@lot105.com> )
- No more in-buffer rewriting for cloned buffers.
- Removed the PII specific CFLAGS in the Makefile.
Version 0.2.1:
- removed dependancy on alloc_tx. tis presented problems when using
this with the br2684 code.
Version 0.2:
- added AAL0 reassembly
- added alloc_tx support
- replaced alloc_skb in decode functions to dev_alloc_skb to allow
calling from interrupt
- fixed embarassing AAL5 bug. I was setting the pti bit in the wrong
byte...
- fixed another emabrassing bug.. picked up the wrong crc type and
forgot to invert the crc result...
- fixed AAL5 length calculations.
- removed automatic skb freeing from encode functions.
This caused problems because i did kfree_skb it, while it
needed to be popped. I cannot determine though whether it
needs to be popped or not. Figu'e it out ye'self ;-)
- added mru field. This is the buffersize. atmsar_decode_aal0 will
use when it allocates a receive buffer. A stop gap for real
buffer management.
Version 0.1:
- library created.
- only contains AAL5, AAL0 can be easily added. ( actually, only
AAL0 reassembly is missing)
*/
#include "atmsar.h"
#include <linux/module.h>
#include <linux/init.h>
#define DRIVER_AUTHOR "Johan Verrept, Johan.Verrept@advalvas.be"
#define DRIVER_DESC "General SAR library for ATM devices"
#define DRIVER_VERSION "0.2.4A"
/***********************
**
** things to remember
**
***********************/
/*
1. the atmsar_vcc_data list pointer MUST be initialized to NULL
2. atmsar_encode_rawcell will drop incomplete cells.
3. ownership of the skb goes to the library !
*/
#define ATM_HDR_VPVC_MASK (ATM_HDR_VPI_MASK | ATM_HDR_VCI_MASK)
/***********************
**
** LOCAL STRUCTURES
**
***********************/
/***********************
**
** LOCAL MACROS
**
***********************/
/*
#define DEBUG 1
*/
#ifdef DEBUG
#define PDEBUG(arg...) printk(KERN_DEBUG "atmsar: " arg)
#else
#define PDEBUG(arg...)
#endif
#define ADD_HEADER(dest, header) \
*dest++ = (unsigned char) (header >> 24); \
*dest++ = (unsigned char) (header >> 16); \
*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);
/* initialiation 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;
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 interurpt 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;
new->gfc = gfc;
new->vp = vpi;
new->vc = vci;
new->pti = pti;
switch (type) {
case ATMSAR_TYPE_AAL0:
new->mtu = ATMSAR_DEF_MTU_AAL0;
break;
case ATMSAR_TYPE_AAL1:
new->mtu = ATMSAR_DEF_MTU_AAL1;
break;
case ATMSAR_TYPE_AAL2:
new->mtu = ATMSAR_DEF_MTU_AAL2;
break;
case ATMSAR_TYPE_AAL34:
/* not supported */
new->mtu = ATMSAR_DEF_MTU_AAL34;
break;
case ATMSAR_TYPE_AAL5:
new->mtu = ATMSAR_DEF_MTU_AAL5;
break;
}
new->atmHeader = ((unsigned long) gfc << ATM_HDR_GFC_SHIFT)
| ((unsigned long) vpi << ATM_HDR_VPI_SHIFT)
| ((unsigned long) vci << ATM_HDR_VCI_SHIFT)
| ((unsigned long) pti << ATM_HDR_PTI_SHIFT);
new->flags = flags;
new->next = NULL;
new->reasBuffer = NULL;
new->next = *list;
*list = new;
PDEBUG ("Allocated new SARLib vcc 0x%p with vp %d vc %d\n", new, vpi, vci);
return new;
}
void atmsar_close (struct atmsar_vcc_data **list, struct atmsar_vcc_data *vcc)
{
struct atmsar_vcc_data *work;
if (*list == vcc) {
*list = (*list)->next;
} else {
for (work = *list; work && work->next && (work->next != vcc); work = work->next);
/* return if not found */
if (work->next != vcc)
return;
work->next = work->next->next;
}
if (vcc->reasBuffer) {
dev_kfree_skb (vcc->reasBuffer);
}
PDEBUG ("Allocated SARLib vcc 0x%p with vp %d vc %d\n", vcc, vcc->vp, vcc->vc);
kfree (vcc);
}
/***********************
**
** ENCODE FUNCTIONS
**
***********************/
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;
}
/***********************
**
** DECODE FUNCTIONS
**
***********************/
struct sk_buff *atmsar_decode_rawcell (struct atmsar_vcc_data *list, struct sk_buff *skb,
struct atmsar_vcc_data **ctx)
{
while (skb->len) {
unsigned char *cell = skb->data;
unsigned char *cell_payload;
struct atmsar_vcc_data *vcc = list;
unsigned long atmHeader =
((unsigned long) (cell[0]) << 24) | ((unsigned long) (cell[1]) << 16) |
((unsigned long) (cell[2]) << 8) | (cell[3] & 0xff);
PDEBUG ("atmsar_decode_rawcell (0x%p, 0x%p, 0x%p) called\n", list, skb, ctx);
PDEBUG ("atmsar_decode_rawcell skb->data %p, skb->tail %p\n", skb->data, skb->tail);
if (!list || !skb || !ctx)
return NULL;
if (!skb->data || !skb->tail)
return NULL;
/* here should the header CRC check be... */
/* look up correct vcc */
for (;
vcc
&& ((vcc->atmHeader & ATM_HDR_VPVC_MASK) != (atmHeader & ATM_HDR_VPVC_MASK));
vcc = vcc->next);
PDEBUG ("atmsar_decode_rawcell found vcc %p for packet on vp %d, vc %d\n", vcc,
(int) ((atmHeader & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT),
(int) ((atmHeader & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT));
if (vcc && (skb->len >= (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52))) {
cell_payload = cell + (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 5 : 4);
switch (vcc->type) {
case ATMSAR_TYPE_AAL0:
/* case ATMSAR_TYPE_AAL1: when we have a decode AAL1 function... */
{
struct sk_buff *tmp = dev_alloc_skb (vcc->mtu);
if (tmp) {
memcpy (tmp->tail, cell_payload, 48);
skb_put (tmp, 48);
if (vcc->stats)
atomic_inc (&vcc->stats->rx);
skb_pull (skb,
(vcc->
flags & ATMSAR_USE_53BYTE_CELL ? 53 :
52));
PDEBUG
("atmsar_decode_rawcell returns ATMSAR_TYPE_AAL0 pdu 0x%p with length %d\n",
tmp, tmp->len);
return tmp;
};
}
break;
case ATMSAR_TYPE_AAL1:
case ATMSAR_TYPE_AAL2:
case ATMSAR_TYPE_AAL34:
/* not supported */
break;
case ATMSAR_TYPE_AAL5:
if (!vcc->reasBuffer)
vcc->reasBuffer = dev_alloc_skb (vcc->mtu);
/* if alloc fails, we just drop the cell. it is possible that we can still
* receive cells on other vcc's
*/
if (vcc->reasBuffer) {
/* if (buffer overrun) discard received cells until now */
if ((vcc->reasBuffer->len) > (vcc->mtu - 48))
skb_trim (vcc->reasBuffer, 0);
/* copy data */
memcpy (vcc->reasBuffer->tail, cell_payload, 48);
skb_put (vcc->reasBuffer, 48);
/* check for end of buffer */
if (cell[3] & 0x2) {
struct sk_buff *tmp;
/* the aal5 buffer ends here, cut the buffer. */
/* buffer will always have at least one whole cell, so */
/* don't need to check return from skb_pull */
skb_pull (skb,
(vcc->
flags & ATMSAR_USE_53BYTE_CELL ? 53 :
52));
*ctx = vcc;
tmp = vcc->reasBuffer;
vcc->reasBuffer = NULL;
PDEBUG
("atmsar_decode_rawcell returns ATMSAR_TYPE_AAL5 pdu 0x%p with length %d\n",
tmp, tmp->len);
return tmp;
}
}
break;
};
/* flush the cell */
/* buffer will always contain at least one whole cell, so don't */
/* need to check return value from skb_pull */
skb_pull (skb, (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52));
} else {
/* If data is corrupt and skb doesn't hold a whole cell, flush the lot */
if (skb_pull (skb, (list->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52)) ==
NULL) {
skb_trim (skb, 0);
}
}
}
return NULL;
};
struct sk_buff *atmsar_decode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff *skb)
{
uint crc = 0xffffffff;
uint length, pdu_crc, pdu_length;
PDEBUG ("atmsar_decode_aal5 (0x%p, 0x%p) called\n", ctx, skb);
if (skb->len && (skb->len % 48))
return NULL;
length = (skb->tail[-6] << 8) + skb->tail[-5];
pdu_crc =
(skb->tail[-4] << 24) + (skb->tail[-3] << 16) + (skb->tail[-2] << 8) + skb->tail[-1];
pdu_length = ((length + 47 + 8) / 48) * 48;
PDEBUG ("atmsar_decode_aal5: skb->len = %d, length = %d, pdu_crc = 0x%x, pdu_length = %d\n",
skb->len, length, pdu_crc, pdu_length);
/* is skb long enough ? */
if (skb->len < pdu_length) {
if (ctx->stats)
atomic_inc (&ctx->stats->rx_err);
return NULL;
}
/* is skb too long ? */
if (skb->len > pdu_length) {
PDEBUG ("atmsar_decode_aal5: Warning: readjusting illeagl size %d -> %d\n",
skb->len, pdu_length);
/* buffer is too long. we can try to recover
* if we discard the first part of the skb.
* the crc will decide whether this was ok
*/
skb_pull (skb, skb->len - pdu_length);
}
crc = ~crc32 (crc, skb->data, pdu_length - 4);
/* check crc */
if (pdu_crc != crc) {
PDEBUG ("atmsar_decode_aal5: crc check failed!\n");
if (ctx->stats)
atomic_inc (&ctx->stats->rx_err);
return NULL;
}
/* pdu is ok */
skb_trim (skb, length);
/* update stats */
if (ctx->stats)
atomic_inc (&ctx->stats->rx);
PDEBUG ("atmsar_decode_aal5 returns pdu 0x%p with length %d\n", skb, skb->len);
return skb;
};
static int start (void)
{
return 0;
}
static void cleanup (void)
{
}
module_init (start);
module_exit (cleanup);
EXPORT_SYMBOL (atmsar_open);
EXPORT_SYMBOL (atmsar_close);
EXPORT_SYMBOL (atmsar_encode_rawcell);
EXPORT_SYMBOL (atmsar_encode_aal5);
EXPORT_SYMBOL (atmsar_decode_rawcell);
EXPORT_SYMBOL (atmsar_decode_aal5);
EXPORT_SYMBOL (atmsar_alloc_tx);
MODULE_AUTHOR (DRIVER_AUTHOR);
MODULE_DESCRIPTION (DRIVER_DESC);
MODULE_LICENSE ("GPL");
/*
*
* General SAR library for ATM devices.
*
* Copyright (c) 2000, Johan Verrept
*
* This code falls under the GNU General Public License, see COPYING for details.
*
*/
#ifndef _ATMSAR_H_
#define _ATMSAR_H_
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>
#include <linux/atmdev.h>
#include <linux/skbuff.h>
#include <linux/types.h>
#include <linux/atm.h>
#define ATMSAR_USE_53BYTE_CELL 0x1L
#define ATMSAR_SET_PTI 0x2L
/* types */
#define ATMSAR_TYPE_AAL0 ATM_AAL0
#define ATMSAR_TYPE_AAL1 ATM_AAL1
#define ATMSAR_TYPE_AAL2 ATM_AAL2
#define ATMSAR_TYPE_AAL34 ATM_AAL34
#define ATMSAR_TYPE_AAL5 ATM_AAL5
/* default MTU's */
#define ATMSAR_DEF_MTU_AAL0 48
#define ATMSAR_DEF_MTU_AAL1 47
#define ATMSAR_DEF_MTU_AAL2 0 /* not supported */
#define ATMSAR_DEF_MTU_AAL34 0 /* not supported */
#define ATMSAR_DEF_MTU_AAL5 65535 /* max mtu .. */
struct atmsar_vcc_data {
struct atmsar_vcc_data *next;
/* general atmsar flags, per connection */
int flags;
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... */
/* cell data */
unsigned int vp;
unsigned int vc;
unsigned char gfc;
unsigned char pti;
unsigned int headerFlags;
unsigned long atmHeader;
/* raw cell reassembly */
struct sk_buff *reasBuffer;
};
extern 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);
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);
#endif /* _ATMSAR_H_ */
/*
* Driver Module for Alcatel SpeedTouch USB xDSL modem
* Copyright 2001, Alcatel
* Written by Johan Verrept (Johan.Verrept@advalvas.be)
*
1.5A: - Version for inclusion in 2.5 series kernel
- Modifcations by Richard Purdie (rpurdie@rpsys.net)
- made compatible with kernel 2.5.6 onwards by changing
udsl_usb_send_data_context->urb changed to a pointer
and adding code to alloc and free it
- remove_wait_queue() added to udsl_atm_processqueue_thread()
1.5: - fixed memory leak when atmsar_decode_aal5 returned NULL.
(reported by stephen.robinson@zen.co.uk)
1.4: - changed the spin_lock() under interrupt to spin_lock_irqsave()
- unlink all active send urbs of a vcc that is being closed.
1.3.1: - added the version number
1.3: - Added multiple send urb support
- fixed memory leak and vcc->tx_inuse starvation bug
when not enough memory left in vcc.
1.2: - Fixed race condition in udsl_usb_send_data()
1.1: - Turned off packet debugging
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/errno.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
#include <linux/smp_lock.h>
#include <linux/atm.h>
#include <linux/atmdev.h>
#include "atmsar.h"
const char *udsl_version = "1.5A";
/*
#define DEBUG 1
#define DEBUG_PACKET 1
*/
#ifdef DEBUG
#define PDEBUG(arg...) printk(KERN_DEBUG "SpeedTouch USB: " arg)
#else
#define PDEBUG(arg...)
#endif
#ifdef DEBUG_PACKET
#define PACKETDEBUG(arg...) udsl_print_packet ( arg )
#else
#define PACKETDEBUG(arg...)
#endif
#define DRIVER_AUTHOR "Johan Verrept, Johan.Verrept@advalvas.be"
#define DRIVER_DESC "Driver for the Alcatel Speed Touch USB ADSL modem"
#define DRIVER_VERSION "1.5A"
#define SPEEDTOUCH_VENDORID 0x06b9
#define SPEEDTOUCH_PRODUCTID 0x4061
#define MAX_UDSL 1
#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
/* 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
/* endpoint declarations */
#define UDSL_ENDPOINT_DATA_OUT 0x07
#define UDSL_ENDPOINT_DATA_IN 0x87
/* usb_device_id struct */
static struct usb_device_id udsl_usb_ids[] = {
{USB_DEVICE (SPEEDTOUCH_VENDORID, SPEEDTOUCH_PRODUCTID)},
{} /* list terminator */
};
/* not exporting this prevents the depmod from generating the map that causes the modules to be isnserted as driver.
* we do not want this, we want the script run.
MODULE_DEVICE_TABLE ( usb, udsl_usb_ids);
*/
/* context declarations */
struct udsl_data_ctx {
struct sk_buff *skb;
struct urb *urb;
struct udsl_instance_data *instance;
};
struct udsl_usb_send_data_context {
struct urb *urb;
struct sk_buff *skb;
struct atm_vcc *vcc;
struct udsl_instance_data *instance;
};
/*
* UDSL main driver data
*/
struct udsl_instance_data {
int minor;
/* usb device part */
struct usb_device *usb_dev;
struct udsl_data_ctx *rcvbufs;
struct sk_buff_head sndqueue;
spinlock_t sndqlock;
struct udsl_usb_send_data_context send_ctx[UDSL_NUMBER_SND_URBS];
int data_started;
/* atm device part */
struct atm_dev *atm_dev;
struct sk_buff_head recvqueue;
spinlock_t recvqlock;
struct atmsar_vcc_data *atmsar_vcc_list;
};
struct udsl_instance_data *minor_data[MAX_UDSL];
static const char udsl_driver_name[] = "Alcatel SpeedTouch USB";
/* data thread */
static int datapid = 0;
DECLARE_WAIT_QUEUE_HEAD (udsl_wqh);
#ifdef DEBUG_PACKET
int udsl_print_packet (const unsigned char *data, int len);
#endif
/*
* atm driver prototypes and stuctures
*/
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);
static int udsl_atm_send (struct atm_vcc *vcc, struct sk_buff *skb);
int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t * pos, char *page);
void udsl_atm_processqueue (struct udsl_instance_data *instance);
static struct atmdev_ops udsl_atm_devops = {
open:udsl_atm_open,
close:udsl_atm_close,
ioctl:udsl_atm_ioctl,
send:udsl_atm_send,
proc_read:udsl_atm_proc_read,
};
struct udsl_atm_dev_data {
struct atmsar_vcc_data *atmsar_vcc;
};
/*
* usb driver prototypes and structures
*/
static void *udsl_usb_probe (struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id);
static void udsl_usb_disconnect (struct usb_device *dev, void *ptr);
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_device *hub, 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,
probe:udsl_usb_probe,
disconnect:udsl_usb_disconnect,
ioctl:udsl_usb_ioctl,
id_table:udsl_usb_ids,
};
/************
** ATM **
************/
/***************************************************************************
*
* init functions
*
****************************************************************************/
struct atm_dev *udsl_atm_startdevice (struct udsl_instance_data *instance,
struct atmdev_ops *devops)
{
MOD_INC_USE_COUNT;
instance->atm_dev = atm_dev_register (udsl_driver_name, devops, -1, 0);
instance->atm_dev->dev_data = instance;
instance->atm_dev->ci_range.vpi_bits = ATM_CI_MAX;
instance->atm_dev->ci_range.vci_bits = ATM_CI_MAX;
instance->atm_dev->signal = ATM_PHY_SIG_LOST;
skb_queue_head_init (&instance->recvqueue);
/* tmp init atm device, set to 128kbit */
instance->atm_dev->link_rate = 128 * 1000 / 424;
return instance->atm_dev;
}
void udsl_atm_stopdevice (struct udsl_instance_data *instance)
{
struct atm_vcc *walk;
struct sk_buff *skb;
struct atm_dev *atm_dev;
unsigned long iflags;
if (!instance->atm_dev)
return;
atm_dev = instance->atm_dev;
/* clean queue */
spin_lock_irqsave (&instance->recvqlock, iflags);
while (!skb_queue_empty (&instance->recvqueue)) {
skb = skb_dequeue (&instance->recvqueue);
dev_kfree_skb (skb);
};
spin_unlock_irqrestore (&instance->recvqlock, iflags);
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;
MOD_DEC_USE_COUNT;
}
void udsl_atm_set_mac (struct udsl_instance_data *instance, const char mac[6])
{
if (!instance->atm_dev)
return;
memcpy (instance->atm_dev->esi, mac, 6);
}
/***************************************************************************
*
* ATM helper functions
*
****************************************************************************/
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;
}
int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t * pos, char *page)
{
struct udsl_instance_data *instance = (struct udsl_instance_data *) atm_dev->dev_data;
int left = *pos;
if (!left--)
return sprintf (page, "Speed Touch USB:%d (%02x:%02x:%02x:%02x:%02x:%02x)\n",
instance->minor, 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),
atomic_read (&atm_dev->stats.aal5.tx_err),
atomic_read (&atm_dev->stats.aal5.rx),
atomic_read (&atm_dev->stats.aal5.rx_err),
atomic_read (&atm_dev->stats.aal5.rx_drop));
return 0;
}
/***************************************************************************
*
* ATM DATA functions
*
****************************************************************************/
int udsl_atm_send (struct atm_vcc *vcc, struct sk_buff *skb)
{
struct udsl_atm_dev_data *dev_data = (struct udsl_atm_dev_data *) vcc->dev_data;
struct udsl_instance_data *instance = (struct udsl_instance_data *) vcc->dev->dev_data;
struct sk_buff *new = NULL;
int err;
PDEBUG ("udsl_atm_send called\n");
if (!dev_data)
return -EINVAL;
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;
};
void udsl_atm_processqueue (struct udsl_instance_data *instance)
{
struct atmsar_vcc_data *atmsar_vcc = NULL;
struct sk_buff *new = NULL, *skb = NULL, *tmp = NULL;
unsigned long iflags;
/* quick check */
spin_lock_irqsave (&instance->recvqlock, iflags);
if (skb_queue_empty (&instance->recvqueue)) {
spin_unlock_irqrestore (&instance->recvqlock, iflags);
return;
}
PDEBUG ("udsl_atm_processqueue entered\n");
while (!skb_queue_empty (&instance->recvqueue)) {
skb = skb_dequeue (&instance->recvqueue);
spin_unlock_irqrestore (&instance->recvqlock, iflags);
PDEBUG ("skb = %p, skb->len = %d\n", skb, skb->len);
PACKETDEBUG (skb->data, skb->len);
while ((new =
atmsar_decode_rawcell (instance->atmsar_vcc_list, skb,
&atmsar_vcc)) != NULL) {
PDEBUG ("(after cell processing)skb->len = %d\n", new->len);
switch (atmsar_vcc->type) {
case ATMSAR_TYPE_AAL5:
tmp = new;
new = atmsar_decode_aal5 (atmsar_vcc, new);
/* we can't send NULL skbs upstream, the ATM layer would try to close the vcc... */
if (new) {
PDEBUG ("(after aal5 decap) skb->len = %d\n", new->len);
if (new->len && atm_charge (atmsar_vcc->vcc, new->truesize)) {
PACKETDEBUG (new->data, new->len);
atmsar_vcc->vcc->push (atmsar_vcc->vcc, new);
} else {
PDEBUG
("dropping incoming packet : rx_inuse = %d, vcc->sk->rcvbuf = %d, skb->true_size = %d\n",
atomic_read (&atmsar_vcc->vcc->rx_inuse),
atmsar_vcc->vcc->sk->rcvbuf, new->truesize);
dev_kfree_skb (new);
}
} else {
PDEBUG ("atmsar_decode_aal5 returned NULL!\n");
dev_kfree_skb (tmp);
}
break;
default:
/* not supported. we delete the skb. */
printk (KERN_INFO
"SpeedTouch USB: illegal vcc type. Dropping packet.\n");
dev_kfree_skb (new);
break;
}
};
dev_kfree_skb (skb);
spin_lock_irqsave (&instance->recvqlock, iflags);
};
spin_unlock_irqrestore (&instance->recvqlock, iflags);
PDEBUG ("udsl_atm_processqueue successfull\n");
}
int udsl_atm_processqueue_thread (void *data)
{
int i = 0;
DECLARE_WAITQUEUE (wait, current);
lock_kernel ();
daemonize ();
/* Setup a nice name */
strcpy (current->comm, "kSpeedSARd");
add_wait_queue (&udsl_wqh, &wait);
for (;;) {
interruptible_sleep_on (&udsl_wqh);
if (signal_pending (current))
break;
PDEBUG ("SpeedSARd awoke\n");
for (i = 0; i < MAX_UDSL; i++)
if (minor_data[i])
udsl_atm_processqueue (minor_data[i]);
};
remove_wait_queue (&udsl_wqh, &wait);
datapid = 0;
PDEBUG ("SpeedSARd is exiting\n");
return 0;
}
void udsl_atm_sar_start (void)
{
datapid = kernel_thread (udsl_atm_processqueue_thread, (void *) NULL,
CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
}
void udsl_atm_sar_stop (void)
{
int ret;
/* Kill the thread */
ret = kill_proc (datapid, SIGTERM, 1);
if (!ret) {
/* Wait 10 seconds */
int count = 10 * 100;
while (datapid && --count) {
current->state = TASK_INTERRUPTIBLE;
schedule_timeout (1);
}
if (!count)
err ("giving up on killing SpeedSAR thread.");
}
}
/***************************************************************************
*
* SAR driver entries
*
****************************************************************************/
int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci)
{
struct udsl_atm_dev_data *dev_data;
struct udsl_instance_data *instance = (struct udsl_instance_data *) vcc->dev->dev_data;
PDEBUG ("udsl_atm_open called\n");
/* at the moment only AAL5 support */
if (vcc->qos.aal != ATM_AAL5)
return -EINVAL;
MOD_INC_USE_COUNT;
dev_data =
(struct udsl_atm_dev_data *) kmalloc (sizeof (struct udsl_atm_dev_data), GFP_KERNEL);
if (!dev_data)
return -ENOMEM;
dev_data->atmsar_vcc =
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);
return -ENOMEM; /* this is the only reason atmsar_open can fail... */
}
vcc->vpi = vpi;
vcc->vci = 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;
PDEBUG ("udsl_atm_open successfull\n");
return 0;
}
void udsl_atm_close (struct atm_vcc *vcc)
{
struct udsl_atm_dev_data *dev_data = (struct udsl_atm_dev_data *) vcc->dev_data;
struct udsl_instance_data *instance = (struct udsl_instance_data *) vcc->dev->dev_data;
PDEBUG ("udsl_atm_close called\n");
/* freeing resources */
/* cancel all sends on this vcc */
udsl_usb_cancelsends (instance, vcc);
atmsar_close (&(instance->atmsar_vcc_list), dev_data->atmsar_vcc);
kfree (dev_data);
vcc->dev_data = NULL;
clear_bit (ATM_VF_PARTIAL, &vcc->flags);
/* freeing address */
vcc->vpi = ATM_VPI_UNSPEC;
vcc->vci = ATM_VCI_UNSPEC;
clear_bit (ATM_VF_ADDR, &vcc->flags);
MOD_DEC_USE_COUNT;
PDEBUG ("udsl_atm_close successfull\n");
return;
};
int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg)
{
switch (cmd) {
case ATM_QUERYLOOP:
return put_user (ATM_LM_NONE, (int *) arg) ? -EFAULT : 0;
default:
return -ENOIOCTLCMD;
}
};
/************
** USB **
************/
/***************************************************************************
*
* usb data functions
*
****************************************************************************/
struct udsl_cb {
struct atm_vcc *vcc;
};
static void udsl_usb_send_data_complete (struct urb *urb)
{
struct udsl_usb_send_data_context *ctx = (struct udsl_usb_send_data_context *) urb->context;
struct udsl_instance_data *instance = ctx->instance;
int err;
unsigned long flags;
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);
ctx->skb = NULL;
spin_lock_irqsave (&instance->sndqlock, flags);
if (skb_queue_empty (&instance->sndqueue)) {
spin_unlock_irqrestore (&instance->sndqlock, flags);
return;
}
/* submit next skb */
ctx->skb = skb_dequeue (&(instance->sndqueue));
ctx->vcc = ((struct udsl_cb *) (ctx->skb->cb))->vcc;
spin_unlock_irqrestore (&instance->sndqlock, flags);
FILL_BULK_URB (urb,
instance->usb_dev,
usb_sndbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_OUT),
(unsigned char *) ctx->skb->data,
ctx->skb->len, (usb_complete_t) udsl_usb_send_data_complete, ctx);
err = usb_submit_urb (urb, GFP_KERNEL);
PDEBUG ("udsl_usb_send_data_completion (send packet %p with length %d), retval = %d\n",
ctx->skb, ctx->skb->len, err);
}
int udsl_usb_cancelsends (struct udsl_instance_data *instance, struct atm_vcc *vcc)
{
int i;
unsigned long flags;
spin_lock_irqsave (&instance->sndqlock, flags);
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;
}
}
spin_unlock_irqrestore (&instance->sndqlock, flags);
return 0;
}
/**** send ******/
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);
if (!instance->data_started)
return -EAGAIN;
PACKETDEBUG (skb->data, skb->len);
spin_lock_irqsave (&instance->sndqlock, 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->sndqlock, 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->sndqlock, 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->sndqlock, flags);
/* submit packet */
FILL_BULK_URB (urb,
instance->usb_dev,
usb_sndbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_OUT),
(unsigned char *) skb->data,
skb->len,
(usb_complete_t) 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;
}
/********* receive *******/
void udsl_usb_data_receive (struct urb *urb)
{
struct udsl_data_ctx *ctx;
struct udsl_instance_data *instance;
unsigned long flags;
if (!urb)
return;
PDEBUG ("udsl_usb_receive_data entered, got packet %p with length %d an status %d\n", urb,
urb->actual_length, urb->status);
ctx = (struct udsl_data_ctx *) urb->context;
if (!ctx || !ctx->skb)
return;
instance = ctx->instance;
switch (urb->status) {
case 0:
PDEBUG ("udsl_usb_data_receive: processing urb with ctx %p, urb %p (%p), skb %p\n",
ctx, ctx ? ctx->urb : NULL, urb, ctx ? ctx->skb : NULL);
/* update the skb structure */
skb_put (ctx->skb, urb->actual_length);
/* queue the skb for processing and wake the SAR */
spin_lock_irqsave (&instance->recvqlock, flags);
skb_queue_tail (&instance->recvqueue, ctx->skb);
spin_unlock_irqrestore (&instance->recvqlock, flags);
wake_up (&udsl_wqh);
/* get a new skb */
ctx->skb = dev_alloc_skb (UDSL_RECEIVE_BUFFER_SIZE);
if (!ctx->skb) {
PDEBUG ("No skb, loosing urb.\n");
usb_free_urb (ctx->urb);
ctx->urb = NULL;
return;
}
break;
case -EPIPE: /* stall or babble */
usb_clear_halt (urb->dev, usb_rcvbulkpipe (urb->dev, UDSL_ENDPOINT_DATA_IN));
break;
case -ENOENT: /* buffer was unlinked */
case -EILSEQ: /* unplug or timeout */
case -ETIMEDOUT: /* unplug or timeout */
/*
* we don't do anything here and we don't resubmit
*/
return;
}
FILL_BULK_URB (urb,
instance->usb_dev,
usb_rcvbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_IN),
(unsigned char *) ctx->skb->data,
UDSL_RECEIVE_BUFFER_SIZE, (usb_complete_t) udsl_usb_data_receive, ctx);
usb_submit_urb (urb, GFP_KERNEL);
return;
};
int udsl_usb_data_init (struct udsl_instance_data *instance)
{
int i, succes;
if (instance->data_started)
return 1;
/* set alternate setting 1 on interface 1 */
usb_set_interface (instance->usb_dev, 1, 2);
PDEBUG ("max packet size on endpoint %d is %d\n", UDSL_ENDPOINT_DATA_OUT,
usb_maxpacket (instance->usb_dev,
usb_sndbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_OUT), 0));
instance->rcvbufs =
(struct udsl_data_ctx *) kmalloc (sizeof (struct udsl_data_ctx) * UDSL_NUMBER_RCV_URBS,
GFP_KERNEL);
if (!instance->rcvbufs)
return -ENOMEM;
memset (instance->rcvbufs, 0, sizeof (struct udsl_data_ctx) * UDSL_NUMBER_RCV_URBS);
skb_queue_head_init (&instance->sndqueue);
for (i = 0, succes = 0; i < UDSL_NUMBER_RCV_URBS; i++) {
struct udsl_data_ctx *ctx = &(instance->rcvbufs[i]);
ctx->urb = NULL;
ctx->skb = dev_alloc_skb (UDSL_RECEIVE_BUFFER_SIZE);
if (!ctx->skb)
continue;
ctx->urb = usb_alloc_urb (0, GFP_KERNEL);
if (!ctx->urb) {
kfree_skb (ctx->skb);
ctx->skb = NULL;
break;
};
FILL_BULK_URB (ctx->urb,
instance->usb_dev,
usb_rcvbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_IN),
(unsigned char *) ctx->skb->data,
UDSL_RECEIVE_BUFFER_SIZE,
(usb_complete_t) udsl_usb_data_receive, ctx);
ctx->instance = instance;
PDEBUG ("udsl_usb_data_init: usb with skb->truesize = %d (Asked for %d)\n",
ctx->skb->truesize, UDSL_RECEIVE_BUFFER_SIZE);
if (usb_submit_urb (ctx->urb, GFP_KERNEL) < 0)
PDEBUG ("udsl_usb_data_init: Submit failed, loosing urb.\n");
else
succes++;
}
PDEBUG ("udsl_usb_data_init %d urb%s queued for receive\n", succes,
(succes != 1) ? "s" : "");
for (i = 0, succes = 0; i < UDSL_NUMBER_SND_URBS; i++) {
instance->send_ctx[i].urb = usb_alloc_urb (0, GFP_KERNEL);
PDEBUG ("udsl_usb_data_init: send urb allocted address %p\n",
instance->send_ctx[i].urb);
if (instance->send_ctx[i].urb)
succes++;
}
PDEBUG ("udsl_usb_data_init %d urb%s queued for send\n", succes, (succes != 1) ? "s" : "");
instance->data_started = 1;
instance->atm_dev->signal = ATM_PHY_SIG_FOUND;
return 0;
}
int udsl_usb_data_exit (struct udsl_instance_data *instance)
{
int i;
if (!instance->data_started)
return 0;
if (!instance->rcvbufs)
return 0;
/* destroy urbs */
for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++) {
struct udsl_data_ctx *ctx = &(instance->rcvbufs[i]);
if ((!ctx->urb) || (!ctx->skb))
continue;
if (ctx->urb->status == -EINPROGRESS)
usb_unlink_urb (ctx->urb);
usb_free_urb (ctx->urb);
kfree_skb (ctx->skb);
ctx->skb = NULL;
}
for (i = 0; i < UDSL_NUMBER_SND_URBS; i++) {
struct udsl_usb_send_data_context *ctx = &(instance->send_ctx[i]);
if (ctx->urb->status == -EINPROGRESS)
usb_unlink_urb (ctx->urb);
if (ctx->skb)
ctx->vcc->pop (ctx->vcc, ctx->skb);
ctx->skb = NULL;
usb_free_urb (ctx->urb);
}
/* free receive contexts */
kfree (instance->rcvbufs);
instance->rcvbufs = NULL;
instance->data_started = 0;
instance->atm_dev->signal = ATM_PHY_SIG_LOST;
return 0;
};
/***************************************************************************
*
* usb driver entries
*
****************************************************************************/
#define hex2int(c) ( (c >= '0')&&(c <= '9') ? (c - '0') : ((c & 0xf)+9) )
static int udsl_usb_ioctl (struct usb_device *dev, unsigned int code, void *user_data)
{
struct udsl_instance_data *instance;
int i;
for (i = 0; i < MAX_UDSL; i++)
if (minor_data[i] && (minor_data[i]->usb_dev == dev))
break;
if (i == MAX_UDSL)
return -EINVAL;
instance = minor_data[i];
switch (code) {
case UDSL_IOCTL_START:
return udsl_usb_data_init (instance);
break;
case UDSL_IOCTL_STOP:
return udsl_usb_data_exit (instance);
break;
default:
break;
}
return -EINVAL;
}
void *udsl_usb_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)
{
int i;
unsigned char mac[6];
unsigned char mac_str[13];
struct udsl_instance_data *instance = NULL;
PDEBUG ("Trying device with Vendor=0x%x, Product=0x%x, ifnum %d\n",
dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum);
if ((dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) ||
(dev->descriptor.idVendor != SPEEDTOUCH_VENDORID) ||
(dev->descriptor.idProduct != SPEEDTOUCH_PRODUCTID) || (ifnum != 1))
return NULL;
MOD_INC_USE_COUNT;
for (i = 0; i < MAX_UDSL; i++)
if (minor_data[i] == NULL)
break;
if (i >= MAX_UDSL) {
printk (KERN_INFO "No minor table space available for SpeedTouch USB\n");
return NULL;
};
PDEBUG ("Device Accepted, assigning minor %d\n", i);
/* device init */
instance = kmalloc (sizeof (struct udsl_instance_data), GFP_KERNEL);
if (!instance) {
PDEBUG ("No memory for Instance data!\n");
return NULL;
}
/* initialize structure */
memset (instance, 0, sizeof (struct udsl_instance_data));
instance->minor = i;
instance->usb_dev = dev;
instance->rcvbufs = NULL;
spin_lock_init (&instance->sndqlock);
spin_lock_init (&instance->recvqlock);
udsl_atm_startdevice (instance, &udsl_atm_devops);
/* set MAC address, it is stored in the serial number */
usb_string (instance->usb_dev, instance->usb_dev->descriptor.iSerialNumber, mac_str, 13);
for (i = 0; i < 6; i++)
mac[i] = (hex2int (mac_str[i * 2]) * 16) + (hex2int (mac_str[i * 2 + 1]));
PDEBUG ("MAC is %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4],
mac[5]);
udsl_atm_set_mac (instance, mac);
minor_data[instance->minor] = instance;
return instance;
}
void udsl_usb_disconnect (struct usb_device *dev, void *ptr)
{
struct udsl_instance_data *instance = (struct udsl_instance_data *) ptr;
int i = instance->minor;
/* unlinking receive buffers */
udsl_usb_data_exit (instance);
/* removing atm device */
if (instance->atm_dev)
udsl_atm_stopdevice (instance);
PDEBUG ("disconnecting minor %d\n", i);
while (MOD_IN_USE > 1) {
current->state = TASK_INTERRUPTIBLE;
schedule_timeout (1);
}
kfree (instance);
minor_data[i] = NULL;
MOD_DEC_USE_COUNT;
}
/***************************************************************************
*
* Driver Init
*
****************************************************************************/
int udsl_usb_init (void)
{
int i;
PDEBUG ("Initializing SpeedTouch Driver Version %s\n", udsl_version);
for (i = 0; i < MAX_UDSL; i++)
minor_data[i] = NULL;
init_waitqueue_head (&udsl_wqh);
udsl_atm_sar_start ();
return usb_register (&udsl_usb_driver);
}
int udsl_usb_cleanup (void)
{
/* killing threads */
udsl_atm_sar_stop ();
usb_deregister (&udsl_usb_driver);
return 0;
}
#ifdef MODULE
int init_module (void)
{
return udsl_usb_init ();
}
int cleanup_module (void)
{
return udsl_usb_cleanup ();
}
#endif
#ifdef DEBUG_PACKET
/*******************************************************************************
*
* Debug
*
*******************************************************************************/
int udsl_print_packet (const unsigned char *data, int len)
{
unsigned char buffer[256];
int i = 0, j = 0;
for (i = 0; i < len;) {
buffer[0] = '\0';
sprintf (buffer, "%.3d :", i);
for (j = 0; (j < 16) && (i < len); j++, i++) {
sprintf (buffer, "%s %2.2x", buffer, data[i]);
}
PDEBUG ("%s\n", buffer);
}
return i;
};
#endif /* PACKETDEBUG */
MODULE_AUTHOR (DRIVER_AUTHOR);
MODULE_DESCRIPTION (DRIVER_DESC);
MODULE_LICENSE ("GPL");
/*****************************************************************************
* USBLCD Kernel Driver *
* See http://www.usblcd.de for Hardware and Documentation. *
* Version 1.01 *
* (C) 2002 Adams IT Services <info@usblcd.de> *
* *
* This file is licensed under the GPL. See COPYING in the package. *
* Based on rio500.c by Cesar Miquel (miquel@df.uba.ar) which is based on *
* hp_scanner.c by David E. Nelson (dnelson@jump.net) *
* *
* 23.7.02 RA changed minor device number to the official assigned one *
*****************************************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
#define DRIVER_VERSION "USBLCD Driver Version 1.01"
#define USBLCD_MINOR 144
#define IOCTL_GET_HARD_VERSION 1
#define IOCTL_GET_DRV_VERSION 2
/* stall/wait timeout for USBLCD */
#define NAK_TIMEOUT (HZ)
#define IBUF_SIZE 0x1000
#define OBUF_SIZE 0x10000
struct lcd_usb_data {
struct usb_device *lcd_dev; /* init: probe_lcd */
unsigned int ifnum; /* Interface number of the USB device */
int minor; /* minor number for this device */
int isopen; /* nz if open */
int present; /* Device is present on the bus */
char *obuf, *ibuf; /* transfer buffers */
char bulk_in_ep, bulk_out_ep; /* Endpoint assignments */
wait_queue_head_t wait_q; /* for timeouts */
};
static struct lcd_usb_data lcd_instance;
static int open_lcd(struct inode *inode, struct file *file)
{
struct lcd_usb_data *lcd = &lcd_instance;
if (lcd->isopen || !lcd->present) {
return -EBUSY;
}
lcd->isopen = 1;
init_waitqueue_head(&lcd->wait_q);
info("USBLCD opened.");
return 0;
}
static int close_lcd(struct inode *inode, struct file *file)
{
struct lcd_usb_data *lcd = &lcd_instance;
lcd->isopen = 0;
info("USBLCD closed.");
return 0;
}
static int
ioctl_lcd(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
struct lcd_usb_data *lcd = &lcd_instance;
int i;
char buf[30];
/* Sanity check to make sure lcd is connected, powered, etc */
if (lcd == NULL ||
lcd->present == 0 ||
lcd->lcd_dev == NULL)
return -1;
switch (cmd) {
case IOCTL_GET_HARD_VERSION:
i = (lcd->lcd_dev)->descriptor.bcdDevice;
sprintf(buf,"%1d%1d.%1d%1d",(i & 0xF000)>>12,(i & 0xF00)>>8,
(i & 0xF0)>>4,(i & 0xF));
if (copy_to_user((void *)arg,buf,strlen(buf))!=0)
return -EFAULT;
break;
case IOCTL_GET_DRV_VERSION:
sprintf(buf,DRIVER_VERSION);
if (copy_to_user((void *)arg,buf,strlen(buf))!=0)
return -EFAULT;
break;
default:
return -ENOIOCTLCMD;
break;
}
return 0;
}
static ssize_t
write_lcd(struct file *file, const char *buffer,
size_t count, loff_t * ppos)
{
struct lcd_usb_data *lcd = &lcd_instance;
unsigned long copy_size;
unsigned long bytes_written = 0;
unsigned int partial;
int result = 0;
int maxretry;
/* Sanity check to make sure lcd is connected, powered, etc */
if (lcd == NULL ||
lcd->present == 0 ||
lcd->lcd_dev == NULL)
return -1;
do {
unsigned long thistime;
char *obuf = lcd->obuf;
thistime = copy_size =
(count >= OBUF_SIZE) ? OBUF_SIZE : count;
if (copy_from_user(lcd->obuf, buffer, copy_size))
return -EFAULT;
maxretry = 5;
while (thistime) {
if (!lcd->lcd_dev)
return -ENODEV;
if (signal_pending(current)) {
return bytes_written ? bytes_written : -EINTR;
}
result = usb_bulk_msg(lcd->lcd_dev,
usb_sndbulkpipe(lcd->lcd_dev, 1),
obuf, thistime, &partial, 10 * HZ);
dbg("write stats: result:%d thistime:%lu partial:%u",
result, thistime, partial);
if (result == -ETIMEDOUT) { /* NAK - so hold for a while */
if (!maxretry--) {
return -ETIME;
}
interruptible_sleep_on_timeout(&lcd-> wait_q, NAK_TIMEOUT);
continue;
} else if (!result & partial) {
obuf += partial;
thistime -= partial;
} else
break;
};
if (result) {
err("Write Whoops - %x", result);
return -EIO;
}
bytes_written += copy_size;
count -= copy_size;
buffer += copy_size;
} while (count > 0);
return bytes_written ? bytes_written : -EIO;
}
static ssize_t
read_lcd(struct file *file, char *buffer, size_t count, loff_t * ppos)
{
struct lcd_usb_data *lcd = &lcd_instance;
ssize_t read_count;
unsigned int partial;
int this_read;
int result;
int maxretry = 10;
char *ibuf = lcd->ibuf;
/* Sanity check to make sure lcd is connected, powered, etc */
if (lcd == NULL ||
lcd->present == 0 ||
lcd->lcd_dev == NULL)
return -1;
read_count = 0;
while (count > 0) {
if (signal_pending(current)) {
return read_count ? read_count : -EINTR;
}
if (!lcd->lcd_dev)
return -ENODEV;
this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
result = usb_bulk_msg(lcd->lcd_dev,
usb_rcvbulkpipe(lcd->lcd_dev, 0),
ibuf, this_read, &partial,
(int) (HZ * 8));
dbg(KERN_DEBUG "read stats: result:%d this_read:%u partial:%u",
result, this_read, partial);
if (partial) {
count = this_read = partial;
} else if (result == -ETIMEDOUT || result == 15) { /* FIXME: 15 ??? */
if (!maxretry--) {
err("read_lcd: maxretry timeout");
return -ETIME;
}
interruptible_sleep_on_timeout(&lcd->wait_q,
NAK_TIMEOUT);
continue;
} else if (result != -EREMOTEIO) {
err("Read Whoops - result:%u partial:%u this_read:%u",
result, partial, this_read);
return -EIO;
} else {
return (0);
}
if (this_read) {
if (copy_to_user(buffer, ibuf, this_read))
return -EFAULT;
count -= this_read;
read_count += this_read;
buffer += this_read;
}
}
return read_count;
}
static struct
file_operations usb_lcd_fops = {
.owner = THIS_MODULE,
.read = read_lcd,
.write = write_lcd,
.ioctl = ioctl_lcd,
.open = open_lcd,
.release = close_lcd,
};
static void *probe_lcd(struct usb_device *dev, unsigned int ifnum)
{
struct lcd_usb_data *lcd = &lcd_instance;
int i;
int retval;
if (dev->descriptor.idProduct != 0x0001 ) {
warn(KERN_INFO "USBLCD model not supported.");
return NULL;
}
if (lcd->present == 1) {
warn(KERN_INFO "Multiple USBLCDs are not supported!");
return NULL;
}
i = dev->descriptor.bcdDevice;
info("USBLCD Version %1d%1d.%1d%1d found at address %d",
(i & 0xF000)>>12,(i & 0xF00)>>8,(i & 0xF0)>>4,(i & 0xF),
dev->devnum);
retval = usb_register_dev(&usb_lcd_fops, USBLCD_MINOR, 1, &lcd->minor);
if (retval) {
err("Not able to get a minor for this device.");
return NULL;
}
lcd->present = 1;
lcd->lcd_dev = dev;
if (!(lcd->obuf = (char *) kmalloc(OBUF_SIZE, GFP_KERNEL))) {
err("probe_lcd: Not enough memory for the output buffer");
return NULL;
}
dbg("probe_lcd: obuf address:%p", lcd->obuf);
if (!(lcd->ibuf = (char *) kmalloc(IBUF_SIZE, GFP_KERNEL))) {
err("probe_lcd: Not enough memory for the input buffer");
kfree(lcd->obuf);
return NULL;
}
dbg("probe_lcd: ibuf address:%p", lcd->ibuf);
return lcd;
}
static void disconnect_lcd(struct usb_device *dev, void *ptr)
{
struct lcd_usb_data *lcd = (struct lcd_usb_data *) ptr;
usb_deregister_dev(1, lcd->minor);
if (lcd->isopen) {
lcd->isopen = 0;
/* better let it finish - the release will do whats needed */
lcd->lcd_dev = NULL;
return;
}
kfree(lcd->ibuf);
kfree(lcd->obuf);
info("USBLCD disconnected.");
lcd->present = 0;
}
static struct usb_device_id id_table [] = {
{ .idVendor = 0x1212, .match_flags = USB_DEVICE_ID_MATCH_VENDOR, },
{},
};
MODULE_DEVICE_TABLE (usb, id_table);
static struct
usb_driver lcd_driver = {
.name = "usblcd",
.probe = (void *)probe_lcd,
.disconnect = disconnect_lcd,
.id_table = id_table,
};
int usb_lcd_init(void)
{
if (usb_register(&lcd_driver) < 0)
return -1;
info("%s (C) Adams IT Services http://www.usblcd.de", DRIVER_VERSION);
info("USBLCD support registered.");
return 0;
}
void usb_lcd_cleanup(void)
{
struct lcd_usb_data *lcd = &lcd_instance;
lcd->present = 0;
usb_deregister(&lcd_driver);
}
module_init(usb_lcd_init);
module_exit(usb_lcd_cleanup);
MODULE_AUTHOR("Adams IT Services <info@usblcd.de>");
MODULE_DESCRIPTION(DRIVER_VERSION);
MODULE_LICENSE("GPL");
......@@ -19,7 +19,7 @@
#define COMPAQ_VENDOR_ID 0x049f
#define COMPAQ_IPAQ_ID 0x0003
#define HP_VENDOR_ID 0x003f
#define HP_VENDOR_ID 0x03f0
#define HP_JORNADA_548_ID 0x1016
#define HP_JORNADA_568_ID 0x1116
......
......@@ -434,6 +434,12 @@ static int isd200_transfer_partial( struct us_data *us,
return ISD200_TRANSPORT_GOOD;
}
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("isd200_transfer_partial(): transfer aborted\n");
return ISD200_TRANSPORT_ABORTED;
}
/* uh oh... we have an error code, so something went wrong. */
if (result) {
/* NAK - that means we've retried a few times already */
......@@ -442,12 +448,6 @@ static int isd200_transfer_partial( struct us_data *us,
return ISD200_TRANSPORT_FAILED;
}
/* -ENOENT -- we canceled this transfer */
if (result == -ENOENT) {
US_DEBUGP("isd200_transfer_partial(): transfer aborted\n");
return ISD200_TRANSPORT_ABORTED;
}
/* the catch-all case */
US_DEBUGP("isd200_transfer_partial(): unknown error\n");
return ISD200_TRANSPORT_FAILED;
......@@ -581,8 +581,11 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb,
&partial);
US_DEBUGP("Bulk command transfer result=%d\n", result);
if (result == -ENOENT)
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
return ISD200_TRANSPORT_ABORTED;
}
else if (result == -EPIPE) {
/* if we stall, we need to clear it before we go on */
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
......@@ -610,8 +613,10 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb,
US_DEBUGP("Attempting to get CSW...\n");
result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN,
&partial);
if (result == -ENOENT)
return ISD200_TRANSPORT_ABORTED;
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
return ISD200_TRANSPORT_ABORTED;
}
/* did the attempt to read the CSW fail? */
if (result == -EPIPE) {
......@@ -624,8 +629,9 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb,
US_BULK_CS_WRAP_LEN, &partial);
/* if the command was aborted, indicate that */
if (result == -ENOENT)
return ISD200_TRANSPORT_ABORTED;
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
return ISD200_TRANSPORT_ABORTED;
}
/* if it fails again, we need a reset and return an error*/
if (result == -EPIPE) {
......
......@@ -3,7 +3,7 @@
* Unrelated to CF/SM - just USB stuff.
*
* This is mostly a thin layer on top of transport.c.
* It converts routines that return values like -ENOENT and -EPIPE
* It converts routines that return values like -EPIPE
* into routines that return USB_STOR_TRANSPORT_ABORTED etc.
*
* There is also some debug printing here.
......@@ -58,13 +58,14 @@ usb_storage_send_control(struct us_data *us,
request, requesttype, value, index,
xfer_data, xfer_len);
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("usb_stor_send_control(): transfer aborted\n");
return US_BULK_TRANSFER_ABORTED;
}
// Check the return code for the command.
if (result < 0) {
/* if the command was aborted, indicate that */
if (result == -ENOENT)
return USB_STOR_TRANSPORT_ABORTED;
/* a stall is a fatal condition from the device */
if (result == -EPIPE) {
......@@ -105,13 +106,13 @@ usb_storage_raw_bulk(struct us_data *us, int direction, unsigned char *data,
/* return US_BULK_TRANSFER_SHORT; */
}
if (result) {
/* -ENOENT -- we canceled this transfer */
if (result == -ENOENT) {
US_DEBUGP("raw_bulk(): transfer aborted\n");
return US_BULK_TRANSFER_ABORTED;
}
/* did we abort this command? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
US_DEBUGP("usb_storage_raw_bulk(): transfer aborted\n");
return US_BULK_TRANSFER_ABORTED;
}
if (result) {
/* NAK - that means we've retried a few times already */
if (result == -ETIMEDOUT)
US_DEBUGP("raw_bulk(): device NAKed\n");
......
......@@ -380,6 +380,7 @@ Scsi_Host_Template usb_stor_host_template = {
.emulated = TRUE
};
/* For a device that is "Not Ready" */
unsigned char usb_stor_sense_notready[18] = {
[0] = 0x70, /* current error */
[2] = 0x02, /* not ready */
......@@ -388,6 +389,14 @@ unsigned char usb_stor_sense_notready[18] = {
[13] = 0x03 /* manual intervention */
};
/* To Report "Illegal Request: Invalid Field in CDB */
unsigned char usb_stor_sense_invalidCDB[18] = {
[0] = 0x70, /* current error */
[2] = ILLEGAL_REQUEST, /* Illegal Request = 0x05 */
[7] = 0x0a, /* additional length */
[12] = 0x24 /* Invalid Field in CDB */
};
#define USB_STOR_SCSI_SENSE_HDRSZ 4
#define USB_STOR_SCSI_SENSE_10_HDRSZ 8
......
......@@ -46,6 +46,7 @@
#include "hosts.h"
extern unsigned char usb_stor_sense_notready[18];
extern unsigned char usb_stor_sense_invalidCDB[18];
extern Scsi_Host_Template usb_stor_host_template;
extern int usb_stor_scsiSense10to6(Scsi_Cmnd*);
extern int usb_stor_scsiSense6to10(Scsi_Cmnd*);
......
......@@ -65,6 +65,17 @@ UNUSUAL_DEV( 0x03f0, 0x0307, 0x0001, 0x0001,
US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0),
#endif
/* Deduced by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
* Entry needed for flags: US_FL_FIX_INQUIRY because initial inquiry message
* always fails and confuses drive; without US_FL_START_STOP, drive accesses
* (read or write) all fail.
*/
UNUSUAL_DEV( 0x0411, 0x001c, 0x0113, 0x0113,
"Buffalo",
"DUB-P40G HDD",
US_SC_SCSI, US_PR_BULK, NULL,
US_FL_FIX_INQUIRY | US_FL_START_STOP),
#ifdef CONFIG_USB_STORAGE_DPCM
UNUSUAL_DEV( 0x0436, 0x0005, 0x0100, 0x0100,
"Microtech",
......
......@@ -385,11 +385,15 @@ static int usb_stor_control_thread(void * __us)
us->srb->result = DID_BAD_TARGET << 16;
}
/* handle those devices which can't do a START_STOP */
else if ((us->srb->cmnd[0] == START_STOP) &&
(us->flags & US_FL_START_STOP)) {
US_DEBUGP("Skipping START_STOP command\n");
us->srb->result = GOOD << 1;
/* handle requests for EVPD, which most USB devices do
* not support */
else if((us->srb->cmnd[0] == INQUIRY) &&
(us->srb->cmnd[1] & 0x1)) {
US_DEBUGP("Faking INQUIRY command for EVPD\n");
memcpy(us->srb->sense_buffer,
usb_stor_sense_invalidCDB,
sizeof(usb_stor_sense_invalidCDB));
us->srb->result = CHECK_CONDITION << 1;
}
/* our device has gone - pretend not ready */
......@@ -405,6 +409,7 @@ static int usb_stor_control_thread(void * __us)
sizeof(usb_stor_sense_notready));
us->srb->result = GOOD << 1;
} else if(us->srb->cmnd[0] == INQUIRY) {
/* INQUIRY should always work, per spec... */
unsigned char data_ptr[36] = {
0x20, 0x80, 0x02, 0x02,
0x1F, 0x00, 0x00, 0x00};
......@@ -412,6 +417,7 @@ static int usb_stor_control_thread(void * __us)
fill_inquiry_response(us, data_ptr, 36);
us->srb->result = GOOD << 1;
} else {
/* not ready */
memcpy(us->srb->sense_buffer,
usb_stor_sense_notready,
sizeof(usb_stor_sense_notready));
......@@ -432,6 +438,35 @@ static int usb_stor_control_thread(void * __us)
us->srb->result = GOOD << 1;
}
/* Most USB devices can't handle START_STOP. But we
* need something for media-change, so we'll use TUR
* instead.
*/
else if (us->srb->cmnd[0] == START_STOP) {
unsigned char saved_cdb[16]; /* largest SCSI-III cmd */
__u8 old_cmd_len;
US_DEBUGP("Converting START_STOP to TUR\n");
/* save old command */
memcpy(saved_cdb, us->srb->cmnd, us->srb->cmd_len);
old_cmd_len = us->srb->cmd_len;
/* set up new command -- preserve LUN */
us->srb->cmd_len = 6;
memset(us->srb->cmnd, 0, us->srb->cmd_len);
us->srb->cmnd[0] = TEST_UNIT_READY;
us->srb->cmnd[1] = saved_cdb[1] & 0xE0;
/* do command */
US_DEBUG(usb_stor_show_command(us->srb));
us->proto_handler(us->srb, us);
/* restore original command */
us->srb->cmd_len = old_cmd_len;
memcpy(us->srb->cmnd, saved_cdb, us->srb->cmd_len);
}
/* we've got a command, let's do it! */
else {
US_DEBUG(usb_stor_show_command(us->srb));
......
......@@ -57,27 +57,6 @@
#define USB_ENDPOINT_XFER_BULK 2
#define USB_ENDPOINT_XFER_INT 3
/*
* USB Packet IDs (PIDs)
*/
#define USB_PID_UNDEF_0 0xf0
#define USB_PID_OUT 0xe1
#define USB_PID_ACK 0xd2
#define USB_PID_DATA0 0xc3
#define USB_PID_PING 0xb4 /* USB 2.0 */
#define USB_PID_SOF 0xa5
#define USB_PID_NYET 0x96 /* USB 2.0 */
#define USB_PID_DATA2 0x87 /* USB 2.0 */
#define USB_PID_SPLIT 0x78 /* USB 2.0 */
#define USB_PID_IN 0x69
#define USB_PID_NAK 0x5a
#define USB_PID_DATA1 0x4b
#define USB_PID_PREAMBLE 0x3c /* Token mode */
#define USB_PID_ERR 0x3c /* USB 2.0: handshake mode */
#define USB_PID_SETUP 0x2d
#define USB_PID_STALL 0x1e
#define USB_PID_MDATA 0x0f /* USB 2.0 */
/*
* Standard requests
*/
......@@ -318,8 +297,6 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size,
struct usb_operations;
#define DEVNUM_ROUND_ROBIN /***** OPTION *****/
/*
* Allocated per bus we have
*/
......@@ -327,9 +304,7 @@ struct usb_bus {
int busnum; /* Bus number (in order of reg) */
char *bus_name; /* stable id (PCI slot_name etc) */
#ifdef DEVNUM_ROUND_ROBIN
int devnum_next; /* Next open device number in round-robin allocation */
#endif /* DEVNUM_ROUND_ROBIN */
struct usb_devmap devmap; /* device address allocation map */
struct usb_operations *op; /* Operations (specific to the HC) */
......@@ -353,10 +328,6 @@ struct usb_bus {
atomic_t refcnt;
};
// FIXME: root_hub_string vanishes when "usb_hcd" conversion is done,
// along with pre-hcd versions of the OHCI and UHCI drivers.
extern int usb_root_hub_string(int id, int serial,
char *type, __u8 *data, int len);
/* -------------------------------------------------------------------------- */
......@@ -745,7 +716,7 @@ typedef void (*usb_complete_t)(struct urb *);
/**
* struct urb - USB Request Block
* @urb_list: For use by current owner of the URB.
* @pipe: Holds endpoint number, direction, type, and max packet size.
* @pipe: Holds endpoint number, direction, type, and more.
* Create these values with the eight macros available;
* usb_{snd,rcv}TYPEpipe(dev,endpoint), where the type is "ctrl"
* (control), "bulk", "int" (interrupt), or "iso" (isochronous).
......@@ -774,7 +745,8 @@ typedef void (*usb_complete_t)(struct urb *);
* @transfer_buffer_length: How big is transfer_buffer. The transfer may
* be broken up into chunks according to the current maximum packet
* size for the endpoint, which is a function of the configuration
* and is encoded in the pipe.
* and is encoded in the pipe. When the length is zero, neither
* transfer_buffer nor transfer_dma is used.
* @actual_length: This is read in non-iso completion functions, and
* it tells how many bytes (out of transfer_buffer_length) were
* transferred. It will normally be the same as requested, unless
......@@ -787,7 +759,7 @@ typedef void (*usb_complete_t)(struct urb *);
* (Not used when URB_NO_DMA_MAP is set.)
* @setup_dma: For control transfers with URB_NO_DMA_MAP set, the device
* driver has provided this DMA address for the setup packet. The
* host controller driver should use instead of setup_buffer.
* host controller driver should use this instead of setup_buffer.
* If there is a data phase, its buffer is identified by transfer_dma.
* @start_frame: Returns the initial frame for interrupt or isochronous
* transfers.
......@@ -817,8 +789,9 @@ typedef void (*usb_complete_t)(struct urb *);
* taken from the general page pool. That is provided by transfer_buffer
* (control requests also use setup_packet), and host controller drivers
* perform a dma mapping (and unmapping) for each buffer transferred. Those
* mapping operations can be expensive on some platforms (such using a dma
* bounce buffer), although they're cheap on commodity x86 and ppc hardware.
* mapping operations can be expensive on some platforms (perhaps using a dma
* bounce buffer or talking to an IOMMU),
* although they're cheap on commodity x86 and ppc hardware.
*
* Alternatively, drivers may pass the URB_NO_DMA_MAP transfer flag, which
* tells the host controller driver that no such mapping is needed since
......@@ -884,7 +857,7 @@ typedef void (*usb_complete_t)(struct urb *);
* things that a completion handler should do is check the status field.
* The status field is provided for all URBs. It is used to report
* unlinked URBs, and status for all non-ISO transfers. It should not
* be examined outside of the completion handler.
* be examined before the URB is returned to the completion handler.
*
* The context field is normally used to link URBs back to the relevant
* driver or request state.
......@@ -1075,7 +1048,6 @@ extern int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
int timeout);
/* wrappers around usb_control_msg() for the most common standard requests */
extern int usb_clear_halt(struct usb_device *dev, int pipe);
extern int usb_get_descriptor(struct usb_device *dev, unsigned char desctype,
unsigned char descindex, void *buf, int size);
extern int usb_get_device_descriptor(struct usb_device *dev);
......@@ -1085,6 +1057,9 @@ extern int usb_get_string(struct usb_device *dev,
unsigned short langid, unsigned char index, void *buf, int size);
extern int usb_string(struct usb_device *dev, int index,
char *buf, size_t size);
/* wrappers that also update important state inside usbcore */
extern int usb_clear_halt(struct usb_device *dev, int pipe);
extern int usb_set_configuration(struct usb_device *dev, int configuration);
extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);
......@@ -1123,9 +1098,10 @@ extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);
*
* - max size: bits 0-1 [Historical; now gone.]
* - direction: bit 7 (0 = Host-to-Device [Out],
* 1 = Device-to-Host [In])
* - device: bits 8-14
* - endpoint: bits 15-18
* 1 = Device-to-Host [In] ...
* like endpoint bEndpointAddress)
* - device: bits 8-14 ... bit positions known to uhci-hcd
* - endpoint: bits 15-18 ... bit positions known to uhci-hcd
* - Data0/1: bit 19 [Historical; now gone. ]
* - lowspeed: bit 26 [Historical; now gone. ]
* - pipe type: bits 30-31 (00 = isochronous, 01 = interrupt,
......@@ -1146,10 +1122,9 @@ extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);
#define usb_maxpacket(dev, pipe, out) (out \
? (dev)->epmaxpacketout[usb_pipeendpoint(pipe)] \
: (dev)->epmaxpacketin [usb_pipeendpoint(pipe)] )
#define usb_packetid(pipe) (((pipe) & USB_DIR_IN) ? USB_PID_IN : USB_PID_OUT)
#define usb_pipeout(pipe) ((((pipe) >> 7) & 1) ^ 1)
#define usb_pipein(pipe) (((pipe) >> 7) & 1)
#define usb_pipein(pipe) ((pipe) & USB_DIR_IN)
#define usb_pipeout(pipe) (!usb_pipein(pipe))
#define usb_pipedevice(pipe) (((pipe) >> 8) & 0x7f)
#define usb_pipeendpoint(pipe) (((pipe) >> 15) & 0xf)
#define usb_pipetype(pipe) (((pipe) >> 30) & 3)
......@@ -1158,19 +1133,16 @@ extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);
#define usb_pipecontrol(pipe) (usb_pipetype((pipe)) == PIPE_CONTROL)
#define usb_pipebulk(pipe) (usb_pipetype((pipe)) == PIPE_BULK)
#define PIPE_DEVEP_MASK 0x0007ff00
/* The D0/D1 toggle bits */
/* The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */
#define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1)
#define usb_dotoggle(dev, ep, out) ((dev)->toggle[out] ^= (1 << (ep)))
#define usb_settoggle(dev, ep, out, bit) ((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << (ep))) | ((bit) << (ep)))
/* Endpoint halt control/status */
#define usb_endpoint_out(ep_dir) ((((ep_dir) >> 7) & 1) ^ 1)
#define usb_endpoint_halt(dev, ep, out) ((dev)->halted[out] |= (1 << (ep)))
/* Endpoint halt control/status ... likewise USE WITH CAUTION */
#define usb_endpoint_running(dev, ep, out) ((dev)->halted[out] &= ~(1 << (ep)))
#define usb_endpoint_halted(dev, ep, out) ((dev)->halted[out] & (1 << (ep)))
static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint)
{
return (dev->devnum << 8) | (endpoint << 15);
......@@ -1211,47 +1183,6 @@ void usb_show_string(struct usb_device *dev, char *id, int index);
#define warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n" , ## arg)
/* -------------------------------------------------------------------------- */
/*
* driver list
* exported only for usbfs (not visible outside usbcore)
*/
extern struct list_head usb_driver_list;
/*
* USB device fs stuff
*/
#ifdef CONFIG_USB_DEVICEFS
/*
* these are expected to be called from the USB core/hub thread
* with the kernel lock held
*/
extern void usbfs_add_bus(struct usb_bus *bus);
extern void usbfs_remove_bus(struct usb_bus *bus);
extern void usbfs_add_device(struct usb_device *dev);
extern void usbfs_remove_device(struct usb_device *dev);
extern void usbfs_update_special (void);
extern int usbfs_init(void);
extern void usbfs_cleanup(void);
#else /* CONFIG_USB_DEVICEFS */
static inline void usbfs_add_bus(struct usb_bus *bus) {}
static inline void usbfs_remove_bus(struct usb_bus *bus) {}
static inline void usbfs_add_device(struct usb_device *dev) {}
static inline void usbfs_remove_device(struct usb_device *dev) {}
static inline void usbfs_update_special (void) {}
static inline int usbfs_init(void) { return 0; }
static inline void usbfs_cleanup(void) { }
#endif /* CONFIG_USB_DEVICEFS */
#endif /* __KERNEL__ */
#endif
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