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
5536b235
Commit
5536b235
authored
Oct 09, 2006
by
Ralf Baechle
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[MIPS] Alchemy: nuke usbdev; it's useless as is ...
Signed-off-by:
Ralf Baechle
<
ralf@linux-mips.org
>
parent
0118c3ca
Changes
11
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
9 additions
and
1662 deletions
+9
-1662
arch/mips/Kconfig
arch/mips/Kconfig
+0
-5
arch/mips/au1000/common/Makefile
arch/mips/au1000/common/Makefile
+0
-1
arch/mips/au1000/common/usbdev.c
arch/mips/au1000/common/usbdev.c
+0
-1552
arch/mips/au1000/db1x00/board_setup.c
arch/mips/au1000/db1x00/board_setup.c
+0
-5
arch/mips/au1000/mtx-1/board_setup.c
arch/mips/au1000/mtx-1/board_setup.c
+2
-6
arch/mips/au1000/pb1000/board_setup.c
arch/mips/au1000/pb1000/board_setup.c
+3
-7
arch/mips/au1000/pb1100/board_setup.c
arch/mips/au1000/pb1100/board_setup.c
+2
-4
arch/mips/au1000/pb1500/board_setup.c
arch/mips/au1000/pb1500/board_setup.c
+2
-7
arch/mips/configs/pb1100_defconfig
arch/mips/configs/pb1100_defconfig
+0
-1
arch/mips/configs/pb1500_defconfig
arch/mips/configs/pb1500_defconfig
+0
-1
include/asm-mips/mach-au1x00/au1000_usbdev.h
include/asm-mips/mach-au1x00/au1000_usbdev.h
+0
-73
No files found.
arch/mips/Kconfig
View file @
5536b235
...
...
@@ -1010,11 +1010,6 @@ endchoice
config ARC32
bool
config AU1X00_USB_DEVICE
bool
depends on MIPS_PB1500 || MIPS_PB1100 || MIPS_PB1000
default n
config BOOT_ELF32
bool
...
...
arch/mips/au1000/common/Makefile
View file @
5536b235
...
...
@@ -10,6 +10,5 @@ obj-y += prom.o irq.o puts.o time.o reset.o \
au1xxx_irqmap.o clocks.o platform.o power.o setup.o
\
sleeper.o cputable.o dma.o dbdma.o gpio.o
obj-$(CONFIG_AU1X00_USB_DEVICE)
+=
usbdev.o
obj-$(CONFIG_KGDB)
+=
dbg_io.o
obj-$(CONFIG_PCI)
+=
pci.o
arch/mips/au1000/common/usbdev.c
deleted
100644 → 0
View file @
0118c3ca
/*
* BRIEF MODULE DESCRIPTION
* Au1000 USB Device-Side (device layer)
*
* Copyright 2001-2002 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* stevel@mvista.com or source@mvista.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/smp_lock.h>
#define DEBUG
#include <linux/usb.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/mipsregs.h>
#include <asm/au1000.h>
#include <asm/au1000_dma.h>
#include <asm/au1000_usbdev.h>
#ifdef DEBUG
#undef VDEBUG
#ifdef VDEBUG
#define vdbg(fmt, arg...) printk(KERN_DEBUG __FILE__ ": " fmt "\n" , ## arg)
#else
#define vdbg(fmt, arg...) do {} while (0)
#endif
#else
#define vdbg(fmt, arg...) do {} while (0)
#endif
#define ALLOC_FLAGS (in_interrupt () ? GFP_ATOMIC : GFP_KERNEL)
#define EP_FIFO_DEPTH 8
typedef
enum
{
SETUP_STAGE
=
0
,
DATA_STAGE
,
STATUS_STAGE
}
ep0_stage_t
;
typedef
struct
{
int
read_fifo
;
int
write_fifo
;
int
ctrl_stat
;
int
read_fifo_status
;
int
write_fifo_status
;
}
endpoint_reg_t
;
typedef
struct
{
usbdev_pkt_t
*
head
;
usbdev_pkt_t
*
tail
;
int
count
;
}
pkt_list_t
;
typedef
struct
{
int
active
;
struct
usb_endpoint_descriptor
*
desc
;
endpoint_reg_t
*
reg
;
/* Only one of these are used, unless this is the control ep */
pkt_list_t
inlist
;
pkt_list_t
outlist
;
unsigned
int
indma
,
outdma
;
/* DMA channel numbers for IN, OUT */
/* following are extracted from endpoint descriptor for easy access */
int
max_pkt_size
;
int
type
;
int
direction
;
/* WE assign endpoint addresses! */
int
address
;
spinlock_t
lock
;
}
endpoint_t
;
static
struct
usb_dev
{
endpoint_t
ep
[
6
];
ep0_stage_t
ep0_stage
;
struct
usb_device_descriptor
*
dev_desc
;
struct
usb_interface_descriptor
*
if_desc
;
struct
usb_config_descriptor
*
conf_desc
;
u8
*
full_conf_desc
;
struct
usb_string_descriptor
*
str_desc
[
6
];
/* callback to function layer */
void
(
*
func_cb
)(
usbdev_cb_type_t
type
,
unsigned
long
arg
,
void
*
cb_data
);
void
*
cb_data
;
usbdev_state_t
state
;
// device state
int
suspended
;
// suspended flag
int
address
;
// device address
int
interface
;
int
num_ep
;
u8
alternate_setting
;
u8
configuration
;
// configuration value
int
remote_wakeup_en
;
}
usbdev
;
static
endpoint_reg_t
ep_reg
[]
=
{
// FIFO's 0 and 1 are EP0 default control
{
USBD_EP0RD
,
USBD_EP0WR
,
USBD_EP0CS
,
USBD_EP0RDSTAT
,
USBD_EP0WRSTAT
},
{
0
},
// FIFO 2 is EP2, IN
{
-
1
,
USBD_EP2WR
,
USBD_EP2CS
,
-
1
,
USBD_EP2WRSTAT
},
// FIFO 3 is EP3, IN
{
-
1
,
USBD_EP3WR
,
USBD_EP3CS
,
-
1
,
USBD_EP3WRSTAT
},
// FIFO 4 is EP4, OUT
{
USBD_EP4RD
,
-
1
,
USBD_EP4CS
,
USBD_EP4RDSTAT
,
-
1
},
// FIFO 5 is EP5, OUT
{
USBD_EP5RD
,
-
1
,
USBD_EP5CS
,
USBD_EP5RDSTAT
,
-
1
}
};
static
struct
{
unsigned
int
id
;
const
char
*
str
;
}
ep_dma_id
[]
=
{
{
DMA_ID_USBDEV_EP0_TX
,
"USBDev EP0 IN"
},
{
DMA_ID_USBDEV_EP0_RX
,
"USBDev EP0 OUT"
},
{
DMA_ID_USBDEV_EP2_TX
,
"USBDev EP2 IN"
},
{
DMA_ID_USBDEV_EP3_TX
,
"USBDev EP3 IN"
},
{
DMA_ID_USBDEV_EP4_RX
,
"USBDev EP4 OUT"
},
{
DMA_ID_USBDEV_EP5_RX
,
"USBDev EP5 OUT"
}
};
#define DIR_OUT 0
#define DIR_IN (1<<3)
#define CONTROL_EP USB_ENDPOINT_XFER_CONTROL
#define BULK_EP USB_ENDPOINT_XFER_BULK
static
inline
endpoint_t
*
epaddr_to_ep
(
struct
usb_dev
*
dev
,
int
ep_addr
)
{
if
(
ep_addr
>=
0
&&
ep_addr
<
2
)
return
&
dev
->
ep
[
0
];
if
(
ep_addr
<
6
)
return
&
dev
->
ep
[
ep_addr
];
return
NULL
;
}
static
const
char
*
std_req_name
[]
=
{
"GET_STATUS"
,
"CLEAR_FEATURE"
,
"RESERVED"
,
"SET_FEATURE"
,
"RESERVED"
,
"SET_ADDRESS"
,
"GET_DESCRIPTOR"
,
"SET_DESCRIPTOR"
,
"GET_CONFIGURATION"
,
"SET_CONFIGURATION"
,
"GET_INTERFACE"
,
"SET_INTERFACE"
,
"SYNCH_FRAME"
};
static
inline
const
char
*
get_std_req_name
(
int
req
)
{
return
(
req
>=
0
&&
req
<=
12
)
?
std_req_name
[
req
]
:
"UNKNOWN"
;
}
#if 0
static void
dump_setup(struct usb_ctrlrequest* s)
{
dbg("%s: requesttype=%d", __FUNCTION__, s->requesttype);
dbg("%s: request=%d %s", __FUNCTION__, s->request,
get_std_req_name(s->request));
dbg("%s: value=0x%04x", __FUNCTION__, s->wValue);
dbg("%s: index=%d", __FUNCTION__, s->index);
dbg("%s: length=%d", __FUNCTION__, s->length);
}
#endif
static
inline
usbdev_pkt_t
*
alloc_packet
(
endpoint_t
*
ep
,
int
data_size
,
void
*
data
)
{
usbdev_pkt_t
*
pkt
=
kmalloc
(
sizeof
(
usbdev_pkt_t
)
+
data_size
,
ALLOC_FLAGS
);
if
(
!
pkt
)
return
NULL
;
pkt
->
ep_addr
=
ep
->
address
;
pkt
->
size
=
data_size
;
pkt
->
status
=
0
;
pkt
->
next
=
NULL
;
if
(
data
)
memcpy
(
pkt
->
payload
,
data
,
data_size
);
return
pkt
;
}
/*
* Link a packet to the tail of the enpoint's packet list.
* EP spinlock must be held when calling.
*/
static
void
link_tail
(
endpoint_t
*
ep
,
pkt_list_t
*
list
,
usbdev_pkt_t
*
pkt
)
{
if
(
!
list
->
tail
)
{
list
->
head
=
list
->
tail
=
pkt
;
list
->
count
=
1
;
}
else
{
list
->
tail
->
next
=
pkt
;
list
->
tail
=
pkt
;
list
->
count
++
;
}
}
/*
* Unlink and return a packet from the head of the given packet
* list. It is the responsibility of the caller to free the packet.
* EP spinlock must be held when calling.
*/
static
usbdev_pkt_t
*
unlink_head
(
pkt_list_t
*
list
)
{
usbdev_pkt_t
*
pkt
;
pkt
=
list
->
head
;
if
(
!
pkt
||
!
list
->
count
)
{
return
NULL
;
}
list
->
head
=
pkt
->
next
;
if
(
!
list
->
head
)
{
list
->
head
=
list
->
tail
=
NULL
;
list
->
count
=
0
;
}
else
list
->
count
--
;
return
pkt
;
}
/*
* Create and attach a new packet to the tail of the enpoint's
* packet list. EP spinlock must be held when calling.
*/
static
usbdev_pkt_t
*
add_packet
(
endpoint_t
*
ep
,
pkt_list_t
*
list
,
int
size
)
{
usbdev_pkt_t
*
pkt
=
alloc_packet
(
ep
,
size
,
NULL
);
if
(
!
pkt
)
return
NULL
;
link_tail
(
ep
,
list
,
pkt
);
return
pkt
;
}
/*
* Unlink and free a packet from the head of the enpoint's
* packet list. EP spinlock must be held when calling.
*/
static
inline
void
free_packet
(
pkt_list_t
*
list
)
{
kfree
(
unlink_head
(
list
));
}
/* EP spinlock must be held when calling. */
static
inline
void
flush_pkt_list
(
pkt_list_t
*
list
)
{
while
(
list
->
count
)
free_packet
(
list
);
}
/* EP spinlock must be held when calling */
static
inline
void
flush_write_fifo
(
endpoint_t
*
ep
)
{
if
(
ep
->
reg
->
write_fifo_status
>=
0
)
{
au_writel
(
USBDEV_FSTAT_FLUSH
|
USBDEV_FSTAT_UF
|
USBDEV_FSTAT_OF
,
ep
->
reg
->
write_fifo_status
);
//udelay(100);
//au_writel(USBDEV_FSTAT_UF | USBDEV_FSTAT_OF,
// ep->reg->write_fifo_status);
}
}
/* EP spinlock must be held when calling */
static
inline
void
flush_read_fifo
(
endpoint_t
*
ep
)
{
if
(
ep
->
reg
->
read_fifo_status
>=
0
)
{
au_writel
(
USBDEV_FSTAT_FLUSH
|
USBDEV_FSTAT_UF
|
USBDEV_FSTAT_OF
,
ep
->
reg
->
read_fifo_status
);
//udelay(100);
//au_writel(USBDEV_FSTAT_UF | USBDEV_FSTAT_OF,
// ep->reg->read_fifo_status);
}
}
/* EP spinlock must be held when calling. */
static
void
endpoint_flush
(
endpoint_t
*
ep
)
{
// First, flush all packets
flush_pkt_list
(
&
ep
->
inlist
);
flush_pkt_list
(
&
ep
->
outlist
);
// Now flush the endpoint's h/w FIFO(s)
flush_write_fifo
(
ep
);
flush_read_fifo
(
ep
);
}
/* EP spinlock must be held when calling. */
static
void
endpoint_stall
(
endpoint_t
*
ep
)
{
u32
cs
;
warn
(
"%s"
,
__FUNCTION__
);
cs
=
au_readl
(
ep
->
reg
->
ctrl_stat
)
|
USBDEV_CS_STALL
;
au_writel
(
cs
,
ep
->
reg
->
ctrl_stat
);
}
/* EP spinlock must be held when calling. */
static
void
endpoint_unstall
(
endpoint_t
*
ep
)
{
u32
cs
;
warn
(
"%s"
,
__FUNCTION__
);
cs
=
au_readl
(
ep
->
reg
->
ctrl_stat
)
&
~
USBDEV_CS_STALL
;
au_writel
(
cs
,
ep
->
reg
->
ctrl_stat
);
}
static
void
endpoint_reset_datatoggle
(
endpoint_t
*
ep
)
{
// FIXME: is this possible?
}
/* EP spinlock must be held when calling. */
static
int
endpoint_fifo_read
(
endpoint_t
*
ep
)
{
int
read_count
=
0
;
u8
*
bufptr
;
usbdev_pkt_t
*
pkt
=
ep
->
outlist
.
tail
;
if
(
!
pkt
)
return
-
EINVAL
;
bufptr
=
&
pkt
->
payload
[
pkt
->
size
];
while
(
au_readl
(
ep
->
reg
->
read_fifo_status
)
&
USBDEV_FSTAT_FCNT_MASK
)
{
*
bufptr
++
=
au_readl
(
ep
->
reg
->
read_fifo
)
&
0xff
;
read_count
++
;
pkt
->
size
++
;
}
return
read_count
;
}
#if 0
/* EP spinlock must be held when calling. */
static int
endpoint_fifo_write(endpoint_t * ep, int index)
{
int write_count = 0;
u8 *bufptr;
usbdev_pkt_t *pkt = ep->inlist.head;
if (!pkt)
return -EINVAL;
bufptr = &pkt->payload[index];
while ((au_readl(ep->reg->write_fifo_status) &
USBDEV_FSTAT_FCNT_MASK) < EP_FIFO_DEPTH) {
if (bufptr < pkt->payload + pkt->size) {
au_writel(*bufptr++, ep->reg->write_fifo);
write_count++;
} else {
break;
}
}
return write_count;
}
#endif
/*
* This routine is called to restart transmission of a packet.
* The endpoint's TSIZE must be set to the new packet's size,
* and DMA to the write FIFO needs to be restarted.
* EP spinlock must be held when calling.
*/
static
void
kickstart_send_packet
(
endpoint_t
*
ep
)
{
u32
cs
;
usbdev_pkt_t
*
pkt
=
ep
->
inlist
.
head
;
vdbg
(
"%s: ep%d, pkt=%p"
,
__FUNCTION__
,
ep
->
address
,
pkt
);
if
(
!
pkt
)
{
err
(
"%s: head=NULL! list->count=%d"
,
__FUNCTION__
,
ep
->
inlist
.
count
);
return
;
}
dma_cache_wback_inv
((
unsigned
long
)
pkt
->
payload
,
pkt
->
size
);
/*
* make sure FIFO is empty
*/
flush_write_fifo
(
ep
);
cs
=
au_readl
(
ep
->
reg
->
ctrl_stat
)
&
USBDEV_CS_STALL
;
cs
|=
(
pkt
->
size
<<
USBDEV_CS_TSIZE_BIT
);
au_writel
(
cs
,
ep
->
reg
->
ctrl_stat
);
if
(
get_dma_active_buffer
(
ep
->
indma
)
==
1
)
{
set_dma_count1
(
ep
->
indma
,
pkt
->
size
);
set_dma_addr1
(
ep
->
indma
,
virt_to_phys
(
pkt
->
payload
));
enable_dma_buffer1
(
ep
->
indma
);
// reenable
}
else
{
set_dma_count0
(
ep
->
indma
,
pkt
->
size
);
set_dma_addr0
(
ep
->
indma
,
virt_to_phys
(
pkt
->
payload
));
enable_dma_buffer0
(
ep
->
indma
);
// reenable
}
if
(
dma_halted
(
ep
->
indma
))
start_dma
(
ep
->
indma
);
}
/*
* This routine is called when a packet in the inlist has been
* completed. Frees the completed packet and starts sending the
* next. EP spinlock must be held when calling.
*/
static
usbdev_pkt_t
*
send_packet_complete
(
endpoint_t
*
ep
)
{
usbdev_pkt_t
*
pkt
=
unlink_head
(
&
ep
->
inlist
);
if
(
pkt
)
{
pkt
->
status
=
(
au_readl
(
ep
->
reg
->
ctrl_stat
)
&
USBDEV_CS_NAK
)
?
PKT_STATUS_NAK
:
PKT_STATUS_ACK
;
vdbg
(
"%s: ep%d, %s pkt=%p, list count=%d"
,
__FUNCTION__
,
ep
->
address
,
(
pkt
->
status
&
PKT_STATUS_NAK
)
?
"NAK"
:
"ACK"
,
pkt
,
ep
->
inlist
.
count
);
}
/*
* The write fifo should already be drained if things are
* working right, but flush it anyway just in case.
*/
flush_write_fifo
(
ep
);
// begin transmitting next packet in the inlist
if
(
ep
->
inlist
.
count
)
{
kickstart_send_packet
(
ep
);
}
return
pkt
;
}
/*
* Add a new packet to the tail of the given ep's packet
* inlist. The transmit complete interrupt frees packets from
* the head of this list. EP spinlock must be held when calling.
*/
static
int
send_packet
(
struct
usb_dev
*
dev
,
usbdev_pkt_t
*
pkt
,
int
async
)
{
pkt_list_t
*
list
;
endpoint_t
*
ep
;
if
(
!
pkt
||
!
(
ep
=
epaddr_to_ep
(
dev
,
pkt
->
ep_addr
)))
return
-
EINVAL
;
if
(
!
pkt
->
size
)
return
0
;
list
=
&
ep
->
inlist
;
if
(
!
async
&&
list
->
count
)
{
halt_dma
(
ep
->
indma
);
flush_pkt_list
(
list
);
}
link_tail
(
ep
,
list
,
pkt
);
vdbg
(
"%s: ep%d, pkt=%p, size=%d, list count=%d"
,
__FUNCTION__
,
ep
->
address
,
pkt
,
pkt
->
size
,
list
->
count
);
if
(
list
->
count
==
1
)
{
/*
* if the packet count is one, it means the list was empty,
* and no more data will go out this ep until we kick-start
* it again.
*/
kickstart_send_packet
(
ep
);
}
return
pkt
->
size
;
}
/*
* This routine is called to restart reception of a packet.
* EP spinlock must be held when calling.
*/
static
void
kickstart_receive_packet
(
endpoint_t
*
ep
)
{
usbdev_pkt_t
*
pkt
;
// get and link a new packet for next reception
if
(
!
(
pkt
=
add_packet
(
ep
,
&
ep
->
outlist
,
ep
->
max_pkt_size
)))
{
err
(
"%s: could not alloc new packet"
,
__FUNCTION__
);
return
;
}
if
(
get_dma_active_buffer
(
ep
->
outdma
)
==
1
)
{
clear_dma_done1
(
ep
->
outdma
);
set_dma_count1
(
ep
->
outdma
,
ep
->
max_pkt_size
);
set_dma_count0
(
ep
->
outdma
,
0
);
set_dma_addr1
(
ep
->
outdma
,
virt_to_phys
(
pkt
->
payload
));
enable_dma_buffer1
(
ep
->
outdma
);
// reenable
}
else
{
clear_dma_done0
(
ep
->
outdma
);
set_dma_count0
(
ep
->
outdma
,
ep
->
max_pkt_size
);
set_dma_count1
(
ep
->
outdma
,
0
);
set_dma_addr0
(
ep
->
outdma
,
virt_to_phys
(
pkt
->
payload
));
enable_dma_buffer0
(
ep
->
outdma
);
// reenable
}
if
(
dma_halted
(
ep
->
outdma
))
start_dma
(
ep
->
outdma
);
}
/*
* This routine is called when a packet in the outlist has been
* completed (received) and we need to prepare for a new packet
* to be received. Halts DMA and computes the packet size from the
* remaining DMA counter. Then prepares a new packet for reception
* and restarts DMA. FIXME: what if another packet comes in
* on top of the completed packet? Counter would be wrong.
* EP spinlock must be held when calling.
*/
static
usbdev_pkt_t
*
receive_packet_complete
(
endpoint_t
*
ep
)
{
usbdev_pkt_t
*
pkt
=
ep
->
outlist
.
tail
;
u32
cs
;
halt_dma
(
ep
->
outdma
);
cs
=
au_readl
(
ep
->
reg
->
ctrl_stat
);
if
(
!
pkt
)
return
NULL
;
pkt
->
size
=
ep
->
max_pkt_size
-
get_dma_residue
(
ep
->
outdma
);
if
(
pkt
->
size
)
dma_cache_inv
((
unsigned
long
)
pkt
->
payload
,
pkt
->
size
);
/*
* need to pull out any remaining bytes in the FIFO.
*/
endpoint_fifo_read
(
ep
);
/*
* should be drained now, but flush anyway just in case.
*/
flush_read_fifo
(
ep
);
pkt
->
status
=
(
cs
&
USBDEV_CS_NAK
)
?
PKT_STATUS_NAK
:
PKT_STATUS_ACK
;
if
(
ep
->
address
==
0
&&
(
cs
&
USBDEV_CS_SU
))
pkt
->
status
|=
PKT_STATUS_SU
;
vdbg
(
"%s: ep%d, %s pkt=%p, size=%d"
,
__FUNCTION__
,
ep
->
address
,
(
pkt
->
status
&
PKT_STATUS_NAK
)
?
"NAK"
:
"ACK"
,
pkt
,
pkt
->
size
);
kickstart_receive_packet
(
ep
);
return
pkt
;
}
/*
****************************************************************************
* Here starts the standard device request handlers. They are
* all called by do_setup() via a table of function pointers.
****************************************************************************
*/
static
ep0_stage_t
do_get_status
(
struct
usb_dev
*
dev
,
struct
usb_ctrlrequest
*
setup
)
{
switch
(
setup
->
bRequestType
)
{
case
0x80
:
// Device
// FIXME: send device status
break
;
case
0x81
:
// Interface
// FIXME: send interface status
break
;
case
0x82
:
// End Point
// FIXME: send endpoint status
break
;
default:
// Invalid Command
endpoint_stall
(
&
dev
->
ep
[
0
]);
// Stall End Point 0
break
;
}
return
STATUS_STAGE
;
}
static
ep0_stage_t
do_clear_feature
(
struct
usb_dev
*
dev
,
struct
usb_ctrlrequest
*
setup
)
{
switch
(
setup
->
bRequestType
)
{
case
0x00
:
// Device
if
((
le16_to_cpu
(
setup
->
wValue
)
&
0xff
)
==
1
)
dev
->
remote_wakeup_en
=
0
;
else
endpoint_stall
(
&
dev
->
ep
[
0
]);
break
;
case
0x02
:
// End Point
if
((
le16_to_cpu
(
setup
->
wValue
)
&
0xff
)
==
0
)
{
endpoint_t
*
ep
=
epaddr_to_ep
(
dev
,
le16_to_cpu
(
setup
->
wIndex
)
&
0xff
);
endpoint_unstall
(
ep
);
endpoint_reset_datatoggle
(
ep
);
}
else
endpoint_stall
(
&
dev
->
ep
[
0
]);
break
;
}
return
SETUP_STAGE
;
}
static
ep0_stage_t
do_reserved
(
struct
usb_dev
*
dev
,
struct
usb_ctrlrequest
*
setup
)
{
// Invalid request, stall End Point 0
endpoint_stall
(
&
dev
->
ep
[
0
]);
return
SETUP_STAGE
;
}
static
ep0_stage_t
do_set_feature
(
struct
usb_dev
*
dev
,
struct
usb_ctrlrequest
*
setup
)
{
switch
(
setup
->
bRequestType
)
{
case
0x00
:
// Device
if
((
le16_to_cpu
(
setup
->
wValue
)
&
0xff
)
==
1
)
dev
->
remote_wakeup_en
=
1
;
else
endpoint_stall
(
&
dev
->
ep
[
0
]);
break
;
case
0x02
:
// End Point
if
((
le16_to_cpu
(
setup
->
wValue
)
&
0xff
)
==
0
)
{
endpoint_t
*
ep
=
epaddr_to_ep
(
dev
,
le16_to_cpu
(
setup
->
wIndex
)
&
0xff
);
endpoint_stall
(
ep
);
}
else
endpoint_stall
(
&
dev
->
ep
[
0
]);
break
;
}
return
SETUP_STAGE
;
}
static
ep0_stage_t
do_set_address
(
struct
usb_dev
*
dev
,
struct
usb_ctrlrequest
*
setup
)
{
int
new_state
=
dev
->
state
;
int
new_addr
=
le16_to_cpu
(
setup
->
wValue
);
dbg
(
"%s: our address=%d"
,
__FUNCTION__
,
new_addr
);
if
(
new_addr
>
127
)
{
// usb spec doesn't tell us what to do, so just go to
// default state
new_state
=
DEFAULT
;
dev
->
address
=
0
;
}
else
if
(
dev
->
address
!=
new_addr
)
{
dev
->
address
=
new_addr
;
new_state
=
ADDRESS
;
}
if
(
dev
->
state
!=
new_state
)
{
dev
->
state
=
new_state
;
/* inform function layer of usbdev state change */
dev
->
func_cb
(
CB_NEW_STATE
,
dev
->
state
,
dev
->
cb_data
);
}
return
SETUP_STAGE
;
}
static
ep0_stage_t
do_get_descriptor
(
struct
usb_dev
*
dev
,
struct
usb_ctrlrequest
*
setup
)
{
int
strnum
,
desc_len
=
le16_to_cpu
(
setup
->
wLength
);
switch
(
le16_to_cpu
(
setup
->
wValue
)
>>
8
)
{
case
USB_DT_DEVICE
:
// send device descriptor!
desc_len
=
desc_len
>
dev
->
dev_desc
->
bLength
?
dev
->
dev_desc
->
bLength
:
desc_len
;
dbg
(
"sending device desc, size=%d"
,
desc_len
);
send_packet
(
dev
,
alloc_packet
(
&
dev
->
ep
[
0
],
desc_len
,
dev
->
dev_desc
),
0
);
break
;
case
USB_DT_CONFIG
:
// If the config descr index in low-byte of
// setup->wValue is valid, send config descr,
// otherwise stall ep0.
if
((
le16_to_cpu
(
setup
->
wValue
)
&
0xff
)
==
0
)
{
// send config descriptor!
if
(
desc_len
<=
USB_DT_CONFIG_SIZE
)
{
dbg
(
"sending partial config desc, size=%d"
,
desc_len
);
send_packet
(
dev
,
alloc_packet
(
&
dev
->
ep
[
0
],
desc_len
,
dev
->
conf_desc
),
0
);
}
else
{
int
len
=
le16_to_cpu
(
dev
->
conf_desc
->
wTotalLength
);
dbg
(
"sending whole config desc,"
" size=%d, our size=%d"
,
desc_len
,
len
);
desc_len
=
desc_len
>
len
?
len
:
desc_len
;
send_packet
(
dev
,
alloc_packet
(
&
dev
->
ep
[
0
],
desc_len
,
dev
->
full_conf_desc
),
0
);
}
}
else
endpoint_stall
(
&
dev
->
ep
[
0
]);
break
;
case
USB_DT_STRING
:
// If the string descr index in low-byte of setup->wValue
// is valid, send string descr, otherwise stall ep0.
strnum
=
le16_to_cpu
(
setup
->
wValue
)
&
0xff
;
if
(
strnum
>=
0
&&
strnum
<
6
)
{
struct
usb_string_descriptor
*
desc
=
dev
->
str_desc
[
strnum
];
desc_len
=
desc_len
>
desc
->
bLength
?
desc
->
bLength
:
desc_len
;
dbg
(
"sending string desc %d"
,
strnum
);
send_packet
(
dev
,
alloc_packet
(
&
dev
->
ep
[
0
],
desc_len
,
desc
),
0
);
}
else
endpoint_stall
(
&
dev
->
ep
[
0
]);
break
;
default:
// Invalid request
err
(
"invalid get desc=%d, stalled"
,
le16_to_cpu
(
setup
->
wValue
)
>>
8
);
endpoint_stall
(
&
dev
->
ep
[
0
]);
// Stall endpoint 0
break
;
}
return
STATUS_STAGE
;
}
static
ep0_stage_t
do_set_descriptor
(
struct
usb_dev
*
dev
,
struct
usb_ctrlrequest
*
setup
)
{
// TODO: implement
// there will be an OUT data stage (the descriptor to set)
return
DATA_STAGE
;
}
static
ep0_stage_t
do_get_configuration
(
struct
usb_dev
*
dev
,
struct
usb_ctrlrequest
*
setup
)
{
// send dev->configuration
dbg
(
"sending config"
);
send_packet
(
dev
,
alloc_packet
(
&
dev
->
ep
[
0
],
1
,
&
dev
->
configuration
),
0
);
return
STATUS_STAGE
;
}
static
ep0_stage_t
do_set_configuration
(
struct
usb_dev
*
dev
,
struct
usb_ctrlrequest
*
setup
)
{
// set active config to low-byte of setup->wValue
dev
->
configuration
=
le16_to_cpu
(
setup
->
wValue
)
&
0xff
;
dbg
(
"set config, config=%d"
,
dev
->
configuration
);
if
(
!
dev
->
configuration
&&
dev
->
state
>
DEFAULT
)
{
dev
->
state
=
ADDRESS
;
/* inform function layer of usbdev state change */
dev
->
func_cb
(
CB_NEW_STATE
,
dev
->
state
,
dev
->
cb_data
);
}
else
if
(
dev
->
configuration
==
1
)
{
dev
->
state
=
CONFIGURED
;
/* inform function layer of usbdev state change */
dev
->
func_cb
(
CB_NEW_STATE
,
dev
->
state
,
dev
->
cb_data
);
}
else
{
// FIXME: "respond with request error" - how?
}
return
SETUP_STAGE
;
}
static
ep0_stage_t
do_get_interface
(
struct
usb_dev
*
dev
,
struct
usb_ctrlrequest
*
setup
)
{
// interface must be zero.
if
((
le16_to_cpu
(
setup
->
wIndex
)
&
0xff
)
||
dev
->
state
==
ADDRESS
)
{
// FIXME: respond with "request error". how?
}
else
if
(
dev
->
state
==
CONFIGURED
)
{
// send dev->alternate_setting
dbg
(
"sending alt setting"
);
send_packet
(
dev
,
alloc_packet
(
&
dev
->
ep
[
0
],
1
,
&
dev
->
alternate_setting
),
0
);
}
return
STATUS_STAGE
;
}
static
ep0_stage_t
do_set_interface
(
struct
usb_dev
*
dev
,
struct
usb_ctrlrequest
*
setup
)
{
if
(
dev
->
state
==
ADDRESS
)
{
// FIXME: respond with "request error". how?
}
else
if
(
dev
->
state
==
CONFIGURED
)
{
dev
->
interface
=
le16_to_cpu
(
setup
->
wIndex
)
&
0xff
;
dev
->
alternate_setting
=
le16_to_cpu
(
setup
->
wValue
)
&
0xff
;
// interface and alternate_setting must be zero
if
(
dev
->
interface
||
dev
->
alternate_setting
)
{
// FIXME: respond with "request error". how?
}
}
return
SETUP_STAGE
;
}
static
ep0_stage_t
do_synch_frame
(
struct
usb_dev
*
dev
,
struct
usb_ctrlrequest
*
setup
)
{
// TODO
return
SETUP_STAGE
;
}
typedef
ep0_stage_t
(
*
req_method_t
)(
struct
usb_dev
*
dev
,
struct
usb_ctrlrequest
*
setup
);
/* Table of the standard device request handlers */
static
const
req_method_t
req_method
[]
=
{
do_get_status
,
do_clear_feature
,
do_reserved
,
do_set_feature
,
do_reserved
,
do_set_address
,
do_get_descriptor
,
do_set_descriptor
,
do_get_configuration
,
do_set_configuration
,
do_get_interface
,
do_set_interface
,
do_synch_frame
};
// SETUP packet request dispatcher
static
void
do_setup
(
struct
usb_dev
*
dev
,
struct
usb_ctrlrequest
*
setup
)
{
req_method_t
m
;
dbg
(
"%s: req %d %s"
,
__FUNCTION__
,
setup
->
bRequestType
,
get_std_req_name
(
setup
->
bRequestType
));
if
((
setup
->
bRequestType
&
USB_TYPE_MASK
)
!=
USB_TYPE_STANDARD
||
(
setup
->
bRequestType
&
USB_RECIP_MASK
)
!=
USB_RECIP_DEVICE
)
{
err
(
"%s: invalid requesttype 0x%02x"
,
__FUNCTION__
,
setup
->
bRequestType
);
return
;
}
if
((
setup
->
bRequestType
&
0x80
)
==
USB_DIR_OUT
&&
setup
->
wLength
)
dbg
(
"%s: OUT phase! length=%d"
,
__FUNCTION__
,
setup
->
wLength
);
if
(
setup
->
bRequestType
<
sizeof
(
req_method
)
/
sizeof
(
req_method_t
))
m
=
req_method
[
setup
->
bRequestType
];
else
m
=
do_reserved
;
dev
->
ep0_stage
=
(
*
m
)(
dev
,
setup
);
}
/*
* A SETUP, DATA0, or DATA1 packet has been received
* on the default control endpoint's fifo.
*/
static
void
process_ep0_receive
(
struct
usb_dev
*
dev
)
{
endpoint_t
*
ep0
=
&
dev
->
ep
[
0
];
usbdev_pkt_t
*
pkt
;
spin_lock
(
&
ep0
->
lock
);
// complete packet and prepare a new packet
pkt
=
receive_packet_complete
(
ep0
);
if
(
!
pkt
)
{
// FIXME: should put a warn/err here.
spin_unlock
(
&
ep0
->
lock
);
return
;
}
// unlink immediately from endpoint.
unlink_head
(
&
ep0
->
outlist
);
// override current stage if h/w says it's a setup packet
if
(
pkt
->
status
&
PKT_STATUS_SU
)
dev
->
ep0_stage
=
SETUP_STAGE
;
switch
(
dev
->
ep0_stage
)
{
case
SETUP_STAGE
:
vdbg
(
"SU bit is %s in setup stage"
,
(
pkt
->
status
&
PKT_STATUS_SU
)
?
"set"
:
"not set"
);
if
(
pkt
->
size
==
sizeof
(
struct
usb_ctrlrequest
))
{
#ifdef VDEBUG
if
(
pkt
->
status
&
PKT_STATUS_ACK
)
vdbg
(
"received SETUP"
);
else
vdbg
(
"received NAK SETUP"
);
#endif
do_setup
(
dev
,
(
struct
usb_ctrlrequest
*
)
pkt
->
payload
);
}
else
err
(
"%s: wrong size SETUP received"
,
__FUNCTION__
);
break
;
case
DATA_STAGE
:
/*
* this setup has an OUT data stage. Of the standard
* device requests, only set_descriptor has this stage,
* so this packet is that descriptor. TODO: drop it for
* now, set_descriptor not implemented.
*
* Need to place a byte in the write FIFO here, to prepare
* to send a zero-length DATA ack packet to the host in the
* STATUS stage.
*/
au_writel
(
0
,
ep0
->
reg
->
write_fifo
);
dbg
(
"received OUT stage DATAx on EP0, size=%d"
,
pkt
->
size
);
dev
->
ep0_stage
=
SETUP_STAGE
;
break
;
case
STATUS_STAGE
:
// this setup had an IN data stage, and host is ACK'ing
// the packet we sent during that stage.
if
(
pkt
->
size
!=
0
)
warn
(
"received non-zero ACK on EP0??"
);
#ifdef VDEBUG
else
vdbg
(
"received ACK on EP0"
);
#endif
dev
->
ep0_stage
=
SETUP_STAGE
;
break
;
}
spin_unlock
(
&
ep0
->
lock
);
// we're done processing the packet, free it
kfree
(
pkt
);
}
/*
* A DATA0/1 packet has been received on one of the OUT endpoints (4 or 5)
*/
static
void
process_ep_receive
(
struct
usb_dev
*
dev
,
endpoint_t
*
ep
)
{
usbdev_pkt_t
*
pkt
;
spin_lock
(
&
ep
->
lock
);
pkt
=
receive_packet_complete
(
ep
);
spin_unlock
(
&
ep
->
lock
);
dev
->
func_cb
(
CB_PKT_COMPLETE
,
(
unsigned
long
)
pkt
,
dev
->
cb_data
);
}
/* This ISR handles the receive complete and suspend events */
static
void
req_sus_intr
(
int
irq
,
void
*
dev_id
)
{
struct
usb_dev
*
dev
=
(
struct
usb_dev
*
)
dev_id
;
u32
status
;
status
=
au_readl
(
USBD_INTSTAT
);
au_writel
(
status
,
USBD_INTSTAT
);
// ack'em
if
(
status
&
(
1
<<
0
))
process_ep0_receive
(
dev
);
if
(
status
&
(
1
<<
4
))
process_ep_receive
(
dev
,
&
dev
->
ep
[
4
]);
if
(
status
&
(
1
<<
5
))
process_ep_receive
(
dev
,
&
dev
->
ep
[
5
]);
}
/* This ISR handles the DMA done events on EP0 */
static
void
dma_done_ep0_intr
(
int
irq
,
void
*
dev_id
)
{
struct
usb_dev
*
dev
=
(
struct
usb_dev
*
)
dev_id
;
usbdev_pkt_t
*
pkt
;
endpoint_t
*
ep0
=
&
dev
->
ep
[
0
];
u32
cs0
,
buff_done
;
spin_lock
(
&
ep0
->
lock
);
cs0
=
au_readl
(
ep0
->
reg
->
ctrl_stat
);
// first check packet transmit done
if
((
buff_done
=
get_dma_buffer_done
(
ep0
->
indma
))
!=
0
)
{
// transmitted a DATAx packet during DATA stage
// on control endpoint 0
// clear DMA done bit
if
(
buff_done
&
DMA_D0
)
clear_dma_done0
(
ep0
->
indma
);
if
(
buff_done
&
DMA_D1
)
clear_dma_done1
(
ep0
->
indma
);
pkt
=
send_packet_complete
(
ep0
);
kfree
(
pkt
);
}
/*
* Now check packet receive done. Shouldn't get these,
* the receive packet complete intr should happen
* before the DMA done intr occurs.
*/
if
((
buff_done
=
get_dma_buffer_done
(
ep0
->
outdma
))
!=
0
)
{
// clear DMA done bit
if
(
buff_done
&
DMA_D0
)
clear_dma_done0
(
ep0
->
outdma
);
if
(
buff_done
&
DMA_D1
)
clear_dma_done1
(
ep0
->
outdma
);
//process_ep0_receive(dev);
}
spin_unlock
(
&
ep0
->
lock
);
}
/* This ISR handles the DMA done events on endpoints 2,3,4,5 */
static
void
dma_done_ep_intr
(
int
irq
,
void
*
dev_id
)
{
struct
usb_dev
*
dev
=
(
struct
usb_dev
*
)
dev_id
;
int
i
;
for
(
i
=
2
;
i
<
6
;
i
++
)
{
u32
buff_done
;
usbdev_pkt_t
*
pkt
;
endpoint_t
*
ep
=
&
dev
->
ep
[
i
];
if
(
!
ep
->
active
)
continue
;
spin_lock
(
&
ep
->
lock
);
if
(
ep
->
direction
==
USB_DIR_IN
)
{
buff_done
=
get_dma_buffer_done
(
ep
->
indma
);
if
(
buff_done
!=
0
)
{
// transmitted a DATAx pkt on the IN ep
// clear DMA done bit
if
(
buff_done
&
DMA_D0
)
clear_dma_done0
(
ep
->
indma
);
if
(
buff_done
&
DMA_D1
)
clear_dma_done1
(
ep
->
indma
);
pkt
=
send_packet_complete
(
ep
);
spin_unlock
(
&
ep
->
lock
);
dev
->
func_cb
(
CB_PKT_COMPLETE
,
(
unsigned
long
)
pkt
,
dev
->
cb_data
);
spin_lock
(
&
ep
->
lock
);
}
}
else
{
/*
* Check packet receive done (OUT ep). Shouldn't get
* these, the rx packet complete intr should happen
* before the DMA done intr occurs.
*/
buff_done
=
get_dma_buffer_done
(
ep
->
outdma
);
if
(
buff_done
!=
0
)
{
// received a DATAx pkt on the OUT ep
// clear DMA done bit
if
(
buff_done
&
DMA_D0
)
clear_dma_done0
(
ep
->
outdma
);
if
(
buff_done
&
DMA_D1
)
clear_dma_done1
(
ep
->
outdma
);
//process_ep_receive(dev, ep);
}
}
spin_unlock
(
&
ep
->
lock
);
}
}
/***************************************************************************
* Here begins the external interface functions
***************************************************************************
*/
/*
* allocate a new packet
*/
int
usbdev_alloc_packet
(
int
ep_addr
,
int
data_size
,
usbdev_pkt_t
**
pkt
)
{
endpoint_t
*
ep
=
epaddr_to_ep
(
&
usbdev
,
ep_addr
);
usbdev_pkt_t
*
lpkt
=
NULL
;
if
(
!
ep
||
!
ep
->
active
||
ep
->
address
<
2
)
return
-
ENODEV
;
if
(
data_size
>
ep
->
max_pkt_size
)
return
-
EINVAL
;
lpkt
=
*
pkt
=
alloc_packet
(
ep
,
data_size
,
NULL
);
if
(
!
lpkt
)
return
-
ENOMEM
;
return
0
;
}
/*
* packet send
*/
int
usbdev_send_packet
(
int
ep_addr
,
usbdev_pkt_t
*
pkt
)
{
unsigned
long
flags
;
int
count
;
endpoint_t
*
ep
;
if
(
!
pkt
||
!
(
ep
=
epaddr_to_ep
(
&
usbdev
,
pkt
->
ep_addr
))
||
!
ep
->
active
||
ep
->
address
<
2
)
return
-
ENODEV
;
if
(
ep
->
direction
!=
USB_DIR_IN
)
return
-
EINVAL
;
spin_lock_irqsave
(
&
ep
->
lock
,
flags
);
count
=
send_packet
(
&
usbdev
,
pkt
,
1
);
spin_unlock_irqrestore
(
&
ep
->
lock
,
flags
);
return
count
;
}
/*
* packet receive
*/
int
usbdev_receive_packet
(
int
ep_addr
,
usbdev_pkt_t
**
pkt
)
{
unsigned
long
flags
;
usbdev_pkt_t
*
lpkt
=
NULL
;
endpoint_t
*
ep
=
epaddr_to_ep
(
&
usbdev
,
ep_addr
);
if
(
!
ep
||
!
ep
->
active
||
ep
->
address
<
2
)
return
-
ENODEV
;
if
(
ep
->
direction
!=
USB_DIR_OUT
)
return
-
EINVAL
;
spin_lock_irqsave
(
&
ep
->
lock
,
flags
);
if
(
ep
->
outlist
.
count
>
1
)
lpkt
=
unlink_head
(
&
ep
->
outlist
);
spin_unlock_irqrestore
(
&
ep
->
lock
,
flags
);
if
(
!
lpkt
)
{
/* no packet available */
*
pkt
=
NULL
;
return
-
ENODATA
;
}
*
pkt
=
lpkt
;
return
lpkt
->
size
;
}
/*
* return total queued byte count on the endpoint.
*/
int
usbdev_get_byte_count
(
int
ep_addr
)
{
unsigned
long
flags
;
pkt_list_t
*
list
;
usbdev_pkt_t
*
scan
;
int
count
=
0
;
endpoint_t
*
ep
=
epaddr_to_ep
(
&
usbdev
,
ep_addr
);
if
(
!
ep
||
!
ep
->
active
||
ep
->
address
<
2
)
return
-
ENODEV
;
if
(
ep
->
direction
==
USB_DIR_IN
)
{
list
=
&
ep
->
inlist
;
spin_lock_irqsave
(
&
ep
->
lock
,
flags
);
for
(
scan
=
list
->
head
;
scan
;
scan
=
scan
->
next
)
count
+=
scan
->
size
;
spin_unlock_irqrestore
(
&
ep
->
lock
,
flags
);
}
else
{
list
=
&
ep
->
outlist
;
spin_lock_irqsave
(
&
ep
->
lock
,
flags
);
if
(
list
->
count
>
1
)
{
for
(
scan
=
list
->
head
;
scan
!=
list
->
tail
;
scan
=
scan
->
next
)
count
+=
scan
->
size
;
}
spin_unlock_irqrestore
(
&
ep
->
lock
,
flags
);
}
return
count
;
}
void
usbdev_exit
(
void
)
{
endpoint_t
*
ep
;
int
i
;
au_writel
(
0
,
USBD_INTEN
);
// disable usb dev ints
au_writel
(
0
,
USBD_ENABLE
);
// disable usb dev
free_irq
(
AU1000_USB_DEV_REQ_INT
,
&
usbdev
);
free_irq
(
AU1000_USB_DEV_SUS_INT
,
&
usbdev
);
// free all control endpoint resources
ep
=
&
usbdev
.
ep
[
0
];
free_au1000_dma
(
ep
->
indma
);
free_au1000_dma
(
ep
->
outdma
);
endpoint_flush
(
ep
);
// free ep resources
for
(
i
=
2
;
i
<
6
;
i
++
)
{
ep
=
&
usbdev
.
ep
[
i
];
if
(
!
ep
->
active
)
continue
;
if
(
ep
->
direction
==
USB_DIR_IN
)
{
free_au1000_dma
(
ep
->
indma
);
}
else
{
free_au1000_dma
(
ep
->
outdma
);
}
endpoint_flush
(
ep
);
}
kfree
(
usbdev
.
full_conf_desc
);
}
int
usbdev_init
(
struct
usb_device_descriptor
*
dev_desc
,
struct
usb_config_descriptor
*
config_desc
,
struct
usb_interface_descriptor
*
if_desc
,
struct
usb_endpoint_descriptor
*
ep_desc
,
struct
usb_string_descriptor
*
str_desc
[],
void
(
*
cb
)(
usbdev_cb_type_t
,
unsigned
long
,
void
*
),
void
*
cb_data
)
{
endpoint_t
*
ep0
;
int
i
,
ret
=
0
;
u8
*
fcd
;
if
(
dev_desc
->
bNumConfigurations
>
1
||
config_desc
->
bNumInterfaces
>
1
||
if_desc
->
bNumEndpoints
>
4
)
{
err
(
"Only one config, one i/f, and no more "
"than 4 ep's allowed"
);
ret
=
-
EINVAL
;
goto
out
;
}
if
(
!
cb
)
{
err
(
"Function-layer callback required"
);
ret
=
-
EINVAL
;
goto
out
;
}
if
(
dev_desc
->
bMaxPacketSize0
!=
USBDEV_EP0_MAX_PACKET_SIZE
)
{
warn
(
"EP0 Max Packet size must be %d"
,
USBDEV_EP0_MAX_PACKET_SIZE
);
dev_desc
->
bMaxPacketSize0
=
USBDEV_EP0_MAX_PACKET_SIZE
;
}
memset
(
&
usbdev
,
0
,
sizeof
(
struct
usb_dev
));
usbdev
.
state
=
DEFAULT
;
usbdev
.
dev_desc
=
dev_desc
;
usbdev
.
if_desc
=
if_desc
;
usbdev
.
conf_desc
=
config_desc
;
for
(
i
=
0
;
i
<
6
;
i
++
)
usbdev
.
str_desc
[
i
]
=
str_desc
[
i
];
usbdev
.
func_cb
=
cb
;
usbdev
.
cb_data
=
cb_data
;
/* Initialize default control endpoint */
ep0
=
&
usbdev
.
ep
[
0
];
ep0
->
active
=
1
;
ep0
->
type
=
CONTROL_EP
;
ep0
->
max_pkt_size
=
USBDEV_EP0_MAX_PACKET_SIZE
;
spin_lock_init
(
&
ep0
->
lock
);
ep0
->
desc
=
NULL
;
// ep0 has no descriptor
ep0
->
address
=
0
;
ep0
->
direction
=
0
;
ep0
->
reg
=
&
ep_reg
[
0
];
/* Initialize the other requested endpoints */
for
(
i
=
0
;
i
<
if_desc
->
bNumEndpoints
;
i
++
)
{
struct
usb_endpoint_descriptor
*
epd
=
&
ep_desc
[
i
];
endpoint_t
*
ep
;
if
((
epd
->
bEndpointAddress
&
0x80
)
==
USB_DIR_IN
)
{
ep
=
&
usbdev
.
ep
[
2
];
ep
->
address
=
2
;
if
(
ep
->
active
)
{
ep
=
&
usbdev
.
ep
[
3
];
ep
->
address
=
3
;
if
(
ep
->
active
)
{
err
(
"too many IN ep's requested"
);
ret
=
-
ENODEV
;
goto
out
;
}
}
}
else
{
ep
=
&
usbdev
.
ep
[
4
];
ep
->
address
=
4
;
if
(
ep
->
active
)
{
ep
=
&
usbdev
.
ep
[
5
];
ep
->
address
=
5
;
if
(
ep
->
active
)
{
err
(
"too many OUT ep's requested"
);
ret
=
-
ENODEV
;
goto
out
;
}
}
}
ep
->
active
=
1
;
epd
->
bEndpointAddress
&=
~
0x0f
;
epd
->
bEndpointAddress
|=
(
u8
)
ep
->
address
;
ep
->
direction
=
epd
->
bEndpointAddress
&
0x80
;
ep
->
type
=
epd
->
bmAttributes
&
0x03
;
ep
->
max_pkt_size
=
le16_to_cpu
(
epd
->
wMaxPacketSize
);
spin_lock_init
(
&
ep
->
lock
);
ep
->
desc
=
epd
;
ep
->
reg
=
&
ep_reg
[
ep
->
address
];
}
/*
* initialize the full config descriptor
*/
usbdev
.
full_conf_desc
=
fcd
=
kmalloc
(
le16_to_cpu
(
config_desc
->
wTotalLength
),
ALLOC_FLAGS
);
if
(
!
fcd
)
{
err
(
"failed to alloc full config descriptor"
);
ret
=
-
ENOMEM
;
goto
out
;
}
memcpy
(
fcd
,
config_desc
,
USB_DT_CONFIG_SIZE
);
fcd
+=
USB_DT_CONFIG_SIZE
;
memcpy
(
fcd
,
if_desc
,
USB_DT_INTERFACE_SIZE
);
fcd
+=
USB_DT_INTERFACE_SIZE
;
for
(
i
=
0
;
i
<
if_desc
->
bNumEndpoints
;
i
++
)
{
memcpy
(
fcd
,
&
ep_desc
[
i
],
USB_DT_ENDPOINT_SIZE
);
fcd
+=
USB_DT_ENDPOINT_SIZE
;
}
/* Now we're ready to enable the controller */
au_writel
(
0x0002
,
USBD_ENABLE
);
udelay
(
100
);
au_writel
(
0x0003
,
USBD_ENABLE
);
udelay
(
100
);
/* build and send config table based on ep descriptors */
for
(
i
=
0
;
i
<
6
;
i
++
)
{
endpoint_t
*
ep
;
if
(
i
==
1
)
continue
;
// skip dummy ep
ep
=
&
usbdev
.
ep
[
i
];
if
(
ep
->
active
)
{
au_writel
((
ep
->
address
<<
4
)
|
0x04
,
USBD_CONFIG
);
au_writel
(((
ep
->
max_pkt_size
&
0x380
)
>>
7
)
|
(
ep
->
direction
>>
4
)
|
(
ep
->
type
<<
4
),
USBD_CONFIG
);
au_writel
((
ep
->
max_pkt_size
&
0x7f
)
<<
1
,
USBD_CONFIG
);
au_writel
(
0x00
,
USBD_CONFIG
);
au_writel
(
ep
->
address
,
USBD_CONFIG
);
}
else
{
u8
dir
=
(
i
==
2
||
i
==
3
)
?
DIR_IN
:
DIR_OUT
;
au_writel
((
i
<<
4
)
|
0x04
,
USBD_CONFIG
);
au_writel
(((
16
&
0x380
)
>>
7
)
|
dir
|
(
BULK_EP
<<
4
),
USBD_CONFIG
);
au_writel
((
16
&
0x7f
)
<<
1
,
USBD_CONFIG
);
au_writel
(
0x00
,
USBD_CONFIG
);
au_writel
(
i
,
USBD_CONFIG
);
}
}
/*
* Enable Receive FIFO Complete interrupts only. Transmit
* complete is being handled by the DMA done interrupts.
*/
au_writel
(
0x31
,
USBD_INTEN
);
/*
* Controller is now enabled, request DMA and IRQ
* resources.
*/
/* request the USB device transfer complete interrupt */
if
(
request_irq
(
AU1000_USB_DEV_REQ_INT
,
req_sus_intr
,
IRQF_DISABLED
,
"USBdev req"
,
&
usbdev
))
{
err
(
"Can't get device request intr"
);
ret
=
-
ENXIO
;
goto
out
;
}
/* request the USB device suspend interrupt */
if
(
request_irq
(
AU1000_USB_DEV_SUS_INT
,
req_sus_intr
,
IRQF_DISABLED
,
"USBdev sus"
,
&
usbdev
))
{
err
(
"Can't get device suspend intr"
);
ret
=
-
ENXIO
;
goto
out
;
}
/* Request EP0 DMA and IRQ */
if
((
ep0
->
indma
=
request_au1000_dma
(
ep_dma_id
[
0
].
id
,
ep_dma_id
[
0
].
str
,
dma_done_ep0_intr
,
IRQF_DISABLED
,
&
usbdev
))
<
0
)
{
err
(
"Can't get %s DMA"
,
ep_dma_id
[
0
].
str
);
ret
=
-
ENXIO
;
goto
out
;
}
if
((
ep0
->
outdma
=
request_au1000_dma
(
ep_dma_id
[
1
].
id
,
ep_dma_id
[
1
].
str
,
NULL
,
0
,
NULL
))
<
0
)
{
err
(
"Can't get %s DMA"
,
ep_dma_id
[
1
].
str
);
ret
=
-
ENXIO
;
goto
out
;
}
// Flush the ep0 buffers and FIFOs
endpoint_flush
(
ep0
);
// start packet reception on ep0
kickstart_receive_packet
(
ep0
);
/* Request DMA and IRQ for the other endpoints */
for
(
i
=
2
;
i
<
6
;
i
++
)
{
endpoint_t
*
ep
=
&
usbdev
.
ep
[
i
];
if
(
!
ep
->
active
)
continue
;
// Flush the endpoint buffers and FIFOs
endpoint_flush
(
ep
);
if
(
ep
->
direction
==
USB_DIR_IN
)
{
ep
->
indma
=
request_au1000_dma
(
ep_dma_id
[
ep
->
address
].
id
,
ep_dma_id
[
ep
->
address
].
str
,
dma_done_ep_intr
,
IRQF_DISABLED
,
&
usbdev
);
if
(
ep
->
indma
<
0
)
{
err
(
"Can't get %s DMA"
,
ep_dma_id
[
ep
->
address
].
str
);
ret
=
-
ENXIO
;
goto
out
;
}
}
else
{
ep
->
outdma
=
request_au1000_dma
(
ep_dma_id
[
ep
->
address
].
id
,
ep_dma_id
[
ep
->
address
].
str
,
NULL
,
0
,
NULL
);
if
(
ep
->
outdma
<
0
)
{
err
(
"Can't get %s DMA"
,
ep_dma_id
[
ep
->
address
].
str
);
ret
=
-
ENXIO
;
goto
out
;
}
// start packet reception on OUT endpoint
kickstart_receive_packet
(
ep
);
}
}
out:
if
(
ret
)
usbdev_exit
();
return
ret
;
}
EXPORT_SYMBOL
(
usbdev_init
);
EXPORT_SYMBOL
(
usbdev_exit
);
EXPORT_SYMBOL
(
usbdev_alloc_packet
);
EXPORT_SYMBOL
(
usbdev_receive_packet
);
EXPORT_SYMBOL
(
usbdev_send_packet
);
EXPORT_SYMBOL
(
usbdev_get_byte_count
);
arch/mips/au1000/db1x00/board_setup.c
View file @
5536b235
...
...
@@ -58,11 +58,6 @@ void __init board_setup(void)
pin_func
=
0
;
/* not valid for 1550 */
#ifdef CONFIG_AU1X00_USB_DEVICE
// 2nd USB port is USB device
pin_func
=
au_readl
(
SYS_PINFUNC
)
&
(
u32
)(
~
0x8000
);
au_writel
(
pin_func
,
SYS_PINFUNC
);
#endif
#if defined(CONFIG_IRDA) && (defined(CONFIG_SOC_AU1000) || defined(CONFIG_SOC_AU1100))
/* set IRFIRSEL instead of GPIO15 */
...
...
arch/mips/au1000/mtx-1/board_setup.c
View file @
5536b235
...
...
@@ -51,15 +51,11 @@ void board_reset (void)
void
__init
board_setup
(
void
)
{
#if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
#ifdef CONFIG_AU1X00_USB_DEVICE
// 2nd USB port is USB device
au_writel
(
au_readl
(
SYS_PINFUNC
)
&
(
u32
)(
~
0x8000
),
SYS_PINFUNC
);
#endif
#ifdef CONFIG_USB_OHCI
// enable USB power switch
au_writel
(
au_readl
(
GPIO2_DIR
)
|
0x10
,
GPIO2_DIR
);
au_writel
(
0x100000
,
GPIO2_OUTPUT
);
#endif // defined (CONFIG_USB_OHCI)
|| defined (CONFIG_AU1X00_USB_DEVICE)
#endif // defined (CONFIG_USB_OHCI)
#ifdef CONFIG_PCI
#if defined(__MIPSEB__)
...
...
arch/mips/au1000/pb1000/board_setup.c
View file @
5536b235
...
...
@@ -54,7 +54,7 @@ void __init board_setup(void)
au_writel
(
0
,
SYS_PINSTATERD
);
udelay
(
100
);
#if
defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
#if
def CONFIG_USB_OHCI
/* zero and disable FREQ2 */
sys_freqctrl
=
au_readl
(
SYS_FREQCTRL0
);
sys_freqctrl
&=
~
0xFFF00000
;
...
...
@@ -104,23 +104,19 @@ void __init board_setup(void)
*/
#ifdef CONFIG_USB_OHCI
sys_clksrc
|=
((
4
<<
12
)
|
(
0
<<
11
)
|
(
0
<<
10
));
#endif
#ifdef CONFIG_AU1X00_USB_DEVICE
sys_clksrc
|=
((
4
<<
7
)
|
(
0
<<
6
)
|
(
0
<<
5
));
#endif
au_writel
(
sys_clksrc
,
SYS_CLKSRC
);
// configure pins GPIO[14:9] as GPIO
pin_func
=
au_readl
(
SYS_PINFUNC
)
&
(
u32
)(
~
0x8080
);
#ifndef CONFIG_AU1X00_USB_DEVICE
// 2nd USB port is USB host
pin_func
|=
0x8000
;
#endif
au_writel
(
pin_func
,
SYS_PINFUNC
);
au_writel
(
0x2800
,
SYS_TRIOUTCLR
);
au_writel
(
0x0030
,
SYS_OUTPUTCLR
);
#endif // defined (CONFIG_USB_OHCI)
|| defined (CONFIG_AU1X00_USB_DEVICE)
#endif // defined (CONFIG_USB_OHCI)
// make gpio 15 an input (for interrupt line)
pin_func
=
au_readl
(
SYS_PINFUNC
)
&
(
u32
)(
~
0x100
);
...
...
arch/mips/au1000/pb1100/board_setup.c
View file @
5536b235
...
...
@@ -55,7 +55,7 @@ void __init board_setup(void)
au_writel
(
0
,
SYS_PININPUTEN
);
udelay
(
100
);
#if
defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
#if
def CONFIG_USB_OHCI
// configure pins GPIO[14:9] as GPIO
pin_func
=
au_readl
(
SYS_PINFUNC
)
&
(
u32
)(
~
0x80
);
...
...
@@ -92,12 +92,10 @@ void __init board_setup(void)
// get USB Functionality pin state (device vs host drive pins)
pin_func
=
au_readl
(
SYS_PINFUNC
)
&
(
u32
)(
~
0x8000
);
#ifndef CONFIG_AU1X00_USB_DEVICE
// 2nd USB port is USB host
pin_func
|=
0x8000
;
#endif
au_writel
(
pin_func
,
SYS_PINFUNC
);
#endif // defined (CONFIG_USB_OHCI)
|| defined (CONFIG_AU1X00_USB_DEVICE)
#endif // defined (CONFIG_USB_OHCI)
/* Enable sys bus clock divider when IDLE state or no bus activity. */
au_writel
(
au_readl
(
SYS_POWERCTRL
)
|
(
0x3
<<
5
),
SYS_POWERCTRL
);
...
...
arch/mips/au1000/pb1500/board_setup.c
View file @
5536b235
...
...
@@ -56,7 +56,7 @@ void __init board_setup(void)
au_writel
(
0
,
SYS_PINSTATERD
);
udelay
(
100
);
#if
defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
#if
def CONFIG_USB_OHCI
/* GPIO201 is input for PCMCIA card detect */
/* GPIO203 is input for PCMCIA interrupt request */
...
...
@@ -87,20 +87,15 @@ void __init board_setup(void)
*/
#ifdef CONFIG_USB_OHCI
sys_clksrc
|=
((
4
<<
12
)
|
(
0
<<
11
)
|
(
0
<<
10
));
#endif
#ifdef CONFIG_AU1X00_USB_DEVICE
sys_clksrc
|=
((
4
<<
7
)
|
(
0
<<
6
)
|
(
0
<<
5
));
#endif
au_writel
(
sys_clksrc
,
SYS_CLKSRC
);
pin_func
=
au_readl
(
SYS_PINFUNC
)
&
(
u32
)(
~
0x8000
);
#ifndef CONFIG_AU1X00_USB_DEVICE
// 2nd USB port is USB host
pin_func
|=
0x8000
;
#endif
au_writel
(
pin_func
,
SYS_PINFUNC
);
#endif // defined (CONFIG_USB_OHCI)
|| defined (CONFIG_AU1X00_USB_DEVICE)
#endif // defined (CONFIG_USB_OHCI)
...
...
arch/mips/configs/pb1100_defconfig
View file @
5536b235
...
...
@@ -76,7 +76,6 @@ CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
CONFIG_SOC_AU1100=y
CONFIG_SOC_AU1X00=y
CONFIG_SWAP_IO_SPACE=y
# CONFIG_AU1X00_USB_DEVICE is not set
CONFIG_MIPS_L1_CACHE_SHIFT=5
#
...
...
arch/mips/configs/pb1500_defconfig
View file @
5536b235
...
...
@@ -75,7 +75,6 @@ CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
CONFIG_SOC_AU1500=y
CONFIG_SOC_AU1X00=y
# CONFIG_AU1X00_USB_DEVICE is not set
CONFIG_MIPS_L1_CACHE_SHIFT=5
#
...
...
include/asm-mips/mach-au1x00/au1000_usbdev.h
deleted
100644 → 0
View file @
0118c3ca
/*
* BRIEF MODULE DESCRIPTION
* Au1000 USB Device-Side Driver
*
* Copyright 2001 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* stevel@mvista.com or source@mvista.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define USBDEV_REV 0x0110 // BCD
#define USBDEV_EP0_MAX_PACKET_SIZE 64
typedef
enum
{
ATTACHED
=
0
,
POWERED
,
DEFAULT
,
ADDRESS
,
CONFIGURED
}
usbdev_state_t
;
typedef
enum
{
CB_NEW_STATE
=
0
,
CB_PKT_COMPLETE
}
usbdev_cb_type_t
;
typedef
struct
usbdev_pkt
{
int
ep_addr
;
// ep addr this packet routed to
int
size
;
// size of payload in bytes
unsigned
status
;
// packet status
struct
usbdev_pkt
*
next
;
// function layer can't touch this
u8
payload
[
0
];
// the payload
}
usbdev_pkt_t
;
#define PKT_STATUS_ACK (1<<0)
#define PKT_STATUS_NAK (1<<1)
#define PKT_STATUS_SU (1<<2)
extern
int
usbdev_init
(
struct
usb_device_descriptor
*
dev_desc
,
struct
usb_config_descriptor
*
config_desc
,
struct
usb_interface_descriptor
*
if_desc
,
struct
usb_endpoint_descriptor
*
ep_desc
,
struct
usb_string_descriptor
*
str_desc
[],
void
(
*
cb
)(
usbdev_cb_type_t
,
unsigned
long
,
void
*
),
void
*
cb_data
);
extern
void
usbdev_exit
(
void
);
extern
int
usbdev_alloc_packet
(
int
ep_addr
,
int
data_size
,
usbdev_pkt_t
**
pkt
);
extern
int
usbdev_send_packet
(
int
ep_addr
,
usbdev_pkt_t
*
pkt
);
extern
int
usbdev_receive_packet
(
int
ep_addr
,
usbdev_pkt_t
**
pkt
);
extern
int
usbdev_get_byte_count
(
int
ep_addr
);
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