Initial version of libusbboot, a fully stand-alone, single threaded and
functional compilation of the FreeBSD USB stack for use with boot loaders and such. Discussed with: Hiroki Sato, hrs @ EuroBSDCon
This commit is contained in:
parent
498944374f
commit
77a9c69878
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=246145
150
sys/boot/usb/Makefile
Normal file
150
sys/boot/usb/Makefile
Normal file
@ -0,0 +1,150 @@
|
||||
#
|
||||
# $FreeBSD$
|
||||
#
|
||||
# Copyright (c) 2013 Hans Petter Selasky. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
|
||||
#
|
||||
|
||||
T=${.CURDIR}/tools
|
||||
S=${.CURDIR}/../..
|
||||
|
||||
.PATH: \
|
||||
${.CURDIR} \
|
||||
${S}/dev/usb \
|
||||
${S}/dev/usb/controller \
|
||||
${S}/dev/usb/serial \
|
||||
${S}/dev/usb/storage \
|
||||
${S}/dev/usb/template
|
||||
|
||||
LIB= usbboot
|
||||
INTERNALLIB=
|
||||
OBJCOPY?= objcopy
|
||||
SYSCC?= cc
|
||||
|
||||
CFLAGS+= -DBOOTPROG=\"usbloader\"
|
||||
CFLAGS+= -DUSB_GLOBAL_INCLUDE_FILE="\"bsd_global.h\""
|
||||
CFLAGS+= -ffunction-sections -fdata-sections
|
||||
CFLAGS+= -ffreestanding
|
||||
CFLAGS+= -Wformat -Wall
|
||||
CFLAGS+= -I ${S}
|
||||
CFLAGS+= -I ${T}
|
||||
CFLAGS+= -I ${.CURDIR}
|
||||
CFLAGS+= -g
|
||||
|
||||
.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64"
|
||||
CFLAGS+= -march=i386
|
||||
CFLAGS+= -mpreferred-stack-boundary=2
|
||||
.endif
|
||||
.if ${MACHINE_CPUARCH} == "amd64"
|
||||
CFLAGS+= -m32
|
||||
.endif
|
||||
|
||||
#
|
||||
# Single threaded BSD kernel
|
||||
#
|
||||
SRCS+= bsd_kernel.c
|
||||
|
||||
#
|
||||
# BUSSPACE implementation
|
||||
#
|
||||
SRCS+= bsd_busspace.c
|
||||
|
||||
#
|
||||
# BUSDMA implementation
|
||||
#
|
||||
SRCS+= usb_busdma_loader.c
|
||||
|
||||
#
|
||||
# USB controller drivers
|
||||
#
|
||||
SRCS+= at91dci.c
|
||||
SRCS+= atmegadci.c
|
||||
SRCS+= avr32dci.c
|
||||
SRCS+= dwc_otg.c
|
||||
SRCS+= ehci.c
|
||||
SRCS+= musb_otg.c
|
||||
SRCS+= ohci.c
|
||||
SRCS+= uhci.c
|
||||
SRCS+= uss820dci.c
|
||||
SRCS+= xhci.c
|
||||
SRCS+= usb_controller.c
|
||||
|
||||
CFLAGS += -DUSB_PROBE_LIST="\"xhci\", \"ehci\", \"uhci\", \"ohci\""
|
||||
|
||||
#
|
||||
# USB core and templates
|
||||
#
|
||||
SRCS+= usb_core.c
|
||||
SRCS+= usb_debug.c
|
||||
SRCS+= usb_device.c
|
||||
SRCS+= usb_dynamic.c
|
||||
SRCS+= usb_error.c
|
||||
SRCS+= usb_handle_request.c
|
||||
SRCS+= usb_hid.c
|
||||
SRCS+= usb_hub.c
|
||||
SRCS+= usb_lookup.c
|
||||
SRCS+= usb_msctest.c
|
||||
SRCS+= usb_parse.c
|
||||
SRCS+= usb_request.c
|
||||
SRCS+= usb_transfer.c
|
||||
SRCS+= usb_util.c
|
||||
SRCS+= usb_template.c
|
||||
SRCS+= usb_template_cdce.c
|
||||
SRCS+= usb_template_msc.c
|
||||
SRCS+= usb_template_mtp.c
|
||||
SRCS+= usb_template_modem.c
|
||||
SRCS+= usb_template_mouse.c
|
||||
SRCS+= usb_template_kbd.c
|
||||
SRCS+= usb_template_audio.c
|
||||
SRCS+= sysinit_data.c
|
||||
SRCS+= sysuninit_data.c
|
||||
|
||||
CLEANFILES+= sysinit
|
||||
CLEANFILES+= sysinit.bin
|
||||
CLEANFILES+= sysinit_data.c
|
||||
CLEANFILES+= sysuninit_data.c
|
||||
|
||||
CLEANFILES+= ${SRCS:C/\.c/.osys/g}
|
||||
|
||||
.include <bsd.lib.mk>
|
||||
|
||||
#
|
||||
# SYSINIT() and SYSUNINIT() handling
|
||||
#
|
||||
sysinit: ${T}/sysinit.c
|
||||
${SYSCC} -Wall -o ${.TARGET} ${.ALLSRC}
|
||||
|
||||
sysinit_data.c: sysinit.bin sysinit
|
||||
${.OBJDIR}/sysinit -i sysinit.bin -o ${.TARGET} -k sysinit -s sysinit_data
|
||||
|
||||
sysuninit_data.c: sysinit.bin sysinit
|
||||
${.OBJDIR}/sysinit -i sysinit.bin -o ${.TARGET} -R -k sysuninit -s sysuninit_data
|
||||
|
||||
.for F in ${OBJS}
|
||||
${F}sys: ${F}
|
||||
${OBJCOPY} -j ".debug.sysinit" -O binary ${F} ${.TARGET}
|
||||
[ -f ${.TARGET} ] || touch ${.TARGET}
|
||||
.endfor
|
||||
|
||||
sysinit.bin: ${OBJS:C/\.o/.osys/g:C/sysinit_data.osys//g:C/sysuninit_data.osys//g}
|
||||
cat ${.ALLSRC} > sysinit.bin
|
61
sys/boot/usb/Makefile.test
Normal file
61
sys/boot/usb/Makefile.test
Normal file
@ -0,0 +1,61 @@
|
||||
#
|
||||
# $FreeBSD$
|
||||
#
|
||||
# Copyright (c) 2013 Hans Petter Selasky. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
|
||||
#
|
||||
|
||||
#
|
||||
# USB test application
|
||||
#
|
||||
|
||||
.PATH: ${.CURDIR}
|
||||
|
||||
PROG= usbloader
|
||||
MAN=
|
||||
SRCS=
|
||||
|
||||
CFLAGS+= -Wall
|
||||
CFLAGS+= -g
|
||||
|
||||
.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64"
|
||||
CFLAGS+= -march=i386
|
||||
CFLAGS+= -mpreferred-stack-boundary=2
|
||||
.endif
|
||||
.if ${MACHINE_CPUARCH} == "amd64"
|
||||
CFLAGS+= -m32
|
||||
.endif
|
||||
|
||||
LDFLAGS+= -Wl,--gc-sections
|
||||
|
||||
SRCS+= bsd_usbloader_test.c
|
||||
|
||||
LDADD+= libusbboot.a
|
||||
DPADD+= libusbboot.a
|
||||
|
||||
all: libusbboot.a
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
||||
libusbboot.a:
|
||||
make -f Makefile
|
207
sys/boot/usb/bsd_busspace.c
Normal file
207
sys/boot/usb/bsd_busspace.c
Normal file
@ -0,0 +1,207 @@
|
||||
/* $FreeBSD$ */
|
||||
/*-
|
||||
* Copyright (c) 2013 Hans Petter Selasky. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
#include <bsd_kernel.h>
|
||||
|
||||
struct burst {
|
||||
uint32_t dw0;
|
||||
uint32_t dw1;
|
||||
uint32_t dw2;
|
||||
uint32_t dw3;
|
||||
uint32_t dw4;
|
||||
uint32_t dw5;
|
||||
uint32_t dw6;
|
||||
uint32_t dw7;
|
||||
};
|
||||
|
||||
void
|
||||
bus_space_read_multi_1(bus_space_tag_t t, bus_space_handle_t h,
|
||||
bus_size_t offset, uint8_t *datap, bus_size_t count)
|
||||
{
|
||||
while (count--) {
|
||||
*datap++ = bus_space_read_1(t, h, offset);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bus_space_read_multi_2(bus_space_tag_t t, bus_space_handle_t h,
|
||||
bus_size_t offset, uint16_t *datap, bus_size_t count)
|
||||
{
|
||||
while (count--) {
|
||||
*datap++ = bus_space_read_2(t, h, offset);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bus_space_read_multi_4(bus_space_tag_t t, bus_space_handle_t h,
|
||||
bus_size_t offset, uint32_t *datap, bus_size_t count)
|
||||
{
|
||||
h += offset;
|
||||
|
||||
while (count--) {
|
||||
*datap++ = *((volatile uint32_t *)h);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bus_space_write_multi_1(bus_space_tag_t t, bus_space_handle_t h,
|
||||
bus_size_t offset, uint8_t *datap, bus_size_t count)
|
||||
{
|
||||
while (count--) {
|
||||
uint8_t temp = *datap++;
|
||||
|
||||
bus_space_write_1(t, h, offset, temp);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bus_space_write_multi_2(bus_space_tag_t t, bus_space_handle_t h,
|
||||
bus_size_t offset, uint16_t *datap, bus_size_t count)
|
||||
{
|
||||
while (count--) {
|
||||
uint16_t temp = *datap++;
|
||||
|
||||
bus_space_write_2(t, h, offset, temp);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bus_space_write_multi_4(bus_space_tag_t t, bus_space_handle_t h,
|
||||
bus_size_t offset, uint32_t *datap, bus_size_t count)
|
||||
{
|
||||
h += offset;
|
||||
|
||||
while (count--) {
|
||||
*((volatile uint32_t *)h) = *datap++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bus_space_write_1(bus_space_tag_t t, bus_space_handle_t h,
|
||||
bus_size_t offset, uint8_t data)
|
||||
{
|
||||
*((volatile uint8_t *)(h + offset)) = data;
|
||||
}
|
||||
|
||||
void
|
||||
bus_space_write_2(bus_space_tag_t t, bus_space_handle_t h,
|
||||
bus_size_t offset, uint16_t data)
|
||||
{
|
||||
*((volatile uint16_t *)(h + offset)) = data;
|
||||
}
|
||||
|
||||
void
|
||||
bus_space_write_4(bus_space_tag_t t, bus_space_handle_t h,
|
||||
bus_size_t offset, uint32_t data)
|
||||
{
|
||||
*((volatile uint32_t *)(h + offset)) = data;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
bus_space_read_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offset)
|
||||
{
|
||||
return (*((volatile uint8_t *)(h + offset)));
|
||||
}
|
||||
|
||||
uint16_t
|
||||
bus_space_read_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offset)
|
||||
{
|
||||
return (*((volatile uint16_t *)(h + offset)));
|
||||
}
|
||||
|
||||
uint32_t
|
||||
bus_space_read_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offset)
|
||||
{
|
||||
return (*((volatile uint32_t *)(h + offset)));
|
||||
}
|
||||
|
||||
void
|
||||
bus_space_read_region_1(bus_space_tag_t t, bus_space_handle_t h,
|
||||
bus_size_t offset, uint8_t *datap, bus_size_t count)
|
||||
{
|
||||
h += offset;
|
||||
|
||||
while (count--) {
|
||||
*datap++ = *((volatile uint8_t *)h);
|
||||
h += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bus_space_write_region_1(bus_space_tag_t t, bus_space_handle_t h,
|
||||
bus_size_t offset, uint8_t *datap, bus_size_t count)
|
||||
{
|
||||
h += offset;
|
||||
|
||||
while (count--) {
|
||||
*((volatile uint8_t *)h) = *datap++;
|
||||
h += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bus_space_read_region_4(bus_space_tag_t t, bus_space_handle_t h,
|
||||
bus_size_t offset, uint32_t *datap, bus_size_t count)
|
||||
{
|
||||
enum { BURST = sizeof(struct burst) / 4 };
|
||||
|
||||
h += offset;
|
||||
|
||||
while (count >= BURST) {
|
||||
*(struct burst *)datap = *((/* volatile */ struct burst *)h);
|
||||
|
||||
h += BURST * 4;
|
||||
datap += BURST;
|
||||
count -= BURST;
|
||||
}
|
||||
|
||||
while (count--) {
|
||||
*datap++ = *((volatile uint32_t *)h);
|
||||
h += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bus_space_write_region_4(bus_space_tag_t t, bus_space_handle_t h,
|
||||
bus_size_t offset, uint32_t *datap, bus_size_t count)
|
||||
{
|
||||
enum { BURST = sizeof(struct burst) / 4 };
|
||||
|
||||
h += offset;
|
||||
|
||||
while (count >= BURST) {
|
||||
*((/* volatile */ struct burst *)h) = *(struct burst *)datap;
|
||||
|
||||
h += BURST * 4;
|
||||
datap += BURST;
|
||||
count -= BURST;
|
||||
}
|
||||
|
||||
while (count--) {
|
||||
*((volatile uint32_t *)h) = *datap++;
|
||||
h += 4;
|
||||
}
|
||||
}
|
63
sys/boot/usb/bsd_global.h
Normal file
63
sys/boot/usb/bsd_global.h
Normal file
@ -0,0 +1,63 @@
|
||||
/* $FreeBSD$ */
|
||||
/*-
|
||||
* Copyright (c) 2013 Hans Petter Selasky. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
#ifndef _BSD_GLOBAL_H_
|
||||
#define _BSD_GLOBAL_H_
|
||||
|
||||
#include <bsd_kernel.h>
|
||||
|
||||
#define USB_DEBUG_VAR usb_debug
|
||||
#include <dev/usb/usb_freebsd_loader.h>
|
||||
#include <dev/usb/usb_endian.h>
|
||||
#include <dev/usb/usb.h>
|
||||
#include <dev/usb/usbdi.h>
|
||||
#include <dev/usb/usb_core.h>
|
||||
#include <dev/usb/usb_debug.h>
|
||||
#include <dev/usb/usb_process.h>
|
||||
#include <dev/usb/usb_busdma.h>
|
||||
#include <dev/usb/usb_dynamic.h>
|
||||
#include <dev/usb/usb_device.h>
|
||||
#include <dev/usb/usb_hub.h>
|
||||
#include <dev/usb/usb_controller.h>
|
||||
#include <dev/usb/usb_bus.h>
|
||||
#include <dev/usb/usbdi_util.h>
|
||||
#include <dev/usb/usb_cdc.h>
|
||||
#include <dev/usb/usb_dev.h>
|
||||
#include <dev/usb/usb_mbuf.h>
|
||||
#include <dev/usb/usb_msctest.h>
|
||||
#include <dev/usb/usb_pci.h>
|
||||
#include <dev/usb/usb_pf.h>
|
||||
#include <dev/usb/usb_request.h>
|
||||
#include <dev/usb/usb_util.h>
|
||||
#include <dev/usb/usb_transfer.h>
|
||||
#include <dev/usb/usb_compat_linux.h>
|
||||
#include <dev/usb/usbhid.h>
|
||||
#include <dev/usb/usb_ioctl.h>
|
||||
#include <dev/usb/usb_generic.h>
|
||||
#include <dev/usb/quirk/usb_quirk.h>
|
||||
#include <dev/usb/template/usb_template.h>
|
||||
|
||||
#endif /* _BSD_GLOBAL_H_ */
|
1269
sys/boot/usb/bsd_kernel.c
Normal file
1269
sys/boot/usb/bsd_kernel.c
Normal file
File diff suppressed because it is too large
Load Diff
458
sys/boot/usb/bsd_kernel.h
Normal file
458
sys/boot/usb/bsd_kernel.h
Normal file
@ -0,0 +1,458 @@
|
||||
/* $FreeBSD$ */
|
||||
/*-
|
||||
* Copyright (c) 2011 Hans Petter Selasky. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
#ifndef _BSD_KERNEL_H_
|
||||
#define _BSD_KERNEL_H_
|
||||
|
||||
#define _KERNEL
|
||||
#define __FreeBSD_version 1000000
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/errno.h>
|
||||
|
||||
#define isalpha(x) (((x) >= 'a' && (x) <= 'z') || ((x) >= 'A' && (x) <= 'Z'))
|
||||
#define isdigit(x) ((x) >= '0' && (x) <= '9')
|
||||
#define panic(...) do { printf("USB PANIC: " __VA_ARGS__); while (1) ; } while (0)
|
||||
#define M_USB 0
|
||||
#define M_USBDEV 0
|
||||
#define USB_PROC_MAX 3
|
||||
#define SYSCTL_DECL(...)
|
||||
#define SYSCTL_NODE(name,...) struct { } name __used
|
||||
#define SYSCTL_INT(...)
|
||||
#define TUNABLE_INT(...)
|
||||
#define MALLOC_DECLARE(...)
|
||||
#define MALLOC_DEFINE(...)
|
||||
#define EVENTHANDLER_DECLARE(...)
|
||||
#define EVENTHANDLER_INVOKE(...)
|
||||
#define KASSERT(...)
|
||||
#define SCHEDULER_STOPPED(x) (0)
|
||||
#define PI_SWI(...) (0)
|
||||
#define UNIQ_NAME(x) x
|
||||
#define UNIQ_NAME_STR(x) #x
|
||||
#define DEVCLASS_MAXUNIT 32
|
||||
#define MOD_LOAD 1
|
||||
#define MOD_UNLOAD 2
|
||||
#define DEVMETHOD(what,func) { #what, (void *)&func }
|
||||
#define DEVMETHOD_END {0,0}
|
||||
#define DRIVER_MODULE(name, busname, driver, devclass, evh, arg) \
|
||||
static struct module_data bsd_##name##_##busname##_driver_mod = { \
|
||||
evh, arg, #busname, #name, #busname "/" #name, \
|
||||
&driver, &devclass, { 0, 0 } }; \
|
||||
SYSINIT(bsd_##name##_##busname##_driver_mod, SI_SUB_DRIVERS, \
|
||||
SI_ORDER_MIDDLE, module_register, \
|
||||
&bsd_##name##_##busname##_driver_mod)
|
||||
#define SYSINIT(uniq, subs, order, _func, _data) \
|
||||
const struct sysinit UNIQ_NAME(sysinit_##uniq) = { \
|
||||
.func = (_func), \
|
||||
.data = __DECONST(void *, _data) \
|
||||
}; \
|
||||
SYSINIT_ENTRY(uniq##_entry, "sysinit", (subs), \
|
||||
(order), "const struct sysinit", \
|
||||
UNIQ_NAME_STR(sysinit_##uniq), "SYSINIT")
|
||||
|
||||
#define SYSUNINIT(uniq, subs, order, _func, _data) \
|
||||
const struct sysinit UNIQ_NAME(sysuninit_##uniq) = { \
|
||||
.func = (_func), \
|
||||
.data = __DECONST(void *, _data) \
|
||||
}; \
|
||||
SYSINIT_ENTRY(uniq##_entry, "sysuninit", (subs), \
|
||||
(order), "const struct sysuninit", \
|
||||
UNIQ_NAME_STR(sysuninit_##uniq), "SYSUNINIT")
|
||||
#define MODULE_DEPEND(...)
|
||||
#define MODULE_VERSION(...)
|
||||
#define NULL ((void *)0)
|
||||
#define BUS_SPACE_BARRIER_READ 0x01
|
||||
#define BUS_SPACE_BARRIER_WRITE 0x02
|
||||
#define hz 1000
|
||||
#define PAGE_SIZE 4096
|
||||
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
|
||||
#define MTX_DEF 0
|
||||
#define MTX_RECURSE 0
|
||||
#define SX_DUPOK 0
|
||||
#define SX_NOWITNESS 0
|
||||
#define WITNESS_WARN(...)
|
||||
#define cold 0
|
||||
#define BUS_PROBE_GENERIC 0
|
||||
#define CALLOUT_RETURNUNLOCKED 0x1
|
||||
#define va_list __builtin_va_list
|
||||
#define va_size(type) __builtin_va_size(type)
|
||||
#define va_start(ap, last) __builtin_va_start(ap, last)
|
||||
#define va_end(ap) __builtin_va_end(ap)
|
||||
#define va_arg(ap, type) __builtin_va_arg((ap), type)
|
||||
#define DEVICE_ATTACH(dev, ...) \
|
||||
(((device_attach_t *)(device_get_method(dev, "device_attach")))(dev,## __VA_ARGS__))
|
||||
#define DEVICE_DETACH(dev, ...) \
|
||||
(((device_detach_t *)(device_get_method(dev, "device_detach")))(dev,## __VA_ARGS__))
|
||||
#define DEVICE_PROBE(dev, ...) \
|
||||
(((device_probe_t *)(device_get_method(dev, "device_probe")))(dev,## __VA_ARGS__))
|
||||
#define DEVICE_RESUME(dev, ...) \
|
||||
(((device_resume_t *)(device_get_method(dev, "device_resume")))(dev,## __VA_ARGS__))
|
||||
#define DEVICE_SHUTDOWN(dev, ...) \
|
||||
(((device_shutdown_t *)(device_get_method(dev, "device_shutdown")))(dev,## __VA_ARGS__))
|
||||
#define DEVICE_SUSPEND(dev, ...) \
|
||||
(((device_suspend_t *)(device_get_method(dev, "device_suspend")))(dev,## __VA_ARGS__))
|
||||
#define USB_HANDLE_REQUEST(dev, ...) \
|
||||
(((usb_handle_request_t *)(device_get_method(dev, "usb_handle_request")))(dev,## __VA_ARGS__))
|
||||
#define USB_TAKE_CONTROLLER(dev, ...) \
|
||||
(((usb_take_controller_t *)(device_get_method(dev, "usb_take_controller")))(dev,## __VA_ARGS__))
|
||||
|
||||
enum {
|
||||
SI_SUB_DUMMY = 0x0000000,
|
||||
SI_SUB_LOCK = 0x1B00000,
|
||||
SI_SUB_KLD = 0x2000000,
|
||||
SI_SUB_DRIVERS = 0x3100000,
|
||||
SI_SUB_PSEUDO = 0x7000000,
|
||||
SI_SUB_KICK_SCHEDULER = 0xa000000,
|
||||
SI_SUB_RUN_SCHEDULER = 0xfffffff
|
||||
};
|
||||
|
||||
enum {
|
||||
SI_ORDER_FIRST = 0x0000000,
|
||||
SI_ORDER_SECOND = 0x0000001,
|
||||
SI_ORDER_THIRD = 0x0000002,
|
||||
SI_ORDER_FOURTH = 0x0000003,
|
||||
SI_ORDER_MIDDLE = 0x1000000,
|
||||
SI_ORDER_ANY = 0xfffffff /* last */
|
||||
};
|
||||
|
||||
struct uio;
|
||||
struct thread;
|
||||
struct malloc_type;
|
||||
struct usb_process;
|
||||
|
||||
typedef unsigned char uint8_t;
|
||||
typedef signed char int8_t;
|
||||
|
||||
typedef unsigned short uint16_t;
|
||||
typedef signed short int16_t;
|
||||
|
||||
typedef unsigned int uint32_t;
|
||||
typedef signed int int32_t;
|
||||
|
||||
typedef unsigned long long uint64_t;
|
||||
typedef signed long long int64_t;
|
||||
|
||||
typedef unsigned long bus_addr_t;
|
||||
typedef unsigned long bus_size_t;
|
||||
|
||||
typedef unsigned long size_t;
|
||||
typedef unsigned long u_long;
|
||||
|
||||
typedef void *bus_dmamap_t;
|
||||
typedef void *bus_dma_tag_t;
|
||||
|
||||
typedef void *bus_space_tag_t;
|
||||
typedef uint8_t *bus_space_handle_t;
|
||||
|
||||
typedef uint16_t uid_t;
|
||||
typedef uint16_t gid_t;
|
||||
typedef uint16_t mode_t;
|
||||
|
||||
typedef uint8_t *caddr_t;
|
||||
typedef unsigned long __uintptr_t;
|
||||
typedef unsigned long uintptr_t;
|
||||
|
||||
/* SYSINIT API */
|
||||
|
||||
#include <sysinit.h>
|
||||
|
||||
struct sysinit {
|
||||
void (*func) (void *arg);
|
||||
void *data;
|
||||
};
|
||||
|
||||
/* MUTEX API */
|
||||
|
||||
struct mtx {
|
||||
int owned;
|
||||
struct mtx *parent;
|
||||
};
|
||||
|
||||
#define mtx_assert(...) do { } while (0)
|
||||
void mtx_init(struct mtx *, const char *, const char *, int);
|
||||
void mtx_lock(struct mtx *);
|
||||
void mtx_unlock(struct mtx *);
|
||||
int mtx_owned(struct mtx *);
|
||||
void mtx_destroy(struct mtx *);
|
||||
|
||||
extern struct mtx Giant;
|
||||
|
||||
/* SX API */
|
||||
|
||||
struct sx {
|
||||
int owned;
|
||||
};
|
||||
|
||||
#define sx_assert(...) do { } while (0)
|
||||
#define sx_init(...) sx_init_flags(__VA_ARGS__, 0)
|
||||
void sx_init_flags(struct sx *, const char *, int);
|
||||
void sx_destroy(struct sx *);
|
||||
void sx_xlock(struct sx *);
|
||||
void sx_xunlock(struct sx *);
|
||||
int sx_xlocked(struct sx *);
|
||||
|
||||
/* CONDVAR API */
|
||||
|
||||
struct cv {
|
||||
int sleeping;
|
||||
};
|
||||
|
||||
void cv_init(struct cv *, const char *desc);
|
||||
void cv_destroy(struct cv *);
|
||||
void cv_wait(struct cv *, struct mtx *);
|
||||
int cv_timedwait(struct cv *, struct mtx *, int);
|
||||
void cv_signal(struct cv *);
|
||||
void cv_broadcast(struct cv *);
|
||||
|
||||
/* CALLOUT API */
|
||||
|
||||
typedef void callout_fn_t (void *);
|
||||
|
||||
extern volatile int ticks;
|
||||
|
||||
struct callout {
|
||||
LIST_ENTRY(callout) entry;
|
||||
callout_fn_t *func;
|
||||
void *arg;
|
||||
struct mtx *mtx;
|
||||
int flags;
|
||||
int timeout;
|
||||
};
|
||||
|
||||
void callout_init_mtx(struct callout *, struct mtx *, int);
|
||||
void callout_reset(struct callout *, int, callout_fn_t *, void *);
|
||||
void callout_stop(struct callout *);
|
||||
void callout_drain(struct callout *);
|
||||
int callout_pending(struct callout *);
|
||||
void callout_process(int timeout);
|
||||
|
||||
/* DEVICE API */
|
||||
|
||||
struct driver;
|
||||
struct devclass;
|
||||
struct device;
|
||||
struct module;
|
||||
struct module_data;
|
||||
|
||||
typedef struct driver driver_t;
|
||||
typedef struct devclass *devclass_t;
|
||||
typedef struct device *device_t;
|
||||
typedef void (intr_fn_t)(void *arg);
|
||||
|
||||
typedef int device_attach_t (device_t dev);
|
||||
typedef int device_detach_t (device_t dev);
|
||||
typedef int device_resume_t (device_t dev);
|
||||
typedef int device_shutdown_t (device_t dev);
|
||||
typedef int device_probe_t (device_t dev);
|
||||
typedef int device_suspend_t (device_t dev);
|
||||
|
||||
typedef int bus_child_location_str_t (device_t parent, device_t child, char *buf, size_t buflen);
|
||||
typedef int bus_child_pnpinfo_str_t (device_t parent, device_t child, char *buf, size_t buflen);
|
||||
typedef void bus_driver_added_t (device_t dev, driver_t *driver);
|
||||
|
||||
struct device_method {
|
||||
const char *desc;
|
||||
void *const func;
|
||||
};
|
||||
|
||||
typedef struct device_method device_method_t;
|
||||
|
||||
struct device {
|
||||
TAILQ_HEAD(device_list, device) dev_children;
|
||||
TAILQ_ENTRY(device) dev_link;
|
||||
|
||||
struct device *dev_parent;
|
||||
const struct module_data *dev_module;
|
||||
void *dev_sc;
|
||||
void *dev_aux;
|
||||
intr_fn_t *dev_irq_fn;
|
||||
void *dev_irq_arg;
|
||||
|
||||
uint16_t dev_unit;
|
||||
|
||||
char dev_nameunit[64];
|
||||
char dev_desc[64];
|
||||
|
||||
uint8_t dev_res_alloc:1;
|
||||
uint8_t dev_quiet:1;
|
||||
uint8_t dev_softc_set:1;
|
||||
uint8_t dev_softc_alloc:1;
|
||||
uint8_t dev_attached:1;
|
||||
uint8_t dev_fixed_class:1;
|
||||
uint8_t dev_unit_manual:1;
|
||||
};
|
||||
|
||||
struct devclass {
|
||||
device_t dev_list[DEVCLASS_MAXUNIT];
|
||||
};
|
||||
|
||||
struct driver {
|
||||
const char *name;
|
||||
const struct device_method *methods;
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
struct module_data {
|
||||
int (*callback) (struct module *, int, void *arg);
|
||||
void *arg;
|
||||
const char *bus_name;
|
||||
const char *mod_name;
|
||||
const char *long_name;
|
||||
const struct driver *driver;
|
||||
struct devclass **devclass_pp;
|
||||
TAILQ_ENTRY(module_data) entry;
|
||||
};
|
||||
|
||||
device_t device_get_parent(device_t dev);
|
||||
void *device_get_method(device_t dev, const char *what);
|
||||
const char *device_get_name(device_t dev);
|
||||
const char *device_get_nameunit(device_t dev);
|
||||
|
||||
#define device_printf(dev, fmt,...) \
|
||||
printf("%s: " fmt, device_get_nameunit(dev),## __VA_ARGS__)
|
||||
device_t device_add_child(device_t dev, const char *name, int unit);
|
||||
void device_quiet(device_t dev);
|
||||
void device_set_interrupt(device_t dev, intr_fn_t *fn, void *arg);
|
||||
void device_run_interrupts(device_t parent);
|
||||
void device_set_ivars(device_t dev, void *ivars);
|
||||
void *device_get_ivars(device_t dev);
|
||||
const char *device_get_desc(device_t dev);
|
||||
int device_probe_and_attach(device_t dev);
|
||||
int device_detach(device_t dev);
|
||||
void *device_get_softc(device_t dev);
|
||||
void device_set_softc(device_t dev, void *softc);
|
||||
int device_delete_child(device_t dev, device_t child);
|
||||
int device_delete_children(device_t dev);
|
||||
int device_is_attached(device_t dev);
|
||||
void device_set_desc(device_t dev, const char *desc);
|
||||
void device_set_desc_copy(device_t dev, const char *desc);
|
||||
int device_get_unit(device_t dev);
|
||||
void *devclass_get_softc(devclass_t dc, int unit);
|
||||
int devclass_get_maxunit(devclass_t dc);
|
||||
device_t devclass_get_device(devclass_t dc, int unit);
|
||||
devclass_t devclass_find(const char *classname);
|
||||
|
||||
#define bus_get_dma_tag(...) (NULL)
|
||||
int bus_generic_detach(device_t dev);
|
||||
int bus_generic_resume(device_t dev);
|
||||
int bus_generic_shutdown(device_t dev);
|
||||
int bus_generic_suspend(device_t dev);
|
||||
int bus_generic_print_child(device_t dev, device_t child);
|
||||
void bus_generic_driver_added(device_t dev, driver_t *driver);
|
||||
|
||||
/* BUS SPACE API */
|
||||
|
||||
void bus_space_write_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offset, uint8_t data);
|
||||
void bus_space_write_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offset, uint16_t data);
|
||||
void bus_space_write_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offset, uint32_t data);
|
||||
|
||||
uint8_t bus_space_read_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offset);
|
||||
uint16_t bus_space_read_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offset);
|
||||
uint32_t bus_space_read_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offset);
|
||||
|
||||
void bus_space_read_multi_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offset, uint8_t *datap, bus_size_t count);
|
||||
void bus_space_read_multi_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offset, uint16_t *datap, bus_size_t count);
|
||||
void bus_space_read_multi_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offset, uint32_t *datap, bus_size_t count);
|
||||
|
||||
void bus_space_write_multi_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offset, uint8_t *datap, bus_size_t count);
|
||||
void bus_space_write_multi_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offset, uint16_t *datap, bus_size_t count);
|
||||
void bus_space_write_multi_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offset, uint32_t *datap, bus_size_t count);
|
||||
|
||||
void bus_space_read_region_1(bus_space_tag_t space, bus_space_handle_t handle, bus_size_t offset, uint8_t *datap, bus_size_t count);
|
||||
void bus_space_write_region_1(bus_space_tag_t space, bus_space_handle_t handle, bus_size_t offset, uint8_t *datap, bus_size_t count);
|
||||
void bus_space_read_region_4(bus_space_tag_t space, bus_space_handle_t handle, bus_size_t offset, uint32_t *datap, bus_size_t count);
|
||||
void bus_space_write_region_4(bus_space_tag_t space, bus_space_handle_t handle, bus_size_t offset, uint32_t *datap, bus_size_t count);
|
||||
|
||||
void bus_space_barrier(bus_space_tag_t space, bus_space_handle_t handle, bus_size_t offset, bus_size_t length, int flags);
|
||||
|
||||
void module_register(void *);
|
||||
|
||||
/* LIB-C */
|
||||
|
||||
void *memset(void *, int, size_t len);
|
||||
void *memcpy(void *, const void *, size_t len);
|
||||
int printf(const char *,...) __printflike(1, 2);
|
||||
int snprintf(char *restrict str, size_t size, const char *restrict format,...) __printflike(3, 4);
|
||||
size_t strlen(const char *s);
|
||||
|
||||
/* MALLOC API */
|
||||
|
||||
#define malloc(s,x,f) usb_malloc(s)
|
||||
void *usb_malloc(size_t);
|
||||
|
||||
#define free(p,x) usb_free(p)
|
||||
void usb_free(void *);
|
||||
|
||||
#define strdup(p,x) usb_strdup(p)
|
||||
char *usb_strdup(const char *str);
|
||||
|
||||
/* ENDIANNESS */
|
||||
|
||||
/* Assume little endian */
|
||||
|
||||
#define htole64(x) ((uint64_t)(x))
|
||||
#define le64toh(x) ((uint64_t)(x))
|
||||
|
||||
#define htole32(x) ((uint32_t)(x))
|
||||
#define le32toh(x) ((uint32_t)(x))
|
||||
|
||||
#define htole16(x) ((uint16_t)(x))
|
||||
#define le16toh(x) ((uint16_t)(x))
|
||||
|
||||
#define be32toh(x) ((uint32_t)(x))
|
||||
#define htobe32(x) ((uint32_t)(x))
|
||||
|
||||
/* USB */
|
||||
|
||||
typedef int usb_handle_request_t (device_t dev, const void *req, void **pptr, uint16_t *plen, uint16_t offset, uint8_t *pstate);
|
||||
typedef int usb_take_controller_t (device_t dev);
|
||||
|
||||
void usb_idle(void);
|
||||
void usb_init(void);
|
||||
void usb_uninit(void);
|
||||
|
||||
/* set some defaults */
|
||||
|
||||
#ifndef USB_POOL_SIZE
|
||||
#define USB_POOL_SIZE (1024*1024) /* 1 MByte */
|
||||
#endif
|
||||
|
||||
int pause(const char *, int);
|
||||
void DELAY(unsigned int);
|
||||
|
||||
/* OTHER */
|
||||
|
||||
struct selinfo {
|
||||
};
|
||||
|
||||
/* SYSTEM STARTUP API */
|
||||
|
||||
extern const void *sysinit_data[];
|
||||
extern const void *sysuninit_data[];
|
||||
|
||||
#endif /* _BSD_KERNEL_H_ */
|
80
sys/boot/usb/bsd_usbloader_test.c
Normal file
80
sys/boot/usb/bsd_usbloader_test.c
Normal file
@ -0,0 +1,80 @@
|
||||
/* $FreeBSD$ */
|
||||
/*-
|
||||
* Copyright (c) 2013 Hans Petter Selasky. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
extern int usleep(int);
|
||||
extern void callout_process(int);
|
||||
extern void usb_idle(void);
|
||||
extern void usb_init(void);
|
||||
extern void usb_uninit(void);
|
||||
|
||||
#define hz 1000
|
||||
|
||||
void
|
||||
DELAY(unsigned int delay)
|
||||
{
|
||||
usleep(delay);
|
||||
}
|
||||
|
||||
int
|
||||
pause(const char *what, int timeout)
|
||||
{
|
||||
if (timeout == 0)
|
||||
timeout = 1;
|
||||
|
||||
usleep((1000000 / hz) * timeout);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
uint32_t time;
|
||||
|
||||
usb_init();
|
||||
|
||||
time = 0;
|
||||
|
||||
while (1) {
|
||||
|
||||
usb_idle();
|
||||
|
||||
usleep(1000);
|
||||
|
||||
if (++time >= (1000 / hz)) {
|
||||
time = 0;
|
||||
callout_process(1);
|
||||
}
|
||||
}
|
||||
|
||||
usb_uninit();
|
||||
|
||||
return (0);
|
||||
}
|
331
sys/boot/usb/tools/sysinit.c
Normal file
331
sys/boot/usb/tools/sysinit.c
Normal file
@ -0,0 +1,331 @@
|
||||
/* $FreeBSD$ */
|
||||
/*-
|
||||
* Copyright (c) 2013 Hans Petter Selasky. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This utility sorts sysinit structure entries in binary format and
|
||||
* prints out the result in C-format.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <err.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <sysexits.h>
|
||||
#include "sysinit.h"
|
||||
|
||||
static int opt_R;
|
||||
static const char *input_f;
|
||||
static const char *output_f;
|
||||
static const char *struct_name;
|
||||
static const char *keyword;
|
||||
static struct sysinit_data **start;
|
||||
static struct sysinit_data **stop;
|
||||
|
||||
static int input_file = -1;
|
||||
static int output_file = -1;
|
||||
|
||||
static uint8_t *input_ptr;
|
||||
static uint32_t input_len;
|
||||
|
||||
static uint32_t endian32;
|
||||
|
||||
static char scratch_buf[4096];
|
||||
|
||||
static int success;
|
||||
|
||||
static void do_sysinit(void);
|
||||
|
||||
/* the following function converts the numbers into host endian format */
|
||||
|
||||
static uint32_t
|
||||
read32(uint32_t val)
|
||||
{
|
||||
uint32_t temp;
|
||||
uint32_t endian;
|
||||
|
||||
endian = endian32;
|
||||
temp = 0;
|
||||
|
||||
while (val) {
|
||||
temp |= (val & 0xF) << ((endian & 0xF) * 4);
|
||||
endian >>= 4;
|
||||
val >>= 4;
|
||||
}
|
||||
return (temp);
|
||||
}
|
||||
|
||||
static void
|
||||
do_write(int fd, const char *buf)
|
||||
{
|
||||
int len = strlen(buf);
|
||||
|
||||
if (write(fd, buf, len) != len)
|
||||
err(EX_SOFTWARE, "Could not write to output file");
|
||||
}
|
||||
|
||||
static void *
|
||||
do_malloc(int size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
ptr = malloc(size);
|
||||
if (ptr == NULL)
|
||||
errx(EX_SOFTWARE, "Could not allocate memory");
|
||||
return (ptr);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
errx(EX_USAGE, "sysinit -i sysinit.bin -o sysinit_data.c \\\n"
|
||||
"\t" "-k sysinit -s sysinit_data [ -R (reverse)]");
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup(void)
|
||||
{
|
||||
if (output_file >= 0)
|
||||
close(output_file);
|
||||
if (input_file >= 0)
|
||||
close(input_file);
|
||||
if (success == 0) {
|
||||
if (output_f)
|
||||
unlink(output_f);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
compare(const void *_pa, const void *_pb)
|
||||
{
|
||||
const struct sysinit_data * const *pa = _pa;
|
||||
const struct sysinit_data * const *pb = _pb;
|
||||
|
||||
if ((*pa)->dw_msb_value > (*pb)->dw_msb_value)
|
||||
return (1);
|
||||
|
||||
if ((*pa)->dw_msb_value < (*pb)->dw_msb_value)
|
||||
return (-1);
|
||||
|
||||
if ((*pa)->dw_lsb_value > (*pb)->dw_lsb_value)
|
||||
return (1);
|
||||
|
||||
if ((*pa)->dw_lsb_value < (*pb)->dw_lsb_value)
|
||||
return (-1);
|
||||
|
||||
return (0); /* equal */
|
||||
}
|
||||
|
||||
static int
|
||||
compare_R(const void *_pa, const void *_pb)
|
||||
{
|
||||
const struct sysinit_data * const *pa = _pa;
|
||||
const struct sysinit_data * const *pb = _pb;
|
||||
|
||||
if ((*pa)->dw_msb_value > (*pb)->dw_msb_value)
|
||||
return (-1);
|
||||
|
||||
if ((*pa)->dw_msb_value < (*pb)->dw_msb_value)
|
||||
return (1);
|
||||
|
||||
if ((*pa)->dw_lsb_value > (*pb)->dw_lsb_value)
|
||||
return (-1);
|
||||
|
||||
if ((*pa)->dw_lsb_value < (*pb)->dw_lsb_value)
|
||||
return (1);
|
||||
|
||||
return (0); /* equal */
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct sysinit_data **sipp;
|
||||
int c;
|
||||
int entries;
|
||||
off_t off;
|
||||
|
||||
while ((c = getopt(argc, argv, "k:s:i:o:Rh")) != -1) {
|
||||
switch (c) {
|
||||
case 'i':
|
||||
input_f = optarg;
|
||||
break;
|
||||
case 'o':
|
||||
output_f = optarg;
|
||||
break;
|
||||
case 'R':
|
||||
opt_R = 1;
|
||||
break;
|
||||
case 'k':
|
||||
keyword = optarg;
|
||||
break;
|
||||
case 's':
|
||||
struct_name = optarg;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
if (input_f == NULL || output_f == NULL ||
|
||||
struct_name == NULL || keyword == NULL)
|
||||
usage();
|
||||
|
||||
atexit(&cleanup);
|
||||
|
||||
cleanup();
|
||||
|
||||
input_file = open(input_f, O_RDONLY);
|
||||
if (input_file < 0)
|
||||
err(EX_SOFTWARE, "Could not open input file: %s", input_f);
|
||||
|
||||
output_file = open(output_f, O_TRUNC | O_CREAT | O_RDWR, 0600);
|
||||
if (output_file < 0)
|
||||
err(EX_SOFTWARE, "Could not open output file: %s", output_f);
|
||||
|
||||
off = lseek(input_file, 0, SEEK_END);
|
||||
|
||||
input_ptr = do_malloc(off);
|
||||
input_len = off;
|
||||
|
||||
if (input_len % (uint32_t)sizeof(struct sysinit_data)) {
|
||||
errx(EX_SOFTWARE, "Input file size is not divisible by %u",
|
||||
(unsigned int)sizeof(struct sysinit_data));
|
||||
}
|
||||
off = lseek(input_file, 0, SEEK_SET);
|
||||
if (off < 0)
|
||||
err(EX_SOFTWARE, "Could not seek to start of input file");
|
||||
|
||||
if (read(input_file, input_ptr, input_len) != input_len)
|
||||
err(EX_SOFTWARE, "Could not read input file");
|
||||
|
||||
entries = input_len / (uint32_t)sizeof(struct sysinit_data);
|
||||
|
||||
start = do_malloc(sizeof(void *) * entries);
|
||||
stop = start + entries;
|
||||
|
||||
for (c = 0; c != entries; c++)
|
||||
start[c] = &((struct sysinit_data *)input_ptr)[c];
|
||||
|
||||
if (start != stop)
|
||||
endian32 = (*start)->dw_endian32;
|
||||
|
||||
/* switch all fields to host endian order */
|
||||
for (sipp = start; sipp < stop; sipp++) {
|
||||
(*sipp)->dw_lsb_value = read32((*sipp)->dw_lsb_value);
|
||||
(*sipp)->dw_msb_value = read32((*sipp)->dw_msb_value);
|
||||
(*sipp)->dw_file_line = read32((*sipp)->dw_file_line);
|
||||
}
|
||||
|
||||
if (opt_R == 0) {
|
||||
/* sort entries, rising numerical order */
|
||||
qsort(start, entries, sizeof(void *), &compare);
|
||||
} else {
|
||||
/* sort entries, falling numerical order */
|
||||
qsort(start, entries, sizeof(void *), &compare_R);
|
||||
}
|
||||
|
||||
/* safe all strings */
|
||||
for (sipp = start; sipp < stop; sipp++) {
|
||||
(*sipp)->b_keyword_name[sizeof((*sipp)->b_keyword_name) - 1] = 0;
|
||||
(*sipp)->b_global_type[sizeof((*sipp)->b_global_type) - 1] = 0;
|
||||
(*sipp)->b_global_name[sizeof((*sipp)->b_global_name) - 1] = 0;
|
||||
(*sipp)->b_file_name[sizeof((*sipp)->b_file_name) - 1] = 0;
|
||||
(*sipp)->b_debug_info[sizeof((*sipp)->b_debug_info) - 1] = 0;
|
||||
}
|
||||
|
||||
if (strcmp(keyword, "sysinit") == 0)
|
||||
do_sysinit();
|
||||
else if (strcmp(keyword, "sysuninit") == 0)
|
||||
do_sysinit();
|
||||
else
|
||||
errx(EX_USAGE, "Unknown keyword '%s'", keyword);
|
||||
|
||||
success = 1;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
do_sysinit(void)
|
||||
{
|
||||
struct sysinit_data **sipp;
|
||||
int c;
|
||||
|
||||
snprintf(scratch_buf, sizeof(scratch_buf),
|
||||
"/*\n"
|
||||
" * This file was automatically generated.\n"
|
||||
" * Please do not edit.\n"
|
||||
" */\n\n");
|
||||
|
||||
/* write out externals */
|
||||
for (c = 0, sipp = start; sipp < stop; c++, sipp++) {
|
||||
if (strcmp((const char *)(*sipp)->b_keyword_name, keyword))
|
||||
continue;
|
||||
if ((*sipp)->dw_msb_value == 0)
|
||||
continue;
|
||||
|
||||
snprintf(scratch_buf, sizeof(scratch_buf),
|
||||
"/* #%04u: %s entry at %s:%u */\n",
|
||||
c, (*sipp)->b_debug_info, (*sipp)->b_file_name,
|
||||
(unsigned int)(*sipp)->dw_file_line);
|
||||
|
||||
do_write(output_file, scratch_buf);
|
||||
|
||||
snprintf(scratch_buf, sizeof(scratch_buf),
|
||||
"extern %s %s;\n\n", (*sipp)->b_global_type,
|
||||
(*sipp)->b_global_name);
|
||||
|
||||
do_write(output_file, scratch_buf);
|
||||
}
|
||||
|
||||
snprintf(scratch_buf, sizeof(scratch_buf),
|
||||
"const void *%s[] = {\n", struct_name);
|
||||
|
||||
do_write(output_file, scratch_buf);
|
||||
|
||||
/* write out actual table */
|
||||
for (c = 0, sipp = start; sipp < stop; c++, sipp++) {
|
||||
if (strcmp((const char *)(*sipp)->b_keyword_name, keyword))
|
||||
continue;
|
||||
if ((*sipp)->dw_msb_value == 0)
|
||||
continue;
|
||||
|
||||
snprintf(scratch_buf, sizeof(scratch_buf),
|
||||
"\t&%s, /* #%04u */\n",
|
||||
(*sipp)->b_global_name, (unsigned int)c);
|
||||
|
||||
do_write(output_file, scratch_buf);
|
||||
}
|
||||
|
||||
snprintf(scratch_buf, sizeof(scratch_buf),
|
||||
"\t(const void *)0\n"
|
||||
"};\n");
|
||||
|
||||
do_write(output_file, scratch_buf);
|
||||
}
|
57
sys/boot/usb/tools/sysinit.h
Normal file
57
sys/boot/usb/tools/sysinit.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* $FreeBSD$ */
|
||||
/*-
|
||||
* Copyright (c) 2013 Hans Petter Selasky. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
#ifndef _SYSINIT_H_
|
||||
#define _SYSINIT_H_
|
||||
|
||||
struct sysinit_data {
|
||||
uint8_t b_keyword_name[64];
|
||||
uint8_t b_debug_info[128];
|
||||
uint8_t b_global_type[128];
|
||||
uint8_t b_global_name[128];
|
||||
uint8_t b_file_name[256];
|
||||
uint32_t dw_endian32;
|
||||
uint32_t dw_msb_value; /* must be non-zero, else entry is skipped */
|
||||
uint32_t dw_lsb_value;
|
||||
uint32_t dw_file_line;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define SYSINIT_ENTRY(uniq, keyword, msb, lsb, g_type, g_name, debug) \
|
||||
static const struct sysinit_data sysinit_##uniq \
|
||||
__attribute__((__section__(".debug.sysinit"), \
|
||||
__used__, __aligned__(1))) = { \
|
||||
.b_keyword_name = { keyword }, \
|
||||
.b_debug_info = { debug }, \
|
||||
.b_global_type = { g_type }, \
|
||||
.b_global_name = { g_name }, \
|
||||
.b_file_name = { __FILE__ }, \
|
||||
.dw_endian32 = 0x76543210U, \
|
||||
.dw_msb_value = (msb), \
|
||||
.dw_lsb_value = (lsb), \
|
||||
.dw_file_line = __LINE__ \
|
||||
}
|
||||
|
||||
#endif /* _SYSINIT_H_ */
|
619
sys/boot/usb/usb_busdma_loader.c
Normal file
619
sys/boot/usb/usb_busdma_loader.c
Normal file
@ -0,0 +1,619 @@
|
||||
/* $FreeBSD$ */
|
||||
/*-
|
||||
* Copyright (c) 2013 Hans Petter Selasky. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
#include <bsd_global.h>
|
||||
|
||||
#if USB_HAVE_BUSDMA
|
||||
static void usb_pc_common_mem_cb(struct usb_page_cache *pc,
|
||||
void *vaddr, uint32_t length);
|
||||
#endif
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usbd_get_page - lookup DMA-able memory for the given offset
|
||||
*
|
||||
* NOTE: Only call this function when the "page_cache" structure has
|
||||
* been properly initialized !
|
||||
*------------------------------------------------------------------------*/
|
||||
void
|
||||
usbd_get_page(struct usb_page_cache *pc, usb_frlength_t offset,
|
||||
struct usb_page_search *res)
|
||||
{
|
||||
#if USB_HAVE_BUSDMA
|
||||
struct usb_page *page;
|
||||
|
||||
if (pc->page_start) {
|
||||
|
||||
/* Case 1 - something has been loaded into DMA */
|
||||
|
||||
if (pc->buffer) {
|
||||
|
||||
/* Case 1a - Kernel Virtual Address */
|
||||
|
||||
res->buffer = USB_ADD_BYTES(pc->buffer, offset);
|
||||
}
|
||||
offset += pc->page_offset_buf;
|
||||
|
||||
/* compute destination page */
|
||||
|
||||
page = pc->page_start;
|
||||
|
||||
if (pc->ismultiseg) {
|
||||
|
||||
page += (offset / USB_PAGE_SIZE);
|
||||
|
||||
offset %= USB_PAGE_SIZE;
|
||||
|
||||
res->length = USB_PAGE_SIZE - offset;
|
||||
res->physaddr = page->physaddr + offset;
|
||||
} else {
|
||||
res->length = (usb_size_t)-1;
|
||||
res->physaddr = page->physaddr + offset;
|
||||
}
|
||||
if (!pc->buffer) {
|
||||
|
||||
/* Case 1b - Non Kernel Virtual Address */
|
||||
|
||||
res->buffer = USB_ADD_BYTES(page->buffer, offset);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
/* Case 2 - Plain PIO */
|
||||
|
||||
res->buffer = USB_ADD_BYTES(pc->buffer, offset);
|
||||
res->length = (usb_size_t)-1;
|
||||
#if USB_HAVE_BUSDMA
|
||||
res->physaddr = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usbd_copy_in - copy directly to DMA-able memory
|
||||
*------------------------------------------------------------------------*/
|
||||
void
|
||||
usbd_copy_in(struct usb_page_cache *cache, usb_frlength_t offset,
|
||||
const void *ptr, usb_frlength_t len)
|
||||
{
|
||||
struct usb_page_search buf_res;
|
||||
|
||||
while (len != 0) {
|
||||
|
||||
usbd_get_page(cache, offset, &buf_res);
|
||||
|
||||
if (buf_res.length > len) {
|
||||
buf_res.length = len;
|
||||
}
|
||||
memcpy(buf_res.buffer, ptr, buf_res.length);
|
||||
|
||||
offset += buf_res.length;
|
||||
len -= buf_res.length;
|
||||
ptr = USB_ADD_BYTES(ptr, buf_res.length);
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usbd_copy_out - copy directly from DMA-able memory
|
||||
*------------------------------------------------------------------------*/
|
||||
void
|
||||
usbd_copy_out(struct usb_page_cache *cache, usb_frlength_t offset,
|
||||
void *ptr, usb_frlength_t len)
|
||||
{
|
||||
struct usb_page_search res;
|
||||
|
||||
while (len != 0) {
|
||||
|
||||
usbd_get_page(cache, offset, &res);
|
||||
|
||||
if (res.length > len) {
|
||||
res.length = len;
|
||||
}
|
||||
memcpy(ptr, res.buffer, res.length);
|
||||
|
||||
offset += res.length;
|
||||
len -= res.length;
|
||||
ptr = USB_ADD_BYTES(ptr, res.length);
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usbd_frame_zero - zero DMA-able memory
|
||||
*------------------------------------------------------------------------*/
|
||||
void
|
||||
usbd_frame_zero(struct usb_page_cache *cache, usb_frlength_t offset,
|
||||
usb_frlength_t len)
|
||||
{
|
||||
struct usb_page_search res;
|
||||
|
||||
while (len != 0) {
|
||||
|
||||
usbd_get_page(cache, offset, &res);
|
||||
|
||||
if (res.length > len) {
|
||||
res.length = len;
|
||||
}
|
||||
memset(res.buffer, 0, res.length);
|
||||
|
||||
offset += res.length;
|
||||
len -= res.length;
|
||||
}
|
||||
}
|
||||
|
||||
#if USB_HAVE_BUSDMA
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usb_pc_common_mem_cb - BUS-DMA callback function
|
||||
*------------------------------------------------------------------------*/
|
||||
static void
|
||||
usb_pc_common_mem_cb(struct usb_page_cache *pc,
|
||||
void *vaddr, uint32_t length)
|
||||
{
|
||||
struct usb_page *pg;
|
||||
usb_size_t rem;
|
||||
bus_size_t off;
|
||||
bus_addr_t phys = (uintptr_t)vaddr; /* XXX */
|
||||
uint32_t nseg;
|
||||
|
||||
if (length == 0)
|
||||
nseg = 1;
|
||||
else
|
||||
nseg = ((length + USB_PAGE_SIZE - 1) / USB_PAGE_SIZE);
|
||||
|
||||
pg = pc->page_start;
|
||||
pg->physaddr = phys & ~(USB_PAGE_SIZE - 1);
|
||||
rem = phys & (USB_PAGE_SIZE - 1);
|
||||
pc->page_offset_buf = rem;
|
||||
pc->page_offset_end += rem;
|
||||
length += rem;
|
||||
|
||||
for (off = USB_PAGE_SIZE; off < length; off += USB_PAGE_SIZE) {
|
||||
pg++;
|
||||
pg->physaddr = (phys + off) & ~(USB_PAGE_SIZE - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usb_pc_alloc_mem - allocate DMA'able memory
|
||||
*
|
||||
* Returns:
|
||||
* 0: Success
|
||||
* Else: Failure
|
||||
*------------------------------------------------------------------------*/
|
||||
uint8_t
|
||||
usb_pc_alloc_mem(struct usb_page_cache *pc, struct usb_page *pg,
|
||||
usb_size_t size, usb_size_t align)
|
||||
{
|
||||
void *ptr;
|
||||
uint32_t rem;
|
||||
|
||||
/* allocate zeroed memory */
|
||||
|
||||
if (align != 1) {
|
||||
ptr = usb_malloc(size + align);
|
||||
if (ptr == NULL)
|
||||
goto error;
|
||||
|
||||
rem = (-((uintptr_t)ptr)) & (align - 1);
|
||||
} else {
|
||||
ptr = usb_malloc(size);
|
||||
if (ptr == NULL)
|
||||
goto error;
|
||||
rem = 0;
|
||||
}
|
||||
|
||||
/* setup page cache */
|
||||
pc->buffer = ((uint8_t *)ptr) + rem;
|
||||
pc->page_start = pg;
|
||||
pc->page_offset_buf = 0;
|
||||
pc->page_offset_end = size;
|
||||
pc->map = NULL;
|
||||
pc->tag = ptr;
|
||||
pc->ismultiseg = (align == 1);
|
||||
|
||||
/* compute physical address */
|
||||
usb_pc_common_mem_cb(pc, ptr, size);
|
||||
|
||||
usb_pc_cpu_flush(pc);
|
||||
return (0);
|
||||
|
||||
error:
|
||||
/* reset most of the page cache */
|
||||
pc->buffer = NULL;
|
||||
pc->page_start = NULL;
|
||||
pc->page_offset_buf = 0;
|
||||
pc->page_offset_end = 0;
|
||||
pc->map = NULL;
|
||||
pc->tag = NULL;
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usb_pc_free_mem - free DMA memory
|
||||
*
|
||||
* This function is NULL safe.
|
||||
*------------------------------------------------------------------------*/
|
||||
void
|
||||
usb_pc_free_mem(struct usb_page_cache *pc)
|
||||
{
|
||||
if (pc != NULL && pc->buffer != NULL) {
|
||||
usb_free(pc->tag);
|
||||
pc->buffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usb_pc_load_mem - load virtual memory into DMA
|
||||
*
|
||||
* Return values:
|
||||
* 0: Success
|
||||
* Else: Error
|
||||
*------------------------------------------------------------------------*/
|
||||
uint8_t
|
||||
usb_pc_load_mem(struct usb_page_cache *pc, usb_size_t size, uint8_t sync)
|
||||
{
|
||||
/* setup page cache */
|
||||
pc->page_offset_buf = 0;
|
||||
pc->page_offset_end = size;
|
||||
pc->ismultiseg = 1;
|
||||
|
||||
mtx_assert(pc->tag_parent->mtx, MA_OWNED);
|
||||
|
||||
if (size > 0) {
|
||||
/* compute physical address */
|
||||
usb_pc_common_mem_cb(pc, pc->buffer, size);
|
||||
}
|
||||
if (sync == 0) {
|
||||
/*
|
||||
* Call callback so that refcount is decremented
|
||||
* properly:
|
||||
*/
|
||||
pc->tag_parent->dma_error = 0;
|
||||
(pc->tag_parent->func) (pc->tag_parent);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usb_pc_cpu_invalidate - invalidate CPU cache
|
||||
*------------------------------------------------------------------------*/
|
||||
void
|
||||
usb_pc_cpu_invalidate(struct usb_page_cache *pc)
|
||||
{
|
||||
if (pc->page_offset_end == pc->page_offset_buf) {
|
||||
/* nothing has been loaded into this page cache! */
|
||||
return;
|
||||
}
|
||||
/* NOP */
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usb_pc_cpu_flush - flush CPU cache
|
||||
*------------------------------------------------------------------------*/
|
||||
void
|
||||
usb_pc_cpu_flush(struct usb_page_cache *pc)
|
||||
{
|
||||
if (pc->page_offset_end == pc->page_offset_buf) {
|
||||
/* nothing has been loaded into this page cache! */
|
||||
return;
|
||||
}
|
||||
/* NOP */
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usb_pc_dmamap_create - create a DMA map
|
||||
*
|
||||
* Returns:
|
||||
* 0: Success
|
||||
* Else: Failure
|
||||
*------------------------------------------------------------------------*/
|
||||
uint8_t
|
||||
usb_pc_dmamap_create(struct usb_page_cache *pc, usb_size_t size)
|
||||
{
|
||||
return (0); /* NOP, success */
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usb_pc_dmamap_destroy
|
||||
*
|
||||
* This function is NULL safe.
|
||||
*------------------------------------------------------------------------*/
|
||||
void
|
||||
usb_pc_dmamap_destroy(struct usb_page_cache *pc)
|
||||
{
|
||||
/* NOP */
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usb_dma_tag_setup - initialise USB DMA tags
|
||||
*------------------------------------------------------------------------*/
|
||||
void
|
||||
usb_dma_tag_setup(struct usb_dma_parent_tag *udpt,
|
||||
struct usb_dma_tag *udt, bus_dma_tag_t dmat,
|
||||
struct mtx *mtx, usb_dma_callback_t *func,
|
||||
uint8_t ndmabits, uint8_t nudt)
|
||||
{
|
||||
memset(udpt, 0, sizeof(*udpt));
|
||||
|
||||
/* sanity checking */
|
||||
if ((nudt == 0) ||
|
||||
(ndmabits == 0) ||
|
||||
(mtx == NULL)) {
|
||||
/* something is corrupt */
|
||||
return;
|
||||
}
|
||||
/* initialise condition variable */
|
||||
cv_init(udpt->cv, "USB DMA CV");
|
||||
|
||||
/* store some information */
|
||||
udpt->mtx = mtx;
|
||||
udpt->func = func;
|
||||
udpt->tag = dmat;
|
||||
udpt->utag_first = udt;
|
||||
udpt->utag_max = nudt;
|
||||
udpt->dma_bits = ndmabits;
|
||||
|
||||
while (nudt--) {
|
||||
memset(udt, 0, sizeof(*udt));
|
||||
udt->tag_parent = udpt;
|
||||
udt++;
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usb_bus_tag_unsetup - factored out code
|
||||
*------------------------------------------------------------------------*/
|
||||
void
|
||||
usb_dma_tag_unsetup(struct usb_dma_parent_tag *udpt)
|
||||
{
|
||||
struct usb_dma_tag *udt;
|
||||
uint8_t nudt;
|
||||
|
||||
udt = udpt->utag_first;
|
||||
nudt = udpt->utag_max;
|
||||
|
||||
while (nudt--) {
|
||||
udt->align = 0;
|
||||
udt++;
|
||||
}
|
||||
|
||||
if (udpt->utag_max) {
|
||||
/* destroy the condition variable */
|
||||
cv_destroy(udpt->cv);
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usb_bdma_work_loop
|
||||
*
|
||||
* This function handles loading of virtual buffers into DMA and is
|
||||
* only called when "dma_refcount" is zero.
|
||||
*------------------------------------------------------------------------*/
|
||||
void
|
||||
usb_bdma_work_loop(struct usb_xfer_queue *pq)
|
||||
{
|
||||
struct usb_xfer_root *info;
|
||||
struct usb_xfer *xfer;
|
||||
usb_frcount_t nframes;
|
||||
|
||||
xfer = pq->curr;
|
||||
info = xfer->xroot;
|
||||
|
||||
mtx_assert(info->xfer_mtx, MA_OWNED);
|
||||
|
||||
if (xfer->error) {
|
||||
/* some error happened */
|
||||
USB_BUS_LOCK(info->bus);
|
||||
usbd_transfer_done(xfer, 0);
|
||||
USB_BUS_UNLOCK(info->bus);
|
||||
return;
|
||||
}
|
||||
if (!xfer->flags_int.bdma_setup) {
|
||||
struct usb_page *pg;
|
||||
usb_frlength_t frlength_0;
|
||||
uint8_t isread;
|
||||
|
||||
xfer->flags_int.bdma_setup = 1;
|
||||
|
||||
/* reset BUS-DMA load state */
|
||||
|
||||
info->dma_error = 0;
|
||||
|
||||
if (xfer->flags_int.isochronous_xfr) {
|
||||
/* only one frame buffer */
|
||||
nframes = 1;
|
||||
frlength_0 = xfer->sumlen;
|
||||
} else {
|
||||
/* can be multiple frame buffers */
|
||||
nframes = xfer->nframes;
|
||||
frlength_0 = xfer->frlengths[0];
|
||||
}
|
||||
|
||||
/*
|
||||
* Set DMA direction first. This is needed to
|
||||
* select the correct cache invalidate and cache
|
||||
* flush operations.
|
||||
*/
|
||||
isread = USB_GET_DATA_ISREAD(xfer);
|
||||
pg = xfer->dma_page_ptr;
|
||||
|
||||
if (xfer->flags_int.control_xfr &&
|
||||
xfer->flags_int.control_hdr) {
|
||||
/* special case */
|
||||
if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) {
|
||||
/* The device controller writes to memory */
|
||||
xfer->frbuffers[0].isread = 1;
|
||||
} else {
|
||||
/* The host controller reads from memory */
|
||||
xfer->frbuffers[0].isread = 0;
|
||||
}
|
||||
} else {
|
||||
/* default case */
|
||||
xfer->frbuffers[0].isread = isread;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup the "page_start" pointer which points to an array of
|
||||
* USB pages where information about the physical address of a
|
||||
* page will be stored. Also initialise the "isread" field of
|
||||
* the USB page caches.
|
||||
*/
|
||||
xfer->frbuffers[0].page_start = pg;
|
||||
|
||||
info->dma_nframes = nframes;
|
||||
info->dma_currframe = 0;
|
||||
info->dma_frlength_0 = frlength_0;
|
||||
|
||||
pg += (frlength_0 / USB_PAGE_SIZE);
|
||||
pg += 2;
|
||||
|
||||
while (--nframes > 0) {
|
||||
xfer->frbuffers[nframes].isread = isread;
|
||||
xfer->frbuffers[nframes].page_start = pg;
|
||||
|
||||
pg += (xfer->frlengths[nframes] / USB_PAGE_SIZE);
|
||||
pg += 2;
|
||||
}
|
||||
|
||||
}
|
||||
if (info->dma_error) {
|
||||
USB_BUS_LOCK(info->bus);
|
||||
usbd_transfer_done(xfer, USB_ERR_DMA_LOAD_FAILED);
|
||||
USB_BUS_UNLOCK(info->bus);
|
||||
return;
|
||||
}
|
||||
if (info->dma_currframe != info->dma_nframes) {
|
||||
|
||||
if (info->dma_currframe == 0) {
|
||||
/* special case */
|
||||
usb_pc_load_mem(xfer->frbuffers,
|
||||
info->dma_frlength_0, 0);
|
||||
} else {
|
||||
/* default case */
|
||||
nframes = info->dma_currframe;
|
||||
usb_pc_load_mem(xfer->frbuffers + nframes,
|
||||
xfer->frlengths[nframes], 0);
|
||||
}
|
||||
|
||||
/* advance frame index */
|
||||
info->dma_currframe++;
|
||||
|
||||
return;
|
||||
}
|
||||
/* go ahead */
|
||||
usb_bdma_pre_sync(xfer);
|
||||
|
||||
/* start loading next USB transfer, if any */
|
||||
usb_command_wrapper(pq, NULL);
|
||||
|
||||
/* finally start the hardware */
|
||||
usbd_pipe_enter(xfer);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usb_bdma_done_event
|
||||
*
|
||||
* This function is called when the BUS-DMA has loaded virtual memory
|
||||
* into DMA, if any.
|
||||
*------------------------------------------------------------------------*/
|
||||
void
|
||||
usb_bdma_done_event(struct usb_dma_parent_tag *udpt)
|
||||
{
|
||||
struct usb_xfer_root *info;
|
||||
|
||||
info = USB_DMATAG_TO_XROOT(udpt);
|
||||
|
||||
mtx_assert(info->xfer_mtx, MA_OWNED);
|
||||
|
||||
/* copy error */
|
||||
info->dma_error = udpt->dma_error;
|
||||
|
||||
/* enter workloop again */
|
||||
usb_command_wrapper(&info->dma_q,
|
||||
info->dma_q.curr);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usb_bdma_pre_sync
|
||||
*
|
||||
* This function handles DMA synchronisation that must be done before
|
||||
* an USB transfer is started.
|
||||
*------------------------------------------------------------------------*/
|
||||
void
|
||||
usb_bdma_pre_sync(struct usb_xfer *xfer)
|
||||
{
|
||||
struct usb_page_cache *pc;
|
||||
usb_frcount_t nframes;
|
||||
|
||||
if (xfer->flags_int.isochronous_xfr) {
|
||||
/* only one frame buffer */
|
||||
nframes = 1;
|
||||
} else {
|
||||
/* can be multiple frame buffers */
|
||||
nframes = xfer->nframes;
|
||||
}
|
||||
|
||||
pc = xfer->frbuffers;
|
||||
|
||||
while (nframes--) {
|
||||
|
||||
if (pc->isread) {
|
||||
usb_pc_cpu_invalidate(pc);
|
||||
} else {
|
||||
usb_pc_cpu_flush(pc);
|
||||
}
|
||||
pc++;
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usb_bdma_post_sync
|
||||
*
|
||||
* This function handles DMA synchronisation that must be done after
|
||||
* an USB transfer is complete.
|
||||
*------------------------------------------------------------------------*/
|
||||
void
|
||||
usb_bdma_post_sync(struct usb_xfer *xfer)
|
||||
{
|
||||
struct usb_page_cache *pc;
|
||||
usb_frcount_t nframes;
|
||||
|
||||
if (xfer->flags_int.isochronous_xfr) {
|
||||
/* only one frame buffer */
|
||||
nframes = 1;
|
||||
} else {
|
||||
/* can be multiple frame buffers */
|
||||
nframes = xfer->nframes;
|
||||
}
|
||||
|
||||
pc = xfer->frbuffers;
|
||||
|
||||
while (nframes--) {
|
||||
if (pc->isread) {
|
||||
usb_pc_cpu_invalidate(pc);
|
||||
}
|
||||
pc++;
|
||||
}
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user