Commit e8825268 authored by Linus Torvalds's avatar Linus Torvalds

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

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 9de88958 34bc27e5
...@@ -109,7 +109,8 @@ static int usb_parse_interface(struct usb_interface *interface, unsigned char *b ...@@ -109,7 +109,8 @@ static int usb_parse_interface(struct usb_interface *interface, unsigned char *b
interface->num_altsetting = 0; interface->num_altsetting = 0;
interface->max_altsetting = USB_ALTSETTINGALLOC; interface->max_altsetting = USB_ALTSETTINGALLOC;
interface->altsetting = kmalloc(sizeof(struct usb_interface_descriptor) * interface->max_altsetting, GFP_KERNEL); interface->altsetting = kmalloc(sizeof(*interface->altsetting) * interface->max_altsetting,
GFP_KERNEL);
if (!interface->altsetting) { if (!interface->altsetting) {
err("couldn't kmalloc interface->altsetting"); err("couldn't kmalloc interface->altsetting");
...@@ -120,27 +121,25 @@ static int usb_parse_interface(struct usb_interface *interface, unsigned char *b ...@@ -120,27 +121,25 @@ static int usb_parse_interface(struct usb_interface *interface, unsigned char *b
struct usb_interface_descriptor *d; struct usb_interface_descriptor *d;
if (interface->num_altsetting >= interface->max_altsetting) { if (interface->num_altsetting >= interface->max_altsetting) {
void *ptr; struct usb_host_interface *ptr;
int oldmas; int oldmas;
oldmas = interface->max_altsetting; oldmas = interface->max_altsetting;
interface->max_altsetting += USB_ALTSETTINGALLOC; interface->max_altsetting += USB_ALTSETTINGALLOC;
if (interface->max_altsetting > USB_MAXALTSETTING) { if (interface->max_altsetting > USB_MAXALTSETTING) {
warn("too many alternate settings (max %d)", warn("too many alternate settings (incr %d max %d)\n",
USB_MAXALTSETTING); USB_ALTSETTINGALLOC, USB_MAXALTSETTING);
return -1; return -1;
} }
ptr = interface->altsetting; ptr = kmalloc(sizeof(*ptr) * interface->max_altsetting, GFP_KERNEL);
interface->altsetting = kmalloc(sizeof(struct usb_interface_descriptor) * interface->max_altsetting, GFP_KERNEL); if (ptr == NULL) {
if (!interface->altsetting) {
err("couldn't kmalloc interface->altsetting"); err("couldn't kmalloc interface->altsetting");
interface->altsetting = ptr;
return -1; return -1;
} }
memcpy(interface->altsetting, ptr, sizeof(struct usb_interface_descriptor) * oldmas); memcpy(ptr, interface->altsetting, sizeof(*interface->altsetting) * oldmas);
kfree(interface->altsetting);
kfree(ptr); interface->altsetting = ptr;
} }
ifp = interface->altsetting + interface->num_altsetting; ifp = interface->altsetting + interface->num_altsetting;
......
/* /*
* USB ViCam WebCam driver * USB ViCam WebCam driver
* Copyright (c) 2002 Joe Burks (jburks@wavicle.org) * Copyright (c) 2002 Joe Burks (jburks@wavicle.org),
* John Tyner (fill in email address)
* *
* Supports 3COM HomeConnect PC Digital WebCam * Supports 3COM HomeConnect PC Digital WebCam
* *
...@@ -43,14 +44,6 @@ ...@@ -43,14 +44,6 @@
// #define VICAM_DEBUG // #define VICAM_DEBUG
#ifndef MODULE_LICENSE
#define MODULE_LICENSE(a)
#endif
#ifndef bool
#define bool int
#endif
#ifdef VICAM_DEBUG #ifdef VICAM_DEBUG
#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __FUNCTION__, lineno, ##args) #define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __FUNCTION__, lineno, ##args)
#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args) #define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args)
...@@ -410,19 +403,20 @@ struct vicam_camera { ...@@ -410,19 +403,20 @@ struct vicam_camera {
u8 *raw_image; // raw data captured from the camera u8 *raw_image; // raw data captured from the camera
u8 *framebuf; // processed data in RGB24 format u8 *framebuf; // processed data in RGB24 format
u8 *cntrlbuf; // area used to send control msgs
struct video_device vdev; // v4l video device struct video_device vdev; // v4l video device
struct usb_device *udev; // usb device struct usb_device *udev; // usb device
struct semaphore busy_lock; // guard against SMP multithreading struct semaphore busy_lock; // guard against SMP multithreading
bool is_initialized; int is_initialized;
u8 open_count; u8 open_count;
u8 bulkEndpoint; u8 bulkEndpoint;
bool needsDummyRead; int needsDummyRead;
#ifdef CONFIG_PROC_FS #if defined(CONFIG_VIDEO_PROC_FS)
struct proc_dir_entry *proc_entry; struct proc_dir_entry *proc_dir;
#endif #endif
}; };
...@@ -437,22 +431,16 @@ send_control_msg(struct usb_device *udev, u8 request, u16 value, u16 index, ...@@ -437,22 +431,16 @@ send_control_msg(struct usb_device *udev, u8 request, u16 value, u16 index,
{ {
int status; int status;
// for reasons not yet known to me, you can't send USB control messages /* cp must be memory that has been allocated by kmalloc */
// with data in the module (if you are compiled as a module). Whatever
// the reason, copying it to memory allocated as kernel memory then
// doing the usb control message fixes the problem.
unsigned char *transfer_buffer = kmalloc(size, GFP_KERNEL);
memcpy(transfer_buffer, cp, size);
status = usb_control_msg(udev, status = usb_control_msg(udev,
usb_sndctrlpipe(udev, 0), usb_sndctrlpipe(udev, 0),
request, request,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_DIR_OUT | USB_TYPE_VENDOR |
USB_RECIP_DEVICE, value, index, USB_RECIP_DEVICE, value, index,
transfer_buffer, size, HZ); cp, size, HZ);
kfree(transfer_buffer); status = min(status, 0);
if (status < 0) { if (status < 0) {
printk(KERN_INFO "Failed sending control message, error %d.\n", printk(KERN_INFO "Failed sending control message, error %d.\n",
...@@ -465,29 +453,30 @@ send_control_msg(struct usb_device *udev, u8 request, u16 value, u16 index, ...@@ -465,29 +453,30 @@ send_control_msg(struct usb_device *udev, u8 request, u16 value, u16 index,
static int static int
initialize_camera(struct vicam_camera *cam) initialize_camera(struct vicam_camera *cam)
{ {
const struct {
u8 *data;
u32 size;
} firmware[] = {
{ .data = setup1, .size = sizeof(setup1) },
{ .data = setup2, .size = sizeof(setup2) },
{ .data = setup3, .size = sizeof(setup3) },
{ .data = setup4, .size = sizeof(setup4) },
{ .data = setup5, .size = sizeof(setup5) },
{ .data = setup3, .size = sizeof(setup3) },
{ .data = NULL, .size = 0 }
};
struct usb_device *udev = cam->udev; struct usb_device *udev = cam->udev;
int status; int err, i;
if ((status = for (i = 0, err = 0; firmware[i].data && !err; i++) {
send_control_msg(udev, 0xff, 0, 0, setup1, sizeof (setup1))) < 0) memcpy(cam->cntrlbuf, firmware[i].data, firmware[i].size);
return status;
if ((status =
send_control_msg(udev, 0xff, 0, 0, setup2, sizeof (setup2))) < 0)
return status;
if ((status =
send_control_msg(udev, 0xff, 0, 0, setup3, sizeof (setup3))) < 0)
return status;
if ((status =
send_control_msg(udev, 0xff, 0, 0, setup4, sizeof (setup4))) < 0)
return status;
if ((status =
send_control_msg(udev, 0xff, 0, 0, setup5, sizeof (setup5))) < 0)
return status;
if ((status =
send_control_msg(udev, 0xff, 0, 0, setup3, sizeof (setup3))) < 0)
return status;
return 0; err = send_control_msg(udev, 0xff, 0, 0,
cam->cntrlbuf, firmware[i].size);
}
return err;
} }
static int static int
...@@ -752,7 +741,8 @@ vicam_open(struct inode *inode, struct file *file) ...@@ -752,7 +741,8 @@ vicam_open(struct inode *inode, struct file *file)
"vicam video_device improperly initialized"); "vicam video_device improperly initialized");
} }
down_interruptible(&cam->busy_lock); if ( down_interruptible(&cam->busy_lock) )
return -EINTR;
if (cam->open_count > 0) { if (cam->open_count > 0) {
printk(KERN_INFO printk(KERN_INFO
...@@ -774,6 +764,14 @@ vicam_open(struct inode *inode, struct file *file) ...@@ -774,6 +764,14 @@ vicam_open(struct inode *inode, struct file *file)
return -ENOMEM; return -ENOMEM;
} }
cam->cntrlbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!cam->cntrlbuf) {
kfree(cam->raw_image);
rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
up(&cam->busy_lock);
return -ENOMEM;
}
// First upload firmware, then turn the camera on // First upload firmware, then turn the camera on
if (!cam->is_initialized) { if (!cam->is_initialized) {
...@@ -803,6 +801,7 @@ vicam_close(struct inode *inode, struct file *file) ...@@ -803,6 +801,7 @@ vicam_close(struct inode *inode, struct file *file)
kfree(cam->raw_image); kfree(cam->raw_image);
rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
kfree(cam->cntrlbuf);
cam->open_count--; cam->open_count--;
...@@ -831,7 +830,7 @@ inline void writepixel(char *rgb, int Y, int Cr, int Cb) ...@@ -831,7 +830,7 @@ inline void writepixel(char *rgb, int Y, int Cr, int Cb)
// Copyright (C) 2002 Monroe Williams (monroe@pobox.com) // Copyright (C) 2002 Monroe Williams (monroe@pobox.com)
// -------------------------------------------------------------------------------- // --------------------------------------------------------------------------------
void vicam_decode_color( char *data, char *rgb) static void vicam_decode_color( char *data, char *rgb)
{ {
int x,y; int x,y;
int Cr, Cb; int Cr, Cb;
...@@ -915,7 +914,7 @@ void vicam_decode_color( char *data, char *rgb) ...@@ -915,7 +914,7 @@ void vicam_decode_color( char *data, char *rgb)
static void static void
read_frame(struct vicam_camera *cam, int framenum) read_frame(struct vicam_camera *cam, int framenum)
{ {
unsigned char request[16]; unsigned char *request = cam->cntrlbuf;
int realShutter; int realShutter;
int n; int n;
int actual_length; int actual_length;
...@@ -984,7 +983,8 @@ vicam_read( struct file *file, char *buf, size_t count, loff_t *ppos ) ...@@ -984,7 +983,8 @@ vicam_read( struct file *file, char *buf, size_t count, loff_t *ppos )
DBG("read %d bytes.\n", (int) count); DBG("read %d bytes.\n", (int) count);
down_interruptible(&cam->busy_lock); if ( down_interruptible(&cam->busy_lock) )
return -EINTR;
if (*ppos >= VICAM_MAX_FRAME_SIZE) { if (*ppos >= VICAM_MAX_FRAME_SIZE) {
*ppos = 0; *ppos = 0;
...@@ -1057,24 +1057,17 @@ vicam_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -1057,24 +1057,17 @@ vicam_mmap(struct file *file, struct vm_area_struct *vma)
return 0; return 0;
} }
#ifdef CONFIG_PROC_FS #if defined(CONFIG_VIDEO_PROC_FS)
static struct proc_dir_entry *vicam_proc_root = NULL; static struct proc_dir_entry *vicam_proc_root = NULL;
static int static int vicam_read_helper(char *page, char **start, off_t off,
vicam_read_proc(char *page, char **start, off_t off, int count, int *eof, int value)
int count, int *eof, void *data)
{ {
char *out = page; char *out = page;
int len; int len;
struct vicam_camera *cam = (struct vicam_camera *) data;
out += out += sprintf(out, "%d",value);
sprintf(out, "Vicam-based WebCam Linux Driver.\n");
out += sprintf(out, "(c) 2002 Joe Burks (jburks@wavicle.org)\n");
out += sprintf(out, "vicam stats:\n");
out += sprintf(out, " Shutter Speed: 1/%d\n", cam->shutter_speed);
out += sprintf(out, " Gain: %d\n", cam->gain);
len = out - page; len = out - page;
len -= off; len -= off;
...@@ -1089,38 +1082,43 @@ vicam_read_proc(char *page, char **start, off_t off, ...@@ -1089,38 +1082,43 @@ vicam_read_proc(char *page, char **start, off_t off,
return len; return len;
} }
static int static int vicam_read_proc_shutter(char *page, char **start, off_t off,
vicam_write_proc(struct file *file, const char *buffer, int count, int *eof, void *data)
unsigned long count, void *data)
{ {
char *in; return vicam_read_helper(page,start,off,count,eof,
char *start; ((struct vicam_camera *)data)->shutter_speed);
struct vicam_camera *cam = (struct vicam_camera *) data; }
in = kmalloc(count + 1, GFP_KERNEL); static int vicam_read_proc_gain(char *page, char **start, off_t off,
if (!in) int count, int *eof, void *data)
return -ENOMEM; {
return vicam_read_helper(page,start,off,count,eof,
((struct vicam_camera *)data)->gain);
}
static int vicam_write_proc_shutter(struct file *file, const char *buffer,
unsigned long count, void *data)
{
struct vicam_camera *cam = (struct vicam_camera *)data;
in[count] = 0; // I'm not sure buffer is gauranteed to be null terminated cam->shutter_speed = simple_strtoul(buffer, NULL, 10);
// so I do this to make sure I have a null in there.
strncpy(in, buffer, count); return count;
}
start = strstr(in, "gain="); static int vicam_write_proc_gain(struct file *file, const char *buffer,
if (start unsigned long count, void *data)
&& (start == in || *(start - 1) == ' ' || *(start - 1) == ',')) {
cam->gain = simple_strtoul(start + 5, NULL, 10); struct vicam_camera *cam = (struct vicam_camera *)data;
start = strstr(in, "shutter="); cam->gain = simple_strtoul(buffer, NULL, 10);
if (start
&& (start == in || *(start - 1) == ' ' || *(start - 1) == ','))
cam->shutter_speed = simple_strtoul(start + 8, NULL, 10);
kfree(in);
return count; return count;
} }
void
static void
vicam_create_proc_root(void) vicam_create_proc_root(void)
{ {
vicam_proc_root = create_proc_entry("video/vicam", S_IFDIR, 0); vicam_proc_root = create_proc_entry("video/vicam", S_IFDIR, 0);
...@@ -1132,19 +1130,17 @@ vicam_create_proc_root(void) ...@@ -1132,19 +1130,17 @@ vicam_create_proc_root(void)
"could not create /proc entry for vicam!"); "could not create /proc entry for vicam!");
} }
void static void
vicam_destroy_proc_root(void) vicam_destroy_proc_root(void)
{ {
if (vicam_proc_root) if (vicam_proc_root)
remove_proc_entry("video/vicam", 0); remove_proc_entry("video/vicam", 0);
} }
void static void
vicam_create_proc_entry(void *ptr) vicam_create_proc_entry(struct vicam_camera *cam)
{ {
struct vicam_camera *cam = (struct vicam_camera *) ptr; char name[64];
char name[7];
struct proc_dir_entry *ent; struct proc_dir_entry *ent;
DBG(KERN_INFO "vicam: creating proc entry\n"); DBG(KERN_INFO "vicam: creating proc entry\n");
...@@ -1158,46 +1154,54 @@ vicam_create_proc_entry(void *ptr) ...@@ -1158,46 +1154,54 @@ vicam_create_proc_entry(void *ptr)
sprintf(name, "video%d", cam->vdev.minor); sprintf(name, "video%d", cam->vdev.minor);
cam->proc_dir = create_proc_entry(name, S_IFDIR, vicam_proc_root);
if ( !cam->proc_dir ) return; // We should probably return an error here
ent = ent =
create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, create_proc_entry("shutter", S_IFREG | S_IRUGO | S_IWUSR,
vicam_proc_root); cam->proc_dir);
if (!ent) if (ent) {
return; ent->data = cam;
ent->read_proc = vicam_read_proc_shutter;
ent->write_proc = vicam_write_proc_shutter;
ent->size = 64;
}
ent = create_proc_entry("gain", S_IFREG | S_IRUGO | S_IWUSR,
cam->proc_dir);
if ( ent ) {
ent->data = cam; ent->data = cam;
ent->read_proc = vicam_read_proc; ent->read_proc = vicam_read_proc_gain;
ent->write_proc = vicam_write_proc; ent->write_proc = vicam_write_proc_gain;
ent->size = 512; ent->size = 64;
cam->proc_entry = ent; }
} }
void static void
vicam_destroy_proc_entry(void *ptr) vicam_destroy_proc_entry(void *ptr)
{ {
struct vicam_camera *cam = (struct vicam_camera *) ptr; struct vicam_camera *cam = (struct vicam_camera *) ptr;
char name[7]; char name[16];
if (!cam || !cam->proc_entry) if ( !cam->proc_dir )
return; return;
sprintf(name, "video%d", cam->vdev.minor); sprintf(name, "video%d", cam->vdev.minor);
remove_proc_entry(name, vicam_proc_root); remove_proc_entry("shutter", cam->proc_dir);
cam->proc_entry = NULL; remove_proc_entry("gain", cam->proc_dir);
remove_proc_entry(name,vicam_proc_root);
cam->proc_dir = NULL;
} }
#else
static inline void vicam_create_proc_root(void) { }
static inline void vicam_destroy_proc_root(void) { }
static inline void vicam_create_proc_entry(struct vicam_camera *cam) { }
static inline void vicam_destroy_proc_entry(void *ptr) { }
#endif #endif
int
vicam_video_init(struct video_device *vdev)
{
// This would normally create the proc entry for this camera
#ifdef CONFIG_PROC_FS
vicam_create_proc_entry(vdev->priv);
#endif
return 0;
}
static struct file_operations vicam_fops = { static struct file_operations vicam_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = vicam_open, .open = vicam_open,
...@@ -1296,6 +1300,8 @@ vicam_probe( struct usb_interface *intf, const struct usb_device_id *id) ...@@ -1296,6 +1300,8 @@ vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
return -EIO; return -EIO;
} }
vicam_create_proc_entry(cam);
printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor); printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
dev_set_drvdata(&intf->dev, cam); dev_set_drvdata(&intf->dev, cam);
...@@ -1314,9 +1320,7 @@ vicam_disconnect(struct usb_interface *intf) ...@@ -1314,9 +1320,7 @@ vicam_disconnect(struct usb_interface *intf)
video_unregister_device(&cam->vdev); video_unregister_device(&cam->vdev);
#ifdef CONFIG_PROC_FS
vicam_destroy_proc_entry(cam); vicam_destroy_proc_entry(cam);
#endif
kfree(cam); kfree(cam);
...@@ -1329,9 +1333,7 @@ static int __init ...@@ -1329,9 +1333,7 @@ static int __init
usb_vicam_init(void) usb_vicam_init(void)
{ {
DBG(KERN_INFO "ViCam-based WebCam driver startup\n"); DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
#ifdef CONFIG_PROC_FS
vicam_create_proc_root(); vicam_create_proc_root();
#endif
if (usb_register(&vicam_driver) != 0) if (usb_register(&vicam_driver) != 0)
printk(KERN_WARNING "usb_register failed!\n"); printk(KERN_WARNING "usb_register failed!\n");
return 0; return 0;
...@@ -1344,9 +1346,7 @@ usb_vicam_exit(void) ...@@ -1344,9 +1346,7 @@ usb_vicam_exit(void)
"ViCam-based WebCam driver shutdown\n"); "ViCam-based WebCam driver shutdown\n");
usb_deregister(&vicam_driver); usb_deregister(&vicam_driver);
#ifdef CONFIG_PROC_FS
vicam_destroy_proc_root(); vicam_destroy_proc_root();
#endif
} }
module_init(usb_vicam_init); module_init(usb_vicam_init);
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
* is out of the interrupt routine. * is out of the interrupt routine.
*/ */
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -46,7 +45,7 @@ ...@@ -46,7 +45,7 @@
/* /*
* Version Information * Version Information
*/ */
#define DRIVER_VERSION "v0.5.6 (2002/06/23)" #define DRIVER_VERSION "v0.5.7 (2002/11/18)"
#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>" #define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
#define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver" #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
...@@ -119,16 +118,9 @@ static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size, ...@@ -119,16 +118,9 @@ static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
void *data) void *data)
{ {
int ret; int ret;
unsigned char *buffer; unsigned char buffer[256];
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
buffer = kmalloc(size, GFP_KERNEL);
if (!buffer) {
err("unable to allocate memory for configuration descriptors");
return 0;
}
memcpy(buffer, data, size);
add_wait_queue(&pegasus->ctrl_wait, &wait); add_wait_queue(&pegasus->ctrl_wait, &wait);
set_current_state(TASK_UNINTERRUPTIBLE); set_current_state(TASK_UNINTERRUPTIBLE);
while (pegasus->flags & ETH_REGS_CHANGED) while (pegasus->flags & ETH_REGS_CHANGED)
...@@ -161,7 +153,6 @@ static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size, ...@@ -161,7 +153,6 @@ static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
out: out:
remove_wait_queue(&pegasus->ctrl_wait, &wait); remove_wait_queue(&pegasus->ctrl_wait, &wait);
memcpy(data, buffer, size); memcpy(data, buffer, size);
kfree(buffer);
return ret; return ret;
} }
...@@ -170,14 +161,9 @@ static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size, ...@@ -170,14 +161,9 @@ static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
void *data) void *data)
{ {
int ret; int ret;
unsigned char *buffer; unsigned char buffer[256];
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
buffer = kmalloc(size, GFP_KERNEL);
if (!buffer) {
err("unable to allocate memory for configuration descriptors");
return 0;
}
memcpy(buffer, data, size); memcpy(buffer, data, size);
add_wait_queue(&pegasus->ctrl_wait, &wait); add_wait_queue(&pegasus->ctrl_wait, &wait);
...@@ -210,7 +196,6 @@ static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size, ...@@ -210,7 +196,6 @@ static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
schedule(); schedule();
out: out:
remove_wait_queue(&pegasus->ctrl_wait, &wait); remove_wait_queue(&pegasus->ctrl_wait, &wait);
kfree(buffer);
return ret; return ret;
} }
...@@ -218,17 +203,9 @@ static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size, ...@@ -218,17 +203,9 @@ static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data) static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data)
{ {
int ret; int ret;
unsigned char *buffer; __u16 tmp = data;
__u16 dat = data;
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
buffer = kmalloc(1, GFP_KERNEL);
if (!buffer) {
err("unable to allocate memory for configuration descriptors");
return 0;
}
memcpy(buffer, &data, 1);
add_wait_queue(&pegasus->ctrl_wait, &wait); add_wait_queue(&pegasus->ctrl_wait, &wait);
set_current_state(TASK_UNINTERRUPTIBLE); set_current_state(TASK_UNINTERRUPTIBLE);
while (pegasus->flags & ETH_REGS_CHANGED) while (pegasus->flags & ETH_REGS_CHANGED)
...@@ -238,7 +215,7 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data) ...@@ -238,7 +215,7 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data)
pegasus->dr.bRequestType = PEGASUS_REQT_WRITE; pegasus->dr.bRequestType = PEGASUS_REQT_WRITE;
pegasus->dr.bRequest = PEGASUS_REQ_SET_REG; pegasus->dr.bRequest = PEGASUS_REQ_SET_REG;
pegasus->dr.wValue = cpu_to_le16p(&dat); pegasus->dr.wValue = cpu_to_le16p(&tmp);
pegasus->dr.wIndex = cpu_to_le16p(&indx); pegasus->dr.wIndex = cpu_to_le16p(&indx);
pegasus->dr.wLength = cpu_to_le16(1); pegasus->dr.wLength = cpu_to_le16(1);
pegasus->ctrl_urb->transfer_buffer_length = 1; pegasus->ctrl_urb->transfer_buffer_length = 1;
...@@ -246,7 +223,7 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data) ...@@ -246,7 +223,7 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data)
usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb,
usb_sndctrlpipe(pegasus->usb, 0), usb_sndctrlpipe(pegasus->usb, 0),
(char *) &pegasus->dr, (char *) &pegasus->dr,
buffer, 1, ctrl_callback, pegasus); &data, 1, ctrl_callback, pegasus);
add_wait_queue(&pegasus->ctrl_wait, &wait); add_wait_queue(&pegasus->ctrl_wait, &wait);
set_current_state(TASK_UNINTERRUPTIBLE); set_current_state(TASK_UNINTERRUPTIBLE);
...@@ -259,7 +236,6 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data) ...@@ -259,7 +236,6 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data)
schedule(); schedule();
out: out:
remove_wait_queue(&pegasus->ctrl_wait, &wait); remove_wait_queue(&pegasus->ctrl_wait, &wait);
kfree(buffer);
return ret; return ret;
} }
...@@ -294,7 +270,7 @@ static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd) ...@@ -294,7 +270,7 @@ static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd)
__u16 regdi; __u16 regdi;
set_register(pegasus, PhyCtrl, 0); set_register(pegasus, PhyCtrl, 0);
set_registers(pegasus, PhyAddr, sizeof(data), data); set_registers(pegasus, PhyAddr, sizeof (data), data);
set_register(pegasus, PhyCtrl, (indx | PHY_READ)); set_register(pegasus, PhyCtrl, (indx | PHY_READ));
for (i = 0; i < REG_TIMEOUT; i++) { for (i = 0; i < REG_TIMEOUT; i++) {
get_registers(pegasus, PhyCtrl, 1, data); get_registers(pegasus, PhyCtrl, 1, data);
...@@ -311,6 +287,15 @@ static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd) ...@@ -311,6 +287,15 @@ static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd)
return 1; return 1;
} }
static int mdio_read(struct net_device *dev, int phy_id, int loc)
{
pegasus_t *pegasus = (pegasus_t *) dev->priv;
int res;
read_mii_word(pegasus, phy_id, loc, (u16 *) & res);
return res & 0xffff;
}
static int write_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 regd) static int write_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 regd)
{ {
int i; int i;
...@@ -332,6 +317,13 @@ static int write_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 regd) ...@@ -332,6 +317,13 @@ static int write_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 regd)
return 1; return 1;
} }
static void mdio_write(struct net_device *dev, int phy_id, int loc, int val)
{
pegasus_t *pegasus = (pegasus_t *) dev->priv;
write_mii_word(pegasus, phy_id, loc, val);
}
static int read_eprom_word(pegasus_t * pegasus, __u8 index, __u16 * retdata) static int read_eprom_word(pegasus_t * pegasus, __u8 index, __u16 * retdata)
{ {
int i; int i;
...@@ -415,8 +407,8 @@ static void set_ethernet_addr(pegasus_t * pegasus) ...@@ -415,8 +407,8 @@ static void set_ethernet_addr(pegasus_t * pegasus)
__u8 node_id[6]; __u8 node_id[6];
get_node_id(pegasus, node_id); get_node_id(pegasus, node_id);
set_registers(pegasus, EthID, sizeof(node_id), node_id); set_registers(pegasus, EthID, sizeof (node_id), node_id);
memcpy(pegasus->net->dev_addr, node_id, sizeof(node_id)); memcpy(pegasus->net->dev_addr, node_id, sizeof (node_id));
} }
static inline int reset_mac(pegasus_t * pegasus) static inline int reset_mac(pegasus_t * pegasus)
...@@ -473,7 +465,7 @@ static int enable_net_traffic(struct net_device *dev, struct usb_device *usb) ...@@ -473,7 +465,7 @@ static int enable_net_traffic(struct net_device *dev, struct usb_device *usb)
data[1] = 0; data[1] = 0;
data[2] = (loopback & 1) ? 0x09 : 0x01; data[2] = (loopback & 1) ? 0x09 : 0x01;
memcpy(pegasus->eth_regs, data, sizeof(data)); memcpy(pegasus->eth_regs, data, sizeof (data));
set_registers(pegasus, EthCtrl0, 3, data); set_registers(pegasus, EthCtrl0, 3, data);
if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS || if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
...@@ -486,11 +478,11 @@ static int enable_net_traffic(struct net_device *dev, struct usb_device *usb) ...@@ -486,11 +478,11 @@ static int enable_net_traffic(struct net_device *dev, struct usb_device *usb)
return 0; return 0;
} }
static void fill_skb_pool(pegasus_t *pegasus) static void fill_skb_pool(pegasus_t * pegasus)
{ {
int i; int i;
for (i=0; i < RX_SKBS; i++) { for (i = 0; i < RX_SKBS; i++) {
if (pegasus->rx_pool[i]) if (pegasus->rx_pool[i])
continue; continue;
pegasus->rx_pool[i] = dev_alloc_skb(PEGASUS_MTU + 2); pegasus->rx_pool[i] = dev_alloc_skb(PEGASUS_MTU + 2);
...@@ -505,11 +497,11 @@ static void fill_skb_pool(pegasus_t *pegasus) ...@@ -505,11 +497,11 @@ static void fill_skb_pool(pegasus_t *pegasus)
} }
} }
static void free_skb_pool(pegasus_t *pegasus) static void free_skb_pool(pegasus_t * pegasus)
{ {
int i; int i;
for (i=0; i < RX_SKBS; i++) { for (i = 0; i < RX_SKBS; i++) {
if (pegasus->rx_pool[i]) { if (pegasus->rx_pool[i]) {
dev_kfree_skb(pegasus->rx_pool[i]); dev_kfree_skb(pegasus->rx_pool[i]);
pegasus->rx_pool[i] = NULL; pegasus->rx_pool[i] = NULL;
...@@ -517,12 +509,12 @@ static void free_skb_pool(pegasus_t *pegasus) ...@@ -517,12 +509,12 @@ static void free_skb_pool(pegasus_t *pegasus)
} }
} }
static inline struct sk_buff *pull_skb(pegasus_t *pegasus) static inline struct sk_buff *pull_skb(pegasus_t * pegasus)
{ {
int i; int i;
struct sk_buff *skb; struct sk_buff *skb;
for (i=0; i < RX_SKBS; i++) { for (i = 0; i < RX_SKBS; i++) {
if (likely(pegasus->rx_pool[i] != NULL)) { if (likely(pegasus->rx_pool[i] != NULL)) {
skb = pegasus->rx_pool[i]; skb = pegasus->rx_pool[i];
pegasus->rx_pool[i] = NULL; pegasus->rx_pool[i] = NULL;
...@@ -563,7 +555,7 @@ static void read_bulk_callback(struct urb *urb) ...@@ -563,7 +555,7 @@ static void read_bulk_callback(struct urb *urb)
if (!count) if (!count)
goto goon; goto goon;
rx_status = le32_to_cpu(*(int *)(urb->transfer_buffer + count - 4)); rx_status = le32_to_cpu(*(int *) (urb->transfer_buffer + count - 4));
if (rx_status & 0x000e0000) { if (rx_status & 0x000e0000) {
dbg("%s: RX packet error %x", net->name, rx_status & 0xe0000); dbg("%s: RX packet error %x", net->name, rx_status & 0xe0000);
pegasus->stats.rx_errors++; pegasus->stats.rx_errors++;
...@@ -575,13 +567,17 @@ static void read_bulk_callback(struct urb *urb) ...@@ -575,13 +567,17 @@ static void read_bulk_callback(struct urb *urb)
pegasus->stats.rx_frame_errors++; pegasus->stats.rx_frame_errors++;
goto goon; goto goon;
} }
if (pegasus->chip == 0x8513) {
pkt_len = le32_to_cpu(*(int *)urb->transfer_buffer);
pkt_len &= 0x0fff;
pegasus->rx_skb->data += 2;
} else {
pkt_len = (rx_status & 0xfff) - 8; pkt_len = (rx_status & 0xfff) - 8;
}
if (pegasus->rx_skb == NULL)
printk("%s: rx_skb == NULL\n", __FUNCTION__);
/* /*
** we are sure at this point pegasus->rx_skb != NULL * at this point we are sure pegasus->rx_skb != NULL
** so we go ahead and pass up the packet. * so we go ahead and pass up the packet.
*/ */
skb_put(pegasus->rx_skb, pkt_len); skb_put(pegasus->rx_skb, pkt_len);
pegasus->rx_skb->protocol = eth_type_trans(pegasus->rx_skb, net); pegasus->rx_skb->protocol = eth_type_trans(pegasus->rx_skb, net);
...@@ -609,7 +605,7 @@ static void read_bulk_callback(struct urb *urb) ...@@ -609,7 +605,7 @@ static void read_bulk_callback(struct urb *urb)
return; return;
tl_sched: tl_sched:
tasklet_schedule(&pegasus->rx_tl); tasklet_schedule(&pegasus->rx_tl);
} }
...@@ -617,7 +613,7 @@ static void rx_fixup(unsigned long data) ...@@ -617,7 +613,7 @@ static void rx_fixup(unsigned long data)
{ {
pegasus_t *pegasus; pegasus_t *pegasus;
pegasus = (pegasus_t *)data; pegasus = (pegasus_t *) data;
spin_lock_irq(&pegasus->rx_pool_lock); spin_lock_irq(&pegasus->rx_pool_lock);
fill_skb_pool(pegasus); fill_skb_pool(pegasus);
...@@ -704,10 +700,9 @@ static void intr_callback(struct urb *urb) ...@@ -704,10 +700,9 @@ static void intr_callback(struct urb *urb)
} }
} }
status = usb_submit_urb (urb, SLAB_ATOMIC); status = usb_submit_urb(urb, SLAB_ATOMIC);
if (status) if (status)
err ("%s: can't resubmit interrupt urb, %d", err("%s: can't resubmit interrupt urb, %d", net->name, status);
net->name, status);
} }
static void pegasus_tx_timeout(struct net_device *net) static void pegasus_tx_timeout(struct net_device *net)
...@@ -794,7 +789,7 @@ static void set_carrier(struct net_device *net) ...@@ -794,7 +789,7 @@ static void set_carrier(struct net_device *net)
} }
static void free_all_urbs(pegasus_t *pegasus) static void free_all_urbs(pegasus_t * pegasus)
{ {
usb_free_urb(pegasus->intr_urb); usb_free_urb(pegasus->intr_urb);
usb_free_urb(pegasus->tx_urb); usb_free_urb(pegasus->tx_urb);
...@@ -802,7 +797,7 @@ static void free_all_urbs(pegasus_t *pegasus) ...@@ -802,7 +797,7 @@ static void free_all_urbs(pegasus_t *pegasus)
usb_free_urb(pegasus->ctrl_urb); usb_free_urb(pegasus->ctrl_urb);
} }
static void unlink_all_urbs(pegasus_t *pegasus) static void unlink_all_urbs(pegasus_t * pegasus)
{ {
usb_unlink_urb(pegasus->intr_urb); usb_unlink_urb(pegasus->intr_urb);
usb_unlink_urb(pegasus->tx_urb); usb_unlink_urb(pegasus->tx_urb);
...@@ -810,7 +805,7 @@ static void unlink_all_urbs(pegasus_t *pegasus) ...@@ -810,7 +805,7 @@ static void unlink_all_urbs(pegasus_t *pegasus)
usb_unlink_urb(pegasus->ctrl_urb); usb_unlink_urb(pegasus->ctrl_urb);
} }
static int alloc_urbs(pegasus_t *pegasus) static int alloc_urbs(pegasus_t * pegasus)
{ {
pegasus->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); pegasus->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!pegasus->ctrl_urb) { if (!pegasus->ctrl_urb) {
...@@ -860,7 +855,7 @@ static int pegasus_open(struct net_device *net) ...@@ -860,7 +855,7 @@ static int pegasus_open(struct net_device *net)
warn("%s: failed rx_urb %d", __FUNCTION__, res); warn("%s: failed rx_urb %d", __FUNCTION__, res);
usb_fill_int_urb(pegasus->intr_urb, pegasus->usb, usb_fill_int_urb(pegasus->intr_urb, pegasus->usb,
usb_rcvintpipe(pegasus->usb, 3), usb_rcvintpipe(pegasus->usb, 3),
pegasus->intr_buff, sizeof(pegasus->intr_buff), pegasus->intr_buff, sizeof (pegasus->intr_buff),
intr_callback, pegasus, pegasus->intr_interval); intr_callback, pegasus, pegasus->intr_interval);
if ((res = usb_submit_urb(pegasus->intr_urb, GFP_KERNEL))) if ((res = usb_submit_urb(pegasus->intr_urb, GFP_KERNEL)))
warn("%s: failed intr_urb %d", __FUNCTION__, res); warn("%s: failed intr_urb %d", __FUNCTION__, res);
...@@ -896,7 +891,82 @@ static int pegasus_close(struct net_device *net) ...@@ -896,7 +891,82 @@ static int pegasus_close(struct net_device *net)
return 0; return 0;
} }
#ifdef CONFIG_MII
static int pegasus_ethtool_ioctl(struct net_device *dev, void *useraddr)
{
u32 ethcmd;
pegasus_t *pegasus = dev->priv;
if (copy_from_user(&ethcmd, useraddr, sizeof (ethcmd)))
return -EFAULT;
switch (ethcmd) {
/* get driver-specific version/etc. info */
case ETHTOOL_GDRVINFO:{
struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
strncpy(info.driver, driver_name,
sizeof (info.driver) - 1);
strncpy(info.version, DRIVER_VERSION,
sizeof (info.version) - 1);
if (copy_to_user(useraddr, &info, sizeof (info)))
return -EFAULT;
return 0;
}
/* get settings */
case ETHTOOL_GSET:{
struct ethtool_cmd ecmd = { ETHTOOL_GSET };
mii_ethtool_gset(&pegasus->mii, &ecmd);
if (copy_to_user(useraddr, &ecmd, sizeof (ecmd)))
return -EFAULT;
return 0;
}
/* set settings */
case ETHTOOL_SSET:{
int r;
struct ethtool_cmd ecmd;
if (copy_from_user(&ecmd, useraddr, sizeof (ecmd)))
return -EFAULT;
r = mii_ethtool_sset(&pegasus->mii, &ecmd);
return r;
}
/* restart autonegotiation */
case ETHTOOL_NWAY_RST:{
return mii_nway_restart(&pegasus->mii);
}
/* get link status */
case ETHTOOL_GLINK:{
struct ethtool_value edata = { ETHTOOL_GLINK };
edata.data = mii_link_ok(&pegasus->mii);
if (copy_to_user(useraddr, &edata, sizeof (edata)))
return -EFAULT;
return 0;
}
/* get message-level */
case ETHTOOL_GMSGLVL:{
struct ethtool_value edata = { ETHTOOL_GMSGLVL };
/* edata.data = pegasus->msg_enable; FIXME */
if (copy_to_user(useraddr, &edata, sizeof (edata)))
return -EFAULT;
return 0;
}
/* set message-level */
case ETHTOOL_SMSGLVL:{
struct ethtool_value edata;
if (copy_from_user(&edata, useraddr, sizeof (edata)))
return -EFAULT;
/* sp->msg_enable = edata.data; FIXME */
return 0;
}
}
return -EOPNOTSUPP;
}
#else
static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr) static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr)
{ {
pegasus_t *pegasus; pegasus_t *pegasus;
...@@ -913,7 +983,7 @@ static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr) ...@@ -913,7 +983,7 @@ static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr)
ETHTOOL_BUSINFO_LEN); ETHTOOL_BUSINFO_LEN);
usb_make_path(pegasus->usb, info.bus_info, usb_make_path(pegasus->usb, info.bus_info,
sizeof info.bus_info); sizeof info.bus_info);
if (copy_to_user(uaddr, &info, sizeof(info))) if (copy_to_user(uaddr, &info, sizeof (info)))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
...@@ -950,7 +1020,7 @@ static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr) ...@@ -950,7 +1020,7 @@ static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr)
ecmd.duplex = bmcr & BMCR_FULLDPLX ? ecmd.duplex = bmcr & BMCR_FULLDPLX ?
DUPLEX_FULL : DUPLEX_HALF; DUPLEX_FULL : DUPLEX_HALF;
} }
if (copy_to_user(uaddr, &ecmd, sizeof(ecmd))) if (copy_to_user(uaddr, &ecmd, sizeof (ecmd)))
return -EFAULT; return -EFAULT;
return 0; return 0;
...@@ -961,7 +1031,7 @@ static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr) ...@@ -961,7 +1031,7 @@ static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr)
case ETHTOOL_GLINK:{ case ETHTOOL_GLINK:{
struct ethtool_value edata = { ETHTOOL_GLINK }; struct ethtool_value edata = { ETHTOOL_GLINK };
edata.data = netif_carrier_ok(net); edata.data = netif_carrier_ok(net);
if (copy_to_user(uaddr, &edata, sizeof(edata))) if (copy_to_user(uaddr, &edata, sizeof (edata)))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
...@@ -969,7 +1039,7 @@ static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr) ...@@ -969,7 +1039,7 @@ static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr)
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
} }
#endif
static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd) static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
{ {
__u16 *data = (__u16 *) & rq->ifr_data; __u16 *data = (__u16 *) & rq->ifr_data;
...@@ -1045,8 +1115,26 @@ static __u8 mii_phy_probe(pegasus_t * pegasus) ...@@ -1045,8 +1115,26 @@ static __u8 mii_phy_probe(pegasus_t * pegasus)
static inline void setup_pegasus_II(pegasus_t * pegasus) static inline void setup_pegasus_II(pegasus_t * pegasus)
{ {
u16 data = 0xa5;
set_register(pegasus, Reg1d, 0); set_register(pegasus, Reg1d, 0);
set_register(pegasus, Reg7b, 1);
mdelay(100);
set_register(pegasus, Reg7b, 2); set_register(pegasus, Reg7b, 2);
set_register(pegasus, 0x83, data);
get_registers(pegasus, 0x83, 1, &data);
if (data == 0xa5) {
pegasus->chip = 0x8513;
} else {
pegasus->chip = 0;
}
set_register(pegasus, 0x80, 0xc0);
set_register(pegasus, 0x83, 0xff);
set_register(pegasus, 0x84, 0x01);
if (pegasus->features & HAS_HOME_PNA && mii_mode) if (pegasus->features & HAS_HOME_PNA && mii_mode)
set_register(pegasus, Reg81, 6); set_register(pegasus, Reg81, 6);
else else
...@@ -1065,13 +1153,13 @@ static int pegasus_probe(struct usb_interface *intf, ...@@ -1065,13 +1153,13 @@ static int pegasus_probe(struct usb_interface *intf,
err("usb_set_configuration() failed"); err("usb_set_configuration() failed");
return -ENODEV; return -ENODEV;
} }
if (!(pegasus = kmalloc(sizeof(struct pegasus), GFP_KERNEL))) { if (!(pegasus = kmalloc(sizeof (struct pegasus), GFP_KERNEL))) {
err("out of memory allocating device structure"); err("out of memory allocating device structure");
return -ENOMEM; return -ENOMEM;
} }
usb_get_dev(dev); usb_get_dev(dev);
memset(pegasus, 0, sizeof(struct pegasus)); memset(pegasus, 0, sizeof (struct pegasus));
pegasus->dev_index = dev_index; pegasus->dev_index = dev_index;
init_waitqueue_head(&pegasus->ctrl_wait); init_waitqueue_head(&pegasus->ctrl_wait);
...@@ -1088,7 +1176,7 @@ static int pegasus_probe(struct usb_interface *intf, ...@@ -1088,7 +1176,7 @@ static int pegasus_probe(struct usb_interface *intf,
} }
init_MUTEX(&pegasus->sem); init_MUTEX(&pegasus->sem);
tasklet_init(&pegasus->rx_tl, rx_fixup, (unsigned long)pegasus); tasklet_init(&pegasus->rx_tl, rx_fixup, (unsigned long) pegasus);
down(&pegasus->sem); down(&pegasus->sem);
pegasus->usb = dev; pegasus->usb = dev;
...@@ -1104,6 +1192,11 @@ static int pegasus_probe(struct usb_interface *intf, ...@@ -1104,6 +1192,11 @@ static int pegasus_probe(struct usb_interface *intf,
net->set_multicast_list = pegasus_set_multicast; net->set_multicast_list = pegasus_set_multicast;
net->get_stats = pegasus_netdev_stats; net->get_stats = pegasus_netdev_stats;
net->mtu = PEGASUS_MTU; net->mtu = PEGASUS_MTU;
pegasus->mii.dev = net;
pegasus->mii.mdio_read = mdio_read;
pegasus->mii.mdio_write = mdio_write;
pegasus->mii.phy_id_mask = 0x1f;
pegasus->mii.reg_num_mask = 0x1f;
spin_lock_init(&pegasus->rx_pool_lock); spin_lock_init(&pegasus->rx_pool_lock);
pegasus->features = usb_dev_id[dev_index].private; pegasus->features = usb_dev_id[dev_index].private;
...@@ -1132,7 +1225,7 @@ static int pegasus_probe(struct usb_interface *intf, ...@@ -1132,7 +1225,7 @@ static int pegasus_probe(struct usb_interface *intf,
exit: exit:
up(&pegasus->sem); up(&pegasus->sem);
if (pegasus) { if (pegasus) {
dev_set_drvdata (&intf->dev, pegasus); dev_set_drvdata(&intf->dev, pegasus);
return 0; return 0;
} }
return -EIO; return -EIO;
...@@ -1140,9 +1233,9 @@ static int pegasus_probe(struct usb_interface *intf, ...@@ -1140,9 +1233,9 @@ static int pegasus_probe(struct usb_interface *intf,
static void pegasus_disconnect(struct usb_interface *intf) static void pegasus_disconnect(struct usb_interface *intf)
{ {
struct pegasus *pegasus = dev_get_drvdata (&intf->dev); struct pegasus *pegasus = dev_get_drvdata(&intf->dev);
dev_set_drvdata (&intf->dev, NULL); dev_set_drvdata(&intf->dev, NULL);
if (!pegasus) { if (!pegasus) {
warn("unregistering non-existant device"); warn("unregistering non-existant device");
return; return;
......
...@@ -85,6 +85,7 @@ typedef struct pegasus { ...@@ -85,6 +85,7 @@ typedef struct pegasus {
struct usb_device *usb; struct usb_device *usb;
struct net_device *net; struct net_device *net;
struct net_device_stats stats; struct net_device_stats stats;
struct mii_if_info mii;
unsigned flags; unsigned flags;
unsigned features; unsigned features;
int dev_index; int dev_index;
...@@ -97,6 +98,7 @@ typedef struct pegasus { ...@@ -97,6 +98,7 @@ typedef struct pegasus {
wait_queue_head_t ctrl_wait; wait_queue_head_t ctrl_wait;
struct semaphore sem; struct semaphore sem;
spinlock_t rx_pool_lock; spinlock_t rx_pool_lock;
int chip;
unsigned char intr_buff[8]; unsigned char intr_buff[8];
__u8 tx_buff[PEGASUS_MTU]; __u8 tx_buff[PEGASUS_MTU];
__u8 eth_regs[4]; __u8 eth_regs[4];
...@@ -131,11 +133,11 @@ struct usb_eth_dev { ...@@ -131,11 +133,11 @@ struct usb_eth_dev {
#define VENDOR_LANEED 0x056e #define VENDOR_LANEED 0x056e
#define VENDOR_LINKSYS 0x066b #define VENDOR_LINKSYS 0x066b
#define VENDOR_MELCO 0x0411 #define VENDOR_MELCO 0x0411
#define VENDOR_NETGEAR 0x0846
#define VENDOR_SMARTBRIDGES 0x08d1 #define VENDOR_SMARTBRIDGES 0x08d1
#define VENDOR_SMC 0x0707 #define VENDOR_SMC 0x0707
#define VENDOR_SOHOWARE 0x15e8 #define VENDOR_SOHOWARE 0x15e8
#define VENDOR_SIEMENS 0x067c #define VENDOR_SIEMENS 0x067c
#define VENDOR_JTEC 0x11ad
#else /* PEGASUS_DEV */ #else /* PEGASUS_DEV */
...@@ -169,7 +171,10 @@ PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046, ...@@ -169,7 +171,10 @@ PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046,
PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet", PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet",
VENDOR_ADMTEK, 0x8511, VENDOR_ADMTEK, 0x8511,
DEFAULT_GPIO_RESET | PEGASUS_II ) DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (eval. board)", PEGASUS_DEV( "ADMtek ADM8513 \"Pegasus II\" USB Ethernet",
VENDOR_ADMTEK, 0x8513,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (evaluation board)",
VENDOR_ADMTEK, 0x0986, VENDOR_ADMTEK, 0x0986,
DEFAULT_GPIO_RESET | HAS_HOME_PNA ) DEFAULT_GPIO_RESET | HAS_HOME_PNA )
PEGASUS_DEV( "AN986A USB MAC", VENDOR_ADMTEK, 1986, PEGASUS_DEV( "AN986A USB MAC", VENDOR_ADMTEK, 1986,
...@@ -192,7 +197,7 @@ PEGASUS_DEV( "Billionton USBE-100", VENDOR_BILLIONTON, 0x8511, ...@@ -192,7 +197,7 @@ PEGASUS_DEV( "Billionton USBE-100", VENDOR_BILLIONTON, 0x8511,
DEFAULT_GPIO_RESET | PEGASUS_II ) DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Corega FEter USB-TX", VENDOR_COREGA, 0x0004, PEGASUS_DEV( "Corega FEter USB-TX", VENDOR_COREGA, 0x0004,
DEFAULT_GPIO_RESET ) DEFAULT_GPIO_RESET )
PEGASUS_DEV( "Corega FEter", VENDOR_COREGA, 0x000d, PEGASUS_DEV( "Corega FEter USB-TXS", VENDOR_COREGA, 0x000d,
DEFAULT_GPIO_RESET | PEGASUS_II ) DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4001, PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4001,
LINKSYS_GPIO_RESET ) LINKSYS_GPIO_RESET )
...@@ -246,6 +251,8 @@ PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0005, ...@@ -246,6 +251,8 @@ PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0005,
DEFAULT_GPIO_RESET ) DEFAULT_GPIO_RESET )
PEGASUS_DEV( "MELCO/BUFFALO LUA2-TX", VENDOR_MELCO, 0x0009, PEGASUS_DEV( "MELCO/BUFFALO LUA2-TX", VENDOR_MELCO, 0x0009,
DEFAULT_GPIO_RESET | PEGASUS_II ) DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "NETGEAR FA101", VENDOR_NETGEAR, 0x1020,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "smartNIC 2 PnP Adapter", VENDOR_SMARTBRIDGES, 0x0003, PEGASUS_DEV( "smartNIC 2 PnP Adapter", VENDOR_SMARTBRIDGES, 0x0003,
DEFAULT_GPIO_RESET | PEGASUS_II ) DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200, PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200,
...@@ -258,8 +265,6 @@ PEGASUS_DEV( "SOHOware NUB110 Ethernet", VENDOR_SOHOWARE, 0x9110, ...@@ -258,8 +265,6 @@ PEGASUS_DEV( "SOHOware NUB110 Ethernet", VENDOR_SOHOWARE, 0x9110,
DEFAULT_GPIO_RESET | PEGASUS_II ) DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_SIEMENS, 0x1001, PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_SIEMENS, 0x1001,
DEFAULT_GPIO_RESET | PEGASUS_II ) DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "FA8101 USB To ETHERNET", VENDOR_JTEC, 0x8101,
DEFAULT_GPIO_RESET | PEGASUS_II )
#endif /* PEGASUS_DEV */ #endif /* PEGASUS_DEV */
...@@ -14,6 +14,10 @@ ...@@ -14,6 +14,10 @@
* *
* See Documentation/usb/usb-serial.txt for more information on using this driver * See Documentation/usb/usb-serial.txt for more information on using this driver
* *
* (11/19/2002) gkh
* removed a few #ifdefs for the generic code and cleaned up the failure
* logic in initialization.
*
* (10/02/2002) gkh * (10/02/2002) gkh
* moved the console code to console.c and out of this file. * moved the console code to console.c and out of this file.
* *
...@@ -341,7 +345,7 @@ ...@@ -341,7 +345,7 @@
/* /*
* Version Information * Version Information
*/ */
#define DRIVER_VERSION "v1.6" #define DRIVER_VERSION "v1.7"
#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/" #define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/"
#define DRIVER_DESC "USB Serial Driver core" #define DRIVER_DESC "USB Serial Driver core"
...@@ -382,7 +386,29 @@ static struct usb_device_id generic_serial_ids[] = { ...@@ -382,7 +386,29 @@ static struct usb_device_id generic_serial_ids[] = {
{.driver_info = 42}, {.driver_info = 42},
{} {}
}; };
#endif
static int generic_register (void)
{
generic_device_ids[0].idVendor = vendor;
generic_device_ids[0].idProduct = product;
generic_device_ids[0].match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT;
/* register our generic driver with ourselves */
return usb_serial_register (&generic_device);
}
static void generic_deregister (void)
{
/* remove our generic driver */
usb_serial_deregister (&generic_device);
}
#else
static inline int generic_register (void) { return 0; }
static inline void generic_deregister (void) { }
#endif /* CONFIG_USB_SERIAL_GENERIC */
/* Driver structure we register with the USB core */ /* Driver structure we register with the USB core */
static struct usb_driver usb_serial_driver = { static struct usb_driver usb_serial_driver = {
...@@ -409,7 +435,6 @@ static struct termios * serial_termios_locked[SERIAL_TTY_MINORS]; ...@@ -409,7 +435,6 @@ static struct termios * serial_termios_locked[SERIAL_TTY_MINORS];
static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */ static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */
static LIST_HEAD(usb_serial_driver_list); static LIST_HEAD(usb_serial_driver_list);
struct usb_serial *usb_serial_get_by_minor (unsigned int minor) struct usb_serial *usb_serial_get_by_minor (unsigned int minor)
{ {
return serial_table[minor]; return serial_table[minor];
...@@ -839,7 +864,7 @@ static int serial_read_proc (char *page, char **start, off_t off, int count, int ...@@ -839,7 +864,7 @@ static int serial_read_proc (char *page, char **start, off_t off, int count, int
length += sprintf (page+length, "%d:", i); length += sprintf (page+length, "%d:", i);
if (serial->type->owner) if (serial->type->owner)
length += sprintf (page+length, " module:%s", serial->type->owner->name); length += sprintf (page+length, " module:%s", module_name(serial->type->owner));
length += sprintf (page+length, " name:\"%s\"", serial->type->name); length += sprintf (page+length, " name:\"%s\"", serial->type->name);
length += sprintf (page+length, " vendor:%04x product:%04x", serial->vendor, serial->product); length += sprintf (page+length, " vendor:%04x product:%04x", serial->vendor, serial->product);
length += sprintf (page+length, " num_ports:%d", serial->num_ports); length += sprintf (page+length, " num_ports:%d", serial->num_ports);
...@@ -1574,40 +1599,49 @@ static struct tty_driver serial_tty_driver = { ...@@ -1574,40 +1599,49 @@ static struct tty_driver serial_tty_driver = {
static int __init usb_serial_init(void) static int __init usb_serial_init(void)
{ {
int i; int i;
int result; int result = 0;
/* Initalize our global data */ /* Initalize our global data */
for (i = 0; i < SERIAL_TTY_MINORS; ++i) { for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
serial_table[i] = NULL; serial_table[i] = NULL;
} }
/* register the generic driver, if we should */
result = generic_register();
if (result < 0) {
err("%s - registering generic driver failed", __FUNCTION__);
goto exit;
}
/* register the tty driver */ /* register the tty driver */
serial_tty_driver.init_termios = tty_std_termios; serial_tty_driver.init_termios = tty_std_termios;
serial_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; serial_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
if (tty_register_driver (&serial_tty_driver)) { result = tty_register_driver (&serial_tty_driver);
err("%s - failed to register tty driver", __FUNCTION__); if (result) {
return -1; err("%s - tty_register_driver failed", __FUNCTION__);
goto exit_generic;
} }
/* register the USB driver */ /* register the USB driver */
result = usb_register(&usb_serial_driver); result = usb_register(&usb_serial_driver);
if (result < 0) { if (result < 0) {
tty_unregister_driver(&serial_tty_driver); err("%s - usb_register failed", __FUNCTION__);
err("usb_register failed for the usb-serial driver. Error number %d", result); goto exit_tty;
return -1;
} }
#ifdef CONFIG_USB_SERIAL_GENERIC
generic_device_ids[0].idVendor = vendor;
generic_device_ids[0].idProduct = product;
generic_device_ids[0].match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT;
/* register our generic driver with ourselves */
usb_serial_register (&generic_device);
#endif
info(DRIVER_DESC " " DRIVER_VERSION); info(DRIVER_DESC " " DRIVER_VERSION);
return 0; return result;
exit_tty:
tty_unregister_driver(&serial_tty_driver);
exit_generic:
generic_deregister();
exit:
err ("%s - returning with error %d", __FUNCTION__, result);
return result;
} }
...@@ -1615,10 +1649,7 @@ static void __exit usb_serial_exit(void) ...@@ -1615,10 +1649,7 @@ static void __exit usb_serial_exit(void)
{ {
usb_serial_console_exit(); usb_serial_console_exit();
#ifdef CONFIG_USB_SERIAL_GENERIC generic_deregister();
/* remove our generic driver */
usb_serial_deregister (&generic_device);
#endif
usb_deregister(&usb_serial_driver); usb_deregister(&usb_serial_driver);
tty_unregister_driver(&serial_tty_driver); tty_unregister_driver(&serial_tty_driver);
......
...@@ -115,7 +115,7 @@ freecom_readdata (Scsi_Cmnd *srb, struct us_data *us, ...@@ -115,7 +115,7 @@ freecom_readdata (Scsi_Cmnd *srb, struct us_data *us,
freecom_udata_t extra = (freecom_udata_t) us->extra; freecom_udata_t extra = (freecom_udata_t) us->extra;
struct freecom_xfer_wrap *fxfr = struct freecom_xfer_wrap *fxfr =
(struct freecom_xfer_wrap *) extra->buffer; (struct freecom_xfer_wrap *) extra->buffer;
int result, partial; int result;
fxfr->Type = FCM_PACKET_INPUT | 0x00; fxfr->Type = FCM_PACKET_INPUT | 0x00;
fxfr->Timeout = 0; /* Short timeout for debugging. */ fxfr->Timeout = 0; /* Short timeout for debugging. */
...@@ -125,14 +125,12 @@ freecom_readdata (Scsi_Cmnd *srb, struct us_data *us, ...@@ -125,14 +125,12 @@ freecom_readdata (Scsi_Cmnd *srb, struct us_data *us,
US_DEBUGP("Read data Freecom! (c=%d)\n", count); US_DEBUGP("Read data Freecom! (c=%d)\n", count);
/* Issue the transfer command. */ /* Issue the transfer command. */
result = usb_stor_bulk_msg (us, fxfr, opipe, result = usb_stor_bulk_transfer_buf (us, opipe, fxfr,
FCM_PACKET_LENGTH, &partial); FCM_PACKET_LENGTH, NULL);
if (result != USB_STOR_XFER_GOOD) { if (result != USB_STOR_XFER_GOOD) {
US_DEBUGP ("Freecom readdata xport failure: r=%d, p=%d\n", US_DEBUGP ("Freecom readdata transport error\n");
result, partial);
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
} }
US_DEBUGP("Done issuing read request: %d %d\n", result, partial);
/* Now transfer all of our blocks. */ /* Now transfer all of our blocks. */
US_DEBUGP("Start of read\n"); US_DEBUGP("Start of read\n");
...@@ -151,7 +149,7 @@ freecom_writedata (Scsi_Cmnd *srb, struct us_data *us, ...@@ -151,7 +149,7 @@ freecom_writedata (Scsi_Cmnd *srb, struct us_data *us,
freecom_udata_t extra = (freecom_udata_t) us->extra; freecom_udata_t extra = (freecom_udata_t) us->extra;
struct freecom_xfer_wrap *fxfr = struct freecom_xfer_wrap *fxfr =
(struct freecom_xfer_wrap *) extra->buffer; (struct freecom_xfer_wrap *) extra->buffer;
int result, partial; int result;
fxfr->Type = FCM_PACKET_OUTPUT | 0x00; fxfr->Type = FCM_PACKET_OUTPUT | 0x00;
fxfr->Timeout = 0; /* Short timeout for debugging. */ fxfr->Timeout = 0; /* Short timeout for debugging. */
...@@ -161,15 +159,12 @@ freecom_writedata (Scsi_Cmnd *srb, struct us_data *us, ...@@ -161,15 +159,12 @@ freecom_writedata (Scsi_Cmnd *srb, struct us_data *us,
US_DEBUGP("Write data Freecom! (c=%d)\n", count); US_DEBUGP("Write data Freecom! (c=%d)\n", count);
/* Issue the transfer command. */ /* Issue the transfer command. */
result = usb_stor_bulk_msg (us, fxfr, opipe, result = usb_stor_bulk_transfer_buf (us, opipe, fxfr,
FCM_PACKET_LENGTH, &partial); FCM_PACKET_LENGTH, NULL);
if (result != USB_STOR_XFER_GOOD) { if (result != USB_STOR_XFER_GOOD) {
US_DEBUGP ("Freecom writedata xport failure: r=%d, p=%d\n", US_DEBUGP ("Freecom writedata transport error\n");
result, partial);
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
} }
US_DEBUGP("Done issuing write request: %d %d\n",
result, partial);
/* Now transfer all of our blocks. */ /* Now transfer all of our blocks. */
US_DEBUGP("Start of write\n"); US_DEBUGP("Start of write\n");
...@@ -191,7 +186,7 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -191,7 +186,7 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
struct freecom_status *fst; struct freecom_status *fst;
unsigned int ipipe, opipe; /* We need both pipes. */ unsigned int ipipe, opipe; /* We need both pipes. */
int result; int result;
int partial; unsigned int partial;
int length; int length;
freecom_udata_t extra; freecom_udata_t extra;
...@@ -215,23 +210,22 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -215,23 +210,22 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
US_DEBUG(pdump (srb->cmnd, 12)); US_DEBUG(pdump (srb->cmnd, 12));
/* Send it out. */ /* Send it out. */
result = usb_stor_bulk_msg (us, fcb, opipe, result = usb_stor_bulk_transfer_buf (us, opipe, fcb,
FCM_PACKET_LENGTH, &partial); FCM_PACKET_LENGTH, NULL);
/* The Freecom device will only fail if there is something wrong in /* The Freecom device will only fail if there is something wrong in
* USB land. It returns the status in its own registers, which * USB land. It returns the status in its own registers, which
* come back in the bulk pipe. */ * come back in the bulk pipe. */
if (result != USB_STOR_XFER_GOOD) { if (result != USB_STOR_XFER_GOOD) {
US_DEBUGP ("freecom xport failure: r=%d, p=%d\n", US_DEBUGP ("freecom transport error\n");
result, partial);
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
} }
/* There are times we can optimize out this status read, but it /* There are times we can optimize out this status read, but it
* doesn't hurt us to always do it now. */ * doesn't hurt us to always do it now. */
result = usb_stor_bulk_msg (us, fst, ipipe, result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
FCM_PACKET_LENGTH, &partial); FCM_PACKET_LENGTH, &partial);
US_DEBUGP("foo Status result %d %d\n", result, partial); US_DEBUGP("foo Status result %d %u\n", result, partial);
if (result != USB_STOR_XFER_GOOD) if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
...@@ -256,24 +250,23 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -256,24 +250,23 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
memset (fcb->Filler, 0, sizeof (fcb->Filler)); memset (fcb->Filler, 0, sizeof (fcb->Filler));
/* Send it out. */ /* Send it out. */
result = usb_stor_bulk_msg (us, fcb, opipe, result = usb_stor_bulk_transfer_buf (us, opipe, fcb,
FCM_PACKET_LENGTH, &partial); FCM_PACKET_LENGTH, NULL);
/* The Freecom device will only fail if there is something /* The Freecom device will only fail if there is something
* wrong in USB land. It returns the status in its own * wrong in USB land. It returns the status in its own
* registers, which come back in the bulk pipe. * registers, which come back in the bulk pipe.
*/ */
if (result != USB_STOR_XFER_GOOD) { if (result != USB_STOR_XFER_GOOD) {
US_DEBUGP ("freecom xport failure: r=%d, p=%d\n", US_DEBUGP ("freecom transport error\n");
result, partial);
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
} }
/* get the data */ /* get the data */
result = usb_stor_bulk_msg (us, fst, ipipe, result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
FCM_PACKET_LENGTH, &partial); FCM_PACKET_LENGTH, &partial);
US_DEBUGP("bar Status result %d %d\n", result, partial); US_DEBUGP("bar Status result %d %u\n", result, partial);
if (result > USB_STOR_XFER_SHORT) if (result > USB_STOR_XFER_SHORT)
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
...@@ -328,7 +321,7 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -328,7 +321,7 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
return result; return result;
US_DEBUGP("FCM: Waiting for status\n"); US_DEBUGP("FCM: Waiting for status\n");
result = usb_stor_bulk_msg (us, fst, ipipe, result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
FCM_PACKET_LENGTH, &partial); FCM_PACKET_LENGTH, &partial);
US_DEBUG(pdump ((void *) fst, partial)); US_DEBUG(pdump ((void *) fst, partial));
...@@ -354,7 +347,7 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -354,7 +347,7 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
return result; return result;
US_DEBUGP("FCM: Waiting for status\n"); US_DEBUGP("FCM: Waiting for status\n");
result = usb_stor_bulk_msg (us, fst, ipipe, result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
FCM_PACKET_LENGTH, &partial); FCM_PACKET_LENGTH, &partial);
if (partial != 4 || result > USB_STOR_XFER_SHORT) if (partial != 4 || result > USB_STOR_XFER_SHORT)
...@@ -385,13 +378,6 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -385,13 +378,6 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
} }
return USB_STOR_TRANSPORT_GOOD; return USB_STOR_TRANSPORT_GOOD;
US_DEBUGP("Freecom: transfer_length = %d\n",
usb_stor_transfer_length (srb));
US_DEBUGP("Freecom: direction = %d\n", srb->sc_data_direction);
return USB_STOR_TRANSPORT_ERROR;
} }
int int
......
...@@ -668,7 +668,7 @@ int isd200_write_config( struct us_data *us ) ...@@ -668,7 +668,7 @@ int isd200_write_config( struct us_data *us )
#endif #endif
/* let's send the command via the control pipe */ /* let's send the command via the control pipe */
result = usb_stor_control_msg( result = usb_stor_ctrl_transfer(
us, us,
us->send_ctrl_pipe, us->send_ctrl_pipe,
0x01, 0x01,
...@@ -709,7 +709,7 @@ int isd200_read_config( struct us_data *us ) ...@@ -709,7 +709,7 @@ int isd200_read_config( struct us_data *us )
/* read the configuration information from ISD200. Use this to */ /* read the configuration information from ISD200. Use this to */
/* determine what the special ATA CDB bytes are. */ /* determine what the special ATA CDB bytes are. */
result = usb_stor_control_msg( result = usb_stor_ctrl_transfer(
us, us,
us->recv_ctrl_pipe, us->recv_ctrl_pipe,
0x02, 0x02,
......
...@@ -479,7 +479,7 @@ int usb_stor_control_msg(struct us_data *us, unsigned int pipe, ...@@ -479,7 +479,7 @@ int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
usb_stor_blocking_completion, NULL); usb_stor_blocking_completion, NULL);
status = usb_stor_msg_common(us); status = usb_stor_msg_common(us);
/* return the actual length of the data transferred if no error*/ /* return the actual length of the data transferred if no error */
if (status >= 0) if (status >= 0)
status = us->current_urb->actual_length; status = us->current_urb->actual_length;
return status; return status;
...@@ -543,47 +543,91 @@ int usb_stor_clear_halt(struct us_data *us, unsigned int pipe) ...@@ -543,47 +543,91 @@ int usb_stor_clear_halt(struct us_data *us, unsigned int pipe)
return 0; return 0;
} }
/* /*
* Transfer one control message * Interpret the results of a URB transfer
* *
* This function does basically the same thing as usb_stor_control_msg() * This function prints appropriate debugging messages, clears halts on
* above, except that return codes are USB_STOR_XFER_xxx rather than the * bulk endpoints, and translates the status to the corresponding
* urb status or transfer length. * USB_STOR_XFER_xxx return code.
*/ */
int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe, static int interpret_urb_result(struct us_data *us, unsigned int pipe,
u8 request, u8 requesttype, u16 value, u16 index, unsigned int length, int result, unsigned int partial) {
void *data, u16 size) {
int result;
US_DEBUGP("usb_stor_ctrl_transfer(): rq=%02x rqtype=%02x " US_DEBUGP("Status code %d; transferred %u/%u\n",
"value=%04x index=%02x len=%d\n", result, partial, length);
request, requesttype, value, index, size);
result = usb_stor_control_msg(us, pipe, request, requesttype,
value, index, data, size);
US_DEBUGP("usb_stor_control_msg returned %d\n", result);
/* a stall indicates a protocol error */ /* stalled */
if (result == -EPIPE) { if (result == -EPIPE) {
/* for non-bulk (i.e., control) endpoints, a stall indicates
* a protocol error */
if (!usb_pipebulk(pipe)) {
US_DEBUGP("-- stall on control pipe\n"); US_DEBUGP("-- stall on control pipe\n");
return USB_STOR_XFER_ERROR; return USB_STOR_XFER_ERROR;
} }
/* some other serious problem here */ /* for a bulk endpoint, clear the stall */
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
if (usb_stor_clear_halt(us, pipe) < 0)
return USB_STOR_XFER_ERROR;
return USB_STOR_XFER_STALLED;
}
/* NAK - that means we've retried this a few times already */
if (result == -ETIMEDOUT) {
US_DEBUGP("-- device NAKed\n");
return USB_STOR_XFER_ERROR;
}
/* the transfer was cancelled, presumably by an abort */
if (result == -ENODEV) {
US_DEBUGP("-- transfer cancelled\n");
return USB_STOR_XFER_ERROR;
}
/* the catch-all error case */
if (result < 0) { if (result < 0) {
US_DEBUGP("-- unknown error\n"); US_DEBUGP("-- unknown error\n");
return USB_STOR_XFER_ERROR; return USB_STOR_XFER_ERROR;
} }
/* was the entire command transferred? */ /* no error code; did we send all the data? */
if (result < size) { if (partial != length) {
US_DEBUGP("-- transferred only %d bytes\n", result); US_DEBUGP("-- transferred only %u bytes\n", partial);
return USB_STOR_XFER_SHORT; return USB_STOR_XFER_SHORT;
} }
US_DEBUGP("-- transfer completed successfully\n"); US_DEBUGP("-- transfer complete\n");
return USB_STOR_XFER_GOOD; return USB_STOR_XFER_GOOD;
} }
/*
* Transfer one control message
*
* This function does basically the same thing as usb_stor_control_msg()
* above, except that return codes are USB_STOR_XFER_xxx rather than the
* urb status or transfer length.
*/
int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe,
u8 request, u8 requesttype, u16 value, u16 index,
void *data, u16 size) {
int result;
unsigned int partial = 0;
US_DEBUGP("usb_stor_ctrl_transfer(): rq=%02x rqtype=%02x "
"value=%04x index=%02x len=%u\n",
request, requesttype, value, index, size);
result = usb_stor_control_msg(us, pipe, request, requesttype,
value, index, data, size);
if (result > 0) { /* Separate out the amount transferred */
partial = result;
result = 0;
}
return interpret_urb_result(us, pipe, size, result, partial);
}
/* /*
* Transfer one buffer via bulk transfer * Transfer one buffer via bulk transfer
* *
...@@ -596,50 +640,17 @@ int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe, ...@@ -596,50 +640,17 @@ int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe,
* urb status or transfer length. * urb status or transfer length.
*/ */
int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe, int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
char *buf, unsigned int length, unsigned int *act_len) void *buf, unsigned int length, unsigned int *act_len)
{ {
int result; int result;
int partial; unsigned int partial;
/* transfer the data */ /* transfer the data */
US_DEBUGP("usb_stor_bulk_transfer_buf(): xfer %d bytes\n", length); US_DEBUGP("usb_stor_bulk_transfer_buf(): xfer %u bytes\n", length);
result = usb_stor_bulk_msg(us, buf, pipe, length, &partial); result = usb_stor_bulk_msg(us, buf, pipe, length, &partial);
US_DEBUGP("usb_stor_bulk_msg() returned %d xferred %d/%d\n",
result, partial, length);
if (act_len) if (act_len)
*act_len = partial; *act_len = partial;
return interpret_urb_result(us, pipe, length, result, partial);
/* if we stall, we need to clear it before we go on */
if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x,"
" stalled at %d bytes\n", pipe, partial);
if (usb_stor_clear_halt(us, pipe) < 0)
return USB_STOR_XFER_ERROR;
return USB_STOR_XFER_STALLED;
}
/* NAK - that means we've retried a few times already */
if (result == -ETIMEDOUT) {
US_DEBUGP("-- device NAKed\n");
return USB_STOR_XFER_ERROR;
}
/* the catch-all error case */
if (result) {
US_DEBUGP("-- unknown error\n");
return USB_STOR_XFER_ERROR;
}
/* did we send all the data? */
if (partial == length) {
US_DEBUGP("-- transfer complete\n");
return USB_STOR_XFER_GOOD;
}
/* no error code, so we must have transferred some data,
* just not all of it */
US_DEBUGP("-- transferred only %d bytes\n", partial);
return USB_STOR_XFER_SHORT;
} }
/* /*
...@@ -653,10 +664,10 @@ int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe, ...@@ -653,10 +664,10 @@ int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
unsigned int *act_len) unsigned int *act_len)
{ {
int result; int result;
int partial; unsigned int partial;
/* initialize the scatter-gather request block */ /* initialize the scatter-gather request block */
US_DEBUGP("usb_stor_bulk_transfer_sglist(): xfer %d bytes, " US_DEBUGP("usb_stor_bulk_transfer_sglist(): xfer %u bytes, "
"%d entries\n", length, num_sg); "%d entries\n", length, num_sg);
result = usb_sg_init(us->current_sg, us->pusb_dev, pipe, 0, result = usb_sg_init(us->current_sg, us->pusb_dev, pipe, 0,
sg, num_sg, length, SLAB_NOIO); sg, num_sg, length, SLAB_NOIO);
...@@ -685,55 +696,22 @@ int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe, ...@@ -685,55 +696,22 @@ int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
result = us->current_sg->status; result = us->current_sg->status;
partial = us->current_sg->bytes; partial = us->current_sg->bytes;
US_DEBUGP("usb_sg_wait() returned %d xferred %d/%d\n",
result, partial, length);
if (act_len) if (act_len)
*act_len = partial; *act_len = partial;
return interpret_urb_result(us, pipe, length, result, partial);
/* if we stall, we need to clear it before we go on */
if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x, "
"stalled at %d bytes\n", pipe, partial);
if (usb_stor_clear_halt(us, pipe) < 0)
return USB_STOR_XFER_ERROR;
return USB_STOR_XFER_STALLED;
}
/* NAK - that means we've retried this a few times already */
if (result == -ETIMEDOUT) {
US_DEBUGP("-- device NAKed\n");
return USB_STOR_XFER_ERROR;
}
/* the catch-all error case */
if (result) {
US_DEBUGP("-- unknown error\n");
return USB_STOR_XFER_ERROR;
}
/* did we send all the data? */
if (partial == length) {
US_DEBUGP("-- transfer complete\n");
return USB_STOR_XFER_GOOD;
}
/* no error code, so we must have transferred some data,
* just not all of it */
US_DEBUGP("-- transferred only %d bytes\n", partial);
return USB_STOR_XFER_SHORT;
} }
/* /*
* Transfer an entire SCSI command's worth of data payload over the bulk * Transfer an entire SCSI command's worth of data payload over the bulk
* pipe. * pipe.
* *
* Nore that this uses usb_stor_bulk_transfer_buf() and * Note that this uses usb_stor_bulk_transfer_buf() and
* usb_stor_bulk_transfer_sglist() to achieve its goals -- * usb_stor_bulk_transfer_sglist() to achieve its goals --
* this function simply determines whether we're going to use * this function simply determines whether we're going to use
* scatter-gather or not, and acts appropriately. * scatter-gather or not, and acts appropriately.
*/ */
int usb_stor_bulk_transfer_sg(struct us_data* us, unsigned int pipe, int usb_stor_bulk_transfer_sg(struct us_data* us, unsigned int pipe,
char *buf, unsigned int length_left, int use_sg, int *residual) void *buf, unsigned int length_left, int use_sg, int *residual)
{ {
int result; int result;
unsigned int partial; unsigned int partial;
...@@ -1278,7 +1256,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -1278,7 +1256,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
(bcb.Lun >> 4), (bcb.Lun & 0x0F), (bcb.Lun >> 4), (bcb.Lun & 0x0F),
le32_to_cpu(bcb.DataTransferLength), bcb.Flags, bcb.Length); le32_to_cpu(bcb.DataTransferLength), bcb.Flags, bcb.Length);
result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
(char *) &bcb, US_BULK_CB_WRAP_LEN, NULL); &bcb, US_BULK_CB_WRAP_LEN, NULL);
US_DEBUGP("Bulk command transfer result=%d\n", result); US_DEBUGP("Bulk command transfer result=%d\n", result);
if (result != USB_STOR_XFER_GOOD) if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
...@@ -1302,7 +1280,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -1302,7 +1280,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
/* get CSW for device status */ /* get CSW for device status */
US_DEBUGP("Attempting to get CSW...\n"); US_DEBUGP("Attempting to get CSW...\n");
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
(char *) &bcs, US_BULK_CS_WRAP_LEN, NULL); &bcs, US_BULK_CS_WRAP_LEN, NULL);
/* did the attempt to read the CSW fail? */ /* did the attempt to read the CSW fail? */
if (result == USB_STOR_XFER_STALLED) { if (result == USB_STOR_XFER_STALLED) {
...@@ -1310,7 +1288,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -1310,7 +1288,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
/* get the status again */ /* get the status again */
US_DEBUGP("Attempting to get CSW (2nd try)...\n"); US_DEBUGP("Attempting to get CSW (2nd try)...\n");
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
(char *) &bcs, US_BULK_CS_WRAP_LEN, NULL); &bcs, US_BULK_CS_WRAP_LEN, NULL);
} }
/* if we still have a failure at this point, we're in trouble */ /* if we still have a failure at this point, we're in trouble */
......
...@@ -117,6 +117,7 @@ struct bulk_cs_wrap { ...@@ -117,6 +117,7 @@ struct bulk_cs_wrap {
/* /*
* usb_stor_bulk_transfer_xxx() return codes, in order of severity * usb_stor_bulk_transfer_xxx() return codes, in order of severity
*/ */
#define USB_STOR_XFER_GOOD 0 /* good transfer */ #define USB_STOR_XFER_GOOD 0 /* good transfer */
#define USB_STOR_XFER_SHORT 1 /* transfered less than expected */ #define USB_STOR_XFER_SHORT 1 /* transfered less than expected */
#define USB_STOR_XFER_STALLED 2 /* endpoint stalled */ #define USB_STOR_XFER_STALLED 2 /* endpoint stalled */
...@@ -129,7 +130,14 @@ struct bulk_cs_wrap { ...@@ -129,7 +130,14 @@ struct bulk_cs_wrap {
#define USB_STOR_TRANSPORT_GOOD 0 /* Transport good, command good */ #define USB_STOR_TRANSPORT_GOOD 0 /* Transport good, command good */
#define USB_STOR_TRANSPORT_FAILED 1 /* Transport good, command failed */ #define USB_STOR_TRANSPORT_FAILED 1 /* Transport good, command failed */
#define USB_STOR_TRANSPORT_ERROR 2 /* Transport bad (i.e. device dead) */ #define USB_STOR_TRANSPORT_ERROR 2 /* Transport bad (i.e. device dead) */
#define USB_STOR_TRANSPORT_ABORTED 3 /* Transport aborted */
/*
* We used to have USB_STOR_XFER_ABORTED and USB_STOR_TRANSPORT_ABORTED
* return codes. But now the transport and low-level transfer routines
* treat an abort as just another error (-ENOENT for a cancelled URB).
* It is up to the invoke_transport() function to test for aborts and
* distinguish them from genuine communication errors.
*/
/* /*
* CBI accept device specific command * CBI accept device specific command
...@@ -162,12 +170,12 @@ extern int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe, ...@@ -162,12 +170,12 @@ extern int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe,
u8 request, u8 requesttype, u16 value, u16 index, u8 request, u8 requesttype, u16 value, u16 index,
void *data, u16 size); void *data, u16 size);
extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe, extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
char *buf, unsigned int length, unsigned int *act_len); void *buf, unsigned int length, unsigned int *act_len);
extern int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe, extern int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
struct scatterlist *sg, int num_sg, unsigned int length, struct scatterlist *sg, int num_sg, unsigned int length,
unsigned int *act_len); unsigned int *act_len);
extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe, extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe,
char *buf, unsigned int length, int use_sg, int *residual); void *buf, unsigned int length, int use_sg, int *residual);
static __inline__ int usb_stor_bulk_transfer_srb(struct us_data *us, static __inline__ int usb_stor_bulk_transfer_srb(struct us_data *us,
unsigned int pipe, Scsi_Cmnd *srb, unsigned int length) { unsigned int pipe, Scsi_Cmnd *srb, unsigned int length) {
......
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