Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
3a80046a
Commit
3a80046a
authored
Jun 24, 2003
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://kernel.bkbits.net/gregkh/linux/linus-2.5
into home.transmeta.com:/home/torvalds/v2.5/linux
parents
e73291c3
33f0554d
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
208 additions
and
1977 deletions
+208
-1977
Documentation/DocBook/gadget.tmpl
Documentation/DocBook/gadget.tmpl
+29
-459
drivers/usb/host/uhci-debug.c
drivers/usb/host/uhci-debug.c
+1
-1
drivers/usb/net/cdc-ether.c
drivers/usb/net/cdc-ether.c
+0
-1397
drivers/usb/net/cdc-ether.h
drivers/usb/net/cdc-ether.h
+0
-98
drivers/usb/net/kaweth.c
drivers/usb/net/kaweth.c
+58
-15
drivers/usb/serial/io_edgeport.c
drivers/usb/serial/io_edgeport.c
+2
-1
drivers/usb/serial/pl2303.c
drivers/usb/serial/pl2303.c
+5
-1
drivers/usb/serial/visor.c
drivers/usb/serial/visor.c
+40
-0
drivers/usb/storage/initializers.c
drivers/usb/storage/initializers.c
+47
-0
drivers/usb/storage/initializers.h
drivers/usb/storage/initializers.h
+6
-0
drivers/usb/storage/unusual_devs.h
drivers/usb/storage/unusual_devs.h
+20
-0
include/linux/usb_gadget.h
include/linux/usb_gadget.h
+0
-5
No files found.
Documentation/DocBook/gadget.tmpl
View file @
3a80046a
...
...
@@ -6,31 +6,32 @@
<edition>
02 June 2003
</edition>
<legalnotice>
<para>
Permission is granted to copy, distribute, and/or modify
this document under the terms of the GNU Free Documentation
License, version 1.2, or any later version published by the
Free Software Foundation; with the Invariant Sections being
the "GNU Free Documentation License",
no Front-Cover Texts,
and
no Back-Cover Texts.
</para>
<para>
This documentation 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 Free Documentation License for more details.
</para>
<para>
Note that certain sections of this document are merged
into Linux kernel source code.
That content is the bulk of
<xref
linkend=
"core"
/>
and
<xref
linkend=
"utils"
/>
,
where the "GNU Free Documentation License" is identified
as an alternate licence for its documentation.
</para>
<para>
This documentation 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.
</para>
<para>
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.
</para>
<para>
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
</para>
<para>
For more details see the file COPYING in the source
distribution of Linux.
</para>
</legalnotice>
<copyright>
<year>
2003
</year>
...
...
@@ -325,9 +326,10 @@ the "chunky" nature of USB messages: I/O requests are in terms
of one or more "packets", and packet boundaries are visible to drivers.
Compared to RS-232 serial protocols, USB resembles
synchronous protocols like HDLC
(N bytes per frame, multipoint addressing from the host)
(N bytes per frame, multipoint addressing, host as the primary
station and devices as secondary stations)
more than asynchronous ones
(tty style
, like 8 bytes
, no parity, one stop bit).
(tty style
: 8 data bits per frame
, no parity, one stop bit).
So for example the controller drivers won't buffer
two single byte writes into a single two-byte USB IN packet,
although gadget drivers may do so when they implement
...
...
@@ -528,438 +530,6 @@ over time, as this driver framework evolves.
</chapter>
<appendix
id=
"gfdl"
>
<title>
GNU Free Documentation License
</title>
<subtitle>
Version 1.2, November 2002
</subtitle>
<blockquote
id=
"fsf-copyright"
>
<para>
Copyright (C) 2000,2001,2002 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
</para>
</blockquote>
<sect1
id=
"gfdl-0"
><title>
PREAMBLE
</title>
<para>
The purpose of this License is to make a manual, textbook, or
other functional and useful document "free" in the sense of freedom: to
assure everyone the effective freedom to copy and redistribute it, with
or without modifying it, either commercially or noncommercially.
Secondarily, this License preserves for the author and publisher a way
to get credit for their work, while not being considered responsible for
modifications made by others.
</para>
<para>
This License is a kind of "copyleft", which means that derivative
works of the document must themselves be free in the same sense. It
complements the GNU General Public License, which is a copyleft license
designed for free software.
</para>
<para>
We have designed this License in order to use it for manuals for
free software, because free software needs free documentation: a free
program should come with manuals providing the same freedoms that the
software does. But this License is not limited to software manuals; it
can be used for any textual work, regardless of subject matter or
whether it is published as a printed book. We recommend this License
principally for works whose purpose is instruction or reference.
</para>
</sect1>
<sect1
id=
"gfdl-1"
><title>
APPLICABILITY AND DEFINITIONS
</title>
<para
id=
"gfdl-doc"
>
This License applies to any manual or other work, in
any medium, that contains a notice placed by the copyright holder saying
it can be distributed under the terms of this License. Such a notice
grants a world-wide, royalty-free license, unlimited in duration, to use
that work under the conditions stated herein. The "Document", below,
refers to any such manual or work. Any member of the public is a
licensee, and is addressed as "you". You accept the license if you
copy, modify or distribute the work in a way requiring permission under
copyright law.
</para>
<para
id=
"gfdl-mod-ver"
>
A "Modified Version" of the Document means any
work containing the Document or a portion of it, either copied verbatim,
or with modifications and/or translated into another language.
</para>
<para
id=
"gfdl-secnd-sect"
>
A "Secondary Section" is a named appendix or
a front-matter section of the Document that deals exclusively with the
relationship of the publishers or authors of the Document to the
Document's overall subject (or to related matters) and contains nothing
that could fall directly within that overall subject. (Thus, if the
Document is in part a textbook of mathematics, a Secondary Section may
not explain any mathematics.) The relationship could be a matter of
historical connection with the subject or with related matters, or of
legal, commercial, philosophical, ethical or political position
regarding them.
</para>
<para
id=
"gfdl-inv-sect"
>
The "Invariant Sections" are certain Secondary
Sections whose titles are designated, as being those of Invariant
Sections, in the notice that says that the Document is released under
this License. If a section does not fit the above definition of
Secondary then it is not allowed to be designated as Invariant. The
Document may contain zero Invariant Sections. If the Document does not
identify any Invariant Sections then there are none.
</para>
<para
id=
"gfdl-cov-text"
>
The "Cover Texts" are certain short passages of
text that are listed, as Front-Cover Texts or Back-Cover Texts, in the
notice that says that the Document is released under this License. A
Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at
most 25 words.
</para>
<para
id=
"gfdl-transparent"
>
A "Transparent" copy of the Document means a
machine-readable copy, represented in a format whose specification is
available to the general public, that is suitable for revising the
document straightforwardly with generic text editors or (for images
composed of pixels) generic paint programs or (for drawings) some widely
available drawing editor, and that is suitable for input to text
formatters or for automatic translation to a variety of formats suitable
for input to text formatters. A copy made in an otherwise Transparent
file format whose markup, or absence of markup, has been arranged to
thwart or discourage subsequent modification by readers is not
Transparent. An image format is not Transparent if used for any
substantial amount of text. A copy that is not "Transparent" is called
"Opaque".
</para>
<para>
Examples of suitable formats for Transparent copies include plain
ASCII without markup, Texinfo input format, LaTeX input format, SGML or
XML using a publicly available DTD, and standard-conforming simple HTML,
PostScript or PDF designed for human modification. Examples of
transparent image formats include PNG, XCF and JPG. Opaque formats
include proprietary formats that can be read and edited only by
proprietary word processors, SGML or XML for which the DTD and/or
processing tools are not generally available, and the machine-generated
HTML, PostScript or PDF produced by some word processors for output
purposes only.
</para>
<para
id=
"gfdl-title-page"
>
The "Title Page" means, for a printed book,
the title page itself, plus such following pages as are needed to hold,
legibly, the material this License requires to appear in the title page.
For works in formats which do not have any title page as such, "Title
Page" means the text near the most prominent appearance of the work's
title, preceding the beginning of the body of the text.
</para>
<para
id=
"gfdl-entitled"
>
A section "Entitled XYZ" means a named subunit
of the Document whose title either is precisely XYZ or contains XYZ in
parentheses following text that translates XYZ in another language.
(Here XYZ stands for a specific section name mentioned below, such as
"Acknowledgements", "Dedications", "Endorsements", or "History".) To
"Preserve the Title" of such a section when you modify the Document
means that it remains a section "Entitled XYZ" according to this
definition.
</para>
<para>
The Document may include Warranty Disclaimers next to the notice
which states that this License applies to the Document. These Warranty
Disclaimers are considered to be included by reference in this License,
but only as regards disclaiming warranties: any other implication that
these Warranty Disclaimers may have is void and has no effect on the
meaning of this License.
</para>
</sect1>
<sect1
id=
"gfdl-2"
><title>
VERBATIM COPYING
</title>
<para>
You may copy and distribute the Document in any medium, either
commercially or noncommercially, provided that this License, the
copyright notices, and the license notice saying this License applies to
the Document are reproduced in all copies, and that you add no other
conditions whatsoever to those of this License. You may not use
technical measures to obstruct or control the reading or further copying
of the copies you make or distribute. However, you may accept
compensation in exchange for copies. If you distribute a large enough
number of copies you must also follow the conditions in section 3.
</para>
<para>
You may also lend copies, under the same conditions stated above,
and you may publicly display copies.
</para>
</sect1>
<sect1
id=
"gfdl-3"
><title>
COPYING IN QUANTITY
</title>
<para>
If you publish printed copies (or copies in media that commonly
have printed covers) of the Document, numbering more than 100, and the
Document's license notice requires Cover Texts, you must enclose the
copies in covers that carry, clearly and legibly, all these Cover Texts:
Front-Cover Texts on the front cover, and Back-Cover Texts on the back
cover. Both covers must also clearly and legibly identify you as the
publisher of these copies. The front cover must present the full title
with all words of the title equally prominent and visible. You may add
other material on the covers in addition. Copying with changes limited
to the covers, as long as they preserve the title of the Document and
satisfy these conditions, can be treated as verbatim copying in other
respects.
</para>
<para>
If the required texts for either cover are too voluminous to fit
legibly, you should put the first ones listed (as many as fit
reasonably) on the actual cover, and continue the rest onto adjacent
pages.
</para>
<para>
If you publish or distribute Opaque copies of the Document
numbering more than 100, you must either include a machine-readable
Transparent copy along with each Opaque copy, or state in or with each
Opaque copy a computer-network location from which the general
network-using public has access to download using public-standard
network protocols a complete Transparent copy of the Document, free of
added material. If you use the latter option, you must take reasonably
prudent steps, when you begin distribution of Opaque copies in quantity,
to ensure that this Transparent copy will remain thus accessible at the
stated location until at least one year after the last time you
distribute an Opaque copy (directly or through your agents or retailers)
of that edition to the public.
</para>
<para>
It is requested, but not required, that you contact the authors of
the Document well before redistributing any large number of copies, to
give them a chance to provide you with an updated version of the
Document.
</para>
</sect1>
<sect1
id=
"gfdl-4"
><title>
MODIFICATIONS
</title>
<para>
You may copy and distribute a Modified Version of the Document
under the conditions of sections 2 and 3 above, provided that you
release the Modified Version under precisely this License, with the
Modified Version filling the role of the Document, thus licensing
distribution and modification of the Modified Version to whoever
possesses a copy of it. In addition, you must do these things in the
Modified Version:
</para>
<orderedlist
id=
"gfdl-modif-cond"
numeration=
"upperalpha"
>
<listitem><simpara>
Use in the Title Page (and on the covers, if any) a
title distinct from that of the Document, and from those of previous
versions (which should, if there were any, be listed in the History
section of the Document). You may use the same title as a previous
version if the original publisher of that version gives permission.
</simpara></listitem>
<listitem><simpara>
List on the Title Page, as authors, one or more
persons or entities responsible for authorship of the modifications in
the Modified Version, together with at least five of the principal
authors of the Document (all of its principal authors, if it has fewer
than five), unless they release you from this requirement.
</simpara></listitem>
<listitem><simpara>
State on the Title page the name of the publisher of
the Modified Version, as the publisher.
</simpara></listitem>
<listitem><simpara>
Preserve all the copyright notices of the Document.
</simpara></listitem>
<listitem><simpara>
Add an appropriate copyright notice for your
modifications adjacent to the other copyright notices.
</simpara></listitem>
<listitem><simpara>
Include, immediately after the copyright notices, a
license notice giving the public permission to use the Modified
Version under the terms of this License, in the form shown in the
<link
linkend=
"gfdl-addendum"
>
Addendum
</link>
below.
</simpara></listitem>
<listitem><simpara>
Preserve in that license notice the full lists of
Invariant Sections and required Cover Texts given in the Document's
license notice.
</simpara></listitem>
<listitem><simpara>
Include an unaltered copy of this License.
</simpara></listitem>
<listitem><simpara>
Preserve the section Entitled "History", Preserve its
Title, and add to it an item stating at least the title, year, new
authors, and publisher of the Modified Version as given on the Title
Page. If there is no section Entitled "History" in the Document,
create one stating the title, year, authors, and publisher of the
Document as given on its Title Page, then add an item describing the
Modified Version as stated in the previous sentence.
</simpara></listitem>
<listitem><simpara>
Preserve the network location, if any, given in the
Document for public access to a Transparent copy of the Document, and
likewise the network locations given in the Document for previous
versions it was based on. These may be placed in the "History"
section. You may omit a network location for a work that was
published at least four years before the Document itself, or if the
original publisher of the version it refers to gives permission.
</simpara></listitem>
<listitem><simpara>
For any section Entitled "Acknowledgements" or
"Dedications", Preserve the Title of the section, and preserve in the
section all the substance and tone of each of the contributor
acknowledgements and/or dedications given therein.
</simpara></listitem>
<listitem><simpara>
Preserve all the Invariant Sections of the Document,
unaltered in their text and in their titles. Section numbers or the
equivalent are not considered part of the section titles.
</simpara></listitem>
<listitem><simpara>
Delete any section Entitled "Endorsements".
Such a section may not be included in the Modified Version.
</simpara></listitem>
<listitem><simpara>
Do not retitle any existing section to be Entitled
"Endorsements" or to conflict in title with any Invariant Section.
</simpara></listitem>
<listitem><simpara>
Preserve any Warranty Disclaimers.
</simpara></listitem>
</orderedlist>
<para>
If the Modified Version includes new front-matter sections or
appendices that qualify as Secondary Sections and contain no material
copied from the Document, you may at your option designate some or all
of these sections as invariant. To do this, add their titles to the
list of Invariant Sections in the Modified Version's license notice.
These titles must be distinct from any other section titles.
</para>
<para>
You may add a section Entitled "Endorsements", provided it
contains nothing but endorsements of your Modified Version by various
parties--for example, statements of peer review or that the text has
been approved by an organization as the authoritative definition of a
standard.
</para>
<para>
You may add a passage of up to five words as a Front-Cover Text,
and a passage of up to 25 words as a Back-Cover Text, to the end of the
list of Cover Texts in the Modified Version. Only one passage of
Front-Cover Text and one of Back-Cover Text may be added by (or through
arrangements made by) any one entity. If the Document already includes
a cover text for the same cover, previously added by you or by
arrangement made by the same entity you are acting on behalf of, you may
not add another; but you may replace the old one, on explicit permission
from the previous publisher that added the old one.
</para>
<para>
The author(s) and publisher(s) of the Document do not by this
License give permission to use their names for publicity for or to
assert or imply endorsement of any Modified Version.
</para>
</sect1>
<sect1
id=
"gfdl-5"
><title>
COMBINING DOCUMENTS
</title>
<para>
You may combine the Document with other documents released under
this License, under the terms defined in
<link
linkend=
"gfdl-4"
>
section
4
</link>
above for modified versions, provided that you include in the
combination all of the Invariant Sections of all of the original
documents, unmodified, and list them all as Invariant Sections of your
combined work in its license notice, and that you preserve all their
Warranty Disclaimers.
</para>
<para>
The combined work need only contain one copy of this License, and
multiple identical Invariant Sections may be replaced with a single
copy. If there are multiple Invariant Sections with the same name but
different contents, make the title of each such section unique by adding
at the end of it, in parentheses, the name of the original author or
publisher of that section if known, or else a unique number. Make the
same adjustment to the section titles in the list of Invariant Sections
in the license notice of the combined work.
</para>
<para>
In the combination, you must combine any sections Entitled
"History" in the various original documents, forming one section
Entitled "History"; likewise combine any sections Entitled
"Acknowledgements", and any sections Entitled "Dedications". You must
delete all sections Entitled "Endorsements".
</para>
</sect1>
<sect1
id=
"gfdl-6"
><title>
COLLECTIONS OF DOCUMENTS
</title>
<para>
You may make a collection consisting of the Document and other
documents released under this License, and replace the individual copies
of this License in the various documents with a single copy that is
included in the collection, provided that you follow the rules of this
License for verbatim copying of each of the documents in all other
respects.
</para>
<para>
You may extract a single document from such a collection, and
distribute it individually under this License, provided you insert a
copy of this License into the extracted document, and follow this
License in all other respects regarding verbatim copying of that
document.
</para>
</sect1>
<sect1
id=
"gfdl-7"
><title>
AGGREGATION WITH INDEPENDENT WORKS
</title>
<para>
A compilation of the Document or its derivatives with other
separate and independent documents or works, in or on a volume of a
storage or distribution medium, is called an "aggregate" if the
copyright resulting from the compilation is not used to limit the legal
rights of the compilation's users beyond what the individual works
permit. When the Document is included an aggregate, this License does
not apply to the other works in the aggregate which are not themselves
derivative works of the Document.
</para>
<para>
If the Cover Text requirement of section 3 is applicable to these
copies of the Document, then if the Document is less than one half of
the entire aggregate, the Document's Cover Texts may be placed on covers
that bracket the Document within the aggregate, or the electronic
equivalent of covers if the Document is in electronic form. Otherwise
they must appear on printed covers that bracket the whole
aggregate.
</para>
</sect1>
<sect1
id=
"gfdl-8"
><title>
TRANSLATION
</title>
<para>
Translation is considered a kind of modification, so you may
distribute translations of the Document under the terms of section 4.
Replacing Invariant Sections with translations requires special
permission from their copyright holders, but you may include
translations of some or all Invariant Sections in addition to the
original versions of these Invariant Sections. You may include a
translation of this License, and all the license notices in the
Document, and any Warranty Disclaimers, provided that you also include
the original English version of this License and the original versions
of those notices and disclaimers. In case of a disagreement between the
translation and the original version of this License or a notice or
disclaimer, the original version will prevail.
</para>
<para>
If a section in the Document is Entitled "Acknowledgements",
"Dedications", or "History", the requirement (section 4) to Preserve its
Title (section 1) will typically require changing the actual
title.
</para>
</sect1>
<sect1
id=
"gfdl-9"
><title>
TERMINATION
</title>
<para>
You may not copy, modify, sublicense, or distribute the Document
except as expressly provided for under this License. Any other attempt
to copy, modify, sublicense or distribute the Document is void, and will
automatically terminate your rights under this License. However,
parties who have received copies, or rights, from you under this License
will not have their licenses terminated so long as such parties remain
in full compliance.
</para>
</sect1>
<sect1
id=
"gfdl-10"
><title>
FUTURE REVISIONS OF THIS LICENSE
</title>
<para>
The Free Software Foundation may publish new, revised versions of
the GNU Free Documentation License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in
detail to address new problems or concerns. See
http://www.gnu.org/copyleft/.
</para>
<para>
Each version of the License is given a distinguishing version
number. If the Document specifies that a particular numbered version of
this License "or any later version" applies to it, you have the option
of following the terms and conditions either of that specified version
or of any later version that has been published (not as a draft) by the
Free Software Foundation. If the Document does not specify a version
number of this License, you may choose any version ever published (not
as a draft) by the Free Software Foundation.
</para>
</sect1>
<sect1
id=
"gfdl-addendum"
><title>
ADDENDUM: How to use this License for
your documents
</title>
<para>
To use this License in a document you have written, include a copy
of the License in the document and put the following copyright and
license notices just after the title page:
</para>
<blockquote
id=
"copyright-sample"
><para>
Copyright (c) YEAR YOUR NAME.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.2
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled "GNU
Free Documentation License".
</para></blockquote>
<para>
If you have Invariant Sections, Front-Cover Texts and Back-Cover
Texts, replace the "with...Texts." line with this:
</para>
<blockquote
id=
"inv-cover-sample"
><para>
with the Invariant Sections being LIST THEIR TITLES, with the
Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
</para></blockquote>
<para>
If you have Invariant Sections without Cover Texts, or some other
combination of the three, merge those two alternatives to suit the
situation.
</para>
<para>
If your document contains nontrivial examples of program code, we
recommend releasing these examples in parallel under your choice of free
software license, such as the GNU General Public License, to permit
their use in free software.
</para>
</sect1>
</appendix>
</book>
<!--
vim:syntax=sgml:sw=4
...
...
drivers/usb/host/uhci-debug.c
View file @
3a80046a
...
...
@@ -513,7 +513,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
}
#ifdef CONFIG_PROC_FS
#define MAX_OUTPUT (
PAGE_SIZE * 16
)
#define MAX_OUTPUT (
64 * 1024
)
static
struct
proc_dir_entry
*
uhci_proc_root
=
NULL
;
...
...
drivers/usb/net/cdc-ether.c
deleted
100644 → 0
View file @
e73291c3
// Portions of this file taken from
// Petko Manolov - Petkan (petkan@dce.bg)
// from his driver pegasus.c
/*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/types.h>
#include <linux/jiffies.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/usb.h>
#include <linux/module.h>
#include "cdc-ether.h"
static
const
char
*
version
=
__FILE__
": v0.98.5 22 Sep 2001 Brad Hards and another"
;
/* Take any CDC device, and sort it out in probe() */
static
struct
usb_device_id
CDCEther_ids
[]
=
{
{
USB_DEVICE_INFO
(
USB_CLASS_COMM
,
0
,
0
)
},
{
}
/* Terminating null entry */
};
/*
* module parameter that provides an alternate upper limit on the
* number of multicast filters we use, with a default to use all
* the filters available to us. Note that the actual number used
* is the lesser of this parameter and the number returned in the
* descriptor for the particular device. See Table 41 of the CDC
* spec for more info on the descriptor limit.
*/
static
int
multicast_filter_limit
=
32767
;
//////////////////////////////////////////////////////////////////////////////
// Callback routines from USB device /////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
static
void
read_bulk_callback
(
struct
urb
*
urb
,
struct
pt_regs
*
regs
)
{
ether_dev_t
*
ether_dev
=
urb
->
context
;
struct
net_device
*
net
;
int
count
=
urb
->
actual_length
,
res
;
struct
sk_buff
*
skb
;
// Sanity check
if
(
!
ether_dev
||
!
(
ether_dev
->
flags
&
CDC_ETHER_RUNNING
)
)
{
dbg
(
"BULK IN callback but driver is not active!"
);
return
;
}
net
=
ether_dev
->
net
;
if
(
!
netif_device_present
(
net
)
)
{
// Somebody killed our network interface...
return
;
}
if
(
ether_dev
->
flags
&
CDC_ETHER_RX_BUSY
)
{
// Are we already trying to receive a frame???
ether_dev
->
stats
.
rx_errors
++
;
dbg
(
"ether_dev Rx busy"
);
return
;
}
// We are busy, leave us alone!
ether_dev
->
flags
|=
CDC_ETHER_RX_BUSY
;
switch
(
urb
->
status
)
{
case
0
:
break
;
case
-
ETIMEDOUT
:
dbg
(
"no repsonse in BULK IN"
);
ether_dev
->
flags
&=
~
CDC_ETHER_RX_BUSY
;
break
;
default:
dbg
(
"%s: RX status %d"
,
net
->
name
,
urb
->
status
);
goto
goon
;
}
// Check to make sure we got some data...
if
(
!
count
)
{
// We got no data!!!
goto
goon
;
}
// Tell the kernel we want some memory
if
(
!
(
skb
=
dev_alloc_skb
(
count
))
)
{
// We got no receive buffer.
goto
goon
;
}
// Here's where it came from
skb
->
dev
=
net
;
// Now we copy it over
eth_copy_and_sum
(
skb
,
ether_dev
->
rx_buff
,
count
,
0
);
// Not sure
skb_put
(
skb
,
count
);
// Not sure here either
skb
->
protocol
=
eth_type_trans
(
skb
,
net
);
// Ship it off to the kernel
netif_rx
(
skb
);
// update out statistics
ether_dev
->
stats
.
rx_packets
++
;
ether_dev
->
stats
.
rx_bytes
+=
count
;
goon:
// Prep the USB to wait for another frame
usb_fill_bulk_urb
(
ether_dev
->
rx_urb
,
ether_dev
->
usb
,
usb_rcvbulkpipe
(
ether_dev
->
usb
,
ether_dev
->
data_ep_in
),
ether_dev
->
rx_buff
,
ether_dev
->
wMaxSegmentSize
,
read_bulk_callback
,
ether_dev
);
// Give this to the USB subsystem so it can tell us
// when more data arrives.
if
(
(
res
=
usb_submit_urb
(
ether_dev
->
rx_urb
,
GFP_ATOMIC
))
)
{
warn
(
"%s failed submint rx_urb %d"
,
__FUNCTION__
,
res
);
}
// We are no longer busy, show us the frames!!!
ether_dev
->
flags
&=
~
CDC_ETHER_RX_BUSY
;
}
static
void
write_bulk_callback
(
struct
urb
*
urb
,
struct
pt_regs
*
regs
)
{
ether_dev_t
*
ether_dev
=
urb
->
context
;
// Sanity check
if
(
!
ether_dev
||
!
(
ether_dev
->
flags
&
CDC_ETHER_RUNNING
)
)
{
// We are insane!!!
err
(
"write_bulk_callback: device not running"
);
return
;
}
// Do we still have a valid kernel network device?
if
(
!
netif_device_present
(
ether_dev
->
net
)
)
{
// Someone killed our network interface.
err
(
"write_bulk_callback: net device not present"
);
return
;
}
// Hmm... What on Earth could have happened???
if
(
urb
->
status
)
{
info
(
"%s: TX status %d"
,
ether_dev
->
net
->
name
,
urb
->
status
);
}
// Update the network interface and tell it we are
// ready for another frame
ether_dev
->
net
->
trans_start
=
jiffies
;
netif_wake_queue
(
ether_dev
->
net
);
}
//static void intr_callback( struct urb *urb )
//{
// ether_dev_t *ether_dev = urb->context;
// struct net_device *net;
// __u8 *d;
//
// if ( !ether_dev )
// return;
//
// switch ( urb->status ) {
// case 0:
// break;
// case -ENOENT:
// return;
// default:
// info("intr status %d", urb->status);
// }
//
// d = urb->transfer_buffer;
// net = ether_dev->net;
// if ( d[0] & 0xfc ) {
// ether_dev->stats.tx_errors++;
// if ( d[0] & TX_UNDERRUN )
// ether_dev->stats.tx_fifo_errors++;
// if ( d[0] & (EXCESSIVE_COL | JABBER_TIMEOUT) )
// ether_dev->stats.tx_aborted_errors++;
// if ( d[0] & LATE_COL )
// ether_dev->stats.tx_window_errors++;
// if ( d[0] & (NO_CARRIER | LOSS_CARRIER) )
// ether_dev->stats.tx_carrier_errors++;
// }
//}
//////////////////////////////////////////////////////////////////////////////
// Routines for turning net traffic on and off on the USB side ///////////////
//////////////////////////////////////////////////////////////////////////////
static
inline
int
enable_net_traffic
(
ether_dev_t
*
ether_dev
)
{
struct
usb_device
*
usb
=
ether_dev
->
usb
;
// Here would be the time to set the data interface to the configuration where
// it has two endpoints that use a protocol we can understand.
if
(
usb_set_interface
(
usb
,
ether_dev
->
data_bInterfaceNumber
,
ether_dev
->
data_bAlternateSetting_with_traffic
)
)
{
err
(
"usb_set_interface() failed"
);
err
(
"Attempted to set interface %d"
,
ether_dev
->
data_bInterfaceNumber
);
err
(
"To alternate setting %d"
,
ether_dev
->
data_bAlternateSetting_with_traffic
);
return
-
1
;
}
return
0
;
}
static
inline
void
disable_net_traffic
(
ether_dev_t
*
ether_dev
)
{
// The thing to do is to set the data interface to the alternate setting that has
// no endpoints. This is what the spec suggests.
if
(
ether_dev
->
data_interface_altset_num_without_traffic
>=
0
)
{
if
(
usb_set_interface
(
ether_dev
->
usb
,
ether_dev
->
data_bInterfaceNumber
,
ether_dev
->
data_bAlternateSetting_without_traffic
)
)
{
err
(
"usb_set_interface() failed"
);
}
}
else
{
// Some devices just may not support this...
warn
(
"No way to disable net traffic"
);
}
}
//////////////////////////////////////////////////////////////////////////////
// Callback routines for kernel Ethernet Device //////////////////////////////
//////////////////////////////////////////////////////////////////////////////
static
void
CDCEther_tx_timeout
(
struct
net_device
*
net
)
{
ether_dev_t
*
ether_dev
=
net
->
priv
;
// Sanity check
if
(
!
ether_dev
)
{
// Seems to be a case of insanity here
return
;
}
// Tell syslog we are hosed.
warn
(
"%s: Tx timed out."
,
net
->
name
);
// Tear the waiting frame off the list
ether_dev
->
tx_urb
->
transfer_flags
|=
URB_ASYNC_UNLINK
;
usb_unlink_urb
(
ether_dev
->
tx_urb
);
// Update statistics
ether_dev
->
stats
.
tx_errors
++
;
}
static
int
CDCEther_start_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
net
)
{
ether_dev_t
*
ether_dev
=
net
->
priv
;
int
res
;
// Tell the kernel, "No more frames 'til we are done
// with this one.'
netif_stop_queue
(
net
);
// Copy it from kernel memory to OUR memory
memcpy
(
ether_dev
->
tx_buff
,
skb
->
data
,
skb
->
len
);
// Fill in the URB for shipping it out.
usb_fill_bulk_urb
(
ether_dev
->
tx_urb
,
ether_dev
->
usb
,
usb_sndbulkpipe
(
ether_dev
->
usb
,
ether_dev
->
data_ep_out
),
ether_dev
->
tx_buff
,
ether_dev
->
wMaxSegmentSize
,
write_bulk_callback
,
ether_dev
);
// Tell the URB how much it will be transporting today
ether_dev
->
tx_urb
->
transfer_buffer_length
=
skb
->
len
;
/* Deal with the zero length problem, I hope */
ether_dev
->
tx_urb
->
transfer_flags
|=
URB_ZERO_PACKET
;
// Send the URB on its merry way.
if
((
res
=
usb_submit_urb
(
ether_dev
->
tx_urb
,
GFP_ATOMIC
)))
{
// Hmm... It didn't go. Tell someone...
warn
(
"failed tx_urb %d"
,
res
);
// update some stats...
ether_dev
->
stats
.
tx_errors
++
;
// and tell the kernel to give us another.
// Maybe we'll get it right next time.
netif_start_queue
(
net
);
}
else
{
// Okay, it went out.
// Update statistics
ether_dev
->
stats
.
tx_packets
++
;
ether_dev
->
stats
.
tx_bytes
+=
skb
->
len
;
// And tell the kernel when the last transmit occurred.
net
->
trans_start
=
jiffies
;
}
// We are done with the kernel's memory
dev_kfree_skb
(
skb
);
// We are done here.
return
0
;
}
static
struct
net_device_stats
*
CDCEther_netdev_stats
(
struct
net_device
*
net
)
{
// Easy enough!
return
&
((
ether_dev_t
*
)
net
->
priv
)
->
stats
;
}
static
int
CDCEther_open
(
struct
net_device
*
net
)
{
ether_dev_t
*
ether_dev
=
(
ether_dev_t
*
)
net
->
priv
;
int
res
;
// Turn on the USB and let the packets flow!!!
if
(
(
res
=
enable_net_traffic
(
ether_dev
))
)
{
err
(
"%s can't enable_net_traffic() - %d"
,
__FUNCTION__
,
res
);
return
-
EIO
;
}
// Prep a receive URB
usb_fill_bulk_urb
(
ether_dev
->
rx_urb
,
ether_dev
->
usb
,
usb_rcvbulkpipe
(
ether_dev
->
usb
,
ether_dev
->
data_ep_in
),
ether_dev
->
rx_buff
,
ether_dev
->
wMaxSegmentSize
,
read_bulk_callback
,
ether_dev
);
// Put it out there so the device can send us stuff
if
(
(
res
=
usb_submit_urb
(
ether_dev
->
rx_urb
,
GFP_KERNEL
))
)
{
// Hmm... Okay...
warn
(
"%s failed rx_urb %d"
,
__FUNCTION__
,
res
);
}
// Tell the kernel we are ready to start receiving from it
netif_start_queue
(
net
);
// We are up and running.
ether_dev
->
flags
|=
CDC_ETHER_RUNNING
;
// Let's get ready to move frames!!!
return
0
;
}
static
int
CDCEther_close
(
struct
net_device
*
net
)
{
ether_dev_t
*
ether_dev
=
net
->
priv
;
// We are no longer running.
ether_dev
->
flags
&=
~
CDC_ETHER_RUNNING
;
// Tell the kernel to stop sending us stuff
netif_stop_queue
(
net
);
// If we are not already unplugged, turn off USB
// traffic
if
(
!
(
ether_dev
->
flags
&
CDC_ETHER_UNPLUG
)
)
{
disable_net_traffic
(
ether_dev
);
}
// We don't need the URBs anymore.
usb_unlink_urb
(
ether_dev
->
rx_urb
);
usb_unlink_urb
(
ether_dev
->
tx_urb
);
usb_unlink_urb
(
ether_dev
->
intr_urb
);
// That's it. I'm done.
return
0
;
}
static
int
CDCEther_ioctl
(
struct
net_device
*
net
,
struct
ifreq
*
rq
,
int
cmd
)
{
//__u16 *data = (__u16 *)&rq->ifr_data;
//ether_dev_t *ether_dev = net->priv;
// No support here yet.
// Do we need support???
switch
(
cmd
)
{
case
SIOCDEVPRIVATE
:
return
-
EOPNOTSUPP
;
case
SIOCDEVPRIVATE
+
1
:
return
-
EOPNOTSUPP
;
case
SIOCDEVPRIVATE
+
2
:
//return 0;
return
-
EOPNOTSUPP
;
default:
return
-
EOPNOTSUPP
;
}
}
#if 0
static void CDC_SetEthernetPacketFilter (ether_dev_t *ether_dev)
{
usb_control_msg(ether_dev->usb,
usb_sndctrlpipe(ether_dev->usb, 0),
SET_ETHERNET_PACKET_FILTER, /* request */
USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE, /* request type */
cpu_to_le16(ether_dev->mode_flags), /* value */
cpu_to_le16((u16)ether_dev->comm_interface), /* index */
NULL,
0, /* size */
HZ); /* timeout */
}
#endif
static
void
CDCEther_set_multicast
(
struct
net_device
*
net
)
{
ether_dev_t
*
ether_dev
=
net
->
priv
;
int
i
;
__u8
*
buff
;
// Tell the kernel to stop sending us frames while we get this
// all set up.
// netif_stop_queue(net);
// FIXME: We hold xmit_lock. If you want to do the queue stuff you need
// to enable it from a completion handler
/* Note: do not reorder, GCC is clever about common statements. */
if
(
net
->
flags
&
IFF_PROMISC
)
{
/* Unconditionally log net taps. */
info
(
"%s: Promiscuous mode enabled"
,
net
->
name
);
ether_dev
->
mode_flags
=
MODE_FLAG_PROMISCUOUS
|
MODE_FLAG_ALL_MULTICAST
|
MODE_FLAG_DIRECTED
|
MODE_FLAG_BROADCAST
|
MODE_FLAG_MULTICAST
;
}
else
if
(
net
->
mc_count
>
ether_dev
->
wNumberMCFilters
)
{
/* Too many to filter perfectly -- accept all multicasts. */
info
(
"%s: set too many MC filters, using allmulti"
,
net
->
name
);
ether_dev
->
mode_flags
=
MODE_FLAG_ALL_MULTICAST
|
MODE_FLAG_DIRECTED
|
MODE_FLAG_BROADCAST
|
MODE_FLAG_MULTICAST
;
}
else
if
(
net
->
flags
&
IFF_ALLMULTI
)
{
/* Filter in software */
info
(
"%s: using allmulti"
,
net
->
name
);
ether_dev
->
mode_flags
=
MODE_FLAG_ALL_MULTICAST
|
MODE_FLAG_DIRECTED
|
MODE_FLAG_BROADCAST
|
MODE_FLAG_MULTICAST
;
}
else
{
/* do multicast filtering in hardware */
struct
dev_mc_list
*
mclist
;
info
(
"%s: set multicast filters"
,
net
->
name
);
ether_dev
->
mode_flags
=
MODE_FLAG_ALL_MULTICAST
|
MODE_FLAG_DIRECTED
|
MODE_FLAG_BROADCAST
|
MODE_FLAG_MULTICAST
;
buff
=
kmalloc
(
6
*
net
->
mc_count
,
GFP_ATOMIC
);
for
(
i
=
0
,
mclist
=
net
->
mc_list
;
mclist
&&
i
<
net
->
mc_count
;
i
++
,
mclist
=
mclist
->
next
)
{
memcpy
(
&
mclist
->
dmi_addr
,
&
buff
[
i
*
6
],
6
);
}
#if 0
usb_control_msg(ether_dev->usb,
// FIXME: We hold a spinlock. You must not use a synchronous API
usb_sndctrlpipe(ether_dev->usb, 0),
SET_ETHERNET_MULTICAST_FILTER, /* request */
USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE, /* request type */
cpu_to_le16(net->mc_count), /* value */
cpu_to_le16((u16)ether_dev->comm_interface), /* index */
buff,
(6* net->mc_count), /* size */
HZ); /* timeout */
#endif
kfree
(
buff
);
}
#if 0
CDC_SetEthernetPacketFilter(ether_dev);
#endif
// Tell the kernel to start giving frames to us again.
// netif_wake_queue(net);
}
//////////////////////////////////////////////////////////////////////////////
// Routines used to parse out the Functional Descriptors /////////////////////
//////////////////////////////////////////////////////////////////////////////
static
int
parse_header_functional_descriptor
(
int
*
bFunctionLength
,
int
bDescriptorType
,
int
bDescriptorSubtype
,
unsigned
char
*
data
,
ether_dev_t
*
ether_dev
,
int
*
requirements
)
{
// Check to make sure we haven't seen one of these already.
if
(
(
~*
requirements
)
&
REQ_HDR_FUNC_DESCR
)
{
err
(
"Multiple Header Functional Descriptors found."
);
return
-
1
;
}
// Is it the right size???
if
(
*
bFunctionLength
!=
5
)
{
info
(
"Invalid length in Header Functional Descriptor"
);
// This is a hack to get around a particular device (NO NAMES)
// It has this function length set to the length of the
// whole class-specific descriptor
*
bFunctionLength
=
5
;
}
// Nothing extremely useful here.
// We'll keep it for posterity
ether_dev
->
bcdCDC
=
data
[
0
]
+
(
data
[
1
]
<<
8
);
dbg
(
"Found Header descriptor, CDC version %x"
,
ether_dev
->
bcdCDC
);
// We've seen one of these
*
requirements
&=
~
REQ_HDR_FUNC_DESCR
;
// It's all good.
return
0
;
}
static
int
parse_union_functional_descriptor
(
int
*
bFunctionLength
,
int
bDescriptorType
,
int
bDescriptorSubtype
,
unsigned
char
*
data
,
ether_dev_t
*
ether_dev
,
int
*
requirements
)
{
// Check to make sure we haven't seen one of these already.
if
(
(
~*
requirements
)
&
REQ_UNION_FUNC_DESCR
)
{
err
(
"Multiple Union Functional Descriptors found."
);
return
-
1
;
}
// Is it the right size?
if
(
*
bFunctionLength
!=
5
)
{
// It is NOT the size we expected.
err
(
"Unsupported length in Union Functional Descriptor"
);
return
-
1
;
}
// Sanity check of sorts
if
(
ether_dev
->
comm_interface
!=
data
[
0
])
{
// This tells us that we are chasing the wrong comm
// interface or we are crazy or something else weird.
if
(
ether_dev
->
comm_interface
==
data
[
1
])
{
info
(
"Probably broken Union descriptor, fudging data interface"
);
// We'll need this in a few microseconds,
// so guess here, and hope for the best
ether_dev
->
data_interface
=
data
[
0
];
}
else
{
err
(
"Union Functional Descriptor is broken beyond repair"
);
return
-
1
;
}
}
else
{
// Descriptor is OK
// We'll need this in a few microseconds!
ether_dev
->
data_interface
=
data
[
1
];
}
// We've seen one of these now.
*
requirements
&=
~
REQ_UNION_FUNC_DESCR
;
// Done
return
0
;
}
static
int
parse_ethernet_functional_descriptor
(
int
*
bFunctionLength
,
int
bDescriptorType
,
int
bDescriptorSubtype
,
unsigned
char
*
data
,
ether_dev_t
*
ether_dev
,
int
*
requirements
)
{
// Check to make sure we haven't seen one of these already.
if
(
(
~*
requirements
)
&
REQ_ETH_FUNC_DESCR
)
{
err
(
"Multiple Ethernet Functional Descriptors found."
);
return
-
1
;
}
// Is it the right size?
if
(
*
bFunctionLength
!=
13
)
{
err
(
"Invalid length in Ethernet Networking Functional Descriptor"
);
return
-
1
;
}
// Lots of goodies from this one. They are all important.
ether_dev
->
iMACAddress
=
data
[
0
];
ether_dev
->
bmEthernetStatistics
=
data
[
1
]
+
(
data
[
2
]
<<
8
)
+
(
data
[
3
]
<<
16
)
+
(
data
[
4
]
<<
24
);
ether_dev
->
wMaxSegmentSize
=
data
[
5
]
+
(
data
[
6
]
<<
8
);
ether_dev
->
wNumberMCFilters
=
(
data
[
7
]
+
(
data
[
8
]
<<
8
))
&
0x00007FFF
;
if
(
ether_dev
->
wNumberMCFilters
>
multicast_filter_limit
)
{
ether_dev
->
wNumberMCFilters
=
multicast_filter_limit
;
}
ether_dev
->
bNumberPowerFilters
=
data
[
9
];
// We've seen one of these now.
*
requirements
&=
~
REQ_ETH_FUNC_DESCR
;
// That's all she wrote.
return
0
;
}
static
int
parse_protocol_unit_functional_descriptor
(
int
*
bFunctionLength
,
int
bDescriptorType
,
int
bDescriptorSubtype
,
unsigned
char
*
data
,
ether_dev_t
*
ether_dev
,
int
*
requirements
)
{
// There should only be one type if we are sane
if
(
bDescriptorType
!=
CS_INTERFACE
)
{
info
(
"Invalid bDescriptorType found."
);
return
-
1
;
}
// The Subtype tells the tale.
switch
(
bDescriptorSubtype
){
case
0x00
:
// Header Functional Descriptor
return
parse_header_functional_descriptor
(
bFunctionLength
,
bDescriptorType
,
bDescriptorSubtype
,
data
,
ether_dev
,
requirements
);
break
;
case
0x06
:
// Union Functional Descriptor
return
parse_union_functional_descriptor
(
bFunctionLength
,
bDescriptorType
,
bDescriptorSubtype
,
data
,
ether_dev
,
requirements
);
break
;
case
0x0F
:
// Ethernet Networking Functional Descriptor
return
parse_ethernet_functional_descriptor
(
bFunctionLength
,
bDescriptorType
,
bDescriptorSubtype
,
data
,
ether_dev
,
requirements
);
break
;
default:
// We don't support this at this time...
// However that doesn't necessarily indicate an error.
dbg
(
"Unexpected header type %x:"
,
bDescriptorSubtype
);
return
0
;
}
// How did we get here???
return
-
1
;
}
static
int
parse_ethernet_class_information
(
unsigned
char
*
data
,
int
length
,
ether_dev_t
*
ether_dev
)
{
int
loc
=
0
;
int
rc
;
int
bFunctionLength
;
int
bDescriptorType
;
int
bDescriptorSubtype
;
int
requirements
=
REQUIREMENTS_TOTAL
;
// As long as there is something here, we will try to parse it
while
(
loc
<
length
)
{
// Length
bFunctionLength
=
data
[
loc
];
loc
++
;
// Type
bDescriptorType
=
data
[
loc
];
loc
++
;
// Subtype
bDescriptorSubtype
=
data
[
loc
];
loc
++
;
// ship this off to be processed elsewhere.
rc
=
parse_protocol_unit_functional_descriptor
(
&
bFunctionLength
,
bDescriptorType
,
bDescriptorSubtype
,
&
data
[
loc
],
ether_dev
,
&
requirements
);
// Did it process okay?
if
(
rc
)
{
// Something was hosed somewhere.
// No need to continue;
err
(
"Bad descriptor parsing: %x"
,
rc
);
return
-
1
;
}
// We have already taken three bytes.
loc
+=
(
bFunctionLength
-
3
);
}
// Check to see if we got everything we need.
if
(
requirements
)
{
// We missed some of the requirements...
err
(
"Not all required functional descriptors present 0x%08X"
,
requirements
);
return
-
1
;
}
// We got everything.
return
0
;
}
//////////////////////////////////////////////////////////////////////////////
// Routine to check for the existence of the Functional Descriptors //////////
//////////////////////////////////////////////////////////////////////////////
static
int
find_and_parse_ethernet_class_information
(
struct
usb_device
*
device
,
ether_dev_t
*
ether_dev
)
{
struct
usb_host_config
*
conf
=
NULL
;
struct
usb_interface
*
comm_intf_group
=
NULL
;
struct
usb_host_interface
*
comm_intf
=
NULL
;
int
rc
=
-
1
;
// The assumption here is that find_ethernet_comm_interface
// and find_valid_configuration
// have already filled in the information about where to find
// the a valid commication interface.
conf
=
&
(
device
->
config
[
ether_dev
->
configuration_num
]
);
comm_intf_group
=
&
(
conf
->
interface
[
ether_dev
->
comm_interface
]
);
comm_intf
=
&
(
comm_intf_group
->
altsetting
[
ether_dev
->
comm_interface_altset_num
]
);
// Let's check and see if it has the extra information we need...
if
(
comm_intf
->
extralen
>
0
)
{
// This is where the information is SUPPOSED to be.
rc
=
parse_ethernet_class_information
(
comm_intf
->
extra
,
comm_intf
->
extralen
,
ether_dev
);
}
else
if
(
conf
->
extralen
>
0
)
{
// This is a hack. The spec says it should be at the interface
// location checked above. However I have seen it here also.
// This is the same device that requires the functional descriptor hack above
warn
(
"Ethernet information found at device configuration. This is broken."
);
rc
=
parse_ethernet_class_information
(
conf
->
extra
,
conf
->
extralen
,
ether_dev
);
}
else
{
// I don't know where else to look.
warn
(
"No ethernet information found."
);
rc
=
-
1
;
}
return
rc
;
}
//////////////////////////////////////////////////////////////////////////////
// Routines to verify the data interface /////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
static
int
get_data_interface_endpoints
(
struct
usb_device
*
device
,
ether_dev_t
*
ether_dev
)
{
struct
usb_host_config
*
conf
=
NULL
;
struct
usb_interface
*
data_intf_group
=
NULL
;
struct
usb_host_interface
*
data_intf
=
NULL
;
// Walk through and get to the data interface we are checking.
conf
=
&
(
device
->
config
[
ether_dev
->
configuration_num
]
);
data_intf_group
=
&
(
conf
->
interface
[
ether_dev
->
data_interface
]
);
data_intf
=
&
(
data_intf_group
->
altsetting
[
ether_dev
->
data_interface_altset_num_with_traffic
]
);
// Start out assuming we won't find anything we can use
ether_dev
->
data_ep_in
=
0
;
ether_dev
->
data_ep_out
=
0
;
// If these are not BULK endpoints, we don't want them
if
(
data_intf
->
endpoint
[
0
].
desc
.
bmAttributes
!=
0x02
)
{
return
-
1
;
}
if
(
data_intf
->
endpoint
[
1
].
desc
.
bmAttributes
!=
0x02
)
{
return
-
1
;
}
// Check the first endpoint to see if it is IN or OUT
if
(
data_intf
->
endpoint
[
0
].
desc
.
bEndpointAddress
&
0x80
)
{
// This endpoint is IN
ether_dev
->
data_ep_in
=
data_intf
->
endpoint
[
0
].
desc
.
bEndpointAddress
&
0x7F
;
}
else
{
// This endpoint is OUT
ether_dev
->
data_ep_out
=
data_intf
->
endpoint
[
0
].
desc
.
bEndpointAddress
&
0x7F
;
ether_dev
->
data_ep_out_size
=
data_intf
->
endpoint
[
0
].
desc
.
wMaxPacketSize
;
}
// Check the second endpoint to see if it is IN or OUT
if
(
data_intf
->
endpoint
[
1
].
desc
.
bEndpointAddress
&
0x80
)
{
// This endpoint is IN
ether_dev
->
data_ep_in
=
data_intf
->
endpoint
[
1
].
desc
.
bEndpointAddress
&
0x7F
;
}
else
{
// This endpoint is OUT
ether_dev
->
data_ep_out
=
data_intf
->
endpoint
[
1
].
desc
.
bEndpointAddress
&
0x7F
;
ether_dev
->
data_ep_out_size
=
data_intf
->
endpoint
[
1
].
desc
.
wMaxPacketSize
;
}
// Now make sure we got both an IN and an OUT
if
(
ether_dev
->
data_ep_in
&&
ether_dev
->
data_ep_out
)
{
// We did get both, we are in good shape...
info
(
"detected BULK OUT packets of size %d"
,
ether_dev
->
data_ep_out_size
);
return
0
;
}
return
-
1
;
}
static
int
verify_ethernet_data_interface
(
struct
usb_device
*
device
,
ether_dev_t
*
ether_dev
)
{
struct
usb_host_config
*
conf
=
NULL
;
struct
usb_interface
*
data_intf_group
=
NULL
;
struct
usb_interface_descriptor
*
data_intf
=
NULL
;
int
rc
=
-
1
;
int
status
;
int
altset_num
;
// The assumption here is that parse_ethernet_class_information()
// and find_valid_configuration()
// have already filled in the information about where to find
// a data interface
conf
=
&
(
device
->
config
[
ether_dev
->
configuration_num
]
);
data_intf_group
=
&
(
conf
->
interface
[
ether_dev
->
data_interface
]
);
// start out assuming we won't find what we are looking for.
ether_dev
->
data_interface_altset_num_with_traffic
=
-
1
;
ether_dev
->
data_bAlternateSetting_with_traffic
=
-
1
;
ether_dev
->
data_interface_altset_num_without_traffic
=
-
1
;
ether_dev
->
data_bAlternateSetting_without_traffic
=
-
1
;
// Walk through every possible setting for this interface until
// we find what makes us happy.
for
(
altset_num
=
0
;
altset_num
<
data_intf_group
->
num_altsetting
;
altset_num
++
)
{
data_intf
=
&
(
data_intf_group
->
altsetting
[
altset_num
].
desc
);
// Is this a data interface we like?
if
(
(
data_intf
->
bInterfaceClass
==
0x0A
)
&&
(
data_intf
->
bInterfaceSubClass
==
0x00
)
&&
(
data_intf
->
bInterfaceProtocol
==
0x00
)
)
{
if
(
data_intf
->
bNumEndpoints
==
2
)
{
// We are required to have one of these.
// An interface with 2 endpoints to send Ethernet traffic back and forth
// It actually may be possible that the device might only
// communicate in a vendor specific manner.
// That would not be very nice.
// We can add that one later.
ether_dev
->
data_bInterfaceNumber
=
data_intf
->
bInterfaceNumber
;
ether_dev
->
data_interface_altset_num_with_traffic
=
altset_num
;
ether_dev
->
data_bAlternateSetting_with_traffic
=
data_intf
->
bAlternateSetting
;
status
=
get_data_interface_endpoints
(
device
,
ether_dev
);
if
(
!
status
)
{
rc
=
0
;
}
}
if
(
data_intf
->
bNumEndpoints
==
0
)
{
// According to the spec we are SUPPOSED to have one of these
// In fact the device is supposed to come up in this state.
// However, I have seen a device that did not have such an interface.
// So it must be just optional for our driver...
ether_dev
->
data_bInterfaceNumber
=
data_intf
->
bInterfaceNumber
;
ether_dev
->
data_interface_altset_num_without_traffic
=
altset_num
;
ether_dev
->
data_bAlternateSetting_without_traffic
=
data_intf
->
bAlternateSetting
;
}
}
}
return
rc
;
}
//////////////////////////////////////////////////////////////////////////////
// Routine to find a communication interface /////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
static
int
find_ethernet_comm_interface
(
struct
usb_device
*
device
,
ether_dev_t
*
ether_dev
)
{
struct
usb_host_config
*
conf
=
NULL
;
struct
usb_interface
*
comm_intf_group
=
NULL
;
struct
usb_interface_descriptor
*
comm_intf
=
NULL
;
int
intf_num
;
int
altset_num
;
int
rc
;
conf
=
&
(
device
->
config
[
ether_dev
->
configuration_num
]
);
// We need to check and see if any of these interfaces are something we want.
// Walk through each interface one at a time
for
(
intf_num
=
0
;
intf_num
<
conf
->
desc
.
bNumInterfaces
;
intf_num
++
)
{
comm_intf_group
=
&
(
conf
->
interface
[
intf_num
]
);
// Now for each of those interfaces, check every possible
// alternate setting.
for
(
altset_num
=
0
;
altset_num
<
comm_intf_group
->
num_altsetting
;
altset_num
++
)
{
comm_intf
=
&
(
comm_intf_group
->
altsetting
[
altset_num
].
desc
);
// Is this a communication class of interface of the
// ethernet subclass variety.
if
(
(
comm_intf
->
bInterfaceClass
==
0x02
)
&&
(
comm_intf
->
bInterfaceSubClass
==
0x06
)
&&
(
comm_intf
->
bInterfaceProtocol
==
0x00
)
)
{
if
(
comm_intf
->
bNumEndpoints
==
1
)
{
// Good, we found one, we will try this one
// Fill in the structure...
ether_dev
->
comm_interface
=
intf_num
;
ether_dev
->
comm_bInterfaceNumber
=
comm_intf
->
bInterfaceNumber
;
ether_dev
->
comm_interface_altset_num
=
altset_num
;
ether_dev
->
comm_bAlternateSetting
=
comm_intf
->
bAlternateSetting
;
// Look for the Ethernet Functional Descriptors
rc
=
find_and_parse_ethernet_class_information
(
device
,
ether_dev
);
if
(
rc
)
{
// Nope this was no good after all.
continue
;
}
// Check that we really can talk to the data
// interface
// This includes # of endpoints, protocols,
// etc.
rc
=
verify_ethernet_data_interface
(
device
,
ether_dev
);
if
(
rc
)
{
// We got something we didn't like
continue
;
}
// This communication interface seems to give us everything
// we require. We have all the ethernet info we need.
// Let's get out of here and go home right now.
return
0
;
}
else
{
// bNumEndPoints != 1
// We found an interface that had the wrong number of
// endpoints but would have otherwise been okay
}
// end bNumEndpoints check.
}
// end interface specifics check.
}
// end for altset_num
}
// end for intf_num
return
-
1
;
}
//////////////////////////////////////////////////////////////////////////////
// Routine to go through all configurations and find one that ////////////////
// is an Ethernet Networking Device //////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
static
int
find_valid_configuration
(
struct
usb_device
*
device
,
ether_dev_t
*
ether_dev
)
{
struct
usb_host_config
*
conf
=
NULL
;
int
conf_num
;
int
rc
;
// We will try each and every possible configuration
for
(
conf_num
=
0
;
conf_num
<
device
->
descriptor
.
bNumConfigurations
;
conf_num
++
)
{
conf
=
&
(
device
->
config
[
conf_num
]
);
// Our first requirement : 2 interfaces
if
(
conf
->
desc
.
bNumInterfaces
!=
2
)
{
// I currently don't know how to handle devices with any number of interfaces
// other than 2.
continue
;
}
// This one passed our first check, fill in some
// useful data
ether_dev
->
configuration_num
=
conf_num
;
ether_dev
->
bConfigurationValue
=
conf
->
desc
.
bConfigurationValue
;
// Now run it through the ringers and see what comes
// out the other side.
rc
=
find_ethernet_comm_interface
(
device
,
ether_dev
);
// Check if we found an ethernet Communcation Device
if
(
!
rc
)
{
// We found one.
return
0
;
}
}
// None of the configurations suited us.
return
-
1
;
}
//////////////////////////////////////////////////////////////////////////////
// Routine that checks a given configuration to see if any driver ////////////
// has claimed any of the devices interfaces /////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
static
int
check_for_claimed_interfaces
(
struct
usb_host_config
*
config
)
{
struct
usb_interface
*
comm_intf_group
;
int
intf_num
;
// Go through all the interfaces and make sure none are
// claimed by anybody else.
for
(
intf_num
=
0
;
intf_num
<
config
->
desc
.
bNumInterfaces
;
intf_num
++
)
{
comm_intf_group
=
&
(
config
->
interface
[
intf_num
]
);
if
(
usb_interface_claimed
(
comm_intf_group
)
)
{
// Somebody has beat us to this guy.
// We can't change the configuration out from underneath of whoever
// is using this device, so we will go ahead and give up.
return
-
1
;
}
}
// We made it all the way through.
// I guess no one has claimed any of these interfaces.
return
0
;
}
//////////////////////////////////////////////////////////////////////////////
// Routines to ask for and set the kernel network interface's MAC address ////
// Used by driver's probe routine ////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
static
inline
unsigned
char
hex2dec
(
unsigned
char
digit
)
{
// Is there a standard way to do this???
// I have written this code TOO MANY times.
if
(
(
digit
>=
'0'
)
&&
(
digit
<=
'9'
)
)
{
return
(
digit
-
'0'
);
}
if
(
(
digit
>=
'a'
)
&&
(
digit
<=
'f'
)
)
{
return
(
digit
-
'a'
+
10
);
}
if
(
(
digit
>=
'A'
)
&&
(
digit
<=
'F'
)
)
{
return
(
digit
-
'A'
+
10
);
}
return
0
;
}
static
void
set_ethernet_addr
(
ether_dev_t
*
ether_dev
)
{
unsigned
char
mac_addr
[
6
];
int
i
;
int
len
;
unsigned
char
buffer
[
13
];
// Let's assume we don't get anything...
mac_addr
[
0
]
=
0x00
;
mac_addr
[
1
]
=
0x00
;
mac_addr
[
2
]
=
0x00
;
mac_addr
[
3
]
=
0x00
;
mac_addr
[
4
]
=
0x00
;
mac_addr
[
5
]
=
0x00
;
// Let's ask the device...
len
=
usb_string
(
ether_dev
->
usb
,
ether_dev
->
iMACAddress
,
buffer
,
13
);
// Sanity check!
if
(
len
!=
12
)
{
// You gotta love failing sanity checks
err
(
"Attempting to get MAC address returned %d bytes"
,
len
);
return
;
}
// Fill in the mac_addr
for
(
i
=
0
;
i
<
6
;
i
++
)
{
mac_addr
[
i
]
=
(
hex2dec
(
buffer
[
2
*
i
]
)
<<
4
)
+
hex2dec
(
buffer
[
2
*
i
+
1
]
);
}
// Now copy it over to the kernel's network driver.
memcpy
(
ether_dev
->
net
->
dev_addr
,
mac_addr
,
sizeof
(
mac_addr
)
);
}
//////////////////////////////////////////////////////////////////////////////
// Routine to print to syslog information about the driver ///////////////////
// Used by driver's probe routine ////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
static
void
log_device_info
(
ether_dev_t
*
ether_dev
)
{
int
len
;
int
string_num
;
unsigned
char
*
manu
=
NULL
;
unsigned
char
*
prod
=
NULL
;
unsigned
char
*
sern
=
NULL
;
unsigned
char
*
mac_addr
;
manu
=
kmalloc
(
256
,
GFP_KERNEL
);
prod
=
kmalloc
(
256
,
GFP_KERNEL
);
sern
=
kmalloc
(
256
,
GFP_KERNEL
);
if
(
!
manu
||
!
prod
||
!
sern
)
{
dbg
(
"no mem for log_device_info"
);
goto
fini
;
}
// Default empty strings in case we don't find a real one
manu
[
0
]
=
0x00
;
prod
[
0
]
=
0x00
;
sern
[
0
]
=
0x00
;
// Try to get the device Manufacturer
string_num
=
ether_dev
->
usb
->
descriptor
.
iManufacturer
;
if
(
string_num
)
{
// Put it into its buffer
len
=
usb_string
(
ether_dev
->
usb
,
string_num
,
manu
,
255
);
// Just to be safe
manu
[
len
]
=
0x00
;
}
// Try to get the device Product Name
string_num
=
ether_dev
->
usb
->
descriptor
.
iProduct
;
if
(
string_num
)
{
// Put it into its buffer
len
=
usb_string
(
ether_dev
->
usb
,
string_num
,
prod
,
255
);
// Just to be safe
prod
[
len
]
=
0x00
;
}
// Try to get the device Serial Number
string_num
=
ether_dev
->
usb
->
descriptor
.
iSerialNumber
;
if
(
string_num
)
{
// Put it into its buffer
len
=
usb_string
(
ether_dev
->
usb
,
string_num
,
sern
,
255
);
// Just to be safe
sern
[
len
]
=
0x00
;
}
// This makes it easier for us to print
mac_addr
=
ether_dev
->
net
->
dev_addr
;
// Now send everything we found to the syslog
info
(
"%s: %s %s %s %02X:%02X:%02X:%02X:%02X:%02X"
,
ether_dev
->
net
->
name
,
manu
,
prod
,
sern
,
mac_addr
[
0
],
mac_addr
[
1
],
mac_addr
[
2
],
mac_addr
[
3
],
mac_addr
[
4
],
mac_addr
[
5
]
);
fini:
kfree
(
manu
);
kfree
(
prod
);
kfree
(
sern
);
}
/* Forward declaration */
static
struct
usb_driver
CDCEther_driver
;
//////////////////////////////////////////////////////////////////////////////
// Module's probe routine ////////////////////////////////////////////////////
// claims interfaces if they are for an Ethernet CDC /////////////////////////
//////////////////////////////////////////////////////////////////////////////
static
int
CDCEther_probe
(
struct
usb_interface
*
intf
,
const
struct
usb_device_id
*
id
)
{
struct
usb_device
*
usb
=
interface_to_usbdev
(
intf
);
struct
net_device
*
net
;
ether_dev_t
*
ether_dev
;
int
rc
;
// First we should check the active configuration to see if
// any other driver has claimed any of the interfaces.
if
(
check_for_claimed_interfaces
(
usb
->
actconfig
)
)
{
// Someone has already put there grubby paws on this device.
// We don't want it now...
return
-
ENODEV
;
}
// We might be finding a device we can use.
// We all go ahead and allocate our storage space.
// We need to because we have to start filling in the data that
// we are going to need later.
if
(
!
(
ether_dev
=
kmalloc
(
sizeof
(
ether_dev_t
),
GFP_KERNEL
)))
{
err
(
"out of memory allocating device structure"
);
return
-
ENOMEM
;
}
// Zero everything out.
memset
(
ether_dev
,
0
,
sizeof
(
ether_dev_t
));
ether_dev
->
rx_urb
=
usb_alloc_urb
(
0
,
GFP_KERNEL
);
if
(
!
ether_dev
->
rx_urb
)
{
kfree
(
ether_dev
);
return
-
ENOMEM
;
}
ether_dev
->
tx_urb
=
usb_alloc_urb
(
0
,
GFP_KERNEL
);
if
(
!
ether_dev
->
tx_urb
)
{
usb_free_urb
(
ether_dev
->
rx_urb
);
kfree
(
ether_dev
);
return
-
ENOMEM
;
}
ether_dev
->
intr_urb
=
usb_alloc_urb
(
0
,
GFP_KERNEL
);
if
(
!
ether_dev
->
intr_urb
)
{
usb_free_urb
(
ether_dev
->
tx_urb
);
usb_free_urb
(
ether_dev
->
rx_urb
);
kfree
(
ether_dev
);
return
-
ENOMEM
;
}
// Let's see if we can find a configuration we can use.
rc
=
find_valid_configuration
(
usb
,
ether_dev
);
if
(
rc
)
{
// Nope we couldn't find one we liked.
// This device was not meant for us to control.
goto
error_all
;
}
// Now that we FOUND a configuration. let's try to make the
// device go into it.
if
(
usb_set_configuration
(
usb
,
ether_dev
->
bConfigurationValue
)
)
{
err
(
"usb_set_configuration() failed"
);
goto
error_all
;
}
// Now set the communication interface up as required.
if
(
usb_set_interface
(
usb
,
ether_dev
->
comm_bInterfaceNumber
,
ether_dev
->
comm_bAlternateSetting
))
{
err
(
"usb_set_interface() failed"
);
goto
error_all
;
}
// Only turn traffic on right now if we must...
if
(
ether_dev
->
data_interface_altset_num_without_traffic
>=
0
)
{
// We found an alternate setting for the data
// interface that allows us to turn off traffic.
// We should use it.
if
(
usb_set_interface
(
usb
,
ether_dev
->
data_bInterfaceNumber
,
ether_dev
->
data_bAlternateSetting_without_traffic
))
{
err
(
"usb_set_interface() failed"
);
goto
error_all
;
}
}
else
{
// We didn't find an alternate setting for the data
// interface that would let us turn off traffic.
// Oh well, let's go ahead and do what we must...
if
(
usb_set_interface
(
usb
,
ether_dev
->
data_bInterfaceNumber
,
ether_dev
->
data_bAlternateSetting_with_traffic
))
{
err
(
"usb_set_interface() failed"
);
goto
error_all
;
}
}
// Now we need to get a kernel Ethernet interface.
net
=
alloc_etherdev
(
0
);
if
(
!
net
)
{
// Hmm... The kernel is not sharing today...
// Fine, we didn't want it anyway...
err
(
"Unable to initialize ethernet device"
);
goto
error_all
;
}
// Now that we have an ethernet device, let's set it up
// (And I don't mean "set [it] up the bomb".)
net
->
priv
=
ether_dev
;
SET_MODULE_OWNER
(
net
);
net
->
open
=
CDCEther_open
;
net
->
stop
=
CDCEther_close
;
net
->
watchdog_timeo
=
CDC_ETHER_TX_TIMEOUT
;
net
->
tx_timeout
=
CDCEther_tx_timeout
;
// TX timeout function
net
->
do_ioctl
=
CDCEther_ioctl
;
net
->
hard_start_xmit
=
CDCEther_start_xmit
;
net
->
set_multicast_list
=
CDCEther_set_multicast
;
net
->
get_stats
=
CDCEther_netdev_stats
;
net
->
mtu
=
ether_dev
->
wMaxSegmentSize
-
14
;
// We'll keep track of this information for later...
ether_dev
->
usb
=
usb
;
ether_dev
->
net
=
net
;
// and don't forget the MAC address.
set_ethernet_addr
(
ether_dev
);
// Send a message to syslog about what we are handling
log_device_info
(
ether_dev
);
// I claim this interface to be a CDC Ethernet Networking device
usb_driver_claim_interface
(
&
CDCEther_driver
,
&
(
usb
->
config
[
ether_dev
->
configuration_num
].
interface
[
ether_dev
->
comm_interface
]),
ether_dev
);
// I claim this interface to be a CDC Ethernet Networking device
usb_driver_claim_interface
(
&
CDCEther_driver
,
&
(
usb
->
config
[
ether_dev
->
configuration_num
].
interface
[
ether_dev
->
data_interface
]),
ether_dev
);
// Does this REALLY do anything???
usb_get_dev
(
usb
);
// TODO - last minute HACK
ether_dev
->
comm_ep_in
=
5
;
if
(
register_netdev
(
net
)
!=
0
)
{
usb_put_dev
(
usb
);
goto
out
;
}
/* FIXME!!! This driver needs to be fixed to work with the new USB interface logic
* this is not the correct thing to be doing here, we need to set the interface
* driver specific data field.
*/
// Okay, we are finally done...
return
0
;
out:
usb_driver_release_interface
(
&
CDCEther_driver
,
&
(
usb
->
config
[
ether_dev
->
configuration_num
].
interface
[
ether_dev
->
comm_interface
])
);
usb_driver_release_interface
(
&
CDCEther_driver
,
&
(
usb
->
config
[
ether_dev
->
configuration_num
].
interface
[
ether_dev
->
data_interface
])
);
// bailing out with our tail between our knees
error_all:
usb_free_urb
(
ether_dev
->
tx_urb
);
usb_free_urb
(
ether_dev
->
rx_urb
);
usb_free_urb
(
ether_dev
->
intr_urb
);
kfree
(
ether_dev
);
return
-
EIO
;
}
//////////////////////////////////////////////////////////////////////////////
// Module's disconnect routine ///////////////////////////////////////////////
// Called when the driver is unloaded or the device is unplugged /////////////
// (Whichever happens first assuming the driver suceeded at its probe) ///////
//////////////////////////////////////////////////////////////////////////////
static
void
CDCEther_disconnect
(
struct
usb_interface
*
intf
)
{
ether_dev_t
*
ether_dev
=
usb_get_intfdata
(
intf
);
struct
usb_device
*
usb
;
usb_set_intfdata
(
intf
,
NULL
);
// Sanity check!!!
if
(
!
ether_dev
||
!
ether_dev
->
usb
)
{
// We failed. We are insane!!!
warn
(
"unregistering non-existant device"
);
return
;
}
// Make sure we fail the sanity check if we try this again.
ether_dev
->
usb
=
NULL
;
usb
=
interface_to_usbdev
(
intf
);
// It is possible that this function is called before
// the "close" function.
// This tells the close function we are already disconnected
ether_dev
->
flags
|=
CDC_ETHER_UNPLUG
;
// We don't need the network device any more
unregister_netdev
(
ether_dev
->
net
);
// For sanity checks
ether_dev
->
net
=
NULL
;
// I ask again, does this do anything???
usb_put_dev
(
usb
);
// We are done with this interface
usb_driver_release_interface
(
&
CDCEther_driver
,
&
(
usb
->
config
[
ether_dev
->
configuration_num
].
interface
[
ether_dev
->
comm_interface
])
);
// We are done with this interface too
usb_driver_release_interface
(
&
CDCEther_driver
,
&
(
usb
->
config
[
ether_dev
->
configuration_num
].
interface
[
ether_dev
->
data_interface
])
);
// No more tied up kernel memory
usb_free_urb
(
ether_dev
->
intr_urb
);
usb_free_urb
(
ether_dev
->
rx_urb
);
usb_free_urb
(
ether_dev
->
rx_urb
);
kfree
(
ether_dev
);
// This does no good, but it looks nice!
ether_dev
=
NULL
;
}
//////////////////////////////////////////////////////////////////////////////
// Driver info ///////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
static
struct
usb_driver
CDCEther_driver
=
{
.
owner
=
THIS_MODULE
,
.
name
=
"CDCEther"
,
.
probe
=
CDCEther_probe
,
.
disconnect
=
CDCEther_disconnect
,
.
id_table
=
CDCEther_ids
,
};
//////////////////////////////////////////////////////////////////////////////
// init and exit routines called when driver is installed and uninstalled ////
//////////////////////////////////////////////////////////////////////////////
int
__init
CDCEther_init
(
void
)
{
info
(
"%s"
,
version
);
return
usb_register
(
&
CDCEther_driver
);
}
void
__exit
CDCEther_exit
(
void
)
{
usb_deregister
(
&
CDCEther_driver
);
}
//////////////////////////////////////////////////////////////////////////////
// Module info ///////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
module_init
(
CDCEther_init
);
module_exit
(
CDCEther_exit
);
MODULE_AUTHOR
(
"Brad Hards and another"
);
MODULE_DESCRIPTION
(
"USB CDC Ethernet driver"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_PARM
(
multicast_filter_limit
,
"i"
);
MODULE_PARM_DESC
(
multicast_filter_limit
,
"CDCEther maximum number of filtered multicast addresses"
);
MODULE_DEVICE_TABLE
(
usb
,
CDCEther_ids
);
//////////////////////////////////////////////////////////////////////////////
// End of file ///////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
drivers/usb/net/cdc-ether.h
deleted
100644 → 0
View file @
e73291c3
// Portions of this file taken from
// Petko Manolov - Petkan (petkan@dce.bg)
// from his driver pegasus.h
/*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define CS_INTERFACE 0x24
#define CDC_ETHER_MAX_MTU 1536
#define CDC_ETHER_PRESENT 0x00000001
#define CDC_ETHER_RUNNING 0x00000002
#define CDC_ETHER_TX_BUSY 0x00000004
#define CDC_ETHER_RX_BUSY 0x00000008
#define CDC_ETHER_UNPLUG 0x00000040
#define CDC_ETHER_TX_TIMEOUT (HZ*10)
#define TX_UNDERRUN 0x80
#define EXCESSIVE_COL 0x40
#define LATE_COL 0x20
#define NO_CARRIER 0x10
#define LOSS_CARRIER 0x08
#define JABBER_TIMEOUT 0x04
#define CDC_ETHER_REQT_READ 0xc0
#define CDC_ETHER_REQT_WRITE 0x40
#define CDC_ETHER_REQ_GET_REGS 0xf0
#define CDC_ETHER_REQ_SET_REGS 0xf1
#define CDC_ETHER_REQ_SET_REG PIPERIDER_REQ_SET_REGS
#define L1_ALIGN(x) x __attribute__((aligned(L1_CACHE_BYTES)))
#define MODE_FLAG_PROMISCUOUS (1<<0)
#define MODE_FLAG_ALL_MULTICAST (1<<1)
#define MODE_FLAG_DIRECTED (1<<2)
#define MODE_FLAG_BROADCAST (1<<3)
#define MODE_FLAG_MULTICAST (1<<4)
#define SET_ETHERNET_MULTICAST_FILTER 0x40
#define SET_ETHERNET_PACKET_FILTER 0x43
typedef
struct
_ether_dev_t
{
struct
usb_device
*
usb
;
struct
net_device
*
net
;
struct
net_device_stats
stats
;
unsigned
flags
;
int
configuration_num
;
int
bConfigurationValue
;
int
comm_interface
;
int
comm_bInterfaceNumber
;
int
comm_interface_altset_num
;
int
comm_bAlternateSetting
;
int
comm_ep_in
;
int
data_interface
;
int
data_bInterfaceNumber
;
int
data_interface_altset_num_with_traffic
;
int
data_bAlternateSetting_with_traffic
;
int
data_interface_altset_num_without_traffic
;
int
data_bAlternateSetting_without_traffic
;
int
data_ep_in
;
int
data_ep_out
;
int
data_ep_out_size
;
__u16
bcdCDC
;
__u8
iMACAddress
;
__u32
bmEthernetStatistics
;
__u16
wMaxSegmentSize
;
__u16
mode_flags
;
__u16
wNumberMCFilters
;
__u8
bNumberPowerFilters
;
int
intr_interval
;
struct
urb
*
rx_urb
,
*
tx_urb
,
*
intr_urb
;
unsigned
char
L1_ALIGN
(
rx_buff
[
CDC_ETHER_MAX_MTU
]);
unsigned
char
L1_ALIGN
(
tx_buff
[
CDC_ETHER_MAX_MTU
]);
unsigned
char
L1_ALIGN
(
intr_buff
[
8
]);
}
ether_dev_t
;
#define REQ_HDR_FUNC_DESCR 0x0001
#define REQ_UNION_FUNC_DESCR 0x0002
#define REQ_ETH_FUNC_DESCR 0x0004
#define REQUIREMENTS_TOTAL 0x0007
drivers/usb/net/kaweth.c
View file @
3a80046a
...
...
@@ -56,9 +56,11 @@
#include <linux/usb.h>
#include <linux/types.h>
#include <linux/ethtool.h>
#include <linux/pci.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
#include <asm/byteorder.h>
#include <asm/dma-mapping.h>
#define DEBUG
...
...
@@ -215,8 +217,10 @@ struct kaweth_device
__u32
status
;
int
end
;
int
removed
;
int
suspend_lowmem
;
int
suspend_lowmem_rx
;
int
suspend_lowmem_ctrl
;
int
linkstate
;
struct
work_struct
lowmem_work
;
struct
usb_device
*
dev
;
struct
net_device
*
net
;
...
...
@@ -475,14 +479,29 @@ static int kaweth_resubmit_rx_urb(struct kaweth_device *, int);
/****************************************************************
int_callback
*****************************************************************/
static
void
kaweth_resubmit_int_urb
(
struct
kaweth_device
*
kaweth
,
int
mf
)
{
int
status
;
status
=
usb_submit_urb
(
kaweth
->
irq_urb
,
mf
);
if
(
unlikely
(
status
==
-
ENOMEM
))
{
kaweth
->
suspend_lowmem_ctrl
=
1
;
schedule_delayed_work
(
&
kaweth
->
lowmem_work
,
HZ
/
4
);
}
else
{
kaweth
->
suspend_lowmem_ctrl
=
0
;
}
if
(
status
)
err
(
"can't resubmit intr, %s-%s, status %d"
,
kaweth
->
dev
->
bus
->
bus_name
,
kaweth
->
dev
->
devpath
,
status
);
}
static
void
int_callback
(
struct
urb
*
u
,
struct
pt_regs
*
regs
)
{
struct
kaweth_device
*
kaweth
=
u
->
context
;
int
act_state
,
status
;
/* we abuse the interrupt urb for rebsubmitting under low memory saving a timer */
if
(
kaweth
->
suspend_lowmem
)
kaweth_resubmit_rx_urb
(
kaweth
,
GFP_ATOMIC
);
int
act_state
;
switch
(
u
->
status
)
{
case
0
:
/* success */
...
...
@@ -506,13 +525,24 @@ static void int_callback(struct urb *u, struct pt_regs *regs)
kaweth
->
linkstate
=
act_state
;
}
resubmit:
status
=
usb_submit_urb
(
u
,
SLAB_ATOMIC
);
if
(
status
)
err
(
"can't resubmit intr, %s-%s, status %d"
,
kaweth
->
dev
->
bus
->
bus_name
,
kaweth
->
dev
->
devpath
,
status
);
kaweth_resubmit_int_urb
(
kaweth
,
GFP_ATOMIC
);
}
static
void
kaweth_resubmit_tl
(
void
*
d
)
{
struct
kaweth_device
*
kaweth
=
(
struct
kaweth_device
*
)
d
;
if
(
kaweth
->
status
|
KAWETH_STATUS_CLOSING
)
return
;
if
(
kaweth
->
suspend_lowmem_rx
)
kaweth_resubmit_rx_urb
(
kaweth
,
GFP_NOIO
);
if
(
kaweth
->
suspend_lowmem_ctrl
)
kaweth_resubmit_int_urb
(
kaweth
,
GFP_NOIO
);
}
/****************************************************************
* kaweth_resubmit_rx_urb
****************************************************************/
...
...
@@ -532,11 +562,13 @@ static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth,
kaweth
->
rx_urb
->
transfer_dma
=
kaweth
->
rxbufferhandle
;
if
((
result
=
usb_submit_urb
(
kaweth
->
rx_urb
,
mem_flags
)))
{
if
(
result
==
-
ENOMEM
)
kaweth
->
suspend_lowmem
=
1
;
if
(
result
==
-
ENOMEM
)
{
kaweth
->
suspend_lowmem_rx
=
1
;
schedule_delayed_work
(
&
kaweth
->
lowmem_work
,
HZ
/
4
);
}
kaweth_err
(
"resubmitting rx_urb %d failed"
,
result
);
}
else
{
kaweth
->
suspend_lowmem
=
0
;
kaweth
->
suspend_lowmem
_rx
=
0
;
}
return
result
;
...
...
@@ -665,6 +697,13 @@ static int kaweth_close(struct net_device *net)
usb_unlink_urb
(
kaweth
->
irq_urb
);
usb_unlink_urb
(
kaweth
->
rx_urb
);
flush_scheduled_work
();
/* a scheduled work may have resubmitted,
we hit them again */
usb_unlink_urb
(
kaweth
->
irq_urb
);
usb_unlink_urb
(
kaweth
->
rx_urb
);
kaweth
->
status
&=
~
KAWETH_STATUS_CLOSING
;
return
0
;
...
...
@@ -1075,10 +1114,15 @@ static int kaweth_probe(
memset
(
&
kaweth
->
stats
,
0
,
sizeof
(
kaweth
->
stats
));
INIT_WORK
(
&
kaweth
->
lowmem_work
,
kaweth_resubmit_tl
,
(
void
*
)
kaweth
);
SET_MODULE_OWNER
(
netdev
);
usb_set_intfdata
(
intf
,
kaweth
);
if
(
dma_supported
(
&
intf
->
dev
,
0xffffffffffffffffULL
))
kaweth
->
net
->
features
|=
NETIF_F_HIGHDMA
;
if
(
register_netdev
(
netdev
)
!=
0
)
{
kaweth_err
(
"Error calling init_etherdev."
);
goto
err_intfdata
;
...
...
@@ -1092,7 +1136,6 @@ static int kaweth_probe(
err_intfdata:
usb_set_intfdata
(
intf
,
NULL
);
err_all:
usb_buffer_free
(
kaweth
->
dev
,
KAWETH_BUF_SIZE
,
(
void
*
)
kaweth
->
rx_buf
,
kaweth
->
rxbufferhandle
);
err_all_but_rxbuf:
usb_buffer_free
(
kaweth
->
dev
,
INTBUFFERSIZE
,
(
void
*
)
kaweth
->
intbuffer
,
kaweth
->
intbufferhandle
);
...
...
drivers/usb/serial/io_edgeport.c
View file @
3a80046a
...
...
@@ -412,6 +412,7 @@ struct divisor_table_entry {
// MCR.7 = 0.
//
static
struct
divisor_table_entry
divisor_table
[]
=
{
{
50
,
4608
},
{
75
,
3072
},
{
110
,
2095
},
/* 2094.545455 => 230450 => .0217 % over */
{
134
,
1713
},
/* 1713.011152 => 230398.5 => .00065% under */
...
...
@@ -2591,7 +2592,7 @@ static int calc_baud_rate_divisor (int baudrate, int *divisor)
// We have tried all of the standard baud rates
// lets try to calculate the divisor for this baud rate
// Make sure the baud rate is reasonable
if
(
baudrate
>
75
&&
baudrate
<
230400
)
{
if
(
baudrate
<
230400
)
{
// get divisor
custom
=
(
__u16
)(
230400L
/
baudrate
);
...
...
drivers/usb/serial/pl2303.c
View file @
3a80046a
...
...
@@ -537,16 +537,20 @@ static int pl2303_tiocmget (struct usb_serial_port *port, struct file *file)
struct
pl2303_private
*
priv
=
usb_get_serial_port_data
(
port
);
unsigned
long
flags
;
unsigned
int
mcr
;
unsigned
int
status
;
unsigned
int
result
;
dbg
(
"%s (%d)"
,
__FUNCTION__
,
port
->
number
);
spin_lock_irqsave
(
&
priv
->
lock
,
flags
);
mcr
=
priv
->
line_control
;
status
=
priv
->
line_status
;
spin_unlock_irqrestore
(
&
priv
->
lock
,
flags
);
result
=
((
mcr
&
CONTROL_DTR
)
?
TIOCM_DTR
:
0
)
|
((
mcr
&
CONTROL_RTS
)
?
TIOCM_RTS
:
0
);
|
((
mcr
&
CONTROL_RTS
)
?
TIOCM_RTS
:
0
)
|
((
status
&
UART_CTS
)
?
TIOCM_CTS
:
0
)
|
((
status
&
UART_DSR
)
?
TIOCM_DSR
:
0
);
dbg
(
"%s - result = %x"
,
__FUNCTION__
,
result
);
...
...
drivers/usb/serial/visor.c
View file @
3a80046a
...
...
@@ -12,6 +12,10 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
* (06/03/2003) Judd Montgomery <judd at jpilot.org>
* Added support for module parameter options for untested/unknown
* devices.
*
* (03/09/2003) gkh
* Added support for the Sony Clie NZ90V device. Thanks to Martin Brachtl
* <brachtl@redgrep.cz> for the information.
...
...
@@ -188,6 +192,9 @@ static int treo_attach (struct usb_serial *serial);
static
int
palm_os_3_probe
(
struct
usb_serial
*
serial
,
const
struct
usb_device_id
*
id
);
static
int
palm_os_4_probe
(
struct
usb_serial
*
serial
,
const
struct
usb_device_id
*
id
);
/* Parameters that may be passed into the module. */
static
int
vendor
=
-
1
;
static
int
product
=
-
1
;
static
struct
usb_device_id
id_table
[]
=
{
{
USB_DEVICE
(
HANDSPRING_VENDOR_ID
,
HANDSPRING_VISOR_ID
),
...
...
@@ -223,6 +230,7 @@ static struct usb_device_id id_table [] = {
.
driver_info
=
(
kernel_ulong_t
)
&
palm_os_4_probe
},
{
USB_DEVICE
(
SONY_VENDOR_ID
,
SONY_CLIE_NZ90V_ID
),
.
driver_info
=
(
kernel_ulong_t
)
&
palm_os_4_probe
},
{
},
/* optional parameter entry */
{
}
/* Terminating entry */
};
...
...
@@ -250,6 +258,7 @@ static struct usb_device_id id_table_combined [] = {
{
USB_DEVICE
(
SONY_VENDOR_ID
,
SONY_CLIE_4_1_ID
)
},
{
USB_DEVICE
(
SONY_VENDOR_ID
,
SONY_CLIE_NX60_ID
)
},
{
USB_DEVICE
(
SONY_VENDOR_ID
,
SONY_CLIE_NZ90V_ID
)
},
{
},
/* optional parameter entry */
{
}
/* Terminating entry */
};
...
...
@@ -942,6 +951,33 @@ static void visor_set_termios (struct usb_serial_port *port, struct termios *old
static
int
__init
visor_init
(
void
)
{
int
i
;
/* Only if parameters were passed to us */
if
((
vendor
>
0
)
&&
(
product
>
0
))
{
struct
usb_device_id
usb_dev_temp
[]
=
{{
USB_DEVICE
(
vendor
,
product
),
.
driver_info
=
(
kernel_ulong_t
)
&
palm_os_4_probe
}};
/* Find the last entry in id_table */
for
(
i
=
0
;
;
i
++
)
{
if
(
id_table
[
i
].
idVendor
==
0
)
{
id_table
[
i
]
=
usb_dev_temp
[
0
];
break
;
}
}
/* Find the last entry in id_table_combined */
for
(
i
=
0
;
;
i
++
)
{
if
(
id_table_combined
[
i
].
idVendor
==
0
)
{
id_table_combined
[
i
]
=
usb_dev_temp
[
0
];
break
;
}
}
info
(
"Untested USB device specified at time of module insertion"
);
info
(
"Warning: This is not guaranteed to work"
);
info
(
"Using a newer kernel is preferred to this method"
);
info
(
"Adding Palm OS protocol 4.x support for unknown device: 0x%x/0x%x"
,
vendor
,
product
);
}
usb_serial_register
(
&
handspring_device
);
usb_serial_register
(
&
clie_3_5_device
);
usb_register
(
&
visor_driver
);
...
...
@@ -969,3 +1005,7 @@ MODULE_LICENSE("GPL");
MODULE_PARM
(
debug
,
"i"
);
MODULE_PARM_DESC
(
debug
,
"Debug enabled or not"
);
MODULE_PARM
(
vendor
,
"i"
);
MODULE_PARM_DESC
(
vendor
,
"User specified vendor ID"
);
MODULE_PARM
(
product
,
"i"
);
MODULE_PARM_DESC
(
product
,
"User specified product ID"
);
drivers/usb/storage/initializers.c
View file @
3a80046a
...
...
@@ -41,6 +41,7 @@
#include <linux/errno.h>
#include "initializers.h"
#include "debug.h"
#include "transport.h"
/* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target
* mode */
...
...
@@ -59,4 +60,50 @@ int usb_stor_euscsi_init(struct us_data *us)
return
0
;
}
/* This function is required to activate all four slots on the UCR-61S2B
* flash reader */
int
usb_stor_ucr61s2b_init
(
struct
us_data
*
us
)
{
struct
bulk_cb_wrap
*
bcb
;
struct
bulk_cs_wrap
*
bcs
;
int
res
,
partial
;
bcb
=
kmalloc
(
sizeof
*
bcb
,
in_interrupt
()
?
GFP_ATOMIC
:
GFP_NOIO
);
if
(
!
bcb
)
{
return
(
-
1
);
}
bcs
=
kmalloc
(
sizeof
*
bcs
,
in_interrupt
()
?
GFP_ATOMIC
:
GFP_NOIO
);
if
(
!
bcs
)
{
kfree
(
bcb
);
return
(
-
1
);
}
US_DEBUGP
(
"Sending UCR-61S2B initialization packet...
\n
"
);
bcb
->
Signature
=
cpu_to_le32
(
US_BULK_CB_SIGN
);
bcb
->
Tag
=
0
;
bcb
->
DataTransferLength
=
cpu_to_le32
(
0
);
bcb
->
Flags
=
bcb
->
Lun
=
0
;
bcb
->
Length
=
sizeof
(
UCR61S2B_INIT
);
memset
(
bcb
->
CDB
,
0
,
sizeof
(
bcb
->
CDB
));
memcpy
(
bcb
->
CDB
,
UCR61S2B_INIT
,
sizeof
(
UCR61S2B_INIT
));
res
=
usb_stor_bulk_transfer_buf
(
us
,
us
->
send_bulk_pipe
,
bcb
,
US_BULK_CB_WRAP_LEN
,
&
partial
);
US_DEBUGP
(
"-- result is %d
\n
"
,
res
);
kfree
(
bcb
);
if
(
res
)
{
kfree
(
bcs
);
return
(
res
);
}
res
=
usb_stor_bulk_transfer_buf
(
us
,
us
->
recv_bulk_pipe
,
bcs
,
US_BULK_CS_WRAP_LEN
,
&
partial
);
US_DEBUGP
(
"-- result of status read is %d
\n
"
,
res
);
kfree
(
bcs
);
return
(
res
?
-
1
:
0
);
}
drivers/usb/storage/initializers.h
View file @
3a80046a
...
...
@@ -48,3 +48,9 @@ int usb_stor_euscsi_init(struct us_data *us);
#ifdef CONFIG_USB_STORAGE_SDDR09
int
sddr09_init
(
struct
us_data
*
us
);
#endif
#define UCR61S2B_INIT "\xec\x0a\x06\x00$PCCHIPS"
/* This function is required to activate all four slots on the UCR-61S2B
* flash reader */
int
usb_stor_ucr61s2b_init
(
struct
us_data
*
us
);
drivers/usb/storage/unusual_devs.h
View file @
3a80046a
...
...
@@ -595,6 +595,16 @@ UNUSUAL_DEV( 0x0a16, 0x8888, 0x0100, 0x0100,
US_SC_SCSI
,
US_PR_BULK
,
NULL
,
US_FL_FIX_INQUIRY
),
/* Pentax Optio S digital camera
* adapted from http://www2.goldfisch.at/knowledge/233
* (Peter Pilsl <pilsl@goldfisch.at>)
* by Christoph Weidemann <cweidema@indiana.edu> */
UNUSUAL_DEV
(
0x0a17
,
0x0006
,
0x0000
,
0xffff
,
"Pentax"
,
"Optio S"
,
US_SC_8070
,
US_PR_CB
,
NULL
,
US_FL_MODE_XLATE
|
US_FL_FIX_INQUIRY
),
#ifdef CONFIG_USB_STORAGE_ISD200
UNUSUAL_DEV
(
0x0bf6
,
0xa001
,
0x0100
,
0x0110
,
"ATI"
,
...
...
@@ -610,6 +620,16 @@ UNUSUAL_DEV( 0x1065, 0x2136, 0x0000, 0x0001,
US_SC_SCSI
,
US_PR_BULK
,
NULL
,
US_FL_MODE_XLATE
|
US_FL_FIX_INQUIRY
),
/* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu>
* Tested on hardware version 1.10.
* Entry is needed only for the initializer function override.
*/
UNUSUAL_DEV
(
0x1019
,
0x0c55
,
0x0000
,
0x9999
,
"Desknote"
,
"UCR-61S2B"
,
US_SC_DEVICE
,
US_PR_DEVICE
,
usb_stor_ucr61s2b_init
,
0
),
/* Reported by Dan Pilone <pilone@slac.com>
* The device needs the flags only.
* Also reported by Brian Hall <brihall@pcisys.net>, again for flags.
...
...
include/linux/usb_gadget.h
View file @
3a80046a
...
...
@@ -10,11 +10,6 @@
* All Rights Reserved.
*
* This software is licensed under the GNU GPL version 2.
*
* ALTERNATIVELY, the kernel API documentation which is included in this
* software may also be licenced under the "GNU Free Documentation
* License" (version 1.2 or, at your choice, any later version), when
* used as part of the "USB Gadget API for Linux" documentation.
*/
#ifndef __LINUX_USB_GADGET_H
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment