Moving UF2 related code away from this repo
This commit is contained in:
parent
1340fd0162
commit
cb0895f166
@ -1,12 +0,0 @@
|
||||
all: mod uf2
|
||||
|
||||
mod:
|
||||
$(MAKE) -C .. MOD=d_usbdev M=`pwd`/kernel ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-
|
||||
@mkdir -p bin
|
||||
cp kernel/*.ko bin/
|
||||
|
||||
uf2:
|
||||
$(MAKE) -C uf2daemon
|
||||
@mkdir -p bin
|
||||
cp uf2daemon/server bin/uf2d
|
||||
|
@ -1,35 +0,0 @@
|
||||
# Support code to run on EV3 brick
|
||||
|
||||
## Kernel module
|
||||
|
||||
Kernel module is based on LEGO's `d_usbdev` module, with the addition of slightly modified `g_mass_storage`
|
||||
module from the Linux kernel. The module and supporting sources are licensed under GPLv2 (since
|
||||
they are derived from GPLv2 code).
|
||||
|
||||
### Modifications
|
||||
|
||||
* the `d_usbdev` uses the composite framework to register an additional mass storage function in addtion
|
||||
to the pre-existing custom USB HID function
|
||||
* the `g_mass_storage` module has the following changes:
|
||||
* additional `/sys/.../lun0/active` entry is added, which allows for signaling drive eject to the host
|
||||
* `d_usbdev` has an additional `ioctl()` to pretend data came from the USB host - this can be used to direct
|
||||
the VM to do stuff
|
||||
|
||||
### Kernel modifications
|
||||
|
||||
The kernel itself has modified FIFO queue sizes. The LEGO kernel uses `1024` for `ep1in` and `ep1out`,
|
||||
and then `64` for `ep2` and `ep3`. Note that this is non-standard modification done with a kernel patch,
|
||||
that I didn't manage to find. The MSD requires `512` for `ep2` and `ep3`. I have binary edited the kernel
|
||||
to do so.
|
||||
|
||||
Note that there's 4k of FIFO memory in the hardware. If you set the queue sizes with a sum of more than
|
||||
4k, the kernel will hang, and you will not know why.
|
||||
|
||||
## UF2 Daemon
|
||||
|
||||
The [UF2](https://github.com/Microsoft/uf2) daemon is based on
|
||||
[UF2 ATSAMD21](https://github.com/Microsoft/uf2-samd21) bootloader code. It exposes a virtual
|
||||
FAT16 file system over Linux Network Block Device interface (`/dev/nbd0` to be precise).
|
||||
This device is then exposed via the `g_mass_storage` module to the host computer.
|
||||
|
||||
The Daemon is licensed under MIT.
|
10
brick/ins
10
brick/ins
@ -1,10 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -ex
|
||||
echo Y > /sys/module/printk/parameters/time
|
||||
cd /mnt/ramdisk/prjs/ko
|
||||
#echo 3 > /proc/sys/kernel/printk
|
||||
insmod ./nbd.ko
|
||||
sleep 1
|
||||
./uf2d /dev/nbd1 > /tmp/uf2d.log 2> /tmp/uf2derr.log
|
||||
sleep 1
|
||||
insmod ./d_usbdev.ko file=/dev/nbd1 HostStr=EV3 SerialStr=0016535543af
|
@ -1,2 +0,0 @@
|
||||
obj-m += $(MOD).o
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,762 +0,0 @@
|
||||
/*
|
||||
* LEGO® MINDSTORMS EV3
|
||||
*
|
||||
* Copyright (C) 2010-2013 The LEGO Group
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This UsbDev file is based on and inheritated from
|
||||
* the original file (zero.c) and work done by David Brownell
|
||||
*
|
||||
* >> zero.c -- Gadget Zero, for USB development <<
|
||||
*
|
||||
* >> Copyright (C) 2003-2008 David Brownell <<
|
||||
* >> Copyright (C) 2008 by Nokia Corporation <<
|
||||
*
|
||||
*/
|
||||
|
||||
/*! \page UsbdevModule USB device Module
|
||||
*
|
||||
*
|
||||
*- \subpage UsbdevModuleResources
|
||||
*/
|
||||
|
||||
|
||||
#ifndef PCASM
|
||||
#include <asm/types.h>
|
||||
#endif
|
||||
|
||||
#include "source/lms2012.h"
|
||||
#include "source/am1808.h"
|
||||
|
||||
|
||||
#define MODULE_NAME "usbdev_module"
|
||||
#define DEVICE1_NAME USBDEV_DEVICE
|
||||
|
||||
|
||||
|
||||
static int ModuleInit(void);
|
||||
static void ModuleExit(void);
|
||||
|
||||
#define __USE_POSIX
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include <linux/sched.h>
|
||||
|
||||
|
||||
#ifndef PCASM
|
||||
#include <linux/hrtimer.h>
|
||||
|
||||
#include <linux/mm.h>
|
||||
#include <linux/hrtimer.h>
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/debugfs.h>
|
||||
|
||||
#include <linux/ioport.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/utsname.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
static struct fsg_common *fsg_common;
|
||||
|
||||
#include "computil.c" // The composite framework used as utility file
|
||||
#include <../drivers/usb/gadget/gadget_chips.h>
|
||||
#include <../drivers/usb/gadget/usbstring.c>
|
||||
#include <../drivers/usb/gadget/config.c>
|
||||
#include <../drivers/usb/gadget/epautoconf.c>
|
||||
|
||||
#include "f_mass_storage.c"
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Kbuild is not very cooperative with respect to linking separately
|
||||
* compiled library objects into one module. So for now we won't use
|
||||
* separate compilation ... ensuring init/exit sections work to shrink
|
||||
* the runtime footprint, and giving us at least some parts of what
|
||||
* a "gcc --combine ... part1.c part2.c part3.c ... " build would.
|
||||
*/
|
||||
|
||||
#include <../drivers/usb/gadget/g_zero.h>
|
||||
#define MAX_EP_SIZE 1024
|
||||
#define MAX_FULLSPEED_EP_SIZE 64
|
||||
unsigned buflen = MAX_EP_SIZE ;
|
||||
char usb_char_buffer_in[MAX_EP_SIZE];
|
||||
char usb_full_buffer_in[MAX_FULLSPEED_EP_SIZE];
|
||||
int usb_char_in_length = 0;
|
||||
char usb_char_buffer_out[MAX_EP_SIZE];
|
||||
char usb_full_buffer_out[MAX_FULLSPEED_EP_SIZE];
|
||||
int usb_char_out_length = 0;
|
||||
|
||||
#define SHM_LENGTH (sizeof(UsbSpeedDefault))
|
||||
#define NPAGES ((SHM_LENGTH + PAGE_SIZE - 1) / PAGE_SIZE)
|
||||
static void *kmalloc_ptr;
|
||||
|
||||
#include "usb_function.c" // Specific USB functionality
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("The LEGO Group");
|
||||
MODULE_DESCRIPTION(MODULE_NAME);
|
||||
MODULE_SUPPORTED_DEVICE(DEVICE1_NAME);
|
||||
|
||||
module_init(ModuleInit);
|
||||
module_exit(ModuleExit);
|
||||
|
||||
#else
|
||||
// Keep Eclipse happy
|
||||
#endif
|
||||
|
||||
// USB main stuff
|
||||
|
||||
#define DRIVER_VERSION "31jan2011->"
|
||||
|
||||
#ifndef PCASM
|
||||
module_param(buflen, uint, 0);
|
||||
#else
|
||||
// Keep Eclipse happy
|
||||
#endif
|
||||
|
||||
static int loopdefault = 0;
|
||||
#ifndef PCASM
|
||||
module_param(loopdefault, bool, S_IRUGO|S_IWUSR);
|
||||
#else
|
||||
// Keep Eclipse happy
|
||||
#endif
|
||||
|
||||
#define DRIVER_VENDOR_NUM 0x0694 // LEGO Group
|
||||
#define DRIVER_PRODUCT_NUM 0x0005 // No. 5 in a row
|
||||
#define DEFAULT_AUTORESUME 0
|
||||
|
||||
/* If the optional "autoresume" mode is enabled, it provides good
|
||||
* functional coverage for the "USBCV" test harness from USB-IF.
|
||||
* It's always set if OTG mode is enabled.
|
||||
*/
|
||||
|
||||
unsigned autoresume = DEFAULT_AUTORESUME;
|
||||
module_param(autoresume, uint, S_IRUGO);
|
||||
|
||||
#ifndef PCASM
|
||||
MODULE_PARM_DESC(autoresume, "zero, or seconds before remote wakeup");
|
||||
#else
|
||||
// Keep Eclipse happy
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static struct usb_device_descriptor device_desc = {
|
||||
.bLength = sizeof device_desc,
|
||||
.bDescriptorType = USB_DT_DEVICE,
|
||||
|
||||
.bcdUSB = cpu_to_le16(0x0200),
|
||||
.bDeviceClass = 0xEF,
|
||||
.bDeviceSubClass = 2,
|
||||
.bDeviceProtocol = 1,
|
||||
|
||||
/*.bMaxPacketSize0 = f(hardware) */
|
||||
.idVendor = cpu_to_le16(DRIVER_VENDOR_NUM),
|
||||
.idProduct = cpu_to_le16(DRIVER_PRODUCT_NUM),
|
||||
|
||||
.bNumConfigurations = 1,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_USB_OTG
|
||||
struct usb_otg_descriptor otg_descriptor = {
|
||||
.bLength = sizeof otg_descriptor,
|
||||
.bDescriptorType = USB_DT_OTG,
|
||||
|
||||
/* REVISIT SRP-only hardware is possible, although
|
||||
* it would not be called "OTG" ...
|
||||
*/
|
||||
.bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
|
||||
};
|
||||
|
||||
const struct usb_descriptor_header *otg_desc[] = {
|
||||
(struct usb_descriptor_header *) &otg_descriptor,
|
||||
NULL,
|
||||
};
|
||||
#endif
|
||||
|
||||
/* string IDs are assigned dynamically */
|
||||
|
||||
#define STRING_MANUFACTURER_IDX 0
|
||||
#define STRING_PRODUCT_IDX 1
|
||||
#define STRING_SERIAL_IDX 2
|
||||
|
||||
static char manufacturer[] = "LEGO Group";
|
||||
static char serial[] = "123456789ABC ";
|
||||
static char longname[] = "EV3 brick ";
|
||||
|
||||
static struct usb_string strings_dev[3] = {
|
||||
[STRING_MANUFACTURER_IDX].s = manufacturer,
|
||||
[STRING_PRODUCT_IDX].s = longname,
|
||||
[STRING_SERIAL_IDX].s = serial
|
||||
};
|
||||
|
||||
|
||||
static struct usb_gadget_strings stringtab_dev = {
|
||||
.language = 0x0409, /* en-us */
|
||||
.strings = strings_dev,
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings *dev_strings[] = {
|
||||
&stringtab_dev,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
struct usb_request *alloc_ep_req(struct usb_ep *ep)
|
||||
{
|
||||
struct usb_request *req;
|
||||
|
||||
req = usb_ep_alloc_request(ep, GFP_ATOMIC);
|
||||
if (req) {
|
||||
req->length = buflen;
|
||||
req->buf = kmalloc(buflen, GFP_ATOMIC);
|
||||
if (!req->buf) {
|
||||
usb_ep_free_request(ep, req);
|
||||
req = NULL;
|
||||
}
|
||||
}
|
||||
return req;
|
||||
}
|
||||
|
||||
void free_ep_req(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
kfree(req->buf);
|
||||
usb_ep_free_request(ep, req);
|
||||
}
|
||||
|
||||
static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep)
|
||||
{
|
||||
int value;
|
||||
|
||||
if (ep->driver_data) {
|
||||
value = usb_ep_disable(ep);
|
||||
if (value < 0)
|
||||
DBG(cdev, "disable %s --> %d\n",
|
||||
ep->name, value);
|
||||
ep->driver_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void disable_endpoints(struct usb_composite_dev *cdev,
|
||||
struct usb_ep *in, struct usb_ep *out)
|
||||
{
|
||||
disable_ep(cdev, in);
|
||||
disable_ep(cdev, out);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static struct timer_list autoresume_timer;
|
||||
|
||||
static void zero_autoresume(unsigned long _c)
|
||||
{
|
||||
struct usb_composite_dev *cdev = (void *)_c;
|
||||
struct usb_gadget *g = cdev->gadget;
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("zero_autoresume\n\r");
|
||||
#endif
|
||||
|
||||
/* unconfigured devices can't issue wakeups */
|
||||
if (!cdev->config)
|
||||
return;
|
||||
|
||||
/* Normally the host would be woken up for something
|
||||
* more significant than just a timer firing; likely
|
||||
* because of some direct user request.
|
||||
*/
|
||||
if (g->speed != USB_SPEED_UNKNOWN) {
|
||||
int status = usb_gadget_wakeup(g);
|
||||
INFO(cdev, "%s --> %d\n", __func__, status);
|
||||
}
|
||||
}
|
||||
|
||||
static void zero_suspend(struct usb_composite_dev *cdev)
|
||||
{
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("zero_suspend\n\r");
|
||||
#endif
|
||||
|
||||
if (cdev->gadget->speed == USB_SPEED_UNKNOWN)
|
||||
return;
|
||||
|
||||
if (autoresume) {
|
||||
mod_timer(&autoresume_timer, jiffies + (HZ * autoresume));
|
||||
DBG(cdev, "suspend, wakeup in %d seconds\n", autoresume);
|
||||
} else
|
||||
DBG(cdev, "%s\n", __func__);
|
||||
}
|
||||
|
||||
static void zero_resume(struct usb_composite_dev *cdev)
|
||||
{
|
||||
DBG(cdev, "%s\n", __func__);
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("zero_resume\n\r");
|
||||
#endif
|
||||
|
||||
del_timer(&autoresume_timer);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int msg_bind(struct usb_composite_dev *cdev);
|
||||
static void msg_bind2(struct usb_composite_dev *cdev);
|
||||
|
||||
static int zero_bind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
int gcnum;
|
||||
struct usb_gadget *gadget = cdev->gadget;
|
||||
int id;
|
||||
|
||||
/* Allocate string descriptor numbers ... note that string
|
||||
* contents can be overridden by the composite_dev glue.
|
||||
*/
|
||||
id = usb_string_id(cdev);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
strings_dev[STRING_MANUFACTURER_IDX].id = id;
|
||||
device_desc.iManufacturer = id;
|
||||
|
||||
id = usb_string_id(cdev);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
|
||||
strings_dev[STRING_PRODUCT_IDX].id = id;
|
||||
device_desc.iProduct = id;
|
||||
|
||||
id = usb_string_id(cdev);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
|
||||
strings_dev[STRING_SERIAL_IDX].id = id;
|
||||
device_desc.iSerialNumber = id;
|
||||
|
||||
id = msg_bind(cdev);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
setup_timer(&autoresume_timer, zero_autoresume, (unsigned long) cdev);
|
||||
|
||||
rudolf_add(cdev, autoresume != 0);
|
||||
|
||||
gcnum = usb_gadget_controller_number(gadget);
|
||||
if (gcnum >= 0)
|
||||
device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
|
||||
else {
|
||||
/* gadget zero is so simple (for now, no altsettings) that
|
||||
* it SHOULD NOT have problems with bulk-capable hardware.
|
||||
* so just warn about unrcognized controllers -- don't panic.
|
||||
*
|
||||
* things like configuration and altsetting numbering
|
||||
* can need hardware-specific attention though.
|
||||
*/
|
||||
pr_warning("%s: controller '%s' not recognized\n",
|
||||
longname, gadget->name);
|
||||
device_desc.bcdDevice = cpu_to_le16(0x9999);
|
||||
}
|
||||
|
||||
msg_bind2(cdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zero_unbind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("zero_unbind\n\r");
|
||||
#endif
|
||||
|
||||
del_timer_sync(&autoresume_timer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct usb_composite_driver zero_driver = {
|
||||
.name = "zero",
|
||||
.dev = &device_desc,
|
||||
.strings = dev_strings,
|
||||
.bind = zero_bind,
|
||||
.unbind = zero_unbind,
|
||||
.suspend = zero_suspend,
|
||||
.resume = zero_resume,
|
||||
};
|
||||
|
||||
static int dUsbInit(void)
|
||||
{
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("dUsbInit\n\r");
|
||||
#endif
|
||||
|
||||
UsbSpeed.Speed = FULL_SPEED; // default to FULL_SPEED if not connected to a HIGH-SPEED
|
||||
(*pUsbSpeed).Speed = FULL_SPEED; // HOST. If not connected to HIGH-SPEED we assume we're
|
||||
// wanting (or at least doing) Daisy Chain
|
||||
return usb_composite_register(&zero_driver);
|
||||
}
|
||||
|
||||
static void dUsbExit(void)
|
||||
{
|
||||
usb_composite_unregister(&zero_driver);
|
||||
}
|
||||
|
||||
// DEVICE1 char device stuff ********************************************************************
|
||||
|
||||
static ssize_t Device1Write(struct file *File,const char *Buffer,size_t Count,loff_t *Data)
|
||||
{
|
||||
// Write data for the HOST to poll - Stuff sent to the HOST
|
||||
|
||||
int BytesWritten = 0;
|
||||
|
||||
#undef DEBUG
|
||||
//#define DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("Device1Write - usb_char_in_length = %d\n", usb_char_in_length);
|
||||
#endif
|
||||
|
||||
if (usb_char_in_length == 0) // ready for more
|
||||
{ // else wait in USER layer
|
||||
BytesWritten = Count;
|
||||
copy_from_user(usb_char_buffer_in, Buffer, BytesWritten);
|
||||
usb_char_in_length = BytesWritten;
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("WR = %d, %d -- ", usb_char_buffer_in[2], usb_char_buffer_in[3]);
|
||||
#endif
|
||||
|
||||
if(USB_DATA_PENDING == input_state)
|
||||
{
|
||||
// Already we've a failed tx (HOST part starwing??
|
||||
|
||||
input_state = USB_DATA_READY;
|
||||
#undef DEBUG
|
||||
//#define DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("DATA_PENDING SECOND time and reset!! in Device1Write\n\r");
|
||||
#endif
|
||||
}
|
||||
|
||||
if(USB_DATA_READY == input_state)
|
||||
{
|
||||
#undef DEBUG
|
||||
//#define DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("USB_DATA_READY in Device1Write\n\r");
|
||||
#endif
|
||||
|
||||
input_state = USB_DATA_BUSY;
|
||||
write_data_to_the_host(save_in_ep, save_in_req);
|
||||
usb_req_arm(save_in_ep, save_in_req); // new request
|
||||
}
|
||||
else
|
||||
{
|
||||
input_state = USB_DATA_PENDING;
|
||||
|
||||
#undef DEBUG
|
||||
//#define DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("DATA_PENDING in Device1Write\n\r");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("usbdev %d written\n\r", BytesWritten);
|
||||
#endif
|
||||
|
||||
return (BytesWritten); // Zero means USB was not ready yet
|
||||
}
|
||||
|
||||
static ssize_t Device1Read(struct file *File,char *Buffer,size_t Count,loff_t *Offset)
|
||||
{
|
||||
// Read the bits'n'bytes from the HOST
|
||||
int BytesRead = 0;
|
||||
|
||||
if (usb_char_out_length > 0) // Something to look at
|
||||
{
|
||||
#undef DEBUG
|
||||
//#define DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("Some bytes to READ?\n\r");
|
||||
#endif
|
||||
|
||||
copy_to_user(Buffer, usb_char_buffer_out, Count);
|
||||
BytesRead = usb_char_out_length;
|
||||
usb_char_out_length = 0;
|
||||
}
|
||||
return (BytesRead);
|
||||
}
|
||||
|
||||
static int Device1Mmap(struct file *filp, struct vm_area_struct *vma)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = remap_pfn_range(vma,vma->vm_start,virt_to_phys((void*)((unsigned long)pUsbSpeed)) >> PAGE_SHIFT,vma->vm_end-vma->vm_start,PAGE_SHARED);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
ret = -EAGAIN;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#define FEED_DATA _IOC(_IOC_WRITE, 't', 108, 1024)
|
||||
|
||||
static int Device1Ioctl(struct inode *pNode, struct file *File, unsigned int Request, unsigned long Pointer)
|
||||
{
|
||||
if (Request != FEED_DATA)
|
||||
return -EINVAL;
|
||||
|
||||
copy_from_user(usb_char_buffer_out,(void*)Pointer,1024);
|
||||
usb_char_out_length = 1024;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations Device1Entries =
|
||||
{
|
||||
.owner = THIS_MODULE,
|
||||
.read = Device1Read,
|
||||
.write = Device1Write,
|
||||
.mmap = Device1Mmap,
|
||||
.ioctl = Device1Ioctl
|
||||
};
|
||||
|
||||
|
||||
static struct miscdevice Device1 =
|
||||
{
|
||||
MISC_DYNAMIC_MINOR,
|
||||
DEVICE1_NAME,
|
||||
&Device1Entries
|
||||
};
|
||||
|
||||
|
||||
static int Device1Init(void)
|
||||
{
|
||||
int Result = -1;
|
||||
UWORD *pTemp;
|
||||
int i;
|
||||
|
||||
Result = misc_register(&Device1);
|
||||
if (Result)
|
||||
{
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk(" %s device register failed\n",DEVICE1_NAME);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk(" %s device register OK\n",DEVICE1_NAME);
|
||||
#endif
|
||||
|
||||
// allocate kernel shared memory for DaisyChain Speed info
|
||||
|
||||
if ((kmalloc_ptr = kmalloc((NPAGES + 2) * PAGE_SIZE, GFP_KERNEL)) != NULL)
|
||||
{
|
||||
|
||||
pTemp = (UWORD*)((((unsigned long)kmalloc_ptr) + PAGE_SIZE - 1) & PAGE_MASK);
|
||||
|
||||
for (i = 0; i < NPAGES * PAGE_SIZE; i += PAGE_SIZE)
|
||||
{
|
||||
SetPageReserved(virt_to_page(((unsigned long)pTemp) + i));
|
||||
}
|
||||
|
||||
pUsbSpeed = (USB_SPEED*)pTemp;
|
||||
}
|
||||
|
||||
dUsbInit();
|
||||
}
|
||||
|
||||
return (Result);
|
||||
}
|
||||
|
||||
static void Device1Exit(void)
|
||||
{
|
||||
int i;
|
||||
UWORD *pTemp = (UWORD*)pUsbSpeed;
|
||||
|
||||
dUsbExit();
|
||||
|
||||
pUsbSpeed = &UsbSpeedDefault;
|
||||
|
||||
for (i = 0; i < NPAGES * PAGE_SIZE; i+= PAGE_SIZE)
|
||||
{
|
||||
ClearPageReserved(virt_to_page(((unsigned long)pTemp) + i));
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk(" %s memory page %d unmapped\n",DEVICE1_NAME,i);
|
||||
#endif
|
||||
}
|
||||
|
||||
kfree(kmalloc_ptr);
|
||||
|
||||
misc_deregister(&Device1);
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk(" %s device unregistered\n",DEVICE1_NAME);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// MODULE *********************************************************************
|
||||
|
||||
char *HostStr; // Used for HostName - or NOT used at all
|
||||
char *SerialStr; // Used for Serial number (I.e. BT number)
|
||||
|
||||
module_param (HostStr, charp, 0);
|
||||
module_param (SerialStr, charp, 0);
|
||||
|
||||
static int ModuleInit(void)
|
||||
{
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("%s Module init started\r\n",MODULE_NAME);
|
||||
#endif
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("This is DEFAULT NAME: %s\n\r", longname);
|
||||
#endif
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("\n\rThis is the HostStr: %s\n\r", HostStr);
|
||||
#endif
|
||||
|
||||
strcpy(longname, HostStr);
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("\n\rThis is the INSMODed NAME: %s\n\r", longname);
|
||||
#endif
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("\n\rThis is the DEFAULT SerialNumber: %s\n\r", serial);
|
||||
#endif
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("\n\rThis is the SerialStr: %s\n\r", SerialStr);
|
||||
#endif
|
||||
|
||||
strcpy(serial, SerialStr);
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("\n\rThis is the INSMODed SerialNumber (BT mac): %s\n\r", serial);
|
||||
#endif
|
||||
|
||||
Device1Init();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void ModuleExit(void)
|
||||
{
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("%s exit started\n",MODULE_NAME);
|
||||
#endif
|
||||
|
||||
Device1Exit();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// MSG
|
||||
|
||||
|
||||
/****************************** Configurations ******************************/
|
||||
|
||||
static struct fsg_module_parameters fsg_mod_data = {
|
||||
.stall = 1
|
||||
};
|
||||
FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
|
||||
|
||||
/****************************** Gadget Bind ******************************/
|
||||
|
||||
|
||||
static void msg_bind2(struct usb_composite_dev *cdev)
|
||||
{
|
||||
fsg_common_put(fsg_common);
|
||||
}
|
||||
|
||||
static int msg_bind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
/* set up mass storage function */
|
||||
fsg_common = fsg_common_from_params(0, cdev, &fsg_mod_data);
|
||||
if (IS_ERR(fsg_common)) {
|
||||
return PTR_ERR(fsg_common);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int msg_config(struct usb_configuration *c) {
|
||||
return fsg_add(c->cdev, c, fsg_common);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,276 +0,0 @@
|
||||
/*
|
||||
* USB device controllers have lots of quirks. Use these macros in
|
||||
* gadget drivers or other code that needs to deal with them, and which
|
||||
* autoconfigures instead of using early binding to the hardware.
|
||||
*
|
||||
* This SHOULD eventually work like the ARM mach_is_*() stuff, driven by
|
||||
* some config file that gets updated as new hardware is supported.
|
||||
* (And avoiding all runtime comparisons in typical one-choice configs!)
|
||||
*
|
||||
* NOTE: some of these controller drivers may not be available yet.
|
||||
* Some are available on 2.4 kernels; several are available, but not
|
||||
* yet pushed in the 2.6 mainline tree.
|
||||
*/
|
||||
|
||||
#ifndef __GADGET_CHIPS_H
|
||||
#define __GADGET_CHIPS_H
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_NET2280
|
||||
#define gadget_is_net2280(g) !strcmp("net2280", (g)->name)
|
||||
#else
|
||||
#define gadget_is_net2280(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_AMD5536UDC
|
||||
#define gadget_is_amd5536udc(g) !strcmp("amd5536udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_amd5536udc(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_DUMMY_HCD
|
||||
#define gadget_is_dummy(g) !strcmp("dummy_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_dummy(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_PXA25X
|
||||
#define gadget_is_pxa(g) !strcmp("pxa25x_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_pxa(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_GOKU
|
||||
#define gadget_is_goku(g) !strcmp("goku_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_goku(g) 0
|
||||
#endif
|
||||
|
||||
/* SH3 UDC -- not yet ported 2.4 --> 2.6 */
|
||||
#ifdef CONFIG_USB_GADGET_SUPERH
|
||||
#define gadget_is_sh(g) !strcmp("sh_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_sh(g) 0
|
||||
#endif
|
||||
|
||||
/* not yet stable on 2.6 (would help "original Zaurus") */
|
||||
#ifdef CONFIG_USB_GADGET_SA1100
|
||||
#define gadget_is_sa1100(g) !strcmp("sa1100_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_sa1100(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_LH7A40X
|
||||
#define gadget_is_lh7a40x(g) !strcmp("lh7a40x_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_lh7a40x(g) 0
|
||||
#endif
|
||||
|
||||
/* handhelds.org tree (?) */
|
||||
#ifdef CONFIG_USB_GADGET_MQ11XX
|
||||
#define gadget_is_mq11xx(g) !strcmp("mq11xx_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_mq11xx(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_OMAP
|
||||
#define gadget_is_omap(g) !strcmp("omap_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_omap(g) 0
|
||||
#endif
|
||||
|
||||
/* not yet ported 2.4 --> 2.6 */
|
||||
#ifdef CONFIG_USB_GADGET_N9604
|
||||
#define gadget_is_n9604(g) !strcmp("n9604_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_n9604(g) 0
|
||||
#endif
|
||||
|
||||
/* various unstable versions available */
|
||||
#ifdef CONFIG_USB_GADGET_PXA27X
|
||||
#define gadget_is_pxa27x(g) !strcmp("pxa27x_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_pxa27x(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_ATMEL_USBA
|
||||
#define gadget_is_atmel_usba(g) !strcmp("atmel_usba_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_atmel_usba(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_S3C2410
|
||||
#define gadget_is_s3c2410(g) !strcmp("s3c2410_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_s3c2410(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_AT91
|
||||
#define gadget_is_at91(g) !strcmp("at91_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_at91(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_IMX
|
||||
#define gadget_is_imx(g) !strcmp("imx_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_imx(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_FSL_USB2
|
||||
#define gadget_is_fsl_usb2(g) !strcmp("fsl-usb2-udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_fsl_usb2(g) 0
|
||||
#endif
|
||||
|
||||
/* Mentor high speed function controller */
|
||||
/* from Montavista kernel (?) */
|
||||
#ifdef CONFIG_USB_GADGET_MUSBHSFC
|
||||
#define gadget_is_musbhsfc(g) !strcmp("musbhsfc_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_musbhsfc(g) 0
|
||||
#endif
|
||||
|
||||
/* Mentor high speed "dual role" controller, in peripheral role */
|
||||
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
|
||||
#define gadget_is_musbhdrc(g) !strcmp("musb_hdrc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_musbhdrc(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_LANGWELL
|
||||
#define gadget_is_langwell(g) (!strcmp("langwell_udc", (g)->name))
|
||||
#else
|
||||
#define gadget_is_langwell(g) 0
|
||||
#endif
|
||||
|
||||
/* from Montavista kernel (?) */
|
||||
#ifdef CONFIG_USB_GADGET_MPC8272
|
||||
#define gadget_is_mpc8272(g) !strcmp("mpc8272_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_mpc8272(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_M66592
|
||||
#define gadget_is_m66592(g) !strcmp("m66592_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_m66592(g) 0
|
||||
#endif
|
||||
|
||||
/* Freescale CPM/QE UDC SUPPORT */
|
||||
#ifdef CONFIG_USB_GADGET_FSL_QE
|
||||
#define gadget_is_fsl_qe(g) !strcmp("fsl_qe_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_fsl_qe(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_CI13XXX
|
||||
#define gadget_is_ci13xxx(g) (!strcmp("ci13xxx_udc", (g)->name))
|
||||
#else
|
||||
#define gadget_is_ci13xxx(g) 0
|
||||
#endif
|
||||
|
||||
// CONFIG_USB_GADGET_SX2
|
||||
// CONFIG_USB_GADGET_AU1X00
|
||||
// ...
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_R8A66597
|
||||
#define gadget_is_r8a66597(g) !strcmp("r8a66597_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_r8a66597(g) 0
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* usb_gadget_controller_number - support bcdDevice id convention
|
||||
* @gadget: the controller being driven
|
||||
*
|
||||
* Return a 2-digit BCD value associated with the peripheral controller,
|
||||
* suitable for use as part of a bcdDevice value, or a negative error code.
|
||||
*
|
||||
* NOTE: this convention is purely optional, and has no meaning in terms of
|
||||
* any USB specification. If you want to use a different convention in your
|
||||
* gadget driver firmware -- maybe a more formal revision ID -- feel free.
|
||||
*
|
||||
* Hosts see these bcdDevice numbers, and are allowed (but not encouraged!)
|
||||
* to change their behavior accordingly. For example it might help avoiding
|
||||
* some chip bug.
|
||||
*/
|
||||
static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
|
||||
{
|
||||
if (gadget_is_net2280(gadget))
|
||||
return 0x01;
|
||||
else if (gadget_is_dummy(gadget))
|
||||
return 0x02;
|
||||
else if (gadget_is_pxa(gadget))
|
||||
return 0x03;
|
||||
else if (gadget_is_sh(gadget))
|
||||
return 0x04;
|
||||
else if (gadget_is_sa1100(gadget))
|
||||
return 0x05;
|
||||
else if (gadget_is_goku(gadget))
|
||||
return 0x06;
|
||||
else if (gadget_is_mq11xx(gadget))
|
||||
return 0x07;
|
||||
else if (gadget_is_omap(gadget))
|
||||
return 0x08;
|
||||
else if (gadget_is_lh7a40x(gadget))
|
||||
return 0x09;
|
||||
else if (gadget_is_n9604(gadget))
|
||||
return 0x10;
|
||||
else if (gadget_is_pxa27x(gadget))
|
||||
return 0x11;
|
||||
else if (gadget_is_s3c2410(gadget))
|
||||
return 0x12;
|
||||
else if (gadget_is_at91(gadget))
|
||||
return 0x13;
|
||||
else if (gadget_is_imx(gadget))
|
||||
return 0x14;
|
||||
else if (gadget_is_musbhsfc(gadget))
|
||||
return 0x15;
|
||||
else if (gadget_is_musbhdrc(gadget))
|
||||
return 0x16;
|
||||
else if (gadget_is_mpc8272(gadget))
|
||||
return 0x17;
|
||||
else if (gadget_is_atmel_usba(gadget))
|
||||
return 0x18;
|
||||
else if (gadget_is_fsl_usb2(gadget))
|
||||
return 0x19;
|
||||
else if (gadget_is_amd5536udc(gadget))
|
||||
return 0x20;
|
||||
else if (gadget_is_m66592(gadget))
|
||||
return 0x21;
|
||||
else if (gadget_is_fsl_qe(gadget))
|
||||
return 0x22;
|
||||
else if (gadget_is_ci13xxx(gadget))
|
||||
return 0x23;
|
||||
else if (gadget_is_langwell(gadget))
|
||||
return 0x24;
|
||||
else if (gadget_is_r8a66597(gadget))
|
||||
return 0x25;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gadget_supports_altsettings - return true if altsettings work
|
||||
* @gadget: the gadget in question
|
||||
*/
|
||||
static inline bool gadget_supports_altsettings(struct usb_gadget *gadget)
|
||||
{
|
||||
/* PXA 21x/25x/26x has no altsettings at all */
|
||||
if (gadget_is_pxa(gadget))
|
||||
return false;
|
||||
|
||||
/* PXA 27x and 3xx have *broken* altsetting support */
|
||||
if (gadget_is_pxa27x(gadget))
|
||||
return false;
|
||||
|
||||
/* SH3 hardware just doesn't do altsettings */
|
||||
if (gadget_is_sh(gadget))
|
||||
return false;
|
||||
|
||||
/* Everything else is *presumably* fine ... */
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* __GADGET_CHIPS_H */
|
@ -1,249 +0,0 @@
|
||||
/*
|
||||
* LEGO® MINDSTORMS EV3
|
||||
*
|
||||
* Copyright (C) 2010-2013 The LEGO Group
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef AM1808_H_
|
||||
#define AM1808_H_
|
||||
|
||||
#ifndef PCASM
|
||||
#include <mach/da8xx.h>
|
||||
#else
|
||||
#define __iomem
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
GP0_0,GP0_1,GP0_2,GP0_3,GP0_4,GP0_5,GP0_6,GP0_7,GP0_8,GP0_9,GP0_10,GP0_11,GP0_12,GP0_13,GP0_14,GP0_15,
|
||||
GP1_0,GP1_1,GP1_2,GP1_3,GP1_4,GP1_5,GP1_6,GP1_7,GP1_8,GP1_9,GP1_10,GP1_11,GP1_12,GP1_13,GP1_14,GP1_15,
|
||||
GP2_0,GP2_1,GP2_2,GP2_3,GP2_4,GP2_5,GP2_6,GP2_7,GP2_8,GP2_9,GP2_10,GP2_11,GP2_12,GP2_13,GP2_14,GP2_15,
|
||||
GP3_0,GP3_1,GP3_2,GP3_3,GP3_4,GP3_5,GP3_6,GP3_7,GP3_8,GP3_9,GP3_10,GP3_11,GP3_12,GP3_13,GP3_14,GP3_15,
|
||||
GP4_0,GP4_1,GP4_2,GP4_3,GP4_4,GP4_5,GP4_6,GP4_7,GP4_8,GP4_9,GP4_10,GP4_11,GP4_12,GP4_13,GP4_14,GP4_15,
|
||||
GP5_0,GP5_1,GP5_2,GP5_3,GP5_4,GP5_5,GP5_6,GP5_7,GP5_8,GP5_9,GP5_10,GP5_11,GP5_12,GP5_13,GP5_14,GP5_15,
|
||||
GP6_0,GP6_1,GP6_2,GP6_3,GP6_4,GP6_5,GP6_6,GP6_7,GP6_8,GP6_9,GP6_10,GP6_11,GP6_12,GP6_13,GP6_14,GP6_15,
|
||||
GP7_0,GP7_1,GP7_2,GP7_3,GP7_4,GP7_5,GP7_6,GP7_7,GP7_8,GP7_9,GP7_10,GP7_11,GP7_12,GP7_13,GP7_14,GP7_15,
|
||||
GP8_0,GP8_1,GP8_2,GP8_3,GP8_4,GP8_5,GP8_6,GP8_7,GP8_8,GP8_9,GP8_10,GP8_11,GP8_12,GP8_13,GP8_14,GP8_15,
|
||||
NO_OF_GPIOS,
|
||||
UART0_TXD,UART0_RXD,UART1_TXD,UART1_RXD,
|
||||
SPI0_MOSI,SPI0_MISO,SPI0_SCL,SPI0_CS,
|
||||
SPI1_MOSI,SPI1_MISO,SPI1_SCL,SPI1_CS,
|
||||
EPWM1A,EPWM1B,APWM0,APWM1,EPWM0B,AXR3,AXR4
|
||||
};
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int Pin;
|
||||
u16 MuxReg;
|
||||
u32 Mask;
|
||||
u32 Mode;
|
||||
}
|
||||
MRM;
|
||||
|
||||
MRM MuxRegMap[] =
|
||||
{ // Pin MuxReg Mask Mode
|
||||
|
||||
{ GP0_1 , 1, 0xF0FFFFFF, 0x08000000 },
|
||||
{ GP0_2 , 1, 0xFF0FFFFF, 0x00800000 },
|
||||
{ GP0_3 , 1, 0xFFF0FFFF, 0x00080000 },
|
||||
{ GP0_4 , 1, 0xFFFF0FFF, 0x00008000 },
|
||||
{ GP0_5 , 1, 0xFFFFF0FF, 0x00000800 },
|
||||
{ GP0_6 , 1, 0xFFFFFF0F, 0x00000080 },
|
||||
{ GP0_7 , 1, 0xFFFFFFF0, 0x00000008 },
|
||||
|
||||
{ GP0_11, 0, 0xFFF0FFFF, 0x00080000 },
|
||||
{ GP0_12, 0, 0xFFFF0FFF, 0x00008000 },
|
||||
{ GP0_13, 0, 0xFFFFF0FF, 0x00000800 },
|
||||
{ GP0_14, 0, 0xFFFFFF0F, 0x00000080 },
|
||||
{ GP0_15, 0, 0xFFFFFFF0, 0x00000008 },
|
||||
|
||||
{ GP1_0 , 4, 0x0FFFFFFF, 0x80000000 },
|
||||
{ GP1_8 , 3, 0xFFFFFFF0, 0x00000004 },
|
||||
|
||||
{ GP1_9, 2, 0xF0FFFFFF, 0x04000000 },
|
||||
{ GP1_10, 2, 0xFF0FFFFF, 0x00400000 },
|
||||
{ GP1_11, 2, 0xFFF0FFFF, 0x00040000 },
|
||||
{ GP1_12, 2, 0xFFFF0FFF, 0x00004000 },
|
||||
{ GP1_13, 2, 0xFFFFF0FF, 0x00000400 },
|
||||
{ GP1_14, 2, 0xFFFFFF0F, 0x00000040 },
|
||||
{ GP1_15, 2, 0xFFFFFFF0, 0x00000008 },
|
||||
|
||||
{ GP2_0, 6, 0x0FFFFFFF, 0x80000000 },
|
||||
{ GP2_1, 6, 0xF0FFFFFF, 0x08000000 },
|
||||
{ GP2_2, 6, 0xFF0FFFFF, 0x00800000 },
|
||||
{ GP2_3, 6, 0xFFF0FFFF, 0x00080000 },
|
||||
{ GP2_4, 6, 0xFFFF0FFF, 0x00008000 },
|
||||
{ GP2_5, 6, 0xFFFFF0FF, 0x00000800 },
|
||||
{ GP2_6, 6, 0xFFFFFF0F, 0x00000080 },
|
||||
{ GP2_7, 6, 0xFFFFFFF0, 0x00000008 },
|
||||
|
||||
{ GP2_8, 5, 0x0FFFFFFF, 0x80000000 },
|
||||
{ GP2_9, 5, 0xF0FFFFFF, 0x08000000 },
|
||||
{ GP2_10, 5, 0xFF0FFFFF, 0x00800000 },
|
||||
{ GP2_11, 5, 0xFFF0FFFF, 0x00080000 },
|
||||
{ GP2_12, 5, 0xFFFF0FFF, 0x00008000 },
|
||||
{ GP2_13, 5, 0xFFFFF0FF, 0x00000800 },
|
||||
|
||||
{ GP3_0, 8, 0x0FFFFFFF, 0x80000000 },
|
||||
{ GP3_1 , 8, 0xF0FFFFFF, 0x08000000 },
|
||||
{ GP3_2, 8, 0xFF0FFFFF, 0x00800000 },
|
||||
{ GP3_3, 8, 0xFFF0FFFF, 0x00080000 },
|
||||
{ GP3_4, 8, 0xFFFF0FFF, 0x00008000 },
|
||||
{ GP3_5, 8, 0xFFFFF0FF, 0x00000800 },
|
||||
{ GP3_6, 8, 0xFFFFFF0F, 0x00000080 },
|
||||
{ GP3_7, 8, 0xFFFFFFF0, 0x00000008 },
|
||||
|
||||
{ GP3_8, 7, 0x0FFFFFFF, 0x80000000 },
|
||||
{ GP3_9, 7, 0xF0FFFFFF, 0x08000000 },
|
||||
{ GP3_10, 7, 0xFF0FFFFF, 0x00800000 },
|
||||
{ GP3_11, 7, 0xFFF0FFFF, 0x00080000 },
|
||||
{ GP3_12, 7, 0xFFFF0FFF, 0x00008000 },
|
||||
{ GP3_13, 7, 0xFFFFF0FF, 0x00000800 },
|
||||
{ GP3_14, 7, 0xFFFFFF0F, 0x00000080 },
|
||||
{ GP3_15, 7, 0xFFFFFFF0, 0x00000008 },
|
||||
|
||||
{ GP4_1, 10, 0xF0FFFFFF, 0x08000000 },
|
||||
|
||||
{ GP4_8, 9, 0x0FFFFFFF, 0x80000000 },
|
||||
{ GP4_9, 9, 0xF0FFFFFF, 0x08000000 },
|
||||
{ GP4_10, 9, 0xFF0FFFFF, 0x00800000 },
|
||||
|
||||
{ GP4_12, 9, 0xFFFF0FFF, 0x00008000 },
|
||||
|
||||
{ GP4_14, 9, 0xFFFFFF0F, 0x00000080 },
|
||||
|
||||
{ GP5_0, 12, 0x0FFFFFFF, 0x80000000 },
|
||||
{ GP5_1, 12, 0xF0FFFFFF, 0x08000000 },
|
||||
{ GP5_2, 12, 0xFF0FFFFF, 0x00800000 },
|
||||
{ GP5_3, 12, 0xFFF0FFFF, 0x00080000 },
|
||||
{ GP5_4, 12, 0xFFFF0FFF, 0x00008000 },
|
||||
{ GP5_5, 12, 0xFFFFF0FF, 0x00000800 },
|
||||
{ GP5_6, 12, 0xFFFFFF0F, 0x00000080 },
|
||||
{ GP5_7, 12, 0xFFFFFFF0, 0x00000008 },
|
||||
|
||||
{ GP5_8, 11, 0x0FFFFFFF, 0x80000000 },
|
||||
{ GP5_9, 11, 0xF0FFFFFF, 0x08000000 },
|
||||
{ GP5_10, 11, 0xFF0FFFFF, 0x00800000 },
|
||||
{ GP5_11, 11, 0xFFF0FFFF, 0x00080000 },
|
||||
{ GP5_12, 11, 0xFFFF0FFF, 0x00008000 },
|
||||
{ GP5_13, 11, 0xFFFFF0FF, 0x00000800 },
|
||||
{ GP5_14, 11, 0xFFFFFF0F, 0x00000080 },
|
||||
{ GP5_15, 11, 0xFFFFFFF0, 0x00000008 },
|
||||
|
||||
{ GP6_0 , 19, 0xF0FFFFFF, 0x08000000 },
|
||||
{ GP6_1, 19, 0xFF0FFFFF, 0x00800000 },
|
||||
{ GP6_2, 19, 0xFFF0FFFF, 0x00080000 },
|
||||
{ GP6_3, 19, 0xFFFF0FFF, 0x00008000 },
|
||||
{ GP6_4, 19, 0xFFFFF0FF, 0x00000800 },
|
||||
{ GP6_5, 16, 0xFFFFFF0F, 0x00000080 },
|
||||
|
||||
{ GP6_6, 14, 0xFFFFFF0F, 0x00000080 },
|
||||
{ GP6_7, 14, 0xFFFFFFF0, 0x00000008 },
|
||||
|
||||
{ GP6_8, 13, 0x0FFFFFFF, 0x80000000 },
|
||||
{ GP6_9, 13, 0xF0FFFFFF, 0x08000000 },
|
||||
{ GP6_10, 13, 0xFF0FFFFF, 0x00800000 },
|
||||
{ GP6_11, 13, 0xFFF0FFFF, 0x00080000 },
|
||||
{ GP6_12, 13, 0xFFFF0FFF, 0x00008000 },
|
||||
{ GP6_13, 13, 0xFFFFF0FF, 0x00000800 },
|
||||
{ GP6_14, 13, 0xFFFFFF0F, 0x00000080 },
|
||||
{ GP6_15, 13, 0xFFFFFFF0, 0x00000008 },
|
||||
|
||||
{ GP7_4, 17, 0xFF0FFFFF, 0x00800000 },
|
||||
{ GP7_8, 17, 0xFFFFFF0F, 0x00000080 },
|
||||
{ GP7_9, 17, 0xFFFFFFF0, 0x00000008 },
|
||||
{ GP7_10, 16, 0x0FFFFFFF, 0x80000000 },
|
||||
{ GP7_11, 16, 0xF0FFFFFF, 0x08000000 },
|
||||
{ GP7_12, 16, 0xFF0FFFFF, 0x00800000 },
|
||||
{ GP7_13, 16, 0xFFF0FFFF, 0x00080000 },
|
||||
{ GP7_14, 16, 0xFFFF0FFF, 0x00008000 },
|
||||
{ GP7_15, 16, 0xFFFFF0FF, 0x00000800 },
|
||||
|
||||
{ GP8_2 , 3 , 0xF0FFFFFF, 0x04000000 },
|
||||
{ GP8_3 , 3 , 0xFF0FFFFF, 0x00400000 },
|
||||
{ GP8_5 , 3 , 0xFFFF0FFF, 0x00004000 },
|
||||
{ GP8_6 , 3 , 0xFFFFF0FF, 0x00000400 },
|
||||
{ GP8_8 , 19, 0xFFFFFF0F, 0x00000080 },
|
||||
{ GP8_9 , 19, 0xFFFFFFF0, 0x00000008 },
|
||||
{ GP8_10, 18, 0x0FFFFFFF, 0x80000000 },
|
||||
{ GP8_11, 18, 0xF0FFFFFF, 0x08000000 },
|
||||
{ GP8_12, 18, 0xFF0FFFFF, 0x00800000 },
|
||||
{ GP8_13, 18, 0xFFF0FFFF, 0x00080000 },
|
||||
{ GP8_14, 18, 0xFFFF0FFF, 0x00008000 },
|
||||
{ GP8_15, 18, 0xFFFFF0FF, 0x00000800 },
|
||||
|
||||
|
||||
{ UART0_TXD, 3, 0xFF0FFFFF, 0x00200000 },
|
||||
{ UART0_RXD, 3, 0xFFF0FFFF, 0x00020000 },
|
||||
|
||||
{ UART1_TXD, 4, 0x0FFFFFFF, 0x20000000 },
|
||||
{ UART1_RXD, 4, 0xF0FFFFFF, 0x02000000 },
|
||||
|
||||
{ SPI0_MOSI, 3, 0xFFFF0FFF, 0x00001000 },
|
||||
{ SPI0_MISO, 3, 0xFFFFF0FF, 0x00000100 },
|
||||
{ SPI0_SCL, 3, 0xFFFFFFF0, 0x00000001 },
|
||||
{ SPI0_CS, 3, 0xF0FFFFFF, 0x01000000 },
|
||||
|
||||
{ SPI1_MOSI, 5, 0xFF0FFFFF, 0x00100000 },
|
||||
{ SPI1_MISO, 5, 0xFFF0FFFF, 0x00010000 },
|
||||
{ SPI1_SCL, 5, 0xFFFFF0FF, 0x00000100 },
|
||||
{ SPI1_CS, 5, 0xFFFF0FFF, 0x00008000 },
|
||||
|
||||
{ EPWM1A, 5, 0xFFFFFFF0, 0x00000002 },
|
||||
{ EPWM1B, 5, 0xFFFFFF0F, 0x00000020 },
|
||||
{ APWM0, 2, 0x0FFFFFFF, 0x20000000 },
|
||||
{ APWM1, 1, 0x0FFFFFFF, 0x40000000 },
|
||||
{ EPWM0B, 3, 0xFFFFFF0F, 0x00000020 },
|
||||
|
||||
{ AXR3, 2, 0xFFF0FFFF, 0x00010000 },
|
||||
{ AXR4, 2, 0xFFFF0FFF, 0x00001000 },
|
||||
|
||||
{-1 }
|
||||
};
|
||||
|
||||
typedef struct gpio_controller *__iomem GPIOC;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int Pin; // GPIO pin number
|
||||
GPIOC pGpio; // GPIO bank base address
|
||||
u32 Mask; // GPIO pin mask
|
||||
}
|
||||
INPIN;
|
||||
|
||||
#define REGUnlock {\
|
||||
iowrite32(0x83E70B13,da8xx_syscfg0_base + 0x38);\
|
||||
iowrite32(0x95A4F1E0,da8xx_syscfg0_base + 0x3C);\
|
||||
}
|
||||
|
||||
#define REGLock {\
|
||||
iowrite32(0x00000000,da8xx_syscfg0_base + 0x38);\
|
||||
iowrite32(0x00000000,da8xx_syscfg0_base + 0x3C);\
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#else
|
||||
|
||||
extern MRM MuxRegMap[];
|
||||
|
||||
#endif /* AM1808_H_ */
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,81 +0,0 @@
|
||||
/*
|
||||
* LEGO® MINDSTORMS EV3
|
||||
*
|
||||
* Copyright (C) 2010-2013 The LEGO Group
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef C_BRANCH_H_
|
||||
#define C_BRANCH_H_
|
||||
|
||||
void cBranchJr(void);
|
||||
|
||||
void cBranchJrFalse(void);
|
||||
|
||||
void cBranchJrTrue(void);
|
||||
|
||||
void cBranchJrNan(void);
|
||||
|
||||
void cBranchJrLt8(void);
|
||||
|
||||
void cBranchJrLt16(void);
|
||||
|
||||
void cBranchJrLt32(void);
|
||||
|
||||
void cBranchJrLtF(void);
|
||||
|
||||
void cBranchJrGt8(void);
|
||||
|
||||
void cBranchJrGt16(void);
|
||||
|
||||
void cBranchJrGt32(void);
|
||||
|
||||
void cBranchJrGtF(void);
|
||||
|
||||
void cBranchJrLtEq8(void);
|
||||
|
||||
void cBranchJrLtEq16(void);
|
||||
|
||||
void cBranchJrLtEq32(void);
|
||||
|
||||
void cBranchJrLtEqF(void);
|
||||
|
||||
void cBranchJrGtEq8(void);
|
||||
|
||||
void cBranchJrGtEq16(void);
|
||||
|
||||
void cBranchJrGtEq32(void);
|
||||
|
||||
void cBranchJrGtEqF(void);
|
||||
|
||||
void cBranchJrEq8(void);
|
||||
|
||||
void cBranchJrEq16(void);
|
||||
|
||||
void cBranchJrEq32(void);
|
||||
|
||||
void cBranchJrEqF(void);
|
||||
|
||||
void cBranchJrNEq8(void);
|
||||
|
||||
void cBranchJrNEq16(void);
|
||||
|
||||
void cBranchJrNEq32(void);
|
||||
|
||||
void cBranchJrNEqF(void);
|
||||
|
||||
#endif /* C_BRANCH_H_ */
|
@ -1,81 +0,0 @@
|
||||
/*
|
||||
* LEGO® MINDSTORMS EV3
|
||||
*
|
||||
* Copyright (C) 2010-2013 The LEGO Group
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef C_COMPARE_H_
|
||||
#define C_COMPARE_H_
|
||||
|
||||
void cCompareLt8(void);
|
||||
|
||||
void cCompareLt16(void);
|
||||
|
||||
void cCompareLt32(void);
|
||||
|
||||
void cCompareLtF(void);
|
||||
|
||||
void cCompareGt8(void);
|
||||
|
||||
void cCompareGt16(void);
|
||||
|
||||
void cCompareGt32(void);
|
||||
|
||||
void cCompareGtF(void);
|
||||
|
||||
void cCompareEq8(void);
|
||||
|
||||
void cCompareEq16(void);
|
||||
|
||||
void cCompareEq32(void);
|
||||
|
||||
void cCompareEqF(void);
|
||||
|
||||
void cCompareNEq8(void);
|
||||
|
||||
void cCompareNEq16(void);
|
||||
|
||||
void cCompareNEq32(void);
|
||||
|
||||
void cCompareNEqF(void);
|
||||
|
||||
void cCompareLtEq8(void);
|
||||
|
||||
void cCompareLtEq16(void);
|
||||
|
||||
void cCompareLtEq32(void);
|
||||
|
||||
void cCompareLtEqF(void);
|
||||
|
||||
void cCompareGtEq8(void);
|
||||
|
||||
void cCompareGtEq16(void);
|
||||
|
||||
void cCompareGtEq32(void);
|
||||
|
||||
void cCompareGtEqF(void);
|
||||
|
||||
void cCompareSelect8(void);
|
||||
|
||||
void cCompareSelect16(void);
|
||||
|
||||
void cCompareSelect32(void);
|
||||
|
||||
void cCompareSelectF(void);
|
||||
|
||||
#endif /* C_COMPARE_H_ */
|
@ -1,88 +0,0 @@
|
||||
/*
|
||||
* LEGO® MINDSTORMS EV3
|
||||
*
|
||||
* Copyright (C) 2010-2013 The LEGO Group
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef C_MATH_H_
|
||||
#define C_MATH_H_
|
||||
|
||||
#define DegToRad(D) (D * 0.0174532925)
|
||||
|
||||
#define RadToDeg(R) (R * 57.2957795)
|
||||
|
||||
|
||||
void cMathAdd8(void);
|
||||
|
||||
void cMathAdd16(void);
|
||||
|
||||
void cMathAdd32(void);
|
||||
|
||||
void cMathAddF(void);
|
||||
|
||||
void cMathSub8(void);
|
||||
|
||||
void cMathSub16(void);
|
||||
|
||||
void cMathSub32(void);
|
||||
|
||||
void cMathSubF(void);
|
||||
|
||||
void cMathMul8(void);
|
||||
|
||||
void cMathMul16(void);
|
||||
|
||||
void cMathMul32(void);
|
||||
|
||||
void cMathMulF(void);
|
||||
|
||||
void cMathDiv8(void);
|
||||
|
||||
void cMathDiv16(void);
|
||||
|
||||
void cMathDiv32(void);
|
||||
|
||||
void cMathDivF(void);
|
||||
|
||||
void cMathOr8(void);
|
||||
|
||||
void cMathOr16(void);
|
||||
|
||||
void cMathOr32(void);
|
||||
|
||||
void cMathAnd8(void);
|
||||
|
||||
void cMathAnd16(void);
|
||||
|
||||
void cMathAnd32(void);
|
||||
|
||||
void cMathXor8(void);
|
||||
|
||||
void cMathXor16(void);
|
||||
|
||||
void cMathXor32(void);
|
||||
|
||||
void cMathRl8(void);
|
||||
|
||||
void cMathRl16(void);
|
||||
|
||||
void cMathRl32(void);
|
||||
|
||||
void cMath(void);
|
||||
|
||||
#endif /* C_MATH_H_ */
|
@ -1,76 +0,0 @@
|
||||
/*
|
||||
* LEGO® MINDSTORMS EV3
|
||||
*
|
||||
* Copyright (C) 2010-2013 The LEGO Group
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef C_MOVE_H_
|
||||
#define C_MOVE_H_
|
||||
|
||||
void cMove8to8(void);
|
||||
|
||||
void cMove8to16(void);
|
||||
|
||||
void cMove8to32(void);
|
||||
|
||||
void cMove8toF(void);
|
||||
|
||||
void cMove16to8(void);
|
||||
|
||||
void cMove16to16(void);
|
||||
|
||||
void cMove16to32(void);
|
||||
|
||||
void cMove16toF(void);
|
||||
|
||||
void cMove32to8(void);
|
||||
|
||||
void cMove32to16(void);
|
||||
|
||||
void cMove32to32(void);
|
||||
|
||||
void cMove32toF(void);
|
||||
|
||||
void cMoveFto8(void);
|
||||
|
||||
void cMoveFto16(void);
|
||||
|
||||
void cMoveFto32(void);
|
||||
|
||||
void cMoveFtoF(void);
|
||||
|
||||
void cMoveInitBytes(void);
|
||||
|
||||
void cMoveRead8(void);
|
||||
|
||||
void cMoveRead16(void);
|
||||
|
||||
void cMoveRead32(void);
|
||||
|
||||
void cMoveReadF(void);
|
||||
|
||||
void cMoveWrite8(void);
|
||||
|
||||
void cMoveWrite16(void);
|
||||
|
||||
void cMoveWrite32(void);
|
||||
|
||||
void cMoveWriteF(void);
|
||||
|
||||
|
||||
#endif /* C_MOVE_H_ */
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* LEGO® MINDSTORMS EV3
|
||||
*
|
||||
* Copyright (C) 2010-2013 The LEGO Group
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef C_TIMER_H_
|
||||
#define C_TIMER_H_
|
||||
|
||||
#if (HARDWARE != SIMULATION)
|
||||
ULONG cTimerGetuS(void);
|
||||
ULONG cTimerGetmS(void);
|
||||
#endif
|
||||
|
||||
void cTimerWait(void);
|
||||
|
||||
void cTimerReady(void);
|
||||
|
||||
void cTimerRead(void);
|
||||
|
||||
void cTimerReaduS(void);
|
||||
|
||||
#endif /* C_TIMER_H_ */
|
File diff suppressed because it is too large
Load Diff
@ -1,195 +0,0 @@
|
||||
/*
|
||||
* LEGO® MINDSTORMS EV3
|
||||
*
|
||||
* Copyright (C) 2010-2013 The LEGO Group
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* As a special exception, if other files instantiate templates or use macros or
|
||||
* inline functions from this file, or you compile this file and link it with
|
||||
* other works to produce a work based on this file, this file does not by itself
|
||||
* cause the resulting work to be covered by the GNU General Public License.
|
||||
* However the source code for this file must still be made available in accordance
|
||||
* with section (3) of the GNU General Public License.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LMSTYPES_H_
|
||||
#define LMSTYPES_H_
|
||||
|
||||
// BASIC DATA TYPES
|
||||
|
||||
#ifndef LEGO_SIMULATION
|
||||
|
||||
typedef unsigned char UBYTE; //!< Basic Type used to symbolise 8 bit unsigned values
|
||||
typedef unsigned short UWORD; //!< Basic Type used to symbolise 16 bit unsigned values
|
||||
typedef unsigned int ULONG; //!< Basic Type used to symbolise 32 bit unsigned values
|
||||
|
||||
typedef signed char SBYTE; //!< Basic Type used to symbolise 8 bit signed values
|
||||
typedef signed short SWORD; //!< Basic Type used to symbolise 16 bit signed values
|
||||
typedef signed int SLONG; //!< Basic Type used to symbolise 32 bit signed values
|
||||
|
||||
typedef float FLOAT; //!< Basic Type used to symbolise 32 bit floating point values
|
||||
|
||||
#define LFILE FILE
|
||||
|
||||
#else
|
||||
|
||||
#include <Base/BasicTypes.h>
|
||||
#include <VMCalls.h>
|
||||
|
||||
typedef LEGO::UInt8 UBYTE; //!< Basic Type used to symbolise 8 bit unsigned values
|
||||
typedef LEGO::UInt16 UWORD; //!< Basic Type used to symbolise 16 bit unsigned values
|
||||
typedef unsigned long ULONG; //!< Basic Type used to symbolise 32 bit unsigned values
|
||||
|
||||
|
||||
typedef LEGO::Int8 SBYTE; //!< Basic Type used to symbolise 8 bit signed values
|
||||
typedef LEGO::Int16 SWORD; //!< Basic Type used to symbolise 16 bit signed values
|
||||
typedef LEGO::Int32 SLONG; //!< Basic Type used to symbolise 32 bit signed values
|
||||
|
||||
typedef LEGO::Real32 FLOAT; //!< Basic Type used to symbolise 32 bit floating point values
|
||||
|
||||
#endif
|
||||
|
||||
// VM DATA TYPES
|
||||
|
||||
typedef SBYTE DATA8; //!< VM Type for 1 byte signed value
|
||||
typedef SWORD DATA16; //!< VM Type for 2 byte signed value
|
||||
typedef SLONG DATA32; //!< VM Type for 4 byte signed value
|
||||
typedef FLOAT DATAF; //!< VM Type for 4 byte floating point value
|
||||
|
||||
// VM VARIABLE TYPES
|
||||
|
||||
typedef UBYTE VARDATA; //!< Variable base type
|
||||
typedef UBYTE IMGDATA; //!< Image base type
|
||||
|
||||
typedef UWORD PRGID; //!< Program id type
|
||||
|
||||
typedef UWORD OBJID; //!< Object id type
|
||||
typedef IMGDATA* IP; //!< Instruction pointer type
|
||||
typedef VARDATA* LP; //!< Local variable pointer type
|
||||
typedef VARDATA* GP; //!< global variable pointer type
|
||||
|
||||
typedef ULONG IMINDEX; //!< ImageData index type
|
||||
typedef ULONG GBINDEX; //!< GlobalBytes index type
|
||||
typedef ULONG LBINDEX; //!< LocalBytes index type
|
||||
typedef UWORD TRIGGER; //!< TriggerCount type
|
||||
typedef UBYTE PARS; //!< NoOfParameters type
|
||||
typedef SLONG IMOFFS; //!< ImageData offset type
|
||||
|
||||
typedef DATA16 HANDLER; //!< Memory list index
|
||||
|
||||
|
||||
|
||||
/*! \page imagelayout Image Layout
|
||||
* The image consists of three different components in this fixed order: imageheader, objectheaders and byte codes.
|
||||
*
|
||||
* The imageheader tells something about image version, filesize, no of objectheaders (objects) and no of global variable bytes.
|
||||
*
|
||||
*
|
||||
* Objectheaders contains different informations depending on the nature of the object:
|
||||
*
|
||||
*- The VMTHREAD object (former TBC_TOPVI) \n
|
||||
* - OffsetToInstructions tells were to find the corresponding byte codes (offset from image start) \n
|
||||
* - OwnerObjectId must be zero \n
|
||||
* - TriggerCount is used but must be zero \n
|
||||
* - LocalBytes describes the number of bytes for local variables \n
|
||||
*
|
||||
*- The SUBCALL object (former TBC_VI and TBC_VI_ALIAS) \n
|
||||
* - OffsetToInstructions tells were to find the corresponding byte codes (if alias this is equal to mother object) \n
|
||||
* - OwnerObjectId must be zero \n
|
||||
* - TriggerCount is used and must be one \n
|
||||
* - LocalBytes describes the number of bytes for local variables \n
|
||||
*
|
||||
*- The BLOCK object (former CLUMP) \n
|
||||
* - OffsetToInstructions tells were to find the corresponding byte codes (offset from image start) \n
|
||||
* - OwnerObjectId is equal to object id it belongs to (not equal to zero) \n
|
||||
* - TriggerCount is used to determine how many triggers needed before the BLOCK object is activated \n
|
||||
* - LocalBytes must be zero (locals are defined in the owner object) \n
|
||||
*
|
||||
* Byte codes are described in a different section.
|
||||
*
|
||||
* Little Endian are used (addresses and data are represented with LSB on lowest address and MSB on highest address).
|
||||
*
|
||||
* Offset to instructions is number of bytes from start of image to start of object instructions.
|
||||
*
|
||||
* Index to global variables are byte based and counted from start of globals (zero based).
|
||||
*
|
||||
* Index to local variables are byte based and counted from start of object locals (zero based).
|
||||
*
|
||||
* Object ID's is not zero based - First object (VMTHEAD) is named 1.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! \page imagelayout
|
||||
*
|
||||
* FILE layout (aligned)
|
||||
*
|
||||
*- IMGHEAD (aligned)
|
||||
* - Sign (4 bytes)
|
||||
* - ImageSize (4 bytes)
|
||||
* - VersionInfo (2 bytes)
|
||||
* - NumberOfObjects (2 bytes)
|
||||
* - GlobalBytes (4 bytes)
|
||||
*/
|
||||
|
||||
/*! \struct IMGHEAD
|
||||
* Image header
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
UBYTE Sign[4]; //!< Place holder for the file type identifier
|
||||
IMINDEX ImageSize; //!< Image size
|
||||
UWORD VersionInfo; //!< Version identifier
|
||||
OBJID NumberOfObjects; //!< Total number of objects in image
|
||||
GBINDEX GlobalBytes; //!< Number of bytes to allocate for global variables
|
||||
}
|
||||
IMGHEAD;
|
||||
|
||||
/*! \page imagelayout
|
||||
*
|
||||
*- OBJHEAD (aligned)
|
||||
* - OffsetToInstructions (4 bytes)
|
||||
* - OwnerObjectId (2 bytes)
|
||||
* - TriggerCount (2 bytes)
|
||||
* - LocalBytes (4 bytes)
|
||||
*
|
||||
*/
|
||||
|
||||
/*! \struct OBJHEAD
|
||||
* Object header used for all types of objects (VMTHREAD, SUBCALL, BLOCK and ALIAS)
|
||||
*/
|
||||
typedef struct // Object header
|
||||
{
|
||||
IP OffsetToInstructions; //!< Offset to instructions from image start
|
||||
OBJID OwnerObjectId; //!< Used by BLOCK's to hold the owner id
|
||||
TRIGGER TriggerCount; //!< Used to determine how many triggers needed before the BLOCK object is activated
|
||||
LBINDEX LocalBytes; //!< Number of bytes to allocate for local variables
|
||||
}
|
||||
OBJHEAD;
|
||||
|
||||
|
||||
/*! \struct LABEL
|
||||
* Label data hold information used for labels
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
IMINDEX Addr; //!< Offset to breakpoint address from image start
|
||||
}
|
||||
LABEL;
|
||||
|
||||
|
||||
#endif /* LMSTYPES_H_ */
|
@ -1,56 +0,0 @@
|
||||
/*
|
||||
* LEGO® MINDSTORMS EV3
|
||||
*
|
||||
* Copyright (C) 2010-2013 The LEGO Group
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef VALIDATE_H_
|
||||
#define VALIDATE_H_
|
||||
|
||||
RESULT cValidateInit(void);
|
||||
|
||||
RESULT cValidateExit(void);
|
||||
|
||||
RESULT cValidateDisassemble(IP pI,IMINDEX *pIndex,LABEL *pLabel);
|
||||
|
||||
RESULT cValidateProgram(PRGID PrgId,IP pI,LABEL *pLabel,DATA8 Disassemble);
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
//*****************************************************************************
|
||||
// Validate Global variables
|
||||
//*****************************************************************************
|
||||
|
||||
int Row;
|
||||
IMINDEX ValidateErrorIndex;
|
||||
}
|
||||
VALIDATE_GLOBALS;
|
||||
|
||||
#ifndef LEGO_SIMULATION
|
||||
extern VALIDATE_GLOBALS ValidateInstance;
|
||||
#else
|
||||
extern VALIDATE_GLOBALS * gValidateInstance;
|
||||
#define ValidateInstance (*gValidateInstance)
|
||||
|
||||
void setValidateInstance(VALIDATE_GLOBALS * _Instance);
|
||||
VALIDATE_GLOBALS * getValidateInstance();
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* VALIDATE_H_ */
|
@ -1,779 +0,0 @@
|
||||
/*
|
||||
* storage_common.c -- Common definitions for mass storage functionality
|
||||
*
|
||||
* Copyright (C) 2003-2008 Alan Stern
|
||||
* Copyeight (C) 2009 Samsung Electronics
|
||||
* Author: Michal Nazarewicz (m.nazarewicz@samsung.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file requires the following identifiers used in USB strings to
|
||||
* be defined (each of type pointer to char):
|
||||
* - fsg_string_manufacturer -- name of the manufacturer
|
||||
* - fsg_string_product -- name of the product
|
||||
* - fsg_string_serial -- product's serial
|
||||
* - fsg_string_config -- name of the configuration
|
||||
* - fsg_string_interface -- name of the interface
|
||||
* The first four are only needed when FSG_DESCRIPTORS_DEVICE_STRINGS
|
||||
* macro is defined prior to including this file.
|
||||
*/
|
||||
|
||||
/*
|
||||
* When FSG_NO_INTR_EP is defined fsg_fs_intr_in_desc and
|
||||
* fsg_hs_intr_in_desc objects as well as
|
||||
* FSG_FS_FUNCTION_PRE_EP_ENTRIES and FSG_HS_FUNCTION_PRE_EP_ENTRIES
|
||||
* macros are not defined.
|
||||
*
|
||||
* When FSG_NO_DEVICE_STRINGS is defined FSG_STRING_MANUFACTURER,
|
||||
* FSG_STRING_PRODUCT, FSG_STRING_SERIAL and FSG_STRING_CONFIG are not
|
||||
* defined (as well as corresponding entries in string tables are
|
||||
* missing) and FSG_STRING_INTERFACE has value of zero.
|
||||
*
|
||||
* When FSG_NO_OTG is defined fsg_otg_desc won't be defined.
|
||||
*/
|
||||
|
||||
/*
|
||||
* When FSG_BUFFHD_STATIC_BUFFER is defined when this file is included
|
||||
* the fsg_buffhd structure's buf field will be an array of FSG_BUFLEN
|
||||
* characters rather then a pointer to void.
|
||||
*/
|
||||
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
|
||||
/* Thanks to NetChip Technologies for donating this product ID.
|
||||
*
|
||||
* DO NOT REUSE THESE IDs with any other driver!! Ever!!
|
||||
* Instead: allocate your own, using normal USB-IF procedures. */
|
||||
#define FSG_VENDOR_ID 0x0525 /* NetChip */
|
||||
#define FSG_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#ifndef DEBUG
|
||||
#undef VERBOSE_DEBUG
|
||||
#undef DUMP_MSGS
|
||||
#endif /* !DEBUG */
|
||||
|
||||
#ifdef VERBOSE_DEBUG
|
||||
#define VLDBG LDBG
|
||||
#else
|
||||
#define VLDBG(lun, fmt, args...) do { } while (0)
|
||||
#endif /* VERBOSE_DEBUG */
|
||||
|
||||
#define LDBG(lun, fmt, args...) dev_dbg (&(lun)->dev, fmt, ## args)
|
||||
#define LERROR(lun, fmt, args...) dev_err (&(lun)->dev, fmt, ## args)
|
||||
#define LWARN(lun, fmt, args...) dev_warn(&(lun)->dev, fmt, ## args)
|
||||
#define LINFO(lun, fmt, args...) dev_info(&(lun)->dev, fmt, ## args)
|
||||
|
||||
/* Keep those macros in sync with thos in
|
||||
* include/linux/ubs/composite.h or else GCC will complain. If they
|
||||
* are identical (the same names of arguments, white spaces in the
|
||||
* same places) GCC will allow redefinition otherwise (even if some
|
||||
* white space is removed or added) warning will be issued. No
|
||||
* checking if those symbols is defined is performed because warning
|
||||
* is desired when those macros were defined by someone else to mean
|
||||
* something else. */
|
||||
#define DBG(d, fmt, args...) dev_dbg(&(d)->gadget->dev , fmt , ## args)
|
||||
#define VDBG(d, fmt, args...) dev_vdbg(&(d)->gadget->dev , fmt , ## args)
|
||||
#define ERROR(d, fmt, args...) dev_err(&(d)->gadget->dev , fmt , ## args)
|
||||
#define WARNING(d, fmt, args...) dev_warn(&(d)->gadget->dev , fmt , ## args)
|
||||
#define INFO(d, fmt, args...) dev_info(&(d)->gadget->dev , fmt , ## args)
|
||||
|
||||
|
||||
|
||||
#ifdef DUMP_MSGS
|
||||
|
||||
# define dump_msg(fsg, /* const char * */ label, \
|
||||
/* const u8 * */ buf, /* unsigned */ length) do { \
|
||||
if (length < 512) { \
|
||||
DBG(fsg, "%s, length %u:\n", label, length); \
|
||||
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, \
|
||||
16, 1, buf, length, 0); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
# define dump_cdb(fsg) do { } while (0)
|
||||
|
||||
#else
|
||||
|
||||
# define dump_msg(fsg, /* const char * */ label, \
|
||||
/* const u8 * */ buf, /* unsigned */ length) do { } while (0)
|
||||
|
||||
# ifdef VERBOSE_DEBUG
|
||||
|
||||
# define dump_cdb(fsg) \
|
||||
print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE, \
|
||||
16, 1, (fsg)->cmnd, (fsg)->cmnd_size, 0) \
|
||||
|
||||
# else
|
||||
|
||||
# define dump_cdb(fsg) do { } while (0)
|
||||
|
||||
# endif /* VERBOSE_DEBUG */
|
||||
|
||||
#endif /* DUMP_MSGS */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* SCSI device types */
|
||||
#define TYPE_DISK 0x00
|
||||
#define TYPE_CDROM 0x05
|
||||
|
||||
/* USB protocol value = the transport method */
|
||||
#define USB_PR_CBI 0x00 /* Control/Bulk/Interrupt */
|
||||
#define USB_PR_CB 0x01 /* Control/Bulk w/o interrupt */
|
||||
#define USB_PR_BULK 0x50 /* Bulk-only */
|
||||
|
||||
/* USB subclass value = the protocol encapsulation */
|
||||
#define USB_SC_RBC 0x01 /* Reduced Block Commands (flash) */
|
||||
#define USB_SC_8020 0x02 /* SFF-8020i, MMC-2, ATAPI (CD-ROM) */
|
||||
#define USB_SC_QIC 0x03 /* QIC-157 (tape) */
|
||||
#define USB_SC_UFI 0x04 /* UFI (floppy) */
|
||||
#define USB_SC_8070 0x05 /* SFF-8070i (removable) */
|
||||
#define USB_SC_SCSI 0x06 /* Transparent SCSI */
|
||||
|
||||
/* Bulk-only data structures */
|
||||
|
||||
/* Command Block Wrapper */
|
||||
struct fsg_bulk_cb_wrap {
|
||||
__le32 Signature; /* Contains 'USBC' */
|
||||
u32 Tag; /* Unique per command id */
|
||||
__le32 DataTransferLength; /* Size of the data */
|
||||
u8 Flags; /* Direction in bit 7 */
|
||||
u8 Lun; /* LUN (normally 0) */
|
||||
u8 Length; /* Of the CDB, <= MAX_COMMAND_SIZE */
|
||||
u8 CDB[16]; /* Command Data Block */
|
||||
};
|
||||
|
||||
#define USB_BULK_CB_WRAP_LEN 31
|
||||
#define USB_BULK_CB_SIG 0x43425355 /* Spells out USBC */
|
||||
#define USB_BULK_IN_FLAG 0x80
|
||||
|
||||
/* Command Status Wrapper */
|
||||
struct bulk_cs_wrap {
|
||||
__le32 Signature; /* Should = 'USBS' */
|
||||
u32 Tag; /* Same as original command */
|
||||
__le32 Residue; /* Amount not transferred */
|
||||
u8 Status; /* See below */
|
||||
};
|
||||
|
||||
#define USB_BULK_CS_WRAP_LEN 13
|
||||
#define USB_BULK_CS_SIG 0x53425355 /* Spells out 'USBS' */
|
||||
#define USB_STATUS_PASS 0
|
||||
#define USB_STATUS_FAIL 1
|
||||
#define USB_STATUS_PHASE_ERROR 2
|
||||
|
||||
/* Bulk-only class specific requests */
|
||||
#define USB_BULK_RESET_REQUEST 0xff
|
||||
#define USB_BULK_GET_MAX_LUN_REQUEST 0xfe
|
||||
|
||||
|
||||
/* CBI Interrupt data structure */
|
||||
struct interrupt_data {
|
||||
u8 bType;
|
||||
u8 bValue;
|
||||
};
|
||||
|
||||
#define CBI_INTERRUPT_DATA_LEN 2
|
||||
|
||||
/* CBI Accept Device-Specific Command request */
|
||||
#define USB_CBI_ADSC_REQUEST 0x00
|
||||
|
||||
|
||||
/* Length of a SCSI Command Data Block */
|
||||
#define MAX_COMMAND_SIZE 16
|
||||
|
||||
/* SCSI commands that we recognize */
|
||||
#define SC_FORMAT_UNIT 0x04
|
||||
#define SC_INQUIRY 0x12
|
||||
#define SC_MODE_SELECT_6 0x15
|
||||
#define SC_MODE_SELECT_10 0x55
|
||||
#define SC_MODE_SENSE_6 0x1a
|
||||
#define SC_MODE_SENSE_10 0x5a
|
||||
#define SC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e
|
||||
#define SC_READ_6 0x08
|
||||
#define SC_READ_10 0x28
|
||||
#define SC_READ_12 0xa8
|
||||
#define SC_READ_CAPACITY 0x25
|
||||
#define SC_READ_FORMAT_CAPACITIES 0x23
|
||||
#define SC_READ_HEADER 0x44
|
||||
#define SC_READ_TOC 0x43
|
||||
#define SC_RELEASE 0x17
|
||||
#define SC_REQUEST_SENSE 0x03
|
||||
#define SC_RESERVE 0x16
|
||||
#define SC_SEND_DIAGNOSTIC 0x1d
|
||||
#define SC_START_STOP_UNIT 0x1b
|
||||
#define SC_SYNCHRONIZE_CACHE 0x35
|
||||
#define SC_TEST_UNIT_READY 0x00
|
||||
#define SC_VERIFY 0x2f
|
||||
#define SC_WRITE_6 0x0a
|
||||
#define SC_WRITE_10 0x2a
|
||||
#define SC_WRITE_12 0xaa
|
||||
|
||||
/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */
|
||||
#define SS_NO_SENSE 0
|
||||
#define SS_COMMUNICATION_FAILURE 0x040800
|
||||
#define SS_INVALID_COMMAND 0x052000
|
||||
#define SS_INVALID_FIELD_IN_CDB 0x052400
|
||||
#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x052100
|
||||
#define SS_LOGICAL_UNIT_NOT_SUPPORTED 0x052500
|
||||
#define SS_MEDIUM_NOT_PRESENT 0x023a00
|
||||
#define SS_MEDIUM_REMOVAL_PREVENTED 0x055302
|
||||
#define SS_NOT_READY_TO_READY_TRANSITION 0x062800
|
||||
#define SS_RESET_OCCURRED 0x062900
|
||||
#define SS_SAVING_PARAMETERS_NOT_SUPPORTED 0x053900
|
||||
#define SS_UNRECOVERED_READ_ERROR 0x031100
|
||||
#define SS_WRITE_ERROR 0x030c02
|
||||
#define SS_WRITE_PROTECTED 0x072700
|
||||
|
||||
#define SK(x) ((u8) ((x) >> 16)) /* Sense Key byte, etc. */
|
||||
#define ASC(x) ((u8) ((x) >> 8))
|
||||
#define ASCQ(x) ((u8) (x))
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
struct fsg_lun {
|
||||
struct file *filp;
|
||||
loff_t file_length;
|
||||
loff_t num_sectors;
|
||||
|
||||
unsigned int initially_ro:1;
|
||||
unsigned int ro:1;
|
||||
unsigned int removable:1;
|
||||
unsigned int cdrom:1;
|
||||
unsigned int prevent_medium_removal:1;
|
||||
unsigned int registered:1;
|
||||
unsigned int info_valid:1;
|
||||
|
||||
u32 sense_data;
|
||||
u32 sense_data_info;
|
||||
u32 unit_attention_data;
|
||||
|
||||
struct device dev;
|
||||
};
|
||||
|
||||
#define fsg_lun_is_open(curlun) ((curlun)->filp != NULL)
|
||||
|
||||
static struct fsg_lun *fsg_lun_from_dev(struct device *dev)
|
||||
{
|
||||
return container_of(dev, struct fsg_lun, dev);
|
||||
}
|
||||
|
||||
|
||||
/* Big enough to hold our biggest descriptor */
|
||||
#define EP0_BUFSIZE 256
|
||||
#define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */
|
||||
|
||||
/* Number of buffers we will use. 2 is enough for double-buffering */
|
||||
#define FSG_NUM_BUFFERS 2
|
||||
|
||||
/* Default size of buffer length. */
|
||||
#define FSG_BUFLEN ((u32)16384)
|
||||
|
||||
/* Maximal number of LUNs supported in mass storage function */
|
||||
#define FSG_MAX_LUNS 8
|
||||
|
||||
enum fsg_buffer_state {
|
||||
BUF_STATE_EMPTY = 0,
|
||||
BUF_STATE_FULL,
|
||||
BUF_STATE_BUSY
|
||||
};
|
||||
|
||||
struct fsg_buffhd {
|
||||
#ifdef FSG_BUFFHD_STATIC_BUFFER
|
||||
char buf[FSG_BUFLEN];
|
||||
#else
|
||||
void *buf;
|
||||
#endif
|
||||
enum fsg_buffer_state state;
|
||||
struct fsg_buffhd *next;
|
||||
|
||||
/* The NetChip 2280 is faster, and handles some protocol faults
|
||||
* better, if we don't submit any short bulk-out read requests.
|
||||
* So we will record the intended request length here. */
|
||||
unsigned int bulk_out_intended_length;
|
||||
|
||||
struct usb_request *inreq;
|
||||
int inreq_busy;
|
||||
struct usb_request *outreq;
|
||||
int outreq_busy;
|
||||
};
|
||||
|
||||
enum fsg_state {
|
||||
/* This one isn't used anywhere */
|
||||
FSG_STATE_COMMAND_PHASE = -10,
|
||||
FSG_STATE_DATA_PHASE,
|
||||
FSG_STATE_STATUS_PHASE,
|
||||
|
||||
FSG_STATE_IDLE = 0,
|
||||
FSG_STATE_ABORT_BULK_OUT,
|
||||
FSG_STATE_RESET,
|
||||
FSG_STATE_INTERFACE_CHANGE,
|
||||
FSG_STATE_CONFIG_CHANGE_DISABLE,
|
||||
FSG_STATE_CONFIG_CHANGE,
|
||||
FSG_STATE_DISCONNECT,
|
||||
FSG_STATE_EXIT,
|
||||
FSG_STATE_TERMINATED
|
||||
};
|
||||
|
||||
enum data_direction {
|
||||
DATA_DIR_UNKNOWN = 0,
|
||||
DATA_DIR_FROM_HOST,
|
||||
DATA_DIR_TO_HOST,
|
||||
DATA_DIR_NONE
|
||||
};
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
static inline u32 get_unaligned_be24(u8 *buf)
|
||||
{
|
||||
return 0xffffff & (u32) get_unaligned_be32(buf - 1);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
enum {
|
||||
#ifndef FSG_NO_DEVICE_STRINGS
|
||||
FSG_STRING_MANUFACTURER = 1,
|
||||
FSG_STRING_PRODUCT,
|
||||
FSG_STRING_SERIAL,
|
||||
FSG_STRING_CONFIG,
|
||||
#endif
|
||||
FSG_STRING_INTERFACE
|
||||
};
|
||||
|
||||
|
||||
#ifndef FSG_NO_OTG
|
||||
static struct usb_otg_descriptor
|
||||
fsg_otg_desc = {
|
||||
.bLength = sizeof fsg_otg_desc,
|
||||
.bDescriptorType = USB_DT_OTG,
|
||||
|
||||
.bmAttributes = USB_OTG_SRP,
|
||||
};
|
||||
#endif
|
||||
|
||||
/* There is only one interface. */
|
||||
|
||||
static struct usb_interface_descriptor
|
||||
fsg_intf_desc = {
|
||||
.bLength = sizeof fsg_intf_desc,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
|
||||
.bNumEndpoints = 2, /* Adjusted during fsg_bind() */
|
||||
.bInterfaceClass = USB_CLASS_MASS_STORAGE,
|
||||
.bInterfaceSubClass = USB_SC_SCSI, /* Adjusted during fsg_bind() */
|
||||
.bInterfaceProtocol = USB_PR_BULK, /* Adjusted during fsg_bind() */
|
||||
.iInterface = FSG_STRING_INTERFACE,
|
||||
};
|
||||
|
||||
/* Three full-speed endpoint descriptors: bulk-in, bulk-out,
|
||||
* and interrupt-in. */
|
||||
|
||||
static struct usb_endpoint_descriptor
|
||||
fsg_fs_bulk_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
/* wMaxPacketSize set by autoconfiguration */
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor
|
||||
fsg_fs_bulk_out_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
.bEndpointAddress = USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
/* wMaxPacketSize set by autoconfiguration */
|
||||
};
|
||||
|
||||
#ifndef FSG_NO_INTR_EP
|
||||
|
||||
static struct usb_endpoint_descriptor
|
||||
fsg_fs_intr_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(2),
|
||||
.bInterval = 32, /* frames -> 32 ms */
|
||||
};
|
||||
|
||||
#ifndef FSG_NO_OTG
|
||||
# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 2
|
||||
#else
|
||||
# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
static struct usb_descriptor_header *fsg_fs_function[] = {
|
||||
#ifndef FSG_NO_OTG
|
||||
(struct usb_descriptor_header *) &fsg_otg_desc,
|
||||
#endif
|
||||
(struct usb_descriptor_header *) &fsg_intf_desc,
|
||||
(struct usb_descriptor_header *) &fsg_fs_bulk_in_desc,
|
||||
(struct usb_descriptor_header *) &fsg_fs_bulk_out_desc,
|
||||
#ifndef FSG_NO_INTR_EP
|
||||
(struct usb_descriptor_header *) &fsg_fs_intr_in_desc,
|
||||
#endif
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* USB 2.0 devices need to expose both high speed and full speed
|
||||
* descriptors, unless they only run at full speed.
|
||||
*
|
||||
* That means alternate endpoint descriptors (bigger packets)
|
||||
* and a "device qualifier" ... plus more construction options
|
||||
* for the config descriptor.
|
||||
*/
|
||||
static struct usb_endpoint_descriptor
|
||||
fsg_hs_bulk_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
/* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor
|
||||
fsg_hs_bulk_out_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
/* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
.bInterval = 1, /* NAK every 1 uframe */
|
||||
};
|
||||
|
||||
#ifndef FSG_NO_INTR_EP
|
||||
|
||||
static struct usb_endpoint_descriptor
|
||||
fsg_hs_intr_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
/* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(2),
|
||||
.bInterval = 9, /* 2**(9-1) = 256 uframes -> 32 ms */
|
||||
};
|
||||
|
||||
#ifndef FSG_NO_OTG
|
||||
# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 2
|
||||
#else
|
||||
# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
static struct usb_descriptor_header *fsg_hs_function[] = {
|
||||
#ifndef FSG_NO_OTG
|
||||
(struct usb_descriptor_header *) &fsg_otg_desc,
|
||||
#endif
|
||||
(struct usb_descriptor_header *) &fsg_intf_desc,
|
||||
(struct usb_descriptor_header *) &fsg_hs_bulk_in_desc,
|
||||
(struct usb_descriptor_header *) &fsg_hs_bulk_out_desc,
|
||||
#ifndef FSG_NO_INTR_EP
|
||||
(struct usb_descriptor_header *) &fsg_hs_intr_in_desc,
|
||||
#endif
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* Maxpacket and other transfer characteristics vary by speed. */
|
||||
static struct usb_endpoint_descriptor *
|
||||
fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
|
||||
struct usb_endpoint_descriptor *hs)
|
||||
{
|
||||
if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
|
||||
return hs;
|
||||
return fs;
|
||||
}
|
||||
|
||||
|
||||
/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */
|
||||
static struct usb_string fsg_strings[] = {
|
||||
#ifndef FSG_NO_DEVICE_STRINGS
|
||||
{FSG_STRING_MANUFACTURER, fsg_string_manufacturer},
|
||||
{FSG_STRING_PRODUCT, fsg_string_product},
|
||||
{FSG_STRING_SERIAL, fsg_string_serial},
|
||||
{FSG_STRING_CONFIG, fsg_string_config},
|
||||
#endif
|
||||
{FSG_STRING_INTERFACE, fsg_string_interface},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings fsg_stringtab = {
|
||||
.language = 0x0409, /* en-us */
|
||||
.strings = fsg_strings,
|
||||
};
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* If the next two routines are called while the gadget is registered,
|
||||
* the caller must own fsg->filesem for writing. */
|
||||
|
||||
static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
|
||||
{
|
||||
int ro;
|
||||
struct file *filp = NULL;
|
||||
int rc = -EINVAL;
|
||||
struct inode *inode = NULL;
|
||||
loff_t size;
|
||||
loff_t num_sectors;
|
||||
loff_t min_sectors;
|
||||
|
||||
/* R/W if we can, R/O if we must */
|
||||
ro = curlun->initially_ro;
|
||||
if (!ro) {
|
||||
filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0);
|
||||
if (-EROFS == PTR_ERR(filp))
|
||||
ro = 1;
|
||||
}
|
||||
if (ro)
|
||||
filp = filp_open(filename, O_RDONLY | O_LARGEFILE, 0);
|
||||
if (IS_ERR(filp)) {
|
||||
LINFO(curlun, "unable to open backing file: %s\n", filename);
|
||||
return PTR_ERR(filp);
|
||||
}
|
||||
|
||||
if (!(filp->f_mode & FMODE_WRITE))
|
||||
ro = 1;
|
||||
|
||||
if (filp->f_path.dentry)
|
||||
inode = filp->f_path.dentry->d_inode;
|
||||
if (inode && S_ISBLK(inode->i_mode)) {
|
||||
if (bdev_read_only(inode->i_bdev))
|
||||
ro = 1;
|
||||
} else if (!inode || !S_ISREG(inode->i_mode)) {
|
||||
LINFO(curlun, "invalid file type: %s\n", filename);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* If we can't read the file, it's no good.
|
||||
* If we can't write the file, use it read-only. */
|
||||
if (!filp->f_op || !(filp->f_op->read || filp->f_op->aio_read)) {
|
||||
LINFO(curlun, "file not readable: %s\n", filename);
|
||||
goto out;
|
||||
}
|
||||
if (!(filp->f_op->write || filp->f_op->aio_write))
|
||||
ro = 1;
|
||||
|
||||
size = i_size_read(inode->i_mapping->host);
|
||||
if (size < 0) {
|
||||
LINFO(curlun, "unable to find file size: %s\n", filename);
|
||||
rc = (int) size;
|
||||
goto out;
|
||||
}
|
||||
num_sectors = size >> 9; /* File size in 512-byte blocks */
|
||||
min_sectors = 1;
|
||||
if (curlun->cdrom) {
|
||||
num_sectors &= ~3; /* Reduce to a multiple of 2048 */
|
||||
min_sectors = 300*4; /* Smallest track is 300 frames */
|
||||
if (num_sectors >= 256*60*75*4) {
|
||||
num_sectors = (256*60*75 - 1) * 4;
|
||||
LINFO(curlun, "file too big: %s\n", filename);
|
||||
LINFO(curlun, "using only first %d blocks\n",
|
||||
(int) num_sectors);
|
||||
}
|
||||
}
|
||||
if (num_sectors < min_sectors) {
|
||||
LINFO(curlun, "file too small: %s\n", filename);
|
||||
rc = -ETOOSMALL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
get_file(filp);
|
||||
curlun->ro = ro;
|
||||
curlun->filp = filp;
|
||||
curlun->file_length = size;
|
||||
curlun->num_sectors = num_sectors;
|
||||
LDBG(curlun, "open backing file: %s\n", filename);
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
filp_close(filp, current->files);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static void fsg_lun_close(struct fsg_lun *curlun)
|
||||
{
|
||||
if (curlun->filp) {
|
||||
LDBG(curlun, "close backing file\n");
|
||||
fput(curlun->filp);
|
||||
curlun->filp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* Sync the file data, don't bother with the metadata.
|
||||
* This code was copied from fs/buffer.c:sys_fdatasync(). */
|
||||
static int fsg_lun_fsync_sub(struct fsg_lun *curlun)
|
||||
{
|
||||
struct file *filp = curlun->filp;
|
||||
|
||||
if (curlun->ro || !filp)
|
||||
return 0;
|
||||
return vfs_fsync(filp, filp->f_path.dentry, 1);
|
||||
}
|
||||
|
||||
static void store_cdrom_address(u8 *dest, int msf, u32 addr)
|
||||
{
|
||||
if (msf) {
|
||||
/* Convert to Minutes-Seconds-Frames */
|
||||
addr >>= 2; /* Convert to 2048-byte frames */
|
||||
addr += 2*75; /* Lead-in occupies 2 seconds */
|
||||
dest[3] = addr % 75; /* Frames */
|
||||
addr /= 75;
|
||||
dest[2] = addr % 60; /* Seconds */
|
||||
addr /= 60;
|
||||
dest[1] = addr; /* Minutes */
|
||||
dest[0] = 0; /* Reserved */
|
||||
} else {
|
||||
/* Absolute sector */
|
||||
put_unaligned_be32(addr, dest);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
static ssize_t fsg_show_ro(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", fsg_lun_is_open(curlun)
|
||||
? curlun->ro
|
||||
: curlun->initially_ro);
|
||||
}
|
||||
|
||||
static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
|
||||
struct rw_semaphore *filesem = dev_get_drvdata(dev);
|
||||
char *p;
|
||||
ssize_t rc;
|
||||
|
||||
down_read(filesem);
|
||||
if (fsg_lun_is_open(curlun)) { /* Get the complete pathname */
|
||||
p = d_path(&curlun->filp->f_path, buf, PAGE_SIZE - 1);
|
||||
if (IS_ERR(p))
|
||||
rc = PTR_ERR(p);
|
||||
else {
|
||||
rc = strlen(p);
|
||||
memmove(buf, p, rc);
|
||||
buf[rc] = '\n'; /* Add a newline */
|
||||
buf[++rc] = 0;
|
||||
}
|
||||
} else { /* No file, return 0 bytes */
|
||||
*buf = 0;
|
||||
rc = 0;
|
||||
}
|
||||
up_read(filesem);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
ssize_t rc = count;
|
||||
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
|
||||
struct rw_semaphore *filesem = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
||||
if (sscanf(buf, "%d", &i) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
/* Allow the write-enable status to change only while the backing file
|
||||
* is closed. */
|
||||
down_read(filesem);
|
||||
if (fsg_lun_is_open(curlun)) {
|
||||
LDBG(curlun, "read-only status change prevented\n");
|
||||
rc = -EBUSY;
|
||||
} else {
|
||||
curlun->ro = !!i;
|
||||
curlun->initially_ro = !!i;
|
||||
LDBG(curlun, "read-only status set to %d\n", curlun->ro);
|
||||
}
|
||||
up_read(filesem);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
|
||||
struct rw_semaphore *filesem = dev_get_drvdata(dev);
|
||||
int rc = 0;
|
||||
|
||||
if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) {
|
||||
LDBG(curlun, "eject attempt prevented\n");
|
||||
return -EBUSY; /* "Door is locked" */
|
||||
}
|
||||
|
||||
/* Remove a trailing newline */
|
||||
if (count > 0 && buf[count-1] == '\n')
|
||||
((char *) buf)[count-1] = 0; /* Ugh! */
|
||||
|
||||
/* Eject current medium */
|
||||
down_write(filesem);
|
||||
if (fsg_lun_is_open(curlun)) {
|
||||
fsg_lun_close(curlun);
|
||||
curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
|
||||
}
|
||||
|
||||
/* Load new medium */
|
||||
if (count > 0 && buf[0]) {
|
||||
rc = fsg_lun_open(curlun, buf);
|
||||
if (rc == 0)
|
||||
curlun->unit_attention_data =
|
||||
SS_NOT_READY_TO_READY_TRANSITION;
|
||||
}
|
||||
up_write(filesem);
|
||||
return (rc < 0 ? rc : count);
|
||||
}
|
@ -1,738 +0,0 @@
|
||||
/*
|
||||
* LEGO® MINDSTORMS EV3
|
||||
*
|
||||
* Copyright (C) 2010-2013 The LEGO Group
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This UsbFunction file is based on and inheritated from
|
||||
* the original file (f_sourcesink.c) and work done by
|
||||
* David Brownell
|
||||
*
|
||||
* >> f_sourcesink.c - USB peripheral source/sink configuration driver <<
|
||||
*
|
||||
* >> Copyright (C) 2003-2008 David Brownell <<
|
||||
* >> Copyright (C) 2008 by Nokia Corporation <<
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* HID IN/OUT Interrupt transfer FUNCTION ...
|
||||
*
|
||||
*/
|
||||
|
||||
struct f_rudolf {
|
||||
struct usb_function function;
|
||||
|
||||
struct usb_ep *in_ep;
|
||||
struct usb_ep *out_ep;
|
||||
};
|
||||
|
||||
enum // Used for signaling the IN stuff USB-state
|
||||
{ // Data from the Brick to the HOST
|
||||
USB_DATA_IDLE, //
|
||||
USB_DATA_BUSY, // Ongoing USB request
|
||||
USB_DATA_PENDING, // Data ready for X-fer, but USB busy
|
||||
USB_DATA_READY, // Initial setting
|
||||
};
|
||||
|
||||
int input_state = USB_DATA_IDLE;
|
||||
struct usb_ep *save_in_ep;
|
||||
struct usb_request *save_in_req;
|
||||
|
||||
#ifndef PCASM
|
||||
static inline struct f_rudolf *func_to_rudolf(struct usb_function *f)
|
||||
{
|
||||
return container_of(f, struct f_rudolf, function);
|
||||
}
|
||||
#else
|
||||
// Keep Eclipse happy
|
||||
#endif
|
||||
|
||||
static struct usb_interface_descriptor rudolf_intf = {
|
||||
.bLength = sizeof rudolf_intf,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bInterfaceNumber = 0,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 2, // Just plain in and out
|
||||
.bInterfaceClass = USB_CLASS_HID, // We go for NONE custom-driver
|
||||
.bInterfaceSubClass = 0,
|
||||
.bInterfaceProtocol = 0,
|
||||
/* .iInterface = DYNAMIC */
|
||||
};
|
||||
|
||||
static struct hid_descriptor hs_hid_rudolf_desc = {
|
||||
.bLength = sizeof hs_hid_rudolf_desc,
|
||||
.bDescriptorType = HID_DT_HID,
|
||||
.bcdHID = cpu_to_le16(0x0110),
|
||||
.bCountryCode = 0x00,
|
||||
.bNumDescriptors = 0x01, // "The one and only"
|
||||
.desc[0].bDescriptorType = 0x22, // Report Descriptor Type - 0x22 = HID
|
||||
.desc[0].wDescriptorLength = sizeof hs_hid_report_descriptor,
|
||||
/*.desc[0].bDescriptorType = DYNAMIC */
|
||||
/*.desc[0].wDescriptorLenght= DYNAMIC */
|
||||
};
|
||||
|
||||
static struct hid_descriptor fs_hid_rudolf_desc = {
|
||||
.bLength = sizeof fs_hid_rudolf_desc,
|
||||
.bDescriptorType = HID_DT_HID,
|
||||
.bcdHID = cpu_to_le16(0x0110),
|
||||
.bCountryCode = 0x00,
|
||||
.bNumDescriptors = 0x01, // "The one and only"
|
||||
.desc[0].bDescriptorType = 0x22, // Report Descriptor Type - 0x22 = HID
|
||||
.desc[0].wDescriptorLength = sizeof fs_hid_report_descriptor,
|
||||
|
||||
};
|
||||
|
||||
/* full speed support: */
|
||||
|
||||
static struct usb_endpoint_descriptor rudolf_out_fs_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(64),
|
||||
.bInterval = 1, /* 1 = 1 mSec POLL rate for FS */
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor rudolf_in_fs_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(64),
|
||||
.bInterval = 1, /* 1 = 1 mSec POLL rate for FS */
|
||||
};
|
||||
|
||||
/* high speed support: */
|
||||
|
||||
static struct usb_endpoint_descriptor rudolf_in_hs_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(1024),
|
||||
.bInterval = 4, /* Calculated as :
|
||||
* 2^(value-1) * 125uS
|
||||
* i.e. value 1: 2^(1-1) * 125 uSec = 125 uSec
|
||||
* - 4: 2^(4-1) * 125 uSec = 1 mSec
|
||||
*/
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor rudolf_out_hs_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(1024),
|
||||
.bInterval = 4, /* Calculated as :
|
||||
* 2^(value-1) * 125uS
|
||||
* i.e. value 1: 2^(1-1) * 125 uSec = 125 uSec
|
||||
* - 4: 2^(4-1) * 125 uSec = 1 mSec
|
||||
*/
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *hs_rudolf_descs[] = {
|
||||
(struct usb_descriptor_header *) &rudolf_intf,
|
||||
(struct usb_descriptor_header *) &hs_hid_rudolf_desc,
|
||||
(struct usb_descriptor_header *) &rudolf_in_hs_desc,
|
||||
(struct usb_descriptor_header *) &rudolf_out_hs_desc,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *fs_rudolf_descs[] = {
|
||||
(struct usb_descriptor_header *) &rudolf_intf,
|
||||
(struct usb_descriptor_header *) &fs_hid_rudolf_desc,
|
||||
(struct usb_descriptor_header *) &rudolf_in_fs_desc,
|
||||
(struct usb_descriptor_header *) &rudolf_out_fs_desc,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* function-specific strings: */
|
||||
|
||||
static struct usb_string strings_rudolf[] = {
|
||||
[0].s = "Xfer data to and from EV3 brick",
|
||||
{ } /* end of list */
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings stringtab_rudolf = {
|
||||
.language = 0x0409, /* en-us */
|
||||
.strings = strings_rudolf,
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings *rudolf_strings[] = {
|
||||
&stringtab_rudolf,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int
|
||||
f_rudolf_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
struct usb_composite_dev *cdev = c->cdev;
|
||||
struct f_rudolf *rudolf = func_to_rudolf(f);
|
||||
int id;
|
||||
|
||||
/* allocate interface ID(s) */
|
||||
id = usb_interface_id(c, f);
|
||||
if (id < 0)
|
||||
return id;
|
||||
rudolf_intf.bInterfaceNumber = id;
|
||||
|
||||
/* allocate endpoints */
|
||||
rudolf->in_ep = usb_ep_autoconfig(cdev->gadget, &rudolf_in_fs_desc);
|
||||
if (!rudolf->in_ep) {
|
||||
autoconf_fail:
|
||||
ERROR(cdev, "%s: can't autoconfigure on %s\n",
|
||||
f->name, cdev->gadget->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
rudolf->in_ep->driver_data = cdev; /* claim */
|
||||
|
||||
rudolf->out_ep = usb_ep_autoconfig(cdev->gadget, &rudolf_out_fs_desc);
|
||||
if (!rudolf->out_ep)
|
||||
goto autoconf_fail;
|
||||
rudolf->out_ep->driver_data = cdev; /* claim */
|
||||
|
||||
|
||||
/* support high speed hardware */
|
||||
if (gadget_is_dualspeed(c->cdev->gadget)) {
|
||||
|
||||
rudolf_in_hs_desc.bEndpointAddress =
|
||||
rudolf_in_fs_desc.bEndpointAddress;
|
||||
rudolf_out_hs_desc.bEndpointAddress =
|
||||
rudolf_out_fs_desc.bEndpointAddress;
|
||||
f->hs_descriptors = hs_rudolf_descs;
|
||||
f->descriptors = fs_rudolf_descs;
|
||||
}
|
||||
|
||||
DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
|
||||
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
|
||||
f->name, rudolf->in_ep->name, rudolf->out_ep->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
f_rudolf_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
kfree(func_to_rudolf(f));
|
||||
}
|
||||
|
||||
static void usb_req_arm(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (UsbSpeed.Speed == FULL_SPEED)
|
||||
{
|
||||
req->length = 64;
|
||||
req->actual = 64;
|
||||
}
|
||||
else
|
||||
{
|
||||
req->length = 1024;
|
||||
req->actual = 1024;
|
||||
}
|
||||
|
||||
status = usb_ep_queue(ep, req, GFP_ATOMIC);
|
||||
if (status) {
|
||||
usb_ep_set_halt(ep);
|
||||
/* FIXME recover later ... somehow */
|
||||
}
|
||||
}
|
||||
|
||||
static int read_data_from_host(struct usb_request *req)
|
||||
{
|
||||
unsigned i;
|
||||
u8 *buf = req->buf;
|
||||
|
||||
int from_host_length = 0; // NO ACCESS LOCKS YET
|
||||
|
||||
// test for actual length > 0
|
||||
|
||||
for (i = 0; i < req->actual; i++, buf++)
|
||||
{
|
||||
|
||||
usb_char_buffer_out[i] = *buf;
|
||||
from_host_length++;
|
||||
}
|
||||
|
||||
return (from_host_length);
|
||||
}
|
||||
|
||||
static void write_data_to_the_host(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
unsigned i;
|
||||
u8 *buf = req->buf;
|
||||
|
||||
//#define DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("WR to HOST req->length = %d\r\n", req->length);
|
||||
#endif
|
||||
|
||||
#undef DEBUG
|
||||
//#define DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("USB = %d, %d\r\n", usb_char_buffer_in[2], usb_char_buffer_in[3]);
|
||||
#endif
|
||||
#undef DEBUG
|
||||
|
||||
for (i = 0; i < req->length; i++)
|
||||
*buf++ = usb_char_buffer_in[i];
|
||||
usb_char_in_length = 0; // Reset and ready
|
||||
}
|
||||
|
||||
static void rudolf_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
struct f_rudolf *rudolf = ep->driver_data;
|
||||
int status = req->status;
|
||||
|
||||
|
||||
switch ( status ) {
|
||||
|
||||
case 0: /* normal completion? */
|
||||
if (ep == rudolf->out_ep) // An OUT completion?
|
||||
{
|
||||
//#define DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("Rudolf_complete OUT\n");
|
||||
#endif
|
||||
|
||||
usb_char_out_length = read_data_from_host(req);
|
||||
usb_req_arm(ep, req);
|
||||
}
|
||||
else // We have an INPUT request complete
|
||||
{
|
||||
//#define DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("Rudolf_complete IN\n");
|
||||
#endif
|
||||
|
||||
switch(input_state) // State of Brick data x-fer
|
||||
{
|
||||
case USB_DATA_READY: //should be BUSY or PENDING....
|
||||
|
||||
#ifdef DEBUG
|
||||
printk("IN_IN_IN - READY ?????\n");
|
||||
#endif
|
||||
|
||||
break;
|
||||
|
||||
case USB_DATA_PENDING: //
|
||||
// #define DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("IN_IN_IN - PENDING settes to BUSY\n");
|
||||
#endif
|
||||
|
||||
input_state = USB_DATA_BUSY;
|
||||
write_data_to_the_host(ep, req);
|
||||
usb_req_arm(ep, req); // new request
|
||||
break;
|
||||
|
||||
case USB_DATA_BUSY: //
|
||||
#ifdef DEBUG
|
||||
printk("IN_IN_IN - BUSY settes to READY\n");
|
||||
#endif
|
||||
#undef DEBUG
|
||||
input_state = USB_DATA_READY;
|
||||
// and relax
|
||||
break;
|
||||
|
||||
case USB_DATA_IDLE: // too lazy
|
||||
#ifdef DEBUG
|
||||
printk("IN_IN_IN - IDLE\n");
|
||||
#endif
|
||||
//#undef DEBUG
|
||||
|
||||
break;
|
||||
|
||||
default: break; // hmmm.
|
||||
}
|
||||
// Reset the buffer size - Ready again
|
||||
usb_char_in_length = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
/* this endpoint is normally active while we're configured */
|
||||
|
||||
case -ESHUTDOWN: /* disconnect from host */
|
||||
// REMOVED 26102012 (*pUsbSpeed).Speed = FULL_SPEED;
|
||||
case -ECONNABORTED: /* hardware forced ep reset */
|
||||
case -ECONNRESET: /* request dequeued */
|
||||
//case -ESHUTDOWN: /* disconnect from host */
|
||||
if (ep == rudolf->out_ep)
|
||||
read_data_from_host(req);
|
||||
free_ep_req(ep, req);
|
||||
return;
|
||||
|
||||
case -EOVERFLOW: /* buffer overrun on read means that
|
||||
we didn't provide a big enough
|
||||
buffer.
|
||||
*/
|
||||
default:
|
||||
//#if 1
|
||||
// DBG(cdev, "%s complete --> %d, %d/%d\n", ep->name,
|
||||
// status, req->actual, req->length);
|
||||
//#endif
|
||||
case -EREMOTEIO: /* short read */
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int rudolf_start_ep(struct f_rudolf *rudolf, bool is_in)
|
||||
{
|
||||
struct usb_ep *ep;
|
||||
struct usb_request *req;
|
||||
int status;
|
||||
|
||||
ep = is_in ? rudolf->in_ep : rudolf->out_ep;
|
||||
req = alloc_ep_req(ep);
|
||||
if (!req)
|
||||
return -ENOMEM;
|
||||
|
||||
req->complete = rudolf_complete;
|
||||
|
||||
#ifdef DEBUG
|
||||
printk("UsbSpeed.Speed = %d\n\r", UsbSpeed.Speed);
|
||||
#endif
|
||||
|
||||
if (UsbSpeed.Speed == FULL_SPEED)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printk("rudolf_start_ep FULL\n\r");
|
||||
#endif
|
||||
|
||||
(*pUsbSpeed).Speed = FULL_SPEED;
|
||||
req->length = 64; // Full speed max buffer size
|
||||
req->actual = 64;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printk("rudolf_start_ep HIGH\n\r");
|
||||
#endif
|
||||
|
||||
(*pUsbSpeed).Speed = HIGH_SPEED;
|
||||
req->length = 1024; // High speed max buffer size
|
||||
req->actual = 1024;
|
||||
}
|
||||
|
||||
if (is_in)
|
||||
{
|
||||
save_in_ep = ep;
|
||||
save_in_req = req;
|
||||
|
||||
#ifdef DEBUG
|
||||
printk("req->length = %d ***** Rudolf_Start_Ep_in\n\r", req->length);
|
||||
#endif
|
||||
|
||||
// reinit_write_data(ep, req);
|
||||
input_state = USB_DATA_BUSY;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printk("***** Rudolf_Start_Ep_out\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
status = usb_ep_queue(ep, req, GFP_ATOMIC);
|
||||
|
||||
if (status) {
|
||||
struct usb_composite_dev *cdev;
|
||||
|
||||
cdev = rudolf->function.config->cdev;
|
||||
ERROR(cdev, "start %s %s --> %d\n",
|
||||
is_in ? "IN" : "OUT",
|
||||
ep->name, status);
|
||||
|
||||
free_ep_req(ep, req);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void disable_rudolf(struct f_rudolf *rudolf)
|
||||
{
|
||||
struct usb_composite_dev *cdev;
|
||||
|
||||
cdev = rudolf->function.config->cdev;
|
||||
disable_endpoints(cdev, rudolf->in_ep, rudolf->out_ep);
|
||||
VDBG(cdev, "%s disabled\n", rudolf->function.name);
|
||||
}
|
||||
|
||||
static int
|
||||
enable_rudolf(struct usb_composite_dev *cdev, struct f_rudolf *rudolf)
|
||||
{
|
||||
int result = 0;
|
||||
const struct usb_endpoint_descriptor *ep_in, *ep_out;
|
||||
struct usb_ep *ep;
|
||||
|
||||
ep_in = ep_choose(cdev->gadget, &rudolf_in_hs_desc, &rudolf_in_fs_desc);
|
||||
|
||||
ep_out = ep_choose(cdev->gadget, &rudolf_out_hs_desc, &rudolf_out_fs_desc);
|
||||
|
||||
ep = rudolf->in_ep;
|
||||
|
||||
result = usb_ep_enable(ep, ep_in);
|
||||
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
ep->driver_data = rudolf;
|
||||
|
||||
result = rudolf_start_ep(rudolf, true);
|
||||
|
||||
if (result < 0) {
|
||||
fail:
|
||||
ep = rudolf->in_ep;
|
||||
usb_ep_disable(ep);
|
||||
ep->driver_data = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* one endpoint reads (sinks) anything OUT (from the host) */
|
||||
ep = rudolf->out_ep;
|
||||
result = usb_ep_enable(ep, ep_out);
|
||||
|
||||
if (result < 0)
|
||||
goto fail;
|
||||
|
||||
ep->driver_data = rudolf;
|
||||
|
||||
result = rudolf_start_ep(rudolf, false);
|
||||
|
||||
if (result < 0) {
|
||||
usb_ep_disable(ep);
|
||||
ep->driver_data = NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
DBG(cdev, "%s enabled\n", rudolf->function.name);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int f_rudolf_set_alt(struct usb_function *f,
|
||||
unsigned intf, unsigned alt)
|
||||
{
|
||||
struct f_rudolf *rudolf = func_to_rudolf(f);
|
||||
struct usb_composite_dev *cdev = f->config->cdev;
|
||||
|
||||
/* we know alt is zero */
|
||||
if (rudolf->in_ep->driver_data)
|
||||
disable_rudolf(rudolf);
|
||||
|
||||
return enable_rudolf(cdev, rudolf);
|
||||
}
|
||||
|
||||
static void f_rudolf_disable(struct usb_function *f)
|
||||
{
|
||||
struct f_rudolf *rudolf = func_to_rudolf(f);
|
||||
|
||||
disable_rudolf(rudolf);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int msg_config(struct usb_configuration *c);
|
||||
|
||||
static int rudolf_bind_config(struct usb_configuration *c)
|
||||
{
|
||||
struct f_rudolf *rudolf;
|
||||
int status;
|
||||
|
||||
rudolf = kzalloc(sizeof *rudolf, GFP_KERNEL);
|
||||
if (!rudolf)
|
||||
return -ENOMEM;
|
||||
|
||||
rudolf->function.name = "rudolf xfer";
|
||||
rudolf->function.descriptors = hs_rudolf_descs;
|
||||
rudolf->function.bind = f_rudolf_bind;
|
||||
rudolf->function.unbind = f_rudolf_unbind;
|
||||
rudolf->function.set_alt = f_rudolf_set_alt;
|
||||
rudolf->function.disable = f_rudolf_disable;
|
||||
|
||||
status = usb_add_function(c, &rudolf->function);
|
||||
if (status) {
|
||||
kfree(rudolf);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status = msg_config(c);
|
||||
if (status) {
|
||||
kfree(rudolf);
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifndef PCASM
|
||||
static int rudolf_setup(struct usb_configuration *c,
|
||||
const struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
struct usb_request *req = c->cdev->req;
|
||||
int value = -EOPNOTSUPP;
|
||||
u16 w_index = le16_to_cpu(ctrl->wIndex);
|
||||
u16 w_value = le16_to_cpu(ctrl->wValue);
|
||||
u16 w_length = le16_to_cpu(ctrl->wLength);
|
||||
u16 length = 0;
|
||||
|
||||
/* composite driver infrastructure handles everything except
|
||||
* the two control test requests.
|
||||
*/
|
||||
|
||||
switch (ctrl->bRequest) {
|
||||
|
||||
/*
|
||||
* These are the same vendor-specific requests supported by
|
||||
* Intel's USB 2.0 compliance test devices. We exceed that
|
||||
* device spec by allowing multiple-packet requests.
|
||||
*
|
||||
* NOTE: the Control-OUT data stays in req->buf ... better
|
||||
* would be copying it into a scratch buffer, so that other
|
||||
* requests may safely intervene.
|
||||
*/
|
||||
|
||||
case 0x5b: /* control WRITE test -- fill the buffer */
|
||||
if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR))
|
||||
goto unknown;
|
||||
if (w_value || w_index)
|
||||
break;
|
||||
/* just read that many bytes into the buffer */
|
||||
if (w_length > req->length)
|
||||
break;
|
||||
value = w_length;
|
||||
break;
|
||||
case 0x5c: /* control READ test -- return the buffer */
|
||||
if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR))
|
||||
goto unknown;
|
||||
if (w_value || w_index)
|
||||
break;
|
||||
/* expect those bytes are still in the buffer; send back */
|
||||
if (w_length > req->length)
|
||||
break;
|
||||
value = w_length;
|
||||
break;
|
||||
|
||||
default:
|
||||
unknown:
|
||||
VDBG(c->cdev,
|
||||
"unknown control req%02x.%02x v%04x i%04x l%d\n",
|
||||
ctrl->bRequestType, ctrl->bRequest,
|
||||
w_value, w_index, w_length);
|
||||
}
|
||||
|
||||
//HER SKAL HID DESC SENDES!!!
|
||||
switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
|
||||
|
||||
|
||||
case ((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8
|
||||
| USB_REQ_GET_DESCRIPTOR):
|
||||
switch (w_value >> 8) {
|
||||
case HID_DT_REPORT:
|
||||
//VDBG(cdev, "USB_REQ_GET_DESCRIPTOR: REPORT\n");
|
||||
length = w_length;
|
||||
length = min_t(unsigned short, length,
|
||||
sizeof hs_hid_report_descriptor);
|
||||
memcpy(req->buf, hs_hid_report_descriptor, length);
|
||||
value = length;
|
||||
goto respond;
|
||||
break;
|
||||
|
||||
default:
|
||||
//VDBG(cdev, "Unknown decriptor request 0x%x\n",
|
||||
// value >> 8);
|
||||
goto stall;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//VDBG(cdev, "Unknown request 0x%x\n",
|
||||
// ctrl->bRequest);
|
||||
goto stall;
|
||||
break;
|
||||
}
|
||||
|
||||
//HERTIL
|
||||
/* respond with data transfer or status phase? */
|
||||
stall:
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
respond:
|
||||
if (value >= 0) {
|
||||
VDBG(c->cdev, "source/sink req%02x.%02x v%04x i%04x l%d\n",
|
||||
ctrl->bRequestType, ctrl->bRequest,
|
||||
w_value, w_index, w_length);
|
||||
req->zero = 0;
|
||||
req->length = value;
|
||||
value = usb_ep_queue(c->cdev->gadget->ep0, req, GFP_ATOMIC);
|
||||
if (value < 0)
|
||||
ERROR(c->cdev, "source/sinkc response, err %d\n",
|
||||
value);
|
||||
}
|
||||
|
||||
/* device either stalls (value < 0) or reports success */
|
||||
return value;
|
||||
}
|
||||
#else
|
||||
// Keep Eclipse happy
|
||||
#endif
|
||||
|
||||
static struct usb_configuration rudolf_driver = {
|
||||
.label = "rudolf driver",
|
||||
.strings = rudolf_strings,
|
||||
.bind = rudolf_bind_config,
|
||||
.setup = rudolf_setup,
|
||||
.bConfigurationValue = 1,
|
||||
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
|
||||
/* .iConfiguration = DYNAMIC */
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
int rudolf_add(struct usb_composite_dev *cdev, bool autoresume)
|
||||
{
|
||||
int id;
|
||||
|
||||
/* allocate string ID(s) */
|
||||
id = usb_string_id(cdev);
|
||||
if (id < 0)
|
||||
return id;
|
||||
strings_rudolf[0].id = id;
|
||||
|
||||
rudolf_intf.iInterface = id;
|
||||
rudolf_driver.iConfiguration = 1; // id;
|
||||
|
||||
/* support autoresume for remote wakeup testing */
|
||||
if (autoresume)
|
||||
rudolf_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
|
||||
/* support OTG systems */
|
||||
if (gadget_is_otg(cdev->gadget)) {
|
||||
rudolf_driver.descriptors = otg_desc;
|
||||
rudolf_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
}
|
||||
|
||||
return usb_add_config(cdev, &rudolf_driver);
|
||||
}
|
7
brick/mk
7
brick/mk
@ -1,7 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -xe
|
||||
scp -qr kernel uf2daemon Makefile vm:linux/pxt/
|
||||
ssh vm "cd linux/pxt; make $1"
|
||||
mkdir -p bin
|
||||
scp vm:linux/pxt/bin/* bin/
|
||||
|
@ -1,14 +0,0 @@
|
||||
# Patched EV3 image
|
||||
|
||||
The file `ev3-fs.patch` summarizes the changes done to the original V1.09D image.
|
||||
You can see some text files are edited, the `d_usbdev.ko` is updated (sources in `../kernel`),
|
||||
`uf2d` added (sources in `../uf2daemon`), and a stock `nbd.ko` module is added.
|
||||
|
||||
Additionally, the `edimax01.ko` is replaced by now much more popular `rtl8192cu.ko` (also stock).
|
||||
|
||||
The init script has a hook for running a shell script from `/mnt/ramdisk/`. This can be used
|
||||
for testing different modules etc.
|
||||
|
||||
The kernel command line has been modified to:
|
||||
* disable DMA for the MUSB driver - otherwise the mass storage device is very unstable
|
||||
* increase the size of dmesg buffer to 128k
|
@ -1,34 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
let fs = require("fs")
|
||||
|
||||
let styles = {
|
||||
"0": "rxtx",
|
||||
"1": " tx",
|
||||
"2": "rx ",
|
||||
}
|
||||
|
||||
function build() {
|
||||
let kern = fs.readFileSync( "foo")
|
||||
let off = 0x0001df30
|
||||
|
||||
kern = kern.slice(off + 6 * 5, off + 6 * (5 + 6))
|
||||
console.log(kern.toString("hex"))
|
||||
off = 0
|
||||
|
||||
for (let i = 0; i < 30; ++i) {
|
||||
if (kern[off+4] == 64) {
|
||||
kern[off+4] = 0
|
||||
kern[off+5] = 2
|
||||
}
|
||||
if(kern[off] == 3 || kern[off] == 4) {
|
||||
kern[off+4] = 0
|
||||
kern[off+5] = 1
|
||||
}
|
||||
console.log(`ep=${kern[off]} style=${styles[kern[off+1]]} buf=${kern[off+2] == 0 ? "sin" : kern[off+2] == 1 ? "dbl" : "XXX"} pad=${kern[off+3]} sz=${kern[off+4]+(kern[off+5]<<8)}`)
|
||||
off += 6
|
||||
}
|
||||
console.log(kern.toString("hex"))
|
||||
}
|
||||
|
||||
build()
|
@ -1,53 +0,0 @@
|
||||
diff -ur orig-ev3/etc/init.d/ev3init.sh dev-ev3/etc/init.d/ev3init.sh
|
||||
--- orig-ev3/etc/init.d/ev3init.sh 1970-01-01 01:00:00.000000000 +0100
|
||||
+++ dev-ev3/etc/init.d/ev3init.sh 2017-07-27 12:19:43.195041798 +0100
|
||||
@@ -1,5 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
+echo Y > /sys/module/printk/parameters/time
|
||||
+
|
||||
bluetoothd -n > /dev/null 2>&1 &
|
||||
|
||||
echo "Setting up VirtualDrive...";
|
||||
@@ -60,3 +62,6 @@
|
||||
sleep 2
|
||||
hciattach /dev/ttyS2 texas 2000000 "flow" "nosleep" $STRING
|
||||
sdptool add SP
|
||||
+
|
||||
+insmod /lib/modules/2.6.33-rc4/kernel/drivers/net/wireless/rtl8192cu.ko
|
||||
+. /mnt/ramdisk/rc.local || :
|
||||
Only in orig-ev3/home/root/lms2012/sys: exit~
|
||||
diff -ur orig-ev3/home/root/lms2012/sys/init dev-ev3/home/root/lms2012/sys/init
|
||||
--- orig-ev3/home/root/lms2012/sys/init 1970-01-01 01:00:00.000000000 +0100
|
||||
+++ dev-ev3/home/root/lms2012/sys/init 2017-07-27 12:23:43.072605126 +0100
|
||||
@@ -5,13 +5,15 @@
|
||||
var=$(printf 'HostStr=%s SerialStr=%s' $(cat /home/root/lms2012/sys/settings/BrickName) $(cat /home/root/lms2012/sys/settings/BTser))
|
||||
echo $var > /home/root/lms2012/sys/settings/UsbInfo.dat
|
||||
|
||||
+insmod ${PWD}/mod/nbd.ko
|
||||
+${PWD}/uf2d
|
||||
insmod ${PWD}/mod/d_iic.ko `cat /home/root/lms2012/sys/settings/HwId`
|
||||
insmod ${PWD}/mod/d_uart.ko `cat /home/root/lms2012/sys/settings/HwId`
|
||||
insmod ${PWD}/mod/d_power.ko `cat /home/root/lms2012/sys/settings/HwId`
|
||||
insmod ${PWD}/mod/d_pwm.ko `cat /home/root/lms2012/sys/settings/HwId`
|
||||
insmod ${PWD}/mod/d_ui.ko `cat /home/root/lms2012/sys/settings/HwId`
|
||||
insmod ${PWD}/mod/d_analog.ko `cat /home/root/lms2012/sys/settings/HwId`
|
||||
-insmod ${PWD}/mod/d_usbdev.ko `cat /home/root/lms2012/sys/settings/UsbInfo.dat`
|
||||
+insmod ${PWD}/mod/d_usbdev.ko `cat /home/root/lms2012/sys/settings/UsbInfo.dat` file=/dev/nbd0
|
||||
insmod ${PWD}/mod/d_usbhost.ko
|
||||
insmod ${PWD}/mod/d_sound.ko `cat /home/root/lms2012/sys/settings/HwId`
|
||||
insmod ${PWD}/mod/d_bt.ko `cat /home/root/lms2012/sys/settings/HwId`
|
||||
@@ -29,6 +31,8 @@
|
||||
chmod 666 /dev/lms_iic
|
||||
chmod 666 /dev/lms_bt
|
||||
|
||||
+echo 4 > /proc/sys/kernel/printk
|
||||
+
|
||||
cd ..
|
||||
ls -R > /dev/null
|
||||
cd sys
|
||||
Binary files orig-ev3/home/root/lms2012/sys/mod/d_usbdev.ko and dev-ev3/home/root/lms2012/sys/mod/d_usbdev.ko differ
|
||||
Only in dev-ev3/home/root/lms2012/sys/mod: nbd.ko
|
||||
Only in dev-ev3/home/root/lms2012/sys: uf2d
|
||||
Only in orig-ev3/lib/modules/2.6.33-rc4/kernel/drivers/net/wireless: edimax01.ko
|
||||
Only in dev-ev3/lib/modules/2.6.33-rc4/kernel/drivers/net/wireless: rtl8192cu.ko
|
@ -1,55 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
let fs = require("fs")
|
||||
// we try to use shorter versions of all parameters for the additional parameters to fit
|
||||
let bootargs = "mem=${memsize} initrd=${filesysaddr},${filesyssize} root=/dev/ram0 rw rootfstype=cramfs console=${console} ip=${ipaddr} lpj=747520 quiet"
|
||||
let bootnews = "mem=64M initrd=0xC1180000,10M root=1:0 rw rootfstype=cramfs console=${console} lpj=747520 musb_hdrc.use_dma=0 log_buf_len=128k quiet"
|
||||
let piggy = true
|
||||
|
||||
function build() {
|
||||
if (bootnews.length > bootargs.length) {
|
||||
console.log("args too long")
|
||||
return
|
||||
}
|
||||
|
||||
while (bootnews.length < bootargs.length)
|
||||
bootnews += " "
|
||||
|
||||
let cr = fs.readFileSync("cram.bin")
|
||||
|
||||
if (cr.length > 10485760) {
|
||||
console.log("too big by " + (cr.length - 10485760))
|
||||
return
|
||||
}
|
||||
let img = fs.readFileSync("EV3 Firmware V1.09D.bin")
|
||||
|
||||
for (let i = 0; i < bootnews.length; ++i) {
|
||||
if (img[0x21DDA + i] != bootargs.charCodeAt(i)) {
|
||||
console.log("boot args mismatch")
|
||||
return
|
||||
}
|
||||
img[0x21DDA + i] = bootnews.charCodeAt(i)
|
||||
}
|
||||
|
||||
let off = 0x250000
|
||||
if (img[off] != 0x45 || img[off + 1] != 0x3d) {
|
||||
console.log("bad magic: " + img[off] + " / " + img[off+1])
|
||||
return
|
||||
}
|
||||
|
||||
cr.copy(img, off)
|
||||
|
||||
let kern = fs.readFileSync(piggy ? "piggy-patched.gzip" : "linux/arch/arm/boot/uImage")
|
||||
off = piggy ? 0x0005540f : 0x00050000
|
||||
|
||||
if (img[off] != kern[0] || img[off+1] != kern[1]) {
|
||||
console.log("bad kernel magic: " + img[off] + " / " + img[off+1])
|
||||
return
|
||||
}
|
||||
|
||||
kern.copy(img, off)
|
||||
|
||||
fs.writeFileSync("firmware.bin", img)
|
||||
}
|
||||
|
||||
build()
|
@ -1,9 +0,0 @@
|
||||
#!/bin/sh
|
||||
# dd if=EV3\ Firmware\ V1.09D.bin of=orig.cram bs=65536 skip=37 count=400
|
||||
|
||||
sudo cp linux/pxt/uf2daemon/server dev-ev3/home/root/lms2012/sys/uf2d
|
||||
sudo cp linux/pxt/kernel/d_usbdev.ko dev-ev3/home/root/lms2012/sys/mod/d_usbdev.ko
|
||||
sudo chown -R root:root dev-ev3/home/root/lms2012
|
||||
sudo mkfs.cramfs dev-ev3 cram.bin
|
||||
node img
|
||||
ls -l firmware.bin
|
@ -1,8 +0,0 @@
|
||||
let small = "010100000004010200000004020100004000020200004000030100000004040000008000"
|
||||
let big = "010100000004010200000004020100000002020200000002030100000001040000000001"
|
||||
|
||||
let fs = require("fs")
|
||||
|
||||
let kern = fs.readFileSync( "foo")
|
||||
let kern2 = new Buffer(kern.toString("hex").replace(small, big), "hex")
|
||||
fs.writeFileSync("foo2", kern2)
|
10
brick/send
10
brick/send
@ -1,10 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
./mk
|
||||
ev3duder up bin/d_usbdev.ko ../prjs/ko/d_usbdev.ko
|
||||
ev3duder up bin/nbd.ko ../prjs/ko/nbd.ko
|
||||
ev3duder up ins ../prjs/ko/ins
|
||||
ev3duder exec 'rm ../prjs/ko/uf2d'
|
||||
ev3duder up bin/uf2d ../prjs/ko/uf2d
|
||||
#ev3duder exec 'echo . /mnt/ramdisk/prjs/ko/ins > /mnt/ramdisk/rc.local'
|
||||
|
@ -1,6 +0,0 @@
|
||||
CFLAGS = -std=c99 -W -Wall
|
||||
SRC = main.c fat.c
|
||||
|
||||
all:
|
||||
gcc -DX86=1 -g $(CFLAGS) $(SRC) -o server86
|
||||
arm-none-linux-gnueabi-gcc -Os -s $(CFLAGS) $(SRC) -o server
|
@ -1,784 +0,0 @@
|
||||
|
||||
#define VENDOR_NAME "The LEGO Group"
|
||||
#define PRODUCT_NAME "Mindstorms EV3"
|
||||
#define VOLUME_LABEL "EV3"
|
||||
#define INDEX_URL "https://makecode.com/lego"
|
||||
|
||||
#define BOARD_ID "LEGO-EV3-v0"
|
||||
|
||||
#define _XOPEN_SOURCE 500
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define max(a, b) \
|
||||
({ \
|
||||
__typeof__(a) _a = (a); \
|
||||
__typeof__(b) _b = (b); \
|
||||
_a > _b ? _a : _b; \
|
||||
})
|
||||
|
||||
#define min(a, b) \
|
||||
({ \
|
||||
__typeof__(a) _a = (a); \
|
||||
__typeof__(b) _b = (b); \
|
||||
_a < _b ? _a : _b; \
|
||||
})
|
||||
|
||||
#include "uf2.h"
|
||||
|
||||
#define DBG LOG
|
||||
|
||||
typedef struct {
|
||||
uint8_t JumpInstruction[3];
|
||||
uint8_t OEMInfo[8];
|
||||
uint16_t SectorSize;
|
||||
uint8_t SectorsPerCluster;
|
||||
uint16_t ReservedSectors;
|
||||
uint8_t FATCopies;
|
||||
uint16_t RootDirectoryEntries;
|
||||
uint16_t TotalSectors16;
|
||||
uint8_t MediaDescriptor;
|
||||
uint16_t SectorsPerFAT;
|
||||
uint16_t SectorsPerTrack;
|
||||
uint16_t Heads;
|
||||
uint32_t HiddenSectors;
|
||||
uint32_t TotalSectors32;
|
||||
uint8_t PhysicalDriveNum;
|
||||
uint8_t Reserved;
|
||||
uint8_t ExtendedBootSig;
|
||||
uint32_t VolumeSerialNumber;
|
||||
char VolumeLabel[11];
|
||||
uint8_t FilesystemIdentifier[8];
|
||||
} __attribute__((packed)) FAT_BootBlock;
|
||||
|
||||
typedef struct {
|
||||
char name[8];
|
||||
char ext[3];
|
||||
uint8_t attrs;
|
||||
uint8_t reserved;
|
||||
uint8_t createTimeFine;
|
||||
uint16_t createTime;
|
||||
uint16_t createDate;
|
||||
uint16_t lastAccessDate;
|
||||
uint16_t highStartCluster;
|
||||
uint16_t updateTime;
|
||||
uint16_t updateDate;
|
||||
uint16_t startCluster;
|
||||
uint32_t size;
|
||||
} __attribute__((packed)) DirEntry;
|
||||
|
||||
typedef struct {
|
||||
uint8_t seqno;
|
||||
uint16_t name0[5];
|
||||
uint8_t attrs;
|
||||
uint8_t type;
|
||||
uint8_t checksum;
|
||||
uint16_t name1[6];
|
||||
uint16_t startCluster;
|
||||
uint16_t name2[2];
|
||||
} __attribute__((packed)) VFatEntry;
|
||||
|
||||
STATIC_ASSERT(sizeof(DirEntry) == 32);
|
||||
|
||||
#define STR0(x) #x
|
||||
#define STR(x) STR0(x)
|
||||
const char infoUf2File[] = //
|
||||
"UF2 Bootloader " UF2_VERSION "\r\n"
|
||||
"Model: " PRODUCT_NAME "\r\n"
|
||||
"Board-ID: " BOARD_ID "\r\n";
|
||||
|
||||
const char indexFile[] = //
|
||||
"<!doctype html>\n"
|
||||
"<html>"
|
||||
"<body>"
|
||||
"<script>\n"
|
||||
"location.replace(\"" INDEX_URL "\");\n"
|
||||
"</script>"
|
||||
"</body>"
|
||||
"</html>\n";
|
||||
|
||||
#define RESERVED_SECTORS 1
|
||||
#define ROOT_DIR_SECTORS 4
|
||||
#define SECTORS_PER_FAT ((NUM_FAT_BLOCKS * 2 + 511) / 512)
|
||||
|
||||
#define START_FAT0 RESERVED_SECTORS
|
||||
#define START_FAT1 (START_FAT0 + SECTORS_PER_FAT)
|
||||
#define START_ROOTDIR (START_FAT1 + SECTORS_PER_FAT)
|
||||
#define START_CLUSTERS (START_ROOTDIR + ROOT_DIR_SECTORS)
|
||||
#define ROOT_DIR_ENTRIES (ROOT_DIR_SECTORS * 512 / 32)
|
||||
|
||||
#define F_TEXT 1
|
||||
#define F_UF2 2
|
||||
#define F_DIR 4
|
||||
#define F_CONT 8
|
||||
|
||||
static const FAT_BootBlock BootBlock = {
|
||||
.JumpInstruction = {0xeb, 0x3c, 0x90},
|
||||
.OEMInfo = "UF2 UF2 ",
|
||||
.SectorSize = 512,
|
||||
.SectorsPerCluster = 1,
|
||||
.ReservedSectors = RESERVED_SECTORS,
|
||||
.FATCopies = 2,
|
||||
.RootDirectoryEntries = ROOT_DIR_ENTRIES,
|
||||
.TotalSectors16 = NUM_FAT_BLOCKS - 2,
|
||||
.MediaDescriptor = 0xF8,
|
||||
.SectorsPerFAT = SECTORS_PER_FAT,
|
||||
.SectorsPerTrack = 1,
|
||||
.Heads = 1,
|
||||
.ExtendedBootSig = 0x29,
|
||||
.VolumeSerialNumber = 0x00420042,
|
||||
.VolumeLabel = VOLUME_LABEL,
|
||||
.FilesystemIdentifier = "FAT16 ",
|
||||
};
|
||||
|
||||
int currCluster = 2;
|
||||
struct FsEntry *rootDir;
|
||||
struct ClusterData *firstCluster, *lastCluster;
|
||||
|
||||
typedef struct ClusterData {
|
||||
int flags;
|
||||
int numclusters;
|
||||
struct stat st;
|
||||
struct ClusterData *dnext;
|
||||
struct ClusterData *cnext;
|
||||
struct FsEntry *dirdata;
|
||||
struct FsEntry *myfile;
|
||||
char name[0];
|
||||
} ClusterData;
|
||||
|
||||
typedef struct FsEntry {
|
||||
int startCluster;
|
||||
uint8_t attrs;
|
||||
int size;
|
||||
int numdirentries;
|
||||
time_t ctime, mtime;
|
||||
struct FsEntry *next;
|
||||
struct ClusterData *data;
|
||||
char fatname[12];
|
||||
char vfatname[0];
|
||||
} FsEntry;
|
||||
|
||||
struct DirMap {
|
||||
const char *mapName;
|
||||
const char *fsName;
|
||||
};
|
||||
|
||||
struct DirMap dirMaps[] = { //
|
||||
#ifdef X86
|
||||
{"foo qux baz", "dirs/bar"}, //
|
||||
{"foo", "dirs/foo"}, //
|
||||
{"xyz", "dirs/bar2"}, //
|
||||
#else
|
||||
{"Projects", "/mnt/ramdisk/prjs/BrkProg_SAVE"},
|
||||
{"SD Card", "/media/card/myapps"},
|
||||
{"USB Stick", "/media/usb/myapps"},
|
||||
#endif
|
||||
{NULL, NULL}};
|
||||
|
||||
void timeToFat(time_t t, uint16_t *dateP, uint16_t *timeP) {
|
||||
struct tm tm;
|
||||
|
||||
localtime_r(&t, &tm);
|
||||
|
||||
if (timeP)
|
||||
*timeP = (tm.tm_hour << 11) | (tm.tm_min << 5) | (tm.tm_sec / 2);
|
||||
|
||||
if (dateP)
|
||||
*dateP = (max(0, tm.tm_year - 80) << 9) | ((tm.tm_mon + 1) << 5) | tm.tm_mday;
|
||||
}
|
||||
|
||||
void padded_memcpy(char *dst, const char *src, int len) {
|
||||
for (int i = 0; i < len; ++i) {
|
||||
if (*src)
|
||||
*dst = *src++;
|
||||
else
|
||||
*dst = ' ';
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
|
||||
char *expandMap(const char *mapName) {
|
||||
static char mapbuf[300];
|
||||
|
||||
const char *rest = "";
|
||||
for (int i = 0; i < (int)sizeof(mapbuf); ++i) {
|
||||
char c = mapName[i];
|
||||
if (c == '/' || c == 0) {
|
||||
mapbuf[i] = 0;
|
||||
rest = mapName + i;
|
||||
break;
|
||||
}
|
||||
mapbuf[i] = c;
|
||||
}
|
||||
for (int i = 0; dirMaps[i].mapName; ++i) {
|
||||
if (strcmp(dirMaps[i].mapName, mapbuf) == 0) {
|
||||
strcpy(mapbuf, dirMaps[i].fsName);
|
||||
strcat(mapbuf, rest);
|
||||
return mapbuf;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ClusterData *mkClusterData(int namelen) {
|
||||
ClusterData *c = malloc(sizeof(*c) + namelen + 1);
|
||||
memset(c, 0, sizeof(*c) + namelen + 1);
|
||||
return c;
|
||||
}
|
||||
|
||||
ClusterData *readDir(const char *mapName) {
|
||||
DIR *d = opendir(expandMap(mapName));
|
||||
if (!d)
|
||||
return NULL;
|
||||
|
||||
ClusterData *res = NULL;
|
||||
for (;;) {
|
||||
struct dirent *ent = readdir(d);
|
||||
if (!ent)
|
||||
break;
|
||||
|
||||
ClusterData *c = mkClusterData(strlen(mapName) + 1 + strlen(ent->d_name));
|
||||
|
||||
c->flags = F_UF2;
|
||||
c->dnext = res;
|
||||
sprintf(c->name, "%s/%s", mapName, ent->d_name);
|
||||
|
||||
int err = stat(expandMap(c->name), &c->st);
|
||||
assert(err >= 0);
|
||||
|
||||
if (S_ISREG(c->st.st_mode) && strlen(c->name) < UF2_FILENAME_MAX) {
|
||||
c->numclusters = (c->st.st_size + 255) / 256;
|
||||
} else {
|
||||
free(c);
|
||||
continue;
|
||||
}
|
||||
|
||||
res = c;
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
return res;
|
||||
}
|
||||
|
||||
int filechar(int c) {
|
||||
if (!c)
|
||||
return 0;
|
||||
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') ||
|
||||
strchr("_-", c);
|
||||
}
|
||||
|
||||
void copyFsChars(char *dst, const char *src, int len) {
|
||||
for (int i = 0; i < len; ++i) {
|
||||
if (filechar(*src))
|
||||
dst[i] = toupper(*src++);
|
||||
else {
|
||||
if (*src == '.')
|
||||
src = "";
|
||||
if (*src == 0)
|
||||
dst[i] = ' ';
|
||||
else
|
||||
dst[i] = '_';
|
||||
while (*src && !filechar(*src))
|
||||
src++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FsEntry *mkFsEntry(const char *name) {
|
||||
int sz = sizeof(FsEntry) + strlen(name) + 1;
|
||||
FsEntry *e = malloc(sz);
|
||||
memset(e, 0, sz);
|
||||
e->startCluster = currCluster;
|
||||
e->next = NULL;
|
||||
// +1 for final 0x0000, and +12 for alignment
|
||||
e->numdirentries = 1 + (strlen(name) + 1 + 12) / 13;
|
||||
strcpy(e->vfatname, name);
|
||||
|
||||
const char *src = name;
|
||||
copyFsChars(e->fatname, src, 8);
|
||||
while (*src && *src != '.')
|
||||
src++;
|
||||
if (*src == '.')
|
||||
src++;
|
||||
else
|
||||
src = "";
|
||||
copyFsChars(e->fatname + 8, src, 3);
|
||||
return e;
|
||||
}
|
||||
|
||||
void addClusterData(ClusterData *c, FsEntry *e) {
|
||||
currCluster += c->numclusters;
|
||||
|
||||
if (firstCluster == NULL) {
|
||||
firstCluster = c;
|
||||
} else {
|
||||
lastCluster->cnext = c;
|
||||
}
|
||||
lastCluster = c;
|
||||
|
||||
if (c->st.st_ctime)
|
||||
e->ctime = min(e->ctime, c->st.st_ctime);
|
||||
e->mtime = max(e->mtime, c->st.st_mtime);
|
||||
|
||||
c->myfile = e;
|
||||
|
||||
DBG("add cluster: flags=%d size=%d numcl=%d", c->flags, (int)c->st.st_size, c->numclusters);
|
||||
}
|
||||
|
||||
FsEntry *addRootText(const char *filename, const char *contents) {
|
||||
FsEntry *e = mkFsEntry(filename);
|
||||
e->next = rootDir;
|
||||
rootDir = e;
|
||||
|
||||
int sz = strlen(contents);
|
||||
e->size = sz;
|
||||
if (sz > 0) {
|
||||
assert(sz <= 512);
|
||||
ClusterData *c = mkClusterData(sz);
|
||||
c->st.st_mtime = c->st.st_ctime = time(NULL);
|
||||
|
||||
c->flags = F_TEXT;
|
||||
strcpy(c->name, contents);
|
||||
c->st.st_size = sz;
|
||||
c->numclusters = 1;
|
||||
addClusterData(c, e);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
int baseLen(const char *a) {
|
||||
int len = 0;
|
||||
while (*a && *a != '.') {
|
||||
a++;
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int nameMatches(const char *a, const char *b) {
|
||||
for (;;) {
|
||||
if ((*a == 0 || *a == '.') && (*b == 0 || *b == '.'))
|
||||
return 1;
|
||||
|
||||
if (*a != *b)
|
||||
return 0;
|
||||
a++;
|
||||
b++;
|
||||
}
|
||||
}
|
||||
|
||||
void setFatNames(FsEntry *dirent) {
|
||||
for (FsEntry *p = dirent; p; p = p->next) {
|
||||
// check for collisions
|
||||
int k = 1;
|
||||
retry:
|
||||
for (FsEntry *o = dirent; o && o != p; o = o->next) {
|
||||
if (strcmp(o->fatname, p->fatname) == 0) {
|
||||
char buf[20];
|
||||
sprintf(buf, "~%d", k++);
|
||||
int len = strlen(buf);
|
||||
memcpy(p->fatname + 8 - len, buf, len);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
DBG("setname: %s [%s] cl=%s @ %d sz=%d dents=%d", p->vfatname, p->fatname,
|
||||
p->data ? p->data->name : "(no data)", p->startCluster, p->size, p->numdirentries);
|
||||
}
|
||||
}
|
||||
|
||||
void addFullDir(const char *mapName) {
|
||||
int numEntries = 0;
|
||||
FsEntry *dirents = NULL;
|
||||
|
||||
time_t mtime = 0, ctime = 0;
|
||||
|
||||
for (ClusterData *cl = readDir(mapName); cl; cl = cl->dnext) {
|
||||
if (cl->cnext || cl == lastCluster)
|
||||
continue; // already done
|
||||
|
||||
// vfat entries
|
||||
const char *filename = strchr(cl->name, '/') + 1;
|
||||
int len = baseLen(filename) + 4;
|
||||
char namebuf[len];
|
||||
memcpy(namebuf, filename, len - 4);
|
||||
strcpy(namebuf + len - 4, ".uf2");
|
||||
|
||||
assert(cl->flags & F_UF2);
|
||||
|
||||
FsEntry *fent = mkFsEntry(namebuf);
|
||||
numEntries += fent->numdirentries;
|
||||
fent->next = dirents;
|
||||
fent->data = cl;
|
||||
fent->size = cl->numclusters * 512;
|
||||
dirents = fent;
|
||||
addClusterData(cl, fent);
|
||||
for (ClusterData *other = cl->dnext; other; other = other->dnext) {
|
||||
if (nameMatches(cl->name, other->name)) {
|
||||
other->flags |= F_CONT;
|
||||
fent->size += other->numclusters * 512;
|
||||
addClusterData(other, fent);
|
||||
}
|
||||
}
|
||||
if (mtime == 0) {
|
||||
mtime = fent->mtime;
|
||||
ctime = fent->ctime;
|
||||
} else {
|
||||
mtime = max(mtime, fent->mtime);
|
||||
ctime = min(ctime, fent->ctime);
|
||||
}
|
||||
}
|
||||
|
||||
setFatNames(dirents);
|
||||
|
||||
FsEntry *dent = mkFsEntry(mapName);
|
||||
dent->data = mkClusterData(0);
|
||||
dent->data->dirdata = dirents;
|
||||
dent->data->numclusters = (numEntries + 16) / 16; // at least 1
|
||||
addClusterData(dent->data, dent);
|
||||
dent->mtime = mtime;
|
||||
dent->ctime = ctime;
|
||||
dent->next = rootDir;
|
||||
dent->attrs = 0x10;
|
||||
dent->data->flags = F_DIR;
|
||||
rootDir = dent;
|
||||
}
|
||||
|
||||
void setupFs() {
|
||||
addRootText("info_uf2.txt", infoUf2File);
|
||||
addRootText("index.html", indexFile);
|
||||
for (int i = 0; dirMaps[i].mapName; ++i) {
|
||||
addFullDir(dirMaps[i].mapName);
|
||||
}
|
||||
|
||||
setFatNames(rootDir); // make names unique
|
||||
|
||||
FsEntry *e = addRootText(BootBlock.VolumeLabel, "");
|
||||
e->numdirentries = 1;
|
||||
e->attrs = 0x28;
|
||||
}
|
||||
|
||||
#define WRITE_ENT(v) \
|
||||
do { \
|
||||
if (skip++ >= 0) \
|
||||
*dest++ = v; \
|
||||
if (skip >= 256) \
|
||||
return; \
|
||||
cl++; \
|
||||
} while (0)
|
||||
|
||||
void readFat(uint16_t *dest, int skip) {
|
||||
int cl = 0;
|
||||
skip = -skip;
|
||||
WRITE_ENT(0xfff0);
|
||||
WRITE_ENT(0xffff);
|
||||
for (ClusterData *c = firstCluster; c; c = c->cnext) {
|
||||
for (int i = 0; i < c->numclusters - 1; i++)
|
||||
WRITE_ENT(cl + 1);
|
||||
if (c->cnext && c->cnext->flags & F_CONT)
|
||||
WRITE_ENT(cl + 1);
|
||||
else
|
||||
WRITE_ENT(0xffff);
|
||||
}
|
||||
}
|
||||
|
||||
// note that ptr might be unaligned
|
||||
const char *copyVFatName(const char *ptr, void *dest, int len) {
|
||||
uint8_t *dst = dest;
|
||||
|
||||
for (int i = 0; i < len; ++i) {
|
||||
if (ptr == NULL) {
|
||||
*dst++ = 0xff;
|
||||
*dst++ = 0xff;
|
||||
} else {
|
||||
*dst++ = *ptr;
|
||||
*dst++ = 0;
|
||||
if (*ptr)
|
||||
ptr++;
|
||||
else
|
||||
ptr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
uint8_t fatChecksum(const char *name) {
|
||||
uint8_t sum = 0;
|
||||
for (int i = 0; i < 11; ++i)
|
||||
sum = ((sum & 1) << 7) + (sum >> 1) + *name++;
|
||||
return sum;
|
||||
}
|
||||
|
||||
void readDirData(uint8_t *dest, FsEntry *dirdata, int blkno) {
|
||||
DirEntry *d = (void *)dest;
|
||||
int idx = blkno * -16;
|
||||
for (FsEntry *e = dirdata; e; e = e->next) {
|
||||
if (idx >= 16)
|
||||
break;
|
||||
|
||||
// DBG("dir idx=%d %s", idx, e->vfatname);
|
||||
|
||||
for (int i = 0; i < e->numdirentries; ++i, ++idx) {
|
||||
if (0 <= idx && idx < 16) {
|
||||
if (i == e->numdirentries - 1) {
|
||||
memcpy(d->name, e->fatname, 11);
|
||||
d->attrs = e->attrs;
|
||||
d->size = e->size;
|
||||
d->startCluster = e->startCluster;
|
||||
timeToFat(e->mtime, &d->updateDate, &d->updateTime);
|
||||
timeToFat(e->ctime, &d->createDate, &d->createTime);
|
||||
} else {
|
||||
VFatEntry *f = (void *)d;
|
||||
int seq = e->numdirentries - i - 2;
|
||||
f->seqno = seq + 1; // they start at 1
|
||||
if (i == 0)
|
||||
f->seqno |= 0x40;
|
||||
f->attrs = 0x0F;
|
||||
f->type = 0x00;
|
||||
f->checksum = fatChecksum(e->fatname);
|
||||
f->startCluster = 0;
|
||||
|
||||
const char *ptr = e->vfatname + (13 * seq);
|
||||
ptr = copyVFatName(ptr, f->name0, 5);
|
||||
ptr = copyVFatName(ptr, f->name1, 6);
|
||||
ptr = copyVFatName(ptr, f->name2, 2);
|
||||
}
|
||||
d++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void readBlock(uint8_t *dest, int blkno) {
|
||||
// DBG("readbl %d", blkno);
|
||||
int blkno0 = blkno;
|
||||
for (ClusterData *c = firstCluster; c; c = c->cnext) {
|
||||
// DBG("off=%d sz=%d", blkno, c->numclusters);
|
||||
if (blkno >= c->numclusters) {
|
||||
blkno -= c->numclusters;
|
||||
continue;
|
||||
}
|
||||
// DBG("readbl off=%d %p", blkno, c);
|
||||
if (c->dirdata) {
|
||||
readDirData(dest, c->dirdata, blkno);
|
||||
} else if (c->flags & F_TEXT) {
|
||||
strcpy((char *)dest, c->name);
|
||||
} else if (c->flags & F_UF2) {
|
||||
UF2_Block *bl = (void *)dest;
|
||||
|
||||
bl->magicStart0 = UF2_MAGIC_START0;
|
||||
bl->magicStart1 = UF2_MAGIC_START1;
|
||||
bl->magicEnd = UF2_MAGIC_END;
|
||||
bl->flags = UF2_FLAG_FILE;
|
||||
bl->blockNo = blkno0 - (c->myfile->startCluster - 2);
|
||||
bl->numBlocks = c->myfile->size / 512;
|
||||
bl->targetAddr = blkno * 256;
|
||||
bl->payloadSize = 256;
|
||||
bl->fileSize = c->st.st_size;
|
||||
|
||||
int fd = open(expandMap(c->name), O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
lseek(fd, bl->targetAddr, SEEK_SET);
|
||||
bl->payloadSize = read(fd, bl->data, 256);
|
||||
close(fd);
|
||||
} else {
|
||||
bl->payloadSize = -1;
|
||||
}
|
||||
|
||||
if (bl->payloadSize < 475 - strlen(c->name))
|
||||
strcpy((char *)bl->data + bl->payloadSize, c->name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void read_block(uint32_t block_no, uint8_t *data) {
|
||||
memset(data, 0, 512);
|
||||
uint32_t sectionIdx = block_no;
|
||||
|
||||
if (block_no == 0) {
|
||||
memcpy(data, &BootBlock, sizeof(BootBlock));
|
||||
data[510] = 0x55;
|
||||
data[511] = 0xaa;
|
||||
// logval("data[0]", data[0]);
|
||||
} else if (block_no < START_ROOTDIR) {
|
||||
sectionIdx -= START_FAT0;
|
||||
if (sectionIdx >= SECTORS_PER_FAT) // second copy of fat?
|
||||
sectionIdx -= SECTORS_PER_FAT;
|
||||
|
||||
readFat((void *)data, sectionIdx * 256);
|
||||
} else if (block_no < START_CLUSTERS) {
|
||||
sectionIdx -= START_ROOTDIR;
|
||||
readDirData(data, rootDir, sectionIdx);
|
||||
} else {
|
||||
sectionIdx -= START_CLUSTERS;
|
||||
readBlock(data, sectionIdx);
|
||||
}
|
||||
}
|
||||
|
||||
char rbfPath[300];
|
||||
|
||||
uint8_t stopApp[] = {
|
||||
0x05, 0x00, // size
|
||||
0x00, 0x00, // seq. no.
|
||||
0x3f, 0x3d, // usb magic,
|
||||
0x02, // req. no.
|
||||
};
|
||||
|
||||
uint8_t runStart[] = {0x00, 0x00, // size
|
||||
0x00, 0x00, // seq. no.
|
||||
0x00, 0x00, 0x08, // something
|
||||
0xC0, 0x08, 0x82, 0x01, 0x00, 0x84};
|
||||
|
||||
uint8_t runEnd[] = {0x00, 0x60, 0x64, 0x03, 0x01, 0x60, 0x64, 0x00};
|
||||
|
||||
#define FEED_DATA _IOC(_IOC_WRITE, 't', 108, 1024)
|
||||
|
||||
void startRbf() {
|
||||
char buf[1024];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
memcpy(buf, stopApp, sizeof(stopApp));
|
||||
|
||||
int fd = open("/dev/lms_usbdev", O_RDWR);
|
||||
ioctl(fd, FEED_DATA, buf);
|
||||
usleep(500000);
|
||||
|
||||
int off = 0;
|
||||
memcpy(buf + off, runStart, sizeof(runStart));
|
||||
off += sizeof(runStart);
|
||||
strcpy(buf + off, rbfPath);
|
||||
off += strlen(rbfPath);
|
||||
memcpy(buf + off, runEnd, sizeof(runEnd));
|
||||
off += sizeof(runEnd);
|
||||
off -= 2;
|
||||
buf[0] = off & 0xff;
|
||||
buf[1] = off >> 8;
|
||||
ioctl(fd, FEED_DATA, buf);
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
#define MAX_BLOCKS 8000
|
||||
typedef struct {
|
||||
uint32_t numBlocks;
|
||||
uint32_t numWritten;
|
||||
uint8_t writtenMask[MAX_BLOCKS / 8 + 1];
|
||||
} WriteState;
|
||||
|
||||
void restartProgram() {
|
||||
if (!rbfPath[0])
|
||||
exit(0);
|
||||
startRbf();
|
||||
exit(0); // causes parent to eject MSD etc
|
||||
}
|
||||
|
||||
int numWrites = 0;
|
||||
static WriteState wrState;
|
||||
void write_block(uint32_t block_no, uint8_t *data) {
|
||||
WriteState *state = &wrState;
|
||||
|
||||
UF2_Block *bl = (void *)data;
|
||||
|
||||
if (bl->magicStart0 == 0x20da6d81 && bl->magicStart1 == 0x747e09d4) {
|
||||
DBG("restart req, #wr=%d", numWrites);
|
||||
if (numWrites) {
|
||||
exit(0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
numWrites++;
|
||||
|
||||
if (!is_uf2_block(bl)) {
|
||||
return;
|
||||
}
|
||||
|
||||
(void)block_no;
|
||||
|
||||
bl->data[475] = 0; // make sure we have NUL terminator
|
||||
char *fn0 = (char *)bl->data + bl->payloadSize;
|
||||
int namelen = 0;
|
||||
if (bl->payloadSize <= UF2_MAX_PAYLOAD) {
|
||||
namelen = strlen(fn0);
|
||||
}
|
||||
|
||||
if ((bl->flags & UF2_FLAG_FILE) && bl->fileSize <= UF2_MAX_FILESIZE &&
|
||||
bl->targetAddr < bl->fileSize && 1 <= namelen && namelen <= UF2_FILENAME_MAX) {
|
||||
|
||||
char *firstSL = strchr(fn0, '/');
|
||||
char *lastSL = strrchr(fn0, '/');
|
||||
if (!lastSL)
|
||||
lastSL = fn0;
|
||||
else
|
||||
lastSL++;
|
||||
int baseLen = strlen(lastSL);
|
||||
char fallback[strlen(dirMaps[0].fsName) + 1 + baseLen + 1];
|
||||
sprintf(fallback, "%s/%s", dirMaps[0].fsName, lastSL);
|
||||
char *fn = NULL;
|
||||
|
||||
if (firstSL && firstSL + 1 == lastSL)
|
||||
fn = expandMap(fn0);
|
||||
if (!fn)
|
||||
fn = fallback;
|
||||
|
||||
char *p = strrchr(fn, '/');
|
||||
*p = 0;
|
||||
mkdir(fn, 0777);
|
||||
*p = '/';
|
||||
|
||||
int fd = open(fn, O_WRONLY | O_CREAT, 0777);
|
||||
if (fd < 0 && errno == ETXTBSY) {
|
||||
unlink(fn);
|
||||
fd = open(fn, O_WRONLY | O_CREAT, 0777);
|
||||
}
|
||||
if (fd >= 0) {
|
||||
ftruncate(fd, bl->fileSize);
|
||||
lseek(fd, bl->targetAddr, SEEK_SET);
|
||||
// DBG("write %d bytes at %d to %s", bl->payloadSize, bl->targetAddr, fn);
|
||||
write(fd, bl->data, bl->payloadSize);
|
||||
close(fd);
|
||||
|
||||
if (strlen(fn) > 4 && !strcmp(fn + strlen(fn) - 4, ".rbf")) {
|
||||
strcpy(rbfPath, fn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state && bl->numBlocks) {
|
||||
if (state->numBlocks != bl->numBlocks) {
|
||||
if (bl->numBlocks >= MAX_BLOCKS || state->numBlocks)
|
||||
state->numBlocks = 0xffffffff;
|
||||
else
|
||||
state->numBlocks = bl->numBlocks;
|
||||
}
|
||||
if (bl->blockNo < MAX_BLOCKS) {
|
||||
uint8_t mask = 1 << (bl->blockNo % 8);
|
||||
uint32_t pos = bl->blockNo / 8;
|
||||
if (!(state->writtenMask[pos] & mask)) {
|
||||
// logval("incr", state->numWritten);
|
||||
state->writtenMask[pos] |= mask;
|
||||
state->numWritten++;
|
||||
DBG("write %d/%d #%d", state->numWritten, state->numBlocks, bl->blockNo);
|
||||
}
|
||||
if (state->numWritten >= state->numBlocks) {
|
||||
restartProgram();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// TODO timeout for restart?
|
||||
}
|
||||
}
|
@ -1,231 +0,0 @@
|
||||
#define _GNU_SOURCE 1
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <linux/nbd.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/fs.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "uf2.h"
|
||||
|
||||
const char *dev_file = "/dev/nbd0";
|
||||
|
||||
|
||||
#define NUM_BLOCKS NUM_FAT_BLOCKS
|
||||
|
||||
uint64_t ntohll(uint64_t a) {
|
||||
return ((uint64_t)ntohl(a & 0xffffffff) << 32) | ntohl(a >> 32);
|
||||
}
|
||||
#define htonll ntohll
|
||||
|
||||
void mylog(const char *fmt, ...) {
|
||||
va_list args;
|
||||
char *p, *p2;
|
||||
|
||||
va_start(args, fmt);
|
||||
vasprintf(&p, fmt, args);
|
||||
vprintf(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
if (p[0] != '<')
|
||||
asprintf(&p2, "<6>%s\n", p);
|
||||
else
|
||||
asprintf(&p2, "%s\n", p);
|
||||
|
||||
int len = strlen(p2);
|
||||
|
||||
#ifdef X86
|
||||
write(2, p2, len);
|
||||
#else
|
||||
int fd = open("/dev/kmsg", O_WRONLY);
|
||||
write(fd, p2, len);
|
||||
close(fd);
|
||||
#endif
|
||||
|
||||
free(p);
|
||||
free(p2);
|
||||
}
|
||||
|
||||
void readAll(int fd, void *dst, uint32_t length) {
|
||||
while (length) {
|
||||
int curr = read(fd, dst, length);
|
||||
if (curr < 0)
|
||||
FAIL("read failed on fd:%d", fd);
|
||||
length -= curr;
|
||||
dst = (char *)dst + curr;
|
||||
}
|
||||
}
|
||||
|
||||
void writeAll(int fd, void *dst, uint32_t length) {
|
||||
while (length) {
|
||||
int curr = write(fd, dst, length);
|
||||
if (curr < 0)
|
||||
FAIL("write failed on fd:%d", fd);
|
||||
length -= curr;
|
||||
dst = (char *)dst + curr;
|
||||
}
|
||||
}
|
||||
|
||||
int nbd;
|
||||
int sock;
|
||||
int sockets[2];
|
||||
struct nbd_request request;
|
||||
struct nbd_reply reply;
|
||||
|
||||
void nbd_ioctl(unsigned id, int arg) {
|
||||
int err = ioctl(nbd, id, arg);
|
||||
if (err < 0)
|
||||
FAIL("ioctl(%ud) failed [%s]", id, strerror(errno));
|
||||
}
|
||||
|
||||
void startclient() {
|
||||
close(sockets[0]);
|
||||
nbd_ioctl(NBD_SET_SOCK, sockets[1]);
|
||||
nbd_ioctl(NBD_DO_IT, 0);
|
||||
nbd_ioctl(NBD_CLEAR_QUE, 0);
|
||||
nbd_ioctl(NBD_CLEAR_SOCK, 0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void handleread(int off, int len) {
|
||||
uint8_t buf[512];
|
||||
LOG("read @%d len=%d", off, len);
|
||||
reply.error = 0; // htonl(EPERM);
|
||||
writeAll(sock, &reply, sizeof(struct nbd_reply));
|
||||
for (int i = 0; i < len; ++i) {
|
||||
read_block(off + i, buf);
|
||||
writeAll(sock, buf, 512);
|
||||
}
|
||||
}
|
||||
|
||||
void handlewrite(int off, int len) {
|
||||
uint8_t buf[512];
|
||||
LOG("write @%d len=%d", off, len);
|
||||
for (int i = 0; i < len; ++i) {
|
||||
readAll(sock, buf, 512);
|
||||
write_block(off + i, buf);
|
||||
}
|
||||
reply.error = 0;
|
||||
writeAll(sock, &reply, sizeof(struct nbd_reply));
|
||||
}
|
||||
|
||||
void setupFs();
|
||||
|
||||
void runNBD() {
|
||||
setupFs();
|
||||
|
||||
int err = socketpair(AF_UNIX, SOCK_STREAM, 0, sockets);
|
||||
assert(err >= 0);
|
||||
|
||||
nbd = open(dev_file, O_RDWR);
|
||||
assert(nbd >= 0);
|
||||
|
||||
nbd_ioctl(BLKFLSBUF, 0);
|
||||
nbd_ioctl(NBD_SET_BLKSIZE, 512);
|
||||
nbd_ioctl(NBD_SET_SIZE_BLOCKS, NUM_BLOCKS);
|
||||
nbd_ioctl(NBD_CLEAR_SOCK, 0);
|
||||
|
||||
if (!fork())
|
||||
startclient();
|
||||
|
||||
int fd = open(dev_file, O_RDONLY);
|
||||
assert(fd != -1);
|
||||
close(fd);
|
||||
|
||||
close(sockets[1]);
|
||||
sock = sockets[0];
|
||||
|
||||
reply.magic = htonl(NBD_REPLY_MAGIC);
|
||||
reply.error = htonl(0);
|
||||
|
||||
for (;;) {
|
||||
// nbd_ioctl(BLKFLSBUF, 0); // flush buffers - we don't want the kernel to cache the writes
|
||||
int nread = read(sock, &request, sizeof(request));
|
||||
|
||||
if (nread < 0) {
|
||||
FAIL("nbd read err %s", strerror(errno));
|
||||
}
|
||||
if (nread == 0)
|
||||
return;
|
||||
assert(nread == sizeof(request));
|
||||
memcpy(reply.handle, request.handle, sizeof(reply.handle));
|
||||
reply.error = htonl(0);
|
||||
|
||||
assert(request.magic == htonl(NBD_REQUEST_MAGIC));
|
||||
|
||||
uint32_t len = ntohl(request.len);
|
||||
assert((len & 511) == 0);
|
||||
len >>= 9;
|
||||
uint64_t from = ntohll(request.from);
|
||||
assert((from & 511) == 0);
|
||||
from >>= 9;
|
||||
|
||||
switch (ntohl(request.type)) {
|
||||
case NBD_CMD_READ:
|
||||
handleread(from, len);
|
||||
break;
|
||||
case NBD_CMD_WRITE:
|
||||
handlewrite(from, len);
|
||||
break;
|
||||
case NBD_CMD_DISC:
|
||||
return;
|
||||
default:
|
||||
FAIL("invalid cmd: %d", ntohl(request.type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void enableMSD(int enabled) {
|
||||
#ifndef X86
|
||||
int fd = open("/sys/devices/platform/musb_hdrc/gadget/lun0/active", O_WRONLY);
|
||||
write(fd, enabled ? "1" : "0", 1);
|
||||
close(fd);
|
||||
#else
|
||||
LOG("fake enable MSD: %d", enabled);
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
#ifndef X86
|
||||
daemon(0, 1);
|
||||
#endif
|
||||
|
||||
if (argc > 1)
|
||||
dev_file = argv[1];
|
||||
|
||||
for (;;) {
|
||||
pid_t child = fork();
|
||||
if (child == 0) {
|
||||
runNBD();
|
||||
return 0;
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
enableMSD(1);
|
||||
|
||||
int wstatus = 0;
|
||||
waitpid(child, &wstatus, 0);
|
||||
enableMSD(0); // force "eject"
|
||||
|
||||
if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0) {
|
||||
LOG("abnormal child return, %d", child);
|
||||
sleep(5);
|
||||
} else {
|
||||
sleep(2);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
#ifndef UF2_H
|
||||
#define UF2_H 1
|
||||
|
||||
#include "uf2format.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef INDEX_URL
|
||||
#define INDEX_URL "https://www.pxt.io/"
|
||||
#endif
|
||||
|
||||
#define UF2_VERSION_BASE "v0.1.0"
|
||||
|
||||
// needs to be more than ~4200 and less than ~65000 (to force FAT16)
|
||||
#define NUM_FAT_BLOCKS 65000
|
||||
|
||||
#define UF2_VERSION UF2_VERSION_BASE " F"
|
||||
|
||||
//! Static block size for all memories
|
||||
#define UDI_MSC_BLOCK_SIZE 512L
|
||||
|
||||
void read_block(uint32_t block_no, uint8_t *data);
|
||||
|
||||
void write_block(uint32_t block_no, uint8_t *data);
|
||||
|
||||
#define CONCAT_1(a, b) a##b
|
||||
#define CONCAT_0(a, b) CONCAT_1(a, b)
|
||||
#define STATIC_ASSERT(e) enum { CONCAT_0(_static_assert_, __LINE__) = 1 / ((e) ? 1 : 0) }
|
||||
|
||||
extern const char infoUf2File[];
|
||||
|
||||
void readAll(int fd, void *dst, uint32_t length);
|
||||
|
||||
STATIC_ASSERT(sizeof(UF2_Block) == 512);
|
||||
|
||||
void mylog(const char *fmt, ...);
|
||||
|
||||
#define FAIL(args...) \
|
||||
do { \
|
||||
mylog("<4>" args); \
|
||||
exit(1); \
|
||||
} while (0)
|
||||
|
||||
#define LOG mylog
|
||||
|
||||
#endif
|
@ -1,48 +0,0 @@
|
||||
#ifndef UF2FORMAT_H
|
||||
#define UF2FORMAT_H 1
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// All entries are little endian.
|
||||
|
||||
// if you increase that, you will also need to update the linker script file
|
||||
#define APP_START_ADDRESS 0x00002000
|
||||
|
||||
#define UF2_MAGIC_START0 0x0A324655UL // "UF2\n"
|
||||
#define UF2_MAGIC_START1 0x9E5D5157UL // Randomly selected
|
||||
#define UF2_MAGIC_END 0x0AB16F30UL // Ditto
|
||||
|
||||
// If set, the block is "comment" and should not be flashed to the device
|
||||
#define UF2_FLAG_NOFLASH 0x00000001
|
||||
#define UF2_FLAG_FILE 0x00001000
|
||||
#define UF2_FILENAME_MAX 150
|
||||
#define UF2_MAX_PAYLOAD (476 - 10) // leaving some space for filename
|
||||
// for this bootloader
|
||||
#define UF2_MAX_FILESIZE (64 * 1024 * 1024)
|
||||
|
||||
typedef struct {
|
||||
// 32 byte header
|
||||
uint32_t magicStart0;
|
||||
uint32_t magicStart1;
|
||||
uint32_t flags;
|
||||
uint32_t targetAddr;
|
||||
uint32_t payloadSize;
|
||||
uint32_t blockNo;
|
||||
uint32_t numBlocks;
|
||||
uint32_t fileSize;
|
||||
|
||||
// raw data, followed by filename (NUL-terminated) at payloadSize
|
||||
uint8_t data[476];
|
||||
|
||||
// store magic also at the end to limit damage from partial block reads
|
||||
uint32_t magicEnd;
|
||||
} UF2_Block;
|
||||
|
||||
static inline bool is_uf2_block(void *data) {
|
||||
UF2_Block *bl = (UF2_Block *)data;
|
||||
return bl->magicStart0 == UF2_MAGIC_START0 && bl->magicStart1 == UF2_MAGIC_START1 &&
|
||||
bl->magicEnd == UF2_MAGIC_END;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,106 +0,0 @@
|
||||
#ifndef UF2_HID_H
|
||||
#define UF2_HID_H 1
|
||||
|
||||
#define HF2_CMD_BININFO 0x0001
|
||||
// no arguments
|
||||
#define HF2_MODE_BOOTLOADER 0x01
|
||||
#define HF2_MODE_USERSPACE 0x02
|
||||
struct HF2_BININFO_Result {
|
||||
uint32_t mode;
|
||||
uint32_t flash_page_size;
|
||||
uint32_t flash_num_pages;
|
||||
uint32_t max_message_size;
|
||||
};
|
||||
|
||||
#define HF2_CMD_INFO 0x0002
|
||||
// no arguments
|
||||
// results is utf8 character array
|
||||
|
||||
#define HF2_CMD_RESET_INTO_APP 0x0003
|
||||
// no arguments, no result
|
||||
|
||||
#define HF2_CMD_RESET_INTO_BOOTLOADER 0x0004
|
||||
// no arguments, no result
|
||||
|
||||
#define HF2_CMD_START_FLASH 0x0005
|
||||
// no arguments, no result
|
||||
|
||||
#define HF2_CMD_WRITE_FLASH_PAGE 0x0006
|
||||
struct HF2_WRITE_FLASH_PAGE_Command {
|
||||
uint32_t target_addr;
|
||||
uint32_t data[0];
|
||||
};
|
||||
// no result
|
||||
|
||||
#define HF2_CMD_CHKSUM_PAGES 0x0007
|
||||
struct HF2_CHKSUM_PAGES_Command {
|
||||
uint32_t target_addr;
|
||||
uint32_t num_pages;
|
||||
};
|
||||
struct HF2_CHKSUM_PAGES_Result {
|
||||
uint16_t chksums[0 /* num_pages */];
|
||||
};
|
||||
|
||||
#define HF2_CMD_READ_WORDS 0x0008
|
||||
struct HF2_READ_WORDS_Command {
|
||||
uint32_t target_addr;
|
||||
uint32_t num_words;
|
||||
};
|
||||
struct HF2_READ_WORDS_Result {
|
||||
uint32_t words[0 /* num_words */];
|
||||
};
|
||||
|
||||
#define HF2_CMD_WRITE_WORDS 0x0009
|
||||
struct HF2_WRITE_WORDS_Command {
|
||||
uint32_t target_addr;
|
||||
uint32_t num_words;
|
||||
uint32_t words[0 /* num_words */];
|
||||
};
|
||||
// no result
|
||||
|
||||
#define HF2_CMD_DMESG 0x0010
|
||||
// no arguments
|
||||
// results is utf8 character array
|
||||
|
||||
typedef struct {
|
||||
uint32_t command_id;
|
||||
uint16_t tag;
|
||||
uint8_t reserved0;
|
||||
uint8_t reserved1;
|
||||
|
||||
union {
|
||||
struct HF2_WRITE_FLASH_PAGE_Command write_flash_page;
|
||||
struct HF2_WRITE_WORDS_Command write_words;
|
||||
struct HF2_READ_WORDS_Command read_words;
|
||||
struct HF2_CHKSUM_PAGES_Command chksum_pages;
|
||||
};
|
||||
} HF2_Command;
|
||||
|
||||
typedef struct {
|
||||
uint16_t tag;
|
||||
union {
|
||||
struct {
|
||||
uint8_t status;
|
||||
uint8_t status_info;
|
||||
};
|
||||
uint16_t status16;
|
||||
};
|
||||
union {
|
||||
struct HF2_BININFO_Result bininfo;
|
||||
uint8_t data8[0];
|
||||
uint16_t data16[0];
|
||||
uint32_t data32[0];
|
||||
};
|
||||
} HF2_Response;
|
||||
|
||||
#define HF2_FLAG_SERIAL_OUT 0x80
|
||||
#define HF2_FLAG_SERIAL_ERR 0xC0
|
||||
#define HF2_FLAG_CMDPKT_LAST 0x40
|
||||
#define HF2_FLAG_CMDPKT_BODY 0x00
|
||||
#define HF2_FLAG_MASK 0xC0
|
||||
#define HF2_SIZE_MASK 63
|
||||
|
||||
#define HF2_STATUS_OK 0x00
|
||||
#define HF2_STATUS_INVALID_CMD 0x01
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user