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
e23525cd
Commit
e23525cd
authored
Sep 04, 2002
by
Greg Kroah-Hartman
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://linuxusb@bkbits.net/linus-2.5
into kroah.com:/home/greg/linux/BK/gregkh-2.5
parents
e42e97d6
681cb8eb
Changes
18
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
864 additions
and
566 deletions
+864
-566
drivers/usb/core/hcd.c
drivers/usb/core/hcd.c
+11
-10
drivers/usb/core/inode.c
drivers/usb/core/inode.c
+32
-11
drivers/usb/host/ehci-dbg.c
drivers/usb/host/ehci-dbg.c
+80
-61
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-hcd.c
+75
-26
drivers/usb/host/ehci-hub.c
drivers/usb/host/ehci-hub.c
+9
-4
drivers/usb/host/ehci-q.c
drivers/usb/host/ehci-q.c
+45
-62
drivers/usb/host/ehci-sched.c
drivers/usb/host/ehci-sched.c
+14
-18
drivers/usb/host/ehci.h
drivers/usb/host/ehci.h
+24
-0
drivers/usb/host/ohci-dbg.c
drivers/usb/host/ohci-dbg.c
+222
-34
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-hcd.c
+37
-42
drivers/usb/host/ohci-mem.c
drivers/usb/host/ohci-mem.c
+0
-27
drivers/usb/host/ohci-q.c
drivers/usb/host/ohci-q.c
+164
-144
drivers/usb/host/ohci.h
drivers/usb/host/ohci.h
+12
-15
drivers/usb/host/uhci-hcd.c
drivers/usb/host/uhci-hcd.c
+86
-101
drivers/usb/host/uhci-hcd.h
drivers/usb/host/uhci-hcd.h
+35
-8
drivers/usb/net/pegasus.h
drivers/usb/net/pegasus.h
+4
-2
drivers/usb/storage/unusual_devs.h
drivers/usb/storage/unusual_devs.h
+7
-0
drivers/usb/storage/usb.c
drivers/usb/storage/usb.c
+7
-1
No files found.
drivers/usb/core/hcd.c
View file @
e23525cd
...
...
@@ -1020,6 +1020,16 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
if
(
status
)
return
status
;
/* increment urb's reference count as part of giving it to the HCD
* (which now controls it). HCD guarantees that it either returns
* an error or calls giveback(), but not both.
*/
urb
=
usb_get_urb
(
urb
);
if
(
urb
->
dev
==
hcd
->
self
.
root_hub
)
{
urb
->
transfer_flags
|=
URB_NO_DMA_MAP
;
return
rh_urb_enqueue
(
hcd
,
urb
);
}
/* lower level hcd code should use *_dma exclusively */
if
(
!
(
urb
->
transfer_flags
&
URB_NO_DMA_MAP
))
{
if
(
usb_pipecontrol
(
urb
->
pipe
))
...
...
@@ -1038,16 +1048,7 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
:
PCI_DMA_TODEVICE
);
}
/* increment urb's reference count as part of giving it to the HCD
* (which now controls it). HCD guarantees that it either returns
* an error or calls giveback(), but not both.
*/
urb
=
usb_get_urb
(
urb
);
if
(
urb
->
dev
==
hcd
->
self
.
root_hub
)
status
=
rh_urb_enqueue
(
hcd
,
urb
);
else
status
=
hcd
->
driver
->
urb_enqueue
(
hcd
,
urb
,
mem_flags
);
return
status
;
return
hcd
->
driver
->
urb_enqueue
(
hcd
,
urb
,
mem_flags
);
}
/*-------------------------------------------------------------------------*/
...
...
drivers/usb/core/inode.c
View file @
e23525cd
...
...
@@ -27,7 +27,6 @@
/*****************************************************************************/
#define __NO_VERSION__
#include <linux/config.h>
#include <linux/module.h>
#include <linux/fs.h>
...
...
@@ -561,35 +560,57 @@ static void put_mount (struct vfsmount **mount)
static
int
create_special_files
(
void
)
{
struct
dentry
*
parent
;
int
retval
;
int
retval
=
0
;
/* create the devices special file */
retval
=
get_mount
(
&
usbdevice_fs_type
,
&
usbdevfs_mount
);
if
(
retval
)
return
retval
;
if
(
retval
)
{
err
(
"Unable to get usbdevfs mount"
);
goto
exit
;
}
retval
=
get_mount
(
&
usb_fs_type
,
&
usbfs_mount
);
if
(
retval
)
{
put_mount
(
&
usbfs_mount
);
return
retval
;
err
(
"Unable to get usbfs mount"
);
goto
error_clean_usbdevfs_mount
;
}
parent
=
usbfs_mount
->
mnt_sb
->
s_root
;
devices_usbfs_dentry
=
fs_create_file
(
"devices"
,
listmode
|
S_IFREG
,
parent
,
devices_usbfs_dentry
=
fs_create_file
(
"devices"
,
listmode
|
S_IFREG
,
parent
,
NULL
,
&
usbdevfs_devices_fops
,
listuid
,
listgid
);
if
(
devices_usbfs_dentry
==
NULL
)
{
err
(
"Unable to create devices usbfs file"
);
return
-
ENODEV
;
retval
=
-
ENODEV
;
goto
error_clean_mounts
;
}
parent
=
usbdevfs_mount
->
mnt_sb
->
s_root
;
devices_usbdevfs_dentry
=
fs_create_file
(
"devices"
,
listmode
|
S_IFREG
,
parent
,
devices_usbdevfs_dentry
=
fs_create_file
(
"devices"
,
listmode
|
S_IFREG
,
parent
,
NULL
,
&
usbdevfs_devices_fops
,
listuid
,
listgid
);
if
(
devices_usbdevfs_dentry
==
NULL
)
{
err
(
"Unable to create devices usbfs file"
);
return
-
ENODEV
;
retval
=
-
ENODEV
;
goto
error_remove_file
;
}
return
0
;
goto
exit
;
error_remove_file:
fs_remove_file
(
devices_usbfs_dentry
);
devices_usbfs_dentry
=
NULL
;
error_clean_mounts:
put_mount
(
&
usbfs_mount
);
error_clean_usbdevfs_mount:
put_mount
(
&
usbdevfs_mount
);
exit:
return
retval
;
}
static
void
remove_special_files
(
void
)
...
...
drivers/usb/host/ehci-dbg.c
View file @
e23525cd
...
...
@@ -57,7 +57,7 @@ static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
strcat
(
buf
,
tmp
);
}
dbg
(
"%s: %s portroute %s"
,
ehci
->
hcd
.
self
.
bus_name
,
label
,
hcd_to_bus
(
&
ehci
->
hcd
)
->
bus_name
,
label
,
buf
);
}
}
...
...
@@ -122,7 +122,8 @@ dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
}
}
static
int
dbg_status_buf
(
char
*
buf
,
unsigned
len
,
char
*
label
,
u32
status
)
static
int
__attribute__
((
__unused__
))
dbg_status_buf
(
char
*
buf
,
unsigned
len
,
char
*
label
,
u32
status
)
{
return
snprintf
(
buf
,
len
,
"%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s"
,
...
...
@@ -140,7 +141,8 @@ static int dbg_status_buf (char *buf, unsigned len, char *label, u32 status)
);
}
static
int
dbg_intr_buf
(
char
*
buf
,
unsigned
len
,
char
*
label
,
u32
enable
)
static
int
__attribute__
((
__unused__
))
dbg_intr_buf
(
char
*
buf
,
unsigned
len
,
char
*
label
,
u32
enable
)
{
return
snprintf
(
buf
,
len
,
"%s%sintrenable %02x%s%s%s%s%s%s"
,
...
...
@@ -213,19 +215,19 @@ dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
static
inline
int
__attribute__
((
__unused__
))
dbg_status_buf
(
char
*
buf
,
unsigned
len
,
char
*
label
,
u32
status
)
{}
{
return
0
;
}
static
inline
int
__attribute__
((
__unused__
))
dbg_command_buf
(
char
*
buf
,
unsigned
len
,
char
*
label
,
u32
command
)
{}
{
return
0
;
}
static
inline
int
__attribute__
((
__unused__
))
dbg_intr_buf
(
char
*
buf
,
unsigned
len
,
char
*
label
,
u32
enable
)
{}
{
return
0
;
}
static
inline
int
__attribute__
((
__unused__
))
dbg_port_buf
(
char
*
buf
,
unsigned
len
,
char
*
label
,
int
port
,
u32
status
)
{}
{
return
0
;
}
#endif
/* DEBUG */
...
...
@@ -248,7 +250,16 @@ dbg_port_buf (char *buf, unsigned len, char *label, int port, u32 status)
dbg ("%s", _buf); \
}
#ifdef DEBUG
/*-------------------------------------------------------------------------*/
#ifdef STUB_DEBUG_FILES
static
inline
void
create_debug_files
(
struct
ehci_hcd
*
bus
)
{
}
static
inline
void
remove_debug_files
(
struct
ehci_hcd
*
bus
)
{
}
#else
/* troubleshooting help: expose state in driverfs */
#define speed_char(info1) ({ char tmp; \
switch (info1 & (3 << 12)) { \
...
...
@@ -258,6 +269,49 @@ dbg_port_buf (char *buf, unsigned len, char *label, int port, u32 status)
default: tmp = '?'; break; \
}; tmp; })
static
void
qh_lines
(
struct
ehci_qh
*
qh
,
char
**
nextp
,
unsigned
*
sizep
)
{
u32
scratch
;
struct
list_head
*
entry
;
struct
ehci_qtd
*
td
;
unsigned
temp
;
unsigned
size
=
*
sizep
;
char
*
next
=
*
nextp
;
scratch
=
cpu_to_le32p
(
&
qh
->
hw_info1
);
temp
=
snprintf
(
next
,
size
,
"qh/%p dev%d %cs ep%d %08x %08x"
,
qh
,
scratch
&
0x007f
,
speed_char
(
scratch
),
(
scratch
>>
8
)
&
0x000f
,
scratch
,
cpu_to_le32p
(
&
qh
->
hw_info2
));
size
-=
temp
;
next
+=
temp
;
list_for_each
(
entry
,
&
qh
->
qtd_list
)
{
td
=
list_entry
(
entry
,
struct
ehci_qtd
,
qtd_list
);
scratch
=
cpu_to_le32p
(
&
td
->
hw_token
);
temp
=
snprintf
(
next
,
size
,
"
\n\t
td/%p %s len=%d %08x urb %p"
,
td
,
({
char
*
tmp
;
switch
((
scratch
>>
8
)
&
0x03
)
{
case
0
:
tmp
=
"out"
;
break
;
case
1
:
tmp
=
"in"
;
break
;
case
2
:
tmp
=
"setup"
;
break
;
default:
tmp
=
"?"
;
break
;
}
tmp
;}),
(
scratch
>>
16
)
&
0x7fff
,
scratch
,
td
->
urb
);
size
-=
temp
;
next
+=
temp
;
}
temp
=
snprintf
(
next
,
size
,
"
\n
"
);
*
sizep
=
size
-
temp
;
*
nextp
=
next
+
temp
;
}
static
ssize_t
show_async
(
struct
device
*
dev
,
char
*
buf
,
size_t
count
,
loff_t
off
)
{
...
...
@@ -284,49 +338,21 @@ show_async (struct device *dev, char *buf, size_t count, loff_t off)
if
(
ehci
->
async
)
{
qh
=
ehci
->
async
;
do
{
u32
scratch
;
struct
list_head
*
entry
;
struct
ehci_qtd
*
td
;
scratch
=
cpu_to_le32p
(
&
qh
->
hw_info1
);
temp
=
snprintf
(
next
,
size
,
"qh %p dev%d %cs ep%d"
,
qh
,
scratch
&
0x007f
,
speed_char
(
scratch
),
(
scratch
>>
8
)
&
0x000f
);
size
-=
temp
;
next
+=
temp
;
list_for_each
(
entry
,
&
qh
->
qtd_list
)
{
td
=
list_entry
(
entry
,
struct
ehci_qtd
,
qtd_list
);
scratch
=
cpu_to_le32p
(
&
td
->
hw_token
);
temp
=
snprintf
(
next
,
size
,
", td %p len=%d tok %04x %s"
,
td
,
scratch
>>
16
,
scratch
&
0xffff
,
({
char
*
tmp
;
switch
((
scratch
>>
8
)
&
0x03
)
{
case
0
:
tmp
=
"out"
;
break
;
case
1
:
tmp
=
"in"
;
break
;
case
2
:
tmp
=
"setup"
;
break
;
default:
tmp
=
"?"
;
break
;
}
tmp
;})
);
size
-=
temp
;
next
+=
temp
;
}
temp
=
snprintf
(
next
,
size
,
"
\n
"
);
size
-=
temp
;
next
+=
temp
;
qh_lines
(
qh
,
&
next
,
&
size
);
}
while
((
qh
=
qh
->
qh_next
.
qh
)
!=
ehci
->
async
);
}
if
(
ehci
->
reclaim
)
{
temp
=
snprintf
(
next
,
size
,
"
\n
reclaim =
\n
"
);
size
-=
temp
;
next
+=
temp
;
qh_lines
(
ehci
->
reclaim
,
&
next
,
&
size
);
}
spin_unlock_irqrestore
(
&
ehci
->
lock
,
flags
);
return
count
-
size
;
}
static
DEVICE_ATTR
(
async
,
S_IRU
SR
,
show_async
,
NULL
);
static
DEVICE_ATTR
(
async
,
S_IRU
GO
,
show_async
,
NULL
);
#define DBG_SCHED_LIMIT 64
...
...
@@ -373,7 +399,7 @@ show_periodic (struct device *dev, char *buf, size_t count, loff_t off)
do
{
switch
(
tag
)
{
case
Q_TYPE_QH
:
temp
=
snprintf
(
next
,
size
,
"
intr-%d
%p"
,
temp
=
snprintf
(
next
,
size
,
"
qh%d/
%p"
,
p
.
qh
->
period
,
p
.
qh
);
size
-=
temp
;
next
+=
temp
;
...
...
@@ -387,12 +413,14 @@ show_periodic (struct device *dev, char *buf, size_t count, loff_t off)
&
p
.
qh
->
hw_info1
);
temp
=
snprintf
(
next
,
size
,
" (%cs dev%d ep%d)"
,
" (%cs dev%d ep%d
[%d/%d] %d
)"
,
speed_char
(
scratch
),
scratch
&
0x007f
,
(
scratch
>>
8
)
&
0x000f
);
(
scratch
>>
8
)
&
0x000f
,
p
.
qh
->
usecs
,
p
.
qh
->
c_usecs
,
scratch
>>
16
);
/* FIXME TD
s
too */
/* FIXME TD
info
too */
if
(
seen_count
<
DBG_SCHED_LIMIT
)
seen
[
seen_count
++
].
qh
=
p
.
qh
;
...
...
@@ -434,7 +462,7 @@ show_periodic (struct device *dev, char *buf, size_t count, loff_t off)
return
count
-
size
;
}
static
DEVICE_ATTR
(
periodic
,
S_IRU
SR
,
show_periodic
,
NULL
);
static
DEVICE_ATTR
(
periodic
,
S_IRU
GO
,
show_periodic
,
NULL
);
#undef DBG_SCHED_LIMIT
...
...
@@ -522,7 +550,7 @@ show_registers (struct device *dev, char *buf, size_t count, loff_t off)
return
count
-
size
;
}
static
DEVICE_ATTR
(
registers
,
S_IRU
SR
,
show_registers
,
NULL
);
static
DEVICE_ATTR
(
registers
,
S_IRU
GO
,
show_registers
,
NULL
);
static
inline
void
create_debug_files
(
struct
ehci_hcd
*
bus
)
{
...
...
@@ -538,14 +566,5 @@ static inline void remove_debug_files (struct ehci_hcd *bus)
device_remove_file
(
&
bus
->
hcd
.
pdev
->
dev
,
&
dev_attr_registers
);
}
#else
/* DEBUG */
static
inline
void
create_debug_files
(
struct
ehci_hcd
*
bus
)
{
}
static
inline
void
remove_debug_files
(
struct
ehci_hcd
*
bus
)
{
}
#endif
/* STUB_DEBUG_FILES */
#endif
/* DEBUG */
drivers/usb/host/ehci-hcd.c
View file @
e23525cd
...
...
@@ -38,7 +38,12 @@
#endif
#include <linux/usb.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,32)
#include "../hcd.h"
#else
#include "../core/hcd.h"
#endif
#include <asm/byteorder.h>
#include <asm/io.h>
...
...
@@ -87,7 +92,7 @@
* 2001-June Works with usb-storage and NEC EHCI on 2.4
*/
#define DRIVER_VERSION "2002-Aug-
06
"
#define DRIVER_VERSION "2002-Aug-
28
"
#define DRIVER_AUTHOR "David Brownell"
#define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
...
...
@@ -104,6 +109,8 @@
#define EHCI_TUNE_MULT_HS 1
/* 1-3 transactions/uframe; 4.10.3 */
#define EHCI_TUNE_MULT_TT 1
#define EHCI_WATCHDOG_JIFFIES (HZ/100)
/* arbitrary; ~10 msec */
/* Initial IRQ latency: lower than default */
static
int
log2_irq_thresh
=
0
;
// 0 to 6
MODULE_PARM
(
log2_irq_thresh
,
"i"
);
...
...
@@ -232,6 +239,19 @@ static void ehci_ready (struct ehci_hcd *ehci)
static
void
ehci_tasklet
(
unsigned
long
param
);
static
void
ehci_irq
(
struct
usb_hcd
*
hcd
);
static
void
ehci_watchdog
(
unsigned
long
param
)
{
struct
ehci_hcd
*
ehci
=
(
struct
ehci_hcd
*
)
param
;
unsigned
long
flags
;
/* guard against lost IAA, which wedges everything */
spin_lock_irqsave
(
&
ehci
->
lock
,
flags
);
ehci_irq
(
&
ehci
->
hcd
);
spin_unlock_irqrestore
(
&
ehci
->
lock
,
flags
);
}
/* EHCI 0.96 (and later) section 5.1 says how to kick BIOS/SMM/...
* off the controller (maybe it can boot from highspeed USB disks).
*/
...
...
@@ -267,6 +287,7 @@ static int ehci_start (struct usb_hcd *hcd)
struct
ehci_hcd
*
ehci
=
hcd_to_ehci
(
hcd
);
u32
temp
;
struct
usb_device
*
udev
;
struct
usb_bus
*
bus
;
int
retval
;
u32
hcc_params
;
u8
tempbyte
;
...
...
@@ -372,16 +393,19 @@ static int ehci_start (struct usb_hcd *hcd)
ehci
->
tasklet
.
func
=
ehci_tasklet
;
ehci
->
tasklet
.
data
=
(
unsigned
long
)
ehci
;
init_timer
(
&
ehci
->
watchdog
);
ehci
->
watchdog
.
function
=
ehci_watchdog
;
ehci
->
watchdog
.
data
=
(
unsigned
long
)
ehci
;
/* wire up the root hub */
hcd
->
self
.
root_hub
=
udev
=
usb_alloc_dev
(
NULL
,
&
hcd
->
self
);
bus
=
hcd_to_bus
(
hcd
);
bus
->
root_hub
=
udev
=
usb_alloc_dev
(
NULL
,
bus
);
if
(
!
udev
)
{
done2:
ehci_mem_cleanup
(
ehci
);
return
-
ENOMEM
;
}
create_debug_files
(
ehci
);
/*
* Start, enabling full USB 2.0 functionality ... usb 1.1 devices
* are explicitly handed to companion controller(s), so no TT is
...
...
@@ -394,7 +418,7 @@ static int ehci_start (struct usb_hcd *hcd)
/* PCI Serial Bus Release Number is at 0x60 offset */
pci_read_config_byte
(
hcd
->
pdev
,
0x60
,
&
tempbyte
);
temp
=
readw
(
&
ehci
->
caps
->
hci_version
);
info
(
"USB %x.%x support enabled, EHCI rev %x.%2x"
,
info
(
"USB %x.%x support enabled, EHCI rev %x.%
0
2x"
,
((
tempbyte
&
0xf0
)
>>
4
),
(
tempbyte
&
0x0f
),
temp
>>
8
,
...
...
@@ -409,16 +433,22 @@ static int ehci_start (struct usb_hcd *hcd)
*/
usb_connect
(
udev
);
udev
->
speed
=
USB_SPEED_HIGH
;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,32)
if
(
usb_new_device
(
udev
)
!=
0
)
{
#else
if
(
usb_register_root_hub
(
udev
,
&
ehci
->
hcd
.
pdev
->
dev
)
!=
0
)
{
#endif
if
(
hcd
->
state
==
USB_STATE_RUNNING
)
ehci_ready
(
ehci
);
ehci_reset
(
ehci
);
hcd
->
self
.
root_hub
=
0
;
bus
->
root_hub
=
0
;
usb_free_dev
(
udev
);
retval
=
-
ENODEV
;
goto
done2
;
}
create_debug_files
(
ehci
);
return
0
;
}
...
...
@@ -428,13 +458,20 @@ static void ehci_stop (struct usb_hcd *hcd)
{
struct
ehci_hcd
*
ehci
=
hcd_to_ehci
(
hcd
);
dbg
(
"%s: stop"
,
hcd
->
self
.
bus_name
);
dbg
(
"%s: stop"
,
hcd
_to_bus
(
hcd
)
->
bus_name
);
/* no more interrupts ... */
if
(
hcd
->
state
==
USB_STATE_RUNNING
)
ehci_ready
(
ehci
);
if
(
in_interrupt
())
/* should not happen!! */
err
(
"stopped %s!"
,
RUN_CONTEXT
);
else
del_timer_sync
(
&
ehci
->
watchdog
);
ehci_reset
(
ehci
);
/* let companion controllers work when we aren't */
writel
(
0
,
&
ehci
->
regs
->
configured_flag
);
remove_debug_files
(
ehci
);
/* root hub is shut down separately (first, when possible) */
...
...
@@ -463,7 +500,7 @@ static int ehci_suspend (struct usb_hcd *hcd, u32 state)
int
ports
;
int
i
;
dbg
(
"%s: suspend to %d"
,
hcd
->
self
.
bus_name
,
state
);
dbg
(
"%s: suspend to %d"
,
hcd
_to_bus
(
hcd
)
->
bus_name
,
state
);
ports
=
HCS_N_PORTS
(
ehci
->
hcs_params
);
...
...
@@ -480,7 +517,7 @@ static int ehci_suspend (struct usb_hcd *hcd, u32 state)
if
((
temp
&
PORT_PE
)
==
0
||
(
temp
&
PORT_OWNER
)
!=
0
)
continue
;
dbg
(
"%s: suspend port %d"
,
hcd
->
self
.
bus_name
,
i
);
dbg
(
"%s: suspend port %d"
,
hcd
_to_bus
(
hcd
)
->
bus_name
,
i
);
temp
|=
PORT_SUSPEND
;
writel
(
temp
,
&
ehci
->
regs
->
port_status
[
i
]);
}
...
...
@@ -502,7 +539,7 @@ static int ehci_resume (struct usb_hcd *hcd)
int
ports
;
int
i
;
dbg
(
"%s: resume"
,
hcd
->
self
.
bus_name
);
dbg
(
"%s: resume"
,
hcd
_to_bus
(
hcd
)
->
bus_name
);
ports
=
HCS_N_PORTS
(
ehci
->
hcs_params
);
...
...
@@ -522,7 +559,7 @@ static int ehci_resume (struct usb_hcd *hcd)
if
((
temp
&
PORT_PE
)
==
0
||
(
temp
&
PORT_SUSPEND
)
!=
0
)
continue
;
dbg
(
"%s: resume port %d"
,
hcd
->
self
.
bus_name
,
i
);
dbg
(
"%s: resume port %d"
,
hcd
_to_bus
(
hcd
)
->
bus_name
,
i
);
temp
|=
PORT_RESUME
;
writel
(
temp
,
&
ehci
->
regs
->
port_status
[
i
]);
readl
(
&
ehci
->
regs
->
command
);
/* unblock posted writes */
...
...
@@ -546,12 +583,17 @@ dbg ("%s: resume port %d", hcd->self.bus_name, i);
static
void
ehci_tasklet
(
unsigned
long
param
)
{
struct
ehci_hcd
*
ehci
=
(
struct
ehci_hcd
*
)
param
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
ehci
->
lock
,
flags
);
if
(
ehci
->
reclaim_ready
)
end_unlink_async
(
ehci
);
scan_async
(
ehci
);
flags
=
end_unlink_async
(
ehci
,
flags
);
flags
=
scan_async
(
ehci
,
flags
);
if
(
ehci
->
next_uframe
!=
-
1
)
scan_periodic
(
ehci
);
flags
=
scan_periodic
(
ehci
,
flags
);
spin_unlock_irqrestore
(
&
ehci
->
lock
,
flags
);
}
/*-------------------------------------------------------------------------*/
...
...
@@ -564,7 +606,7 @@ static void ehci_irq (struct usb_hcd *hcd)
/* e.g. cardbus physical eject */
if
(
status
==
~
(
u32
)
0
)
{
dbg
(
"%s: device removed!"
,
hcd
->
self
.
bus_name
);
dbg
(
"%s: device removed!"
,
hcd
_to_bus
(
hcd
)
->
bus_name
);
goto
dead
;
}
...
...
@@ -597,7 +639,7 @@ static void ehci_irq (struct usb_hcd *hcd)
/* PCI errors [4.15.2.4] */
if
(
unlikely
((
status
&
STS_FATAL
)
!=
0
))
{
err
(
"%s: fatal error, state %x"
,
hcd
->
self
.
bus_name
,
hcd
->
state
);
hcd
_to_bus
(
hcd
)
->
bus_name
,
hcd
->
state
);
dead:
ehci_reset
(
ehci
);
/* generic layer kills/unlinks all urbs, then
...
...
@@ -673,7 +715,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
unsigned
long
flags
;
dbg
(
"%s urb_dequeue %p qh %p state %d"
,
hcd
->
self
.
bus_name
,
urb
,
qh
,
qh
->
qh_state
);
hcd
_to_bus
(
hcd
)
->
bus_name
,
urb
,
qh
,
qh
->
qh_state
);
switch
(
usb_pipetype
(
urb
->
pipe
))
{
// case PIPE_CONTROL:
...
...
@@ -681,7 +723,13 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
default:
spin_lock_irqsave
(
&
ehci
->
lock
,
flags
);
if
(
ehci
->
reclaim
)
{
dbg
(
"dq: reclaim busy, %s"
,
RUN_CONTEXT
);
dbg
(
"dq %p: reclaim = %p, %s"
,
qh
,
ehci
->
reclaim
,
RUN_CONTEXT
);
if
(
qh
==
ehci
->
reclaim
)
{
/* unlinking qh for another queued urb? */
spin_unlock_irqrestore
(
&
ehci
->
lock
,
flags
);
return
0
;
}
if
(
in_interrupt
())
{
spin_unlock_irqrestore
(
&
ehci
->
lock
,
flags
);
return
-
EAGAIN
;
...
...
@@ -702,19 +750,19 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
break
;
case
PIPE_INTERRUPT
:
spin_lock_irqsave
(
&
ehci
->
lock
,
flags
);
if
(
qh
->
qh_state
==
QH_STATE_LINKED
)
{
/* messy, can spin or block a microframe ... */
intr_deschedule
(
ehci
,
qh
,
1
);
flags
=
intr_deschedule
(
ehci
,
qh
,
1
,
flags
);
/* qh_state == IDLE */
}
qh_completions
(
ehci
,
qh
);
flags
=
qh_completions
(
ehci
,
qh
,
flags
);
/* reschedule QH iff another request is queued */
if
(
!
list_empty
(
&
qh
->
qtd_list
)
&&
HCD_IS_RUNNING
(
ehci
->
hcd
.
state
))
{
int
status
;
spin_lock_irqsave
(
&
ehci
->
lock
,
flags
);
status
=
qh_schedule
(
ehci
,
qh
);
spin_unlock_irqrestore
(
&
ehci
->
lock
,
flags
);
...
...
@@ -726,7 +774,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
}
return
status
;
}
spin_unlock_irqrestore
(
&
ehci
->
lock
,
flags
);
break
;
case
PIPE_ISOCHRONOUS
:
...
...
@@ -754,7 +802,8 @@ static void ehci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
/* ASSERT: no requests/urbs are still linked (so no TDs) */
/* ASSERT: nobody can be submitting urbs for this any more */
dbg
(
"%s: free_config devnum %d"
,
hcd
->
self
.
bus_name
,
udev
->
devnum
);
dbg
(
"%s: free_config devnum %d"
,
hcd_to_bus
(
hcd
)
->
bus_name
,
udev
->
devnum
);
spin_lock_irqsave
(
&
ehci
->
lock
,
flags
);
for
(
i
=
0
;
i
<
32
;
i
++
)
{
...
...
@@ -775,7 +824,8 @@ static void ehci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
why
=
0
;
if
(
why
)
{
err
(
"dev %s-%s ep %d-%s error: %s"
,
hcd
->
self
.
bus_name
,
udev
->
devpath
,
hcd_to_bus
(
hcd
)
->
bus_name
,
udev
->
devpath
,
i
&
0xf
,
(
i
&
0x10
)
?
"IN"
:
"OUT"
,
why
);
BUG
();
...
...
@@ -805,8 +855,7 @@ static void ehci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
start_unlink_async
(
ehci
,
qh
);
while
(
qh
->
qh_state
!=
QH_STATE_IDLE
&&
ehci
->
hcd
.
state
!=
USB_STATE_HALT
)
{
spin_unlock_irqrestore
(
&
ehci
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
ehci
->
lock
,
flags
);
wait_ms
(
1
);
spin_lock_irqsave
(
&
ehci
->
lock
,
flags
);
}
...
...
drivers/usb/host/ehci-hub.c
View file @
e23525cd
...
...
@@ -41,14 +41,17 @@ static int check_reset_complete (
/* if reset finished and it's still not enabled -- handoff */
if
(
!
(
port_status
&
PORT_PE
))
{
dbg
(
"%s port %d full speed, give to companion, 0x%x"
,
ehci
->
hcd
.
self
.
bus_name
,
index
+
1
,
port_status
);
hcd_to_bus
(
&
ehci
->
hcd
)
->
bus_name
,
index
+
1
,
port_status
);
// what happens if HCS_N_CC(params) == 0 ?
port_status
|=
PORT_OWNER
;
writel
(
port_status
,
&
ehci
->
regs
->
port_status
[
index
]);
}
else
dbg
(
"%s port %d high speed"
,
ehci
->
hcd
.
self
.
bus_name
,
index
+
1
);
dbg
(
"%s port %d high speed"
,
hcd_to_bus
(
&
ehci
->
hcd
)
->
bus_name
,
index
+
1
);
return
port_status
;
}
...
...
@@ -310,11 +313,13 @@ static int ehci_hub_control (
if
((
temp
&
(
PORT_PE
|
PORT_CONNECT
))
==
PORT_CONNECT
&&
PORT_USB11
(
temp
))
{
dbg
(
"%s port %d low speed, give to companion"
,
hcd
->
self
.
bus_name
,
wIndex
+
1
);
hcd_to_bus
(
&
ehci
->
hcd
)
->
bus_name
,
wIndex
+
1
);
temp
|=
PORT_OWNER
;
}
else
{
vdbg
(
"%s port %d reset"
,
hcd
->
self
.
bus_name
,
wIndex
+
1
);
hcd_to_bus
(
&
ehci
->
hcd
)
->
bus_name
,
wIndex
+
1
);
temp
|=
PORT_RESET
;
temp
&=
~
PORT_PE
;
...
...
drivers/usb/host/ehci-q.c
View file @
e23525cd
...
...
@@ -161,9 +161,10 @@ static inline void qtd_copy_status (struct urb *urb, size_t length, u32 token)
/* urb->lock ignored from here on (hcd is done with urb) */
static
void
ehci_urb_done
(
static
unsigned
long
ehci_urb_done
(
struct
ehci_hcd
*
ehci
,
struct
urb
*
urb
struct
urb
*
urb
,
unsigned
long
flags
)
{
#ifdef INTR_AUTOMAGIC
struct
urb
*
resubmit
=
0
;
...
...
@@ -177,7 +178,7 @@ static void ehci_urb_done (
if
((
qh
->
hw_info2
&
cpu_to_le32
(
0x00ff
))
!=
0
)
{
/* ... update hc-wide periodic stats (for usbfs) */
ehci
->
hcd
.
self
.
bandwidth_int_reqs
--
;
hcd_to_bus
(
&
ehci
->
hcd
)
->
bandwidth_int_reqs
--
;
#ifdef INTR_AUTOMAGIC
if
(
!
((
urb
->
status
==
-
ENOENT
)
...
...
@@ -199,6 +200,8 @@ static void ehci_urb_done (
urb
->
status
=
0
;
}
/* complete() can reenter this HCD */
spin_unlock_irqrestore
(
&
ehci
->
lock
,
flags
);
usb_hcd_giveback_urb
(
&
ehci
->
hcd
,
urb
);
#ifdef INTR_AUTOMAGIC
...
...
@@ -212,34 +215,32 @@ static void ehci_urb_done (
int
status
;
resubmit
->
dev
=
dev
;
status
=
usb_submit_urb
(
resubmit
,
SLAB_KERNEL
);
status
=
SUBMIT_URB
(
resubmit
,
SLAB_KERNEL
);
if
(
status
!=
0
)
err
(
"can't resubmit interrupt urb %p: status %d"
,
resubmit
,
status
);
usb_put_urb
(
resubmit
);
}
#endif
spin_lock_irqsave
(
&
ehci
->
lock
,
flags
);
return
flags
;
}
/*
* Process completed qtds for a qh, issuing completions if needed.
* Frees qtds, unmaps buf, returns URB to driver.
* Races up to qh->hw_current; returns number of urb completions.
* Process and free completed qtds for a qh, returning URBs to drivers.
* Chases up to qh->hw_current, returns irqsave flags (maybe modified).
*/
static
void
qh_completions
(
struct
ehci_hcd
*
ehci
,
struct
ehci_qh
*
qh
)
static
unsigned
long
qh_completions
(
struct
ehci_hcd
*
ehci
,
struct
ehci_qh
*
qh
,
unsigned
long
flags
)
{
struct
ehci_qtd
*
qtd
,
*
last
;
struct
list_head
*
next
,
*
qtd_list
=
&
qh
->
qtd_list
;
int
unlink
=
0
,
halted
=
0
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
ehci
->
lock
,
flags
);
if
(
unlikely
(
list_empty
(
qtd_list
)))
{
spin_unlock_irqrestore
(
&
ehci
->
lock
,
flags
);
return
;
}
if
(
unlikely
(
list_empty
(
qtd_list
)))
return
flags
;
/* scan QTDs till end of list, or we reach an active one */
for
(
qtd
=
list_entry
(
qtd_list
->
next
,
struct
ehci_qtd
,
qtd_list
),
...
...
@@ -252,12 +253,8 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* clean up any state from previous QTD ...*/
if
(
last
)
{
if
(
likely
(
last
->
urb
!=
urb
))
{
/* complete() can reenter this HCD */
spin_unlock_irqrestore
(
&
ehci
->
lock
,
flags
);
ehci_urb_done
(
ehci
,
last
->
urb
);
spin_lock_irqsave
(
&
ehci
->
lock
,
flags
);
}
if
(
likely
(
last
->
urb
!=
urb
))
flags
=
ehci_urb_done
(
ehci
,
last
->
urb
,
flags
);
/* qh overlays can have HC's old cached copies of
* next qtd ptrs, if an URB was queued afterwards.
...
...
@@ -283,6 +280,9 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
||
(
ehci
->
hcd
.
state
==
USB_STATE_HALT
)
||
(
qh
->
qh_state
==
QH_STATE_IDLE
);
// FIXME Remove the automagic unlink mode.
// Drivers can now clean up safely; its' their job.
/* fault: unlink the rest, since this qtd saw an error? */
if
(
unlikely
((
token
&
QTD_STS_HALT
)
!=
0
))
{
unlink
=
1
;
...
...
@@ -341,18 +341,19 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
#endif
}
/* patch up list head? */
/* last urb's completion might still need calling */
if
(
likely
(
last
!=
0
))
{
flags
=
ehci_urb_done
(
ehci
,
last
->
urb
,
flags
);
ehci_qtd_free
(
ehci
,
last
);
}
/* reactivate queue after error and driver's cleanup */
if
(
unlikely
(
halted
&&
!
list_empty
(
qtd_list
)))
{
qh_update
(
qh
,
list_entry
(
qtd_list
->
next
,
struct
ehci_qtd
,
qtd_list
));
}
spin_unlock_irqrestore
(
&
ehci
->
lock
,
flags
);
/* last urb's completion might still need calling */
if
(
likely
(
last
!=
0
))
{
ehci_urb_done
(
ehci
,
last
->
urb
);
ehci_qtd_free
(
ehci
,
last
);
}
return
flags
;
}
/*-------------------------------------------------------------------------*/
...
...
@@ -367,31 +368,12 @@ static void qtd_list_free (
struct
list_head
*
qtd_list
)
{
struct
list_head
*
entry
,
*
temp
;
int
unmapped
=
0
;
list_for_each_safe
(
entry
,
temp
,
qtd_list
)
{
struct
ehci_qtd
*
qtd
;
qtd
=
list_entry
(
entry
,
struct
ehci_qtd
,
qtd_list
);
list_del
(
&
qtd
->
qtd_list
);
if
(
unmapped
!=
2
)
{
int
direction
;
size_t
size
;
/* for ctrl unmap twice: SETUP and DATA;
* else (bulk, intr) just once: DATA
*/
if
(
!
unmapped
++
&&
usb_pipecontrol
(
urb
->
pipe
))
{
direction
=
PCI_DMA_TODEVICE
;
size
=
sizeof
(
struct
usb_ctrlrequest
);
}
else
{
direction
=
usb_pipein
(
urb
->
pipe
)
?
PCI_DMA_FROMDEVICE
:
PCI_DMA_TODEVICE
;
size
=
qtd
->
urb
->
transfer_buffer_length
;
unmapped
++
;
}
}
ehci_qtd_free
(
ehci
,
qtd
);
}
}
...
...
@@ -670,8 +652,8 @@ ehci_qh_make (
info2
|=
hb_mult
(
maxp
)
<<
30
;
}
break
;
#ifdef DEBUG
default:
#ifdef DEBUG
BUG
();
#endif
}
...
...
@@ -859,7 +841,8 @@ submit_async (
epnum
|=
0x10
;
vdbg
(
"%s: submit_async urb %p len %d ep %d-%s qtd %p [qh %p]"
,
ehci
->
hcd
.
self
.
bus_name
,
urb
,
urb
->
transfer_buffer_length
,
hcd_to_bus
(
&
ehci
->
hcd
)
->
bus_name
,
urb
,
urb
->
transfer_buffer_length
,
epnum
&
0x0f
,
(
epnum
&
0x10
)
?
"in"
:
"out"
,
qtd
,
dev
?
dev
->
ep
[
epnum
]
:
(
void
*
)
~
0
);
...
...
@@ -886,25 +869,28 @@ submit_async (
/* the async qh for the qtds being reclaimed are now unlinked from the HC */
/* caller must not own ehci->lock */
static
void
end_unlink_async
(
struct
ehci_hcd
*
ehci
)
static
unsigned
long
end_unlink_async
(
struct
ehci_hcd
*
ehci
,
unsigned
long
flags
)
{
struct
ehci_qh
*
qh
=
ehci
->
reclaim
;
del_timer
(
&
ehci
->
watchdog
);
qh
->
qh_state
=
QH_STATE_IDLE
;
qh
->
qh_next
.
qh
=
0
;
qh_put
(
ehci
,
qh
);
// refcount from reclaim
ehci
->
reclaim
=
0
;
ehci
->
reclaim_ready
=
0
;
qh_completions
(
ehci
,
qh
);
flags
=
qh_completions
(
ehci
,
qh
,
flags
);
// unlink any urb should now unlink all following urbs, so that
// relinking only happens for urbs before the unlinked ones.
if
(
!
list_empty
(
&
qh
->
qtd_list
)
&&
HCD_IS_RUNNING
(
ehci
->
hcd
.
state
))
qh_link_async
(
ehci
,
qh
);
else
qh_put
(
ehci
,
qh
);
// refcount from async list
return
flags
;
}
...
...
@@ -975,16 +961,17 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
cmd
|=
CMD_IAAD
;
writel
(
cmd
,
&
ehci
->
regs
->
command
);
/* posted write need not be known to HC yet ... */
mod_timer
(
&
ehci
->
watchdog
,
jiffies
+
EHCI_WATCHDOG_JIFFIES
);
}
/*-------------------------------------------------------------------------*/
static
void
scan_async
(
struct
ehci_hcd
*
ehci
)
static
unsigned
long
scan_async
(
struct
ehci_hcd
*
ehci
,
unsigned
long
flags
)
{
struct
ehci_qh
*
qh
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
ehci
->
lock
,
flags
);
rescan:
qh
=
ehci
->
async
;
if
(
likely
(
qh
!=
0
))
{
...
...
@@ -993,12 +980,9 @@ static void scan_async (struct ehci_hcd *ehci)
if
(
!
list_empty
(
&
qh
->
qtd_list
))
{
// dbg_qh ("scan_async", ehci, qh);
qh
=
qh_get
(
qh
);
spin_unlock_irqrestore
(
&
ehci
->
lock
,
flags
);
/* concurrent unlink could happen here */
qh_completions
(
ehci
,
qh
);
spin_lock_irqsave
(
&
ehci
->
lock
,
flags
);
flags
=
qh_completions
(
ehci
,
qh
,
flags
);
qh_put
(
ehci
,
qh
);
}
...
...
@@ -1020,6 +1004,5 @@ static void scan_async (struct ehci_hcd *ehci)
goto
rescan
;
}
while
(
qh
!=
ehci
->
async
);
}
spin_unlock_irqrestore
(
&
ehci
->
lock
,
flags
);
return
flags
;
}
drivers/usb/host/ehci-sched.c
View file @
e23525cd
...
...
@@ -222,17 +222,15 @@ static int disable_periodic (struct ehci_hcd *ehci)
// FIXME microframe periods not yet handled
static
void
intr_deschedule
(
static
unsigned
long
intr_deschedule
(
struct
ehci_hcd
*
ehci
,
struct
ehci_qh
*
qh
,
int
wait
int
wait
,
unsigned
long
flags
)
{
unsigned
long
flags
;
int
status
;
unsigned
frame
=
qh
->
start
;
spin_lock_irqsave
(
&
ehci
->
lock
,
flags
);
do
{
periodic_unlink
(
ehci
,
frame
,
qh
);
qh_put
(
ehci
,
qh
);
...
...
@@ -251,8 +249,6 @@ static void intr_deschedule (
vdbg
(
"periodic schedule still enabled"
);
}
spin_unlock_irqrestore
(
&
ehci
->
lock
,
flags
);
/*
* If the hc may be looking at this qh, then delay a uframe
* (yeech!) to be sure it's done.
...
...
@@ -260,8 +256,10 @@ static void intr_deschedule (
*/
if
(((
ehci_get_frame
(
&
ehci
->
hcd
)
-
frame
)
%
qh
->
period
)
==
0
)
{
if
(
wait
)
{
spin_unlock_irqrestore
(
&
ehci
->
lock
,
flags
);
udelay
(
125
);
qh
->
hw_next
=
EHCI_LIST_END
;
spin_lock_irqsave
(
&
ehci
->
lock
,
flags
);
}
else
{
/* we may not be IDLE yet, but if the qh is empty
* the race is very short. then if qh also isn't
...
...
@@ -275,12 +273,13 @@ static void intr_deschedule (
qh
->
qh_state
=
QH_STATE_IDLE
;
/* update per-qh bandwidth utilization (for usbfs) */
ehci
->
hcd
.
self
.
bandwidth_allocated
-=
hcd_to_bus
(
&
ehci
->
hcd
)
->
bandwidth_allocated
-=
(
qh
->
usecs
+
qh
->
c_usecs
)
/
qh
->
period
;
vdbg
(
"descheduled qh %p, per = %d frame = %d count = %d, urbs = %d"
,
qh
,
qh
->
period
,
frame
,
atomic_read
(
&
qh
->
refcount
),
ehci
->
periodic_sched
);
return
flags
;
}
static
int
check_period
(
...
...
@@ -436,7 +435,7 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
}
while
(
frame
<
ehci
->
periodic_size
);
/* update per-qh bandwidth for usbfs */
ehci
->
hcd
.
self
.
bandwidth_allocated
+=
hcd_to_bus
(
&
ehci
->
hcd
)
->
bandwidth_allocated
+=
(
qh
->
usecs
+
qh
->
c_usecs
)
/
qh
->
period
;
/* maybe enable periodic schedule processing */
...
...
@@ -486,7 +485,7 @@ static int intr_submit (
BUG_ON
(
qh
==
0
);
/* ... update usbfs periodic stats */
ehci
->
hcd
.
self
.
bandwidth_int_reqs
++
;
hcd_to_bus
(
&
ehci
->
hcd
)
->
bandwidth_int_reqs
++
;
done:
spin_unlock_irqrestore
(
&
ehci
->
lock
,
flags
);
...
...
@@ -513,12 +512,10 @@ intr_complete (
}
/* handle any completions */
spin_unlock_irqrestore
(
&
ehci
->
lock
,
flags
);
qh_completions
(
ehci
,
qh
);
spin_lock_irqsave
(
&
ehci
->
lock
,
flags
);
flags
=
qh_completions
(
ehci
,
qh
,
flags
);
if
(
unlikely
(
list_empty
(
&
qh
->
qtd_list
)))
intr_deschedule
(
ehci
,
qh
,
0
);
flags
=
intr_deschedule
(
ehci
,
qh
,
0
,
flags
);
return
flags
;
}
...
...
@@ -1091,13 +1088,12 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
/*-------------------------------------------------------------------------*/
static
void
scan_periodic
(
struct
ehci_hcd
*
ehci
)
static
unsigned
long
scan_periodic
(
struct
ehci_hcd
*
ehci
,
unsigned
long
flags
)
{
unsigned
frame
,
clock
,
now_uframe
,
mod
;
unsigned
long
flags
;
mod
=
ehci
->
periodic_size
<<
3
;
spin_lock_irqsave
(
&
ehci
->
lock
,
flags
);
/*
* When running, scan from last scan point up to "now"
...
...
@@ -1237,5 +1233,5 @@ static void scan_periodic (struct ehci_hcd *ehci)
}
else
frame
=
(
frame
+
1
)
%
ehci
->
periodic_size
;
}
spin_unlock_irqrestore
(
&
ehci
->
lock
,
flags
)
;
return
flags
;
}
drivers/usb/host/ehci.h
View file @
e23525cd
...
...
@@ -69,6 +69,8 @@ struct ehci_hcd { /* one per controller */
struct
pci_pool
*
qtd_pool
;
/* one or more per qh */
struct
pci_pool
*
itd_pool
;
/* itd per iso urb */
struct
pci_pool
*
sitd_pool
;
/* sitd per split iso urb */
struct
timer_list
watchdog
;
};
/* unwrap an HCD pointer to get an EHCI_HCD pointer */
...
...
@@ -389,4 +391,26 @@ struct ehci_fstn {
union
ehci_shadow
fstn_next
;
/* ptr to periodic q entry */
}
__attribute__
((
aligned
(
32
)));
/*-------------------------------------------------------------------------*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,32)
#define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb)
#define STUB_DEBUG_FILES
#else
/* LINUX_VERSION_CODE */
static
inline
struct
usb_bus
*
hcd_to_bus
(
struct
usb_hcd
*
hcd
)
{
return
&
hcd
->
self
;
}
#define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb,mem_flags)
#ifndef DEBUG
#define STUB_DEBUG_FILES
#endif
/* DEBUG */
#endif
/* LINUX_VERSION_CODE */
/*-------------------------------------------------------------------------*/
#endif
/* __LINUX_EHCI_HCD_H */
drivers/usb/host/ohci-dbg.c
View file @
e23525cd
...
...
@@ -72,37 +72,6 @@ static void urb_print (struct urb * urb, char * str, int small)
#endif
}
static
inline
struct
ed
*
dma_to_ed
(
struct
ohci_hcd
*
hc
,
dma_addr_t
ed_dma
);
/* print non-empty branches of the periodic ed tree */
static
void
__attribute__
((
unused
))
ohci_dump_periodic
(
struct
ohci_hcd
*
ohci
,
char
*
label
)
{
int
i
,
j
;
u32
*
ed_p
;
int
printed
=
0
;
for
(
i
=
0
;
i
<
32
;
i
++
)
{
j
=
5
;
ed_p
=
&
(
ohci
->
hcca
->
int_table
[
i
]);
if
(
*
ed_p
==
0
)
continue
;
printed
=
1
;
printk
(
KERN_DEBUG
"%s, ohci %s frame %2d:"
,
label
,
ohci
->
hcd
.
self
.
bus_name
,
i
);
while
(
*
ed_p
!=
0
&&
j
--
)
{
struct
ed
*
ed
=
dma_to_ed
(
ohci
,
le32_to_cpup
(
ed_p
));
printk
(
" %p/%08x;"
,
ed
,
ed
->
hwINFO
);
ed_p
=
&
ed
->
hwNextED
;
}
printk
(
"
\n
"
);
}
if
(
!
printed
)
printk
(
KERN_DEBUG
"%s, ohci %s, empty periodic schedule
\n
"
,
label
,
ohci
->
hcd
.
self
.
bus_name
);
}
static
void
ohci_dump_intr_mask
(
char
*
label
,
__u32
mask
)
{
dbg
(
"%s: 0x%08x%s%s%s%s%s%s%s%s%s"
,
...
...
@@ -239,7 +208,8 @@ static void ohci_dump (struct ohci_hcd *controller, int verbose)
if
(
verbose
)
ohci_dump_periodic
(
controller
,
"hcca"
);
#endif
dbg
(
"hcca frame #%04x"
,
controller
->
hcca
->
frame_no
);
if
(
controller
->
hcca
)
dbg
(
"hcca frame #%04x"
,
controller
->
hcca
->
frame_no
);
ohci_dump_roothub
(
controller
,
1
);
}
...
...
@@ -316,8 +286,9 @@ ohci_dump_ed (struct ohci_hcd *ohci, char *label, struct ed *ed, int verbose)
case
ED_IN
:
type
=
"-IN"
;
break
;
/* else from TDs ... control */
}
dbg
(
" info %08x MAX=%d%s%s%s EP=%d%s DEV=%d"
,
le32_to_cpu
(
tmp
),
0x0fff
&
(
le32_to_cpu
(
tmp
)
>>
16
),
dbg
(
" info %08x MAX=%d%s%s%s%s EP=%d%s DEV=%d"
,
le32_to_cpu
(
tmp
),
0x03ff
&
(
le32_to_cpu
(
tmp
)
>>
16
),
(
tmp
&
ED_DEQUEUE
)
?
" DQ"
:
""
,
(
tmp
&
ED_ISO
)
?
" ISO"
:
""
,
(
tmp
&
ED_SKIP
)
?
" SKIP"
:
""
,
(
tmp
&
ED_LOWSPEED
)
?
" LOW"
:
""
,
...
...
@@ -344,5 +315,222 @@ ohci_dump_ed (struct ohci_hcd *ohci, char *label, struct ed *ed, int verbose)
}
}
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,32)
# define DRIVERFS_DEBUG_FILES
#endif
#endif
/* DEBUG */
/*-------------------------------------------------------------------------*/
#ifdef DRIVERFS_DEBUG_FILES
static
ssize_t
show_list
(
struct
ohci_hcd
*
ohci
,
char
*
buf
,
size_t
count
,
struct
ed
*
ed
)
{
unsigned
temp
,
size
=
count
;
if
(
!
ed
)
return
0
;
/* print first --> last */
while
(
ed
->
ed_prev
)
ed
=
ed
->
ed_prev
;
/* dump a snapshot of the bulk or control schedule */
while
(
ed
)
{
u32
info
=
ed
->
hwINFO
;
u32
scratch
=
cpu_to_le32p
(
&
ed
->
hwINFO
);
struct
list_head
*
entry
;
struct
td
*
td
;
temp
=
snprintf
(
buf
,
size
,
"ed/%p %cs dev%d ep%d-%s max %d %08x%s%s %s"
,
ed
,
(
info
&
ED_LOWSPEED
)
?
'l'
:
'f'
,
scratch
&
0x7f
,
(
scratch
>>
7
)
&
0xf
,
(
info
&
ED_IN
)
?
"in"
:
"out"
,
0x03ff
&
(
scratch
>>
16
),
scratch
,
(
info
&
ED_SKIP
)
?
" s"
:
""
,
(
ed
->
hwHeadP
&
ED_H
)
?
" H"
:
""
,
(
ed
->
hwHeadP
&
ED_C
)
?
data1
:
data0
);
size
-=
temp
;
buf
+=
temp
;
list_for_each
(
entry
,
&
ed
->
td_list
)
{
u32
cbp
,
be
;
td
=
list_entry
(
entry
,
struct
td
,
td_list
);
scratch
=
cpu_to_le32p
(
&
td
->
hwINFO
);
cbp
=
le32_to_cpup
(
&
td
->
hwCBP
);
be
=
le32_to_cpup
(
&
td
->
hwBE
);
temp
=
snprintf
(
buf
,
size
,
"
\n\t
td %p %s %d cc=%x urb %p (%08x)"
,
td
,
({
char
*
pid
;
switch
(
scratch
&
TD_DP
)
{
case
TD_DP_SETUP
:
pid
=
"setup"
;
break
;
case
TD_DP_IN
:
pid
=
"in"
;
break
;
case
TD_DP_OUT
:
pid
=
"out"
;
break
;
default:
pid
=
"(?)"
;
break
;
}
pid
;}),
cbp
?
(
be
+
1
-
cbp
)
:
0
,
TD_CC_GET
(
scratch
),
td
->
urb
,
scratch
);
size
-=
temp
;
buf
+=
temp
;
}
temp
=
snprintf
(
buf
,
size
,
"
\n
"
);
size
-=
temp
;
buf
+=
temp
;
ed
=
ed
->
ed_next
;
}
return
count
-
size
;
}
static
ssize_t
show_async
(
struct
device
*
dev
,
char
*
buf
,
size_t
count
,
loff_t
off
)
{
struct
pci_dev
*
pdev
;
struct
ohci_hcd
*
ohci
;
size_t
temp
;
unsigned
long
flags
;
if
(
off
!=
0
)
return
0
;
pdev
=
container_of
(
dev
,
struct
pci_dev
,
dev
);
ohci
=
container_of
(
pci_get_drvdata
(
pdev
),
struct
ohci_hcd
,
hcd
);
/* display control and bulk lists together, for simplicity */
spin_lock_irqsave
(
&
ohci
->
lock
,
flags
);
temp
=
show_list
(
ohci
,
buf
,
count
,
ohci
->
ed_controltail
);
count
=
show_list
(
ohci
,
buf
+
temp
,
count
-
temp
,
ohci
->
ed_bulktail
);
spin_unlock_irqrestore
(
&
ohci
->
lock
,
flags
);
return
temp
+
count
;
}
static
DEVICE_ATTR
(
async
,
S_IRUGO
,
show_async
,
NULL
);
#define DBG_SCHED_LIMIT 64
static
ssize_t
show_periodic
(
struct
device
*
dev
,
char
*
buf
,
size_t
count
,
loff_t
off
)
{
struct
pci_dev
*
pdev
;
struct
ohci_hcd
*
ohci
;
struct
ed
**
seen
,
*
ed
;
unsigned
long
flags
;
unsigned
temp
,
size
,
seen_count
;
char
*
next
;
unsigned
i
;
if
(
off
!=
0
)
return
0
;
if
(
!
(
seen
=
kmalloc
(
DBG_SCHED_LIMIT
*
sizeof
*
seen
,
SLAB_ATOMIC
)))
return
0
;
seen_count
=
0
;
pdev
=
container_of
(
dev
,
struct
pci_dev
,
dev
);
ohci
=
container_of
(
pci_get_drvdata
(
pdev
),
struct
ohci_hcd
,
hcd
);
next
=
buf
;
size
=
count
;
temp
=
snprintf
(
next
,
size
,
"size = %d
\n
"
,
NUM_INTS
);
size
-=
temp
;
next
+=
temp
;
/* dump a snapshot of the periodic schedule (and load) */
spin_lock_irqsave
(
&
ohci
->
lock
,
flags
);
for
(
i
=
0
;
i
<
NUM_INTS
;
i
++
)
{
if
(
!
(
ed
=
ohci
->
periodic
[
i
]))
continue
;
temp
=
snprintf
(
next
,
size
,
"%2d [%3d]:"
,
i
,
ohci
->
load
[
i
]);
size
-=
temp
;
next
+=
temp
;
do
{
temp
=
snprintf
(
next
,
size
,
" ed%d/%p"
,
ed
->
interval
,
ed
);
size
-=
temp
;
next
+=
temp
;
for
(
temp
=
0
;
temp
<
seen_count
;
temp
++
)
{
if
(
seen
[
temp
]
==
ed
)
break
;
}
/* show more info the first time around */
if
(
temp
==
seen_count
)
{
u32
info
=
ed
->
hwINFO
;
u32
scratch
=
cpu_to_le32p
(
&
ed
->
hwINFO
);
temp
=
snprintf
(
next
,
size
,
" (%cs dev%d%s ep%d-%s"
" max %d %08x%s%s)"
,
(
info
&
ED_LOWSPEED
)
?
'l'
:
'f'
,
scratch
&
0x7f
,
(
info
&
ED_ISO
)
?
" iso"
:
""
,
(
scratch
>>
7
)
&
0xf
,
(
info
&
ED_IN
)
?
"in"
:
"out"
,
0x03ff
&
(
scratch
>>
16
),
scratch
,
(
info
&
ED_SKIP
)
?
" s"
:
""
,
(
ed
->
hwHeadP
&
ED_H
)
?
" H"
:
""
);
size
-=
temp
;
next
+=
temp
;
// FIXME some TD info too
if
(
seen_count
<
DBG_SCHED_LIMIT
)
seen
[
seen_count
++
]
=
ed
;
ed
=
ed
->
ed_next
;
}
else
{
/* we've seen it and what's after */
temp
=
0
;
ed
=
0
;
}
}
while
(
ed
);
temp
=
snprintf
(
next
,
size
,
"
\n
"
);
size
-=
temp
;
next
+=
temp
;
}
spin_unlock_irqrestore
(
&
ohci
->
lock
,
flags
);
kfree
(
seen
);
return
count
-
size
;
}
static
DEVICE_ATTR
(
periodic
,
S_IRUGO
,
show_periodic
,
NULL
);
#undef DBG_SCHED_LIMIT
static
inline
void
create_debug_files
(
struct
ohci_hcd
*
bus
)
{
device_create_file
(
&
bus
->
hcd
.
pdev
->
dev
,
&
dev_attr_async
);
device_create_file
(
&
bus
->
hcd
.
pdev
->
dev
,
&
dev_attr_periodic
);
// registers
dbg
(
"%s: created debug files"
,
bus
->
hcd
.
self
.
bus_name
);
}
static
inline
void
remove_debug_files
(
struct
ohci_hcd
*
bus
)
{
device_remove_file
(
&
bus
->
hcd
.
pdev
->
dev
,
&
dev_attr_async
);
device_remove_file
(
&
bus
->
hcd
.
pdev
->
dev
,
&
dev_attr_periodic
);
}
#else
/* empty stubs for creating those files */
static
inline
void
create_debug_files
(
struct
ohci_hcd
*
bus
)
{
}
static
inline
void
remove_debug_files
(
struct
ohci_hcd
*
bus
)
{
}
#endif
/* DRIVERFS_DEBUG_FILES */
/*-------------------------------------------------------------------------*/
drivers/usb/host/ohci-hcd.c
View file @
e23525cd
...
...
@@ -17,6 +17,8 @@
*
* History:
*
* 2002/09/03 get rid of ed hashtables, rework periodic scheduling and
* bandwidth accounting; if debugging, show schedules in driverfs
* 2002/07/19 fixes to management of ED and schedule state.
* 2002/06/09 SA-1111 support (Christopher Hoover)
* 2002/06/01 remember frame when HC won't see EDs any more; use that info
...
...
@@ -66,7 +68,6 @@
* v1.0 1999/04/27 initial release
*
* This file is licenced under the GPL.
* $Id: ohci-hcd.c,v 1.9 2002/03/27 20:41:57 dbrownell Exp $
*/
#include <linux/config.h>
...
...
@@ -107,8 +108,8 @@
* - lots more testing!!
*/
#define DRIVER_VERSION "2002-
Jul-19
"
#define DRIVER_AUTHOR "Roman Weissgaerber
<weissg@vienna.at>
, David Brownell"
#define DRIVER_VERSION "2002-
Sep-03
"
#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
/*-------------------------------------------------------------------------*/
...
...
@@ -152,7 +153,6 @@ static int ohci_urb_enqueue (
unsigned
int
pipe
=
urb
->
pipe
;
int
i
,
size
=
0
;
unsigned
long
flags
;
int
bustime
=
0
;
int
retval
=
0
;
#ifdef OHCI_VERBOSE_DEBUG
...
...
@@ -230,43 +230,32 @@ static int ohci_urb_enqueue (
}
}
// FIXME: much of this switch should be generic, move to hcd code ...
// ... and what's not generic can't really be handled this way.
// need to consider periodicity for both types!
/* allocate and claim bandwidth if needed; ISO
* needs start frame index if it was't provided.
*/
switch
(
usb_pipetype
(
pipe
))
{
case
PIPE_ISOCHRONOUS
:
if
(
urb
->
transfer_flags
&
USB_ISO_ASAP
)
{
urb
->
start_frame
=
((
ed
->
state
!=
ED_IDLE
)
?
(
ed
->
intriso
.
last_iso
+
1
)
:
(
le16_to_cpu
(
ohci
->
hcca
->
frame_no
)
+
10
))
&
0xffff
;
}
/* FALLTHROUGH */
case
PIPE_INTERRUPT
:
if
(
urb
->
bandwidth
==
0
)
{
bustime
=
usb_check_bandwidth
(
urb
->
dev
,
urb
);
}
if
(
bustime
<
0
)
{
retval
=
bustime
;
goto
fail
;
}
usb_claim_bandwidth
(
urb
->
dev
,
urb
,
bustime
,
usb_pipeisoc
(
urb
->
pipe
));
}
/* schedule the ed if needed */
if
(
ed
->
state
==
ED_IDLE
)
{
retval
=
ed_schedule
(
ohci
,
ed
);
if
(
retval
<
0
)
goto
fail
;
if
(
ed
->
type
==
PIPE_ISOCHRONOUS
)
{
u16
frame
=
le16_to_cpu
(
ohci
->
hcca
->
frame_no
);
urb
->
hcpriv
=
urb_priv
;
/* delay a few frames before the first TD */
frame
+=
max_t
(
u16
,
8
,
ed
->
interval
);
frame
&=
~
(
ed
->
interval
-
1
);
frame
|=
ed
->
branch
;
urb
->
start_frame
=
frame
;
/* schedule the ed if needed */
if
(
ed
->
state
==
ED_IDLE
)
ed_schedule
(
ohci
,
ed
);
/* yes, only USB_ISO_ASAP is supported, and
* urb->start_frame is never used as input.
*/
}
}
else
if
(
ed
->
type
==
PIPE_ISOCHRONOUS
)
urb
->
start_frame
=
ed
->
last_iso
+
ed
->
interval
;
/* fill the TDs and link them to the ed; and
* enable that part of the schedule, if needed
* and update count of queued periodic urbs
*/
urb
->
hcpriv
=
urb_priv
;
td_submit_urb
(
ohci
,
urb
);
fail:
...
...
@@ -530,13 +519,15 @@ static int hc_start (struct ohci_hcd *ohci)
usb_connect
(
udev
);
udev
->
speed
=
USB_SPEED_FULL
;
if
(
usb_register_root_hub
(
udev
,
ohci
->
parent_dev
)
!=
0
)
{
usb_free_dev
(
udev
);
usb_free_dev
(
udev
);
ohci
->
hcd
.
self
.
root_hub
=
NULL
;
disable
(
ohci
);
ohci
->
hc_control
&=
~
OHCI_CTRL_HCFS
;
writel
(
ohci
->
hc_control
,
&
ohci
->
regs
->
control
);
return
-
ENODEV
;
}
create_debug_files
(
ohci
);
return
0
;
}
...
...
@@ -571,7 +562,8 @@ static void ohci_irq (struct usb_hcd *hcd)
if
(
ints
&
OHCI_INTR_UE
)
{
disable
(
ohci
);
err
(
"OHCI Unrecoverable Error, %s disabled"
,
hcd
->
self
.
bus_name
);
err
(
"OHCI Unrecoverable Error, %s disabled"
,
hcd
->
self
.
bus_name
);
// e.g. due to PCI Master/Target Abort
#ifdef DEBUG
...
...
@@ -620,10 +612,14 @@ static void ohci_stop (struct usb_hcd *hcd)
if
(
!
ohci
->
disabled
)
hc_reset
(
ohci
);
remove_debug_files
(
ohci
);
ohci_mem_cleanup
(
ohci
);
pci_free_consistent
(
ohci
->
hcd
.
pdev
,
sizeof
*
ohci
->
hcca
,
ohci
->
hcca
,
ohci
->
hcca_dma
);
if
(
ohci
->
hcca
)
{
pci_free_consistent
(
ohci
->
hcd
.
pdev
,
sizeof
*
ohci
->
hcca
,
ohci
->
hcca
,
ohci
->
hcca_dma
);
ohci
->
hcca
=
NULL
;
ohci
->
hcca_dma
=
0
;
}
}
/*-------------------------------------------------------------------------*/
...
...
@@ -646,14 +642,13 @@ static int hc_restart (struct ohci_hcd *ohci)
usb_disconnect
(
&
ohci
->
hcd
.
self
.
root_hub
);
/* empty the interrupt branches */
for
(
i
=
0
;
i
<
NUM_INTS
;
i
++
)
ohci
->
ohci_int_
load
[
i
]
=
0
;
for
(
i
=
0
;
i
<
NUM_INTS
;
i
++
)
ohci
->
load
[
i
]
=
0
;
for
(
i
=
0
;
i
<
NUM_INTS
;
i
++
)
ohci
->
hcca
->
int_table
[
i
]
=
0
;
/* no EDs to remove */
ohci
->
ed_rm_list
=
NULL
;
/* empty control and bulk lists */
ohci
->
ed_isotail
=
NULL
;
ohci
->
ed_controltail
=
NULL
;
ohci
->
ed_bulktail
=
NULL
;
...
...
drivers/usb/host/ohci-mem.c
View file @
e23525cd
...
...
@@ -5,7 +5,6 @@
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
*
* This file is licenced under the GPL.
* $Id: ohci-mem.c,v 1.3 2002/03/22 16:04:54 dbrownell Exp $
*/
/*-------------------------------------------------------------------------*/
...
...
@@ -52,13 +51,6 @@ dma_to_ed_td (struct hash_list_t * entry, dma_addr_t dma)
return
scan
->
virt
;
}
static
struct
ed
*
dma_to_ed
(
struct
ohci_hcd
*
hc
,
dma_addr_t
ed_dma
)
{
return
(
struct
ed
*
)
dma_to_ed_td
(
&
(
hc
->
ed_hash
[
ED_HASH_FUNC
(
ed_dma
)]),
ed_dma
);
}
static
struct
td
*
dma_to_td
(
struct
ohci_hcd
*
hc
,
dma_addr_t
td_dma
)
{
...
...
@@ -97,13 +89,6 @@ hash_add_ed_td (
return
1
;
}
static
inline
int
hash_add_ed
(
struct
ohci_hcd
*
hc
,
struct
ed
*
ed
,
int
mem_flags
)
{
return
hash_add_ed_td
(
&
(
hc
->
ed_hash
[
ED_HASH_FUNC
(
ed
->
dma
)]),
ed
,
ed
->
dma
,
mem_flags
);
}
static
inline
int
hash_add_td
(
struct
ohci_hcd
*
hc
,
struct
td
*
td
,
int
mem_flags
)
{
...
...
@@ -138,12 +123,6 @@ hash_free_ed_td (struct hash_list_t *entry, void *virt)
}
}
static
inline
void
hash_free_ed
(
struct
ohci_hcd
*
hc
,
struct
ed
*
ed
)
{
hash_free_ed_td
(
&
(
hc
->
ed_hash
[
ED_HASH_FUNC
(
ed
->
dma
)]),
ed
);
}
static
inline
void
hash_free_td
(
struct
ohci_hcd
*
hc
,
struct
td
*
td
)
{
...
...
@@ -223,11 +202,6 @@ ed_alloc (struct ohci_hcd *hc, int mem_flags)
memset
(
ed
,
0
,
sizeof
(
*
ed
));
INIT_LIST_HEAD
(
&
ed
->
td_list
);
ed
->
dma
=
dma
;
/* hash it for later reverse mapping */
if
(
!
hash_add_ed
(
hc
,
ed
,
mem_flags
))
{
pci_pool_free
(
hc
->
ed_cache
,
ed
,
dma
);
return
NULL
;
}
}
return
ed
;
}
...
...
@@ -235,7 +209,6 @@ ed_alloc (struct ohci_hcd *hc, int mem_flags)
static
void
ed_free
(
struct
ohci_hcd
*
hc
,
struct
ed
*
ed
)
{
hash_free_ed
(
hc
,
ed
);
pci_pool_free
(
hc
->
ed_cache
,
ed
,
ed
->
dma
);
}
drivers/usb/host/ohci-q.c
View file @
e23525cd
...
...
@@ -5,7 +5,6 @@
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
*
* This file is licenced under the GPL.
* $Id: ohci-q.c,v 1.8 2002/03/27 20:57:01 dbrownell Exp $
*/
static
void
urb_free_priv
(
struct
ohci_hcd
*
hc
,
urb_priv_t
*
urb_priv
)
...
...
@@ -52,6 +51,15 @@ static void finish_urb (struct ohci_hcd *ohci, struct urb *urb)
urb
->
status
=
0
;
spin_unlock_irqrestore
(
&
urb
->
lock
,
flags
);
switch
(
usb_pipetype
(
urb
->
pipe
))
{
case
PIPE_ISOCHRONOUS
:
ohci
->
hcd
.
self
.
bandwidth_isoc_reqs
--
;
break
;
case
PIPE_INTERRUPT
:
ohci
->
hcd
.
self
.
bandwidth_int_reqs
--
;
break
;
}
#ifdef OHCI_VERBOSE_DEBUG
urb_print
(
urb
,
"RET"
,
usb_pipeout
(
urb
->
pipe
));
#endif
...
...
@@ -111,67 +119,111 @@ static inline void intr_resub (struct ohci_hcd *hc, struct urb *urb)
* ED handling functions
*-------------------------------------------------------------------------*/
/* search for the right branch to insert an interrupt ed into the int tree
* do some load balancing;
* returns the branch
* FIXME allow for failure, when there's no bandwidth left;
* and consider iso loads too
/* search for the right schedule branch to use for a periodic ed.
* does some load balancing; returns the branch, or negative errno.
*/
static
int
ep_int_
balance
(
struct
ohci_hcd
*
ohci
,
int
interval
,
int
load
)
static
int
balance
(
struct
ohci_hcd
*
ohci
,
int
interval
,
int
load
)
{
int
i
,
branch
=
0
;
/* search for the least loaded interrupt endpoint branch */
for
(
i
=
0
;
i
<
NUM_INTS
;
i
++
)
if
(
ohci
->
ohci_int_load
[
branch
]
>
ohci
->
ohci_int_load
[
i
])
branch
=
i
;
int
i
,
branch
=
-
ENOSPC
;
branch
=
branch
%
interval
;
for
(
i
=
branch
;
i
<
NUM_INTS
;
i
+=
interval
)
ohci
->
ohci_int_load
[
i
]
+=
load
;
/* iso periods can be huge; iso tds specify frame numbers */
if
(
interval
>
NUM_INTS
)
interval
=
NUM_INTS
;
/* search for the least loaded schedule branch of that period
* that has enough bandwidth left unreserved.
*/
for
(
i
=
0
;
i
<
interval
;
i
++
)
{
if
(
branch
<
0
||
ohci
->
load
[
branch
]
>
ohci
->
load
[
i
])
{
#ifdef CONFIG_USB_BANDWIDTH
int
j
;
/* usb 1.1 says 90% of one frame */
for
(
j
=
i
;
j
<
NUM_INTS
;
j
+=
interval
)
{
if
((
ohci
->
load
[
j
]
+
load
)
>
900
)
break
;
}
if
(
j
<
NUM_INTS
)
continue
;
#endif
branch
=
i
;
}
}
return
branch
;
}
/*-------------------------------------------------------------------------*/
/*
the int tree is a binary tree
* in
order to process it sequentially the indexes of the branches hav
e
*
to be mapped the mapping reverses the bits of a word of num_bits length
/*
both iso and interrupt requests have periods; this routine puts them
* in
to the schedule tree in the apppropriate place. most iso devices us
e
*
1msec periods, but that's not required.
*/
static
int
ep_rev
(
int
num_bits
,
int
wor
d
)
static
void
periodic_link
(
struct
ohci_hcd
*
ohci
,
struct
ed
*
e
d
)
{
int
i
,
wout
=
0
;
unsigned
i
;
for
(
i
=
0
;
i
<
num_bits
;
i
++
)
wout
|=
((
(
word
>>
i
)
&
1
)
<<
(
num_bits
-
i
-
1
));
return
wout
;
}
dbg
(
"%s: link %sed %p branch %d [%dus.], interval %d"
,
ohci
->
hcd
.
self
.
bus_name
,
(
ed
->
hwINFO
&
ED_ISO
)
?
"iso "
:
""
,
ed
,
ed
->
branch
,
ed
->
load
,
ed
->
interval
);
/*-------------------------------------------------------------------------*/
for
(
i
=
ed
->
branch
;
i
<
NUM_INTS
;
i
+=
ed
->
interval
)
{
struct
ed
**
prev
=
&
ohci
->
periodic
[
i
];
u32
*
prev_p
=
&
ohci
->
hcca
->
int_table
[
i
];
struct
ed
*
here
=
*
prev
;
/* sorting each branch by period (slow before fast)
* lets us share the faster parts of the tree.
* (plus maybe: put interrupt eds before iso)
*/
while
(
here
&&
ed
!=
here
)
{
if
(
ed
->
interval
>
here
->
interval
)
break
;
prev
=
&
here
->
ed_next
;
prev_p
=
&
here
->
hwNextED
;
here
=
*
prev
;
}
if
(
ed
!=
here
)
{
ed
->
ed_next
=
here
;
if
(
here
)
ed
->
hwNextED
=
*
prev_p
;
wmb
();
*
prev
=
ed
;
*
prev_p
=
cpu_to_le32p
(
&
ed
->
dma
);
}
ohci
->
load
[
i
]
+=
ed
->
load
;
}
ohci
->
hcd
.
self
.
bandwidth_allocated
+=
ed
->
load
/
ed
->
interval
;
}
/* link an ed into one of the HC chains */
static
void
ed_schedule
(
struct
ohci_hcd
*
ohci
,
struct
ed
*
ed
)
static
int
ed_schedule
(
struct
ohci_hcd
*
ohci
,
struct
ed
*
ed
)
{
int
int_branch
,
i
;
int
inter
,
interval
,
load
;
__u32
*
ed_p
;
int
branch
;
ed
->
state
=
ED_OPER
;
ed
->
ed_prev
=
0
;
ed
->
ed_next
=
0
;
ed
->
hwNextED
=
0
;
wmb
();
/* we care about rm_list when setting CLE/BLE in case the HC was at
* work on some TD when CLE/BLE was turned off, and isn't quiesced
* yet. finish_unlinks() restarts as needed, some upcoming INTR_SF.
*
* control and bulk EDs are doubly linked (ed_next, ed_prev), but
* periodic ones are singly linked (ed_next). that's because the
* periodic schedule encodes a tree like figure 3-5 in the ohci
* spec: each qh can have several "previous" nodes, and the tree
* doesn't have unused/idle descriptors.
*/
switch
(
ed
->
type
)
{
case
PIPE_CONTROL
:
if
(
ohci
->
ed_controltail
==
NULL
)
{
writel
(
ed
->
dma
,
&
ohci
->
regs
->
ed_controlhead
);
}
else
{
ohci
->
ed_controltail
->
ed_next
=
ed
;
ohci
->
ed_controltail
->
hwNextED
=
cpu_to_le32
(
ed
->
dma
);
}
ed
->
ed_prev
=
ohci
->
ed_controltail
;
...
...
@@ -187,6 +239,7 @@ static void ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
if
(
ohci
->
ed_bulktail
==
NULL
)
{
writel
(
ed
->
dma
,
&
ohci
->
regs
->
ed_bulkhead
);
}
else
{
ohci
->
ed_bulktail
->
ed_next
=
ed
;
ohci
->
ed_bulktail
->
hwNextED
=
cpu_to_le32
(
ed
->
dma
);
}
ed
->
ed_prev
=
ohci
->
ed_bulktail
;
...
...
@@ -198,74 +251,55 @@ static void ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
ohci
->
ed_bulktail
=
ed
;
break
;
case
PIPE_INTERRUPT
:
load
=
ed
->
intriso
.
intr_info
.
int_load
;
interval
=
ed
->
interval
;
int_branch
=
ep_int_balance
(
ohci
,
interval
,
load
);
ed
->
intriso
.
intr_info
.
int_branch
=
int_branch
;
for
(
i
=
0
;
i
<
ep_rev
(
6
,
interval
);
i
+=
inter
)
{
inter
=
1
;
for
(
ed_p
=
&
(
ohci
->
hcca
->
int_table
[
ep_rev
(
5
,
i
)
+
int_branch
]);
(
*
ed_p
!=
0
)
&&
((
dma_to_ed
(
ohci
,
le32_to_cpup
(
ed_p
)))
->
interval
>=
interval
);
ed_p
=
&
((
dma_to_ed
(
ohci
,
le32_to_cpup
(
ed_p
)))
->
hwNextED
))
inter
=
ep_rev
(
6
,
(
dma_to_ed
(
ohci
,
le32_to_cpup
(
ed_p
)))
->
interval
);
ed
->
hwNextED
=
*
ed_p
;
*
ed_p
=
cpu_to_le32
(
ed
->
dma
);
// case PIPE_INTERRUPT:
// case PIPE_ISOCHRONOUS:
default:
branch
=
balance
(
ohci
,
ed
->
interval
,
ed
->
load
);
if
(
branch
<
0
)
{
dbg
(
"%s: ERR %d, interval %d msecs, load %d"
,
ohci
->
hcd
.
self
.
bus_name
,
branch
,
ed
->
interval
,
ed
->
load
);
// FIXME if there are TDs queued, fail them!
return
branch
;
}
wmb
();
#ifdef OHCI_VERBOSE_DEBUG
ohci_dump_periodic
(
ohci
,
"LINK_INT"
);
#endif
break
;
case
PIPE_ISOCHRONOUS
:
ed
->
ed_prev
=
ohci
->
ed_isotail
;
if
(
ohci
->
ed_isotail
!=
NULL
)
{
ohci
->
ed_isotail
->
hwNextED
=
cpu_to_le32
(
ed
->
dma
);
}
else
{
for
(
i
=
0
;
i
<
NUM_INTS
;
i
+=
inter
)
{
inter
=
1
;
for
(
ed_p
=
&
(
ohci
->
hcca
->
int_table
[
ep_rev
(
5
,
i
)]);
*
ed_p
!=
0
;
ed_p
=
&
((
dma_to_ed
(
ohci
,
le32_to_cpup
(
ed_p
)))
->
hwNextED
))
inter
=
ep_rev
(
6
,
(
dma_to_ed
(
ohci
,
le32_to_cpup
(
ed_p
)))
->
interval
);
*
ed_p
=
cpu_to_le32
(
ed
->
dma
);
}
}
wmb
();
ohci
->
ed_isotail
=
ed
;
#ifdef OHCI_VERBOSE_DEBUG
ohci_dump_periodic
(
ohci
,
"LINK_ISO"
);
#endif
break
;
ed
->
branch
=
branch
;
periodic_link
(
ohci
,
ed
);
}
/* the HC may not see the schedule updates yet, but if it does
* then they'll be properly ordered.
*/
return
0
;
}
/*-------------------------------------------------------------------------*/
/* scan the periodic table to find and unlink this ED */
static
void
periodic_unlink
(
struct
ohci_hcd
*
ohci
,
struct
ed
*
ed
,
unsigned
index
,
unsigned
period
)
{
for
(;
index
<
NUM_INTS
;
index
+=
period
)
{
__u32
*
ed_p
=
&
ohci
->
hcca
->
int_table
[
index
];
static
void
periodic_unlink
(
struct
ohci_hcd
*
ohci
,
struct
ed
*
ed
)
{
int
i
;
while
(
*
ed_p
!=
0
)
{
if
((
dma_to_ed
(
ohci
,
le32_to_cpup
(
ed_p
)))
==
ed
)
{
*
ed_p
=
ed
->
hwNextED
;
break
;
}
ed_p
=
&
((
dma_to_ed
(
ohci
,
le32_to_cpup
(
ed_p
)))
->
hwNextED
);
for
(
i
=
ed
->
branch
;
i
<
NUM_INTS
;
i
+=
ed
->
interval
)
{
struct
ed
*
temp
;
struct
ed
**
prev
=
&
ohci
->
periodic
[
i
];
u32
*
prev_p
=
&
ohci
->
hcca
->
int_table
[
i
];
while
(
*
prev
&&
(
temp
=
*
prev
)
!=
ed
)
{
prev_p
=
&
temp
->
hwNextED
;
prev
=
&
temp
->
ed_next
;
}
if
(
*
prev
)
{
*
prev_p
=
ed
->
hwNextED
;
*
prev
=
ed
->
ed_next
;
}
ohci
->
load
[
i
]
-=
ed
->
load
;
}
ohci
->
hcd
.
self
.
bandwidth_allocated
-=
ed
->
load
/
ed
->
interval
;
dbg
(
"%s: unlink %sed %p branch %d [%dus.], interval %d"
,
ohci
->
hcd
.
self
.
bus_name
,
(
ed
->
hwINFO
&
ED_ISO
)
?
"iso "
:
""
,
ed
,
ed
->
branch
,
ed
->
load
,
ed
->
interval
);
}
/* unlink an ed from one of the HC chains.
...
...
@@ -275,8 +309,6 @@ static void periodic_unlink (
*/
static
void
ed_deschedule
(
struct
ohci_hcd
*
ohci
,
struct
ed
*
ed
)
{
int
i
;
ed
->
hwINFO
|=
ED_SKIP
;
switch
(
ed
->
type
)
{
...
...
@@ -289,13 +321,15 @@ static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed)
writel
(
le32_to_cpup
(
&
ed
->
hwNextED
),
&
ohci
->
regs
->
ed_controlhead
);
}
else
{
ed
->
ed_prev
->
ed_next
=
ed
->
ed_next
;
ed
->
ed_prev
->
hwNextED
=
ed
->
hwNextED
;
}
if
(
ohci
->
ed_controltail
==
ed
)
{
ohci
->
ed_controltail
=
ed
->
ed_prev
;
if
(
ohci
->
ed_controltail
)
ohci
->
ed_controltail
->
ed_next
=
0
;
}
else
{
(
dma_to_ed
(
ohci
,
le32_to_cpup
(
&
ed
->
hwNextED
)))
->
ed_prev
=
ed
->
ed_prev
;
ed
->
ed_next
->
ed_prev
=
ed
->
ed_prev
;
}
break
;
...
...
@@ -308,50 +342,33 @@ static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed)
writel
(
le32_to_cpup
(
&
ed
->
hwNextED
),
&
ohci
->
regs
->
ed_bulkhead
);
}
else
{
ed
->
ed_prev
->
ed_next
=
ed
->
ed_next
;
ed
->
ed_prev
->
hwNextED
=
ed
->
hwNextED
;
}
if
(
ohci
->
ed_bulktail
==
ed
)
{
ohci
->
ed_bulktail
=
ed
->
ed_prev
;
if
(
ohci
->
ed_bulktail
)
ohci
->
ed_bulktail
->
ed_next
=
0
;
}
else
{
(
dma_to_ed
(
ohci
,
le32_to_cpup
(
&
ed
->
hwNextED
)))
->
ed_prev
=
ed
->
ed_prev
;
ed
->
ed_next
->
ed_prev
=
ed
->
ed_prev
;
}
break
;
case
PIPE_INTERRUPT
:
periodic_unlink
(
ohci
,
ed
,
ed
->
intriso
.
intr_info
.
int_branch
,
ed
->
interval
);
for
(
i
=
ed
->
intriso
.
intr_info
.
int_branch
;
i
<
NUM_INTS
;
i
+=
ed
->
interval
)
ohci
->
ohci_int_load
[
i
]
-=
ed
->
intriso
.
intr_info
.
int_load
;
#ifdef OHCI_VERBOSE_DEBUG
ohci_dump_periodic
(
ohci
,
"UNLINK_INT"
);
#endif
break
;
case
PIPE_ISOCHRONOUS
:
if
(
ohci
->
ed_isotail
==
ed
)
ohci
->
ed_isotail
=
ed
->
ed_prev
;
if
(
ed
->
hwNextED
!=
0
)
(
dma_to_ed
(
ohci
,
le32_to_cpup
(
&
ed
->
hwNextED
)))
->
ed_prev
=
ed
->
ed_prev
;
if
(
ed
->
ed_prev
!=
NULL
)
ed
->
ed_prev
->
hwNextED
=
ed
->
hwNextED
;
else
periodic_unlink
(
ohci
,
ed
,
0
,
1
);
#ifdef OHCI_VERBOSE_DEBUG
ohci_dump_periodic
(
ohci
,
"UNLINK_ISO"
);
#endif
// case PIPE_INTERRUPT:
// case PIPE_ISOCHRONOUS:
default:
periodic_unlink
(
ohci
,
ed
);
break
;
}
/*
FIXME
Except for a couple of exceptionally clean unlink cases
/*
NOTE:
Except for a couple of exceptionally clean unlink cases
* (like unlinking the only c/b ED, with no TDs) HCs may still be
* caching this (till SOF).
*
* To avoid racing with the hardware, this needs to use ED_UNLINK
* and delay til next INTR_SF. Merge with start_urb_unlink().
* caching this operational ED (or its address). Safe unlinking
* involves not marking it ED_IDLE till INTR_SF; we always do that
* if td_list isn't empty. Otherwise the race is small; but ...
*/
ed
->
state
=
ED_IDLE
;
if
(
ed
->
state
==
ED_OPER
)
ed
->
state
=
ED_IDLE
;
}
...
...
@@ -369,7 +386,6 @@ static struct ed *ed_get (
)
{
int
is_out
=
!
usb_pipein
(
pipe
);
int
type
=
usb_pipetype
(
pipe
);
int
bus_msecs
=
0
;
struct
hcd_dev
*
dev
=
(
struct
hcd_dev
*
)
udev
->
hcpriv
;
struct
ed
*
ed
;
unsigned
ep
;
...
...
@@ -378,9 +394,6 @@ static struct ed *ed_get (
ep
=
usb_pipeendpoint
(
pipe
)
<<
1
;
if
(
type
!=
PIPE_CONTROL
&&
is_out
)
ep
|=
1
;
if
(
type
==
PIPE_INTERRUPT
)
bus_msecs
=
usb_calc_bus_time
(
udev
->
speed
,
!
is_out
,
0
,
usb_maxpacket
(
udev
,
pipe
,
is_out
))
/
1000
;
spin_lock_irqsave
(
&
ohci
->
lock
,
flags
);
...
...
@@ -422,23 +435,25 @@ static struct ed *ed_get (
info
=
cpu_to_le32
(
info
);
if
(
udev
->
speed
==
USB_SPEED_LOW
)
info
|=
ED_LOWSPEED
;
/* control transfers store pids in tds */
/*
only
control transfers store pids in tds */
if
(
type
!=
PIPE_CONTROL
)
{
info
|=
is_out
?
ED_OUT
:
ED_IN
;
if
(
type
==
PIPE_ISOCHRONOUS
)
info
|=
ED_ISO
;
if
(
type
==
PIPE_INTERRUPT
)
{
ed
->
intriso
.
intr_info
.
int_load
=
bus_msecs
;
if
(
interval
>
32
)
if
(
type
!=
PIPE_BULK
)
{
/* periodic transfers... */
if
(
type
==
PIPE_ISOCHRONOUS
)
info
|=
ED_ISO
;
else
if
(
interval
>
32
)
/* iso can be bigger */
interval
=
32
;
ed
->
interval
=
interval
;
ed
->
load
=
usb_calc_bus_time
(
udev
->
speed
,
!
is_out
,
type
==
PIPE_ISOCHRONOUS
,
usb_maxpacket
(
udev
,
pipe
,
is_out
))
/
1000
;
}
}
ed
->
hwINFO
=
info
;
/* value ignored except on periodic EDs, where
* we know it's already a power of 2
*/
ed
->
interval
=
interval
;
#ifdef DEBUG
/*
* There are two other cases we ought to change hwINFO, both during
...
...
@@ -473,8 +488,9 @@ static struct ed *ed_get (
*/
static
void
start_urb_unlink
(
struct
ohci_hcd
*
ohci
,
struct
ed
*
ed
)
{
ed
_deschedule
(
ohci
,
ed
)
;
ed
->
hwINFO
|=
ED_DEQUEUE
;
ed
->
state
=
ED_UNLINK
;
ed_deschedule
(
ohci
,
ed
);
/* SF interrupt might get delayed; record the frame counter value that
* indicates when the HC isn't looking at it, so concurrent unlinks
...
...
@@ -483,7 +499,9 @@ static void start_urb_unlink (struct ohci_hcd *ohci, struct ed *ed)
*/
ed
->
tick
=
le16_to_cpu
(
ohci
->
hcca
->
frame_no
)
+
1
;
/* rm_list is just singly linked, for simplicity */
ed
->
ed_next
=
ohci
->
ed_rm_list
;
ed
->
ed_prev
=
0
;
ohci
->
ed_rm_list
=
ed
;
/* enable SOF interrupt */
...
...
@@ -529,7 +547,6 @@ td_fill (unsigned int info,
/* use this td as the next dummy */
td_pt
=
urb_priv
->
td
[
index
];
td_pt
->
hwNextTD
=
0
;
/* fill the old dummy TD */
td
=
urb_priv
->
td
[
index
]
=
urb_priv
->
ed
->
dummy
;
...
...
@@ -547,7 +564,7 @@ td_fill (unsigned int info,
if
(
is_iso
)
{
td
->
hwCBP
=
cpu_to_le32
(
data
&
0xFFFFF000
);
td
->
hwPSW
[
0
]
=
cpu_to_le16
((
data
&
0x0FFF
)
|
0xE000
);
td
->
ed
->
intriso
.
last_iso
=
info
&
0xffff
;
td
->
ed
->
last_iso
=
info
&
0xffff
;
}
else
{
td
->
hwCBP
=
cpu_to_le32
(
data
);
}
...
...
@@ -608,9 +625,11 @@ static void td_submit_urb (
/* Bulk and interrupt are identical except for where in the schedule
* their EDs live.
*/
// case PIPE_BULK:
// case PIPE_INTERRUPT:
default:
case
PIPE_INTERRUPT
:
/* ... and periodic urbs have extra accounting */
ohci
->
hcd
.
self
.
bandwidth_int_reqs
++
;
/* FALLTHROUGH */
case
PIPE_BULK
:
info
=
is_out
?
TD_T_TOGGLE
|
TD_CC
|
TD_DP_OUT
:
TD_T_TOGGLE
|
TD_CC
|
TD_DP_IN
;
...
...
@@ -676,6 +695,7 @@ static void td_submit_urb (
data
+
urb
->
iso_frame_desc
[
cnt
].
offset
,
urb
->
iso_frame_desc
[
cnt
].
length
,
urb
,
cnt
);
}
ohci
->
hcd
.
self
.
bandwidth_isoc_reqs
++
;
break
;
}
if
(
urb_priv
->
length
!=
cnt
)
...
...
@@ -802,6 +822,7 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
if
(
td_list
->
ed
->
hwHeadP
&
ED_H
)
{
if
(
urb_priv
&&
((
td_list
->
index
+
1
)
<
urb_priv
->
length
))
{
#ifdef DEBUG
struct
urb
*
urb
=
td_list
->
urb
;
/* help for troubleshooting: */
...
...
@@ -817,6 +838,7 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
1
+
td_list
->
index
,
urb_priv
->
length
,
cc
,
cc_to_error
[
cc
]);
#endif
td_list
->
ed
->
hwHeadP
=
(
urb_priv
->
td
[
urb_priv
->
length
-
1
]
->
hwNextTD
&
__constant_cpu_to_le32
(
TD_MASK
))
...
...
@@ -872,8 +894,7 @@ static void finish_unlinks (struct ohci_hcd *ohci, u16 tick)
* we call a completion since it might have unlinked
* another (earlier) urb
*
* FIXME use td_list to scan, not ed hashtables.
* completely abolish ed hashtables!
* FIXME use td_list to scan, not td hashtables.
*/
rescan_this:
completed
=
0
;
...
...
@@ -894,8 +915,7 @@ static void finish_unlinks (struct ohci_hcd *ohci, u16 tick)
td_done
(
urb
,
td
);
urb_priv
->
td_cnt
++
;
*
td_p
=
td
->
hwNextTD
|
(
*
td_p
&
__constant_cpu_to_le32
(
0x3
));
*
td_p
=
td
->
hwNextTD
|
(
*
td_p
&
~
TD_MASK
);
/* URB is done; clean up */
if
(
urb_priv
->
td_cnt
==
urb_priv
->
length
)
{
...
...
drivers/usb/host/ohci.h
View file @
e23525cd
...
...
@@ -5,7 +5,6 @@
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
*
* This file is licenced under the GPL.
* $Id: ohci.h,v 1.6 2002/03/22 16:04:54 dbrownell Exp $
*/
/*
...
...
@@ -18,13 +17,16 @@
struct
ed
{
/* first fields are hardware-specified, le32 */
__u32
hwINFO
;
/* endpoint config bitmap */
/* info bits defined by hcd */
#define ED_DEQUEUE __constant_cpu_to_le32(1 << 27)
/* info bits defined by the hardware */
#define ED_ISO __constant_cpu_to_le32(1 << 15)
#define ED_SKIP __constant_cpu_to_le32(1 << 14)
#define ED_LOWSPEED __constant_cpu_to_le32(1 << 13)
#define ED_OUT __constant_cpu_to_le32(0x01 << 11)
#define ED_IN __constant_cpu_to_le32(0x02 << 11)
__u32
hwTailP
;
/* tail of TD list */
__u32
hwHeadP
;
/* head of TD list */
__u32
hwHeadP
;
/* head of TD list
(hc r/w)
*/
#define ED_C __constant_cpu_to_le32(0x02)
/* toggle carry */
#define ED_H __constant_cpu_to_le32(0x01)
/* halted */
__u32
hwNextED
;
/* next ED in list */
...
...
@@ -48,14 +50,12 @@ struct ed {
#define ED_OPER 0x02
/* IS linked to hc */
u8
type
;
/* PIPE_{BULK,...} */
u16
interval
;
/* interrupt, isochronous */
union
{
struct
intr_info
{
/* interrupt */
u8
int_branch
;
u8
int_load
;
}
intr_info
;
u16
last_iso
;
/* isochronous */
}
intriso
;
/* periodic scheduling params (for intr and iso) */
u8
branch
;
u16
interval
;
u16
load
;
u16
last_iso
;
/* iso only */
/* HC may see EDs on rm_list until next frame (frame_no == tick) */
u16
tick
;
...
...
@@ -335,10 +335,8 @@ struct hash_list_t {
};
#define TD_HASH_SIZE 64
/* power'o'two */
#define ED_HASH_SIZE 64
/* power'o'two */
#define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma >> 5)) % TD_HASH_SIZE)
#define ED_HASH_FUNC(ed_dma) ((ed_dma ^ (ed_dma >> 5)) % ED_HASH_SIZE)
/*
...
...
@@ -373,7 +371,7 @@ struct ohci_hcd {
struct
ed
*
ed_bulktail
;
/* last in bulk list */
struct
ed
*
ed_controltail
;
/* last in ctrl list */
struct
ed
*
ed_isotail
;
/* last in iso list
*/
struct
ed
*
periodic
[
NUM_INTS
];
/* shadow int_table
*/
/*
* memory management for queue data structures
...
...
@@ -381,14 +379,13 @@ struct ohci_hcd {
struct
pci_pool
*
td_cache
;
struct
pci_pool
*
ed_cache
;
struct
hash_list_t
td_hash
[
TD_HASH_SIZE
];
struct
hash_list_t
ed_hash
[
ED_HASH_SIZE
];
/*
* driver state
*/
int
disabled
;
/* e.g. got a UE, we're hung */
int
sleeping
;
int
ohci_int_
load
[
NUM_INTS
];
int
load
[
NUM_INTS
];
u32
hc_control
;
/* copy of hc control reg */
unsigned
long
flags
;
/* for HC bugs */
...
...
drivers/usb/host/uhci-hcd.c
View file @
e23525cd
...
...
@@ -105,12 +105,10 @@ static void wakeup_hc(struct uhci_hcd *uhci);
/* to make sure it doesn't hog all of the bandwidth */
#define DEPTH_INTERVAL 5
#define MAX_URB_LOOP 2048
/* Maximum number of linked URB's */
/*
* Technically, updating td->status here is a race, but it's not really a
* problem. The worst that can happen is that we set the IOC bit again
* generating a spurios interrupt. We could fix this by creating another
* generating a spurio
u
s interrupt. We could fix this by creating another
* QH and leaving the IOC bit always set, but then we would have to play
* games with the FSBR code to make sure we get the correct order in all
* the cases. I don't think it's worth the effort
...
...
@@ -148,7 +146,7 @@ static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *d
dma_addr_t
dma_handle
;
struct
uhci_td
*
td
;
td
=
pci_pool_alloc
(
uhci
->
td_pool
,
GFP_
DMA
|
GFP_
ATOMIC
,
&
dma_handle
);
td
=
pci_pool_alloc
(
uhci
->
td_pool
,
GFP_ATOMIC
,
&
dma_handle
);
if
(
!
td
)
return
NULL
;
...
...
@@ -273,7 +271,7 @@ static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td)
/*
* Inserts a td into qh list at the top.
*/
static
void
uhci_insert_tds_in_qh
(
struct
uhci_qh
*
qh
,
struct
urb
*
urb
,
int
breadth
)
static
void
uhci_insert_tds_in_qh
(
struct
uhci_qh
*
qh
,
struct
urb
*
urb
,
u32
breadth
)
{
struct
list_head
*
tmp
,
*
head
;
struct
urb_priv
*
urbp
=
(
struct
urb_priv
*
)
urb
->
hcpriv
;
...
...
@@ -290,7 +288,7 @@ static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, int bread
td
=
list_entry
(
tmp
,
struct
uhci_td
,
list
);
/* Add the first TD to the QH element pointer */
qh
->
element
=
cpu_to_le32
(
td
->
dma_handle
)
|
(
breadth
?
0
:
UHCI_PTR_DEPTH
)
;
qh
->
element
=
cpu_to_le32
(
td
->
dma_handle
)
|
breadth
;
ptd
=
td
;
...
...
@@ -301,7 +299,7 @@ static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, int bread
tmp
=
tmp
->
next
;
ptd
->
link
=
cpu_to_le32
(
td
->
dma_handle
)
|
(
breadth
?
0
:
UHCI_PTR_DEPTH
)
;
ptd
->
link
=
cpu_to_le32
(
td
->
dma_handle
)
|
breadth
;
ptd
=
td
;
}
...
...
@@ -311,10 +309,6 @@ static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, int bread
static
void
uhci_free_td
(
struct
uhci_hcd
*
uhci
,
struct
uhci_td
*
td
)
{
/*
if (!list_empty(&td->list) || !list_empty(&td->fl_list))
dbg("td %p is still in URB list!", td);
*/
if
(
!
list_empty
(
&
td
->
list
))
dbg
(
"td %p is still in list!"
,
td
);
if
(
!
list_empty
(
&
td
->
fl_list
))
...
...
@@ -331,7 +325,7 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, struct usb_device *d
dma_addr_t
dma_handle
;
struct
uhci_qh
*
qh
;
qh
=
pci_pool_alloc
(
uhci
->
qh_pool
,
GFP_
DMA
|
GFP_
ATOMIC
,
&
dma_handle
);
qh
=
pci_pool_alloc
(
uhci
->
qh_pool
,
GFP_ATOMIC
,
&
dma_handle
);
if
(
!
qh
)
return
NULL
;
...
...
@@ -365,43 +359,57 @@ static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
}
/*
* Append this urb's qh after the last qh in skelqh->list
* MUST be called with uhci->frame_list_lock acquired
*
* Note that urb_priv.queue_list doesn't have a separate queue head;
* it's a ring with every element "live".
*/
static
void
_uhci_insert_qh
(
struct
uhci_hcd
*
uhci
,
struct
uhci_qh
*
skelqh
,
struct
urb
*
urb
)
{
struct
urb_priv
*
urbp
=
(
struct
urb_priv
*
)
urb
->
hcpriv
;
struct
list_head
*
head
,
*
tmp
;
struct
list_head
*
tmp
;
struct
uhci_qh
*
lqh
;
/* Grab the last QH */
lqh
=
list_entry
(
skelqh
->
list
.
prev
,
struct
uhci_qh
,
list
);
/* Patch this endpoint's URBs' QHs to point to the next skelQH:
* SkelQH --> ... lqh --> NewQH --> NextSkelQH
* Do this first, so the HC always sees the right QH after this one.
*/
list_for_each
(
tmp
,
&
urbp
->
queue_list
)
{
struct
urb_priv
*
turbp
=
list_entry
(
tmp
,
struct
urb_priv
,
queue_list
);
turbp
->
qh
->
link
=
lqh
->
link
;
}
urbp
->
qh
->
link
=
lqh
->
link
;
wmb
();
/* Ordering is important */
/* Patch QHs for previous endpoint's queued URBs? HC goes
* here next, not to the NextSkelQH it now points to.
*
* lqh --> td ... --> qh ... --> td --> qh ... --> td
* | | |
* v v v
* +<----------------+-----------------+
* v
* NewQH --> td ... --> td
* |
* v
* ...
*
* The HC could see (and use!) any of these as we write them.
*/
if
(
lqh
->
urbp
)
{
head
=
&
lqh
->
urbp
->
queue_list
;
tmp
=
head
->
next
;
while
(
head
!=
tmp
)
{
list_for_each
(
tmp
,
&
lqh
->
urbp
->
queue_list
)
{
struct
urb_priv
*
turbp
=
list_entry
(
tmp
,
struct
urb_priv
,
queue_list
);
tmp
=
tmp
->
next
;
turbp
->
qh
->
link
=
cpu_to_le32
(
urbp
->
qh
->
dma_handle
)
|
UHCI_PTR_QH
;
}
}
head
=
&
urbp
->
queue_list
;
tmp
=
head
->
next
;
while
(
head
!=
tmp
)
{
struct
urb_priv
*
turbp
=
list_entry
(
tmp
,
struct
urb_priv
,
queue_list
);
tmp
=
tmp
->
next
;
turbp
->
qh
->
link
=
lqh
->
link
;
}
urbp
->
qh
->
link
=
lqh
->
link
;
mb
();
/* Ordering is important */
lqh
->
link
=
cpu_to_le32
(
urbp
->
qh
->
dma_handle
)
|
UHCI_PTR_QH
;
list_add_tail
(
&
urbp
->
qh
->
list
,
&
skelqh
->
list
);
...
...
@@ -416,6 +424,9 @@ static void uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct
spin_unlock_irqrestore
(
&
uhci
->
frame_list_lock
,
flags
);
}
/* start removal of qh from schedule; it finishes next frame.
* TDs should be unlinked before this is called.
*/
static
void
uhci_remove_qh
(
struct
uhci_hcd
*
uhci
,
struct
uhci_qh
*
qh
)
{
unsigned
long
flags
;
...
...
@@ -869,12 +880,12 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb)
urbp
->
qh
=
qh
;
qh
->
urbp
=
urbp
;
/* Low speed
or small transfers gets a different queue and treatment
*/
/* Low speed
transfers get a different queue, and won't hog the bus
*/
if
(
urb
->
dev
->
speed
==
USB_SPEED_LOW
)
{
uhci_insert_tds_in_qh
(
qh
,
urb
,
0
);
uhci_insert_tds_in_qh
(
qh
,
urb
,
UHCI_PTR_DEPTH
);
uhci_insert_qh
(
uhci
,
uhci
->
skel_ls_control_qh
,
urb
);
}
else
{
uhci_insert_tds_in_qh
(
qh
,
urb
,
1
);
uhci_insert_tds_in_qh
(
qh
,
urb
,
UHCI_PTR_BREADTH
);
uhci_insert_qh
(
uhci
,
uhci
->
skel_hs_control_qh
,
urb
);
uhci_inc_fsbr
(
uhci
,
urb
);
}
...
...
@@ -914,9 +925,9 @@ static int usb_control_retrigger_status(struct uhci_hcd *uhci, struct urb *urb)
urbp
->
qh
->
urbp
=
urbp
;
/* One TD, who cares about Breadth first? */
uhci_insert_tds_in_qh
(
urbp
->
qh
,
urb
,
0
);
uhci_insert_tds_in_qh
(
urbp
->
qh
,
urb
,
UHCI_PTR_DEPTH
);
/* Low speed
or small transfers gets a different queue and treatment
*/
/* Low speed
transfers get a different queue
*/
if
(
urb
->
dev
->
speed
==
USB_SPEED_LOW
)
uhci_insert_qh
(
uhci
,
uhci
->
skel_ls_control_qh
,
urb
);
else
...
...
@@ -1242,8 +1253,8 @@ static int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, struct urb *
urbp
->
qh
=
qh
;
qh
->
urbp
=
urbp
;
/* Always
assume
breadth first */
uhci_insert_tds_in_qh
(
qh
,
urb
,
1
);
/* Always breadth first */
uhci_insert_tds_in_qh
(
qh
,
urb
,
UHCI_PTR_BREADTH
);
if
(
eurb
)
uhci_append_queued_urb
(
uhci
,
eurb
,
urb
);
...
...
@@ -1487,6 +1498,10 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, int mem_flags)
spin_unlock_irqrestore
(
&
uhci
->
urb_list_lock
,
flags
);
if
(
ret
!=
-
EINPROGRESS
)
{
uhci_destroy_urb_priv
(
uhci
,
urb
);
return
ret
;
}
return
0
;
}
...
...
@@ -1795,8 +1810,7 @@ static void uhci_finish_urb(struct usb_hcd *hcd, struct urb *urb)
spin_lock_irqsave
(
&
urb
->
lock
,
flags
);
killed
=
(
urb
->
status
==
-
ENOENT
||
urb
->
status
==
-
ECONNABORTED
||
urb
->
status
==
-
ECONNRESET
);
killed
=
(
urb
->
status
==
-
ENOENT
||
urb
->
status
==
-
ECONNRESET
);
resubmit_interrupt
=
(
usb_pipetype
(
urb
->
pipe
)
==
PIPE_INTERRUPT
&&
urb
->
interval
);
...
...
@@ -1817,9 +1831,7 @@ static void uhci_finish_urb(struct usb_hcd *hcd, struct urb *urb)
if
(
resubmit_interrupt
)
/* Recheck the status. The completion handler may have */
/* unlinked the resubmitting interrupt URB */
killed
=
(
urb
->
status
==
-
ENOENT
||
urb
->
status
==
-
ECONNABORTED
||
urb
->
status
==
-
ECONNRESET
);
killed
=
(
urb
->
status
==
-
ENOENT
||
urb
->
status
==
-
ECONNRESET
);
if
(
resubmit_interrupt
&&
!
killed
)
{
urb
->
dev
=
dev
;
...
...
@@ -2016,19 +2028,12 @@ static void start_hc(struct uhci_hcd *uhci)
uhci
->
hcd
.
state
=
USB_STATE_READY
;
}
#ifdef CONFIG_PROC_FS
static
int
uhci_num
=
0
;
#endif
/*
* De-allocate all resources..
*/
static
void
release_uhci
(
struct
uhci_hcd
*
uhci
)
{
int
i
;
#ifdef CONFIG_PROC_FS
char
buf
[
8
];
#endif
for
(
i
=
0
;
i
<
UHCI_NUM_SKELQH
;
i
++
)
if
(
uhci
->
skelqh
[
i
])
{
...
...
@@ -2053,15 +2058,13 @@ static void release_uhci(struct uhci_hcd *uhci)
}
if
(
uhci
->
fl
)
{
pci_free_consistent
(
uhci
->
dev
,
sizeof
(
*
uhci
->
fl
),
uhci
->
fl
,
uhci
->
fl
->
dma_handle
);
pci_free_consistent
(
uhci
->
hcd
.
p
dev
,
sizeof
(
*
uhci
->
fl
),
uhci
->
fl
,
uhci
->
fl
->
dma_handle
);
uhci
->
fl
=
NULL
;
}
#ifdef CONFIG_PROC_FS
if
(
uhci
->
proc_entry
)
{
sprintf
(
buf
,
"hc%d"
,
uhci
->
num
);
remove_proc_entry
(
buf
,
uhci_proc_root
);
remove_proc_entry
(
uhci
->
hcd
.
self
.
bus_name
,
uhci_proc_root
);
uhci
->
proc_entry
=
NULL
;
}
#endif
...
...
@@ -2086,33 +2089,20 @@ static void release_uhci(struct uhci_hcd *uhci)
static
int
__devinit
uhci_start
(
struct
usb_hcd
*
hcd
)
{
struct
uhci_hcd
*
uhci
=
hcd_to_uhci
(
hcd
);
struct
pci_dev
*
dev
=
hcd
->
pdev
;
int
retval
=
-
EBUSY
;
int
i
,
port
;
unsigned
io_size
;
dma_addr_t
dma_handle
;
struct
usb_device
*
udev
;
#ifdef CONFIG_PROC_FS
char
buf
[
8
];
struct
proc_dir_entry
*
ent
;
#endif
uhci
->
dev
=
dev
;
/* Should probably move to core/hcd.c */
if
(
pci_set_dma_mask
(
dev
,
0xFFFFFFFF
))
{
err
(
"couldn't set PCI dma mask"
);
retval
=
-
ENODEV
;
goto
err_pci_set_dma_mask
;
}
uhci
->
io_addr
=
pci_resource_start
(
dev
,
hcd
->
region
);
uhci
->
io_size
=
pci_resource_len
(
dev
,
hcd
->
region
);
uhci
->
io_addr
=
(
unsigned
)
hcd
->
regs
;
io_size
=
pci_resource_len
(
hcd
->
pdev
,
hcd
->
region
);
#ifdef CONFIG_PROC_FS
uhci
->
num
=
uhci_num
++
;
sprintf
(
buf
,
"hc%d"
,
uhci
->
num
);
ent
=
create_proc_entry
(
buf
,
S_IFREG
|
S_IRUGO
|
S_IWUSR
,
uhci_proc_root
);
ent
=
create_proc_entry
(
hcd
->
self
.
bus_name
,
S_IFREG
|
S_IRUGO
|
S_IWUSR
,
uhci_proc_root
);
if
(
!
ent
)
{
err
(
"couldn't create uhci proc entry"
);
retval
=
-
ENOMEM
;
...
...
@@ -2148,7 +2138,7 @@ static int __devinit uhci_start(struct usb_hcd *hcd)
spin_lock_init
(
&
uhci
->
frame_list_lock
);
uhci
->
fl
=
pci_alloc_consistent
(
dev
,
sizeof
(
*
uhci
->
fl
),
&
dma_handle
);
uhci
->
fl
=
pci_alloc_consistent
(
hcd
->
p
dev
,
sizeof
(
*
uhci
->
fl
),
&
dma_handle
);
if
(
!
uhci
->
fl
)
{
err
(
"unable to allocate consistent memory for frame list"
);
goto
err_alloc_fl
;
...
...
@@ -2158,15 +2148,15 @@ static int __devinit uhci_start(struct usb_hcd *hcd)
uhci
->
fl
->
dma_handle
=
dma_handle
;
uhci
->
td_pool
=
pci_pool_create
(
"uhci_td"
,
dev
,
sizeof
(
struct
uhci_td
),
16
,
0
,
GFP_
DMA
|
GFP_
ATOMIC
);
uhci
->
td_pool
=
pci_pool_create
(
"uhci_td"
,
hcd
->
p
dev
,
sizeof
(
struct
uhci_td
),
16
,
0
,
GFP_ATOMIC
);
if
(
!
uhci
->
td_pool
)
{
err
(
"unable to create td pci_pool"
);
goto
err_create_td_pool
;
}
uhci
->
qh_pool
=
pci_pool_create
(
"uhci_qh"
,
dev
,
sizeof
(
struct
uhci_qh
),
16
,
0
,
GFP_
DMA
|
GFP_
ATOMIC
);
uhci
->
qh_pool
=
pci_pool_create
(
"uhci_qh"
,
hcd
->
p
dev
,
sizeof
(
struct
uhci_qh
),
16
,
0
,
GFP_ATOMIC
);
if
(
!
uhci
->
qh_pool
)
{
err
(
"unable to create qh pci_pool"
);
goto
err_create_qh_pool
;
...
...
@@ -2178,7 +2168,7 @@ static int __devinit uhci_start(struct usb_hcd *hcd)
/* they may have more but give no way to determine how many they */
/* have. However, according to the UHCI spec, Bit 7 is always set */
/* to 1. So we try to use this to our advantage */
for
(
port
=
0
;
port
<
(
uhci
->
io_size
-
0x10
)
/
2
;
port
++
)
{
for
(
port
=
0
;
port
<
(
io_size
-
0x10
)
/
2
;
port
++
)
{
unsigned
int
portstatus
;
portstatus
=
inw
(
uhci
->
io_addr
+
0x10
+
(
port
*
2
));
...
...
@@ -2197,13 +2187,13 @@ static int __devinit uhci_start(struct usb_hcd *hcd)
uhci
->
rh_numports
=
port
;
hcd
->
self
.
root_hub
=
u
hci
->
rh_
dev
=
usb_alloc_dev
(
NULL
,
&
hcd
->
self
);
if
(
!
u
hci
->
rh_
dev
)
{
hcd
->
self
.
root_hub
=
udev
=
usb_alloc_dev
(
NULL
,
&
hcd
->
self
);
if
(
!
udev
)
{
err
(
"unable to allocate root hub"
);
goto
err_alloc_root_hub
;
}
uhci
->
skeltd
[
0
]
=
uhci_alloc_td
(
uhci
,
u
hci
->
rh_
dev
);
uhci
->
skeltd
[
0
]
=
uhci_alloc_td
(
uhci
,
udev
);
if
(
!
uhci
->
skeltd
[
0
])
{
err
(
"unable to allocate TD 0"
);
goto
err_alloc_skeltd
;
...
...
@@ -2216,7 +2206,7 @@ static int __devinit uhci_start(struct usb_hcd *hcd)
for
(
i
=
1
;
i
<
9
;
i
++
)
{
struct
uhci_td
*
td
;
td
=
uhci
->
skeltd
[
i
]
=
uhci_alloc_td
(
uhci
,
u
hci
->
rh_
dev
);
td
=
uhci
->
skeltd
[
i
]
=
uhci_alloc_td
(
uhci
,
udev
);
if
(
!
td
)
{
err
(
"unable to allocate TD %d"
,
i
);
goto
err_alloc_skeltd
;
...
...
@@ -2227,14 +2217,14 @@ static int __devinit uhci_start(struct usb_hcd *hcd)
td
->
link
=
cpu_to_le32
(
uhci
->
skeltd
[
i
-
1
]
->
dma_handle
);
}
uhci
->
skel_term_td
=
uhci_alloc_td
(
uhci
,
u
hci
->
rh_
dev
);
uhci
->
skel_term_td
=
uhci_alloc_td
(
uhci
,
udev
);
if
(
!
uhci
->
skel_term_td
)
{
err
(
"unable to allocate skel TD term"
);
goto
err_alloc_skeltd
;
}
for
(
i
=
0
;
i
<
UHCI_NUM_SKELQH
;
i
++
)
{
uhci
->
skelqh
[
i
]
=
uhci_alloc_qh
(
uhci
,
u
hci
->
rh_
dev
);
uhci
->
skelqh
[
i
]
=
uhci_alloc_qh
(
uhci
,
udev
);
if
(
!
uhci
->
skelqh
[
i
])
{
err
(
"unable to allocate QH %d"
,
i
);
goto
err_alloc_skelqh
;
...
...
@@ -2303,12 +2293,12 @@ static int __devinit uhci_start(struct usb_hcd *hcd)
init_stall_timer
(
hcd
);
/* disable legacy emulation */
pci_write_config_word
(
dev
,
USBLEGSUP
,
USBLEGSUP_DEFAULT
);
pci_write_config_word
(
hcd
->
p
dev
,
USBLEGSUP
,
USBLEGSUP_DEFAULT
);
usb_connect
(
u
hci
->
rh_
dev
);
uhci
->
rh_
dev
->
speed
=
USB_SPEED_FULL
;
usb_connect
(
udev
);
u
dev
->
speed
=
USB_SPEED_FULL
;
if
(
usb_register_root_hub
(
u
hci
->
rh_dev
,
&
dev
->
dev
)
!=
0
)
{
if
(
usb_register_root_hub
(
u
dev
,
&
hcd
->
p
dev
->
dev
)
!=
0
)
{
err
(
"unable to start root hub"
);
retval
=
-
ENOMEM
;
goto
err_start_root_hub
;
...
...
@@ -2322,7 +2312,7 @@ static int __devinit uhci_start(struct usb_hcd *hcd)
err_start_root_hub:
reset_hc
(
uhci
);
del_timer
(
&
uhci
->
stall_timer
);
del_timer
_sync
(
&
uhci
->
stall_timer
);
for
(
i
=
0
;
i
<
UHCI_NUM_SKELQH
;
i
++
)
if
(
uhci
->
skelqh
[
i
])
{
...
...
@@ -2338,8 +2328,8 @@ static int __devinit uhci_start(struct usb_hcd *hcd)
}
err_alloc_skeltd:
usb_free_dev
(
u
hci
->
rh_
dev
);
uhci
->
rh_dev
=
NULL
;
usb_free_dev
(
udev
);
hcd
->
self
.
root_hub
=
NULL
;
err_alloc_root_hub:
pci_pool_destroy
(
uhci
->
qh_pool
);
...
...
@@ -2350,19 +2340,17 @@ static int __devinit uhci_start(struct usb_hcd *hcd)
uhci
->
td_pool
=
NULL
;
err_create_td_pool:
pci_free_consistent
(
dev
,
sizeof
(
*
uhci
->
fl
),
uhci
->
fl
,
uhci
->
fl
->
dma_handle
);
pci_free_consistent
(
hcd
->
p
dev
,
sizeof
(
*
uhci
->
fl
),
uhci
->
fl
,
uhci
->
fl
->
dma_handle
);
uhci
->
fl
=
NULL
;
err_alloc_fl:
#ifdef CONFIG_PROC_FS
remove_proc_entry
(
buf
,
uhci_proc_root
);
remove_proc_entry
(
hcd
->
self
.
bus_name
,
uhci_proc_root
);
uhci
->
proc_entry
=
NULL
;
err_create_proc_entry:
#endif
err_pci_set_dma_mask:
return
retval
;
}
...
...
@@ -2370,10 +2358,7 @@ static void uhci_stop(struct usb_hcd *hcd)
{
struct
uhci_hcd
*
uhci
=
hcd_to_uhci
(
hcd
);
if
(
uhci
->
rh_dev
)
usb_disconnect
(
&
uhci
->
rh_dev
);
del_timer
(
&
uhci
->
stall_timer
);
del_timer_sync
(
&
uhci
->
stall_timer
);
/*
* At this point, we're guaranteed that no new connects can be made
...
...
@@ -2402,7 +2387,7 @@ static int uhci_resume(struct usb_hcd *hcd)
{
struct
uhci_hcd
*
uhci
=
hcd_to_uhci
(
hcd
);
pci_set_master
(
uhci
->
dev
);
pci_set_master
(
uhci
->
hcd
.
p
dev
);
reset_hc
(
uhci
);
start_hc
(
uhci
);
...
...
drivers/usb/host/uhci-hcd.h
View file @
e23525cd
...
...
@@ -65,6 +65,7 @@
#define UHCI_PTR_TERM cpu_to_le32(0x0001)
#define UHCI_PTR_QH cpu_to_le32(0x0002)
#define UHCI_PTR_DEPTH cpu_to_le32(0x0004)
#define UHCI_PTR_BREADTH cpu_to_le32(0x0000)
#define UHCI_NUMFRAMES 1024
/* in the frame list [array] */
#define UHCI_MAX_SOF_NUMBER 2047
/* in an SOF packet */
...
...
@@ -80,6 +81,19 @@ struct uhci_frame_list {
struct
urb_priv
;
/* One role of a QH is to hold a queue of TDs for some endpoint. Each QH is
* used with one URB, and qh->element (updated by the HC) is either:
* - the next unprocessed TD for the URB, or
* - UHCI_PTR_TERM (when there's no more traffic for this endpoint), or
* - the QH for the next URB queued to the same endpoint.
*
* The other role of a QH is to serve as a "skeleton" framelist entry, so we
* can easily splice a QH for some endpoint into the schedule at the right
* place. Then qh->element is UHCI_PTR_TERM.
*
* In the frame list, qh->link maintains a list of QHs seen by the HC:
* skel1 --> ep1-qh --> ep2-qh --> ... --> skel2 --> ...
*/
struct
uhci_qh
{
/* Hardware fields */
__u32
link
;
/* Next queue */
...
...
@@ -156,6 +170,9 @@ struct uhci_qh {
*
* Alas, not anymore, we have more than 4 words for software, woops.
* Everything still works tho, surprise! -jerdfelt
*
* td->link points to either another TD (not necessarily for the same urb or
* even the same endpoint), or nothing (PTR_TERM), or a QH (for queued urbs)
*/
struct
uhci_td
{
/* Hardware fields */
...
...
@@ -172,7 +189,7 @@ struct uhci_td {
struct
list_head
list
;
/* P: urb->lock */
int
frame
;
int
frame
;
/* for iso: what frame? */
struct
list_head
fl_list
;
/* P: uhci->frame_list_lock */
}
__attribute__
((
aligned
(
16
)));
...
...
@@ -217,6 +234,22 @@ struct uhci_td {
*
* To keep with Linus' nomenclature, this is called the QH skeleton. These
* labels (below) are only signficant to the root hub's QH's
*
*
* NOTE: That ASCII art doesn't match the current (August 2002) code, in
* more ways than just not using QHs for ISO.
*
* NOTE: Another way to look at the UHCI schedules is to compare them to what
* other host controller interfaces use. EHCI, OHCI, and UHCI all have tables
* of transfers that the controller scans, frame by frame, and which hold the
* scheduled periodic transfers. The key differences are that UHCI
*
* (a) puts control and bulk transfers into that same table; the others
* have separate data structures for non-periodic transfers.
* (b) lets QHs be linked from TDs, not just other QHs, since they don't
* hold endpoint data. this driver chooses to use one QH per URB.
* (c) needs more TDs, since it uses one per packet. the data toggle
* is stored in those TDs, along with all other endpoint state.
*/
#define UHCI_NUM_SKELTD 10
...
...
@@ -275,7 +308,7 @@ static inline int __interval_to_skel(int interval)
return
7
;
/* int128 for 128-255 ms (Max.) */
}
#define hcd_to_uhci(hcd_ptr)
list_entry
(hcd_ptr, struct uhci_hcd, hcd)
#define hcd_to_uhci(hcd_ptr)
container_of
(hcd_ptr, struct uhci_hcd, hcd)
/*
* This describes the full uhci information.
...
...
@@ -286,18 +319,13 @@ static inline int __interval_to_skel(int interval)
struct
uhci_hcd
{
struct
usb_hcd
hcd
;
struct
pci_dev
*
dev
;
#ifdef CONFIG_PROC_FS
/* procfs */
int
num
;
struct
proc_dir_entry
*
proc_entry
;
#endif
/* Grabbed from PCI */
int
irq
;
unsigned
int
io_addr
;
unsigned
int
io_size
;
struct
pci_pool
*
qh_pool
;
struct
pci_pool
*
td_pool
;
...
...
@@ -329,7 +357,6 @@ struct uhci_hcd {
spinlock_t
complete_list_lock
;
struct
list_head
complete_list
;
/* P: uhci->complete_list_lock */
struct
usb_device
*
rh_dev
;
/* Root hub */
int
rh_numports
;
struct
timer_list
stall_timer
;
...
...
drivers/usb/net/pegasus.h
View file @
e23525cd
...
...
@@ -191,6 +191,8 @@ PEGASUS_DEV( "Billionton USBE-100", VENDOR_BILLIONTON, 0x8511,
DEFAULT_GPIO_RESET
|
PEGASUS_II
)
PEGASUS_DEV
(
"Corega FEter USB-TX"
,
VENDOR_COREGA
,
0x0004
,
DEFAULT_GPIO_RESET
)
PEGASUS_DEV
(
"Corega FEter"
,
VENDOR_COREGA
,
0x0004
,
DEFAULT_GPIO_RESET
|
PEGASUS_II
)
PEGASUS_DEV
(
"D-Link DSB-650TX"
,
VENDOR_DLINK
,
0x4001
,
LINKSYS_GPIO_RESET
)
PEGASUS_DEV
(
"D-Link DSB-650TX"
,
VENDOR_DLINK
,
0x4002
,
...
...
@@ -205,7 +207,7 @@ PEGASUS_DEV( "D-Link DSB-650TX(PNA)", VENDOR_DLINK, 0x4003,
DEFAULT_GPIO_RESET
|
HAS_HOME_PNA
)
PEGASUS_DEV
(
"D-Link DSB-650"
,
VENDOR_DLINK
,
0xabc1
,
DEFAULT_GPIO_RESET
)
PEGASUS_DEV
(
"
ELCON EPLC10Mi USB to Powerline
Adapter"
,
VENDOR_ELCON
,
0x0002
,
PEGASUS_DEV
(
"
GOLDPFEIL USB
Adapter"
,
VENDOR_ELCON
,
0x0002
,
DEFAULT_GPIO_RESET
|
PEGASUS_II
|
HAS_HOME_PNA
)
PEGASUS_DEV
(
"Elsa Micolink USB2Ethernet"
,
VENDOR_ELSA
,
0x3000
,
DEFAULT_GPIO_RESET
)
...
...
@@ -254,7 +256,7 @@ PEGASUS_DEV( "SOHOware NUB100 Ethernet", VENDOR_SOHOWARE, 0x9100,
PEGASUS_DEV
(
"SOHOware NUB110 Ethernet"
,
VENDOR_SOHOWARE
,
0x9110
,
DEFAULT_GPIO_RESET
|
PEGASUS_II
)
PEGASUS_DEV
(
"SpeedStream USB 10/100 Ethernet"
,
VENDOR_SIEMENS
,
0x1001
,
DEFAULT_GPIO_RESET
)
DEFAULT_GPIO_RESET
|
PEGASUS_II
)
#endif
/* PEGASUS_DEV */
drivers/usb/storage/unusual_devs.h
View file @
e23525cd
...
...
@@ -310,6 +310,13 @@ UNUSUAL_DEV( 0x05dc, 0x0001, 0x0000, 0x0001,
US_FL_MODE_XLATE
),
#endif
/* Reported by Blake Matheny <bmatheny@purdue.edu> */
UNUSUAL_DEV
(
0x05dc
,
0xb002
,
0x0000
,
0x0113
,
"Lexar"
,
"USB CF Reader"
,
US_SC_SCSI
,
US_PR_BULK
,
NULL
,
US_FL_FIX_INQUIRY
),
/* Reported by Carlos Villegas <cav@uniscope.co.jp>
* This device needs an INQUIRY of exactly 36-bytes to function.
* That is the only reason this entry is needed.
...
...
drivers/usb/storage/usb.c
View file @
e23525cd
...
...
@@ -440,8 +440,14 @@ static int usb_stor_control_thread(void * __us)
/* Most USB devices can't handle START_STOP. But we
* need something for media-change, so we'll use TUR
* instead.
*
* We specifically allow this command through if either:
* (a) it's a load/eject command (cmnd[4] & 2)
* (b) it's a multi-target unit (i.e. legacy SCSI adaptor)
*/
else
if
(
us
->
srb
->
cmnd
[
0
]
==
START_STOP
)
{
else
if
(
us
->
srb
->
cmnd
[
0
]
==
START_STOP
&&
!
(
us
->
srb
->
cmnd
[
4
]
&
2
)
&&
!
(
us
->
flags
&
US_FL_SCM_MULT_TARG
))
{
unsigned
char
saved_cdb
[
16
];
/* largest SCSI-III cmd */
__u8
old_cmd_len
;
...
...
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