diff options
author | kevans <kevans@FreeBSD.org> | 2018-02-12 01:08:44 +0000 |
---|---|---|
committer | kevans <kevans@FreeBSD.org> | 2018-02-12 01:08:44 +0000 |
commit | 7d97ee5b28b409c00bfaf12daf5ab497a6038b9d (patch) | |
tree | 245306b754606bcf49c0ff17b131b58609b6c7a6 /stand/usb | |
parent | 43b278e1b66cf4de337a17034087ea785031bd6f (diff) | |
download | FreeBSD-src-7d97ee5b28b409c00bfaf12daf5ab497a6038b9d.zip FreeBSD-src-7d97ee5b28b409c00bfaf12daf5ab497a6038b9d.tar.gz |
MFC r325834,r325997,326502: Move sys/boot to stand/
This is effectively a direct commit to stable/11, due to differences between
stable/11 and head. Changes to DTS in sys/boot/fdt/dts were often
accompanied by kernel changes. Many of these were also risc-v updates that
likely had many more dependencies to MFC.
Because of this, sys/boot/fdt/dts remains as-is while everything else in
sys/boot relocates to stand/.
r325834: Move sys/boot to stand. Fix all references to new location
r325997: Remove empty directories.
r326502: Document the sys/boot -> stand move in hier.7 and the top-level README.
Diffstat (limited to 'stand/usb')
-rw-r--r-- | stand/usb/Makefile | 58 | ||||
-rw-r--r-- | stand/usb/Makefile.test | 61 | ||||
-rw-r--r-- | stand/usb/bsd_usbloader_test.c | 101 | ||||
-rw-r--r-- | stand/usb/storage/umass_common.c | 90 | ||||
-rw-r--r-- | stand/usb/storage/umass_common.h | 41 | ||||
-rw-r--r-- | stand/usb/storage/umass_loader.c | 239 | ||||
-rw-r--r-- | stand/usb/tools/Makefile | 10 | ||||
-rw-r--r-- | stand/usb/tools/sysinit.c | 331 | ||||
-rw-r--r-- | stand/usb/usb_busdma_loader.c | 619 | ||||
-rw-r--r-- | stand/usb/usbcore.mk | 175 |
10 files changed, 1725 insertions, 0 deletions
diff --git a/stand/usb/Makefile b/stand/usb/Makefile new file mode 100644 index 0000000..1b94b3d --- /dev/null +++ b/stand/usb/Makefile @@ -0,0 +1,58 @@ +# +# $FreeBSD$ +# +# Copyright (c) 2013 Hans Petter Selasky. +# Copyright (c) 2014 SRI International +# All rights reserved. +# +# This software was developed by SRI International and the University of +# Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237 +# ("CTSRD"), as part of the DARPA CRASH research programme. +# +# 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. +# + +LIB= usbboot +INTERNALLIB= + +CFLAGS+= -DBOOTPROG=\"usbloader\" +CFLAGS+= -ffunction-sections -fdata-sections +CFLAGS+= -ffreestanding +CFLAGS+= -Wformat -Wall +CFLAGS+= -g +CFLAGS+= -fno-pic + +.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64" +CFLAGS+= -march=i386 +CFLAGS.gcc+= -mpreferred-stack-boundary=2 +.endif +.if ${MACHINE_CPUARCH} == "amd64" +CFLAGS+= -m32 +.endif +.if ${MACHINE_CPUARCH} == "mips" +CFLAGS+= -mno-abicalls +.endif + + +.include "usbcore.mk" +.include "../kshim/kshim.mk" +.include <bsd.lib.mk> diff --git a/stand/usb/Makefile.test b/stand/usb/Makefile.test new file mode 100644 index 0000000..7c6a66d1 --- /dev/null +++ b/stand/usb/Makefile.test @@ -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.gcc+= -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 + +.include <bsd.prog.mk> + +${PROG}: libusbboot.a + +libusbboot.a: + make -f Makefile diff --git a/stand/usb/bsd_usbloader_test.c b/stand/usb/bsd_usbloader_test.c new file mode 100644 index 0000000..35140b8 --- /dev/null +++ b/stand/usb/bsd_usbloader_test.c @@ -0,0 +1,101 @@ +/* $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 <stdlib.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 + +#ifdef HAVE_MALLOC +void * +usb_malloc(size_t size) +{ + return (malloc(size)); +} + +void +usb_free(void *ptr) +{ + free(ptr); +} +#endif + +void +DELAY(unsigned int delay) +{ + usleep(delay); +} + +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); +} diff --git a/stand/usb/storage/umass_common.c b/stand/usb/storage/umass_common.c new file mode 100644 index 0000000..5ddd159 --- /dev/null +++ b/stand/usb/storage/umass_common.c @@ -0,0 +1,90 @@ +/* $FreeBSD$ */ +/*- + * Copyright (c) 2014 Hans Petter Selasky <hselasky@FreeBSD.org> + * All rights reserved. + * + * This software was developed by SRI International and the University of + * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) + * ("CTSRD"), as part of the DARPA CRASH research programme. + * + * 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 USB_GLOBAL_INCLUDE_FILE + +#include "umass_common.h" + +struct usb_attach_arg umass_uaa; + +static device_probe_t umass_probe; +static device_attach_t umass_attach; +static device_detach_t umass_detach; + +static devclass_t umass_devclass; + +static device_method_t umass_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, umass_probe), + DEVMETHOD(device_attach, umass_attach), + DEVMETHOD(device_detach, umass_detach), + + DEVMETHOD_END +}; + +static driver_t umass_driver = { + .name = "umass", + .methods = umass_methods, +}; + +DRIVER_MODULE(umass, uhub, umass_driver, umass_devclass, NULL, 0); + +static int +umass_probe(device_t dev) +{ + struct usb_attach_arg *uaa = device_get_ivars(dev); + + if (uaa->usb_mode != USB_MODE_HOST || + uaa->info.bInterfaceClass != UICLASS_MASS || + uaa->info.bInterfaceSubClass != UISUBCLASS_SCSI || + uaa->info.bInterfaceProtocol != UIPROTO_MASS_BBB || + device_get_unit(dev) != 0) + return (ENXIO); + return (0); +} + +static int +umass_attach(device_t dev) +{ + struct usb_attach_arg *uaa = device_get_ivars(dev); + umass_uaa = *uaa; + return (0); /* success */ +} + +static int +umass_detach(device_t dev) +{ + +#ifdef USB_DEBUG + memset(&umass_uaa, 0, sizeof(umass_uaa)); +#endif + return (0); +} diff --git a/stand/usb/storage/umass_common.h b/stand/usb/storage/umass_common.h new file mode 100644 index 0000000..a8ffd49 --- /dev/null +++ b/stand/usb/storage/umass_common.h @@ -0,0 +1,41 @@ +/* $FreeBSD$ */ +/*- + * Copyright (c) 2014 Hans Petter Selasky <hselasky@FreeBSD.org> + * All rights reserved. + * + * This software was developed by SRI International and the University of + * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) + * ("CTSRD"), as part of the DARPA CRASH research programme. + * + * 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 _UMASS_COMMON_H_ +#define _UMASS_COMMON_H_ + +struct usb_attach_arg; +struct devsw; + +extern struct usb_attach_arg umass_uaa; +extern struct devsw umass_disk; + +#endif /* _UMASS_COMMON_H_ */ diff --git a/stand/usb/storage/umass_loader.c b/stand/usb/storage/umass_loader.c new file mode 100644 index 0000000..fbb890b --- /dev/null +++ b/stand/usb/storage/umass_loader.c @@ -0,0 +1,239 @@ +/* $FreeBSD$ */ +/*- + * Copyright (c) 2014 Hans Petter Selasky <hselasky@FreeBSD.org> + * All rights reserved. + * + * This software was developed by SRI International and the University of + * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) + * ("CTSRD"), as part of the DARPA CRASH research programme. + * + * 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 <sys/param.h> + +#include <bootstrap.h> +#include <stdarg.h> + +#include <stand.h> +#include <disk.h> + +#define HAVE_STANDARD_DEFS + +#include USB_GLOBAL_INCLUDE_FILE + +#include "umass_common.h" + +static int umass_disk_init(void); +static int umass_disk_open(struct open_file *,...); +static int umass_disk_close(struct open_file *); +static void umass_disk_cleanup(void); +static int umass_disk_ioctl(struct open_file *, u_long, void *); +static int umass_disk_strategy(void *, int, daddr_t, size_t, char *, size_t *); +static int umass_disk_print(int); + +struct devsw umass_disk = { + .dv_name = "umass", + .dv_type = DEVT_DISK, + .dv_init = umass_disk_init, + .dv_strategy = umass_disk_strategy, + .dv_open = umass_disk_open, + .dv_close = umass_disk_close, + .dv_ioctl = umass_disk_ioctl, + .dv_print = umass_disk_print, + .dv_cleanup = umass_disk_cleanup, +}; + +static int +umass_disk_init(void) +{ + uint32_t time; + + usb_init(); + usb_needs_explore_all(); + + /* wait 8 seconds for a USB mass storage device to appear */ + for (time = 0; time < (8 * hz); time++) { + usb_idle(); + delay(1000000 / hz); + time++; + callout_process(1); + if (umass_uaa.device != NULL) + return (0); + } + return (0); +} + +static int +umass_disk_strategy(void *devdata, int flag, daddr_t dblk, size_t size, + char *buf, size_t *rsizep) +{ + if (umass_uaa.device == NULL) + return (ENXIO); + if (rsizep != NULL) + *rsizep = 0; + + flag &= F_MASK; + if (flag == F_WRITE) { + if (usb_msc_write_10(umass_uaa.device, 0, dblk, size >> 9, buf) != 0) + return (EINVAL); + } else if (flag == F_READ) { + if (usb_msc_read_10(umass_uaa.device, 0, dblk, size >> 9, buf) != 0) + return (EINVAL); + } else { + return (EROFS); + } + + if (rsizep != NULL) + *rsizep = size; + return (0); +} + +static int +umass_disk_open_sub(struct disk_devdesc *dev) +{ + uint32_t nblock; + uint32_t blocksize; + + if (usb_msc_read_capacity(umass_uaa.device, 0, &nblock, &blocksize) != 0) + return (EINVAL); + + return (disk_open(dev, ((uint64_t)nblock + 1) * (uint64_t)blocksize, blocksize)); +} + +static int +umass_disk_open(struct open_file *f,...) +{ + va_list ap; + struct disk_devdesc *dev; + + va_start(ap, f); + dev = va_arg(ap, struct disk_devdesc *); + va_end(ap); + + if (umass_uaa.device == NULL) + return (ENXIO); + if (dev->d_unit != 0) + return (EIO); + return (umass_disk_open_sub(dev)); +} + +static int +umass_disk_ioctl(struct open_file *f, u_long cmd, void *buf) +{ + struct disk_devdesc *dev; + uint32_t nblock; + uint32_t blocksize; + int rc; + + dev = (struct disk_devdesc *)(f->f_devdata); + if (dev == NULL) + return (EINVAL); + + rc = disk_ioctl(dev, cmd, buf); + if (rc != ENOTTY) + return (rc); + + switch (cmd) { + case DIOCGSECTORSIZE: + case DIOCGMEDIASIZE: + if (usb_msc_read_capacity(umass_uaa.device, 0, + &nblock, &blocksize) != 0) + return (EINVAL); + + if (cmd == DIOCGMEDIASIZE) + *(uint64_t*)buf = nblock; + else + *(uint32_t*)buf = blocksize; + + return (0); + default: + return (ENXIO); + } +} + +static int +umass_disk_close(struct open_file *f) +{ + struct disk_devdesc *dev; + + dev = (struct disk_devdesc *)f->f_devdata; + return (disk_close(dev)); +} + +static int +umass_disk_print(int verbose) +{ + struct disk_devdesc dev; + + printf("%s devices:", umass_disk.dv_name); + if (pager_output("\n") != 0) + return (1); + + memset(&dev, 0, sizeof(dev)); + + ret = pager_output(" umass0 UMASS device\n"); + if (ret != 0) + return (ret); + dev.d_dev = &umass_disk; + dev.d_unit = 0; + dev.d_slice = -1; + dev.d_partition = -1; + + if (umass_disk_open_sub(&dev) == 0) { + ret = disk_print(&dev, " umass0", verbose); + disk_close(&dev); + } + return (ret); +} + +static void +umass_disk_cleanup(void) +{ + + usb_uninit(); +} + + +/* USB specific functions */ + +extern void callout_process(int); +extern void usb_idle(void); +extern void usb_init(void); +extern void usb_uninit(void); + +void +DELAY(unsigned int usdelay) +{ + delay(usdelay); +} + +int +pause(const char *what, int timeout) +{ + if (timeout == 0) + timeout = 1; + + delay((1000000 / hz) * timeout); + + return (0); +} diff --git a/stand/usb/tools/Makefile b/stand/usb/tools/Makefile new file mode 100644 index 0000000..64cf28c --- /dev/null +++ b/stand/usb/tools/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +PROG= sysinit +MAN= + +CFLAGS+= -I${.CURDIR}/../../kshim + +BINDIR?= /usr/bin + +.include <bsd.prog.mk> diff --git a/stand/usb/tools/sysinit.c b/stand/usb/tools/sysinit.c new file mode 100644 index 0000000..b968fe0 --- /dev/null +++ b/stand/usb/tools/sysinit.c @@ -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); +} diff --git a/stand/usb/usb_busdma_loader.c b/stand/usb/usb_busdma_loader.c new file mode 100644 index 0000000..90dc169 --- /dev/null +++ b/stand/usb/usb_busdma_loader.c @@ -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 = malloc(size + align, XXX, XXX); + if (ptr == NULL) + goto error; + + rem = (-((uintptr_t)ptr)) & (align - 1); + } else { + ptr = malloc(size, XXX, XXX); + 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, pc->buffer, 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) { + free(pc->tag, XXX); + 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 diff --git a/stand/usb/usbcore.mk b/stand/usb/usbcore.mk new file mode 100644 index 0000000..153a1d4 --- /dev/null +++ b/stand/usb/usbcore.mk @@ -0,0 +1,175 @@ +# +# $FreeBSD$ +# +# Copyright (c) 2013 Hans Petter Selasky. +# Copyright (c) 2014 SRI International +# All rights reserved. +# +# This software was developed by SRI International and the University of +# Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237 +# ("CTSRD"), as part of the DARPA CRASH research programme. +# +# 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. +# + +USBCOREDIR:= ${.PARSEDIR} +S=${USBCOREDIR}/../.. + +MACHDEP_DIRS= + +.if defined(HAVE_EXYNOS_EHCI) +MACHDEP_DIRS+= ${S}/arm/samsung/exynos +.endif + +.PATH: \ + ${USBCOREDIR} \ + ${USBCOREDIR}/storage \ + ${S}/dev/usb \ + ${S}/dev/usb/controller \ + ${S}/dev/usb/serial \ + ${S}/dev/usb/storage \ + ${S}/dev/usb/template \ + ${MACHDEP_DIRS} +.undef S + +USB_POOL_SIZE?= 131072 + +CFLAGS+= -DUSB_MSCTEST_BULK_SIZE=65536 +CFLAGS+= -DUSB_POOL_SIZE=${USB_POOL_SIZE} + + +# +# BUSDMA implementation +# +SRCS+= usb_busdma_loader.c + +# +# USB controller drivers +# + +KSRCS+= usb_controller.c + +.if defined(HAVE_AT91DCI) +CFLAGS += -DUSB_PCI_PROBE_LIST="\"at91dci\"" +KSRCS+= at91dci.c +.endif + +.if defined(HAVE_ATMEGADCI) +CFLAGS += -DUSB_PCI_PROBE_LIST="\"atmegadci\"" +KSRCS+= atmegadci.c +.endif + +.if defined(HAVE_AVR32DCI) +CFLAGS += -DUSB_PCI_PROBE_LIST="\"avr32dci\"" +KSRCS+= avr32dci.c +.endif + +.if defined(HAVE_DWCOTG) +CFLAGS += -DUSB_PCI_PROBE_LIST="\"dwcotg\"" +KSRCS+= dwcotg.c +.endif + +.if defined(HAVE_MUSBOTG) +CFLAGS += -DUSB_PCI_PROBE_LIST="\"musbotg\"" +KSRCS+= musbotg.c +.endif + +.if defined(HAVE_EHCI) +CFLAGS += -DUSB_PCI_PROBE_LIST="\"ehci\"" +KSRCS+= ehci.c +.endif + +.if defined(HAVE_EXYNOS_EHCI) +CFLAGS += -DUSB_PCI_PROBE_LIST="\"combiner\", \"pad\", \"ehci\"" +KSRCS+= ehci.c +KSRCS+= exynos5_combiner.c +KSRCS+= exynos5_pad.c +KSRCS+= exynos5_ehci.c +.endif + +.if defined(HAVE_OHCI) +CFLAGS += -DUSB_PCI_PROBE_LIST="\"ohci\"" +KSRCS+= ohci.c +.endif + +.if defined(HAVE_UHCI) +CFLAGS += -DUSB_PCI_PROBE_LIST="\"uhci\"" +KSRCS+= uhci.c +.endif + +.if defined(HAVE_XHCI) +CFLAGS += -DUSB_PCI_PROBE_LIST="\"xhci\"" +KSRCS+= xhci.c +.endif + +.if defined(HAVE_USS820DCI) +CFLAGS += -DUSB_PCI_PROBE_LIST="\"uss820dci\"" +KSRCS+= uss820dci.c +.endif + +.if defined(HAVE_SAF1761OTG) +CFLAGS += -DUSB_PCI_PROBE_LIST="\"saf1761otg\"" +CFLAGS += -DUSB_PCI_MEMORY_ADDRESS=0x900000007f100000ULL +CFLAGS += -DUSB_PCI_MEMORY_SIZE=0x40000U +KSRCS+= saf1761_otg.c +KSRCS+= saf1761_otg_boot.c +.endif + +# +# USB core and templates +# +KSRCS+= usb_core.c +KSRCS+= usb_debug.c +KSRCS+= usb_device.c +KSRCS+= usb_dynamic.c +KSRCS+= usb_error.c +KSRCS+= usb_handle_request.c +KSRCS+= usb_hid.c +KSRCS+= usb_hub.c +KSRCS+= usb_lookup.c +KSRCS+= usb_msctest.c +KSRCS+= usb_parse.c +KSRCS+= usb_request.c +KSRCS+= usb_transfer.c +KSRCS+= usb_util.c +KSRCS+= usb_template.c +KSRCS+= usb_template_cdce.c +KSRCS+= usb_template_msc.c +KSRCS+= usb_template_mtp.c +KSRCS+= usb_template_modem.c +KSRCS+= usb_template_mouse.c +KSRCS+= usb_template_kbd.c +KSRCS+= usb_template_audio.c +KSRCS+= usb_template_phone.c +KSRCS+= usb_template_serialnet.c +KSRCS+= usb_template_midi.c + +# +# USB mass storage support +# +SRCS+= umass_common.c + +.if defined(HAVE_UMASS_LOADER) +CFLAGS+= -I${.CURDIR}/../common +SRCS+= umass_loader.c +.endif + |