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
Kirill Smelkov
linux
Commits
1a569433
Commit
1a569433
authored
May 23, 2003
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://kernel.bkbits.net/gregkh/linux/linus-2.5
into penguin.transmeta.com:/home/torvalds/v2.5/linux
parents
47e4079c
85b55d6f
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
522 additions
and
472 deletions
+522
-472
drivers/usb/core/message.c
drivers/usb/core/message.c
+3
-1
drivers/usb/gadget/ether.c
drivers/usb/gadget/ether.c
+1
-1
drivers/usb/gadget/net2280.c
drivers/usb/gadget/net2280.c
+53
-43
drivers/usb/gadget/net2280.h
drivers/usb/gadget/net2280.h
+9
-0
drivers/usb/gadget/zero.c
drivers/usb/gadget/zero.c
+2
-5
drivers/usb/host/uhci-hcd.c
drivers/usb/host/uhci-hcd.c
+130
-34
drivers/usb/host/uhci-hcd.h
drivers/usb/host/uhci-hcd.h
+28
-1
drivers/usb/misc/speedtch.c
drivers/usb/misc/speedtch.c
+293
-386
drivers/usb/storage/transport.c
drivers/usb/storage/transport.c
+1
-1
drivers/usb/storage/transport.h
drivers/usb/storage/transport.h
+2
-0
No files found.
drivers/usb/core/message.c
View file @
1a569433
...
...
@@ -672,6 +672,7 @@ void usb_set_maxpacket(struct usb_device *dev)
{
int
i
,
b
;
/* NOTE: affects all endpoints _except_ ep0 */
for
(
i
=
0
;
i
<
dev
->
actconfig
->
desc
.
bNumInterfaces
;
i
++
)
{
struct
usb_interface
*
ifp
=
dev
->
actconfig
->
interface
+
i
;
struct
usb_host_interface
*
as
=
ifp
->
altsetting
+
ifp
->
act_altsetting
;
...
...
@@ -862,6 +863,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
usb_settoggle
(
dev
,
ep
,
out
,
0
);
(
out
?
dev
->
epmaxpacketout
:
dev
->
epmaxpacketin
)
[
ep
]
=
iface_as
->
endpoint
[
i
].
desc
.
wMaxPacketSize
;
usb_endpoint_running
(
dev
,
ep
,
out
);
}
return
0
;
...
...
@@ -916,7 +918,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
/* if it's already configured, clear out old state first. */
if
(
dev
->
state
!=
USB_STATE_ADDRESS
&&
disable
)
{
for
(
i
=
0
;
i
<
15
;
i
++
)
{
for
(
i
=
1
/* skip ep0 */
;
i
<
15
;
i
++
)
{
disable
(
dev
,
i
);
disable
(
dev
,
USB_DIR_IN
|
i
);
}
...
...
drivers/usb/gadget/ether.c
View file @
1a569433
...
...
@@ -1107,7 +1107,7 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
}
/* respond with data transfer before status phase? */
if
(
value
>
0
)
{
if
(
value
>
=
0
)
{
req
->
length
=
value
;
value
=
usb_ep_queue
(
gadget
->
ep0
,
req
,
GFP_ATOMIC
);
if
(
value
<
0
)
{
...
...
drivers/usb/gadget/net2280.c
View file @
1a569433
...
...
@@ -393,7 +393,7 @@ net2280_free_request (struct usb_ep *_ep, struct usb_request *_req)
struct
net2280_request
*
req
;
ep
=
container_of
(
_ep
,
struct
net2280_ep
,
ep
);
if
(
!
ep
||
!
_req
)
if
(
!
_
ep
||
!
_req
)
return
;
req
=
container_of
(
_req
,
struct
net2280_request
,
req
);
...
...
@@ -442,7 +442,7 @@ net2280_alloc_buffer (
struct
net2280_ep
*
ep
;
ep
=
container_of
(
_ep
,
struct
net2280_ep
,
ep
);
if
(
!
ep
||
(
!
ep
->
desc
&&
ep
->
num
!=
0
))
if
(
!
_
ep
||
(
!
ep
->
desc
&&
ep
->
num
!=
0
))
return
0
;
*
dma
=
DMA_ADDR_INVALID
;
...
...
@@ -561,16 +561,12 @@ static void out_flush (struct net2280_ep *ep)
writel
((
1
<<
FIFO_FLUSH
),
statp
);
mb
();
tmp
=
readl
(
statp
);
if
(
tmp
&
(
1
<<
DATA_OUT_PING_TOKEN_INTERRUPT
))
{
if
(
tmp
&
(
1
<<
DATA_OUT_PING_TOKEN_INTERRUPT
)
/* high speed did bulk NYET; fifo isn't filling */
&&
ep
->
dev
->
gadget
.
speed
==
USB_SPEED_FULL
)
{
unsigned
usec
;
if
(
ep
->
dev
->
gadget
.
speed
==
USB_SPEED_HIGH
)
{
if
(
ep
->
ep
.
maxpacket
<=
512
)
usec
=
10
;
/* 512 byte bulk */
else
usec
=
21
;
/* 1024 byte interrupt */
}
else
usec
=
50
;
/* 64 byte bulk/interrupt */
usec
=
50
;
/* 64 byte bulk/interrupt */
handshake
(
statp
,
(
1
<<
USB_OUT_PING_NAK_SENT
),
(
1
<<
USB_OUT_PING_NAK_SENT
),
usec
);
/* NAK done; now CLEAR_NAK_OUT_PACKETS is safe */
...
...
@@ -614,15 +610,13 @@ read_fifo (struct net2280_ep *ep, struct net2280_request *req)
count
=
readl
(
&
regs
->
ep_avail
);
tmp
=
req
->
req
.
length
-
req
->
req
.
actual
;
if
(
count
>
tmp
)
{
unsigned
over
=
tmp
%
ep
->
ep
.
maxpacket
;
/* FIXME handle this consistently between PIO and DMA */
if
(
over
)
{
/* as with DMA, data overflow gets flushed */
if
((
tmp
%
ep
->
ep
.
maxpacket
)
!=
0
)
{
ERROR
(
ep
->
dev
,
"%s out fifo %d bytes,
over %d extra
%d
\n
"
,
ep
->
ep
.
name
,
count
,
over
,
count
-
tmp
);
"%s out fifo %d bytes,
expected
%d
\n
"
,
ep
->
ep
.
name
,
count
,
tmp
);
req
->
req
.
status
=
-
EOVERFLOW
;
tmp
-=
over
;
cleanup
=
1
;
}
count
=
tmp
;
}
...
...
@@ -670,10 +664,12 @@ fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid)
/* don't let DMA continue after a short OUT packet,
* so overruns can't affect the next transfer.
* in case of overruns on max-size packets, we can't
* stop the fifo from filling but we can flush it.
*/
if
(
ep
->
is_in
)
dmacount
|=
(
1
<<
DMA_DIRECTION
);
else
if
((
dmacount
%
ep
->
ep
.
maxpacket
)
!=
0
)
else
dmacount
|=
(
1
<<
END_OF_CHAIN
);
req
->
valid
=
valid
;
...
...
@@ -897,8 +893,12 @@ net2280_queue (struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
start_dma
(
ep
,
req
);
else
{
/* maybe there's no control data, just status ack */
if
(
ep
->
num
==
0
&&
_req
->
length
==
0
)
if
(
ep
->
num
==
0
&&
_req
->
length
==
0
)
{
allow_status
(
ep
);
done
(
ep
,
req
,
0
);
VDEBUG
(
dev
,
"%s status ack
\n
"
,
ep
->
ep
.
name
);
goto
done
;
}
/* PIO ... stuff the fifo, or unblock it. */
if
(
ep
->
is_in
)
...
...
@@ -948,10 +948,9 @@ net2280_queue (struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
}
/* else the irq handler advances the queue. */
if
(
req
)
{
done:
if
(
req
)
list_add_tail
(
&
req
->
queue
,
&
ep
->
queue
);
}
done:
spin_unlock_irqrestore
(
&
dev
->
lock
,
flags
);
/* pci writes may still be posted */
...
...
@@ -992,6 +991,8 @@ static void scan_dma_completions (struct net2280_ep *ep)
/* SHORT_PACKET_TRANSFERRED_INTERRUPT handles "usb-short"
* packets, including overruns, even when the transfer was
* exactly the length requested (dmacount now zero).
* FIXME there's an overrun case here too, where we expect
* a short packet but receive a max length one (won't NAK).
*/
if
(
!
ep
->
is_in
&&
(
req
->
req
.
length
%
ep
->
ep
.
maxpacket
)
!=
0
)
{
req
->
dma_done
=
1
;
...
...
@@ -1186,7 +1187,8 @@ net2280_set_halt (struct usb_ep *_ep, int value)
return
-
EINVAL
;
if
(
!
ep
->
dev
->
driver
||
ep
->
dev
->
gadget
.
speed
==
USB_SPEED_UNKNOWN
)
return
-
ESHUTDOWN
;
if
((
ep
->
desc
->
bmAttributes
&
0x03
)
==
USB_ENDPOINT_XFER_ISOC
)
if
(
ep
->
desc
/* not ep0 */
&&
(
ep
->
desc
->
bmAttributes
&
0x03
)
==
USB_ENDPOINT_XFER_ISOC
)
return
-
EINVAL
;
VDEBUG
(
ep
->
dev
,
"%s %s halt
\n
"
,
_ep
->
name
,
value
?
"set"
:
"clear"
);
...
...
@@ -1712,7 +1714,7 @@ static void usb_reinit (struct net2280 *dev)
static
void
ep0_start
(
struct
net2280
*
dev
)
{
writel
(
(
1
<<
SET
_EP_HIDE_STATUS_PHASE
)
writel
(
(
1
<<
CLEAR
_EP_HIDE_STATUS_PHASE
)
|
(
1
<<
CLEAR_NAK_OUT_PACKETS
)
|
(
1
<<
CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE
)
,
&
dev
->
epregs
[
0
].
ep_rsp
);
...
...
@@ -1916,22 +1918,27 @@ static void handle_ep_small (struct net2280_ep *ep)
if
(
ep
->
is_in
)
{
/* status; stop NAKing */
if
(
t
&
(
1
<<
DATA_OUT_PING_TOKEN_INTERRUPT
))
{
if
(
ep
->
dev
->
protocol_stall
)
if
(
ep
->
dev
->
protocol_stall
)
{
ep
->
stopped
=
1
;
set_halt
(
ep
);
}
mode
=
2
;
/* reply to extra IN tokens with a zlp */
/* reply to extra IN
data
tokens with a zlp */
}
else
if
(
t
&
(
1
<<
DATA_IN_TOKEN_INTERRUPT
))
{
if
(
ep
->
dev
->
protocol_stall
)
{
ep
->
stopped
=
1
;
set_halt
(
ep
);
mode
=
2
;
}
else
if
(
!
req
)
}
else
if
(
!
req
&&
ep
->
stopped
)
write_fifo
(
ep
,
0
);
}
}
else
{
/* status; stop NAKing */
if
(
t
&
(
1
<<
DATA_IN_TOKEN_INTERRUPT
))
{
if
(
ep
->
dev
->
protocol_stall
)
if
(
ep
->
dev
->
protocol_stall
)
{
ep
->
stopped
=
1
;
set_halt
(
ep
);
}
mode
=
2
;
/* an extra OUT token is an error */
}
else
if
(((
t
&
(
1
<<
DATA_OUT_PING_TOKEN_INTERRUPT
))
...
...
@@ -2031,6 +2038,10 @@ static void handle_ep_small (struct net2280_ep *ep)
/* maybe advance queue to next request */
if
(
ep
->
num
==
0
)
{
/* FIXME need mechanism (request flag?) so control OUT
* can decide to stall ep0 after that done() returns,
* from non-irq context
*/
allow_status
(
ep
);
req
=
0
;
}
else
{
...
...
@@ -2171,6 +2182,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
struct
net2280_ep
*
e
;
u16
status
;
/* hw handles device and interface status */
if
(
u
.
r
.
bRequestType
!=
(
USB_DIR_IN
|
USB_RECIP_ENDPOINT
))
goto
delegate
;
if
((
e
=
get_ep_by_addr
(
dev
,
u
.
r
.
wIndex
))
==
0
...
...
@@ -2188,12 +2200,14 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
set_fifo_bytecount
(
ep
,
u
.
r
.
wLength
);
writel
(
status
,
&
dev
->
epregs
[
0
].
ep_data
);
allow_status
(
ep
);
VDEBUG
(
dev
,
"%s stat %02x
\n
"
,
ep
->
ep
.
name
,
status
);
goto
next_endpoints
;
}
break
;
case
USB_REQ_CLEAR_FEATURE
:
{
struct
net2280_ep
*
e
;
/* hw handles device features */
if
(
u
.
r
.
bRequestType
!=
USB_RECIP_ENDPOINT
)
goto
delegate
;
if
(
u
.
r
.
wIndex
!=
0
/* HALT feature */
...
...
@@ -2202,11 +2216,15 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
if
((
e
=
get_ep_by_addr
(
dev
,
u
.
r
.
wIndex
))
==
0
)
goto
do_stall
;
clear_halt
(
e
);
allow_status
(
ep
);
VDEBUG
(
dev
,
"%s clear halt
\n
"
,
ep
->
ep
.
name
);
goto
next_endpoints
;
}
break
;
case
USB_REQ_SET_FEATURE
:
{
struct
net2280_ep
*
e
;
/* hw handles device features */
if
(
u
.
r
.
bRequestType
!=
USB_RECIP_ENDPOINT
)
goto
delegate
;
if
(
u
.
r
.
wIndex
!=
0
/* HALT feature */
...
...
@@ -2215,6 +2233,9 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
if
((
e
=
get_ep_by_addr
(
dev
,
u
.
r
.
wIndex
))
==
0
)
goto
do_stall
;
set_halt
(
e
);
allow_status
(
ep
);
VDEBUG
(
dev
,
"%s set halt
\n
"
,
ep
->
ep
.
name
);
goto
next_endpoints
;
}
break
;
default:
...
...
@@ -2235,23 +2256,12 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
VDEBUG
(
dev
,
"req %02x.%02x protocol STALL; stat %d
\n
"
,
u
.
r
.
bRequestType
,
u
.
r
.
bRequest
,
tmp
);
dev
->
protocol_stall
=
1
;
/* when there's no data, queueing a response is optional */
}
else
if
(
list_empty
(
&
ep
->
queue
))
{
if
(
u
.
r
.
wLength
==
0
)
{
/* done() not possible/requested */
allow_status
(
ep
);
}
else
{
DEBUG
(
dev
,
"req %02x.%02x v%04x "
"gadget error, len %d, stat %d
\n
"
,
u
.
r
.
bRequestType
,
u
.
r
.
bRequest
,
le16_to_cpu
(
u
.
r
.
wValue
),
u
.
r
.
wLength
,
tmp
);
dev
->
protocol_stall
=
1
;
}
}
/* some in/out token irq should follow; maybe stall then. */
/* some in/out token irq should follow; maybe stall then.
* driver must queue a request (even zlp) or halt ep0
* before the host times out.
*/
}
next_endpoints:
...
...
drivers/usb/gadget/net2280.h
View file @
1a569433
...
...
@@ -437,6 +437,8 @@ struct net2280_ep_regs { /* [11.9] */
/*-------------------------------------------------------------------------*/
#ifdef __KERNEL__
/* indexed registers [11.10] are accessed indirectly
* caller must own the device lock.
*/
...
...
@@ -457,6 +459,9 @@ set_idx_reg (struct net2280_regs *regs, u32 index, u32 value)
/* posted, may not be visible yet */
}
#endif
/* __KERNEL__ */
#define REG_DIAG 0x0
#define RETRY_COUNTER 16
#define FORCE_PCI_SERR 11
...
...
@@ -471,6 +476,8 @@ set_idx_reg (struct net2280_regs *regs, u32 index, u32 value)
#define REG_CHIPREV 0x03
/* in bcd */
#define REG_HS_NAK_RATE 0x0a
/* NAK per N uframes */
#ifdef __KERNEL__
/* ep a-f highspeed and fullspeed maxpacket, addresses
* computed from ep->num
*/
...
...
@@ -519,6 +526,7 @@ static inline void allow_status (struct net2280_ep *ep)
writel
(
(
1
<<
CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE
)
|
(
1
<<
CLEAR_NAK_OUT_PACKETS_MODE
)
,
&
ep
->
regs
->
ep_rsp
);
ep
->
stopped
=
1
;
}
static
inline
void
set_halt
(
struct
net2280_ep
*
ep
)
...
...
@@ -707,3 +715,4 @@ static inline void stop_out_naking (struct net2280_ep *ep)
writel
((
1
<<
CLEAR_NAK_OUT_PACKETS
),
&
ep
->
regs
->
ep_rsp
);
}
#endif
/* __KERNEL__ */
drivers/usb/gadget/zero.c
View file @
1a569433
...
...
@@ -653,7 +653,7 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
/* this endpoint is normally active while we're configured */
case
-
ECONNRESET
:
/* request dequeued */
case
-
ESHUTDOWN
:
/* disconnect from host */
DEBUG
(
dev
,
"%s gone (%d), %d/%d
\n
"
,
ep
->
name
,
status
,
V
DEBUG
(
dev
,
"%s gone (%d), %d/%d
\n
"
,
ep
->
name
,
status
,
req
->
actual
,
req
->
length
);
free_ep_req
(
ep
,
req
);
return
;
...
...
@@ -1035,9 +1035,6 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
if
(
ctrl
->
bRequestType
!=
0
)
break
;
spin_lock
(
&
dev
->
lock
);
/* change hardware configuration!
* no response queued, just zero status == success
*/
value
=
zero_set_config
(
dev
,
ctrl
->
wValue
,
GFP_ATOMIC
);
spin_unlock
(
&
dev
->
lock
);
break
;
...
...
@@ -1092,7 +1089,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
}
/* respond with data transfer before status phase? */
if
(
value
>
0
)
{
if
(
value
>
=
0
)
{
req
->
length
=
value
;
value
=
usb_ep_queue
(
gadget
->
ep0
,
req
,
GFP_ATOMIC
);
if
(
value
<
0
)
{
...
...
drivers/usb/host/uhci-hcd.c
View file @
1a569433
...
...
@@ -61,7 +61,7 @@
/*
* Version Information
*/
#define DRIVER_VERSION "v2.
0
"
#define DRIVER_VERSION "v2.
1
"
#define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber"
#define DRIVER_DESC "USB Universal Host Controller Interface driver"
...
...
@@ -91,9 +91,7 @@ static int uhci_get_current_frame_number(struct uhci_hcd *uhci);
static
int
uhci_urb_dequeue
(
struct
usb_hcd
*
hcd
,
struct
urb
*
urb
);
static
void
uhci_unlink_generic
(
struct
uhci_hcd
*
uhci
,
struct
urb
*
urb
);
static
int
ports_active
(
struct
uhci_hcd
*
uhci
);
static
void
suspend_hc
(
struct
uhci_hcd
*
uhci
);
static
void
wakeup_hc
(
struct
uhci_hcd
*
uhci
);
static
void
hc_state_transitions
(
struct
uhci_hcd
*
uhci
);
/* If a transfer is still active after this much time, turn off FSBR */
#define IDLE_TIMEOUT (HZ / 20)
/* 50 ms */
...
...
@@ -1757,9 +1755,8 @@ static void stall_callback(unsigned long ptr)
uhci
->
skel_term_qh
->
link
=
UHCI_PTR_TERM
;
}
/* enter global suspend if nothing connected */
if
(
!
uhci
->
is_suspended
&&
!
ports_active
(
uhci
))
suspend_hc
(
uhci
);
/* Poll for and perform state transitions */
hc_state_transitions
(
uhci
);
init_stall_timer
(
hcd
);
}
...
...
@@ -1884,14 +1881,14 @@ static void uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
err
(
"%x: host system error, PCI problems?"
,
io_addr
);
if
(
status
&
USBSTS_HCPE
)
err
(
"%x: host controller process error. something bad happened"
,
io_addr
);
if
((
status
&
USBSTS_HCH
)
&&
!
uhci
->
is_suspended
)
{
if
((
status
&
USBSTS_HCH
)
&&
uhci
->
state
>
0
)
{
err
(
"%x: host controller halted. very bad"
,
io_addr
);
/* FIXME: Reset the controller, fix the offending TD */
}
}
if
(
status
&
USBSTS_RD
)
wakeup_hc
(
uhci
)
;
uhci
->
resume_detect
=
1
;
uhci_free_pending_qhs
(
uhci
);
...
...
@@ -1922,10 +1919,18 @@ static void reset_hc(struct uhci_hcd *uhci)
unsigned
int
io_addr
=
uhci
->
io_addr
;
/* Global reset for 50ms */
uhci
->
state
=
UHCI_RESET
;
outw
(
USBCMD_GRESET
,
io_addr
+
USBCMD
);
wait_ms
(
50
);
set_current_state
(
TASK_UNINTERRUPTIBLE
);
schedule_timeout
((
HZ
*
50
+
999
)
/
1000
);
set_current_state
(
TASK_RUNNING
);
outw
(
0
,
io_addr
+
USBCMD
);
wait_ms
(
10
);
/* Another 10ms delay */
set_current_state
(
TASK_UNINTERRUPTIBLE
);
schedule_timeout
((
HZ
*
10
+
999
)
/
1000
);
set_current_state
(
TASK_RUNNING
);
uhci
->
resume_detect
=
0
;
}
static
void
suspend_hc
(
struct
uhci_hcd
*
uhci
)
...
...
@@ -1933,34 +1938,49 @@ static void suspend_hc(struct uhci_hcd *uhci)
unsigned
int
io_addr
=
uhci
->
io_addr
;
dbg
(
"%x: suspend_hc"
,
io_addr
);
uhci
->
is_suspended
=
1
;
smp_wmb
();
uhci
->
state
=
UHCI_SUSPENDED
;
uhci
->
resume_detect
=
0
;
outw
(
USBCMD_EGSM
,
io_addr
+
USBCMD
);
}
static
void
wakeup_hc
(
struct
uhci_hcd
*
uhci
)
{
unsigned
int
io_addr
=
uhci
->
io_addr
;
unsigned
int
status
;
dbg
(
"%x: wakeup_hc"
,
io_addr
);
switch
(
uhci
->
state
)
{
case
UHCI_SUSPENDED
:
/* Start the resume */
dbg
(
"%x: wakeup_hc"
,
io_addr
);
/* Global resume for 20ms */
outw
(
USBCMD_FGR
|
USBCMD_EGSM
,
io_addr
+
USBCMD
);
wait_ms
(
20
);
outw
(
0
,
io_addr
+
USBCMD
);
/* wait for EOP to be sent */
status
=
inw
(
io_addr
+
USBCMD
);
while
(
status
&
USBCMD_FGR
)
status
=
inw
(
io_addr
+
USBCMD
);
/* Global resume for >= 20ms */
outw
(
USBCMD_FGR
|
USBCMD_EGSM
,
io_addr
+
USBCMD
);
uhci
->
state
=
UHCI_RESUMING_1
;
uhci
->
state_end
=
jiffies
+
(
20
*
HZ
+
999
)
/
1000
;
break
;
uhci
->
is_suspended
=
0
;
case
UHCI_RESUMING_1
:
/* End global resume */
uhci
->
state
=
UHCI_RESUMING_2
;
outw
(
0
,
io_addr
+
USBCMD
);
/* Falls through */
/* Run and mark it configured with a 64-byte max packet */
outw
(
USBCMD_RS
|
USBCMD_CF
|
USBCMD_MAXP
,
io_addr
+
USBCMD
);
case
UHCI_RESUMING_2
:
/* Wait for EOP to be sent */
if
(
inw
(
io_addr
+
USBCMD
)
&
USBCMD_FGR
)
break
;
/* Run for at least 1 second, and
* mark it configured with a 64-byte max packet */
uhci
->
state
=
UHCI_RUNNING_GRACE
;
uhci
->
state_end
=
jiffies
+
HZ
;
outw
(
USBCMD_RS
|
USBCMD_CF
|
USBCMD_MAXP
,
io_addr
+
USBCMD
);
break
;
case
UHCI_RUNNING_GRACE
:
/* Now allowed to suspend */
uhci
->
state
=
UHCI_RUNNING
;
break
;
default:
break
;
}
}
static
int
ports_active
(
struct
uhci_hcd
*
uhci
)
...
...
@@ -1975,6 +1995,73 @@ static int ports_active(struct uhci_hcd *uhci)
return
connection
;
}
static
int
suspend_allowed
(
struct
uhci_hcd
*
uhci
)
{
unsigned
int
io_addr
=
uhci
->
io_addr
;
int
i
;
if
(
!
uhci
->
hcd
.
pdev
||
uhci
->
hcd
.
pdev
->
vendor
!=
PCI_VENDOR_ID_INTEL
||
uhci
->
hcd
.
pdev
->
device
!=
PCI_DEVICE_ID_INTEL_82371AB_2
)
return
1
;
/* This is a 82371AB/EB/MB USB controller which has a bug that
* causes false resume indications if any port has an
* over current condition. To prevent problems, we will not
* allow a global suspend if any ports are OC.
*
* Some motherboards using the 82371AB/EB/MB (but not the USB portion)
* appear to hardwire the over current inputs active to disable
* the USB ports.
*/
/* check for over current condition on any port */
for
(
i
=
0
;
i
<
uhci
->
rh_numports
;
i
++
)
{
if
(
inw
(
io_addr
+
USBPORTSC1
+
i
*
2
)
&
USBPORTSC_OC
)
return
0
;
}
return
1
;
}
static
void
hc_state_transitions
(
struct
uhci_hcd
*
uhci
)
{
switch
(
uhci
->
state
)
{
case
UHCI_RUNNING
:
/* global suspend if nothing connected for 1 second */
if
(
!
ports_active
(
uhci
)
&&
suspend_allowed
(
uhci
))
{
uhci
->
state
=
UHCI_SUSPENDING_GRACE
;
uhci
->
state_end
=
jiffies
+
HZ
;
}
break
;
case
UHCI_SUSPENDING_GRACE
:
if
(
ports_active
(
uhci
))
uhci
->
state
=
UHCI_RUNNING
;
else
if
(
time_after_eq
(
jiffies
,
uhci
->
state_end
))
suspend_hc
(
uhci
);
break
;
case
UHCI_SUSPENDED
:
/* wakeup if requested by a device */
if
(
uhci
->
resume_detect
)
wakeup_hc
(
uhci
);
break
;
case
UHCI_RESUMING_1
:
case
UHCI_RESUMING_2
:
case
UHCI_RUNNING_GRACE
:
if
(
time_after_eq
(
jiffies
,
uhci
->
state_end
))
wakeup_hc
(
uhci
);
break
;
default:
break
;
}
}
static
void
start_hc
(
struct
uhci_hcd
*
uhci
)
{
unsigned
int
io_addr
=
uhci
->
io_addr
;
...
...
@@ -2003,6 +2090,8 @@ static void start_hc(struct uhci_hcd *uhci)
outl
(
uhci
->
fl
->
dma_handle
,
io_addr
+
USBFLBASEADD
);
/* Run and mark it configured with a 64-byte max packet */
uhci
->
state
=
UHCI_RUNNING_GRACE
;
uhci
->
state_end
=
jiffies
+
HZ
;
outw
(
USBCMD_RS
|
USBCMD_CF
|
USBCMD_MAXP
,
io_addr
+
USBCMD
);
uhci
->
hcd
.
state
=
USB_STATE_READY
;
...
...
@@ -2101,8 +2190,6 @@ static int __devinit uhci_start(struct usb_hcd *hcd)
uhci
->
fsbr
=
0
;
uhci
->
fsbrtimeout
=
0
;
uhci
->
is_suspended
=
0
;
spin_lock_init
(
&
uhci
->
qh_remove_list_lock
);
INIT_LIST_HEAD
(
&
uhci
->
qh_remove_list
);
...
...
@@ -2335,7 +2422,11 @@ static int uhci_suspend(struct usb_hcd *hcd, u32 state)
{
struct
uhci_hcd
*
uhci
=
hcd_to_uhci
(
hcd
);
suspend_hc
(
uhci
);
/* Don't try to suspend broken motherboards, reset instead */
if
(
suspend_allowed
(
uhci
))
suspend_hc
(
uhci
);
else
reset_hc
(
uhci
);
return
0
;
}
...
...
@@ -2345,8 +2436,13 @@ static int uhci_resume(struct usb_hcd *hcd)
pci_set_master
(
uhci
->
hcd
.
pdev
);
reset_hc
(
uhci
);
start_hc
(
uhci
);
if
(
uhci
->
state
==
UHCI_SUSPENDED
)
uhci
->
resume_detect
=
1
;
else
{
reset_hc
(
uhci
);
start_hc
(
uhci
);
}
uhci
->
hcd
.
state
=
USB_STATE_READY
;
return
0
;
}
#endif
...
...
drivers/usb/host/uhci-hcd.h
View file @
1a569433
...
...
@@ -53,6 +53,7 @@
#define USBPORTSC_RD 0x0040
/* Resume Detect */
#define USBPORTSC_LSDA 0x0100
/* Low Speed Device Attached */
#define USBPORTSC_PR 0x0200
/* Port Reset */
#define USBPORTSC_OC 0x0400
/* Over Current condition */
#define USBPORTSC_SUSP 0x1000
/* Suspend */
/* Legacy support register */
...
...
@@ -282,6 +283,29 @@ static inline int __interval_to_skel(int interval)
return
0
;
/* int128 for 128-255 ms (Max.) */
}
/*
* Device states for the host controller.
*
* To prevent "bouncing" in the presence of electrical noise,
* we insist on a 1-second "grace" period, before switching to
* the RUNNING or SUSPENDED states, during which the state is
* not allowed to change.
*
* The resume process is divided into substates in order to avoid
* potentially length delays during the timer handler.
*
* States in which the host controller is halted must have values <= 0.
*/
enum
uhci_state
{
UHCI_RESET
,
UHCI_RUNNING_GRACE
,
/* Before RUNNING */
UHCI_RUNNING
,
/* The normal state */
UHCI_SUSPENDING_GRACE
,
/* Before SUSPENDED */
UHCI_SUSPENDED
=
-
10
,
/* When no devices are attached */
UHCI_RESUMING_1
,
UHCI_RESUMING_2
};
#define hcd_to_uhci(hcd_ptr) container_of(hcd_ptr, struct uhci_hcd, hcd)
/*
...
...
@@ -313,7 +337,10 @@ struct uhci_hcd {
struct
uhci_frame_list
*
fl
;
/* P: uhci->frame_list_lock */
int
fsbr
;
/* Full speed bandwidth reclamation */
unsigned
long
fsbrtimeout
;
/* FSBR delay */
int
is_suspended
;
enum
uhci_state
state
;
/* FIXME: needs a spinlock */
unsigned
long
state_end
;
/* Time of next transition */
int
resume_detect
;
/* Need a Global Resume */
/* Main list of URB's currently controlled by this HC */
spinlock_t
urb_list_lock
;
...
...
drivers/usb/misc/speedtch.c
View file @
1a569433
/******************************************************************************
* speedtouch.c -
- Alcatel SpeedTouch USB xDSL modem driver.
* speedtouch.c -
Alcatel SpeedTouch USB xDSL modem driver
*
* Copyright (C) 2001, Alcatel
* Copyright (C) 2003, Duncan Sands
*
* 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
...
...
@@ -40,7 +41,6 @@
* udsl_usb_send_data_context->urb to a pointer and adding code
* to alloc and free it
* - remove_wait_queue() added to udsl_atm_processqueue_thread()
* - Duncan Sands (duncan.sands@wanadoo.fr) is the new maintainer
*
* 1.5: - fixed memory leak when atmsar_decode_aal5 returned NULL.
* (reported by stephen.robinson@zen.co.uk)
...
...
@@ -97,48 +97,65 @@ static int udsl_print_packet (const unsigned char *data, int len);
#define DRIVER_DESC "Alcatel SpeedTouch USB driver"
#define DRIVER_VERSION "1.6"
static
const
char
udsl_driver_name
[]
=
"speedtch"
;
#define SPEEDTOUCH_VENDORID 0x06b9
#define SPEEDTOUCH_PRODUCTID 0x4061
#define UDSL_NUMBER_RCV_URBS 1
#define UDSL_NUMBER_SND_URBS 1
#define UDSL_NUMBER_SND_BUFS (2*UDSL_NUMBER_SND_URBS)
#define UDSL_RCV_BUFFER_SIZE (1*64)
/* ATM cells */
#define UDSL_SND_BUFFER_SIZE (1*64)
/* ATM cells */
/* max should be (1500 IP mtu + 2 ppp bytes + 32 * 5 cellheader overhead) for
* PPPoA and (1500 + 14 + 32*5 cellheader overhead) for PPPoE */
#define UDSL_MAX_AAL5_MRU 2048
#define UDSL_IOCTL_START 1
#define UDSL_IOCTL_STOP 2
#define UDSL_NUM_RCV_URBS 1
#define UDSL_NUM_SND_URBS 1
#define UDSL_NUM_RCV_BUFS (2*UDSL_NUM_RCV_URBS)
#define UDSL_NUM_SND_BUFS (2*UDSL_NUM_SND_URBS)
#define UDSL_RCV_BUF_SIZE 32
/* ATM cells */
#define UDSL_SND_BUF_SIZE 64
/* ATM cells */
/* endpoint declarations */
#define UDSL_IOCTL_LINE_UP 1
#define UDSL_IOCTL_LINE_DOWN 2
#define UDSL_ENDPOINT_DATA_OUT 0x07
#define UDSL_ENDPOINT_DATA_IN 0x87
#define ATM_CELL_HEADER (ATM_CELL_SIZE - ATM_CELL_PAYLOAD)
#define UDSL_NUM_CELLS(x) (((x) + ATM_AAL5_TRAILER + ATM_CELL_PAYLOAD - 1) / ATM_CELL_PAYLOAD)
#define hex2int(c) ( (c >= '0')&&(c <= '9') ? (c - '0') : ((c & 0xf)+9) )
/* usb_device_id struct */
#define hex2int(c) ( (c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9) )
static
struct
usb_device_id
udsl_usb_ids
[]
=
{
{
USB_DEVICE
(
SPEEDTOUCH_VENDORID
,
SPEEDTOUCH_PRODUCTID
)
},
{
}
/* Terminating entry */
{
}
};
MODULE_DEVICE_TABLE
(
usb
,
udsl_usb_ids
);
/* context declarations */
/* receive */
struct
udsl_receive_buffer
{
struct
list_head
list
;
unsigned
char
*
base
;
unsigned
int
filled_cells
;
};
struct
udsl_receiver
{
struct
list_head
list
;
struct
sk_buff
*
skb
;
struct
udsl_receive_buffer
*
buffer
;
struct
urb
*
urb
;
struct
udsl_instance_data
*
instance
;
};
struct
udsl_vcc_data
{
/* vpi/vci lookup */
struct
list_head
list
;
short
vpi
;
int
vci
;
struct
atm_vcc
*
vcc
;
/* raw cell reassembly */
struct
sk_buff
*
skb
;
unsigned
int
max_pdu
;
};
/* send */
struct
udsl_send_buffer
{
struct
list_head
list
;
unsigned
char
*
base
;
...
...
@@ -157,73 +174,55 @@ struct udsl_control {
struct
atm_skb_data
atm_data
;
unsigned
int
num_cells
;
unsigned
int
num_entire
;
unsigned
char
cell_header
[
ATM_CELL_HEADER
];
unsigned
int
pdu_padding
;
unsigned
char
cell_header
[
ATM_CELL_HEADER
];
unsigned
char
aal5_trailer
[
ATM_AAL5_TRAILER
];
};
#define UDSL_SKB(x) ((struct udsl_control *)(x)->cb)
struct
udsl_vcc_data
{
/* vpi/vci lookup */
struct
list_head
list
;
short
vpi
;
int
vci
;
struct
atm_vcc
*
vcc
;
/* raw cell reassembly */
unsigned
short
mtu
;
struct
sk_buff
*
reasBuffer
;
};
/*
* UDSL main driver data
*/
/* main driver data */
struct
udsl_instance_data
{
struct
semaphore
serialize
;
/*
usb
device part */
/*
USB
device part */
struct
usb_device
*
usb_dev
;
char
description
[
64
];
int
firmware_loaded
;
/*
atm
device part */
/*
ATM
device part */
struct
atm_dev
*
atm_dev
;
struct
list_head
vcc_list
;
/* receiving */
struct
udsl_receiver
all_receivers
[
UDSL_NUMBER_RCV_URBS
];
/* receive */
struct
udsl_receiver
receivers
[
UDSL_NUM_RCV_URBS
];
struct
udsl_receive_buffer
receive_buffers
[
UDSL_NUM_RCV_BUFS
];
spinlock_t
spare_receivers
_lock
;
spinlock_t
receive
_lock
;
struct
list_head
spare_receivers
;
spinlock_t
completed_receivers_lock
;
struct
list_head
completed_receivers
;
struct
list_head
filled_receive_buffers
;
struct
tasklet_struct
receive_tasklet
;
struct
list_head
spare_receive_buffers
;
/* send
ing
*/
struct
udsl_sender
all_senders
[
UDSL_NUMBER
_SND_URBS
];
struct
udsl_send_buffer
all_buffers
[
UDSL_NUMBER
_SND_BUFS
];
/* send */
struct
udsl_sender
senders
[
UDSL_NUM
_SND_URBS
];
struct
udsl_send_buffer
send_buffers
[
UDSL_NUM
_SND_BUFS
];
struct
sk_buff_head
sndqueue
;
spinlock_t
send_lock
;
struct
list_head
spare_senders
;
struct
list_head
spare_buffers
;
struct
list_head
spare_
send_
buffers
;
struct
tasklet_struct
send_tasklet
;
struct
sk_buff
*
current_skb
;
/* being emptied */
struct
udsl_send_buffer
*
current_buffer
;
/* being filled */
struct
list_head
filled_buffers
;
struct
list_head
filled_
send_
buffers
;
};
static
const
char
udsl_driver_name
[]
=
"speedtch"
;
/*
* atm driver prototypes and structures
*/
/* ATM */
static
void
udsl_atm_dev_close
(
struct
atm_dev
*
dev
);
static
int
udsl_atm_open
(
struct
atm_vcc
*
vcc
,
short
vpi
,
int
vci
);
...
...
@@ -239,17 +238,17 @@ static struct atmdev_ops udsl_atm_devops = {
.
ioctl
=
udsl_atm_ioctl
,
.
send
=
udsl_atm_send
,
.
proc_read
=
udsl_atm_proc_read
,
.
owner
=
THIS_MODULE
,
};
/*
* usb driver prototypes and structures
*/
static
int
udsl_usb_probe
(
struct
usb_interface
*
intf
,
const
struct
usb_device_id
*
id
);
/* USB */
static
int
udsl_usb_probe
(
struct
usb_interface
*
intf
,
const
struct
usb_device_id
*
id
);
static
void
udsl_usb_disconnect
(
struct
usb_interface
*
intf
);
static
int
udsl_usb_ioctl
(
struct
usb_interface
*
intf
,
unsigned
int
code
,
void
*
user_data
);
static
struct
usb_driver
udsl_usb_driver
=
{
.
owner
=
THIS_MODULE
,
.
name
=
udsl_driver_name
,
.
probe
=
udsl_usb_probe
,
.
disconnect
=
udsl_usb_disconnect
,
...
...
@@ -272,133 +271,110 @@ static inline struct udsl_vcc_data *udsl_find_vcc (struct udsl_instance_data *in
return
NULL
;
}
static
struct
sk_buff
*
udsl_decode_rawcell
(
struct
udsl_instance_data
*
instance
,
struct
sk_buff
*
skb
,
struct
udsl_vcc_data
**
ctx
)
static
void
udsl_extract_cells
(
struct
udsl_instance_data
*
instance
,
unsigned
char
*
source
,
unsigned
int
howmany
)
{
if
(
!
instance
||
!
skb
||
!
ctx
)
return
NULL
;
if
(
!
skb
->
data
||
!
skb
->
tail
)
return
NULL
;
struct
udsl_vcc_data
*
cached_vcc
=
NULL
;
struct
atm_vcc
*
vcc
;
struct
sk_buff
*
skb
;
struct
udsl_vcc_data
*
vcc_data
;
int
cached_vci
=
0
;
unsigned
int
i
;
unsigned
int
length
;
unsigned
int
pdu_length
;
int
pti
;
int
vci
;
short
cached_vpi
=
0
;
short
vpi
;
while
(
skb
->
len
)
{
unsigned
char
*
cell
=
skb
->
data
;
unsigned
char
*
cell_payload
;
struct
udsl_vcc_data
*
vcc
;
short
vpi
;
int
vci
;
for
(
i
=
0
;
i
<
howmany
;
i
++
,
source
+=
ATM_CELL_SIZE
)
{
vpi
=
((
source
[
0
]
&
0x0f
)
<<
4
)
|
(
source
[
1
]
>>
4
);
vci
=
((
source
[
1
]
&
0x0f
)
<<
12
)
|
(
source
[
2
]
<<
4
)
|
(
source
[
3
]
>>
4
);
pti
=
(
source
[
3
]
&
0x2
)
!=
0
;
vpi
=
((
cell
[
0
]
&
0x0f
)
<<
4
)
|
(
cell
[
1
]
>>
4
);
vci
=
((
cell
[
1
]
&
0x0f
)
<<
12
)
|
(
cell
[
2
]
<<
4
)
|
(
cell
[
3
]
>>
4
);
vdbg
(
"udsl_extract_cells: vpi %hd, vci %d, pti %d"
,
vpi
,
vci
,
pti
);
vdbg
(
"udsl_decode_rawcell (0x%p, 0x%p, 0x%p) called"
,
instance
,
skb
,
ctx
);
vdbg
(
"udsl_decode_rawcell skb->data %p, skb->tail %p"
,
skb
->
data
,
skb
->
tail
);
if
(
cached_vcc
&&
(
vci
==
cached_vci
)
&&
(
vpi
==
cached_vpi
))
vcc_data
=
cached_vcc
;
else
if
((
vcc_data
=
udsl_find_vcc
(
instance
,
vpi
,
vci
)))
{
cached_vcc
=
vcc_data
;
cached_vpi
=
vpi
;
cached_vci
=
vci
;
}
else
{
dbg
(
"udsl_extract_cells: unknown vpi/vci (%hd/%d)!"
,
vpi
,
vci
);
continue
;
}
/* here should the header CRC check be... */
vcc
=
vcc_data
->
vcc
;
if
(
!
(
vcc
=
udsl_find_vcc
(
instance
,
vpi
,
vci
)))
{
dbg
(
"udsl_decode_rawcell: no vcc found for packet on vpi %d, vci %d"
,
vpi
,
vci
);
__skb_pull
(
skb
,
min
(
skb
->
len
,
(
unsigned
)
53
));
}
else
{
vdbg
(
"udsl_decode_rawcell found vcc %p for packet on vpi %d, vci %d"
,
vcc
,
vpi
,
vci
);
if
(
skb
->
len
>=
53
)
{
cell_payload
=
cell
+
5
;
if
(
!
vcc
->
reasBuffer
)
vcc
->
reasBuffer
=
dev_alloc_skb
(
vcc
->
mtu
);
/* if alloc fails, we just drop the cell. it is possible that we can still
* receive cells on other vcc's
*/
if
(
vcc
->
reasBuffer
)
{
/* if (buffer overrun) discard received cells until now */
if
((
vcc
->
reasBuffer
->
len
)
>
(
vcc
->
mtu
-
48
))
skb_trim
(
vcc
->
reasBuffer
,
0
);
/* copy data */
memcpy
(
vcc
->
reasBuffer
->
tail
,
cell_payload
,
48
);
skb_put
(
vcc
->
reasBuffer
,
48
);
/* check for end of buffer */
if
(
cell
[
3
]
&
0x2
)
{
struct
sk_buff
*
tmp
;
/* the aal5 buffer ends here, cut the buffer. */
/* buffer will always have at least one whole cell, so */
/* don't need to check return from skb_pull */
skb_pull
(
skb
,
53
);
*
ctx
=
vcc
;
tmp
=
vcc
->
reasBuffer
;
vcc
->
reasBuffer
=
NULL
;
vdbg
(
"udsl_decode_rawcell returns ATM_AAL5 pdu 0x%p with length %d"
,
tmp
,
tmp
->
len
);
return
tmp
;
}
}
/* flush the cell */
/* buffer will always contain at least one whole cell, so don't */
/* need to check return value from skb_pull */
skb_pull
(
skb
,
53
);
}
else
{
/* If data is corrupt and skb doesn't hold a whole cell, flush the lot */
__skb_pull
(
skb
,
skb
->
len
);
return
NULL
;
}
if
(
!
vcc_data
->
skb
&&
!
(
vcc_data
->
skb
=
dev_alloc_skb
(
vcc_data
->
max_pdu
)))
{
dbg
(
"udsl_extract_cells: no memory for skb (vcc: 0x%p)!"
,
vcc
);
if
(
pti
)
atomic_inc
(
&
vcc
->
stats
->
rx_err
);
continue
;
}
}
return
NULL
;
}
skb
=
vcc_data
->
skb
;
static
struct
sk_buff
*
udsl_decode_aal5
(
struct
udsl_vcc_data
*
ctx
,
struct
sk_buff
*
skb
)
{
uint
crc
=
0xffffffff
;
uint
length
,
pdu_crc
,
pdu_length
;
if
(
skb
->
len
+
ATM_CELL_PAYLOAD
>
vcc_data
->
max_pdu
)
{
dbg
(
"udsl_extract_cells: buffer overrun (max_pdu: %u, skb->len %u, vcc: 0x%p)"
,
vcc_data
->
max_pdu
,
skb
->
len
,
vcc
);
/* discard cells already received */
skb_trim
(
skb
,
0
);
BUG_ON
(
vcc_data
->
max_pdu
<
ATM_CELL_PAYLOAD
);
}
vdbg
(
"udsl_decode_aal5 (0x%p, 0x%p) called"
,
ctx
,
skb
);
memcpy
(
skb
->
tail
,
source
+
ATM_CELL_HEADER
,
ATM_CELL_PAYLOAD
);
__skb_put
(
skb
,
ATM_CELL_PAYLOAD
);
if
(
skb
->
len
&&
(
skb
->
len
%
48
))
return
NULL
;
if
(
pti
)
{
length
=
(
source
[
ATM_CELL_SIZE
-
6
]
<<
8
)
+
source
[
ATM_CELL_SIZE
-
5
]
;
length
=
(
skb
->
tail
[
-
6
]
<<
8
)
+
skb
->
tail
[
-
5
];
pdu_crc
=
(
skb
->
tail
[
-
4
]
<<
24
)
+
(
skb
->
tail
[
-
3
]
<<
16
)
+
(
skb
->
tail
[
-
2
]
<<
8
)
+
skb
->
tail
[
-
1
];
pdu_length
=
((
length
+
47
+
8
)
/
48
)
*
48
;
/* guard against overflow */
if
(
length
>
ATM_MAX_AAL5_PDU
)
{
dbg
(
"udsl_extract_cells: bogus length %u (vcc: 0x%p)"
,
length
,
vcc
);
goto
drop
;
}
vdbg
(
"udsl_decode_aal5: skb->len = %d, length = %d, pdu_crc = 0x%x, pdu_length = %d"
,
skb
->
len
,
length
,
pdu_crc
,
pdu_length
)
;
pdu_length
=
UDSL_NUM_CELLS
(
length
)
*
ATM_CELL_PAYLOAD
;
/* is skb long enough ? */
if
(
skb
->
len
<
pdu_length
)
{
atomic_inc
(
&
ctx
->
vcc
->
stats
->
rx_err
);
return
NULL
;
}
if
(
skb
->
len
<
pdu_length
)
{
dbg
(
"udsl_extract_cells: bogus pdu_length %u (skb->len: %u, vcc: 0x%p)"
,
pdu_length
,
skb
->
len
,
vcc
);
goto
drop
;
}
/* is skb too long ? */
if
(
skb
->
len
>
pdu_length
)
{
dbg
(
"udsl_decode_aal5: Warning: readjusting illegal size %d -> %d"
,
skb
->
len
,
pdu_length
);
/* buffer is too long. we can try to recover
* if we discard the first part of the skb.
* the crc will decide whether this was ok
*/
skb_pull
(
skb
,
skb
->
len
-
pdu_length
);
}
if
(
crc32_be
(
~
0
,
skb
->
tail
-
pdu_length
,
pdu_length
)
!=
0xc704dd7b
)
{
dbg
(
"udsl_extract_cells: packet failed crc check (vcc: 0x%p)"
,
vcc
);
goto
drop
;
}
crc
=
~
crc32_be
(
crc
,
skb
->
data
,
pdu_length
-
4
);
if
(
!
atm_charge
(
vcc
,
skb
->
truesize
))
{
dbg
(
"udsl_extract_cells: failed atm_charge (skb->truesize: %u)"
,
skb
->
truesize
);
goto
drop_no_stats
;
/* atm_charge increments rx_drop */
}
/* check crc */
if
(
pdu_crc
!=
crc
)
{
dbg
(
"udsl_decode_aal5: crc check failed!"
);
atomic_inc
(
&
ctx
->
vcc
->
stats
->
rx_err
);
return
NULL
;
}
/* now that we are sure to send the skb, it is ok to change skb->data */
if
(
skb
->
len
>
pdu_length
)
skb_pull
(
skb
,
skb
->
len
-
pdu_length
);
/* discard initial junk */
/* pdu is ok */
skb_trim
(
skb
,
length
);
skb_trim
(
skb
,
length
);
/* drop zero padding and trailer */
/* update stats */
atomic_inc
(
&
ctx
->
vcc
->
stats
->
rx
);
atomic_inc
(
&
vcc
->
stats
->
rx
);
vdbg
(
"udsl_decode_aal5 returns pdu 0x%p with length %d"
,
skb
,
skb
->
len
);
return
skb
;
PACKETDEBUG
(
skb
->
data
,
skb
->
len
);
vdbg
(
"udsl_extract_cells: sending skb 0x%p, skb->len %u, skb->truesize %u"
,
skb
,
skb
->
len
,
skb
->
truesize
);
vcc
->
push
(
vcc
,
skb
);
vcc_data
->
skb
=
NULL
;
continue
;
drop:
atomic_inc
(
&
vcc
->
stats
->
rx_err
);
drop_no_stats:
skb_trim
(
skb
,
0
);
}
}
}
...
...
@@ -406,7 +382,7 @@ static struct sk_buff *udsl_decode_aal5 (struct udsl_vcc_data *ctx, struct sk_bu
** encode **
*************/
static
const
unsigned
char
zeros
[
ATM_CELL_PAYLOAD
];
static
const
unsigned
char
zeros
[
ATM_CELL_PAYLOAD
];
static
void
udsl_groom_skb
(
struct
atm_vcc
*
vcc
,
struct
sk_buff
*
skb
)
{
...
...
@@ -421,7 +397,7 @@ static void udsl_groom_skb (struct atm_vcc *vcc, struct sk_buff *skb)
ctrl
->
cell_header
[
3
]
=
vcc
->
vci
<<
4
;
ctrl
->
cell_header
[
4
]
=
0xec
;
ctrl
->
num_cells
=
(
skb
->
len
+
ATM_AAL5_TRAILER
+
ATM_CELL_PAYLOAD
-
1
)
/
ATM_CELL_PAYLOAD
;
ctrl
->
num_cells
=
UDSL_NUM_CELLS
(
skb
->
len
)
;
ctrl
->
num_entire
=
skb
->
len
/
ATM_CELL_PAYLOAD
;
zero_padding
=
ctrl
->
num_cells
*
ATM_CELL_PAYLOAD
-
skb
->
len
-
ATM_AAL5_TRAILER
;
...
...
@@ -490,8 +466,7 @@ static unsigned int udsl_write_cells (unsigned int howmany, struct sk_buff *skb,
memset
(
target
,
0
,
ATM_CELL_PAYLOAD
-
ATM_AAL5_TRAILER
);
target
+=
ATM_CELL_PAYLOAD
-
ATM_AAL5_TRAILER
;
if
(
--
ctrl
->
num_cells
)
BUG
();
BUG_ON
(
--
ctrl
->
num_cells
);
}
memcpy
(
target
,
ctrl
->
aal5_trailer
,
ATM_AAL5_TRAILER
);
...
...
@@ -511,145 +486,89 @@ static unsigned int udsl_write_cells (unsigned int howmany, struct sk_buff *skb,
static
void
udsl_complete_receive
(
struct
urb
*
urb
,
struct
pt_regs
*
regs
)
{
struct
udsl_receive_buffer
*
buf
;
struct
udsl_instance_data
*
instance
;
struct
udsl_receiver
*
rcv
;
unsigned
long
flags
;
if
(
!
urb
||
!
(
rcv
=
urb
->
context
)
||
!
(
instance
=
rcv
->
instance
)
)
{
if
(
!
urb
||
!
(
rcv
=
urb
->
context
))
{
dbg
(
"udsl_complete_receive: bad urb!"
);
return
;
}
vdbg
(
"udsl_complete_receive entered (urb 0x%p, status %d)"
,
urb
,
urb
->
status
);
instance
=
rcv
->
instance
;
buf
=
rcv
->
buffer
;
buf
->
filled_cells
=
urb
->
actual_length
/
ATM_CELL_SIZE
;
vdbg
(
"udsl_complete_receive: urb 0x%p, status %d, actual_length %d, filled_cells %u, rcv 0x%p, buf 0x%p"
,
urb
,
urb
->
status
,
urb
->
actual_length
,
buf
->
filled_cells
,
rcv
,
buf
);
BUG_ON
(
buf
->
filled_cells
>
UDSL_RCV_BUF_SIZE
);
/* may not be in_interrupt() */
spin_lock_irqsave
(
&
instance
->
completed_receivers_lock
,
flags
);
list_add_tail
(
&
rcv
->
list
,
&
instance
->
completed_receivers
);
tasklet_schedule
(
&
instance
->
receive_tasklet
);
spin_unlock_irqrestore
(
&
instance
->
completed_receivers_lock
,
flags
);
spin_lock_irqsave
(
&
instance
->
receive_lock
,
flags
);
list_add
(
&
rcv
->
list
,
&
instance
->
spare_receivers
);
list_add_tail
(
&
buf
->
list
,
&
instance
->
filled_receive_buffers
);
if
(
likely
(
!
urb
->
status
))
tasklet_schedule
(
&
instance
->
receive_tasklet
);
spin_unlock_irqrestore
(
&
instance
->
receive_lock
,
flags
);
}
static
void
udsl_process_receive
(
unsigned
long
data
)
{
struct
udsl_receive_buffer
*
buf
;
struct
udsl_instance_data
*
instance
=
(
struct
udsl_instance_data
*
)
data
;
struct
udsl_receiver
*
rcv
;
unsigned
char
*
data_start
;
struct
sk_buff
*
skb
;
struct
urb
*
urb
;
struct
udsl_vcc_data
*
atmsar_vcc
=
NULL
;
struct
sk_buff
*
new
=
NULL
,
*
tmp
=
NULL
;
int
err
;
vdbg
(
"udsl_process_receive entered"
);
spin_lock_irq
(
&
instance
->
completed_receivers_lock
);
while
(
!
list_empty
(
&
instance
->
completed_receivers
))
{
rcv
=
list_entry
(
instance
->
completed_receivers
.
next
,
struct
udsl_receiver
,
list
);
list_del
(
&
rcv
->
list
);
spin_unlock_irq
(
&
instance
->
completed_receivers_lock
);
urb
=
rcv
->
urb
;
vdbg
(
"udsl_process_receive: got packet %p with length %d and status %d"
,
urb
,
urb
->
actual_length
,
urb
->
status
);
switch
(
urb
->
status
)
{
case
0
:
vdbg
(
"udsl_process_receive: processing urb with rcv %p, urb %p, skb %p"
,
rcv
,
urb
,
rcv
->
skb
);
/* update the skb structure */
skb
=
rcv
->
skb
;
skb_trim
(
skb
,
0
);
skb_put
(
skb
,
urb
->
actual_length
);
data_start
=
skb
->
data
;
vdbg
(
"skb->len = %d"
,
skb
->
len
);
PACKETDEBUG
(
skb
->
data
,
skb
->
len
);
while
((
new
=
udsl_decode_rawcell
(
instance
,
skb
,
&
atmsar_vcc
)))
{
vdbg
(
"(after cell processing)skb->len = %d"
,
new
->
len
);
tmp
=
new
;
new
=
udsl_decode_aal5
(
atmsar_vcc
,
new
);
/* we can't send NULL skbs upstream, the ATM layer would try to close the vcc... */
if
(
new
)
{
vdbg
(
"(after aal5 decap) skb->len = %d"
,
new
->
len
);
if
(
new
->
len
&&
atm_charge
(
atmsar_vcc
->
vcc
,
new
->
truesize
))
{
PACKETDEBUG
(
new
->
data
,
new
->
len
);
atmsar_vcc
->
vcc
->
push
(
atmsar_vcc
->
vcc
,
new
);
}
else
{
dbg
(
"dropping incoming packet : vcc->sk->rcvbuf = %d, skb->true_size = %d"
,
atmsar_vcc
->
vcc
->
sk
->
rcvbuf
,
new
->
truesize
);
dev_kfree_skb
(
new
);
}
}
else
{
dbg
(
"udsl_decode_aal5 returned NULL!"
);
dev_kfree_skb
(
tmp
);
}
}
/* restore skb */
skb_push
(
skb
,
skb
->
data
-
data_start
);
usb_fill_bulk_urb
(
urb
,
instance
->
usb_dev
,
usb_rcvbulkpipe
(
instance
->
usb_dev
,
UDSL_ENDPOINT_DATA_IN
),
(
unsigned
char
*
)
rcv
->
skb
->
data
,
UDSL_RCV_BUFFER_SIZE
*
ATM_CELL_SIZE
,
udsl_complete_receive
,
rcv
);
if
(
!
(
err
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
)))
break
;
dbg
(
"udsl_process_receive: submission failed (%d)"
,
err
);
/* fall through */
default:
/* error or urb unlinked */
vdbg
(
"udsl_process_receive: adding to spare_receivers"
);
spin_lock_irq
(
&
instance
->
spare_receivers_lock
);
list_add
(
&
rcv
->
list
,
&
instance
->
spare_receivers
);
spin_unlock_irq
(
&
instance
->
spare_receivers_lock
);
made_progress:
while
(
!
list_empty
(
&
instance
->
spare_receive_buffers
))
{
spin_lock_irq
(
&
instance
->
receive_lock
);
if
(
list_empty
(
&
instance
->
spare_receivers
))
{
spin_unlock_irq
(
&
instance
->
receive_lock
);
break
;
}
/* switch */
spin_lock_irq
(
&
instance
->
completed_receivers_lock
);
}
/* while */
spin_unlock_irq
(
&
instance
->
completed_receivers_lock
);
vdbg
(
"udsl_process_receive successful"
);
}
static
void
udsl_fire_receivers
(
struct
udsl_instance_data
*
instance
)
{
struct
list_head
receivers
,
*
pos
,
*
n
;
INIT_LIST_HEAD
(
&
receivers
);
down
(
&
instance
->
serialize
);
spin_lock_irq
(
&
instance
->
spare_receivers_lock
);
list_splice_init
(
&
instance
->
spare_receivers
,
&
receivers
);
spin_unlock_irq
(
&
instance
->
spare_receivers_lock
);
}
rcv
=
list_entry
(
instance
->
spare_receivers
.
next
,
struct
udsl_receiver
,
list
);
list_del
(
&
rcv
->
list
);
spin_unlock_irq
(
&
instance
->
receive_lock
);
list_for_each_safe
(
pos
,
n
,
&
receivers
)
{
struct
udsl_receiver
*
rcv
=
list_entry
(
pos
,
struct
udsl_receiver
,
list
);
buf
=
list_entry
(
instance
->
spare_receive_buffers
.
next
,
struct
udsl_receive_buffer
,
list
);
list_del
(
&
buf
->
list
);
dbg
(
"udsl_fire_receivers: firing urb %p"
,
rcv
->
urb
)
;
rcv
->
buffer
=
buf
;
usb_fill_bulk_urb
(
rcv
->
urb
,
instance
->
usb_dev
,
usb_rcvbulkpipe
(
instance
->
usb_dev
,
UDSL_ENDPOINT_DATA_IN
),
(
unsigned
char
*
)
rcv
->
skb
->
data
,
UDSL_RCV_BUF
FER
_SIZE
*
ATM_CELL_SIZE
,
buf
->
base
,
UDSL_RCV_BUF_SIZE
*
ATM_CELL_SIZE
,
udsl_complete_receive
,
rcv
);
if
(
usb_submit_urb
(
rcv
->
urb
,
GFP_KERNEL
)
<
0
)
{
dbg
(
"udsl_fire_receivers: submit failed!"
);
spin_lock_irq
(
&
instance
->
spare_receivers_lock
);
list_move
(
pos
,
&
instance
->
spare_receivers
);
spin_unlock_irq
(
&
instance
->
spare_receivers_lock
);
vdbg
(
"udsl_process_receive: sending urb 0x%p, rcv 0x%p, buf 0x%p"
,
rcv
->
urb
,
rcv
,
buf
);
if
((
err
=
usb_submit_urb
(
rcv
->
urb
,
GFP_ATOMIC
))
<
0
)
{
dbg
(
"udsl_process_receive: urb submission failed (%d)!"
,
err
);
list_add
(
&
buf
->
list
,
&
instance
->
spare_receive_buffers
);
spin_lock_irq
(
&
instance
->
receive_lock
);
list_add
(
&
rcv
->
list
,
&
instance
->
spare_receivers
);
spin_unlock_irq
(
&
instance
->
receive_lock
);
break
;
}
}
up
(
&
instance
->
serialize
);
spin_lock_irq
(
&
instance
->
receive_lock
);
if
(
list_empty
(
&
instance
->
filled_receive_buffers
))
{
spin_unlock_irq
(
&
instance
->
receive_lock
);
return
;
/* done - no more buffers */
}
buf
=
list_entry
(
instance
->
filled_receive_buffers
.
next
,
struct
udsl_receive_buffer
,
list
);
list_del
(
&
buf
->
list
);
spin_unlock_irq
(
&
instance
->
receive_lock
);
vdbg
(
"udsl_process_receive: processing buf 0x%p"
,
buf
);
udsl_extract_cells
(
instance
,
buf
->
base
,
buf
->
filled_cells
);
list_add
(
&
buf
->
list
,
&
instance
->
spare_receive_buffers
);
goto
made_progress
;
}
...
...
@@ -673,7 +592,7 @@ static void udsl_complete_send (struct urb *urb, struct pt_regs *regs)
/* may not be in_interrupt() */
spin_lock_irqsave
(
&
instance
->
send_lock
,
flags
);
list_add
(
&
snd
->
list
,
&
instance
->
spare_senders
);
list_add
(
&
snd
->
buffer
->
list
,
&
instance
->
spare_buffers
);
list_add
(
&
snd
->
buffer
->
list
,
&
instance
->
spare_
send_
buffers
);
tasklet_schedule
(
&
instance
->
send_tasklet
);
spin_unlock_irqrestore
(
&
instance
->
send_lock
,
flags
);
}
...
...
@@ -681,17 +600,17 @@ static void udsl_complete_send (struct urb *urb, struct pt_regs *regs)
static
void
udsl_process_send
(
unsigned
long
data
)
{
struct
udsl_send_buffer
*
buf
;
int
err
;
struct
udsl_instance_data
*
instance
=
(
struct
udsl_instance_data
*
)
data
;
unsigned
int
num_written
;
struct
sk_buff
*
skb
;
struct
udsl_sender
*
snd
;
int
err
;
unsigned
int
num_written
;
made_progress:
spin_lock_irq
(
&
instance
->
send_lock
);
while
(
!
list_empty
(
&
instance
->
spare_senders
))
{
if
(
!
list_empty
(
&
instance
->
filled_buffers
))
{
buf
=
list_entry
(
instance
->
filled_buffers
.
next
,
struct
udsl_send_buffer
,
list
);
if
(
!
list_empty
(
&
instance
->
filled_
send_
buffers
))
{
buf
=
list_entry
(
instance
->
filled_
send_
buffers
.
next
,
struct
udsl_send_buffer
,
list
);
list_del
(
&
buf
->
list
);
}
else
if
((
buf
=
instance
->
current_buffer
))
{
instance
->
current_buffer
=
NULL
;
...
...
@@ -707,7 +626,7 @@ static void udsl_process_send (unsigned long data)
instance
->
usb_dev
,
usb_sndbulkpipe
(
instance
->
usb_dev
,
UDSL_ENDPOINT_DATA_OUT
),
buf
->
base
,
(
UDSL_SND_BUF
FER
_SIZE
-
buf
->
free_cells
)
*
ATM_CELL_SIZE
,
(
UDSL_SND_BUF_SIZE
-
buf
->
free_cells
)
*
ATM_CELL_SIZE
,
udsl_complete_send
,
snd
);
...
...
@@ -718,33 +637,32 @@ static void udsl_process_send (unsigned long data)
spin_lock_irq
(
&
instance
->
send_lock
);
list_add
(
&
snd
->
list
,
&
instance
->
spare_senders
);
spin_unlock_irq
(
&
instance
->
send_lock
);
list_add
(
&
buf
->
list
,
&
instance
->
filled_buffers
);
return
;
list_add
(
&
buf
->
list
,
&
instance
->
filled_
send_
buffers
);
return
;
/* bail out */
}
spin_lock_irq
(
&
instance
->
send_lock
);
}
/* while */
spin_unlock_irq
(
&
instance
->
send_lock
);
if
(
!
instance
->
current_skb
&&
!
(
instance
->
current_skb
=
skb_dequeue
(
&
instance
->
sndqueue
)))
{
if
(
!
instance
->
current_skb
&&
!
(
instance
->
current_skb
=
skb_dequeue
(
&
instance
->
sndqueue
)))
return
;
/* done - no more skbs */
}
skb
=
instance
->
current_skb
;
if
(
!
(
buf
=
instance
->
current_buffer
))
{
spin_lock_irq
(
&
instance
->
send_lock
);
if
(
list_empty
(
&
instance
->
spare_buffers
))
{
if
(
list_empty
(
&
instance
->
spare_
send_
buffers
))
{
instance
->
current_buffer
=
NULL
;
spin_unlock_irq
(
&
instance
->
send_lock
);
return
;
/* done - no more buffers */
}
buf
=
list_entry
(
instance
->
spare_buffers
.
next
,
struct
udsl_send_buffer
,
list
);
buf
=
list_entry
(
instance
->
spare_
send_
buffers
.
next
,
struct
udsl_send_buffer
,
list
);
list_del
(
&
buf
->
list
);
spin_unlock_irq
(
&
instance
->
send_lock
);
buf
->
free_start
=
buf
->
base
;
buf
->
free_cells
=
UDSL_SND_BUF
FER
_SIZE
;
buf
->
free_cells
=
UDSL_SND_BUF_SIZE
;
instance
->
current_buffer
=
buf
;
}
...
...
@@ -754,7 +672,7 @@ static void udsl_process_send (unsigned long data)
vdbg
(
"udsl_process_send: wrote %u cells from skb 0x%p to buffer 0x%p"
,
num_written
,
skb
,
buf
);
if
(
!
(
buf
->
free_cells
-=
num_written
))
{
list_add_tail
(
&
buf
->
list
,
&
instance
->
filled_buffers
);
list_add_tail
(
&
buf
->
list
,
&
instance
->
filled_
send_
buffers
);
instance
->
current_buffer
=
NULL
;
}
...
...
@@ -766,7 +684,7 @@ static void udsl_process_send (unsigned long data)
if
(
vcc
->
pop
)
vcc
->
pop
(
vcc
,
skb
);
else
kfree_skb
(
skb
);
dev_
kfree_skb
(
skb
);
instance
->
current_skb
=
NULL
;
atomic_inc
(
&
vcc
->
stats
->
tx
);
...
...
@@ -788,7 +706,7 @@ static void udsl_cancel_send (struct udsl_instance_data *instance, struct atm_vc
if
(
vcc
->
pop
)
vcc
->
pop
(
vcc
,
skb
);
else
kfree_skb
(
skb
);
dev_
kfree_skb
(
skb
);
}
spin_unlock_irq
(
&
instance
->
sndqueue
.
lock
);
...
...
@@ -799,7 +717,7 @@ static void udsl_cancel_send (struct udsl_instance_data *instance, struct atm_vc
if
(
vcc
->
pop
)
vcc
->
pop
(
vcc
,
skb
);
else
kfree_skb
(
skb
);
dev_
kfree_skb
(
skb
);
}
tasklet_enable
(
&
instance
->
send_tasklet
);
dbg
(
"udsl_cancel_send done"
);
...
...
@@ -851,6 +769,7 @@ static void udsl_atm_dev_close (struct atm_dev *dev)
dbg
(
"udsl_atm_dev_close: queue has %u elements"
,
instance
->
sndqueue
.
qlen
);
tasklet_kill
(
&
instance
->
receive_tasklet
);
tasklet_kill
(
&
instance
->
send_tasklet
);
kfree
(
instance
);
dev
->
dev_data
=
NULL
;
...
...
@@ -871,8 +790,8 @@ static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t *pos, char *page)
if
(
!
left
--
)
return
sprintf
(
page
,
"MAC: %02x:%02x:%02x:%02x:%02x:%02x
\n
"
,
atm_dev
->
esi
[
0
],
atm_dev
->
esi
[
1
],
atm_dev
->
esi
[
2
],
atm_dev
->
esi
[
3
],
atm_dev
->
esi
[
4
],
atm_dev
->
esi
[
5
]);
atm_dev
->
esi
[
0
],
atm_dev
->
esi
[
1
],
atm_dev
->
esi
[
2
],
atm_dev
->
esi
[
3
],
atm_dev
->
esi
[
4
],
atm_dev
->
esi
[
5
]);
if
(
!
left
--
)
return
sprintf
(
page
,
"AAL5: tx %d ( %d err ), rx %d ( %d err, %d drop )
\n
"
,
...
...
@@ -925,7 +844,7 @@ static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci)
return
-
EINVAL
;
/* only support AAL5 */
if
(
vcc
->
qos
.
aal
!=
ATM_AAL5
)
if
(
(
vcc
->
qos
.
aal
!=
ATM_AAL5
)
||
(
vcc
->
qos
.
rxtp
.
max_sdu
<
0
)
||
(
vcc
->
qos
.
rxtp
.
max_sdu
>
ATM_MAX_AAL5_PDU
)
)
return
-
EINVAL
;
if
(
!
instance
->
firmware_loaded
)
{
...
...
@@ -949,7 +868,7 @@ static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci)
new
->
vcc
=
vcc
;
new
->
vpi
=
vpi
;
new
->
vci
=
vci
;
new
->
m
tu
=
UDSL_MAX_AAL5_MRU
;
new
->
m
ax_pdu
=
max
(
1
,
UDSL_NUM_CELLS
(
vcc
->
qos
.
rxtp
.
max_sdu
))
*
ATM_CELL_PAYLOAD
;
vcc
->
dev_data
=
new
;
vcc
->
vpi
=
vpi
;
...
...
@@ -965,7 +884,7 @@ static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci)
up
(
&
instance
->
serialize
);
udsl_fire_receivers
(
instance
);
tasklet_schedule
(
&
instance
->
receive_tasklet
);
dbg
(
"udsl_atm_open: allocated vcc data 0x%p (max_pdu: %u)"
,
new
,
new
->
max_pdu
);
...
...
@@ -994,9 +913,9 @@ static void udsl_atm_close (struct atm_vcc *vcc)
list_del
(
&
vcc_data
->
list
);
tasklet_enable
(
&
instance
->
receive_tasklet
);
if
(
vcc_data
->
reasBuffer
)
kfree_skb
(
vcc_data
->
reasBuffer
);
vcc_data
->
reasBuffer
=
NULL
;
if
(
vcc_data
->
skb
)
dev_kfree_skb
(
vcc_data
->
skb
);
vcc_data
->
skb
=
NULL
;
kfree
(
vcc_data
);
vcc
->
dev_data
=
NULL
;
...
...
@@ -1041,7 +960,9 @@ static int udsl_set_alternate (struct udsl_instance_data *instance)
instance
->
firmware_loaded
=
1
;
}
up
(
&
instance
->
serialize
);
udsl_fire_receivers
(
instance
);
tasklet_schedule
(
&
instance
->
receive_tasklet
);
return
0
;
}
...
...
@@ -1057,10 +978,10 @@ static int udsl_usb_ioctl (struct usb_interface *intf, unsigned int code, void *
}
switch
(
code
)
{
case
UDSL_IOCTL_
START
:
case
UDSL_IOCTL_
LINE_UP
:
instance
->
atm_dev
->
signal
=
ATM_PHY_SIG_FOUND
;
return
udsl_set_alternate
(
instance
);
case
UDSL_IOCTL_
STOP
:
case
UDSL_IOCTL_
LINE_DOWN
:
instance
->
atm_dev
->
signal
=
ATM_PHY_SIG_LOST
;
return
0
;
default:
...
...
@@ -1101,31 +1022,25 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i
INIT_LIST_HEAD
(
&
instance
->
vcc_list
);
spin_lock_init
(
&
instance
->
spare_receivers
_lock
);
spin_lock_init
(
&
instance
->
receive
_lock
);
INIT_LIST_HEAD
(
&
instance
->
spare_receivers
);
spin_lock_init
(
&
instance
->
completed_receivers_lock
);
INIT_LIST_HEAD
(
&
instance
->
completed_receivers
);
INIT_LIST_HEAD
(
&
instance
->
filled_receive_buffers
);
tasklet_init
(
&
instance
->
receive_tasklet
,
udsl_process_receive
,
(
unsigned
long
)
instance
);
INIT_LIST_HEAD
(
&
instance
->
spare_receive_buffers
);
skb_queue_head_init
(
&
instance
->
sndqueue
);
spin_lock_init
(
&
instance
->
send_lock
);
INIT_LIST_HEAD
(
&
instance
->
spare_senders
);
INIT_LIST_HEAD
(
&
instance
->
spare_buffers
);
INIT_LIST_HEAD
(
&
instance
->
spare_
send_
buffers
);
tasklet_init
(
&
instance
->
send_tasklet
,
udsl_process_send
,
(
unsigned
long
)
instance
);
INIT_LIST_HEAD
(
&
instance
->
filled_buffers
);
INIT_LIST_HEAD
(
&
instance
->
filled_
send_
buffers
);
/* receive init */
for
(
i
=
0
;
i
<
UDSL_NUMBER_RCV_URBS
;
i
++
)
{
struct
udsl_receiver
*
rcv
=
&
(
instance
->
all_receivers
[
i
]);
if
(
!
(
rcv
->
skb
=
dev_alloc_skb
(
UDSL_RCV_BUFFER_SIZE
*
ATM_CELL_SIZE
)))
{
dbg
(
"udsl_usb_probe: no memory for skb %d!"
,
i
);
goto
fail
;
}
for
(
i
=
0
;
i
<
UDSL_NUM_RCV_URBS
;
i
++
)
{
struct
udsl_receiver
*
rcv
=
&
(
instance
->
receivers
[
i
]);
if
(
!
(
rcv
->
urb
=
usb_alloc_urb
(
0
,
GFP_KERNEL
)))
{
dbg
(
"udsl_usb_probe: no memory for receive urb %d!"
,
i
);
...
...
@@ -1135,13 +1050,22 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i
rcv
->
instance
=
instance
;
list_add
(
&
rcv
->
list
,
&
instance
->
spare_receivers
);
}
for
(
i
=
0
;
i
<
UDSL_NUM_RCV_BUFS
;
i
++
)
{
struct
udsl_receive_buffer
*
buf
=
&
(
instance
->
receive_buffers
[
i
]);
if
(
!
(
buf
->
base
=
kmalloc
(
UDSL_RCV_BUF_SIZE
*
ATM_CELL_SIZE
,
GFP_KERNEL
)))
{
dbg
(
"udsl_usb_probe: no memory for receive buffer %d!"
,
i
);
goto
fail
;
}
dbg
(
"udsl_usb_probe: skb->truesize = %d (asked for %d)"
,
rcv
->
skb
->
truesize
,
UDSL_RCV_BUF_SIZE
*
ATM_CELL_SIZE
);
list_add
(
&
buf
->
list
,
&
instance
->
spare_receive_buffers
);
}
/* send init */
for
(
i
=
0
;
i
<
UDSL_NUM
BER
_SND_URBS
;
i
++
)
{
struct
udsl_sender
*
snd
=
&
(
instance
->
all_senders
[
i
]);
for
(
i
=
0
;
i
<
UDSL_NUM_SND_URBS
;
i
++
)
{
struct
udsl_sender
*
snd
=
&
(
instance
->
senders
[
i
]);
if
(
!
(
snd
->
urb
=
usb_alloc_urb
(
0
,
GFP_KERNEL
)))
{
dbg
(
"udsl_usb_probe: no memory for send urb %d!"
,
i
);
...
...
@@ -1153,18 +1077,18 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i
list_add
(
&
snd
->
list
,
&
instance
->
spare_senders
);
}
for
(
i
=
0
;
i
<
UDSL_NUM
BER
_SND_BUFS
;
i
++
)
{
struct
udsl_send_buffer
*
buf
=
&
(
instance
->
all_buffers
[
i
]);
for
(
i
=
0
;
i
<
UDSL_NUM_SND_BUFS
;
i
++
)
{
struct
udsl_send_buffer
*
buf
=
&
(
instance
->
send_buffers
[
i
]);
if
(
!
(
buf
->
base
=
kmalloc
(
UDSL_SND_BUF
FER
_SIZE
*
ATM_CELL_SIZE
,
GFP_KERNEL
)))
{
if
(
!
(
buf
->
base
=
kmalloc
(
UDSL_SND_BUF_SIZE
*
ATM_CELL_SIZE
,
GFP_KERNEL
)))
{
dbg
(
"udsl_usb_probe: no memory for send buffer %d!"
,
i
);
goto
fail
;
}
list_add
(
&
buf
->
list
,
&
instance
->
spare_buffers
);
list_add
(
&
buf
->
list
,
&
instance
->
spare_
send_
buffers
);
}
/*
atm
init */
/*
ATM
init */
if
(
!
(
instance
->
atm_dev
=
atm_dev_register
(
udsl_driver_name
,
&
udsl_atm_devops
,
-
1
,
0
)))
{
dbg
(
"udsl_usb_probe: failed to register ATM device!"
);
goto
fail
;
...
...
@@ -1174,14 +1098,14 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i
instance
->
atm_dev
->
ci_range
.
vci_bits
=
ATM_CI_MAX
;
instance
->
atm_dev
->
signal
=
ATM_PHY_SIG_UNKNOWN
;
/* t
mp init atm
device, set to 128kbit */
/* t
emp init ATM
device, set to 128kbit */
instance
->
atm_dev
->
link_rate
=
128
*
1000
/
424
;
/* set MAC address, it is stored in the serial number */
memset
(
instance
->
atm_dev
->
esi
,
0
,
sizeof
(
instance
->
atm_dev
->
esi
));
if
(
usb_string
(
dev
,
dev
->
descriptor
.
iSerialNumber
,
mac_str
,
sizeof
(
mac_str
))
==
12
)
for
(
i
=
0
;
i
<
6
;
i
++
)
instance
->
atm_dev
->
esi
[
i
]
=
(
hex2int
(
mac_str
[
i
*
2
])
*
16
)
+
(
hex2int
(
mac_str
[
i
*
2
+
1
]));
instance
->
atm_dev
->
esi
[
i
]
=
(
hex2int
(
mac_str
[
i
*
2
])
*
16
)
+
(
hex2int
(
mac_str
[
i
*
2
+
1
]));
/* device description */
buf
=
instance
->
description
;
...
...
@@ -1215,20 +1139,17 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i
return
0
;
fail:
for
(
i
=
0
;
i
<
UDSL_NUM
BER
_SND_BUFS
;
i
++
)
kfree
(
instance
->
all_buffers
[
i
].
base
);
for
(
i
=
0
;
i
<
UDSL_NUM_SND_BUFS
;
i
++
)
kfree
(
instance
->
send_buffers
[
i
].
base
);
for
(
i
=
0
;
i
<
UDSL_NUM
BER
_SND_URBS
;
i
++
)
usb_free_urb
(
instance
->
all_senders
[
i
].
urb
);
for
(
i
=
0
;
i
<
UDSL_NUM_SND_URBS
;
i
++
)
usb_free_urb
(
instance
->
senders
[
i
].
urb
);
for
(
i
=
0
;
i
<
UDSL_NUM
BER_RCV_URBS
;
i
++
)
{
struct
udsl_receiver
*
rcv
=
&
(
instance
->
all_receivers
[
i
]
);
for
(
i
=
0
;
i
<
UDSL_NUM
_RCV_BUFS
;
i
++
)
kfree
(
instance
->
receive_buffers
[
i
].
base
);
usb_free_urb
(
rcv
->
urb
);
if
(
rcv
->
skb
)
kfree_skb
(
rcv
->
skb
);
}
for
(
i
=
0
;
i
<
UDSL_NUM_RCV_URBS
;
i
++
)
usb_free_urb
(
instance
->
receivers
[
i
].
urb
);
kfree
(
instance
);
...
...
@@ -1239,7 +1160,7 @@ static void udsl_usb_disconnect (struct usb_interface *intf)
{
struct
udsl_instance_data
*
instance
=
usb_get_intfdata
(
intf
);
struct
list_head
*
pos
;
unsigned
int
count
=
0
;
unsigned
int
count
;
int
result
,
i
;
dbg
(
"udsl_usb_disconnect entered"
);
...
...
@@ -1251,38 +1172,25 @@ static void udsl_usb_disconnect (struct usb_interface *intf)
return
;
}
tasklet_disable
(
&
instance
->
receive_tasklet
);
/* receive finalize */
down
(
&
instance
->
serialize
);
/* vs udsl_fire_receivers */
/* no need to take the spinlock */
list_for_each
(
pos
,
&
instance
->
spare_receivers
)
if
(
++
count
>
UDSL_NUMBER_RCV_URBS
)
panic
(
__FILE__
": memory corruption detected at line %d!
\n
"
,
__LINE__
);
INIT_LIST_HEAD
(
&
instance
->
spare_receivers
);
up
(
&
instance
->
serialize
);
dbg
(
"udsl_usb_disconnect: flushed %u spare receivers"
,
count
);
count
=
UDSL_NUMBER_RCV_URBS
-
count
;
tasklet_disable
(
&
instance
->
receive_tasklet
);
for
(
i
=
0
;
i
<
UDSL_NUM
BER
_RCV_URBS
;
i
++
)
if
((
result
=
usb_unlink_urb
(
instance
->
all_receivers
[
i
].
urb
))
<
0
)
for
(
i
=
0
;
i
<
UDSL_NUM_RCV_URBS
;
i
++
)
if
((
result
=
usb_unlink_urb
(
instance
->
receivers
[
i
].
urb
))
<
0
)
dbg
(
"udsl_usb_disconnect: usb_unlink_urb on receive urb %d returned %d"
,
i
,
result
);
/* wait for completion handlers to finish */
do
{
unsigned
int
completed
=
0
;
spin_lock_irq
(
&
instance
->
completed_receivers_lock
);
list_for_each
(
pos
,
&
instance
->
completed_receivers
)
if
(
++
completed
>
count
)
count
=
0
;
spin_lock_irq
(
&
instance
->
receive_lock
);
list_for_each
(
pos
,
&
instance
->
spare_receivers
)
if
(
++
count
>
UDSL_NUM_RCV_URBS
)
panic
(
__FILE__
": memory corruption detected at line %d!
\n
"
,
__LINE__
);
spin_unlock_irq
(
&
instance
->
completed_receivers
_lock
);
spin_unlock_irq
(
&
instance
->
receive
_lock
);
dbg
(
"udsl_usb_disconnect: found %u
completed receivers"
,
completed
);
dbg
(
"udsl_usb_disconnect: found %u
spare receivers"
,
count
);
if
(
co
mpleted
==
count
)
if
(
co
unt
==
UDSL_NUM_RCV_URBS
)
break
;
set_current_state
(
TASK_RUNNING
);
...
...
@@ -1290,37 +1198,36 @@ static void udsl_usb_disconnect (struct usb_interface *intf)
}
while
(
1
);
/* no need to take the spinlock */
INIT_LIST_HEAD
(
&
instance
->
completed_receivers
);
INIT_LIST_HEAD
(
&
instance
->
filled_receive_buffers
);
INIT_LIST_HEAD
(
&
instance
->
spare_receive_buffers
);
tasklet_enable
(
&
instance
->
receive_tasklet
);
tasklet_kill
(
&
instance
->
receive_tasklet
);
for
(
i
=
0
;
i
<
UDSL_NUM
BER_RCV_URBS
;
i
++
)
{
struct
udsl_receiver
*
rcv
=
&
(
instance
->
all_receivers
[
i
]
);
for
(
i
=
0
;
i
<
UDSL_NUM
_RCV_URBS
;
i
++
)
usb_free_urb
(
instance
->
receivers
[
i
].
urb
);
usb_free_urb
(
rcv
->
urb
);
kfree_skb
(
rcv
->
skb
);
}
for
(
i
=
0
;
i
<
UDSL_NUM_RCV_BUFS
;
i
++
)
kfree
(
instance
->
receive_buffers
[
i
].
base
);
/* send finalize */
tasklet_disable
(
&
instance
->
send_tasklet
);
for
(
i
=
0
;
i
<
UDSL_NUM
BER
_SND_URBS
;
i
++
)
if
((
result
=
usb_unlink_urb
(
instance
->
all_senders
[
i
].
urb
))
<
0
)
for
(
i
=
0
;
i
<
UDSL_NUM_SND_URBS
;
i
++
)
if
((
result
=
usb_unlink_urb
(
instance
->
senders
[
i
].
urb
))
<
0
)
dbg
(
"udsl_usb_disconnect: usb_unlink_urb on send urb %d returned %d"
,
i
,
result
);
/* wait for completion handlers to finish */
do
{
count
=
0
;
spin_lock
(
&
instance
->
send_lock
);
spin_lock
_irq
(
&
instance
->
send_lock
);
list_for_each
(
pos
,
&
instance
->
spare_senders
)
if
(
++
count
>
UDSL_NUM
BER
_SND_URBS
)
if
(
++
count
>
UDSL_NUM_SND_URBS
)
panic
(
__FILE__
": memory corruption detected at line %d!
\n
"
,
__LINE__
);
spin_unlock
(
&
instance
->
send_lock
);
spin_unlock
_irq
(
&
instance
->
send_lock
);
dbg
(
"udsl_usb_disconnect: found %u spare senders"
,
count
);
if
(
count
==
UDSL_NUM
BER
_SND_URBS
)
if
(
count
==
UDSL_NUM_SND_URBS
)
break
;
set_current_state
(
TASK_RUNNING
);
...
...
@@ -1329,22 +1236,22 @@ static void udsl_usb_disconnect (struct usb_interface *intf)
/* no need to take the spinlock */
INIT_LIST_HEAD
(
&
instance
->
spare_senders
);
INIT_LIST_HEAD
(
&
instance
->
spare_buffers
);
INIT_LIST_HEAD
(
&
instance
->
spare_
send_
buffers
);
instance
->
current_buffer
=
NULL
;
tasklet_enable
(
&
instance
->
send_tasklet
);
for
(
i
=
0
;
i
<
UDSL_NUM
BER
_SND_URBS
;
i
++
)
usb_free_urb
(
instance
->
all_senders
[
i
].
urb
);
for
(
i
=
0
;
i
<
UDSL_NUM_SND_URBS
;
i
++
)
usb_free_urb
(
instance
->
senders
[
i
].
urb
);
for
(
i
=
0
;
i
<
UDSL_NUM
BER
_SND_BUFS
;
i
++
)
kfree
(
instance
->
all_buffers
[
i
].
base
);
for
(
i
=
0
;
i
<
UDSL_NUM_SND_BUFS
;
i
++
)
kfree
(
instance
->
send_buffers
[
i
].
base
);
wmb
();
instance
->
usb_dev
=
NULL
;
/*
atm
finalize */
shutdown_atm_dev
(
instance
->
atm_dev
);
/* frees instance */
/*
ATM
finalize */
shutdown_atm_dev
(
instance
->
atm_dev
);
/* frees instance
, kills tasklets
*/
}
...
...
@@ -1392,10 +1299,10 @@ static int udsl_print_packet (const unsigned char *data, int len)
int
i
=
0
,
j
=
0
;
for
(
i
=
0
;
i
<
len
;)
{
buffer
[
0
]
=
'\0'
;
buffer
[
0
]
=
'\0'
;
sprintf
(
buffer
,
"%.3d :"
,
i
);
for
(
j
=
0
;
(
j
<
16
)
&&
(
i
<
len
);
j
++
,
i
++
)
{
sprintf
(
buffer
,
"%s %2.2x"
,
buffer
,
data
[
i
]);
sprintf
(
buffer
,
"%s %2.2x"
,
buffer
,
data
[
i
]);
}
dbg
(
"%s"
,
buffer
);
}
...
...
drivers/usb/storage/transport.c
View file @
1a569433
...
...
@@ -988,7 +988,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
US_DEBUGP
(
"Bulk status Sig 0x%x T 0x%x R %d Stat 0x%x
\n
"
,
le32_to_cpu
(
bcs
.
Signature
),
bcs
.
Tag
,
bcs
.
Residue
,
bcs
.
Status
);
if
(
bcs
.
Signature
!=
cpu_to_le32
(
US_BULK_CS_SIGN
)
||
if
(
(
bcs
.
Signature
!=
cpu_to_le32
(
US_BULK_CS_SIGN
)
&&
bcs
.
Signature
!=
cpu_to_le32
(
US_BULK_CS_OLYMPUS_SIGN
)
)
||
bcs
.
Tag
!=
bcb
.
Tag
||
bcs
.
Status
>
US_BULK_STAT_PHASE
)
{
US_DEBUGP
(
"Bulk logical error
\n
"
);
...
...
drivers/usb/storage/transport.h
View file @
1a569433
...
...
@@ -105,6 +105,8 @@ struct bulk_cs_wrap {
#define US_BULK_CS_WRAP_LEN 13
#define US_BULK_CS_SIGN 0x53425355
/* spells out 'USBS' */
/* This is for Olympus Camedia digital cameras */
#define US_BULK_CS_OLYMPUS_SIGN 0x55425355
/* spells out 'USBU' */
#define US_BULK_STAT_OK 0
#define US_BULK_STAT_FAIL 1
#define US_BULK_STAT_PHASE 2
...
...
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