Commit 5202f40d authored by Linus Torvalds's avatar Linus Torvalds

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

into penguin.transmeta.com:/home/penguin/torvalds/repositories/kernel/linux
parents dcd21270 5266e52c
14 April 2000
david-b@pacbell.net
This is an overview of how to use the "dc2xx" USB driver with certain
digital still cameras from Kodak and other vendors.
CAMERAS
This driver will mostly be used with Kodak DC-2xx series digital still
cameras, but it should be trivial to tell it about several non-Kodak
USB-enabled cameras.
You'll most likely want to hook it up to recent versions of "gPhoto"
(www.gphoto.org), since version 0.4 and later know how to use it to talk
to Kodak DC-240 and DC-280 cameras over USB.
In addition the DC-220, DC-260, DC-265, and DC-290 are also recognized.
However, like other cameras using the "Digita OS" (from www.flashpoint.com)
there is no gPhoto support for this camera. There is a python script
for accessing these cameras (see archives of the linux-usb mailing list)
and a "Digita Services" library that can also use this driver.
The HP PhotoSmart C500 should also work, since it's another Digita camera
with USB support.
USB HARDWARE
Recent kernels have had no particular problems using this driver with
either OHCI or UHCI chipsets, and have worked on the PowerMac platform.
Note that in some cases changes in BIOS settings may be needed before
your USB works. At least one user has reported a need for SMP-related
settings as well, and some old hardware may not handle USB correctly.
SETUP
Configure in the DC2XX USB driver, and have it in your kernel. It works
as a module, or compiled in directly.
Create at least one device, perhaps like this (both read and write):
# mknod -m 0660 /dev/usb/dc2xx0 c 180 80
# mknod -m 0660 /dev/usb/dc2xx1 c 180 81
...
NOTE: you would normally configure PAM so that the user logged in at
the console is granted ownership of these devices. console.perms(5)
explains how to do this.
The driver supports multiple device nodes. The USB framework supports
a maximum of sixteen device nodes (up to minor device number 96).
When you plug in one camera, it will use the first device node (dc2xx0
in the example above). A second camera will use the second device node,
and so on.
SANITY TESTING
First: if you've got /proc support, make sure that the driver has hooked
itself up correctly.
- You should see an entry in /proc/bus/usb/drivers for "dc2xx",
if you enabled USB /proc support and correctly mounted the
usbdevfs on /proc/bus/usb.
Second: when you connect your camera to the computer, does it get recognized
by the driver? (Make sure the camera is powered on!)
- if you've got /proc/bus/usb/devices, you should see an entry
something like this. The "ProdID" may be different if you didn't
plug in a DC-240, as may the strings presented, but "Driver=dc2xx"
had better be there.
T: Lev=01 Prnt=00 Port=00 Cnt=01 Dev#= 1 Spd=12 MxCh= 0
D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=040a ProdID=0120 Rev= 1.08
S: Manufacturer=Eastman Kodak Company
S: Product=KODAK DC240 Zoom Digital Camera
C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr=100mA
I: If#= 0 Alt= 0 #EPs= 2 Cls=00(>ifc ) Sub=00 Prot=00 Driver=dc2xx
E: Ad=01(O) Atr=02(Bulk) MxPS= 64 Ivl= 0ms
E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl= 0ms
- see if "dmesg" output tells you that you plugged in your camera.
Manufacturer: Eastman Kodak Company
Product: KODAK DC240 Zoom Digital Camera
dc2xx.c: USB Camera #0 connected
Third: (optional) can you use gPhoto to talk to the camera?
- When you configure your camera, tell it to use "/dev/usb/dc2xx0"
(or whatever name you used). Right now, gPhoto emits a diagnostic
message (non-GUI) saying that it since it didn't act like a TTY,
it's assuming it's got a USB connection.
- With the camera turned on, get the "camera summary". It'll
talk to the camera -- and tell you you're using USB.
If you got that far, you should be able to use everything fine.
ADDITIONAL INFORMATION
You may find that you need more driver-specific information, which is
currently accessible through a link from http://www.linux-usb.org/
along with other Linux USB resources.
......@@ -3523,7 +3523,7 @@ static void usb_audio_recurseunit(struct consmixstate *state, unsigned char unit
unsigned char *p1;
unsigned int i, j;
if (test_and_set_bit(unitid, &state->unitbitmap)) {
if (test_and_set_bit(unitid, state->unitbitmap)) {
printk(KERN_INFO "usbaudio: mixer path revisits unit %d\n", unitid);
return;
}
......@@ -3571,7 +3571,7 @@ static void usb_audio_recurseunit(struct consmixstate *state, unsigned char unit
return;
case PROCESSING_UNIT:
if (p1[0] < 13 || p1[0] < 13+p1[6] || p1[0] < 13+p1[6]+p1[11+p1[6]] || p1[0] < 13+p1[6]+p1[11+p1[6]]+p1[13+p1[6]+p1[11+p1[6]]]) {
if (p1[0] < 13 || p1[0] < 13+p1[6] || p1[0] < 13+p1[6]+p1[11+p1[6]]) {
printk(KERN_ERR "usbaudio: unit %u: invalid PROCESSING_UNIT descriptor\n", unitid);
return;
}
......@@ -3613,7 +3613,7 @@ static void usb_audio_constructmixer(struct usb_audio_state *s, unsigned char *b
state.buffer = buffer;
state.buflen = buflen;
state.ctrlif = ctrlif;
set_bit(oterm[3], &state.unitbitmap); /* mark terminal ID as visited */
set_bit(oterm[3], state.unitbitmap); /* mark terminal ID as visited */
printk(KERN_DEBUG "usbaudio: constructing mixer for Terminal %u type 0x%04x\n",
oterm[3], oterm[4] | (oterm[5] << 8));
usb_audio_recurseunit(&state, oterm[7]);
......
......@@ -144,7 +144,7 @@ struct acm {
struct usb_device *dev; /* the coresponding usb device */
struct usb_interface *iface; /* the interfaces - +0 control +1 data */
struct tty_struct *tty; /* the coresponding tty */
struct urb ctrlurb, readurb, writeurb; /* urbs */
struct urb *ctrlurb, *readurb, *writeurb; /* urbs */
struct acm_line line; /* line coding (bits, stop, parity) */
struct tq_struct tqueue; /* task queue for line discipline waking up */
unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */
......@@ -316,12 +316,12 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
unlock_kernel();
acm->ctrlurb.dev = acm->dev;
if (usb_submit_urb(&acm->ctrlurb, GFP_KERNEL))
acm->ctrlurb->dev = acm->dev;
if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL))
dbg("usb_submit_urb(ctrl irq) failed");
acm->readurb.dev = acm->dev;
if (usb_submit_urb(&acm->readurb, GFP_KERNEL))
acm->readurb->dev = acm->dev;
if (usb_submit_urb(acm->readurb, GFP_KERNEL))
dbg("usb_submit_urb(read bulk) failed");
acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS);
......@@ -342,12 +342,15 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
if (!--acm->used) {
if (acm->dev) {
acm_set_control(acm, acm->ctrlout = 0);
usb_unlink_urb(&acm->ctrlurb);
usb_unlink_urb(&acm->writeurb);
usb_unlink_urb(&acm->readurb);
usb_unlink_urb(acm->ctrlurb);
usb_unlink_urb(acm->writeurb);
usb_unlink_urb(acm->readurb);
} else {
tty_unregister_devfs(&acm_tty_driver, acm->minor);
acm_table[acm->minor] = NULL;
usb_free_urb(acm->ctrlurb);
usb_free_urb(acm->readurb);
usb_free_urb(acm->writeurb);
kfree(acm);
}
}
......@@ -359,20 +362,20 @@ static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned c
struct acm *acm = tty->driver_data;
if (!ACM_READY(acm)) return -EINVAL;
if (acm->writeurb.status == -EINPROGRESS) return 0;
if (acm->writeurb->status == -EINPROGRESS) return 0;
if (!count) return 0;
count = (count > acm->writesize) ? acm->writesize : count;
if (from_user)
copy_from_user(acm->writeurb.transfer_buffer, buf, count);
copy_from_user(acm->writeurb->transfer_buffer, buf, count);
else
memcpy(acm->writeurb.transfer_buffer, buf, count);
memcpy(acm->writeurb->transfer_buffer, buf, count);
acm->writeurb.transfer_buffer_length = count;
acm->writeurb.dev = acm->dev;
acm->writeurb->transfer_buffer_length = count;
acm->writeurb->dev = acm->dev;
if (usb_submit_urb(&acm->writeurb, GFP_KERNEL))
if (usb_submit_urb(acm->writeurb, GFP_KERNEL))
dbg("usb_submit_urb(write bulk) failed");
return count;
......@@ -382,14 +385,14 @@ static int acm_tty_write_room(struct tty_struct *tty)
{
struct acm *acm = tty->driver_data;
if (!ACM_READY(acm)) return -EINVAL;
return acm->writeurb.status == -EINPROGRESS ? 0 : acm->writesize;
return acm->writeurb->status == -EINPROGRESS ? 0 : acm->writesize;
}
static int acm_tty_chars_in_buffer(struct tty_struct *tty)
{
struct acm *acm = tty->driver_data;
if (!ACM_READY(acm)) return -EINVAL;
return acm->writeurb.status == -EINPROGRESS ? acm->writeurb.transfer_buffer_length : 0;
return acm->writeurb->status == -EINPROGRESS ? acm->writeurb->transfer_buffer_length : 0;
}
static void acm_tty_throttle(struct tty_struct *tty)
......@@ -404,8 +407,8 @@ static void acm_tty_unthrottle(struct tty_struct *tty)
struct acm *acm = tty->driver_data;
if (!ACM_READY(acm)) return;
acm->throttle = 0;
if (acm->readurb.status != -EINPROGRESS)
acm_read_bulk(&acm->readurb);
if (acm->readurb->status != -EINPROGRESS)
acm_read_bulk(acm->readurb);
}
static void acm_tty_break_ctl(struct tty_struct *tty, int state)
......@@ -585,16 +588,38 @@ static void *acm_probe(struct usb_device *dev, unsigned int ifnum,
return NULL;
}
FILL_INT_URB(&acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress),
acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
if (!acm->ctrlurb) {
err("out of memory");
kfree(acm);
return NULL;
}
acm->readurb = usb_alloc_urb(0, GFP_KERNEL);
if (!acm->readurb) {
err("out of memory");
usb_free_urb(acm->ctrlurb);
kfree(acm);
return NULL;
}
acm->writeurb = usb_alloc_urb(0, GFP_KERNEL);
if (!acm->writeurb) {
err("out of memory");
usb_free_urb(acm->readurb);
usb_free_urb(acm->ctrlurb);
kfree(acm);
return NULL;
}
usb_fill_int_urb(acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress),
buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
FILL_BULK_URB(&acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
usb_fill_bulk_urb(acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
buf += ctrlsize, readsize, acm_read_bulk, acm);
acm->readurb.transfer_flags |= USB_NO_FSBR;
acm->readurb->transfer_flags |= USB_NO_FSBR;
FILL_BULK_URB(&acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
usb_fill_bulk_urb(acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
buf += readsize, acm->writesize, acm_write_bulk, acm);
acm->writeurb.transfer_flags |= USB_NO_FSBR;
acm->writeurb->transfer_flags |= USB_NO_FSBR;
printk(KERN_INFO "ttyACM%d: USB ACM device\n", minor);
......@@ -625,11 +650,11 @@ static void acm_disconnect(struct usb_device *dev, void *ptr)
acm->dev = NULL;
usb_unlink_urb(&acm->ctrlurb);
usb_unlink_urb(&acm->readurb);
usb_unlink_urb(&acm->writeurb);
usb_unlink_urb(acm->ctrlurb);
usb_unlink_urb(acm->readurb);
usb_unlink_urb(acm->writeurb);
kfree(acm->ctrlurb.transfer_buffer);
kfree(acm->ctrlurb->transfer_buffer);
usb_driver_release_interface(&acm_driver, acm->iface + 0);
usb_driver_release_interface(&acm_driver, acm->iface + 1);
......@@ -637,6 +662,9 @@ static void acm_disconnect(struct usb_device *dev, void *ptr)
if (!acm->used) {
tty_unregister_devfs(&acm_tty_driver, acm->minor);
acm_table[acm->minor] = NULL;
usb_free_urb(acm->ctrlurb);
usb_free_urb(acm->readurb);
usb_free_urb(acm->writeurb);
kfree(acm);
return;
}
......
......@@ -297,7 +297,9 @@ static void destroy_all_async(struct dev_state *ps)
}
/*
* interface claiming
* interface claims are made only at the request of user level code,
* which can also release them (explicitly or by closing files).
* they're also undone when devices disconnect.
*/
static void *driver_probe(struct usb_device *dev, unsigned int intf,
......@@ -310,8 +312,20 @@ static void driver_disconnect(struct usb_device *dev, void *context)
{
struct dev_state *ps = (struct dev_state *)context;
if (ps)
ps->ifclaimed = 0;
if (!ps)
return;
/* this waits till synchronous requests complete */
down_write (&ps->devsem);
/* prevent new I/O requests */
ps->dev = 0;
ps->ifclaimed = 0;
/* force async requests to complete */
destroy_all_async (ps);
up_write (&ps->devsem);
}
struct usb_driver usbdevfs_driver = {
......
......@@ -310,7 +310,7 @@ static int rh_string (
// serial number
} else if (id == 1) {
strcpy (buf, hcd->bus_name);
strcpy (buf, hcd->self.bus_name);
// product description
} else if (id == 2) {
......@@ -406,7 +406,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
// wValue == urb->dev->devaddr
dbg ("%s root hub device address %d",
hcd->bus_name, wValue);
hcd->self.bus_name, wValue);
break;
/* INTERFACE REQUESTS (no defined feature/status flags) */
......@@ -520,7 +520,7 @@ static void rh_report_status (unsigned long ptr)
&& rh_status_urb (hcd, urb) != 0) {
/* another driver snuck in? */
dbg ("%s, can't resubmit roothub status urb?",
hcd->bus_name);
hcd->self.bus_name);
spin_unlock_irqrestore (&hcd_data_lock, flags);
BUG ();
}
......@@ -1051,8 +1051,7 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
usb_init_bus (&hcd->self);
hcd->self.op = &hcd_operations;
hcd->self.hcpriv = (void *) hcd;
hcd->bus = &hcd->self;
hcd->bus_name = dev->slot_name;
hcd->self.bus_name = dev->slot_name;
hcd->product_desc = dev->name;
INIT_LIST_HEAD (&hcd->dev_list);
......@@ -1089,16 +1088,15 @@ void usb_hcd_pci_remove (struct pci_dev *dev)
hcd = pci_get_drvdata(dev);
if (!hcd)
return;
info ("remove: %s, state %x", hcd->bus_name, hcd->state);
info ("remove: %s, state %x", hcd->self.bus_name, hcd->state);
if (in_interrupt ()) BUG ();
hub = hcd->bus->root_hub;
hub = hcd->self.root_hub;
hcd->state = USB_STATE_QUIESCING;
dbg ("%s: roothub graceful disconnect", hcd->bus_name);
dbg ("%s: roothub graceful disconnect", hcd->self.bus_name);
usb_disconnect (&hub);
// usb_disconnect (&hcd->bus->root_hub);
hcd->driver->stop (hcd);
hcd->state = USB_STATE_HALT;
......@@ -1113,10 +1111,9 @@ void usb_hcd_pci_remove (struct pci_dev *dev)
pci_resource_len (dev, hcd->region));
}
usb_deregister_bus (hcd->bus);
usb_deregister_bus (&hcd->self);
if (atomic_read (&hcd->self.refcnt) != 1)
err ("usb_hcd_pci_remove %s, count != 1", hcd->bus_name);
hcd->bus = NULL;
err ("usb_hcd_pci_remove %s, count != 1", hcd->self.bus_name);
hcd->driver->hcd_free (hcd);
}
......@@ -1164,7 +1161,7 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
int retval;
hcd = pci_get_drvdata(dev);
info ("suspend %s to state %d", hcd->bus_name, state);
info ("suspend %s to state %d", hcd->self.bus_name, state);
pci_save_state (dev, hcd->pci_state);
......@@ -1193,12 +1190,12 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
int retval;
hcd = pci_get_drvdata(dev);
info ("resume %s", hcd->bus_name);
info ("resume %s", hcd->self.bus_name);
/* guard against multiple resumes (APM bug?) */
atomic_inc (&hcd->resume_count);
if (atomic_read (&hcd->resume_count) != 1) {
err ("concurrent PCI resumes for %s", hcd->bus_name);
err ("concurrent PCI resumes for %s", hcd->self.bus_name);
retval = 0;
goto done;
}
......@@ -1215,7 +1212,7 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
retval = hcd->driver->resume (hcd);
if (!HCD_IS_RUNNING (hcd->state)) {
dbg ("resume %s failure, retval %d", hcd->bus_name, retval);
dbg ("resume %s failure, retval %d", hcd->self.bus_name, retval);
hc_died (hcd);
// FIXME: recover, reset etc.
} else {
......@@ -1290,7 +1287,7 @@ static void hc_died (struct usb_hcd *hcd)
list_for_each (urblist, &dev->urb_list) {
urb = list_entry (urblist, struct urb, urb_list);
dbg ("shutdown %s urb %p pipe %x, current status %d",
hcd->bus_name, urb, urb->pipe, urb->status);
hcd->self.bus_name, urb, urb->pipe, urb->status);
if (urb->status == -EINPROGRESS)
urb->status = -ESHUTDOWN;
}
......@@ -1534,7 +1531,7 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
* since we report some queuing/setup errors ourselves
*/
urb = usb_get_urb (urb);
if (urb->dev == hcd->bus->root_hub)
if (urb->dev == hcd->self.root_hub)
status = rh_urb_enqueue (hcd, urb);
else
status = hcd->driver->urb_enqueue (hcd, urb, mem_flags);
......@@ -1686,7 +1683,7 @@ if (retval && urb->status == -ENOENT) err ("whoa! retval %d", retval);
&& HCD_IS_RUNNING (hcd->state)
&& !retval) {
dbg ("%s: wait for giveback urb %p",
hcd->bus_name, urb);
hcd->self.bus_name, urb);
wait_for_completion (&splice.done);
} else if ((urb->transfer_flags & USB_ASYNC_UNLINK) && retval == 0) {
return -EINPROGRESS;
......@@ -1698,7 +1695,7 @@ if (retval && urb->status == -ENOENT) err ("whoa! retval %d", retval);
bye:
if (retval)
dbg ("%s: hcd_unlink_urb fail %d",
hcd ? hcd->bus_name : "(no bus?)",
hcd ? hcd->self.bus_name : "(no bus?)",
retval);
return retval;
}
......@@ -1731,7 +1728,7 @@ static int hcd_free_dev (struct usb_device *udev)
/* device driver problem with refcounts? */
if (!list_empty (&dev->urb_list)) {
dbg ("free busy dev, %s devnum %d (bug!)",
hcd->bus_name, udev->devnum);
hcd->self.bus_name, udev->devnum);
return -EINVAL;
}
......
......@@ -35,10 +35,8 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
/*
* housekeeping
*/
struct usb_bus *bus; /* FIXME only use "self" */
struct usb_bus self; /* hcd is-a bus */
const char *bus_name;
const char *product_desc; /* product/vendor string */
const char *description; /* "ehci-hcd" etc */
......
......@@ -765,23 +765,23 @@ static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port,
* devices by location for diagnostics, tools, etc. The
* string is a path along hub ports, from the root. Each
* device's id will be stable until USB is re-cabled, and
* hubs are often labled with these port numbers.
* hubs are often labeled with these port numbers.
*
* Initial size: "/NN" times five hubs + NUL = 16 bytes max
* Initial size: ".NN" times five hubs + NUL = 16 bytes max
* (quite rare, since most hubs have 4-6 ports).
*/
pdev = dev->parent;
if (pdev->devpath [1] != '\0') /* parent not root */
if (pdev->devpath [0] != '/') /* parent not root */
len = snprintf (dev->devpath, sizeof dev->devpath,
"%s/%d", pdev->devpath, port + 1);
else /* root == "/", root port 2 == "/2" */
"%s.%d", pdev->devpath, port + 1);
else /* root == "/", root port 2 == "2", port 3 that hub "/2.3" */
len = snprintf (dev->devpath, sizeof dev->devpath,
"/%d", port + 1);
"%d", port + 1);
if (len == sizeof dev->devpath)
warn ("devpath size! usb/%03d/%03d path %s",
dev->bus->busnum, dev->devnum, dev->devpath);
info("new USB device on bus %d path %s, assigned address %d",
dev->bus->busnum, dev->devpath, dev->devnum);
info("new USB device %s-%s, assigned address %d",
dev->bus->bus_name, dev->devpath, dev->devnum);
/* put the device in the global device tree */
dev->dev.parent = &dev->parent->dev;
......@@ -964,7 +964,7 @@ static int usb_hub_thread(void *__hub)
/* Send me a signal to get me die (for debugging) */
do {
usb_hub_events();
interruptible_sleep_on(&khubd_wait);
wait_event_interruptible(khubd_wait, !list_empty(&hub_event_list));
} while (!signal_pending(current));
dbg("usb_hub_thread exiting");
......@@ -1122,7 +1122,7 @@ int usb_reset_device(struct usb_device *dev)
dev->devpath,
sizeof(dev->descriptor), ret);
clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
clear_bit(dev->devnum, dev->bus->devmap.devicemap);
dev->devnum = -1;
return -EIO;
}
......@@ -1131,7 +1131,7 @@ int usb_reset_device(struct usb_device *dev)
if (ret < 0) {
err("unable to get configuration (error=%d)", ret);
usb_destroy_configuration(dev);
clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
clear_bit(dev->devnum, dev->bus->devmap.devicemap);
dev->devnum = -1;
return 1;
}
......
......@@ -1784,7 +1784,7 @@ void usb_disconnect(struct usb_device **pdev)
/* Free the device number and remove the /proc/bus/usb entry */
if (dev->devnum > 0) {
clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
clear_bit(dev->devnum, dev->bus->devmap.devicemap);
usbfs_remove_device(dev);
put_device(&dev->dev);
}
......@@ -2407,56 +2407,6 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
return err;
}
/**
* usb_make_path - returns device path in the hub tree
* @dev: the device whose path is being constructed
* @buf: where to put the string
* @size: how big is "buf"?
* Context: !in_interrupt ()
*
* Returns length of the string (>= 0) or out of memory status (< 0).
*
* NOTE: prefer to use use dev->devpath directly.
*/
int usb_make_path(struct usb_device *dev, char *buf, size_t size)
{
struct usb_device *pdev = dev->parent;
char *tmp;
char *port;
int i;
if (!(port = kmalloc(size, GFP_KERNEL)))
return -ENOMEM;
if (!(tmp = kmalloc(size, GFP_KERNEL))) {
kfree(port);
return -ENOMEM;
}
*port = 0;
while (pdev) {
for (i = 0; i < pdev->maxchild; i++)
if (pdev->children[i] == dev)
break;
if (pdev->children[i] != dev) {
kfree(port);
kfree(tmp);
return -ENODEV;
}
strcpy(tmp, port);
snprintf(port, size, strlen(port) ? "%d.%s" : "%d", i + 1, tmp);
dev = pdev;
pdev = dev->parent;
}
snprintf(buf, size, "usb%d:%s", dev->bus->busnum, port);
kfree(port);
kfree(tmp);
return strlen(buf);
}
/*
* By the time we get here, the device has gotten a new device ID
* and is in the default state. We need to identify the thing and
......@@ -2484,7 +2434,7 @@ int usb_new_device(struct usb_device *dev)
if (err < 0) {
err("USB device not accepting new address=%d (error=%d)",
dev->devnum, err);
clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
clear_bit(dev->devnum, dev->bus->devmap.devicemap);
dev->devnum = -1;
return 1;
}
......@@ -2497,7 +2447,7 @@ int usb_new_device(struct usb_device *dev)
err("USB device not responding, giving up (error=%d)", err);
else
err("USB device descriptor short read (expected %i, got %i)", 8, err);
clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
clear_bit(dev->devnum, dev->bus->devmap.devicemap);
dev->devnum = -1;
return 1;
}
......@@ -2512,7 +2462,7 @@ int usb_new_device(struct usb_device *dev)
err("USB device descriptor short read (expected %Zi, got %i)",
sizeof(dev->descriptor), err);
clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
clear_bit(dev->devnum, dev->bus->devmap.devicemap);
dev->devnum = -1;
return 1;
}
......@@ -2521,7 +2471,7 @@ int usb_new_device(struct usb_device *dev)
if (err < 0) {
err("unable to get device %d configuration (error=%d)",
dev->devnum, err);
clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
clear_bit(dev->devnum, dev->bus->devmap.devicemap);
dev->devnum = -1;
return 1;
}
......@@ -2531,7 +2481,7 @@ int usb_new_device(struct usb_device *dev)
if (err) {
err("failed to set device %d default configuration (error=%d)",
dev->devnum, err);
clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
clear_bit(dev->devnum, dev->bus->devmap.devicemap);
dev->devnum = -1;
return 1;
}
......
......@@ -55,7 +55,7 @@ static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
strcat(buf, tmp);
}
dbg ("%s: %s portroute %s",
ehci->hcd.bus_name, label,
ehci->hcd.self.bus_name, label,
buf);
}
}
......
......@@ -248,7 +248,7 @@ static int ehci_start (struct usb_hcd *hcd)
ehci->tasklet.data = (unsigned long) ehci;
/* wire up the root hub */
hcd->bus->root_hub = udev = usb_alloc_dev (NULL, hcd->bus);
hcd->self.root_hub = udev = usb_alloc_dev (NULL, &hcd->self);
if (!udev) {
done2:
ehci_mem_cleanup (ehci);
......@@ -288,8 +288,7 @@ static int ehci_start (struct usb_hcd *hcd)
while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS))
udelay (100);
ehci_reset (ehci);
// usb_disconnect (udev);
hcd->bus->root_hub = 0;
hcd->self.root_hub = 0;
usb_free_dev (udev);
retval = -ENODEV;
goto done2;
......@@ -304,7 +303,7 @@ static void ehci_stop (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
dbg ("%s: stop", hcd->bus_name);
dbg ("%s: stop", hcd->self.bus_name);
if (hcd->state == USB_STATE_RUNNING)
ehci_ready (ehci);
......@@ -339,7 +338,7 @@ static int ehci_suspend (struct usb_hcd *hcd, u32 state)
int ports;
int i;
dbg ("%s: suspend to %d", hcd->bus_name, state);
dbg ("%s: suspend to %d", hcd->self.bus_name, state);
ports = HCS_N_PORTS (ehci->hcs_params);
......@@ -356,7 +355,7 @@ static int ehci_suspend (struct usb_hcd *hcd, u32 state)
if ((temp & PORT_PE) == 0
|| (temp & PORT_OWNER) != 0)
continue;
dbg ("%s: suspend port %d", hcd->bus_name, i);
dbg ("%s: suspend port %d", hcd->self.bus_name, i);
temp |= PORT_SUSPEND;
writel (temp, &ehci->regs->port_status [i]);
}
......@@ -380,7 +379,7 @@ static int ehci_resume (struct usb_hcd *hcd)
int ports;
int i;
dbg ("%s: resume", hcd->bus_name);
dbg ("%s: resume", hcd->self.bus_name);
ports = HCS_N_PORTS (ehci->hcs_params);
......@@ -400,7 +399,7 @@ static int ehci_resume (struct usb_hcd *hcd)
if ((temp & PORT_PE) == 0
|| (temp & PORT_SUSPEND) != 0)
continue;
dbg ("%s: resume port %d", hcd->bus_name, i);
dbg ("%s: resume port %d", hcd->self.bus_name, i);
temp |= PORT_RESUME;
writel (temp, &ehci->regs->port_status [i]);
readl (&ehci->regs->command); /* unblock posted writes */
......@@ -472,7 +471,7 @@ static void ehci_irq (struct usb_hcd *hcd)
/* PCI errors [4.15.2.4] */
if (unlikely ((status & STS_FATAL) != 0)) {
err ("%s: fatal error, state %x", hcd->bus_name, hcd->state);
err ("%s: fatal error, state %x", hcd->self.bus_name, hcd->state);
ehci_reset (ehci);
// generic layer kills/unlinks all urbs
// then tasklet cleans up the rest
......@@ -547,7 +546,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
unsigned long flags;
dbg ("%s urb_dequeue %p qh state %d",
hcd->bus_name, urb, qh->qh_state);
hcd->self.bus_name, urb, qh->qh_state);
switch (usb_pipetype (urb->pipe)) {
case PIPE_CONTROL:
......@@ -608,7 +607,7 @@ static void ehci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
/* ASSERT: nobody can be submitting urbs for this any more */
dbg ("%s: free_config devnum %d", hcd->bus_name, udev->devnum);
dbg ("%s: free_config devnum %d", hcd->self.bus_name, udev->devnum);
spin_lock_irqsave (&ehci->lock, flags);
for (i = 0; i < 32; i++) {
......@@ -645,7 +644,7 @@ static void ehci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
spin_lock_irqsave (&ehci->lock, flags);
}
}
qh_unput (ehci, qh);
qh_put (ehci, qh);
}
}
......
......@@ -41,14 +41,14 @@ static int check_reset_complete (
/* if reset finished and it's still not enabled -- handoff */
if (!(port_status & PORT_PE)) {
dbg ("%s port %d full speed, give to companion, 0x%x",
ehci->hcd.bus_name, index + 1, port_status);
ehci->hcd.self.bus_name, index + 1, port_status);
// what happens if HCS_N_CC(params) == 0 ?
port_status |= PORT_OWNER;
writel (port_status, &ehci->regs->port_status [index]);
} else
dbg ("%s port %d high speed", ehci->hcd.bus_name, index + 1);
dbg ("%s port %d high speed", ehci->hcd.self.bus_name, index + 1);
return port_status;
}
......@@ -306,11 +306,11 @@ static int ehci_hub_control (
if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
&& PORT_USB11 (temp)) {
dbg ("%s port %d low speed, give to companion",
hcd->bus_name, wIndex + 1);
hcd->self.bus_name, wIndex + 1);
temp |= PORT_OWNER;
} else {
vdbg ("%s port %d reset",
hcd->bus_name, wIndex + 1);
hcd->self.bus_name, wIndex + 1);
temp |= PORT_RESET;
temp &= ~PORT_PE;
......
......@@ -98,16 +98,16 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags)
}
/* to share a qh (cpu threads, or hc) */
static inline struct ehci_qh *qh_put (/* ehci, */ struct ehci_qh *qh)
static inline struct ehci_qh *qh_get (/* ehci, */ struct ehci_qh *qh)
{
// dbg ("put %p (%d++)", qh, qh->refcount.counter);
// dbg ("get %p (%d++)", qh, qh->refcount.counter);
atomic_inc (&qh->refcount);
return qh;
}
static void qh_unput (struct ehci_hcd *ehci, struct ehci_qh *qh)
static void qh_put (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
// dbg ("unput %p (--%d)", qh, qh->refcount.counter);
// dbg ("put %p (--%d)", qh, qh->refcount.counter);
if (!atomic_dec_and_test (&qh->refcount))
return;
/* clean qtds first, and know this is not linked */
......
......@@ -194,7 +194,7 @@ static void ehci_urb_done (
? PCI_DMA_FROMDEVICE
: PCI_DMA_TODEVICE);
if (likely (urb->hcpriv != 0)) {
qh_unput (ehci, (struct ehci_qh *) urb->hcpriv);
qh_put (ehci, (struct ehci_qh *) urb->hcpriv);
urb->hcpriv = 0;
}
......@@ -733,7 +733,7 @@ submit_async (
epnum |= 0x10;
vdbg ("%s: submit_async urb %p len %d ep %d-%s qtd %p [qh %p]",
ehci->hcd.bus_name, urb, urb->transfer_buffer_length,
ehci->hcd.self.bus_name, urb, urb->transfer_buffer_length,
epnum & 0x0f, (epnum & 0x10) ? "in" : "out",
qtd, dev ? dev->ep [epnum] : (void *)~0);
......@@ -815,9 +815,9 @@ submit_async (
* the HC and TT handle it when the TT has a buffer ready.
*/
if (likely (qh != 0)) {
urb->hcpriv = qh_put (qh);
urb->hcpriv = qh_get (qh);
if (likely (qh->qh_state == QH_STATE_IDLE))
qh_link_async (ehci, qh_put (qh));
qh_link_async (ehci, qh_get (qh));
}
spin_unlock_irqrestore (&ehci->lock, flags);
if (unlikely (!qh))
......@@ -835,7 +835,7 @@ static void end_unlink_async (struct ehci_hcd *ehci)
qh->qh_state = QH_STATE_IDLE;
qh->qh_next.qh = 0;
qh_unput (ehci, qh); // refcount from reclaim
qh_put (ehci, qh); // refcount from reclaim
ehci->reclaim = 0;
ehci->reclaim_ready = 0;
......@@ -847,7 +847,7 @@ static void end_unlink_async (struct ehci_hcd *ehci)
&& HCD_IS_RUNNING (ehci->hcd.state))
qh_link_async (ehci, qh);
else
qh_unput (ehci, qh); // refcount from async list
qh_put (ehci, qh); // refcount from async list
}
......@@ -872,7 +872,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
#endif
qh->qh_state = QH_STATE_UNLINK;
ehci->reclaim = qh = qh_put (qh);
ehci->reclaim = qh = qh_get (qh);
// dbg_qh ("start unlink", ehci, qh);
......@@ -937,14 +937,14 @@ static void scan_async (struct ehci_hcd *ehci)
/* clean any finished work for this qh */
if (!list_empty (&qh->qtd_list)) {
// dbg_qh ("scan_async", ehci, qh);
qh = qh_put (qh);
qh = qh_get (qh);
spin_unlock_irqrestore (&ehci->lock, flags);
/* concurrent unlink could happen here */
qh_completions (ehci, &qh->qtd_list, 1);
spin_lock_irqsave (&ehci->lock, flags);
qh_unput (ehci, qh);
qh_put (ehci, qh);
}
/* unlink idle entries (reduces PCI usage) */
......
......@@ -224,7 +224,7 @@ static void intr_deschedule (
do {
periodic_unlink (ehci, frame, qh);
qh_unput (ehci, qh);
qh_put (ehci, qh);
frame += period;
} while (frame < ehci->periodic_size);
......@@ -345,7 +345,7 @@ static int intr_submit (
qh->hw_next = EHCI_LIST_END;
qh->usecs = usecs;
urb->hcpriv = qh_put (qh);
urb->hcpriv = qh_get (qh);
status = -ENOSPC;
/* pick a set of schedule slots, link the QH into them */
......@@ -393,7 +393,7 @@ static int intr_submit (
// AND handle it already being (implicitly) linked into this frame
BUG ();
} else {
ehci->pshadow [frame].qh = qh_put (qh);
ehci->pshadow [frame].qh = qh_get (qh);
ehci->periodic [frame] =
QH_NEXT (qh->qh_dma);
}
......@@ -1113,8 +1113,8 @@ static void scan_periodic (struct ehci_hcd *ehci)
temp = q.qh->qh_next;
type = Q_NEXT_TYPE (q.qh->hw_next);
flags = intr_complete (ehci, frame,
qh_put (q.qh), flags);
qh_unput (ehci, q.qh);
qh_get (q.qh), flags);
qh_put (ehci, q.qh);
q = temp;
break;
case Q_TYPE_FSTN:
......
......@@ -89,7 +89,7 @@ void ohci_dump_periodic (struct ohci_hcd *ohci, char *label)
continue;
printed = 1;
printk (KERN_DEBUG "%s, ohci %s frame %2d:",
label, ohci->hcd.bus_name, i);
label, ohci->hcd.self.bus_name, i);
while (*ed_p != 0 && j--) {
struct ed *ed = dma_to_ed (ohci, le32_to_cpup(ed_p));
printk (" %p/%08x;", ed, ed->hwINFO);
......@@ -99,7 +99,7 @@ void ohci_dump_periodic (struct ohci_hcd *ohci, char *label)
}
if (!printed)
printk (KERN_DEBUG "%s, ohci %s, empty periodic schedule\n",
label, ohci->hcd.bus_name);
label, ohci->hcd.self.bus_name);
}
#endif
......@@ -229,7 +229,7 @@ static void ohci_dump_roothub (struct ohci_hcd *controller, int verbose)
static void ohci_dump (struct ohci_hcd *controller, int verbose)
{
dbg ("OHCI controller %s state", controller->hcd.bus_name);
dbg ("OHCI controller %s state", controller->hcd.self.bus_name);
// dumps some of the state we know about
ohci_dump_status (controller);
......
......@@ -379,7 +379,7 @@ static int hc_reset (struct ohci_hcd *ohci)
writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
dbg ("USB HC reset_hc %s: ctrl = 0x%x ;",
ohci->hcd.bus_name,
ohci->hcd.self.bus_name,
readl (&ohci->regs->control));
/* Reset USB (needed by some controllers) */
......@@ -449,7 +449,7 @@ static int hc_start (struct ohci_hcd *ohci)
mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
/* connect the virtual root hub */
ohci->hcd.bus->root_hub = udev = usb_alloc_dev (NULL, ohci->hcd.bus);
ohci->hcd.self.root_hub = udev = usb_alloc_dev (NULL, &ohci->hcd.self);
ohci->hcd.state = USB_STATE_READY;
if (!udev) {
ohci->disabled = 1;
......@@ -491,7 +491,7 @@ static void ohci_irq (struct usb_hcd *hcd)
if (ints & OHCI_INTR_UE) {
ohci->disabled++;
err ("OHCI Unrecoverable Error, %s disabled", hcd->bus_name);
err ("OHCI Unrecoverable Error, %s disabled", hcd->self.bus_name);
// e.g. due to PCI Master/Target Abort
#ifdef DEBUG
......@@ -530,7 +530,7 @@ static void ohci_stop (struct usb_hcd *hcd)
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
dbg ("%s: stop %s controller%s",
hcd->bus_name,
hcd->self.bus_name,
hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
ohci->disabled ? " (disabled)" : ""
);
......@@ -571,7 +571,7 @@ ohci_start (struct usb_hcd *hcd)
&& hcd->pdev->device == 0x740c) {
ohci->flags = OHCI_QUIRK_AMD756;
info ("%s: AMD756 erratum 4 workaround",
hcd->bus_name);
hcd->self.bus_name);
}
/* Apple's OHCI driver has a lot of bizarre workarounds
......@@ -581,7 +581,7 @@ ohci_start (struct usb_hcd *hcd)
else if (hcd->pdev->vendor == 0x1045
&& hcd->pdev->device == 0xc861) {
info ("%s: WARNING: OPTi workarounds unavailable",
hcd->bus_name);
hcd->self.bus_name);
}
}
#else
......@@ -601,7 +601,7 @@ ohci_start (struct usb_hcd *hcd)
}
if (hc_start (ohci) < 0) {
err ("can't start %s", ohci->hcd.bus_name);
err ("can't start %s", ohci->hcd.self.bus_name);
ohci_stop (hcd);
return -EBUSY;
}
......@@ -623,13 +623,13 @@ static int ohci_suspend (struct usb_hcd *hcd, u32 state)
u16 cmd;
if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) {
dbg ("can't suspend %s (state is %s)", hcd->bus_name,
dbg ("can't suspend %s (state is %s)", hcd->self.bus_name,
hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS));
return -EIO;
}
/* act as if usb suspend can always be used */
dbg ("%s: suspend to %d", hcd->bus_name, state);
dbg ("%s: suspend to %d", hcd->self.bus_name, state);
ohci->sleeping = 1;
/* First stop processing */
......@@ -664,16 +664,16 @@ static int ohci_suspend (struct usb_hcd *hcd, u32 state)
switch (readl (&ohci->regs->control) & OHCI_CTRL_HCFS) {
case OHCI_USB_RESET:
dbg ("%s suspend->reset ?", hcd->bus_name);
dbg ("%s suspend->reset ?", hcd->self.bus_name);
break;
case OHCI_USB_RESUME:
dbg ("%s suspend->resume ?", hcd->bus_name);
dbg ("%s suspend->resume ?", hcd->self.bus_name);
break;
case OHCI_USB_OPER:
dbg ("%s suspend->operational ?", hcd->bus_name);
dbg ("%s suspend->operational ?", hcd->self.bus_name);
break;
case OHCI_USB_SUSPEND:
dbg ("%s suspended", hcd->bus_name);
dbg ("%s suspended", hcd->self.bus_name);
break;
}
......@@ -711,8 +711,8 @@ static int hc_restart (struct ohci_hcd *ohci)
ohci->disabled = 1;
ohci->sleeping = 0;
if (ohci->hcd.bus->root_hub)
usb_disconnect (&ohci->hcd.bus->root_hub);
if (ohci->hcd.self.root_hub)
usb_disconnect (&ohci->hcd.self.root_hub);
/* empty the interrupt branches */
for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load [i] = 0;
......@@ -728,10 +728,10 @@ static int hc_restart (struct ohci_hcd *ohci)
ohci->ed_bulktail = NULL;
if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) {
err ("can't restart %s, %d", ohci->hcd.bus_name, temp);
err ("can't restart %s, %d", ohci->hcd.self.bus_name, temp);
return temp;
} else
dbg ("restart %s completed", ohci->hcd.bus_name);
dbg ("restart %s completed", ohci->hcd.self.bus_name);
return 0;
}
......@@ -767,13 +767,13 @@ static int ohci_resume (struct usb_hcd *hcd)
switch (temp) {
case OHCI_USB_RESET: // lost power
info ("USB restart: %s", hcd->bus_name);
info ("USB restart: %s", hcd->self.bus_name);
retval = hc_restart (ohci);
break;
case OHCI_USB_SUSPEND: // host wakeup
case OHCI_USB_RESUME: // remote wakeup
info ("USB continue: %s from %s wakeup", hcd->bus_name,
info ("USB continue: %s from %s wakeup", hcd->self.bus_name,
(temp == OHCI_USB_SUSPEND)
? "host" : "remote");
ohci->hc_control = OHCI_USB_RESUME;
......@@ -786,7 +786,7 @@ static int ohci_resume (struct usb_hcd *hcd)
temp = readl (&ohci->regs->control);
temp = ohci->hc_control & OHCI_CTRL_HCFS;
if (temp != OHCI_USB_RESUME) {
err ("controller %s won't resume", hcd->bus_name);
err ("controller %s won't resume", hcd->self.bus_name);
ohci->disabled = 1;
retval = -EIO;
break;
......@@ -836,7 +836,7 @@ dbg ("sleeping = %d, disabled = %d", ohci->sleeping, ohci->disabled);
break;
default:
warn ("odd PCI resume for %s", hcd->bus_name);
warn ("odd PCI resume for %s", hcd->self.bus_name);
}
return retval;
}
......
......@@ -41,7 +41,7 @@ static u32 roothub_portstatus (struct ohci_hcd *hc, int i)
#define dbg_port(hc,label,num,value) \
dbg ("%s: %s roothub.portstatus [%d] " \
"= 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s", \
hc->hcd.bus_name, label, num, temp, \
hc->hcd.self.bus_name, label, num, temp, \
(temp & RH_PS_PRSC) ? " PRSC" : "", \
(temp & RH_PS_OCIC) ? " OCIC" : "", \
(temp & RH_PS_PSSC) ? " PSSC" : "", \
......@@ -71,7 +71,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
ports = roothub_a (ohci) & RH_A_NDP;
if (ports > MAX_ROOT_PORTS) {
err ("%s: bogus NDP=%d", hcd->bus_name, ports);
err ("%s: bogus NDP=%d", hcd->self.bus_name, ports);
err ("rereads as NDP=%d",
readl (&ohci->regs->roothub.a) & RH_A_NDP);
/* retry later; "should not happen" */
......
......@@ -2799,6 +2799,7 @@ static int alloc_uhci(struct pci_dev *dev, unsigned int io_addr, unsigned int io
uhci->bus = bus;
bus->hcpriv = uhci;
bus->bus_name = dev->slot_name;
usb_register_bus(uhci->bus);
......
......@@ -2400,6 +2400,7 @@ static ohci_t * __devinit hc_alloc_ohci (struct pci_dev *dev, void * mem_base)
return NULL;
}
ohci->bus->hcpriv = (void *) ohci;
ohci->bus->bus_name = dev->slot_name;
return ohci;
}
......
......@@ -2977,6 +2977,7 @@ _static int __devinit alloc_uhci (struct pci_dev *dev, int irq, unsigned int io_
s->bus = bus;
bus->hcpriv = s;
bus->bus_name = dev->slot_name;
/* UHCI specs says devices must have 2 ports, but goes on to say */
/* they may have more but give no way to determine how many they */
......
CONFIG_USB_DC2XX
Say Y here if you want to connect this type of still camera to your
computer's USB port. See <file:Documentation/usb/dc2xx.txt> for
more information; some non-Kodak cameras may also work with this
driver, given application support (such as <http://www.gphoto.org/>).
This code is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called dc2xx.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_USB_MDC800
Say Y here if you want to connect this type of still camera to
your computer's USB port. This driver can be used with gphoto 0.4.3
......
......@@ -2,7 +2,6 @@
# USB Imageing devices configuration
#
comment 'USB Imaging devices'
dep_tristate ' USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
dep_tristate ' USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB $CONFIG_EXPERIMENTAL
dep_tristate ' USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB
dep_tristate ' Microtek X6USB scanner support' CONFIG_USB_MICROTEK $CONFIG_USB $CONFIG_SCSI
......@@ -10,10 +9,10 @@ dep_tristate ' HP53xx USB scanner support (EXPERIMENTAL)' CONFIG_USB_HPUSBSCSI
# Turn on CONFIG_USB_IMAGE if any of the drivers are compiled into the kernel to
# make our Makefile logic a bit simpler
if [ "$CONFIG_USB_DC2XX" = "y" -o "$CONFIG_USB_MDC800" = "y" ]; then
if [ "$CONFIG_USB_MDC800" = "y" -o "$CONFIG_USB_SCANNER" = "y" ]; then
define_bool CONFIG_USB_IMAGE y
fi
if [ "$CONFIG_USB_SCANNER" = "y" -o "$CONFIG_USB_MICROTEK" = "y" -o "$CONFIG_USB_HPUSBSCSI" = "y" ]; then
if [ "$CONFIG_USB_MICROTEK" = "y" -o "$CONFIG_USB_HPUSBSCSI" = "y" ]; then
define_bool CONFIG_USB_IMAGE y
fi
......@@ -4,7 +4,6 @@
O_TARGET := usb-image.o
obj-$(CONFIG_USB_DC2XX) += dc2xx.o
obj-$(CONFIG_USB_MDC800) += mdc800.o
obj-$(CONFIG_USB_HPUSBSCSI) += hpusbscsi.o
obj-$(CONFIG_USB_MICROTEK) += microtek.o
......
/*
* Copyright (C) 1999-2000 by David Brownell <dbrownell@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* USB driver for Kodak DC-2XX series digital still cameras
*
* The protocol here is the same as the one going over a serial line, but
* it uses USB for speed. Set up /dev/kodak, get gphoto (www.gphoto.org),
* and have fun!
*
* This should also work for a number of other digital (non-Kodak) cameras,
* by adding the vendor and product IDs to the table below. They'll need
* to be the sort using USB just as a fast bulk data channel.
*/
/*
* HISTORY
*
* 26 August, 1999 -- first release (0.1), works with my DC-240.
* The DC-280 (2Mpixel) should also work, but isn't tested.
* If you use gphoto, make sure you have the USB updates.
* Lives in a 2.3.14 or so Linux kernel, in drivers/usb.
* 31 August, 1999 -- minor update to recognize DC-260 and handle
* its endpoints being in a different order. Note that as
* of gPhoto 0.36pre, the USB updates are integrated.
* 12 Oct, 1999 -- handle DC-280 interface class (0xff not 0x0);
* added timeouts to bulk_msg calls. Minor updates, docs.
* 03 Nov, 1999 -- update for 2.3.25 kernel API changes.
* 08 Jan, 2000 .. multiple camera support
* 12 Aug, 2000 .. add some real locking, remove an Oops
* 10 Oct, 2000 .. usb_device_id table created.
* 01 Nov, 2000 .. usb_device_id support added by Adam J. Richter
* 08 Apr, 2001 .. Identify version on module load. gb
*
* Thanks to: the folk who've provided USB product IDs, sent in
* patches, and shared their successes!
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/random.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/devfs_fs_kernel.h>
#ifdef CONFIG_USB_DEBUG
#define DEBUG
#else
#undef DEBUG
#endif
#include <linux/usb.h>
/* /dev/usb dir. */
extern devfs_handle_t usb_devfs_handle;
/*
* Version Information
*/
#define DRIVER_VERSION "v1.0.0"
#define DRIVER_AUTHOR "David Brownell, <dbrownell@users.sourceforge.net>"
#define DRIVER_DESC "USB Camera Driver for Kodak DC-2xx series cameras"
/* current USB framework handles max of 16 USB devices per driver */
#define MAX_CAMERAS 16
/* USB char devs use USB_MAJOR and from USB_CAMERA_MINOR_BASE up */
#define USB_CAMERA_MINOR_BASE 80
// XXX remove packet size limit, now that bulk transfers seem fixed
/* Application protocol limit is 0x8002; USB has disliked that limit! */
#define MAX_PACKET_SIZE 0x2000 /* e.g. image downloading */
#define MAX_READ_RETRY 5 /* times to retry reads */
#define MAX_WRITE_RETRY 5 /* times to retry writes */
#define RETRY_TIMEOUT (HZ) /* sleep between retries */
/* table of cameras that work through this driver */
static struct usb_device_id camera_table [] = {
/* These have the same application level protocol */
{ USB_DEVICE(0x040a, 0x0120) }, // Kodak DC-240
{ USB_DEVICE(0x040a, 0x0130) }, // Kodak DC-280
{ USB_DEVICE(0x040a, 0x0131) }, // Kodak DC-5000
{ USB_DEVICE(0x040a, 0x0132) }, // Kodak DC-3400
/* These have a different application level protocol which
* is part of the Flashpoint "DigitaOS". That supports some
* non-camera devices, and some non-Kodak cameras.
* Use this driver to get USB and "OpenDis" to talk.
*/
{ USB_DEVICE(0x040a, 0x0100) }, // Kodak DC-220
{ USB_DEVICE(0x040a, 0x0110) }, // Kodak DC-260
{ USB_DEVICE(0x040a, 0x0111) }, // Kodak DC-265
{ USB_DEVICE(0x040a, 0x0112) }, // Kodak DC-290
{ USB_DEVICE(0xf003, 0x6002) }, // HP PhotoSmart C500
{ USB_DEVICE(0x03f0, 0x4102) }, // HP PhotoSmart C618
{ USB_DEVICE(0x0a17, 0x1001) }, // Pentax EI-200
/* Other USB devices may well work here too, so long as they
* just stick to half duplex bulk packet exchanges. That
* means, among other things, no iso or interrupt endpoints.
*/
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, camera_table);
struct camera_state {
struct usb_device *dev; /* USB device handle */
int inEP; /* read endpoint */
int outEP; /* write endpoint */
const struct usb_device_id *info; /* DC-240, etc */
int subminor; /* which minor dev #? */
struct semaphore sem; /* locks this struct */
/* this is non-null iff the device is open */
char *buf; /* buffer for I/O */
devfs_handle_t devfs; /* devfs device */
/* always valid */
wait_queue_head_t wait; /* for timed waits */
};
/* Support multiple cameras, possibly of different types. */
static struct camera_state *minor_data [MAX_CAMERAS];
/* make this an rwlock if contention becomes an issue */
static DECLARE_MUTEX (state_table_mutex);
static ssize_t camera_read (struct file *file,
char *buf, size_t len, loff_t *ppos)
{
struct camera_state *camera;
int retries;
int retval = 0;
if (len > MAX_PACKET_SIZE)
return -EINVAL;
camera = (struct camera_state *) file->private_data;
down (&camera->sem);
if (!camera->dev) {
up (&camera->sem);
return -ENODEV;
}
/* Big reads are common, for image downloading. Smaller ones
* are also common (even "directory listing" commands don't
* send very much data). We preserve packet boundaries here,
* they matter in the application protocol.
*/
for (retries = 0; retries < MAX_READ_RETRY; retries++) {
int count;
if (signal_pending (current)) {
retval = -EINTR;
break;
}
retval = usb_bulk_msg (camera->dev,
usb_rcvbulkpipe (camera->dev, camera->inEP),
camera->buf, len, &count, HZ*10);
dbg ("read (%Zd) - 0x%x %d", len, retval, count);
if (!retval) {
if (copy_to_user (buf, camera->buf, count))
retval = -EFAULT;
else
retval = count;
break;
}
if (retval != -ETIMEDOUT)
break;
interruptible_sleep_on_timeout (&camera->wait, RETRY_TIMEOUT);
dbg ("read (%Zd) - retry", len);
}
up (&camera->sem);
return retval;
}
static ssize_t camera_write (struct file *file,
const char *buf, size_t len, loff_t *ppos)
{
struct camera_state *camera;
ssize_t bytes_written = 0;
if (len > MAX_PACKET_SIZE)
return -EINVAL;
camera = (struct camera_state *) file->private_data;
down (&camera->sem);
if (!camera->dev) {
up (&camera->sem);
return -ENODEV;
}
/* most writes will be small: simple commands, sometimes with
* parameters. putting images (like borders) into the camera
* would be the main use of big writes.
*/
while (len > 0) {
char *obuf = camera->buf;
int maxretry = MAX_WRITE_RETRY;
unsigned long copy_size, thistime;
/* it's not clear that retrying can do any good ... or that
* fragmenting application packets into N writes is correct.
*/
thistime = copy_size = len;
if (copy_from_user (obuf, buf, copy_size)) {
bytes_written = -EFAULT;
break;
}
while (thistime) {
int result;
int count;
if (signal_pending (current)) {
if (!bytes_written)
bytes_written = -EINTR;
goto done;
}
result = usb_bulk_msg (camera->dev,
usb_sndbulkpipe (camera->dev, camera->outEP),
obuf, thistime, &count, HZ*10);
if (result)
dbg ("write USB err - %d", result);
if (count) {
obuf += count;
thistime -= count;
maxretry = MAX_WRITE_RETRY;
continue;
} else if (!result)
break;
if (result == -ETIMEDOUT) { /* NAK - delay a bit */
if (!maxretry--) {
if (!bytes_written)
bytes_written = -ETIME;
goto done;
}
interruptible_sleep_on_timeout (&camera->wait,
RETRY_TIMEOUT);
continue;
}
if (!bytes_written)
bytes_written = -EIO;
goto done;
}
bytes_written += copy_size;
len -= copy_size;
buf += copy_size;
}
done:
up (&camera->sem);
dbg ("wrote %Zd", bytes_written);
return bytes_written;
}
static int camera_open (struct inode *inode, struct file *file)
{
struct camera_state *camera = NULL;
int subminor;
int value = 0;
down (&state_table_mutex);
subminor = minor (inode->i_rdev) - USB_CAMERA_MINOR_BASE;
if (subminor < 0 || subminor >= MAX_CAMERAS
|| !(camera = minor_data [subminor])) {
up (&state_table_mutex);
return -ENODEV;
}
down (&camera->sem);
up (&state_table_mutex);
if (camera->buf) {
value = -EBUSY;
goto done;
}
if (!(camera->buf = (char *) kmalloc (MAX_PACKET_SIZE, GFP_KERNEL))) {
value = -ENOMEM;
goto done;
}
dbg ("open #%d", subminor);
file->private_data = camera;
done:
up (&camera->sem);
return value;
}
static int camera_release (struct inode *inode, struct file *file)
{
struct camera_state *camera;
int subminor;
camera = (struct camera_state *) file->private_data;
down (&state_table_mutex);
down (&camera->sem);
if (camera->buf) {
kfree (camera->buf);
camera->buf = 0;
}
subminor = camera->subminor;
/* If camera was unplugged with open file ... */
if (!camera->dev) {
minor_data [subminor] = NULL;
kfree (camera);
} else
up (&camera->sem);
up (&state_table_mutex);
dbg ("close #%d", subminor);
return 0;
}
/* XXX should define some ioctls to expose camera type
* to applications ... what USB exposes should suffice.
* apps should be able to see the camera type.
*/
static /* const */ struct file_operations usb_camera_fops = {
/* Uses GCC initializer extension; simpler to maintain */
owner: THIS_MODULE,
read: camera_read,
write: camera_write,
open: camera_open,
release: camera_release,
};
static void *
camera_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *camera_info)
{
int i;
struct usb_interface_descriptor *interface;
struct usb_endpoint_descriptor *endpoint;
int direction, ep;
char name[8];
struct camera_state *camera = NULL;
/* these have one config, one interface */
if (dev->descriptor.bNumConfigurations != 1
|| dev->config[0].bNumInterfaces != 1) {
dbg ("Bogus camera config info");
return NULL;
}
/* models differ in how they report themselves */
interface = &dev->actconfig->interface[ifnum].altsetting[0];
if ((interface->bInterfaceClass != USB_CLASS_PER_INTERFACE
&& interface->bInterfaceClass != USB_CLASS_VENDOR_SPEC)
|| interface->bInterfaceSubClass != 0
|| interface->bInterfaceProtocol != 0
|| interface->bNumEndpoints != 2
) {
dbg ("Bogus camera interface info");
return NULL;
}
/* select "subminor" number (part of a minor number) */
down (&state_table_mutex);
for (i = 0; i < MAX_CAMERAS; i++) {
if (!minor_data [i])
break;
}
if (i >= MAX_CAMERAS) {
info ("Ignoring additional USB Camera");
goto bye;
}
/* allocate & init camera state */
camera = minor_data [i] = kmalloc (sizeof *camera, GFP_KERNEL);
if (!camera) {
err ("no memory!");
goto bye;
}
init_MUTEX (&camera->sem);
camera->info = camera_info;
camera->subminor = i;
camera->buf = NULL;
init_waitqueue_head (&camera->wait);
/* get input and output endpoints (either order) */
endpoint = interface->endpoint;
camera->outEP = camera->inEP = -1;
ep = endpoint [0].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
direction = endpoint [0].bEndpointAddress & USB_ENDPOINT_DIR_MASK;
if (direction == USB_DIR_IN)
camera->inEP = ep;
else
camera->outEP = ep;
ep = endpoint [1].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
direction = endpoint [1].bEndpointAddress & USB_ENDPOINT_DIR_MASK;
if (direction == USB_DIR_IN)
camera->inEP = ep;
else
camera->outEP = ep;
if (camera->outEP == -1 || camera->inEP == -1
|| endpoint [0].bmAttributes != USB_ENDPOINT_XFER_BULK
|| endpoint [1].bmAttributes != USB_ENDPOINT_XFER_BULK
) {
dbg ("Bogus endpoints");
goto error;
}
info ("USB Camera #%d connected, major/minor %d/%d", camera->subminor,
USB_MAJOR, USB_CAMERA_MINOR_BASE + camera->subminor);
camera->dev = dev;
usb_inc_dev_use (dev);
/* If we have devfs, register the device */
sprintf(name, "dc2xx%d", camera->subminor);
camera->devfs = devfs_register(usb_devfs_handle, name,
DEVFS_FL_DEFAULT, USB_MAJOR,
USB_CAMERA_MINOR_BASE + camera->subminor,
S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
S_IWGRP, &usb_camera_fops, NULL);
goto bye;
error:
minor_data [camera->subminor] = NULL;
kfree (camera);
camera = NULL;
bye:
up (&state_table_mutex);
return camera;
}
static void camera_disconnect(struct usb_device *dev, void *ptr)
{
struct camera_state *camera = (struct camera_state *) ptr;
int subminor = camera->subminor;
down (&state_table_mutex);
down (&camera->sem);
devfs_unregister(camera->devfs);
/* If camera's not opened, we can clean up right away.
* Else apps see a disconnect on next I/O; the release cleans.
*/
if (!camera->buf) {
minor_data [subminor] = NULL;
kfree (camera);
camera = NULL;
} else
camera->dev = NULL;
info ("USB Camera #%d disconnected", subminor);
usb_dec_dev_use (dev);
if (camera != NULL)
up (&camera->sem);
up (&state_table_mutex);
}
static /* const */ struct usb_driver camera_driver = {
name: "dc2xx",
id_table: camera_table,
probe: camera_probe,
disconnect: camera_disconnect,
fops: &usb_camera_fops,
minor: USB_CAMERA_MINOR_BASE
};
int __init usb_dc2xx_init(void)
{
if (usb_register (&camera_driver) < 0)
return -1;
info(DRIVER_VERSION ":" DRIVER_DESC);
return 0;
}
void __exit usb_dc2xx_cleanup(void)
{
usb_deregister (&camera_driver);
}
module_init (usb_dc2xx_init);
module_exit (usb_dc2xx_cleanup);
MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_LICENSE("GPL");
......@@ -33,7 +33,7 @@
/*
* Version Information
*/
#define DRIVER_VERSION "1.02"
#define DRIVER_VERSION "1.03"
#define DRIVER_AUTHOR "Romain Lievin <roms@lpg.ticalc.org> & Julien Blache <jb@jblache.org>"
#define DRIVER_DESC "TI-GRAPH LINK USB (aka SilverLink) driver"
#define DRIVER_LICENSE "GPL"
......@@ -383,6 +383,7 @@ static void tiglusb_disconnect (struct usb_device *dev, void *drv_context)
wake_up (&s->wait);
if (s->state == _started)
sleep_on (&s->remove_ok);
down (&s->mutex);
s->dev = NULL;
s->opened = 0;
......@@ -479,7 +480,7 @@ static void __exit tiglusb_cleanup (void)
/* --------------------------------------------------------------------- */
__setup ("tipar=", tiglusb_setup);
__setup ("tiusb=", tiglusb_setup);
module_init (tiglusb_init);
module_exit (tiglusb_cleanup);
......
......@@ -7,10 +7,10 @@ if [ "$CONFIG_NET" = "n" ]; then
else
dep_tristate ' USB CATC NetMate-based Ethernet device support (EXPERIMENTAL)' CONFIG_USB_CATC $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
dep_tristate ' USB CDC Ethernet support (EXPERIMENTAL)' CONFIG_USB_CDCETHER $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
dep_tristate ' USB KLSI KL5USB101-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_KAWETH $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
dep_tristate ' USB Pegasus/Pegasus-II based ethernet device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
dep_tristate ' USB KLSI KL5USB101-based ethernet device support' CONFIG_USB_KAWETH $CONFIG_USB $CONFIG_NET
dep_tristate ' USB Pegasus/Pegasus-II based ethernet device support' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET
dep_tristate ' USB RTL8150 based ethernet device support (EXPERIMENTAL)' CONFIG_USB_RTL8150 $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
dep_tristate ' USB-to-USB Networking cable device support (EXPERIMENTAL)' CONFIG_USB_USBNET $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
dep_tristate ' USB-to-USB Networking cable device support' CONFIG_USB_USBNET $CONFIG_USB $CONFIG_NET
fi
# Turn on CONFIG_USB_NET if any of the drivers are compiled into the kernel to
......
......@@ -278,7 +278,7 @@ static void catc_rx_done(struct urb *urb)
atomic_dec(&catc->recq_sz);
dbg("getting extra packet");
urb->dev = catc->usbdev;
if ((status = usb_submit_urb(urb, GFP_KERNEL)) < 0) {
if ((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
dbg("submit(rx_urb) status %d", status);
}
} else {
......@@ -329,7 +329,7 @@ static void catc_irq_done(struct urb *urb)
atomic_inc(&catc->recq_sz);
} else {
catc->rx_urb->dev = catc->usbdev;
if ((status = usb_submit_urb(catc->rx_urb, GFP_KERNEL)) < 0) {
if ((status = usb_submit_urb(catc->rx_urb, GFP_ATOMIC)) < 0) {
err("submit(rx_urb) status %d", status);
}
}
......@@ -351,7 +351,7 @@ static void catc_tx_run(struct catc *catc)
catc->tx_urb->transfer_buffer = catc->tx_buf[catc->tx_idx];
catc->tx_urb->dev = catc->usbdev;
if ((status = usb_submit_urb(catc->tx_urb, GFP_KERNEL)) < 0)
if ((status = usb_submit_urb(catc->tx_urb, GFP_ATOMIC)) < 0)
err("submit(tx_urb), status %d", status);
catc->tx_idx = !catc->tx_idx;
......@@ -655,7 +655,6 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
{
struct catc *catc = dev->priv;
u32 cmd;
char tmp[40];
if (get_user(cmd, (u32 *)useraddr))
return -EFAULT;
......@@ -666,8 +665,7 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
strncpy(info.driver, SHORT_DRIVER_DESC, ETHTOOL_BUSINFO_LEN);
strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
sprintf(tmp, "usb%d:%d", catc->usbdev->bus->busnum, catc->usbdev->devnum);
strncpy(info.bus_info, tmp,ETHTOOL_BUSINFO_LEN);
usb_make_path (catc->usbdev, info.bus_info, sizeof info.bus_info);
if (copy_to_user(useraddr, &info, sizeof(info)))
return -EFAULT;
return 0;
......@@ -909,9 +907,9 @@ static void *catc_probe(struct usb_device *usbdev, unsigned int ifnum, const str
f5u011_rxmode(catc, catc->rxmode);
}
dbg("Init done.");
printk(KERN_INFO "%s: %s USB Ethernet at usb%d:%d.%d, ",
printk(KERN_INFO "%s: %s USB Ethernet at usb-%s-%s/%d, ",
netdev->name, (catc->is_f5u011) ? "Belkin F5U011" : "CATC EL1210A NetMate",
usbdev->bus->busnum, usbdev->devnum, ifnum);
usbdev->bus->bus_name, usbdev->devpath, ifnum);
for (i = 0; i < 5; i++) printk("%2.2x:", netdev->dev_addr[i]);
printk("%2.2x.\n", netdev->dev_addr[i]);
return catc;
......
......@@ -5,17 +5,18 @@
* (c) 2000 Interlan Communications
* (c) 2000 Stephane Alnet
* (C) 2001 Brad Hards
* (C) 2002 Oliver Neukum
*
* Original author: The Zapman <zapman@interlan.net>
* Inspired by, and much credit goes to Michael Rothwell
* Inspired by, and much credit goes to Michael Rothwell
* <rothwell@interlan.net> for the test equipment, help, and patience
* Based off of (and with thanks to) Petko Manolov's pegaus.c driver.
* Also many thanks to Joel Silverman and Ed Surprenant at Kawasaki
* Also many thanks to Joel Silverman and Ed Surprenant at Kawasaki
* for providing the firmware and driver resources.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2, or
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
......@@ -25,7 +26,7 @@
*
* 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.
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
****************************************************************/
......@@ -36,8 +37,8 @@
* Fix bugs from previous two steps
* Snoop other OSs for any tricks we're not doing
* SMP locking
* Reduce arbitrary timeouts
* Smart multicast support
* Reduce arbitrary timeouts
* Smart multicast support
* Temporary MAC change support
* Tunable SOFs parameter - ioctl()?
* Ethernet stats collection
......@@ -99,8 +100,14 @@
#define KAWETH_SOFS_TO_WAIT 0x05
#define INTBUFFERSIZE 4
MODULE_AUTHOR("Michael Zappe <zapman@interlan.net>, Stephane Alnet <stephane@u-picardie.fr> and Brad Hards <bhards@bigpond.net.au>");
#define STATE_OFFSET 0
#define STATE_MASK 0x40
#define STATE_SHIFT 5
MODULE_AUTHOR("Michael Zappe <zapman@interlan.net>, Stephane Alnet <stephane@u-picardie.fr>, Brad Hards <bhards@bigpond.net.au> and Oliver Neukum <oliver@neukum.org>");
MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver");
MODULE_LICENSE("GPL");
......@@ -118,21 +125,21 @@ int kaweth_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe,
* usb_device_id
****************************************************************/
static struct usb_device_id usb_klsi_table[] = {
{ USB_DEVICE(0x03e8, 0x0008) }, /* AOX Endpoints USB Ethernet */
{ USB_DEVICE(0x03e8, 0x0008) }, /* AOX Endpoints USB Ethernet */
{ USB_DEVICE(0x04bb, 0x0901) }, /* I-O DATA USB-ET/T */
{ USB_DEVICE(0x0506, 0x03e8) }, /* 3Com 3C19250 */
{ USB_DEVICE(0x0557, 0x2002) }, /* ATEN USB Ethernet */
{ USB_DEVICE(0x0557, 0x4000) }, /* D-Link DSB-650C */
{ USB_DEVICE(0x0506, 0x03e8) }, /* 3Com 3C19250 */
{ USB_DEVICE(0x0557, 0x2002) }, /* ATEN USB Ethernet */
{ USB_DEVICE(0x0557, 0x4000) }, /* D-Link DSB-650C */
{ USB_DEVICE(0x0565, 0x0002) }, /* Peracom Enet */
{ USB_DEVICE(0x0565, 0x0003) }, /* Optus@Home UEP1045A */
{ USB_DEVICE(0x0565, 0x0005) }, /* Peracom Enet2 */
{ USB_DEVICE(0x0565, 0x0005) }, /* Peracom Enet2 */
{ USB_DEVICE(0x05e9, 0x0008) }, /* KLSI KL5KUSB101B */
{ USB_DEVICE(0x05e9, 0x0009) }, /* KLSI KL5KUSB101B (Board change) */
{ USB_DEVICE(0x066b, 0x2202) }, /* Linksys USB10T */
{ USB_DEVICE(0x06e1, 0x0008) }, /* ADS USB-10BT */
{ USB_DEVICE(0x06e1, 0x0009) }, /* ADS USB-10BT */
{ USB_DEVICE(0x0707, 0x0100) }, /* SMC 2202USB */
{ USB_DEVICE(0x07aa, 0x0001) }, /* Correga K.K. */
{ USB_DEVICE(0x066b, 0x2202) }, /* Linksys USB10T */
{ USB_DEVICE(0x06e1, 0x0008) }, /* ADS USB-10BT */
{ USB_DEVICE(0x06e1, 0x0009) }, /* ADS USB-10BT */
{ USB_DEVICE(0x0707, 0x0100) }, /* SMC 2202USB */
{ USB_DEVICE(0x07aa, 0x0001) }, /* Correga K.K. */
{ USB_DEVICE(0x07b8, 0x4000) }, /* D-Link DU-E10 */
{ USB_DEVICE(0x0846, 0x1001) }, /* NetGear EA-101 */
{ USB_DEVICE(0x0846, 0x1002) }, /* NetGear EA-101 */
......@@ -144,9 +151,9 @@ static struct usb_device_id usb_klsi_table[] = {
{ USB_DEVICE(0x10bd, 0x1427) }, /* ASANTE USB To Ethernet Adapter */
{ USB_DEVICE(0x1342, 0x0204) }, /* Mobility USB-Ethernet Adapter */
{ USB_DEVICE(0x13d2, 0x0400) }, /* Shark Pocket Adapter */
{ USB_DEVICE(0x1645, 0x0005) }, /* Entrega E45 */
{ USB_DEVICE(0x1645, 0x0008) }, /* Entrega USB Ethernet Adapter */
{ USB_DEVICE(0x1645, 0x8005) }, /* PortGear Ethernet Adapter */
{ USB_DEVICE(0x1645, 0x0005) }, /* Entrega E45 */
{ USB_DEVICE(0x1645, 0x0008) }, /* Entrega USB Ethernet Adapter */
{ USB_DEVICE(0x1645, 0x8005) }, /* PortGear Ethernet Adapter */
{ USB_DEVICE(0x2001, 0x4000) }, /* D-link DSB-650C */
{} /* Null terminator */
};
......@@ -200,17 +207,23 @@ struct kaweth_device
spinlock_t device_lock;
__u32 status;
int end;
int removed;
int suspend_lowmem;
int linkstate;
struct usb_device *dev;
struct net_device *net;
wait_queue_head_t control_wait;
wait_queue_head_t term_wait;
struct urb *rx_urb;
struct urb *tx_urb;
struct urb *irq_urb;
__u8 firmware_buf[KAWETH_FIRMWARE_BUF_SIZE];
__u8 tx_buf[KAWETH_BUF_SIZE];
__u8 rx_buf[KAWETH_BUF_SIZE];
__u8 intbuffer[INTBUFFERSIZE];
__u16 packet_filter_bitmap;
struct kaweth_ethernet_configuration configuration;
......@@ -223,13 +236,13 @@ struct kaweth_device
* kaweth_control
****************************************************************/
static int kaweth_control(struct kaweth_device *kaweth,
unsigned int pipe,
__u8 request,
__u8 requesttype,
__u16 value,
unsigned int pipe,
__u8 request,
__u8 requesttype,
__u16 value,
__u16 index,
void *data,
__u16 size,
void *data,
__u16 size,
int timeout)
{
struct usb_ctrlrequest *dr;
......@@ -247,7 +260,7 @@ static int kaweth_control(struct kaweth_device *kaweth,
kaweth_dbg("kmalloc() failed");
return -ENOMEM;
}
dr->bRequestType= requesttype;
dr->bRequest = request;
dr->wValue = cpu_to_le16p(&value);
......@@ -354,19 +367,19 @@ static int kaweth_set_receive_filter(struct kaweth_device *kaweth,
/****************************************************************
* kaweth_download_firmware
****************************************************************/
static int kaweth_download_firmware(struct kaweth_device *kaweth,
__u8 *data,
static int kaweth_download_firmware(struct kaweth_device *kaweth,
__u8 *data,
__u16 data_len,
__u8 interrupt,
__u8 type)
{
{
if(data_len > KAWETH_FIRMWARE_BUF_SIZE) {
kaweth_err("Firmware too big: %d", data_len);
return -ENOSPC;
}
memcpy(kaweth->firmware_buf, data, data_len);
kaweth->firmware_buf[2] = (data_len & 0xFF) - 7;
kaweth->firmware_buf[3] = data_len >> 8;
kaweth->firmware_buf[4] = type;
......@@ -375,8 +388,8 @@ static int kaweth_download_firmware(struct kaweth_device *kaweth,
kaweth_dbg("High: %i, Low:%i", kaweth->firmware_buf[3],
kaweth->firmware_buf[2]);
kaweth_dbg("Downloading firmware at %p to kaweth device at %p",
data,
kaweth_dbg("Downloading firmware at %p to kaweth device at %p",
data,
kaweth);
kaweth_dbg("Firmware length: %d", data_len);
......@@ -405,7 +418,7 @@ static int kaweth_trigger_firmware(struct kaweth_device *kaweth,
kaweth->firmware_buf[5] = interrupt;
kaweth->firmware_buf[6] = 0x00;
kaweth->firmware_buf[7] = 0x00;
kaweth_dbg("Triggering firmware");
return kaweth_control(kaweth,
......@@ -429,12 +442,12 @@ static int kaweth_reset(struct kaweth_device *kaweth)
kaweth_dbg("kaweth_reset(%p)", kaweth);
result = kaweth_control(kaweth,
usb_sndctrlpipe(kaweth->dev, 0),
USB_REQ_SET_CONFIGURATION,
0,
USB_REQ_SET_CONFIGURATION,
0,
kaweth->dev->config[0].bConfigurationValue,
0,
NULL,
0,
0,
NULL,
0,
KAWETH_CONTROL_TIMEOUT);
udelay(10000);
......@@ -445,17 +458,40 @@ static int kaweth_reset(struct kaweth_device *kaweth)
}
static void kaweth_usb_receive(struct urb *);
static void kaweth_resubmit_rx_urb(struct kaweth_device *, int);
/****************************************************************
int_callback
*****************************************************************/
static void int_callback(struct urb *u)
{
struct kaweth_device *kaweth = u->context;
int act_state;
/* we abuse the interrupt urb for rebsubmitting under low memory saving a timer */
if (kaweth->suspend_lowmem)
kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
/* we check the link state to report changes */
if (kaweth->linkstate != (act_state = ( kaweth->intbuffer[STATE_OFFSET] | STATE_MASK) >> STATE_SHIFT)) {
if (!act_state)
netif_carrier_on(kaweth->net);
else
netif_carrier_off(kaweth->net);
kaweth->linkstate = act_state;
}
}
/****************************************************************
* kaweth_resubmit_rx_urb
****************************************************************/
static inline void kaweth_resubmit_rx_urb(struct kaweth_device *kaweth,
static void kaweth_resubmit_rx_urb(struct kaweth_device *kaweth,
int mem_flags)
{
int result;
memset(kaweth->rx_urb, 0, sizeof(*kaweth->rx_urb));
FILL_BULK_URB(kaweth->rx_urb,
kaweth->dev,
usb_rcvbulkpipe(kaweth->dev, 1),
......@@ -465,7 +501,11 @@ static inline void kaweth_resubmit_rx_urb(struct kaweth_device *kaweth,
kaweth);
if((result = usb_submit_urb(kaweth->rx_urb, mem_flags))) {
if (result == -ENOMEM)
kaweth->suspend_lowmem = 1;
kaweth_err("resubmitting rx_urb %d failed", result);
} else {
kaweth->suspend_lowmem = 0;
}
}
......@@ -478,23 +518,30 @@ static void kaweth_usb_receive(struct urb *urb)
{
struct kaweth_device *kaweth = urb->context;
struct net_device *net = kaweth->net;
int count = urb->actual_length;
int count2 = urb->transfer_buffer_length;
__u16 pkt_len = le16_to_cpup((u16 *)kaweth->rx_buf);
struct sk_buff *skb;
if(kaweth->status & KAWETH_STATUS_CLOSING) {
if(unlikely(urb->status == -ECONNRESET || urb->status == -ECONNABORTED))
/* we are killed - set a flag and wake the disconnect handler */
{
kaweth->end = 1;
wake_up(&kaweth->term_wait);
return;
}
if(urb->status && urb->status != -EREMOTEIO && count != 1) {
if (kaweth->status & KAWETH_STATUS_CLOSING)
return;
if(urb->status && urb->status != -EREMOTEIO && count != 1) {
kaweth_err("%s RX status: %d count: %d packet_len: %d",
net->name,
net->name,
urb->status,
count,
count,
(int)pkt_len);
kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
return;
......@@ -508,7 +555,7 @@ static void kaweth_usb_receive(struct urb *urb)
kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
return;
}
if(!(skb = dev_alloc_skb(pkt_len+2))) {
kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
return;
......@@ -517,13 +564,13 @@ static void kaweth_usb_receive(struct urb *urb)
skb->dev = net;
eth_copy_and_sum(skb, kaweth->rx_buf + 2, pkt_len, 0);
skb_put(skb, pkt_len);
skb->protocol = eth_type_trans(skb, net);
netif_rx(skb);
kaweth->stats.rx_packets++;
kaweth->stats.rx_bytes += pkt_len;
}
......@@ -546,6 +593,18 @@ static int kaweth_open(struct net_device *net)
kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL);
FILL_INT_URB(
kaweth->irq_urb,
kaweth->dev,
usb_rcvintpipe(kaweth->dev, 3),
kaweth->intbuffer,
INTBUFFERSIZE,
int_callback,
kaweth,
HZ/4);
usb_submit_urb(kaweth->irq_urb, GFP_KERNEL);
netif_start_queue(net);
kaweth_async_set_rx_mode(kaweth);
......@@ -563,6 +622,7 @@ static int kaweth_close(struct net_device *net)
kaweth->status |= KAWETH_STATUS_CLOSING;
usb_unlink_urb(kaweth->irq_urb);
usb_unlink_urb(kaweth->rx_urb);
kaweth->status &= ~KAWETH_STATUS_CLOSING;
......@@ -602,11 +662,18 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
{
struct kaweth_device *kaweth = net->priv;
int count = skb->len;
int res;
spin_lock(&kaweth->device_lock);
if (kaweth->removed) {
/* our device is undergoing disconnection - we bail out */
spin_unlock(&kaweth->device_lock);
dev_kfree_skb(skb);
return 0;
}
kaweth_async_set_rx_mode(kaweth);
netif_stop_queue(net);
......@@ -614,8 +681,6 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
memcpy(kaweth->tx_buf + 2, skb->data, skb->len);
memset(kaweth->tx_urb, 0, sizeof(*kaweth->tx_urb));
FILL_BULK_URB(kaweth->tx_urb,
kaweth->dev,
usb_sndbulkpipe(kaweth->dev, 2),
......@@ -623,15 +688,17 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
count + 2,
kaweth_usb_transmit_complete,
kaweth);
kaweth->end = 0;
kaweth->tx_urb->transfer_flags |= USB_ASYNC_UNLINK;
if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC)))
{
kaweth_warn("kaweth failed tx_urb %d", res);
kaweth->stats.tx_errors++;
netif_start_queue(net);
}
else
}
else
{
kaweth->stats.tx_packets++;
kaweth->stats.tx_bytes += skb->len;
......@@ -651,7 +718,7 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
static void kaweth_set_rx_mode(struct net_device *net)
{
struct kaweth_device *kaweth = net->priv;
__u16 packet_filter_bitmap = KAWETH_PACKET_FILTER_DIRECTED |
KAWETH_PACKET_FILTER_BROADCAST |
KAWETH_PACKET_FILTER_MULTICAST;
......@@ -662,7 +729,7 @@ static void kaweth_set_rx_mode(struct net_device *net)
if (net->flags & IFF_PROMISC) {
packet_filter_bitmap |= KAWETH_PACKET_FILTER_PROMISCUOUS;
}
}
else if ((net->mc_count) || (net->flags & IFF_ALLMULTI)) {
packet_filter_bitmap |= KAWETH_PACKET_FILTER_ALL_MULTICAST;
}
......@@ -677,7 +744,7 @@ static void kaweth_set_rx_mode(struct net_device *net)
static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth)
{
__u16 packet_filter_bitmap = kaweth->packet_filter_bitmap;
kaweth->packet_filter_bitmap = 0;
kaweth->packet_filter_bitmap = 0;
if(packet_filter_bitmap == 0) return;
{
......@@ -737,14 +804,14 @@ static void *kaweth_probe(
int result = 0;
kaweth_dbg("Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x",
dev->devnum,
(int)dev->descriptor.idVendor,
dev->devnum,
(int)dev->descriptor.idVendor,
(int)dev->descriptor.idProduct,
(int)dev->descriptor.bcdDevice);
kaweth_dbg("Device at %p", dev);
kaweth_dbg("Descriptor length: %x type: %x",
kaweth_dbg("Descriptor length: %x type: %x",
(int)dev->descriptor.bLength,
(int)dev->descriptor.bDescriptorType);
......@@ -757,7 +824,8 @@ static void *kaweth_probe(
kaweth->dev = dev;
spin_lock_init(&kaweth->device_lock);
init_waitqueue_head(&kaweth->term_wait);
kaweth_dbg("Resetting.");
kaweth_reset(kaweth);
......@@ -772,20 +840,20 @@ static void *kaweth_probe(
} else {
/* Download the firmware */
kaweth_info("Downloading firmware...");
if ((result = kaweth_download_firmware(kaweth,
kaweth_new_code,
len_kaweth_new_code,
100,
if ((result = kaweth_download_firmware(kaweth,
kaweth_new_code,
len_kaweth_new_code,
100,
2)) < 0) {
kaweth_err("Error downloading firmware (%d)", result);
kfree(kaweth);
return NULL;
}
if ((result = kaweth_download_firmware(kaweth,
kaweth_new_code_fix,
len_kaweth_new_code_fix,
100,
if ((result = kaweth_download_firmware(kaweth,
kaweth_new_code_fix,
len_kaweth_new_code_fix,
100,
3)) < 0) {
kaweth_err("Error downloading firmware fix (%d)", result);
kfree(kaweth);
......@@ -845,7 +913,7 @@ static void *kaweth_probe(
(int)kaweth->configuration.hw_addr[5]);
if(!memcmp(&kaweth->configuration.hw_addr,
&bcast_addr,
&bcast_addr,
sizeof(bcast_addr))) {
kaweth_err("Firmware not functioning properly, no net device created");
kfree(kaweth);
......@@ -856,13 +924,13 @@ static void *kaweth_probe(
kaweth_dbg("Error setting URB size");
return kaweth;
}
if(kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT) < 0) {
kaweth_err("Error setting SOFS wait");
return kaweth;
}
result = kaweth_set_receive_filter(kaweth,
result = kaweth_set_receive_filter(kaweth,
KAWETH_PACKET_FILTER_DIRECTED |
KAWETH_PACKET_FILTER_BROADCAST |
KAWETH_PACKET_FILTER_MULTICAST);
......@@ -871,11 +939,18 @@ static void *kaweth_probe(
kaweth_err("Error setting receive filter");
return kaweth;
}
kaweth_dbg("Initializing net device.");
kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!kaweth->tx_urb)
goto err_no_urb;
kaweth->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!kaweth->rx_urb)
goto err_only_tx;
kaweth->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!kaweth->irq_urb)
goto err_tx_and_rx;
kaweth->net = init_etherdev(0, 0);
if (!kaweth->net) {
......@@ -884,17 +959,17 @@ static void *kaweth_probe(
}
memcpy(kaweth->net->broadcast, &bcast_addr, sizeof(bcast_addr));
memcpy(kaweth->net->dev_addr,
memcpy(kaweth->net->dev_addr,
&kaweth->configuration.hw_addr,
sizeof(kaweth->configuration.hw_addr));
kaweth->net->priv = kaweth;
kaweth->net->open = kaweth_open;
kaweth->net->stop = kaweth_close;
kaweth->net->watchdog_timeo = KAWETH_TX_TIMEOUT;
kaweth->net->tx_timeout = kaweth_tx_timeout;
kaweth->net->do_ioctl = kaweth_ioctl;
kaweth->net->hard_start_xmit = kaweth_start_xmit;
kaweth->net->set_multicast_list = kaweth_set_rx_mode;
......@@ -904,10 +979,18 @@ static void *kaweth_probe(
memset(&kaweth->stats, 0, sizeof(kaweth->stats));
kaweth_info("kaweth interface created at %s", kaweth->net->name);
kaweth_dbg("Kaweth probe returning.");
return kaweth;
err_tx_and_rx:
usb_free_urb(kaweth->rx_urb);
err_only_tx:
usb_free_urb(kaweth->tx_urb);
err_no_urb:
kfree(kaweth);
return NULL;
}
/****************************************************************
......@@ -923,9 +1006,20 @@ static void kaweth_disconnect(struct usb_device *dev, void *ptr)
kaweth_warn("unregistering non-existant device");
return;
}
usb_unlink_urb(kaweth->tx_urb);
kaweth->removed = 1;
usb_unlink_urb(kaweth->irq_urb);
usb_unlink_urb(kaweth->rx_urb);
/* we need to wait for the urb to be cancelled, if it is active */
spin_lock(&kaweth->device_lock);
if (usb_unlink_urb(kaweth->tx_urb) == -EINPROGRESS) {
spin_unlock(&kaweth->device_lock);
wait_event(kaweth->term_wait, kaweth->end);
} else {
spin_unlock(&kaweth->device_lock);
}
if(kaweth->net) {
if(kaweth->net->flags & IFF_UP) {
kaweth_dbg("Closing net device");
......@@ -944,7 +1038,7 @@ static void kaweth_disconnect(struct usb_device *dev, void *ptr)
// FIXME this completion stuff is a modified clone of
// an OLD version of some stuff in usb.c ...
// an OLD version of some stuff in usb.c ...
struct usb_api_data {
wait_queue_head_t wqh;
int done;
......@@ -974,7 +1068,7 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
init_waitqueue_head(&awd.wqh);
awd.done = 0;
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&awd.wqh, &wait);
urb->context = &awd;
......@@ -1021,7 +1115,7 @@ int kaweth_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe,
int retv;
int length;
urb = usb_alloc_urb(0, GFP_KERNEL);
urb = usb_alloc_urb(0, GFP_NOIO);
if (!urb)
return -ENOMEM;
......@@ -1065,3 +1159,4 @@ module_exit(kaweth_exit);
......@@ -41,7 +41,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/init.h>
......@@ -59,7 +58,7 @@
/*
* Version Information
*/
#define DRIVER_VERSION "v0.5.2 (2002/03/21)"
#define DRIVER_VERSION "v0.5.4 (2002/04/11)"
#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
#define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
......@@ -85,105 +84,103 @@ static struct usb_device_id pegasus_ids[] = {
{match_flags: USB_DEVICE_ID_MATCH_DEVICE, idVendor:vid, idProduct:pid},
#include "pegasus.h"
#undef PEGASUS_DEV
{ }
{}
};
MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
MODULE_PARM(loopback, "i");
MODULE_PARM(mii_mode, "i");
MODULE_PARM_DESC(loopback, "Enable MAC loopback mode (bit 0)");
MODULE_PARM_DESC(mii_mode, "Enable HomePNA mode (bit 0),default=MII mode = 0");
MODULE_DEVICE_TABLE (usb, pegasus_ids);
MODULE_DEVICE_TABLE(usb, pegasus_ids);
static int update_eth_regs_async( pegasus_t * );
static int update_eth_regs_async(pegasus_t *);
/* Aargh!!! I _really_ hate such tweaks */
static void ctrl_callback( struct urb *urb )
static void ctrl_callback(struct urb *urb)
{
pegasus_t *pegasus = urb->context;
pegasus_t *pegasus = urb->context;
if ( !pegasus )
if (!pegasus)
return;
switch ( urb->status ) {
case 0:
if ( pegasus->flags & ETH_REGS_CHANGE ) {
pegasus->flags &= ~ETH_REGS_CHANGE;
pegasus->flags |= ETH_REGS_CHANGED;
update_eth_regs_async( pegasus );
return;
}
break;
case -EINPROGRESS:
switch (urb->status) {
case 0:
if (pegasus->flags & ETH_REGS_CHANGE) {
pegasus->flags &= ~ETH_REGS_CHANGE;
pegasus->flags |= ETH_REGS_CHANGED;
update_eth_regs_async(pegasus);
return;
case -ENOENT:
break;
default:
warn("%s: status %d", __FUNCTION__, urb->status);
}
break;
case -EINPROGRESS:
return;
case -ENOENT:
break;
default:
warn("%s: status %d", __FUNCTION__, urb->status);
}
pegasus->flags &= ~ETH_REGS_CHANGED;
wake_up(&pegasus->ctrl_wait );
wake_up(&pegasus->ctrl_wait);
}
static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
void *data)
{
int ret;
int ret;
unsigned char *buffer;
DECLARE_WAITQUEUE(wait, current);
buffer = kmalloc(size,GFP_KERNEL);
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);
set_current_state(TASK_UNINTERRUPTIBLE);
while ( pegasus->flags & ETH_REGS_CHANGED )
while (pegasus->flags & ETH_REGS_CHANGED)
schedule();
remove_wait_queue(&pegasus->ctrl_wait, &wait);
set_current_state(TASK_RUNNING);
pegasus->dr.bRequestType = PEGASUS_REQT_READ;
pegasus->dr.bRequest = PEGASUS_REQ_GET_REGS;
pegasus->dr.wValue = cpu_to_le16 (0);
pegasus->dr.wValue = cpu_to_le16(0);
pegasus->dr.wIndex = cpu_to_le16p(&indx);
pegasus->dr.wLength = cpu_to_le16p(&size);
pegasus->ctrl_urb->transfer_buffer_length = size;
FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
usb_rcvctrlpipe(pegasus->usb,0),
(char *)&pegasus->dr,
buffer, size, ctrl_callback, pegasus );
FILL_CONTROL_URB(pegasus->ctrl_urb, pegasus->usb,
usb_rcvctrlpipe(pegasus->usb, 0),
(char *) &pegasus->dr,
buffer, size, ctrl_callback, pegasus);
add_wait_queue( &pegasus->ctrl_wait, &wait );
set_current_state( TASK_UNINTERRUPTIBLE );
add_wait_queue(&pegasus->ctrl_wait, &wait);
set_current_state(TASK_UNINTERRUPTIBLE);
/* using ATOMIC, we'd never wake up if we slept */
if ( (ret = usb_submit_urb( pegasus->ctrl_urb, GFP_ATOMIC )) ) {
if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) {
err("%s: BAD CTRLs %d", __FUNCTION__, ret);
goto out;
}
schedule();
out:
remove_wait_queue( &pegasus->ctrl_wait, &wait );
memcpy(data,buffer,size);
remove_wait_queue(&pegasus->ctrl_wait, &wait);
memcpy(data, buffer, size);
kfree(buffer);
return ret;
}
static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
void *data)
{
int ret;
int ret;
unsigned char *buffer;
DECLARE_WAITQUEUE(wait, current);
......@@ -196,47 +193,46 @@ static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
add_wait_queue(&pegasus->ctrl_wait, &wait);
set_current_state(TASK_UNINTERRUPTIBLE);
while ( pegasus->flags & ETH_REGS_CHANGED )
while (pegasus->flags & ETH_REGS_CHANGED)
schedule();
remove_wait_queue(&pegasus->ctrl_wait, &wait);
set_current_state(TASK_RUNNING);
pegasus->dr.bRequestType = PEGASUS_REQT_WRITE;
pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS;
pegasus->dr.wValue = cpu_to_le16 (0);
pegasus->dr.wIndex = cpu_to_le16p( &indx );
pegasus->dr.wLength = cpu_to_le16p( &size );
pegasus->dr.wValue = cpu_to_le16(0);
pegasus->dr.wIndex = cpu_to_le16p(&indx);
pegasus->dr.wLength = cpu_to_le16p(&size);
pegasus->ctrl_urb->transfer_buffer_length = size;
FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
usb_sndctrlpipe(pegasus->usb,0),
(char *)&pegasus->dr,
buffer, size, ctrl_callback, pegasus );
add_wait_queue( &pegasus->ctrl_wait, &wait );
set_current_state( TASK_UNINTERRUPTIBLE );
FILL_CONTROL_URB(pegasus->ctrl_urb, pegasus->usb,
usb_sndctrlpipe(pegasus->usb, 0),
(char *) &pegasus->dr,
buffer, size, ctrl_callback, pegasus);
if ( (ret = usb_submit_urb( pegasus->ctrl_urb, GFP_ATOMIC )) ) {
add_wait_queue(&pegasus->ctrl_wait, &wait);
set_current_state(TASK_UNINTERRUPTIBLE);
if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) {
err("%s: BAD CTRL %d", __FUNCTION__, ret);
goto out;
}
schedule();
out:
remove_wait_queue( &pegasus->ctrl_wait, &wait );
remove_wait_queue(&pegasus->ctrl_wait, &wait);
kfree(buffer);
return ret;
}
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 dat = data;
DECLARE_WAITQUEUE(wait, current);
buffer = kmalloc(1, GFP_KERNEL);
if (!buffer) {
err("unable to allocate memory for configuration descriptors");
......@@ -246,129 +242,126 @@ static int set_register( pegasus_t *pegasus, __u16 indx, __u8 data )
add_wait_queue(&pegasus->ctrl_wait, &wait);
set_current_state(TASK_UNINTERRUPTIBLE);
while ( pegasus->flags & ETH_REGS_CHANGED )
while (pegasus->flags & ETH_REGS_CHANGED)
schedule();
remove_wait_queue(&pegasus->ctrl_wait, &wait);
set_current_state(TASK_RUNNING);
pegasus->dr.bRequestType = PEGASUS_REQT_WRITE;
pegasus->dr.bRequest = PEGASUS_REQ_SET_REG;
pegasus->dr.wValue = cpu_to_le16p( &dat);
pegasus->dr.wIndex = cpu_to_le16p( &indx );
pegasus->dr.wLength = cpu_to_le16( 1 );
pegasus->dr.wValue = cpu_to_le16p(&dat);
pegasus->dr.wIndex = cpu_to_le16p(&indx);
pegasus->dr.wLength = cpu_to_le16(1);
pegasus->ctrl_urb->transfer_buffer_length = 1;
FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
usb_sndctrlpipe(pegasus->usb,0),
(char *)&pegasus->dr,
buffer, 1, ctrl_callback, pegasus );
FILL_CONTROL_URB(pegasus->ctrl_urb, pegasus->usb,
usb_sndctrlpipe(pegasus->usb, 0),
(char *) &pegasus->dr,
buffer, 1, ctrl_callback, pegasus);
add_wait_queue( &pegasus->ctrl_wait, &wait );
set_current_state( TASK_UNINTERRUPTIBLE );
add_wait_queue(&pegasus->ctrl_wait, &wait);
set_current_state(TASK_UNINTERRUPTIBLE);
if ( (ret = usb_submit_urb( pegasus->ctrl_urb, GFP_ATOMIC )) ) {
if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) {
err("%s: BAD CTRL %d", __FUNCTION__, ret);
goto out;
}
schedule();
out:
remove_wait_queue( &pegasus->ctrl_wait, &wait );
remove_wait_queue(&pegasus->ctrl_wait, &wait);
kfree(buffer);
return ret;
}
static int update_eth_regs_async( pegasus_t *pegasus )
static int update_eth_regs_async(pegasus_t * pegasus)
{
int ret;
int ret;
pegasus->dr.bRequestType = PEGASUS_REQT_WRITE;
pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS;
pegasus->dr.wValue = 0;
pegasus->dr.wIndex = cpu_to_le16(EthCtrl0);
pegasus->dr.wIndex = cpu_to_le16(EthCtrl0);
pegasus->dr.wLength = cpu_to_le16(3);
pegasus->ctrl_urb->transfer_buffer_length = 3;
FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
usb_sndctrlpipe(pegasus->usb,0),
(char *)&pegasus->dr,
pegasus->eth_regs, 3, ctrl_callback, pegasus );
FILL_CONTROL_URB(pegasus->ctrl_urb, pegasus->usb,
usb_sndctrlpipe(pegasus->usb, 0),
(char *) &pegasus->dr,
pegasus->eth_regs, 3, ctrl_callback, pegasus);
if ( (ret = usb_submit_urb( pegasus->ctrl_urb, GFP_ATOMIC )) )
err("%s: BAD CTRL %d, flgs %x",__FUNCTION__,ret,pegasus->flags);
if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC)))
err("%s: BAD CTRL %d, flgs %x", __FUNCTION__, ret,
pegasus->flags);
return ret;
return ret;
}
static int read_mii_word( pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd )
static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd)
{
int i;
__u8 data[4] = { phy, 0, 0, indx };
__u16 regdi;
set_register( pegasus, PhyCtrl, 0 );
set_registers( pegasus, PhyAddr, sizeof(data), data );
set_register( pegasus, PhyCtrl, (indx | PHY_READ) );
int i;
__u8 data[4] = { phy, 0, 0, indx };
__u16 regdi;
set_register(pegasus, PhyCtrl, 0);
set_registers(pegasus, PhyAddr, sizeof(data), data);
set_register(pegasus, PhyCtrl, (indx | PHY_READ));
for (i = 0; i < REG_TIMEOUT; i++) {
get_registers(pegasus, PhyCtrl, 1, data);
if ( data[0] & PHY_DONE )
if (data[0] & PHY_DONE)
break;
}
if ( i < REG_TIMEOUT ) {
get_registers( pegasus, PhyData, 2, &regdi );
if (i < REG_TIMEOUT) {
get_registers(pegasus, PhyData, 2, &regdi);
*regd = le16_to_cpu(regdi);
return 0;
return 0;
}
warn("%s: failed", __FUNCTION__);
return 1;
}
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;
__u8 data[4] = { phy, 0, 0, indx };
*(data + 1) = cpu_to_le16p( &regd );
set_register( pegasus, PhyCtrl, 0 );
set_registers( pegasus, PhyAddr, 4, data );
set_register( pegasus, PhyCtrl, (indx | PHY_WRITE) );
int i;
__u8 data[4] = { phy, 0, 0, indx };
*(data + 1) = cpu_to_le16p(&regd);
set_register(pegasus, PhyCtrl, 0);
set_registers(pegasus, PhyAddr, 4, data);
set_register(pegasus, PhyCtrl, (indx | PHY_WRITE));
for (i = 0; i < REG_TIMEOUT; i++) {
get_registers(pegasus, PhyCtrl, 1, data);
if ( data[0] & PHY_DONE )
if (data[0] & PHY_DONE)
break;
}
if ( i < REG_TIMEOUT )
return 0;
if (i < REG_TIMEOUT)
return 0;
warn("%s: failed", __FUNCTION__);
return 1;
}
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;
__u8 tmp;
__u16 retdatai;
set_register( pegasus, EpromCtrl, 0 );
set_register( pegasus, EpromOffset, index );
set_register( pegasus, EpromCtrl, EPROM_READ);
for ( i=0; i < REG_TIMEOUT; i++ ) {
get_registers( pegasus, EpromCtrl, 1, &tmp );
if ( tmp & EPROM_DONE )
set_register(pegasus, EpromCtrl, 0);
set_register(pegasus, EpromOffset, index);
set_register(pegasus, EpromCtrl, EPROM_READ);
for (i = 0; i < REG_TIMEOUT; i++) {
get_registers(pegasus, EpromCtrl, 1, &tmp);
if (tmp & EPROM_DONE)
break;
}
if ( i < REG_TIMEOUT ) {
get_registers( pegasus, EpromData, 2, &retdatai );
*retdata = le16_to_cpu (retdatai);
return 0;
if (i < REG_TIMEOUT) {
get_registers(pegasus, EpromData, 2, &retdatai);
*retdata = le16_to_cpu(retdatai);
return 0;
}
warn("%s: failed", __FUNCTION__);
......@@ -376,355 +369,372 @@ static int read_eprom_word( pegasus_t *pegasus, __u8 index, __u16 *retdata )
}
#ifdef PEGASUS_WRITE_EEPROM
static inline void enable_eprom_write( pegasus_t *pegasus )
static inline void enable_eprom_write(pegasus_t * pegasus)
{
__u8 tmp;
__u8 tmp;
get_registers( pegasus, EthCtrl2, 1, &tmp );
set_register( pegasus, EthCtrl2, tmp | EPROM_WR_ENABLE );
get_registers(pegasus, EthCtrl2, 1, &tmp);
set_register(pegasus, EthCtrl2, tmp | EPROM_WR_ENABLE);
}
static inline void disable_eprom_write( pegasus_t *pegasus )
static inline void disable_eprom_write(pegasus_t * pegasus)
{
__u8 tmp;
__u8 tmp;
get_registers( pegasus, EthCtrl2, 1, &tmp );
set_register( pegasus, EpromCtrl, 0 );
set_register( pegasus, EthCtrl2, tmp & ~EPROM_WR_ENABLE );
get_registers(pegasus, EthCtrl2, 1, &tmp);
set_register(pegasus, EpromCtrl, 0);
set_register(pegasus, EthCtrl2, tmp & ~EPROM_WR_ENABLE);
}
static int write_eprom_word( pegasus_t *pegasus, __u8 index, __u16 data )
static int write_eprom_word(pegasus_t * pegasus, __u8 index, __u16 data)
{
int i, tmp;
__u8 d[4] = {0x3f, 0, 0, EPROM_WRITE};
set_registers( pegasus, EpromOffset, 4, d );
enable_eprom_write( pegasus );
set_register( pegasus, EpromOffset, index );
set_registers( pegasus, EpromData, 2, &data );
set_register( pegasus, EpromCtrl, EPROM_WRITE );
for ( i=0; i < REG_TIMEOUT; i++ ) {
get_registers( pegasus, EpromCtrl, 1, &tmp );
if ( tmp & EPROM_DONE )
int i, tmp;
__u8 d[4] = { 0x3f, 0, 0, EPROM_WRITE };
set_registers(pegasus, EpromOffset, 4, d);
enable_eprom_write(pegasus);
set_register(pegasus, EpromOffset, index);
set_registers(pegasus, EpromData, 2, &data);
set_register(pegasus, EpromCtrl, EPROM_WRITE);
for (i = 0; i < REG_TIMEOUT; i++) {
get_registers(pegasus, EpromCtrl, 1, &tmp);
if (tmp & EPROM_DONE)
break;
}
disable_eprom_write( pegasus );
if ( i < REG_TIMEOUT )
return 0;
disable_eprom_write(pegasus);
if (i < REG_TIMEOUT)
return 0;
warn("%s: failed", __FUNCTION__);
return -1;
return -1;
}
#endif /* PEGASUS_WRITE_EEPROM */
#endif /* PEGASUS_WRITE_EEPROM */
static inline void get_node_id( pegasus_t *pegasus, __u8 *id )
static inline void get_node_id(pegasus_t * pegasus, __u8 * id)
{
int i;
int i;
__u16 w16;
for (i = 0; i < 3; i++) {
read_eprom_word( pegasus, i, &w16);
((__u16 *) id)[i] = cpu_to_le16p (&w16);
read_eprom_word(pegasus, i, &w16);
((__u16 *) id)[i] = cpu_to_le16p(&w16);
}
}
static void set_ethernet_addr( pegasus_t *pegasus )
static void set_ethernet_addr(pegasus_t * pegasus)
{
__u8 node_id[6];
__u8 node_id[6];
get_node_id(pegasus, node_id);
set_registers( pegasus, EthID, sizeof(node_id), node_id );
memcpy( pegasus->net->dev_addr, node_id, sizeof(node_id) );
set_registers(pegasus, EthID, sizeof(node_id), 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)
{
__u8 data = 0x8;
int i;
__u8 data = 0x8;
int i;
set_register(pegasus, EthCtrl1, data);
for (i = 0; i < REG_TIMEOUT; i++) {
get_registers(pegasus, EthCtrl1, 1, &data);
if (~data & 0x08) {
if (loopback & 1)
if (loopback & 1)
break;
if ( mii_mode && (pegasus->features & HAS_HOME_PNA) )
set_register( pegasus, Gpio1, 0x34 );
if (mii_mode && (pegasus->features & HAS_HOME_PNA))
set_register(pegasus, Gpio1, 0x34);
else
set_register( pegasus, Gpio1, 0x26 );
set_register( pegasus, Gpio0, pegasus->features );
set_register( pegasus, Gpio0, DEFAULT_GPIO_SET );
set_register(pegasus, Gpio1, 0x26);
set_register(pegasus, Gpio0, pegasus->features);
set_register(pegasus, Gpio0, DEFAULT_GPIO_SET);
break;
}
}
if ( i == REG_TIMEOUT )
if (i == REG_TIMEOUT)
return 1;
if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) {
__u16 auxmode;
read_mii_word(pegasus, 1, MII_TPISTATUS, &auxmode);
write_mii_word(pegasus, 1, MII_TPISTATUS, auxmode | 4);
set_register(pegasus, Gpio0, 0x24);
set_register(pegasus, Gpio0, 0x26);
}
if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_ELCON) {
__u16 auxmode;
__u16 auxmode;
read_mii_word(pegasus, 3, 0x1b, &auxmode);
write_mii_word(pegasus, 3, 0x1b, auxmode | 4);
}
return 0;
return 0;
}
static int enable_net_traffic( struct net_device *dev, struct usb_device *usb )
static int enable_net_traffic(struct net_device *dev, struct usb_device *usb)
{
__u16 linkpart, bmsr;
__u8 data[4];
__u16 linkpart, bmsr;
__u8 data[4];
pegasus_t *pegasus = dev->priv;
read_mii_word(pegasus, pegasus->phy, MII_BMSR, &bmsr);
read_mii_word(pegasus, pegasus->phy, MII_BMSR, &bmsr);
if ( !(bmsr & 4) && !loopback )
warn( "%s: link NOT established (%04x) - check the cable.",
dev->name, bmsr );
if ( read_mii_word(pegasus, pegasus->phy, MII_LPA, &linkpart) )
if (!(bmsr & BMSR_LSTATUS) && !loopback)
warn("%s: link NOT established (%04x) - check the cable.",
dev->name, bmsr);
if (read_mii_word(pegasus, pegasus->phy, MII_LPA, &linkpart))
return 2;
if ( !(linkpart & 1) )
warn( "link partner stat %x", linkpart );
if (!(linkpart & 1))
warn("link partner stat %x", linkpart);
data[0] = 0xc9;
data[1] = 0;
if ( linkpart & (ADVERTISE_100FULL | ADVERTISE_10FULL) )
data[1] |= 0x20; /* set full duplex */
if ( linkpart & (ADVERTISE_100FULL | ADVERTISE_100HALF) )
data[1] |= 0x10; /* set 100 Mbps */
if ( mii_mode )
if (linkpart & (ADVERTISE_100FULL | ADVERTISE_10FULL))
data[1] |= 0x20; /* set full duplex */
if (linkpart & (ADVERTISE_100FULL | ADVERTISE_100HALF))
data[1] |= 0x10; /* set 100 Mbps */
if (mii_mode)
data[1] = 0;
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 ||
usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) {
u16 auxmode;
read_mii_word(pegasus, 0, 0x1b, &auxmode);
write_mii_word(pegasus, 0, 0x1b, auxmode | 4);
}
return 0;
}
static void read_bulk_callback( struct urb *urb )
static void read_bulk_callback(struct urb *urb)
{
pegasus_t *pegasus = urb->context;
struct net_device *net;
int count = urb->actual_length, res;
int count = urb->actual_length;
int rx_status;
struct sk_buff *skb;
struct sk_buff *skb;
__u16 pkt_len;
if ( !pegasus || !(pegasus->flags & PEGASUS_RUNNING) )
if (!pegasus || !(pegasus->flags & PEGASUS_RUNNING))
return;
net = pegasus->net;
if ( !netif_device_present(net) )
if (!netif_device_present(net))
return;
if ( pegasus->flags & PEGASUS_RX_BUSY ) {
pegasus->stats.rx_errors++;
dbg("pegasus Rx busy");
return;
}
pegasus->flags |= PEGASUS_RX_BUSY;
switch ( urb->status ) {
case 0:
break;
case -ETIMEDOUT:
dbg( "reset MAC" );
pegasus->flags &= ~PEGASUS_RX_BUSY;
break;
default:
dbg( "%s: RX status %d", net->name, urb->status );
goto goon;
switch (urb->status) {
case 0:
break;
case -ETIMEDOUT:
dbg("reset MAC");
pegasus->flags &= ~PEGASUS_RX_BUSY;
break;
default:
dbg("%s: RX status %d", net->name, urb->status);
goto goon;
}
if ( !count )
if (!count)
goto goon;
rx_status = le32_to_cpu(*(int *)(pegasus->rx_buff + count - 4));
if ( rx_status & 0x000e0000 ) {
rx_status = le32_to_cpu(*(int *)(urb->transfer_buffer + count - 4));
if (rx_status & 0x000e0000) {
dbg("%s: RX packet error %x", net->name, rx_status & 0xe0000);
pegasus->stats.rx_errors++;
if ( rx_status & 0x060000 )
if (rx_status & 0x060000)
pegasus->stats.rx_length_errors++;
if ( rx_status & 0x080000 )
if (rx_status & 0x080000)
pegasus->stats.rx_crc_errors++;
if ( rx_status & 0x100000 )
if (rx_status & 0x100000)
pegasus->stats.rx_frame_errors++;
goto goon;
}
pkt_len = (rx_status & 0xfff) - 8;
if ( !(skb = dev_alloc_skb(pkt_len+2)) )
goto goon;
tasklet_schedule(&pegasus->rx_tl);
if (!pegasus->rx_skb)
return;
skb_put(pegasus->rx_skb, pkt_len);
pegasus->rx_skb->protocol = eth_type_trans(pegasus->rx_skb, net);
netif_rx(pegasus->rx_skb);
if (!(skb = dev_alloc_skb(PEGASUS_MTU + 2))) {
pegasus->rx_skb = NULL;
return;
}
skb->dev = net;
skb_reserve(skb, 2);
eth_copy_and_sum(skb, pegasus->rx_buff, pkt_len, 0);
skb_put(skb, pkt_len);
skb->protocol = eth_type_trans(skb, net);
netif_rx(skb);
pegasus->rx_skb = skb;
pegasus->stats.rx_packets++;
pegasus->stats.rx_bytes += pkt_len;
goon:
FILL_BULK_URB( pegasus->rx_urb, pegasus->usb,
usb_rcvbulkpipe(pegasus->usb, 1),
pegasus->rx_buff, PEGASUS_MAX_MTU,
read_bulk_callback, pegasus );
if ( (res = usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC)) )
warn("%s: failed submint rx_urb %d", __FUNCTION__, res);
pegasus->flags &= ~PEGASUS_RX_BUSY;
FILL_BULK_URB(pegasus->rx_urb, pegasus->usb,
usb_rcvbulkpipe(pegasus->usb, 1),
pegasus->rx_skb->data, PEGASUS_MTU + 8,
read_bulk_callback, pegasus);
if (usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC))
pegasus->flags |= PEGASUS_RX_URB_FAIL;
else
pegasus->flags &= ~PEGASUS_RX_URB_FAIL;
}
static void rx_fixup(unsigned long data)
{
pegasus_t *pegasus;
static void write_bulk_callback( struct urb *urb )
pegasus = (pegasus_t *)data;
if (pegasus->flags & PEGASUS_RX_URB_FAIL) {
goto try_again;
}
if (pegasus->rx_skb)
return;
if (!(pegasus->rx_skb = dev_alloc_skb(PEGASUS_MTU + 2))) {
tasklet_schedule(&pegasus->rx_tl);
return;
}
FILL_BULK_URB(pegasus->rx_urb, pegasus->usb,
usb_rcvbulkpipe(pegasus->usb, 1),
pegasus->rx_skb->data, PEGASUS_MTU + 8,
read_bulk_callback, pegasus);
try_again:
if (usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC)) {
pegasus->flags |= PEGASUS_RX_URB_FAIL;
tasklet_schedule(&pegasus->rx_tl);
} else {
pegasus->flags &= ~PEGASUS_RX_URB_FAIL;
}
}
static void write_bulk_callback(struct urb *urb)
{
pegasus_t *pegasus = urb->context;
if ( !pegasus || !(pegasus->flags & PEGASUS_RUNNING) )
if (!pegasus || !(pegasus->flags & PEGASUS_RUNNING))
return;
if ( !netif_device_present(pegasus->net) )
if (!netif_device_present(pegasus->net))
return;
if ( urb->status )
if (urb->status)
info("%s: TX status %d", pegasus->net->name, urb->status);
pegasus->net->trans_start = jiffies;
netif_wake_queue( pegasus->net );
netif_wake_queue(pegasus->net);
}
#ifdef PEGASUS_USE_INTR
static void intr_callback( struct urb *urb )
static void intr_callback(struct urb *urb)
{
pegasus_t *pegasus = urb->context;
struct net_device *net;
__u8 *d;
__u8 *d;
if ( !pegasus )
if (!pegasus)
return;
switch ( urb->status ) {
case 0:
break;
case -ENOENT:
return;
default:
info("intr status %d", urb->status);
switch (urb->status) {
case 0:
break;
case -ENOENT:
return;
default:
info("intr status %d", urb->status);
}
d = urb->transfer_buffer;
net = pegasus->net;
if ( d[0] & 0xfc ) {
if (d[0] & 0xfc) {
pegasus->stats.tx_errors++;
if ( d[0] & TX_UNDERRUN )
if (d[0] & TX_UNDERRUN)
pegasus->stats.tx_fifo_errors++;
if ( d[0] & (EXCESSIVE_COL | JABBER_TIMEOUT) )
if (d[0] & (EXCESSIVE_COL | JABBER_TIMEOUT))
pegasus->stats.tx_aborted_errors++;
if ( d[0] & LATE_COL )
if (d[0] & LATE_COL)
pegasus->stats.tx_window_errors++;
if ( d[0] & (NO_CARRIER | LOSS_CARRIER) )
if (d[0] & (NO_CARRIER | LOSS_CARRIER))
pegasus->stats.tx_carrier_errors++;
}
}
#endif
static void pegasus_tx_timeout( struct net_device *net )
static void pegasus_tx_timeout(struct net_device *net)
{
pegasus_t *pegasus = net->priv;
if ( !pegasus )
if (!pegasus)
return;
warn("%s: Tx timed out.", net->name);
pegasus->tx_urb->transfer_flags |= USB_ASYNC_UNLINK;
usb_unlink_urb( pegasus->tx_urb );
usb_unlink_urb(pegasus->tx_urb);
pegasus->stats.tx_errors++;
}
static int pegasus_start_xmit( struct sk_buff *skb, struct net_device *net )
static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net)
{
pegasus_t *pegasus = net->priv;
int count = ((skb->len+2) & 0x3f) ? skb->len+2 : skb->len+3;
int res;
pegasus_t *pegasus = net->priv;
int count = ((skb->len + 2) & 0x3f) ? skb->len + 2 : skb->len + 3;
int res;
__u16 l16 = skb->len;
netif_stop_queue( net );
((__u16 *)pegasus->tx_buff)[0] = cpu_to_le16( l16 );
memcpy(pegasus->tx_buff+2, skb->data, skb->len);
FILL_BULK_URB( pegasus->tx_urb, pegasus->usb,
usb_sndbulkpipe(pegasus->usb, 2),
pegasus->tx_buff, PEGASUS_MAX_MTU,
write_bulk_callback, pegasus );
pegasus->tx_urb->transfer_buffer_length = count;
netif_stop_queue(net);
((__u16 *) pegasus->tx_buff)[0] = cpu_to_le16(l16);
memcpy(pegasus->tx_buff + 2, skb->data, skb->len);
FILL_BULK_URB(pegasus->tx_urb, pegasus->usb,
usb_sndbulkpipe(pegasus->usb, 2),
pegasus->tx_buff, count,
write_bulk_callback, pegasus);
if ((res = usb_submit_urb(pegasus->tx_urb, GFP_ATOMIC))) {
warn("failed tx_urb %d", res);
pegasus->stats.tx_errors++;
netif_start_queue( net );
netif_start_queue(net);
} else {
pegasus->stats.tx_packets++;
pegasus->stats.tx_bytes += skb->len;
net->trans_start = jiffies;
}
dev_kfree_skb(skb);
return 0;
}
static struct net_device_stats *pegasus_netdev_stats( struct net_device *dev )
static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev)
{
return &((pegasus_t *)dev->priv)->stats;
return &((pegasus_t *) dev->priv)->stats;
}
static inline void disable_net_traffic( pegasus_t *pegasus )
static inline void disable_net_traffic(pegasus_t * pegasus)
{
int tmp=0;
int tmp = 0;
set_registers( pegasus, EthCtrl0, 2, &tmp );
set_registers(pegasus, EthCtrl0, 2, &tmp);
}
static inline void get_interrupt_interval( pegasus_t *pegasus )
static inline void get_interrupt_interval(pegasus_t * pegasus)
{
__u8 data[2];
__u8 data[2];
read_eprom_word( pegasus, 4, (__u16 *)data );
if ( data[1] < 0x80 ) {
info( "intr interval will be changed from %ums to %ums",
data[1], 0x80 );
read_eprom_word(pegasus, 4, (__u16 *) data);
if (data[1] < 0x80) {
info("intr interval will be changed from %ums to %ums",
data[1], 0x80);
data[1] = 0x80;
#ifdef PEGASUS_WRITE_EEPROM
write_eprom_word( pegasus, 4, *(__u16 *)data );
write_eprom_word(pegasus, 4, *(__u16 *) data);
#endif
}
pegasus->intr_interval = data[1];
}
static void set_carrier(struct net_device *net)
{
pegasus_t *pegasus;
short tmp;
pegasus_t *pegasus;
short tmp;
pegasus = net->priv;
read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp);
......@@ -732,33 +742,37 @@ static void set_carrier(struct net_device *net)
netif_carrier_on(net);
else
netif_carrier_off(net);
}
}
static int pegasus_open(struct net_device *net)
{
pegasus_t *pegasus = (pegasus_t *)net->priv;
int res;
pegasus_t *pegasus = (pegasus_t *) net->priv;
int res;
if (!(pegasus->rx_skb = dev_alloc_skb(PEGASUS_MTU + 2)))
return -ENOMEM;
pegasus->rx_skb->dev = net;
skb_reserve(pegasus->rx_skb, 2);
down(&pegasus->sem);
FILL_BULK_URB( pegasus->rx_urb, pegasus->usb,
usb_rcvbulkpipe(pegasus->usb, 1),
pegasus->rx_buff, PEGASUS_MAX_MTU,
read_bulk_callback, pegasus );
if ( (res = usb_submit_urb(pegasus->rx_urb, GFP_KERNEL)) )
FILL_BULK_URB(pegasus->rx_urb, pegasus->usb,
usb_rcvbulkpipe(pegasus->usb, 1),
pegasus->rx_skb->data, PEGASUS_MTU + 8,
read_bulk_callback, pegasus);
if ((res = usb_submit_urb(pegasus->rx_urb, GFP_KERNEL)))
warn("%s: failed rx_urb %d", __FUNCTION__, res);
#ifdef PEGASUS_USE_INTR
FILL_INT_URB( pegasus->intr_urb, pegasus->usb,
usb_rcvintpipe(pegasus->usb, 3),
pegasus->intr_buff, sizeof(pegasus->intr_buff),
intr_callback, pegasus, pegasus->intr_interval );
if ( (res = usb_submit_urb(pegasus->intr_urb, GFP_KERNEL)) )
FILL_INT_URB(pegasus->intr_urb, pegasus->usb,
usb_rcvintpipe(pegasus->usb, 3),
pegasus->intr_buff, sizeof(pegasus->intr_buff),
intr_callback, pegasus, pegasus->intr_interval);
if ((res = usb_submit_urb(pegasus->intr_urb, GFP_KERNEL)))
warn("%s: failed intr_urb %d", __FUNCTION__, res);
#endif
netif_start_queue( net );
netif_start_queue(net);
pegasus->flags |= PEGASUS_RUNNING;
if ( (res = enable_net_traffic(net, pegasus->usb)) ) {
if ((res = enable_net_traffic(net, pegasus->usb))) {
err("can't enable_net_traffic() - %d", res);
res = -EIO;
goto exit;
......@@ -771,125 +785,122 @@ static int pegasus_open(struct net_device *net)
return res;
}
static int pegasus_close( struct net_device *net )
static int pegasus_close(struct net_device *net)
{
pegasus_t *pegasus = net->priv;
pegasus_t *pegasus = net->priv;
down(&pegasus->sem);
pegasus->flags &= ~PEGASUS_RUNNING;
netif_stop_queue( net );
if ( !(pegasus->flags & PEGASUS_UNPLUG) )
disable_net_traffic( pegasus );
netif_stop_queue(net);
if (!(pegasus->flags & PEGASUS_UNPLUG))
disable_net_traffic(pegasus);
usb_unlink_urb( pegasus->rx_urb );
usb_unlink_urb( pegasus->tx_urb );
usb_unlink_urb( pegasus->ctrl_urb );
usb_unlink_urb(pegasus->rx_urb);
usb_unlink_urb(pegasus->tx_urb);
usb_unlink_urb(pegasus->ctrl_urb);
#ifdef PEGASUS_USE_INTR
usb_unlink_urb( pegasus->intr_urb );
usb_unlink_urb(pegasus->intr_urb);
#endif
up(&pegasus->sem);
return 0;
}
static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr)
{
pegasus_t *pegasus;
int cmd;
char tmp[128];
pegasus_t *pegasus;
int cmd;
char tmp[128];
pegasus = net->priv;
if (get_user(cmd, (int *)uaddr))
if (get_user(cmd, (int *) uaddr))
return -EFAULT;
switch (cmd) {
case ETHTOOL_GDRVINFO: {
struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
strncpy(info.driver, DRIVER_DESC, ETHTOOL_BUSINFO_LEN);
strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
sprintf(tmp, "usb%d:%d", pegasus->usb->bus->busnum,
pegasus->usb->devnum);
strncpy(info.bus_info, tmp, ETHTOOL_BUSINFO_LEN);
if (copy_to_user(uaddr, &info, sizeof(info)))
return -EFAULT;
return 0;
}
case ETHTOOL_GSET: {
struct ethtool_cmd ecmd;
short lpa, bmcr;
if (copy_from_user(&ecmd, uaddr, sizeof(ecmd)))
return -EFAULT;
ecmd.supported = (SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_Autoneg |
SUPPORTED_TP |
SUPPORTED_MII);
ecmd.port = PORT_TP;
ecmd.transceiver = XCVR_INTERNAL;
ecmd.phy_address = pegasus->phy;
read_mii_word(pegasus, pegasus->phy, MII_BMCR, &bmcr);
read_mii_word(pegasus, pegasus->phy, MII_LPA, &lpa);
if (bmcr & BMCR_ANENABLE) {
ecmd.autoneg = AUTONEG_ENABLE;
ecmd.speed = lpa & (LPA_100HALF|LPA_100FULL) ?
SPEED_100 : SPEED_10;
if (ecmd.speed == SPEED_100)
ecmd.duplex = lpa & LPA_100FULL ?
DUPLEX_FULL : DUPLEX_HALF;
else
ecmd.duplex = lpa & LPA_10FULL ?
DUPLEX_FULL : DUPLEX_HALF;
} else {
ecmd.autoneg = AUTONEG_DISABLE;
ecmd.speed = bmcr & BMCR_SPEED100 ?
SPEED_100 : SPEED_10;
ecmd.duplex = bmcr & BMCR_FULLDPLX ?
DUPLEX_FULL : DUPLEX_HALF;
case ETHTOOL_GDRVINFO:{
struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
strncpy(info.driver, DRIVER_DESC, ETHTOOL_BUSINFO_LEN);
strncpy(info.version, DRIVER_VERSION,
ETHTOOL_BUSINFO_LEN);
sprintf(tmp, "usb%d:%d", pegasus->usb->bus->busnum,
pegasus->usb->devnum);
strncpy(info.bus_info, tmp, ETHTOOL_BUSINFO_LEN);
if (copy_to_user(uaddr, &info, sizeof(info)))
return -EFAULT;
return 0;
}
case ETHTOOL_GSET:{
struct ethtool_cmd ecmd;
short lpa, bmcr;
if (copy_from_user(&ecmd, uaddr, sizeof(ecmd)))
return -EFAULT;
ecmd.supported = (SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_Autoneg |
SUPPORTED_TP | SUPPORTED_MII);
ecmd.port = PORT_TP;
ecmd.transceiver = XCVR_INTERNAL;
ecmd.phy_address = pegasus->phy;
read_mii_word(pegasus, pegasus->phy, MII_BMCR, &bmcr);
read_mii_word(pegasus, pegasus->phy, MII_LPA, &lpa);
if (bmcr & BMCR_ANENABLE) {
ecmd.autoneg = AUTONEG_ENABLE;
ecmd.speed = lpa & (LPA_100HALF | LPA_100FULL) ?
SPEED_100 : SPEED_10;
if (ecmd.speed == SPEED_100)
ecmd.duplex = lpa & LPA_100FULL ?
DUPLEX_FULL : DUPLEX_HALF;
else
ecmd.duplex = lpa & LPA_10FULL ?
DUPLEX_FULL : DUPLEX_HALF;
} else {
ecmd.autoneg = AUTONEG_DISABLE;
ecmd.speed = bmcr & BMCR_SPEED100 ?
SPEED_100 : SPEED_10;
ecmd.duplex = bmcr & BMCR_FULLDPLX ?
DUPLEX_FULL : DUPLEX_HALF;
}
if (copy_to_user(uaddr, &ecmd, sizeof(ecmd)))
return -EFAULT;
return 0;
}
case ETHTOOL_SSET:{
return -EOPNOTSUPP;
}
case ETHTOOL_GLINK:{
struct ethtool_value edata = { ETHTOOL_GLINK };
edata.data = netif_carrier_ok(net);
if (copy_to_user(uaddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
if (copy_to_user(uaddr, &ecmd, sizeof(ecmd)))
return -EFAULT;
return 0;
}
case ETHTOOL_SSET: {
return -EOPNOTSUPP;
}
case ETHTOOL_GLINK: {
struct ethtool_value edata = {ETHTOOL_GLINK};
edata.data = netif_carrier_ok(net);
if (copy_to_user(uaddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
default:
return -EOPNOTSUPP;
}
}
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;
pegasus_t *pegasus = net->priv;
int res;
__u16 *data = (__u16 *) & rq->ifr_data;
pegasus_t *pegasus = net->priv;
int res;
down(&pegasus->sem);
switch(cmd) {
switch (cmd) {
case SIOCETHTOOL:
res = pegasus_ethtool_ioctl(net, rq->ifr_data);
break;
case SIOCDEVPRIVATE:
data[0] = pegasus->phy;
case SIOCDEVPRIVATE+1:
read_mii_word(pegasus, data[0], data[1]&0x1f, &data[3]);
case SIOCDEVPRIVATE + 1:
read_mii_word(pegasus, data[0], data[1] & 0x1f, &data[3]);
res = 0;
break;
case SIOCDEVPRIVATE+2:
if ( !capable(CAP_NET_ADMIN) ) {
case SIOCDEVPRIVATE + 2:
if (!capable(CAP_NET_ADMIN)) {
up(&pegasus->sem);
return -EPERM;
}
......@@ -903,8 +914,7 @@ static int pegasus_ioctl( struct net_device *net, struct ifreq *rq, int cmd )
return res;
}
static void pegasus_set_multicast( struct net_device *net )
static void pegasus_set_multicast(struct net_device *net)
{
pegasus_t *pegasus = net->priv;
......@@ -914,7 +924,7 @@ static void pegasus_set_multicast( struct net_device *net )
pegasus->eth_regs[EthCtrl2] |= RX_PROMISCUOUS;
info("%s: Promiscuous mode enabled", net->name);
} else if ((net->mc_count > multicast_filter_limit) ||
(net->flags & IFF_ALLMULTI)) {
(net->flags & IFF_ALLMULTI)) {
pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST;
pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;
info("%s set allmulti", net->name);
......@@ -924,98 +934,97 @@ static void pegasus_set_multicast( struct net_device *net )
}
pegasus->flags |= ETH_REGS_CHANGE;
ctrl_callback( pegasus->ctrl_urb );
ctrl_callback(pegasus->ctrl_urb);
netif_wake_queue(net);
}
static __u8 mii_phy_probe( pegasus_t *pegasus )
static __u8 mii_phy_probe(pegasus_t * pegasus)
{
int i;
__u16 tmp;
int i;
__u16 tmp;
for ( i=0; i < 32; i++ ) {
read_mii_word( pegasus, i, MII_BMSR, &tmp );
if ( tmp == 0 || tmp == 0xffff || (tmp & BMSR_MEDIA) == 0 )
for (i = 0; i < 32; i++) {
read_mii_word(pegasus, i, MII_BMSR, &tmp);
if (tmp == 0 || tmp == 0xffff || (tmp & BMSR_MEDIA) == 0)
continue;
else
return i;
return i;
}
return 0xff;
return 0xff;
}
static inline void setup_pegasus_II( pegasus_t *pegasus )
static inline void setup_pegasus_II(pegasus_t * pegasus)
{
set_register( pegasus, Reg1d, 0 );
set_register( pegasus, Reg7b, 2 );
if ( pegasus->features & HAS_HOME_PNA && mii_mode )
set_register( pegasus, Reg81, 6 );
set_register(pegasus, Reg1d, 0);
set_register(pegasus, Reg7b, 2);
if (pegasus->features & HAS_HOME_PNA && mii_mode)
set_register(pegasus, Reg81, 6);
else
set_register( pegasus, Reg81, 2 );
set_register(pegasus, Reg81, 2);
}
static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id)
static void *pegasus_probe(struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id)
{
struct net_device *net;
pegasus_t *pegasus;
int dev_index = id - pegasus_ids;
struct net_device *net;
pegasus_t *pegasus;
int dev_index = id - pegasus_ids;
if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
err("usb_set_configuration() failed");
return NULL;
}
if(!(pegasus = kmalloc(sizeof(struct pegasus), GFP_KERNEL))) {
if (!(pegasus = kmalloc(sizeof(struct pegasus), GFP_KERNEL))) {
err("out of memory allocating device structure");
return NULL;
}
usb_inc_dev_use( dev );
usb_inc_dev_use(dev);
memset(pegasus, 0, sizeof(struct pegasus));
pegasus->dev_index = dev_index;
init_waitqueue_head( &pegasus->ctrl_wait );
init_waitqueue_head(&pegasus->ctrl_wait);
pegasus->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!pegasus->ctrl_urb) {
kfree (pegasus);
kfree(pegasus);
return NULL;
}
pegasus->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!pegasus->rx_urb) {
usb_free_urb (pegasus->ctrl_urb);
kfree (pegasus);
usb_free_urb(pegasus->ctrl_urb);
kfree(pegasus);
return NULL;
}
pegasus->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!pegasus->tx_urb) {
usb_free_urb (pegasus->rx_urb);
usb_free_urb (pegasus->ctrl_urb);
kfree (pegasus);
usb_free_urb(pegasus->rx_urb);
usb_free_urb(pegasus->ctrl_urb);
kfree(pegasus);
return NULL;
}
pegasus->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!pegasus->intr_urb) {
usb_free_urb (pegasus->tx_urb);
usb_free_urb (pegasus->rx_urb);
usb_free_urb (pegasus->ctrl_urb);
kfree (pegasus);
usb_free_urb(pegasus->tx_urb);
usb_free_urb(pegasus->rx_urb);
usb_free_urb(pegasus->ctrl_urb);
kfree(pegasus);
return NULL;
}
net = init_etherdev( NULL, 0 );
if ( !net ) {
usb_free_urb (pegasus->tx_urb);
usb_free_urb (pegasus->rx_urb);
usb_free_urb (pegasus->ctrl_urb);
kfree( pegasus );
net = init_etherdev(NULL, 0);
if (!net) {
usb_free_urb(pegasus->tx_urb);
usb_free_urb(pegasus->rx_urb);
usb_free_urb(pegasus->ctrl_urb);
kfree(pegasus);
return NULL;
}
init_MUTEX(&pegasus->sem);
tasklet_init(&pegasus->rx_tl, rx_fixup, (unsigned long)pegasus);
down(&pegasus->sem);
pegasus->usb = dev;
pegasus->net = net;
......@@ -1033,32 +1042,32 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum,
pegasus->features = usb_dev_id[dev_index].private;
#ifdef PEGASUS_USE_INTR
get_interrupt_interval( pegasus );
get_interrupt_interval(pegasus);
#endif
if ( reset_mac(pegasus) ) {
if (reset_mac(pegasus)) {
err("can't reset MAC");
unregister_netdev( pegasus->net );
usb_free_urb (pegasus->tx_urb);
usb_free_urb (pegasus->rx_urb);
usb_free_urb (pegasus->ctrl_urb);
unregister_netdev(pegasus->net);
usb_free_urb(pegasus->tx_urb);
usb_free_urb(pegasus->rx_urb);
usb_free_urb(pegasus->ctrl_urb);
kfree(pegasus->net);
kfree(pegasus);
pegasus = NULL;
goto exit;
}
info( "%s: %s", net->name, usb_dev_id[dev_index].name );
info("%s: %s", net->name, usb_dev_id[dev_index].name);
set_ethernet_addr( pegasus );
set_ethernet_addr(pegasus);
if ( pegasus->features & PEGASUS_II ) {
info( "setup Pegasus II specific registers" );
setup_pegasus_II( pegasus );
if (pegasus->features & PEGASUS_II) {
info("setup Pegasus II specific registers");
setup_pegasus_II(pegasus);
}
pegasus->phy = mii_phy_probe( pegasus );
if ( pegasus->phy == 0xff ) {
warn( "can't locate MII phy, using default" );
pegasus->phy = mii_phy_probe(pegasus);
if (pegasus->phy == 0xff) {
warn("can't locate MII phy, using default");
pegasus->phy = 1;
}
exit:
......@@ -1066,19 +1075,18 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum,
return pegasus;
}
static void pegasus_disconnect( struct usb_device *dev, void *ptr )
static void pegasus_disconnect(struct usb_device *dev, void *ptr)
{
struct pegasus *pegasus = ptr;
if ( !pegasus ) {
if (!pegasus) {
warn("unregistering non-existant device");
return;
}
pegasus->flags |= PEGASUS_UNPLUG;
unregister_netdev( pegasus->net );
usb_dec_dev_use( dev );
unregister_netdev(pegasus->net);
usb_dec_dev_use(dev);
usb_unlink_urb(pegasus->intr_urb);
usb_unlink_urb(pegasus->tx_urb);
usb_unlink_urb(pegasus->rx_urb);
......@@ -1087,12 +1095,13 @@ static void pegasus_disconnect( struct usb_device *dev, void *ptr )
usb_free_urb(pegasus->tx_urb);
usb_free_urb(pegasus->rx_urb);
usb_free_urb(pegasus->ctrl_urb);
kfree( pegasus->net );
kfree( pegasus );
if (pegasus->rx_skb)
dev_kfree_skb(pegasus->rx_skb);
kfree(pegasus->net);
kfree(pegasus);
pegasus = NULL;
}
static struct usb_driver pegasus_driver = {
name: "pegasus",
probe: pegasus_probe,
......@@ -1103,13 +1112,13 @@ static struct usb_driver pegasus_driver = {
int __init pegasus_init(void)
{
info(DRIVER_VERSION ":" DRIVER_DESC);
return usb_register( &pegasus_driver );
return usb_register(&pegasus_driver);
}
void __exit pegasus_exit(void)
{
usb_deregister( &pegasus_driver );
usb_deregister(&pegasus_driver);
}
module_init( pegasus_init );
module_exit( pegasus_exit );
module_init(pegasus_init);
module_exit(pegasus_exit);
......@@ -22,8 +22,7 @@
#define PEGASUS_II 0x80000000
#define HAS_HOME_PNA 0x40000000
#define PEGASUS_MTU 1500
#define PEGASUS_MAX_MTU 1536
#define PEGASUS_MTU 1536
#define EPROM_WRITE 0x01
#define EPROM_READ 0x02
......@@ -45,6 +44,7 @@
#define CTRL_URB_RUNNING 0x00000010
#define CTRL_URB_SLEEP 0x00000020
#define PEGASUS_UNPLUG 0x00000040
#define PEGASUS_RX_URB_FAIL 0x00000080
#define ETH_REGS_CHANGE 0x40000000
#define ETH_REGS_CHANGED 0x80000000
......@@ -98,13 +98,14 @@ typedef struct pegasus {
unsigned features;
int dev_index;
int intr_interval;
struct tasklet_struct rx_tl;
struct urb *ctrl_urb, *rx_urb, *tx_urb, *intr_urb;
struct sk_buff *rx_skb;
struct usb_ctrlrequest dr;
wait_queue_head_t ctrl_wait;
struct semaphore sem;
unsigned char rx_buff[PEGASUS_MAX_MTU];
unsigned char tx_buff[PEGASUS_MAX_MTU];
unsigned char intr_buff[8];
__u8 tx_buff[PEGASUS_MTU];
__u8 eth_regs[4];
__u8 phy;
__u8 gpio_res;
......@@ -236,7 +237,7 @@ PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2204,
LINKSYS_GPIO_RESET | HAS_HOME_PNA )
PEGASUS_DEV( "Linksys USB Ethernet Adapter", VENDOR_LINKSYS, 0x2206,
LINKSYS_GPIO_RESET )
PEGASUS_DEV( "Linksys USB USB10TX", VENDOR_LINKSYS, 0x400b,
PEGASUS_DEV( "Linksys USB USB100TX", VENDOR_LINKSYS, 0x400b,
LINKSYS_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x200c,
LINKSYS_GPIO_RESET | PEGASUS_II )
......
......@@ -21,14 +21,11 @@
#include <linux/usb.h>
#include <asm/uaccess.h>
/* Version Information */
#define DRIVER_VERSION "v0.5.0 (2002/03/28)"
#define DRIVER_VERSION "v0.5.4 (2002/04/11)"
#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
#define DRIVER_DESC "rtl8150 based usb-ethernet driver"
#define IRD 0x0120
#define MAR 0x0126
#define CR 0x012e
......@@ -53,64 +50,65 @@
#define PHY_WRITE 0x20
#define PHY_GO 0x40
#define MII_TIMEOUT 10
#define RTL8150_REQT_READ 0xc0
#define RTL8150_REQT_WRITE 0x40
#define RTL8150_REQ_GET_REGS 0x05
#define RTL8150_REQ_SET_REGS 0x05
#define RTL8150_MTU 1500
#define RTL8150_MAX_MTU 1536
#define RTL8150_MTU 1540
#define RTL8150_TX_TIMEOUT (HZ)
#define RX_SKB_POOL_SIZE 4
/* rtl8150 flags */
#define RTL8150_FLAG_HWCRC 0
#define RTL8150_HW_CRC 0
#define RX_REG_SET 1
#define RTL8150_UNPLUG 2
#define RX_URB_FAIL 3
/* Define these values to match your device */
#define VENDOR_ID_REALTEK 0x0bda
#define PRODUCT_ID_RTL8150 0x8150
/* table of devices that work with this driver */
static struct usb_device_id rtl8150_table [] = {
{ USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8150) },
{ }
static struct usb_device_id rtl8150_table[] = {
{USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8150)},
{}
};
MODULE_DEVICE_TABLE (usb, rtl8150_table);
MODULE_DEVICE_TABLE(usb, rtl8150_table);
struct rtl8150 {
unsigned int flags;
struct usb_device *udev;
struct usb_interface *interface;
struct semaphore sem;
struct net_device_stats stats;
struct net_device *netdev;
struct urb *rx_urb, *tx_urb, *intr_urb, *ctrl_urb;
struct usb_ctrlrequest dr;
int intr_interval;
u16 rx_creg;
u8 rx_buff[RTL8150_MAX_MTU];
u8 tx_buff[RTL8150_MAX_MTU];
u8 intr_buff[8];
u8 phy;
unsigned long flags;
struct usb_device *udev;
struct semaphore sem;
struct tasklet_struct tl;
struct net_device_stats stats;
struct net_device *netdev;
struct urb *rx_urb, *tx_urb, *intr_urb, *ctrl_urb;
struct sk_buff *tx_skb, *rx_skb;
struct sk_buff *rx_skb_pool[RX_SKB_POOL_SIZE];
spinlock_t rx_pool_lock;
struct usb_ctrlrequest dr;
int intr_interval;
u16 rx_creg;
u8 intr_buff[8];
u8 phy;
};
typedef struct rtl8150 rtl8150_t;
typedef struct rtl8150 rtl8150_t;
/* the global usb devfs handle */
extern devfs_handle_t usb_devfs_handle;
unsigned long multicast_filter_limit = 32;
static void fill_skb_pool(rtl8150_t *);
static void free_skb_pool(rtl8150_t *);
static struct sk_buff *pull_skb(rtl8150_t *);
static void rtl8150_disconnect(struct usb_device *dev, void *ptr);
static void * rtl8150_probe(struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id);
static void *rtl8150_probe(struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id);
static struct usb_driver rtl8150_driver = {
name: "rtl8150",
......@@ -119,33 +117,29 @@ static struct usb_driver rtl8150_driver = {
id_table: rtl8150_table,
};
/*
**
** device related part of the code
**
*/
static int get_registers(rtl8150_t *dev, u16 indx, u16 size, void *data)
static int get_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
{
return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev,0),
RTL8150_REQ_GET_REGS, RTL8150_REQT_READ,
indx, 0, data, size, HZ/2);
return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
RTL8150_REQ_GET_REGS, RTL8150_REQT_READ,
indx, 0, data, size, HZ / 2);
}
static int set_registers(rtl8150_t *dev, u16 indx, u16 size, void *data)
static int set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
{
return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev,0),
RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE,
indx, 0, data, size, HZ/2);
return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE,
indx, 0, data, size, HZ / 2);
}
static void ctrl_callback(struct urb *urb)
{
rtl8150_t *dev;
rtl8150_t *dev;
switch (urb->status) {
case 0:
break;
......@@ -160,23 +154,22 @@ static void ctrl_callback(struct urb *urb)
clear_bit(RX_REG_SET, &dev->flags);
}
static int async_set_registers(rtl8150_t *dev, u16 indx, u16 size, void *data)
static int async_set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
{
int ret;
int ret;
if (test_bit(RX_REG_SET, &dev->flags))
return -EAGAIN;
dev->dr.bRequestType = RTL8150_REQT_WRITE;
dev->dr.bRequest = RTL8150_REQ_SET_REGS;
dev->dr.wValue = cpu_to_le16(indx);
dev->dr.wIndex = 0;
dev->dr.wLength = cpu_to_le16(size);
dev->ctrl_urb->transfer_buffer_length = size;
FILL_CONTROL_URB(dev->ctrl_urb, dev->udev, usb_sndctrlpipe(dev->udev,0),
(char*)&dev->dr, &dev->rx_creg, size,
ctrl_callback, dev);
FILL_CONTROL_URB(dev->ctrl_urb, dev->udev,
usb_sndctrlpipe(dev->udev, 0), (char *) &dev->dr,
&dev->rx_creg, size, ctrl_callback, dev);
if ((ret = usb_submit_urb(dev->ctrl_urb, GFP_ATOMIC)))
err("control request submission failed: %d", ret);
else
......@@ -185,11 +178,10 @@ static int async_set_registers(rtl8150_t *dev, u16 indx, u16 size, void *data)
return ret;
}
static int read_mii_word(rtl8150_t *dev, u8 phy, __u8 indx, u16 *reg)
static int read_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 * reg)
{
int i;
u8 data[3], tmp;
int i;
u8 data[3], tmp;
data[0] = phy;
data[1] = data[2] = 0;
......@@ -200,9 +192,9 @@ static int read_mii_word(rtl8150_t *dev, u8 phy, __u8 indx, u16 *reg)
set_registers(dev, PHYCNT, 1, &tmp);
do {
get_registers(dev, PHYCNT, 1, data);
} while ((data[0] & PHY_GO) && (i++ < HZ));
} while ((data[0] & PHY_GO) && (i++ < MII_TIMEOUT));
if (i < HZ) {
if (i < MII_TIMEOUT) {
get_registers(dev, PHYDAT, 2, data);
*reg = le16_to_cpup(data);
return 0;
......@@ -210,11 +202,10 @@ static int read_mii_word(rtl8150_t *dev, u8 phy, __u8 indx, u16 *reg)
return 1;
}
static int write_mii_word(rtl8150_t *dev, u8 phy, __u8 indx, u16 reg)
static int write_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 reg)
{
int i;
u8 data[3], tmp;
int i;
u8 data[3], tmp;
data[0] = phy;
*(data + 1) = cpu_to_le16p(&reg);
......@@ -225,39 +216,36 @@ static int write_mii_word(rtl8150_t *dev, u8 phy, __u8 indx, u16 reg)
set_registers(dev, PHYCNT, 1, &tmp);
do {
get_registers(dev, PHYCNT, 1, data);
} while((data[0] & PHY_GO) && (i++ < HZ));
} while ((data[0] & PHY_GO) && (i++ < MII_TIMEOUT));
if (i < HZ)
if (i < MII_TIMEOUT)
return 0;
else
return 1;
}
static inline void set_ethernet_addr(rtl8150_t *dev)
static inline void set_ethernet_addr(rtl8150_t * dev)
{
u8 node_id[6];
u8 node_id[6];
get_registers(dev, IRD, sizeof(node_id), node_id);
memcpy(dev->netdev->dev_addr, node_id, sizeof(node_id));
}
static int rtl8150_reset(rtl8150_t *dev)
static int rtl8150_reset(rtl8150_t * dev)
{
u8 data=0x10;
int i=HZ;
u8 data = 0x10;
int i = HZ;
set_registers(dev, CR, 1, &data);
do {
get_registers(dev, CR, 1, &data);
} while ((data & 0x10) && --i);
return (i > 0) ? 0 : -1;
}
return (i > 0) ? 1 : 0;
}
static int alloc_all_urbs(rtl8150_t *dev)
static int alloc_all_urbs(rtl8150_t * dev)
{
dev->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->rx_urb)
......@@ -284,8 +272,7 @@ static int alloc_all_urbs(rtl8150_t *dev)
return 1;
}
static void free_all_urbs(rtl8150_t *dev)
static void free_all_urbs(rtl8150_t * dev)
{
usb_free_urb(dev->rx_urb);
usb_free_urb(dev->tx_urb);
......@@ -293,8 +280,7 @@ static void free_all_urbs(rtl8150_t *dev)
usb_free_urb(dev->ctrl_urb);
}
static void unlink_all_urbs(rtl8150_t *dev)
static void unlink_all_urbs(rtl8150_t * dev)
{
usb_unlink_urb(dev->rx_urb);
usb_unlink_urb(dev->tx_urb);
......@@ -302,30 +288,28 @@ static void unlink_all_urbs(rtl8150_t *dev)
usb_unlink_urb(dev->ctrl_urb);
}
static void read_bulk_callback(struct urb *urb)
{
rtl8150_t *dev;
unsigned pkt_len, res;
struct sk_buff *skb;
rtl8150_t *dev;
unsigned pkt_len, res;
struct sk_buff *skb;
struct net_device *netdev;
u16 rx_stat;
u16 rx_stat;
dev = urb->context;
if (!dev) {
warn("!dev");
if (!dev)
return;
if (test_bit(RTL8150_UNPLUG, &dev->flags))
return;
}
netdev = dev->netdev;
if (!netif_device_present(netdev)) {
warn("netdev is not present");
if (!netif_device_present(netdev))
return;
}
switch (urb->status) {
case 0:
break;
case -ENOENT:
return;
return; /* urb's in unlink state */
case -ETIMEDOUT:
warn("reset needed may be?..");
goto goon;
......@@ -334,35 +318,76 @@ static void read_bulk_callback(struct urb *urb)
goto goon;
}
tasklet_schedule(&dev->tl);
if (!dev->rx_skb) {
/* lost packets++ */
return;
}
res = urb->actual_length;
rx_stat = le16_to_cpu(*(short*)(dev->rx_buff + res - 4));
rx_stat = le16_to_cpu(*(short *)(urb->transfer_buffer + res - 4));
pkt_len = res - 4;
if (!(skb = dev_alloc_skb(pkt_len + 2)))
goto goon;
skb->dev = netdev;
skb_reserve(skb, 2);
eth_copy_and_sum(skb, dev->rx_buff, pkt_len, 0);
skb_put(skb, pkt_len);
skb->protocol = eth_type_trans(skb, netdev);
netif_rx(skb);
skb_put(dev->rx_skb, pkt_len);
dev->rx_skb->protocol = eth_type_trans(dev->rx_skb, netdev);
netif_rx(dev->rx_skb);
dev->stats.rx_packets++;
dev->stats.rx_bytes += pkt_len;
skb = pull_skb(dev);
if (!skb) {
dev->rx_skb = NULL;
return;
}
skb->dev = netdev;
skb_reserve(skb, 2);
dev->rx_skb = skb;
goon:
FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev,1),
dev->rx_buff, RTL8150_MAX_MTU, read_bulk_callback, dev);
if ((res=usb_submit_urb(dev->rx_urb, GFP_ATOMIC)))
warn("%s: Rx urb submission failed %d", netdev->name, res);
FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
if (usb_submit_urb(dev->rx_urb, GFP_ATOMIC))
set_bit(RX_URB_FAIL, &dev->flags);
else
clear_bit(RX_URB_FAIL, &dev->flags);
}
static void rx_fixup(unsigned long data)
{
rtl8150_t *dev;
struct sk_buff *skb;
dev = (rtl8150_t *)data;
fill_skb_pool(dev);
if (test_bit(RX_URB_FAIL, &dev->flags))
goto try_again;
if (dev->rx_skb)
return;
if (!(skb = pull_skb(dev))) {
tasklet_schedule(&dev->tl);
return;
}
dev->rx_skb = skb;
FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
try_again:
if (usb_submit_urb(dev->rx_urb, GFP_ATOMIC)) {
set_bit(RX_URB_FAIL, &dev->flags);
tasklet_schedule(&dev->tl);
} else
clear_bit(RX_URB_FAIL, &dev->flags);
}
static void write_bulk_callback(struct urb *urb)
{
rtl8150_t *dev;
rtl8150_t *dev;
dev = urb->context;
if (!dev)
return;
dev_kfree_skb_irq(dev->tx_skb);
if (!netif_device_present(dev->netdev))
return;
if (urb->status)
......@@ -371,43 +396,94 @@ static void write_bulk_callback(struct urb *urb)
netif_wake_queue(dev->netdev);
}
void intr_callback(struct urb *urb)
{
rtl8150_t *dev;
rtl8150_t *dev;
dev = urb->context;
if (!dev)
return;
switch (urb->status) {
case 0:
break;
case -ENOENT:
return;
default:
info("%s: intr status %d", dev->netdev->name,
urb->status);
case 0:
break;
case -ENOENT:
return;
default:
info("%s: intr status %d", dev->netdev->name, urb->status);
}
}
/*
**
** network related part of the code
**
*/
static void fill_skb_pool(rtl8150_t *dev)
{
struct sk_buff *skb;
int i;
unsigned long flags;
spin_lock_irqsave(&dev->rx_pool_lock, flags);
for (i = 0; i < RX_SKB_POOL_SIZE; i++) {
if (dev->rx_skb_pool[i])
continue;
skb = dev_alloc_skb(RTL8150_MTU + 2);
if (!skb) {
spin_unlock_irqrestore(&dev->rx_pool_lock, flags);
return;
}
skb->dev = dev->netdev;
skb_reserve(skb, 2);
dev->rx_skb_pool[i] = skb;
}
spin_unlock_irqrestore(&dev->rx_pool_lock, flags);
}
static int enable_net_traffic(rtl8150_t *dev)
static void free_skb_pool(rtl8150_t *dev)
{
u8 cr, tcr, rcr, msr;
int i;
if (rtl8150_reset(dev)) {
spin_lock_irq(&dev->rx_pool_lock);
for (i = 0; i < RX_SKB_POOL_SIZE; i++)
if (dev->rx_skb_pool[i])
dev_kfree_skb(dev->rx_skb_pool[i]);
spin_unlock_irq(&dev->rx_pool_lock);
}
static struct sk_buff *pull_skb(rtl8150_t *dev)
{
struct sk_buff *skb;
int i;
unsigned long flags;
spin_lock_irqsave(&dev->rx_pool_lock, flags);
for (i = 0; i < RX_SKB_POOL_SIZE; i++) {
if (dev->rx_skb_pool[i]) {
skb = dev->rx_skb_pool[i];
dev->rx_skb_pool[i] = NULL;
spin_unlock_irqrestore(&dev->rx_pool_lock, flags);
return skb;
}
}
spin_unlock_irqrestore(&dev->rx_pool_lock, flags);
return NULL;
}
static int enable_net_traffic(rtl8150_t * dev)
{
u8 cr, tcr, rcr, msr;
if (!rtl8150_reset(dev)) {
warn("%s - device reset failed", __FUNCTION__);
}
dev->rx_creg = rcr = 0x9e; /* bit7=1 attach Rx info at the end */
tcr = 0xd8; /* bit0=1 no CRC at the end of the frame */
/* RCR bit7=1 attach Rx info at the end; =0 HW CRC (which is broken) */
dev->rx_creg = rcr = 0x9e;
tcr = 0xd8;
cr = 0x0c;
if (!(rcr & 0x80))
set_bit(RTL8150_HW_CRC, &dev->flags);
set_registers(dev, RCR, 1, &rcr);
set_registers(dev, TCR, 1, &tcr);
set_registers(dev, CR, 1, &cr);
......@@ -416,26 +492,23 @@ static int enable_net_traffic(rtl8150_t *dev)
return 0;
}
static void disable_net_traffic(rtl8150_t *dev)
static void disable_net_traffic(rtl8150_t * dev)
{
u8 cr;
u8 cr;
get_registers(dev, CR, 1, &cr);
cr &= 0xf3;
set_registers(dev, CR, 1, &cr);
}
static struct net_device_stats *rtl8150_netdev_stats(struct net_device *dev)
{
return &((rtl8150_t *)dev->priv)->stats;
return &((rtl8150_t *) dev->priv)->stats;
}
static void rtl8150_tx_timeout(struct net_device *netdev)
{
rtl8150_t *dev;
rtl8150_t *dev;
dev = netdev->priv;
if (!dev)
......@@ -446,10 +519,9 @@ static void rtl8150_tx_timeout(struct net_device *netdev)
dev->stats.tx_errors++;
}
static void rtl8150_set_multicast(struct net_device *netdev)
{
rtl8150_t *dev;
rtl8150_t *dev;
dev = netdev->priv;
netif_stop_queue(netdev);
......@@ -457,7 +529,7 @@ static void rtl8150_set_multicast(struct net_device *netdev)
dev->rx_creg |= 0x0001;
info("%s: promiscuous mode", netdev->name);
} else if ((netdev->mc_count > multicast_filter_limit) ||
(netdev->flags & IFF_ALLMULTI)) {
(netdev->flags & IFF_ALLMULTI)) {
dev->rx_creg &= 0xfffe;
dev->rx_creg |= 0x0002;
info("%s: allmulti set", netdev->name);
......@@ -469,22 +541,19 @@ static void rtl8150_set_multicast(struct net_device *netdev)
netif_wake_queue(netdev);
}
static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev)
{
rtl8150_t *dev;
int count, res;
rtl8150_t *dev;
int count, res;
netif_stop_queue(netdev);
dev = netdev->priv;
count = (skb->len < 60) ? 60 : skb->len;
count = (count & 0x3f) ? count : count + 1;
memcpy(dev->tx_buff, skb->data, skb->len);
FILL_BULK_URB(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev,2),
dev->tx_buff, RTL8150_MAX_MTU, write_bulk_callback, dev);
dev->tx_urb->transfer_buffer_length = count;
if ((res = usb_submit_urb(dev->tx_urb, GFP_KERNEL))) {
dev->tx_skb = skb;
FILL_BULK_URB(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2),
skb->data, count, write_bulk_callback, dev);
if ((res = usb_submit_urb(dev->tx_urb, GFP_ATOMIC))) {
warn("failed tx_urb %d\n", res);
dev->stats.tx_errors++;
netif_start_queue(netdev);
......@@ -493,31 +562,33 @@ static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev)
dev->stats.tx_bytes += skb->len;
netdev->trans_start = jiffies;
}
dev_kfree_skb(skb);
return 0;
}
static int rtl8150_open(struct net_device *netdev)
{
rtl8150_t *dev;
int res;
rtl8150_t *dev;
int res;
dev = netdev->priv;
if (dev == NULL) {
return -ENODEV;
}
dev->rx_skb = pull_skb(dev);
if (!dev->rx_skb)
return -ENOMEM;
down(&dev->sem);
FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev,1),
dev->rx_buff, RTL8150_MAX_MTU, read_bulk_callback, dev);
if ((res=usb_submit_urb(dev->rx_urb, GFP_KERNEL)))
FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
if ((res = usb_submit_urb(dev->rx_urb, GFP_KERNEL)))
warn("%s: rx_urb submit failed: %d", __FUNCTION__, res);
FILL_INT_URB(dev->intr_urb, dev->udev, usb_rcvintpipe(dev->udev,3),
dev->intr_buff, sizeof(dev->intr_buff), intr_callback,
dev, dev->intr_interval);
if ((res=usb_submit_urb(dev->intr_urb, GFP_KERNEL)))
FILL_INT_URB(dev->intr_urb, dev->udev, usb_rcvintpipe(dev->udev, 3),
dev->intr_buff, sizeof(dev->intr_buff), intr_callback,
dev, dev->intr_interval);
if ((res = usb_submit_urb(dev->intr_urb, GFP_KERNEL)))
warn("%s: intr_urb submit failed: %d", __FUNCTION__, res);
netif_start_queue(netdev);
enable_net_traffic(dev);
......@@ -526,7 +597,6 @@ static int rtl8150_open(struct net_device *netdev)
return res;
}
static int rtl8150_close(struct net_device *netdev)
{
rtl8150_t *dev;
......@@ -537,53 +607,47 @@ static int rtl8150_close(struct net_device *netdev)
return -ENODEV;
down(&dev->sem);
netif_stop_queue(netdev);
if (!test_bit(RTL8150_UNPLUG, &dev->flags))
disable_net_traffic(dev);
unlink_all_urbs(dev);
netif_stop_queue(netdev);
up(&dev->sem);
return res;
}
static int rtl8150_ethtool_ioctl(struct net_device *netdev, void *uaddr)
{
rtl8150_t *dev;
int cmd;
char tmp[128];
rtl8150_t *dev;
int cmd;
dev = netdev->priv;
if (get_user(cmd, (int *)uaddr))
if (get_user(cmd, (int *) uaddr))
return -EFAULT;
switch (cmd) {
case ETHTOOL_GDRVINFO: {
struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
case ETHTOOL_GDRVINFO:{
struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
strncpy(info.driver, DRIVER_DESC, ETHTOOL_BUSINFO_LEN);
strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
sprintf(tmp, "usb%d:%d", dev->udev->bus->busnum,
dev->udev->devnum);
strncpy(info.bus_info, tmp, ETHTOOL_BUSINFO_LEN);
usb_make_path(dev->udev, info.bus_info, sizeof info.bus_info);
if (copy_to_user(uaddr, &info, sizeof(info)))
return -EFAULT;
return 0;
}
case ETHTOOL_GSET: {
}
case ETHTOOL_GSET:{
struct ethtool_cmd ecmd;
short lpa, bmcr;
short lpa, bmcr;
if (copy_from_user(&ecmd, uaddr, sizeof(ecmd)))
return -EFAULT;
ecmd.supported = (SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_Autoneg |
SUPPORTED_TP |
SUPPORTED_MII);
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_Autoneg |
SUPPORTED_TP | SUPPORTED_MII);
ecmd.port = PORT_TP;
ecmd.transceiver = XCVR_INTERNAL;
ecmd.phy_address = dev->phy;
......@@ -595,45 +659,44 @@ static int rtl8150_ethtool_ioctl(struct net_device *netdev, void *uaddr)
SPEED_100 : SPEED_10;
if (ecmd.speed == SPEED_100)
ecmd.duplex = (lpa & LPA_100FULL) ?
DUPLEX_FULL : DUPLEX_HALF;
DUPLEX_FULL : DUPLEX_HALF;
else
ecmd.duplex = (lpa & LPA_10FULL) ?
DUPLEX_FULL : DUPLEX_HALF;
DUPLEX_FULL : DUPLEX_HALF;
} else {
ecmd.autoneg = AUTONEG_DISABLE;
ecmd.speed = (bmcr & BMCR_SPEED100) ?
SPEED_100 : SPEED_10;
SPEED_100 : SPEED_10;
ecmd.duplex = (bmcr & BMCR_FULLDPLX) ?
DUPLEX_FULL : DUPLEX_HALF;
DUPLEX_FULL : DUPLEX_HALF;
}
if (copy_to_user(uaddr, &ecmd, sizeof(ecmd)))
return -EFAULT;
return 0;
}
}
case ETHTOOL_SSET:
return -ENOTSUPP;
case ETHTOOL_GLINK: {
struct ethtool_value edata = {ETHTOOL_GLINK};
case ETHTOOL_GLINK:{
struct ethtool_value edata = { ETHTOOL_GLINK };
edata.data = netif_carrier_ok(netdev);
if (copy_to_user(uaddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
}
default:
return -EOPNOTSUPP;
}
}
static int rtl8150_ioctl (struct net_device *netdev, struct ifreq *rq, int cmd)
static int rtl8150_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
{
rtl8150_t *dev;
u16 *data;
int res;
u16 *data;
int res;
dev = netdev->priv;
data = (u16 *)&rq->ifr_data;
data = (u16 *) & rq->ifr_data;
res = 0;
down(&dev->sem);
......@@ -643,10 +706,10 @@ static int rtl8150_ioctl (struct net_device *netdev, struct ifreq *rq, int cmd)
break;
case SIOCDEVPRIVATE:
data[0] = dev->phy;
case SIOCDEVPRIVATE+1:
case SIOCDEVPRIVATE + 1:
read_mii_word(dev, dev->phy, (data[1] & 0x1f), &data[3]);
break;
case SIOCDEVPRIVATE+2:
case SIOCDEVPRIVATE + 2:
if (!capable(CAP_NET_ADMIN)) {
up(&dev->sem);
return -EPERM;
......@@ -660,27 +723,25 @@ static int rtl8150_ioctl (struct net_device *netdev, struct ifreq *rq, int cmd)
return res;
}
static void * rtl8150_probe(struct usb_device *udev, unsigned int ifnum,
const struct usb_device_id *id)
static void *rtl8150_probe(struct usb_device *udev, unsigned int ifnum,
const struct usb_device_id *id)
{
rtl8150_t *dev;
struct net_device *netdev;
udev->config[0].bConfigurationValue = 1;
if (usb_set_configuration(udev, udev->config[0].bConfigurationValue)) {
err("usb_set_configuration() failed");
return NULL;
}
if ((udev->descriptor.idVendor != VENDOR_ID_REALTEK) ||
(udev->descriptor.idProduct != PRODUCT_ID_RTL8150)) {
err("Not the one we are interested about");
err("Not the one we are interested about");
return NULL;
}
dev = kmalloc(sizeof(rtl8150_t), GFP_KERNEL);
if (!dev) {
err ("Out of memory");
goto exit;
err("Out of memory");
return NULL;
} else
memset(dev, 0, sizeof(rtl8150_t));
......@@ -688,11 +749,14 @@ static void * rtl8150_probe(struct usb_device *udev, unsigned int ifnum,
if (!netdev) {
kfree(dev);
err("Oh boy, out of memory again?!?");
dev = NULL;
goto exit;
return NULL;
}
init_MUTEX(&dev->sem);
tasklet_init(&dev->tl, rx_fixup, (unsigned long)dev);
spin_lock_init(&dev->rx_pool_lock);
down(&dev->sem);
dev->udev = udev;
dev->netdev = netdev;
SET_MODULE_OWNER(netdev);
......@@ -708,23 +772,29 @@ static void * rtl8150_probe(struct usb_device *udev, unsigned int ifnum,
netdev->mtu = RTL8150_MTU;
dev->intr_interval = 100; /* 100ms */
if (rtl8150_reset(dev) || !alloc_all_urbs(dev)) {
if (!alloc_all_urbs(dev)) {
err("out of memory");
goto err;
}
if (!rtl8150_reset(dev)) {
err("couldn't reset the device");
free_all_urbs(dev);
unregister_netdev(dev->netdev);
kfree(netdev);
kfree(dev);
dev = NULL;
goto exit;
goto err;
}
fill_skb_pool(dev);
set_ethernet_addr(dev);
info("%s: rtl8150 is detected", netdev->name);
exit:
up(&dev->sem);
return dev;
err:
unregister_netdev(dev->netdev);
up(&dev->sem);
kfree(netdev);
kfree(dev);
return NULL;
}
static void rtl8150_disconnect(struct usb_device *udev, void *ptr)
{
rtl8150_t *dev;
......@@ -734,27 +804,26 @@ static void rtl8150_disconnect(struct usb_device *udev, void *ptr)
unregister_netdev(dev->netdev);
unlink_all_urbs(dev);
free_all_urbs(dev);
free_skb_pool(dev);
if (dev->rx_skb)
dev_kfree_skb(dev->rx_skb);
kfree(dev->netdev);
kfree(dev);
dev->netdev = NULL;
dev = NULL;
}
static int __init usb_rtl8150_init(void)
{
info(DRIVER_DESC " " DRIVER_VERSION);
return usb_register(&rtl8150_driver);
}
static void __exit usb_rtl8150_exit(void)
{
usb_deregister(&rtl8150_driver);
}
module_init(usb_rtl8150_init);
module_exit(usb_rtl8150_exit);
......
......@@ -538,25 +538,25 @@ static int genelink_rx_fixup (struct usbnet *dev, struct sk_buff *skb)
// allocate the skb for the individual packet
gl_skb = alloc_skb (size, GFP_ATOMIC);
if (gl_skb == 0)
return 0;
if (gl_skb) {
// copy the packet data to the new skb
memcpy (gl_skb->data, packet->packet_data, size);
// copy the packet data to the new skb
memcpy (gl_skb->data, packet->packet_data, size);
// set skb data size
gl_skb->len = size;
gl_skb->dev = &dev->net;
// set skb data size
gl_skb->len = size;
gl_skb->dev = &dev->net;
// determine the packet's protocol ID
gl_skb->protocol = eth_type_trans (gl_skb, &dev->net);
// determine the packet's protocol ID
gl_skb->protocol = eth_type_trans (gl_skb, &dev->net);
// update the status
dev->stats.rx_packets++;
dev->stats.rx_bytes += size;
// update the status
dev->stats.rx_packets++;
dev->stats.rx_bytes += size;
// notify os of the received packet
status = netif_rx (gl_skb);
// notify os of the received packet
status = netif_rx (gl_skb);
}
// advance to the next packet
packet = (struct gl_packet *)
......@@ -834,10 +834,10 @@ static void nc_dump_registers (struct usbnet *dev)
static inline void nc_dump_usbctl (struct usbnet *dev, u16 usbctl)
{
#ifdef DEBUG
devdbg (dev, "net1080 %03d/%03d usbctl 0x%x:%s%s%s%s%s;"
devdbg (dev, "net1080 %s-%s usbctl 0x%x:%s%s%s%s%s;"
" this%s%s;"
" other%s%s; r/o 0x%x",
dev->udev->bus->busnum, dev->udev->devnum,
dev->udev->bus->bus_name, dev->udev->devpath,
usbctl,
(usbctl & USBCTL_ENABLE_LANG) ? " lang" : "",
(usbctl & USBCTL_ENABLE_MFGR) ? " mfgr" : "",
......@@ -879,10 +879,10 @@ static inline void nc_dump_usbctl (struct usbnet *dev, u16 usbctl)
static inline void nc_dump_status (struct usbnet *dev, u16 status)
{
#ifdef DEBUG
devdbg (dev, "net1080 %03d/%03d status 0x%x:"
devdbg (dev, "net1080 %s-%s status 0x%x:"
" this (%c) PKT=%d%s%s%s;"
" other PKT=%d%s%s%s; unspec 0x%x",
dev->udev->bus->busnum, dev->udev->devnum,
dev->udev->bus->bus_name, dev->udev->devpath,
status,
// XXX the packet counts don't seem right
......@@ -917,8 +917,8 @@ static inline void nc_dump_status (struct usbnet *dev, u16 status)
static inline void nc_dump_ttl (struct usbnet *dev, u16 ttl)
{
#ifdef DEBUG
devdbg (dev, "net1080 %03d/%03d ttl 0x%x this = %d, other = %d",
dev->udev->bus->busnum, dev->udev->devnum,
devdbg (dev, "net1080 %s-%s ttl 0x%x this = %d, other = %d",
dev->udev->bus->bus_name, dev->udev->devpath,
ttl,
TTL_THIS (ttl),
......@@ -941,7 +941,8 @@ static int net1080_reset (struct usbnet *dev)
// nc_dump_registers (dev);
if ((retval = nc_register_read (dev, REG_STATUS, vp)) < 0) {
dbg ("can't read dev %d status: %d", dev->udev->devnum, retval);
dbg ("can't read %s-%s status: %d",
dev->udev->bus->bus_name, dev->udev->devpath, retval);
goto done;
}
status = *vp;
......@@ -1504,10 +1505,9 @@ static int usbnet_open (struct net_device *net)
// put into "known safe" state
if (info->reset && (retval = info->reset (dev)) < 0) {
devinfo (dev, "open reset fail (%d) usbnet bus%d%s, %s",
devinfo (dev, "open reset fail (%d) usbnet usb-%s-%s, %s",
retval,
// FIXME busnum is unstable
dev->udev->bus->busnum, dev->udev->devpath,
dev->udev->bus->bus_name, dev->udev->devpath,
info->description);
goto done;
}
......@@ -1557,9 +1557,7 @@ static int usbnet_ethtool_ioctl (struct net_device *net, void *useraddr)
strncpy (info.version, DRIVER_VERSION, sizeof info.version);
strncpy (info.fw_version, dev->driver_info->description,
sizeof info.fw_version);
snprintf (info.bus_info, sizeof info.bus_info, "USB bus%d%s",
/* FIXME busnums are bogus/unstable IDs */
dev->udev->bus->busnum, dev->udev->devpath);
usb_make_path (dev->udev, info.bus_info, sizeof info.bus_info);
if (copy_to_user (useraddr, &info, sizeof (info)))
return -EFAULT;
return 0;
......@@ -1847,9 +1845,8 @@ static void usbnet_disconnect (struct usb_device *udev, void *ptr)
{
struct usbnet *dev = (struct usbnet *) ptr;
devinfo (dev, "unregister usbnet bus%d%s, %s",
// FIXME busnum is unstable
udev->bus->busnum, udev->devpath,
devinfo (dev, "unregister usbnet usb-%s-%s, %s",
udev->bus->bus_name, udev->devpath,
dev->driver_info->description);
unregister_netdev (&dev->net);
......@@ -1938,9 +1935,8 @@ usbnet_probe (struct usb_device *udev, unsigned ifnum,
net->do_ioctl = usbnet_ioctl;
register_netdev (&dev->net);
devinfo (dev, "register usbnet bus%d%s, %s",
// FIXME busnum is unstable
udev->bus->busnum, udev->devpath,
devinfo (dev, "register usbnet usb-%s-%s, %s",
udev->bus->bus_name, udev->devpath,
dev->driver_info->description);
// ok, it's ready to go.
......
......@@ -197,6 +197,7 @@ static struct usb_serial_device_type ftdi_sio_device = {
};
static struct usb_serial_device_type ftdi_8U232AM_device = {
owner: THIS_MODULE,
name: "FTDI 8U232AM",
id_table: id_table_8U232AM,
num_interrupt_in: 0,
......
......@@ -798,6 +798,7 @@ static void keyspan_pda_shutdown (struct usb_serial *serial)
#ifdef KEYSPAN
static struct usb_serial_device_type keyspan_pda_fake_device = {
owner: THIS_MODULE,
name: "Keyspan PDA - (prerenumeration)",
id_table: id_table_fake,
num_interrupt_in: NUM_DONT_CARE,
......@@ -810,17 +811,19 @@ static struct usb_serial_device_type keyspan_pda_fake_device = {
#ifdef XIRCOM
static struct usb_serial_device_type xircom_pgs_fake_device = {
name: "Xircom / Entregra PGS - (prerenumeration)",
id_table: id_table_fake_xircom,
num_interrupt_in: NUM_DONT_CARE,
num_bulk_in: NUM_DONT_CARE,
num_bulk_out: NUM_DONT_CARE,
num_ports: 1,
startup: keyspan_pda_fake_startup,
owner: THIS_MODULE,
name: "Xircom / Entregra PGS - (prerenumeration)",
id_table: id_table_fake_xircom,
num_interrupt_in: NUM_DONT_CARE,
num_bulk_in: NUM_DONT_CARE,
num_bulk_out: NUM_DONT_CARE,
num_ports: 1,
startup: keyspan_pda_fake_startup,
};
#endif
static struct usb_serial_device_type keyspan_pda_device = {
owner: THIS_MODULE,
name: "Keyspan PDA",
id_table: id_table_std,
num_interrupt_in: 1,
......
......@@ -15,6 +15,10 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
* (04/10/2002) gkh
* added serial_read_proc function which creates a
* /proc/tty/driver/usb-serial file.
*
* (03/27/2002) gkh
* Got USB serial console code working properly and merged into the main
* version of the tree. Thanks to Randy Dunlap for the initial version
......@@ -340,7 +344,7 @@
/*
* Version Information
*/
#define DRIVER_VERSION "v1.4"
#define DRIVER_VERSION "v1.5"
#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/"
#define DRIVER_DESC "USB Serial Driver core"
......@@ -844,6 +848,48 @@ static void serial_shutdown (struct usb_serial *serial)
generic_shutdown(serial);
}
static int serial_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
{
struct usb_serial *serial;
int length = 0;
int i;
off_t begin = 0;
char tmp[40];
dbg(__FUNCTION__);
length += sprintf (page, "usbserinfo:1.0 driver:%s\n", DRIVER_VERSION);
for (i = 0; i < SERIAL_TTY_MINORS && length < PAGE_SIZE; ++i) {
serial = get_serial_by_minor(i);
if (serial == NULL)
continue;
length += sprintf (page+length, "%d:", i);
if (serial->type->owner)
length += sprintf (page+length, " module:%s", serial->type->owner->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, " num_ports:%d", serial->num_ports);
length += sprintf (page+length, " port:%d", i - serial->minor + 1);
usb_make_path(serial->dev, tmp, sizeof(tmp));
length += sprintf (page+length, " path:%s", tmp);
length += sprintf (page+length, "\n");
if ((length + begin) > (off + count))
goto done;
if ((length + begin) < off) {
begin += length;
length = 0;
}
}
*eof = 1;
done:
if (off >= (length + begin))
return 0;
*start = page + (off-begin);
return ((count < begin+length-off) ? count : begin+length-off);
}
/*****************************************************************************
* generic devices specific driver functions
*****************************************************************************/
......@@ -1491,6 +1537,7 @@ static struct tty_driver serial_tty_driver = {
unthrottle: serial_unthrottle,
break_ctl: serial_break,
chars_in_buffer: serial_chars_in_buffer,
read_proc: serial_read_proc,
};
......
......@@ -10,16 +10,14 @@ EXTRA_CFLAGS := -I../../scsi/
obj-$(CONFIG_USB_STORAGE) += usb-storage.o
usb-storage-obj-$(CONFIG_USB_STORAGE_DEBUG) += debug.o
usb-storage-obj-$(CONFIG_USB_STORAGE_HP8200e) += shuttle_usbat.o
usb-storage-obj-$(CONFIG_USB_STORAGE_SDDR09) += sddr09.o
usb-storage-obj-$(CONFIG_USB_STORAGE_FREECOM) += freecom.o
usb-storage-obj-$(CONFIG_USB_STORAGE_SHUTTLE_SMARTMEDIA) += shuttle_sm.o
usb-storage-obj-$(CONFIG_USB_STORAGE_SHUTTLE_COMPACTFLASH) += shuttle_cf.o
usb-storage-obj-$(CONFIG_USB_STORAGE_DPCM) += dpcm.o
usb-storage-obj-$(CONFIG_USB_STORAGE_ISD200) += isd200.o
usb-storage-obj-$(CONFIG_USB_STORAGE_DATAFAB) += datafab.o
usb-storage-obj-$(CONFIG_USB_STORAGE_JUMPSHOT) += jumpshot.o
usb-storage-obj-$(CONFIG_USB_STORAGE_DEBUG) += debug.o
usb-storage-obj-$(CONFIG_USB_STORAGE_HP8200e) += shuttle_usbat.o
usb-storage-obj-$(CONFIG_USB_STORAGE_SDDR09) += sddr09.o
usb-storage-obj-$(CONFIG_USB_STORAGE_FREECOM) += freecom.o
usb-storage-obj-$(CONFIG_USB_STORAGE_DPCM) += dpcm.o
usb-storage-obj-$(CONFIG_USB_STORAGE_ISD200) += isd200.o
usb-storage-obj-$(CONFIG_USB_STORAGE_DATAFAB) += datafab.o
usb-storage-obj-$(CONFIG_USB_STORAGE_JUMPSHOT) += jumpshot.o
usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \
initializers.o $(usb-storage-obj-y)
......
......@@ -890,7 +890,6 @@ extern int usb_string(struct usb_device *dev, int index,
char *buf, size_t size);
extern int usb_set_configuration(struct usb_device *dev, int configuration);
extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);
extern int usb_make_path(struct usb_device *dev, char *buf, size_t size);
/*
* timeouts, in seconds, used for sending/receiving control messages
......@@ -917,6 +916,7 @@ struct usb_operations;
*/
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 */
......@@ -1087,6 +1087,37 @@ const struct usb_device_id *usb_match_id(struct usb_device *dev,
struct usb_interface *interface,
const struct usb_device_id *id);
/**
* usb_make_path - returns stable device path in the usb tree
* @dev: the device whose path is being constructed
* @buf: where to put the string
* @size: how big is "buf"?
*
* Returns length of the string (> 0) or negative if size was too small.
*
* This identifier is intended to be "stable", reflecting physical paths in
* hardware such as physical bus addresses for host controllers or ports on
* USB hubs. That makes it stay the same until systems are physically
* reconfigured, by re-cabling a tree of USB devices or by moving USB host
* controllers. Adding and removing devices, including virtual root hubs
* in host controller driver modules, does not change these path identifers;
* neither does rebooting or re-enumerating. These are more useful identifiers
* than changeable ("unstable") ones like bus numbers or device addresses.
*
* With a partial exception for devices connected to USB 2.0 root hubs, these
* identifiers are also predictable: so long as the device tree isn't changed,
* plugging any USB device into a given hub port always gives it the same path.
* Because of the use of "companion" controllers, devices connected to ports on
* USB 2.0 root hubs (EHCI host controllers) will get one path ID if they are
* high speed, and a different one if they are full or low speed.
*/
static inline int usb_make_path (struct usb_device *dev, char *buf, size_t size)
{
int actual;
actual = snprintf (buf, size, "usb-%s-%s", dev->bus->bus_name, dev->devpath);
return (actual >= size) ? -1 : actual;
}
/* -------------------------------------------------------------------------- */
/*
......
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