Compare commits
13 Commits
kernelport
...
v0.0.1
Author | SHA1 | Date | |
---|---|---|---|
c9cdd3112a | |||
fe7e3a8790 | |||
8321c76f4c | |||
227f9614b0 | |||
de0b5f0d86 | |||
abdb21f2a0 | |||
b16f659ea1 | |||
34db42b469 | |||
3edceb248d | |||
8f9b9a5e4e | |||
14783eadc2 | |||
5e7754b436 | |||
c6b4e506d1 |
@ -11,8 +11,9 @@ they are derived from GPLv2 code).
|
|||||||
* the `d_usbdev` uses the composite framework to register an additional mass storage function in addtion
|
* the `d_usbdev` uses the composite framework to register an additional mass storage function in addtion
|
||||||
to the pre-existing custom USB HID function
|
to the pre-existing custom USB HID function
|
||||||
* the `g_mass_storage` module has the following changes:
|
* the `g_mass_storage` module has the following changes:
|
||||||
* a bug fixed, where page-misaligned writes would hang
|
|
||||||
* additional `/sys/.../lun0/active` entry is added, which allows for signaling drive eject to the host
|
* 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
|
### Kernel modifications
|
||||||
|
|
||||||
|
@ -5,6 +5,6 @@ cd /mnt/ramdisk/prjs/ko
|
|||||||
#echo 3 > /proc/sys/kernel/printk
|
#echo 3 > /proc/sys/kernel/printk
|
||||||
insmod ./nbd.ko
|
insmod ./nbd.ko
|
||||||
sleep 1
|
sleep 1
|
||||||
./uf2d > /tmp/uf2d.log 2> /tmp/uf2derr.log
|
./uf2d /dev/nbd1 > /tmp/uf2d.log 2> /tmp/uf2derr.log
|
||||||
sleep 1
|
sleep 1
|
||||||
insmod ./d_usbdev.ko file=/dev/nbd0 HostStr=EV3 SerialStr=0016535543af
|
insmod ./d_usbdev.ko file=/dev/nbd1 HostStr=EV3 SerialStr=0016535543af
|
||||||
|
@ -543,12 +543,27 @@ static int Device1Mmap(struct file *filp, struct vm_area_struct *vma)
|
|||||||
|
|
||||||
return (ret);
|
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 =
|
static const struct file_operations Device1Entries =
|
||||||
{
|
{
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.read = Device1Read,
|
.read = Device1Read,
|
||||||
.write = Device1Write,
|
.write = Device1Write,
|
||||||
.mmap = Device1Mmap
|
.mmap = Device1Mmap,
|
||||||
|
.ioctl = Device1Ioctl
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -288,7 +288,6 @@
|
|||||||
|
|
||||||
#include <linux/usb/ch9.h>
|
#include <linux/usb/ch9.h>
|
||||||
#include <linux/usb/gadget.h>
|
#include <linux/usb/gadget.h>
|
||||||
#include <linux/usb/composite.h>
|
|
||||||
|
|
||||||
#include "gadget_chips.h"
|
#include "gadget_chips.h"
|
||||||
|
|
||||||
@ -303,6 +302,7 @@ static const char fsg_string_interface[] = "Mass Storage";
|
|||||||
|
|
||||||
|
|
||||||
#define FSG_NO_INTR_EP 1
|
#define FSG_NO_INTR_EP 1
|
||||||
|
#define FSG_BUFFHD_STATIC_BUFFER 1
|
||||||
#define FSG_NO_DEVICE_STRINGS 1
|
#define FSG_NO_DEVICE_STRINGS 1
|
||||||
#define FSG_NO_OTG 1
|
#define FSG_NO_OTG 1
|
||||||
#define FSG_NO_INTR_EP 1
|
#define FSG_NO_INTR_EP 1
|
||||||
@ -318,8 +318,8 @@ struct fsg_dev;
|
|||||||
/* Data shared by all the FSG instances. */
|
/* Data shared by all the FSG instances. */
|
||||||
struct fsg_common {
|
struct fsg_common {
|
||||||
struct usb_gadget *gadget;
|
struct usb_gadget *gadget;
|
||||||
struct fsg_dev *fsg, *new_fsg;
|
struct fsg_dev *fsg;
|
||||||
wait_queue_head_t fsg_wait;
|
struct fsg_dev *prev_fsg;
|
||||||
|
|
||||||
/* filesem protects: backing files in use */
|
/* filesem protects: backing files in use */
|
||||||
struct rw_semaphore filesem;
|
struct rw_semaphore filesem;
|
||||||
@ -348,6 +348,7 @@ struct fsg_common {
|
|||||||
enum fsg_state state; /* For exception handling */
|
enum fsg_state state; /* For exception handling */
|
||||||
unsigned int exception_req_tag;
|
unsigned int exception_req_tag;
|
||||||
|
|
||||||
|
u8 config, new_config;
|
||||||
enum data_direction data_dir;
|
enum data_direction data_dir;
|
||||||
u32 data_size;
|
u32 data_size;
|
||||||
u32 data_size_from_cmnd;
|
u32 data_size_from_cmnd;
|
||||||
@ -587,7 +588,7 @@ static int fsg_setup(struct usb_function *f,
|
|||||||
u16 w_value = le16_to_cpu(ctrl->wValue);
|
u16 w_value = le16_to_cpu(ctrl->wValue);
|
||||||
u16 w_length = le16_to_cpu(ctrl->wLength);
|
u16 w_length = le16_to_cpu(ctrl->wLength);
|
||||||
|
|
||||||
if (!fsg_is_set(fsg->common))
|
if (!fsg->common->config)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
switch (ctrl->bRequest) {
|
switch (ctrl->bRequest) {
|
||||||
@ -613,12 +614,7 @@ static int fsg_setup(struct usb_function *f,
|
|||||||
return -EDOM;
|
return -EDOM;
|
||||||
VDBG(fsg, "get max LUN\n");
|
VDBG(fsg, "get max LUN\n");
|
||||||
*(u8 *) req->buf = fsg->common->nluns - 1;
|
*(u8 *) req->buf = fsg->common->nluns - 1;
|
||||||
|
return 1;
|
||||||
/* Respond with data/status */
|
|
||||||
req->length = min((u16)1, w_length);
|
|
||||||
fsg->common->ep0req_name =
|
|
||||||
ctrl->bRequestType & USB_DIR_IN ? "ep0-in" : "ep0-out";
|
|
||||||
return ep0_queue(fsg->common);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VDBG(fsg,
|
VDBG(fsg,
|
||||||
@ -709,7 +705,9 @@ static int do_read(struct fsg_common *common)
|
|||||||
u32 amount_left;
|
u32 amount_left;
|
||||||
loff_t file_offset, file_offset_tmp;
|
loff_t file_offset, file_offset_tmp;
|
||||||
unsigned int amount;
|
unsigned int amount;
|
||||||
unsigned int partial_page;
|
// partial_page handling causes hangs
|
||||||
|
// same thing in do_write() --mmoskal
|
||||||
|
//unsigned int partial_page;
|
||||||
ssize_t nread;
|
ssize_t nread;
|
||||||
|
|
||||||
/* Get the starting Logical Block Address and check that it's
|
/* Get the starting Logical Block Address and check that it's
|
||||||
@ -754,10 +752,12 @@ static int do_read(struct fsg_common *common)
|
|||||||
amount = min(amount_left, FSG_BUFLEN);
|
amount = min(amount_left, FSG_BUFLEN);
|
||||||
amount = min((loff_t) amount,
|
amount = min((loff_t) amount,
|
||||||
curlun->file_length - file_offset);
|
curlun->file_length - file_offset);
|
||||||
|
/*
|
||||||
partial_page = file_offset & (PAGE_CACHE_SIZE - 1);
|
partial_page = file_offset & (PAGE_CACHE_SIZE - 1);
|
||||||
if (partial_page > 0)
|
if (partial_page > 0)
|
||||||
amount = min(amount, (unsigned int) PAGE_CACHE_SIZE -
|
amount = min(amount, (unsigned int) PAGE_CACHE_SIZE -
|
||||||
partial_page);
|
partial_page);
|
||||||
|
*/
|
||||||
/* Wait for the next buffer to become available */
|
/* Wait for the next buffer to become available */
|
||||||
bh = common->next_buffhd_to_fill;
|
bh = common->next_buffhd_to_fill;
|
||||||
while (bh->state != BUF_STATE_EMPTY) {
|
while (bh->state != BUF_STATE_EMPTY) {
|
||||||
@ -840,7 +840,7 @@ static int do_write(struct fsg_common *common)
|
|||||||
u32 amount_left_to_req, amount_left_to_write;
|
u32 amount_left_to_req, amount_left_to_write;
|
||||||
loff_t usb_offset, file_offset, file_offset_tmp;
|
loff_t usb_offset, file_offset, file_offset_tmp;
|
||||||
unsigned int amount;
|
unsigned int amount;
|
||||||
unsigned int partial_page;
|
//unsigned int partial_page;
|
||||||
ssize_t nwritten;
|
ssize_t nwritten;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@ -904,10 +904,12 @@ static int do_write(struct fsg_common *common)
|
|||||||
amount = min(amount_left_to_req, FSG_BUFLEN);
|
amount = min(amount_left_to_req, FSG_BUFLEN);
|
||||||
amount = min((loff_t) amount, curlun->file_length -
|
amount = min((loff_t) amount, curlun->file_length -
|
||||||
usb_offset);
|
usb_offset);
|
||||||
|
/*
|
||||||
partial_page = usb_offset & (PAGE_CACHE_SIZE - 1);
|
partial_page = usb_offset & (PAGE_CACHE_SIZE - 1);
|
||||||
if (partial_page > 0)
|
if (partial_page > 0)
|
||||||
amount = min(amount,
|
amount = min(amount,
|
||||||
(unsigned int) PAGE_CACHE_SIZE - partial_page);
|
(unsigned int) PAGE_CACHE_SIZE - partial_page);
|
||||||
|
*/
|
||||||
|
|
||||||
if (amount == 0) {
|
if (amount == 0) {
|
||||||
get_some_more = 0;
|
get_some_more = 0;
|
||||||
@ -938,7 +940,6 @@ static int do_write(struct fsg_common *common)
|
|||||||
bh->outreq->length = amount;
|
bh->outreq->length = amount;
|
||||||
bh->bulk_out_intended_length = amount;
|
bh->bulk_out_intended_length = amount;
|
||||||
bh->outreq->short_not_ok = 1;
|
bh->outreq->short_not_ok = 1;
|
||||||
printk("write transfer %d\n", amount);
|
|
||||||
START_TRANSFER_OR(common, bulk_out, bh->outreq,
|
START_TRANSFER_OR(common, bulk_out, bh->outreq,
|
||||||
&bh->outreq_busy, &bh->state)
|
&bh->outreq_busy, &bh->state)
|
||||||
/* Don't know what to do if
|
/* Don't know what to do if
|
||||||
@ -1015,14 +1016,10 @@ static int do_write(struct fsg_common *common)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
printk("before sleep\n");
|
|
||||||
|
|
||||||
/* Wait for something to happen */
|
/* Wait for something to happen */
|
||||||
rc = sleep_thread(common);
|
rc = sleep_thread(common);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
printk("after sleep\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -EIO; /* No default reply */
|
return -EIO; /* No default reply */
|
||||||
@ -2266,20 +2263,24 @@ static int alloc_request(struct fsg_common *common, struct usb_ep *ep,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset interface setting and re-init endpoint state (toggle etc). */
|
/*
|
||||||
static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg)
|
* Reset interface setting and re-init endpoint state (toggle etc).
|
||||||
|
* Call with altsetting < 0 to disable the interface. The only other
|
||||||
|
* available altsetting is 0, which enables the interface.
|
||||||
|
*/
|
||||||
|
static int do_set_interface(struct fsg_common *common, int altsetting)
|
||||||
{
|
{
|
||||||
|
int rc = 0;
|
||||||
|
int i;
|
||||||
const struct usb_endpoint_descriptor *d;
|
const struct usb_endpoint_descriptor *d;
|
||||||
struct fsg_dev *fsg;
|
|
||||||
int i, rc = 0;
|
|
||||||
|
|
||||||
if (common->running)
|
if (common->running)
|
||||||
DBG(common, "reset interface\n");
|
DBG(common, "reset interface\n");
|
||||||
|
|
||||||
reset:
|
reset:
|
||||||
/* Deallocate the requests */
|
/* Deallocate the requests */
|
||||||
if (common->fsg) {
|
if (common->prev_fsg) {
|
||||||
fsg = common->fsg;
|
struct fsg_dev *fsg = common->prev_fsg;
|
||||||
|
|
||||||
for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
|
for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
|
||||||
struct fsg_buffhd *bh = &common->buffhds[i];
|
struct fsg_buffhd *bh = &common->buffhds[i];
|
||||||
@ -2304,16 +2305,18 @@ reset:
|
|||||||
fsg->bulk_out_enabled = 0;
|
fsg->bulk_out_enabled = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
common->fsg = NULL;
|
common->prev_fsg = 0;
|
||||||
wake_up(&common->fsg_wait);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
common->running = 0;
|
common->running = 0;
|
||||||
if (!new_fsg || rc)
|
if (altsetting < 0 || rc != 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
common->fsg = new_fsg;
|
DBG(common, "set interface %d\n", altsetting);
|
||||||
fsg = common->fsg;
|
|
||||||
|
if (fsg_is_set(common)) {
|
||||||
|
struct fsg_dev *fsg = common->fsg;
|
||||||
|
common->prev_fsg = common->fsg;
|
||||||
|
|
||||||
/* Enable the endpoints */
|
/* Enable the endpoints */
|
||||||
d = fsg_ep_desc(common->gadget,
|
d = fsg_ep_desc(common->gadget,
|
||||||
@ -2352,6 +2355,39 @@ reset:
|
|||||||
for (i = 0; i < common->nluns; ++i)
|
for (i = 0; i < common->nluns; ++i)
|
||||||
common->luns[i].unit_attention_data = SS_RESET_OCCURRED;
|
common->luns[i].unit_attention_data = SS_RESET_OCCURRED;
|
||||||
return rc;
|
return rc;
|
||||||
|
} else {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Change our operational configuration. This code must agree with the code
|
||||||
|
* that returns config descriptors, and with interface altsetting code.
|
||||||
|
*
|
||||||
|
* It's also responsible for power management interactions. Some
|
||||||
|
* configurations might not work with our current power sources.
|
||||||
|
* For now we just assume the gadget is always self-powered.
|
||||||
|
*/
|
||||||
|
static int do_set_config(struct fsg_common *common, u8 new_config)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
/* Disable the single interface */
|
||||||
|
if (common->config != 0) {
|
||||||
|
DBG(common, "reset config\n");
|
||||||
|
common->config = 0;
|
||||||
|
rc = do_set_interface(common, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable the interface */
|
||||||
|
if (new_config != 0) {
|
||||||
|
common->config = new_config;
|
||||||
|
rc = do_set_interface(common, 0);
|
||||||
|
if (rc != 0)
|
||||||
|
common->config = 0; /* Reset on errors */
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2361,7 +2397,9 @@ reset:
|
|||||||
static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
||||||
{
|
{
|
||||||
struct fsg_dev *fsg = fsg_from_func(f);
|
struct fsg_dev *fsg = fsg_from_func(f);
|
||||||
fsg->common->new_fsg = fsg;
|
fsg->common->prev_fsg = fsg->common->fsg;
|
||||||
|
fsg->common->fsg = fsg;
|
||||||
|
fsg->common->new_config = 1;
|
||||||
raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
|
raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -2369,8 +2407,31 @@ static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
|||||||
static void fsg_disable(struct usb_function *f)
|
static void fsg_disable(struct usb_function *f)
|
||||||
{
|
{
|
||||||
struct fsg_dev *fsg = fsg_from_func(f);
|
struct fsg_dev *fsg = fsg_from_func(f);
|
||||||
fsg->common->new_fsg = NULL;
|
fsg->common->prev_fsg = fsg->common->fsg;
|
||||||
raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
|
fsg->common->fsg = fsg;
|
||||||
|
fsg->common->new_config = 0;
|
||||||
|
|
||||||
|
DBG(common, "fsg_disable filp=%p\n", fsg->common->luns[0].filp);
|
||||||
|
raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE_DISABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void shutdown_server(void) {
|
||||||
|
DBG(fsg_common, "shutdown_server filp=%p\n", fsg_common->luns[0].filp);
|
||||||
|
if (fsg_common->luns[0].filp) {
|
||||||
|
uint32_t buf[512 / 4];
|
||||||
|
loff_t file_offset_tmp = 512 * 50000; // make sure we're outside of FS area
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// this should shut down the nbd server, so that the caches are flushed
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
buf[0] = 0x20da6d81;
|
||||||
|
buf[1] = 0x747e09d4;
|
||||||
|
|
||||||
|
fsg_common->luns[0].filp->f_flags |= O_SYNC;
|
||||||
|
for (i = 0; i < 2; ++i)
|
||||||
|
vfs_write(fsg_common->luns[0].filp,
|
||||||
|
(char*)buf, 512, &file_offset_tmp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2379,17 +2440,19 @@ static void fsg_disable(struct usb_function *f)
|
|||||||
static void handle_exception(struct fsg_common *common)
|
static void handle_exception(struct fsg_common *common)
|
||||||
{
|
{
|
||||||
siginfo_t info;
|
siginfo_t info;
|
||||||
|
int sig;
|
||||||
int i;
|
int i;
|
||||||
struct fsg_buffhd *bh;
|
struct fsg_buffhd *bh;
|
||||||
enum fsg_state old_state;
|
enum fsg_state old_state;
|
||||||
|
u8 new_config;
|
||||||
struct fsg_lun *curlun;
|
struct fsg_lun *curlun;
|
||||||
unsigned int exception_req_tag;
|
unsigned int exception_req_tag;
|
||||||
|
int rc;
|
||||||
|
|
||||||
/* Clear the existing signals. Anything but SIGUSR1 is converted
|
/* Clear the existing signals. Anything but SIGUSR1 is converted
|
||||||
* into a high-priority EXIT exception. */
|
* into a high-priority EXIT exception. */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int sig =
|
sig = dequeue_signal_lock(current, ¤t->blocked, &info);
|
||||||
dequeue_signal_lock(current, ¤t->blocked, &info);
|
|
||||||
if (!sig)
|
if (!sig)
|
||||||
break;
|
break;
|
||||||
if (sig != SIGUSR1) {
|
if (sig != SIGUSR1) {
|
||||||
@ -2400,7 +2463,7 @@ static void handle_exception(struct fsg_common *common)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Cancel all the pending transfers */
|
/* Cancel all the pending transfers */
|
||||||
if (likely(common->fsg)) {
|
if (fsg_is_set(common)) {
|
||||||
for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
|
for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
|
||||||
bh = &common->buffhds[i];
|
bh = &common->buffhds[i];
|
||||||
if (bh->inreq_busy)
|
if (bh->inreq_busy)
|
||||||
@ -2441,6 +2504,7 @@ static void handle_exception(struct fsg_common *common)
|
|||||||
common->next_buffhd_to_fill = &common->buffhds[0];
|
common->next_buffhd_to_fill = &common->buffhds[0];
|
||||||
common->next_buffhd_to_drain = &common->buffhds[0];
|
common->next_buffhd_to_drain = &common->buffhds[0];
|
||||||
exception_req_tag = common->exception_req_tag;
|
exception_req_tag = common->exception_req_tag;
|
||||||
|
new_config = common->new_config;
|
||||||
old_state = common->state;
|
old_state = common->state;
|
||||||
|
|
||||||
if (old_state == FSG_STATE_ABORT_BULK_OUT)
|
if (old_state == FSG_STATE_ABORT_BULK_OUT)
|
||||||
@ -2489,13 +2553,24 @@ static void handle_exception(struct fsg_common *common)
|
|||||||
/* SS_RESET_OCCURRED; */
|
/* SS_RESET_OCCURRED; */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case FSG_STATE_CONFIG_CHANGE_DISABLE:
|
||||||
|
shutdown_server();
|
||||||
|
// fall-through
|
||||||
case FSG_STATE_CONFIG_CHANGE:
|
case FSG_STATE_CONFIG_CHANGE:
|
||||||
do_set_interface(common, common->new_fsg);
|
rc = do_set_config(common, new_config);
|
||||||
|
if (common->ep0_req_tag != exception_req_tag)
|
||||||
|
break;
|
||||||
|
if (rc != 0) { /* STALL on errors */
|
||||||
|
DBG(common, "ep0 set halt\n");
|
||||||
|
usb_ep_set_halt(common->ep0);
|
||||||
|
} else { /* Complete the status stage */
|
||||||
|
ep0_queue(common);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FSG_STATE_EXIT:
|
case FSG_STATE_EXIT:
|
||||||
case FSG_STATE_TERMINATED:
|
case FSG_STATE_TERMINATED:
|
||||||
do_set_interface(common, NULL); /* Free resources */
|
do_set_config(common, 0); /* Free resources */
|
||||||
spin_lock_irq(&common->lock);
|
spin_lock_irq(&common->lock);
|
||||||
common->state = FSG_STATE_TERMINATED; /* Stop the thread */
|
common->state = FSG_STATE_TERMINATED; /* Stop the thread */
|
||||||
spin_unlock_irq(&common->lock);
|
spin_unlock_irq(&common->lock);
|
||||||
@ -2669,7 +2744,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
|
|||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
common->free_storage_on_release = 1;
|
common->free_storage_on_release = 1;
|
||||||
} else {
|
} else {
|
||||||
memset(common, 0, sizeof *common);
|
memset(common, 0, sizeof common);
|
||||||
common->free_storage_on_release = 0;
|
common->free_storage_on_release = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2747,19 +2822,13 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
|
|||||||
|
|
||||||
|
|
||||||
/* Data buffers cyclic list */
|
/* Data buffers cyclic list */
|
||||||
|
/* Buffers in buffhds are static -- no need for additional
|
||||||
|
* allocation. */
|
||||||
bh = common->buffhds;
|
bh = common->buffhds;
|
||||||
i = FSG_NUM_BUFFERS;
|
i = FSG_NUM_BUFFERS - 1;
|
||||||
goto buffhds_first_it;
|
|
||||||
do {
|
do {
|
||||||
bh->next = bh + 1;
|
bh->next = bh + 1;
|
||||||
++bh;
|
} while (++bh, --i);
|
||||||
buffhds_first_it:
|
|
||||||
bh->buf = kmalloc(FSG_BUFLEN, GFP_KERNEL);
|
|
||||||
if (unlikely(!bh->buf)) {
|
|
||||||
rc = -ENOMEM;
|
|
||||||
goto error_release;
|
|
||||||
}
|
|
||||||
} while (--i);
|
|
||||||
bh->next = common->buffhds;
|
bh->next = common->buffhds;
|
||||||
|
|
||||||
|
|
||||||
@ -2813,7 +2882,6 @@ buffhds_first_it:
|
|||||||
goto error_release;
|
goto error_release;
|
||||||
}
|
}
|
||||||
init_completion(&common->thread_notifier);
|
init_completion(&common->thread_notifier);
|
||||||
init_waitqueue_head(&common->fsg_wait);
|
|
||||||
#undef OR
|
#undef OR
|
||||||
|
|
||||||
|
|
||||||
@ -2868,7 +2936,6 @@ static void fsg_common_release(struct kref *ref)
|
|||||||
container_of(ref, struct fsg_common, ref);
|
container_of(ref, struct fsg_common, ref);
|
||||||
unsigned i = common->nluns;
|
unsigned i = common->nluns;
|
||||||
struct fsg_lun *lun = common->luns;
|
struct fsg_lun *lun = common->luns;
|
||||||
struct fsg_buffhd *bh;
|
|
||||||
|
|
||||||
/* If the thread isn't already dead, tell it to exit now */
|
/* If the thread isn't already dead, tell it to exit now */
|
||||||
if (common->state != FSG_STATE_TERMINATED) {
|
if (common->state != FSG_STATE_TERMINATED) {
|
||||||
@ -2890,13 +2957,6 @@ static void fsg_common_release(struct kref *ref)
|
|||||||
}
|
}
|
||||||
|
|
||||||
kfree(common->luns);
|
kfree(common->luns);
|
||||||
|
|
||||||
i = FSG_NUM_BUFFERS;
|
|
||||||
bh = common->buffhds;
|
|
||||||
do {
|
|
||||||
kfree(bh->buf);
|
|
||||||
} while (++bh, --i);
|
|
||||||
|
|
||||||
if (common->free_storage_on_release)
|
if (common->free_storage_on_release)
|
||||||
kfree(common);
|
kfree(common);
|
||||||
}
|
}
|
||||||
@ -2908,19 +2968,9 @@ static void fsg_common_release(struct kref *ref)
|
|||||||
static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
|
static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||||
{
|
{
|
||||||
struct fsg_dev *fsg = fsg_from_func(f);
|
struct fsg_dev *fsg = fsg_from_func(f);
|
||||||
struct fsg_common *common = fsg->common;
|
|
||||||
|
|
||||||
DBG(fsg, "unbind\n");
|
DBG(fsg, "unbind\n");
|
||||||
|
fsg_common_put(fsg->common);
|
||||||
if (fsg->common->fsg == fsg) {
|
|
||||||
fsg->common->new_fsg = NULL;
|
|
||||||
raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
|
|
||||||
/* FIXME: make interruptible or killable somehow? */
|
|
||||||
wait_event(common->fsg_wait, common->fsg != fsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
fsg_common_put(common);
|
|
||||||
|
|
||||||
kfree(fsg);
|
kfree(fsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2929,6 +2979,7 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
|
|||||||
{
|
{
|
||||||
struct fsg_dev *fsg = fsg_from_func(f);
|
struct fsg_dev *fsg = fsg_from_func(f);
|
||||||
struct usb_gadget *gadget = c->cdev->gadget;
|
struct usb_gadget *gadget = c->cdev->gadget;
|
||||||
|
int rc;
|
||||||
int i;
|
int i;
|
||||||
struct usb_ep *ep;
|
struct usb_ep *ep;
|
||||||
|
|
||||||
@ -2954,13 +3005,6 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
|
|||||||
ep->driver_data = fsg->common; /* claim the endpoint */
|
ep->driver_data = fsg->common; /* claim the endpoint */
|
||||||
fsg->bulk_out = ep;
|
fsg->bulk_out = ep;
|
||||||
|
|
||||||
/* Copy descriptors */
|
|
||||||
f->descriptors = usb_copy_descriptors(fsg_fs_function);
|
|
||||||
if (unlikely(!f->descriptors)) {
|
|
||||||
usb_free_descriptors(f->descriptors);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gadget_is_dualspeed(gadget)) {
|
if (gadget_is_dualspeed(gadget)) {
|
||||||
/* Assume endpoint addresses are the same for both speeds */
|
/* Assume endpoint addresses are the same for both speeds */
|
||||||
fsg_hs_bulk_in_desc.bEndpointAddress =
|
fsg_hs_bulk_in_desc.bEndpointAddress =
|
||||||
@ -2974,8 +3018,9 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
|
|||||||
|
|
||||||
autoconf_fail:
|
autoconf_fail:
|
||||||
ERROR(fsg, "unable to autoconfigure all endpoints\n");
|
ERROR(fsg, "unable to autoconfigure all endpoints\n");
|
||||||
|
rc = -ENOTSUPP;
|
||||||
fsg_unbind(c, f);
|
fsg_unbind(c, f);
|
||||||
return -ENOTSUPP;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,7 +73,6 @@
|
|||||||
#undef DUMP_MSGS
|
#undef DUMP_MSGS
|
||||||
#endif /* !DEBUG */
|
#endif /* !DEBUG */
|
||||||
|
|
||||||
#define VERBOSE_DEBUG
|
|
||||||
#ifdef VERBOSE_DEBUG
|
#ifdef VERBOSE_DEBUG
|
||||||
#define VLDBG LDBG
|
#define VLDBG LDBG
|
||||||
#else
|
#else
|
||||||
@ -335,6 +334,7 @@ enum fsg_state {
|
|||||||
FSG_STATE_ABORT_BULK_OUT,
|
FSG_STATE_ABORT_BULK_OUT,
|
||||||
FSG_STATE_RESET,
|
FSG_STATE_RESET,
|
||||||
FSG_STATE_INTERFACE_CHANGE,
|
FSG_STATE_INTERFACE_CHANGE,
|
||||||
|
FSG_STATE_CONFIG_CHANGE_DISABLE,
|
||||||
FSG_STATE_CONFIG_CHANGE,
|
FSG_STATE_CONFIG_CHANGE,
|
||||||
FSG_STATE_DISCONNECT,
|
FSG_STATE_DISCONNECT,
|
||||||
FSG_STATE_EXIT,
|
FSG_STATE_EXIT,
|
||||||
|
14
brick/scripts/README.md
Normal file
14
brick/scripts/README.md
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# 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
|
53
brick/scripts/ev3-fs.patch
Normal file
53
brick/scripts/ev3-fs.patch
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
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,14 +1,36 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
let fs = require("fs")
|
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() {
|
function build() {
|
||||||
let cr = fs.readFileSync("cram.bin")
|
if (bootnews.length > bootargs.length) {
|
||||||
if (cr.length > 10878976) {
|
console.log("args too long")
|
||||||
console.log("too big")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let img = fs.readFileSync("boot.bin")
|
|
||||||
|
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
|
let off = 0x250000
|
||||||
if (img[off] != 0x45 || img[off + 1] != 0x3d) {
|
if (img[off] != 0x45 || img[off + 1] != 0x3d) {
|
||||||
console.log("bad magic: " + img[off] + " / " + img[off+1])
|
console.log("bad magic: " + img[off] + " / " + img[off+1])
|
||||||
@ -17,8 +39,8 @@ function build() {
|
|||||||
|
|
||||||
cr.copy(img, off)
|
cr.copy(img, off)
|
||||||
|
|
||||||
let kern = fs.readFileSync("piggy-patched.gzip")
|
let kern = fs.readFileSync(piggy ? "piggy-patched.gzip" : "linux/arch/arm/boot/uImage")
|
||||||
off = 0x0005540f
|
off = piggy ? 0x0005540f : 0x00050000
|
||||||
|
|
||||||
if (img[off] != kern[0] || img[off+1] != kern[1]) {
|
if (img[off] != kern[0] || img[off+1] != kern[1]) {
|
||||||
console.log("bad kernel magic: " + img[off] + " / " + img[off+1])
|
console.log("bad kernel magic: " + img[off] + " / " + img[off+1])
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
#!/bin/sh
|
#!/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
|
sudo mkfs.cramfs dev-ev3 cram.bin
|
||||||
node img
|
node img
|
||||||
ls -l firmware.bin
|
ls -l firmware.bin
|
||||||
|
@ -19,6 +19,9 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#define max(a, b) \
|
#define max(a, b) \
|
||||||
({ \
|
({ \
|
||||||
@ -627,6 +630,48 @@ void read_block(uint32_t block_no, uint8_t *data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
#define MAX_BLOCKS 8000
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t numBlocks;
|
uint32_t numBlocks;
|
||||||
@ -634,81 +679,30 @@ typedef struct {
|
|||||||
uint8_t writtenMask[MAX_BLOCKS / 8 + 1];
|
uint8_t writtenMask[MAX_BLOCKS / 8 + 1];
|
||||||
} WriteState;
|
} WriteState;
|
||||||
|
|
||||||
char elfPath[300];
|
|
||||||
|
|
||||||
int lmsPid;
|
|
||||||
void stopLMS() {
|
|
||||||
struct dirent *ent;
|
|
||||||
DIR *dir;
|
|
||||||
|
|
||||||
dir = opendir("/proc");
|
|
||||||
if (dir == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
while ((ent = readdir(dir)) != NULL) {
|
|
||||||
int pid = atoi(ent->d_name);
|
|
||||||
if (!pid)
|
|
||||||
continue;
|
|
||||||
char namebuf[100];
|
|
||||||
snprintf(namebuf, 1000, "/proc/%d/cmdline", pid);
|
|
||||||
FILE *f = fopen(namebuf, "r");
|
|
||||||
if (f) {
|
|
||||||
fread(namebuf, 1, 99, f);
|
|
||||||
if (strcmp(namebuf, "./lms2012") == 0) {
|
|
||||||
lmsPid = pid;
|
|
||||||
}
|
|
||||||
fclose(f);
|
|
||||||
if (lmsPid)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
closedir(dir);
|
|
||||||
|
|
||||||
if (lmsPid) {
|
|
||||||
DBG("SIGSTOP to lmsPID=%d", lmsPid);
|
|
||||||
kill(lmsPid, SIGSTOP);
|
|
||||||
} else {
|
|
||||||
DBG("LMS not found");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void waitAndContinue() {
|
|
||||||
stopLMS();
|
|
||||||
for (int fd = 3; fd < 9999; ++fd)
|
|
||||||
close(fd);
|
|
||||||
pid_t child = fork();
|
|
||||||
if (child == 0) {
|
|
||||||
DBG("start %s", elfPath);
|
|
||||||
execl(elfPath, elfPath, "--msd", (char *)NULL);
|
|
||||||
exit(128);
|
|
||||||
}
|
|
||||||
int status;
|
|
||||||
waitpid(child, &status, 0);
|
|
||||||
DBG("re-start LMS");
|
|
||||||
if (lmsPid) {
|
|
||||||
kill(lmsPid, SIGCONT);
|
|
||||||
}
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void restartProgram() {
|
void restartProgram() {
|
||||||
if (!elfPath[0])
|
if (!rbfPath[0])
|
||||||
exit(0);
|
exit(0);
|
||||||
|
startRbf();
|
||||||
pid_t child = fork();
|
|
||||||
if (child == 0)
|
|
||||||
waitAndContinue();
|
|
||||||
else
|
|
||||||
exit(0); // causes parent to eject MSD etc
|
exit(0); // causes parent to eject MSD etc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int numWrites = 0;
|
||||||
static WriteState wrState;
|
static WriteState wrState;
|
||||||
void write_block(uint32_t block_no, uint8_t *data) {
|
void write_block(uint32_t block_no, uint8_t *data) {
|
||||||
WriteState *state = &wrState;
|
WriteState *state = &wrState;
|
||||||
|
|
||||||
UF2_Block *bl = (void *)data;
|
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)) {
|
if (!is_uf2_block(bl)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -747,6 +741,10 @@ void write_block(uint32_t block_no, uint8_t *data) {
|
|||||||
*p = '/';
|
*p = '/';
|
||||||
|
|
||||||
int fd = open(fn, O_WRONLY | O_CREAT, 0777);
|
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) {
|
if (fd >= 0) {
|
||||||
ftruncate(fd, bl->fileSize);
|
ftruncate(fd, bl->fileSize);
|
||||||
lseek(fd, bl->targetAddr, SEEK_SET);
|
lseek(fd, bl->targetAddr, SEEK_SET);
|
||||||
@ -754,8 +752,8 @@ void write_block(uint32_t block_no, uint8_t *data) {
|
|||||||
write(fd, bl->data, bl->payloadSize);
|
write(fd, bl->data, bl->payloadSize);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
if (strlen(fn) > 4 && !strcmp(fn + strlen(fn) - 4, ".elf")) {
|
if (strlen(fn) > 4 && !strcmp(fn + strlen(fn) - 4, ".rbf")) {
|
||||||
strcpy(elfPath, fn);
|
strcpy(rbfPath, fn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,9 @@
|
|||||||
|
|
||||||
#include "uf2.h"
|
#include "uf2.h"
|
||||||
|
|
||||||
|
const char *dev_file = "/dev/nbd0";
|
||||||
|
|
||||||
|
|
||||||
#define NUM_BLOCKS NUM_FAT_BLOCKS
|
#define NUM_BLOCKS NUM_FAT_BLOCKS
|
||||||
|
|
||||||
uint64_t ntohll(uint64_t a) {
|
uint64_t ntohll(uint64_t a) {
|
||||||
@ -29,23 +32,30 @@ uint64_t ntohll(uint64_t a) {
|
|||||||
|
|
||||||
void mylog(const char *fmt, ...) {
|
void mylog(const char *fmt, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
char *p;
|
char *p, *p2;
|
||||||
|
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
vasprintf(&p, fmt, args);
|
vasprintf(&p, fmt, args);
|
||||||
vprintf(fmt, args);
|
vprintf(fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
int len = strlen(p) + 1;
|
if (p[0] != '<')
|
||||||
p[len - 1] = '\n';
|
asprintf(&p2, "<6>%s\n", p);
|
||||||
|
else
|
||||||
|
asprintf(&p2, "%s\n", p);
|
||||||
|
|
||||||
|
int len = strlen(p2);
|
||||||
|
|
||||||
#ifdef X86
|
#ifdef X86
|
||||||
write(2, p, len);
|
write(2, p2, len);
|
||||||
#else
|
#else
|
||||||
int fd = open("/dev/kmsg", O_WRONLY);
|
int fd = open("/dev/kmsg", O_WRONLY);
|
||||||
write(fd, p, len);
|
write(fd, p2, len);
|
||||||
close(fd);
|
close(fd);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
free(p);
|
||||||
|
free(p2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void readAll(int fd, void *dst, uint32_t length) {
|
void readAll(int fd, void *dst, uint32_t length) {
|
||||||
@ -89,8 +99,6 @@ void startclient() {
|
|||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define dev_file "/dev/nbd0"
|
|
||||||
|
|
||||||
void handleread(int off, int len) {
|
void handleread(int off, int len) {
|
||||||
uint8_t buf[512];
|
uint8_t buf[512];
|
||||||
LOG("read @%d len=%d", off, len);
|
LOG("read @%d len=%d", off, len);
|
||||||
@ -189,11 +197,14 @@ void enableMSD(int enabled) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main(int argc, char **argv) {
|
||||||
#ifndef X86
|
#ifndef X86
|
||||||
daemon(0, 1);
|
daemon(0, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (argc > 1)
|
||||||
|
dev_file = argv[1];
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
pid_t child = fork();
|
pid_t child = fork();
|
||||||
if (child == 0) {
|
if (child == 0) {
|
||||||
|
@ -37,7 +37,7 @@ void mylog(const char *fmt, ...);
|
|||||||
|
|
||||||
#define FAIL(args...) \
|
#define FAIL(args...) \
|
||||||
do { \
|
do { \
|
||||||
mylog(args); \
|
mylog("<4>" args); \
|
||||||
exit(1); \
|
exit(1); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
@ -41,7 +41,8 @@ namespace pxt.editor {
|
|||||||
export function deployCoreAsync(resp: pxtc.CompileResult, isCli = false) {
|
export function deployCoreAsync(resp: pxtc.CompileResult, isCli = false) {
|
||||||
let w: Ev3Wrapper
|
let w: Ev3Wrapper
|
||||||
|
|
||||||
let filename = resp.downloadFileBaseName
|
let filename = resp.downloadFileBaseName || "pxt"
|
||||||
|
filename = filename.replace(/^lego-/, "")
|
||||||
|
|
||||||
let fspath = "../prjs/BrkProg_SAVE/"
|
let fspath = "../prjs/BrkProg_SAVE/"
|
||||||
|
|
||||||
|
2
libs/base/enums.d.ts
vendored
2
libs/base/enums.d.ts
vendored
@ -30,7 +30,5 @@
|
|||||||
Object = 4,
|
Object = 4,
|
||||||
Function = 5,
|
Function = 5,
|
||||||
}
|
}
|
||||||
declare namespace serial {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Auto-generated. Do not edit. Really.
|
// Auto-generated. Do not edit. Really.
|
||||||
|
158
libs/base/shims.d.ts
vendored
Normal file
158
libs/base/shims.d.ts
vendored
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
// Auto-generated. Do not edit.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//% indexerGet=BufferMethods::getByte indexerSet=BufferMethods::setByte
|
||||||
|
declare interface Buffer {
|
||||||
|
/**
|
||||||
|
* Write a number in specified format in the buffer.
|
||||||
|
*/
|
||||||
|
//% shim=BufferMethods::setNumber
|
||||||
|
setNumber(format: NumberFormat, offset: int32, value: number): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a number in specified format from the buffer.
|
||||||
|
*/
|
||||||
|
//% shim=BufferMethods::getNumber
|
||||||
|
getNumber(format: NumberFormat, offset: int32): number;
|
||||||
|
|
||||||
|
/** Returns the length of a Buffer object. */
|
||||||
|
//% property shim=BufferMethods::length
|
||||||
|
length: int32;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fill (a fragment) of the buffer with given value.
|
||||||
|
*/
|
||||||
|
//% offset.defl=0 length.defl=-1 shim=BufferMethods::fill
|
||||||
|
fill(value: int32, offset?: int32, length?: int32): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a copy of a fragment of a buffer.
|
||||||
|
*/
|
||||||
|
//% offset.defl=0 length.defl=-1 shim=BufferMethods::slice
|
||||||
|
slice(offset?: int32, length?: int32): Buffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shift buffer left in place, with zero padding.
|
||||||
|
* @param offset number of bytes to shift; use negative value to shift right
|
||||||
|
* @param start start offset in buffer. Default is 0.
|
||||||
|
* @param length number of elements in buffer. If negative, length is set as the buffer length minus
|
||||||
|
* start. eg: -1
|
||||||
|
*/
|
||||||
|
//% start.defl=0 length.defl=-1 shim=BufferMethods::shift
|
||||||
|
shift(offset: int32, start?: int32, length?: int32): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a buffer to its hexadecimal representation.
|
||||||
|
*/
|
||||||
|
//% shim=BufferMethods::toHex
|
||||||
|
toHex(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rotate buffer left in place.
|
||||||
|
* @param offset number of bytes to shift; use negative value to shift right
|
||||||
|
* @param start start offset in buffer. Default is 0.
|
||||||
|
* @param length number of elements in buffer. If negative, length is set as the buffer length minus
|
||||||
|
* start. eg: -1
|
||||||
|
*/
|
||||||
|
//% start.defl=0 length.defl=-1 shim=BufferMethods::rotate
|
||||||
|
rotate(offset: int32, start?: int32, length?: int32): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write contents of `src` at `dstOffset` in current buffer.
|
||||||
|
*/
|
||||||
|
//% shim=BufferMethods::write
|
||||||
|
write(dstOffset: int32, src: Buffer): void;
|
||||||
|
}
|
||||||
|
declare namespace loops {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Repeats the code forever in the background. On each iteration, allows other codes to run.
|
||||||
|
* @param body code to execute
|
||||||
|
*/
|
||||||
|
//% help=loops/forever weight=100 blockGap=8
|
||||||
|
//% blockId=forever block="forever" blockAllowMultiple=1 shim=loops::forever
|
||||||
|
function forever(a: () => void): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pause for the specified time in milliseconds
|
||||||
|
* @param ms how long to pause for, eg: 100, 200, 500, 1000, 2000
|
||||||
|
*/
|
||||||
|
//% help=loops/pause weight=99
|
||||||
|
//% async block="pause (ms) %pause"
|
||||||
|
//% blockId=device_pause shim=loops::pause
|
||||||
|
function pause(ms: int32): void;
|
||||||
|
}
|
||||||
|
declare namespace control {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of milliseconds elapsed since power on.
|
||||||
|
*/
|
||||||
|
//% help=control/millis weight=50
|
||||||
|
//% blockId=control_running_time block="millis (ms)" shim=control::millis
|
||||||
|
function millis(): int32;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run code when a registered event happens.
|
||||||
|
* @param id the event compoent id
|
||||||
|
* @param value the event value to match
|
||||||
|
*/
|
||||||
|
//% weight=20 blockGap=8 blockId="control_on_event" block="on event|from %src|with value %value"
|
||||||
|
//% blockExternalInputs=1
|
||||||
|
//% help="control/on-event" shim=control::onEvent
|
||||||
|
function onEvent(src: int32, value: int32, handler: () => void): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the device.
|
||||||
|
*/
|
||||||
|
//% weight=30 async help=control/reset blockGap=8
|
||||||
|
//% blockId="control_reset" block="reset" shim=control::reset
|
||||||
|
function reset(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Block the current fiber for the given microseconds
|
||||||
|
* @param micros number of micro-seconds to wait. eg: 4
|
||||||
|
*/
|
||||||
|
//% help=control/wait-micros weight=29 async
|
||||||
|
//% blockId="control_wait_us" block="wait (µs)%micros" shim=control::waitMicros
|
||||||
|
function waitMicros(micros: int32): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run other code in the background.
|
||||||
|
*/
|
||||||
|
//% help=control/run-in-background blockAllowMultiple=1
|
||||||
|
//% blockId="control_run_in_background" block="run in background" blockGap=8 shim=control::runInBackground
|
||||||
|
function runInBackground(a: () => void): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blocks the calling thread until the specified event is raised.
|
||||||
|
*/
|
||||||
|
//% help=control/wait-for-event async
|
||||||
|
//% blockId=control_wait_for_event block="wait for event|from %src|with value %value" shim=control::waitForEvent
|
||||||
|
function waitForEvent(src: int32, value: int32): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derive a unique, consistent serial number of this device from internal data.
|
||||||
|
*/
|
||||||
|
//% blockId="control_device_serial_number" block="device serial number" weight=9 shim=control::deviceSerialNumber
|
||||||
|
function deviceSerialNumber(): int32;
|
||||||
|
}
|
||||||
|
declare namespace serial {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write some text to the serial port.
|
||||||
|
*/
|
||||||
|
//% help=serial/write-string
|
||||||
|
//% weight=87
|
||||||
|
//% blockId=serial_writestring block="serial|write string %text" shim=serial::writeString
|
||||||
|
function writeString(text: string): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a buffer across the serial connection.
|
||||||
|
*/
|
||||||
|
//% help=serial/write-buffer advanced=true weight=6
|
||||||
|
//% blockId=serial_writebuffer block="serial|write buffer %buffer" shim=serial::writeBuffer
|
||||||
|
function writeBuffer(buffer: Buffer): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-generated. Do not edit. Really.
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "pxt-ev3",
|
"name": "pxt-ev3",
|
||||||
"version": "0.0.0",
|
"version": "0.0.1",
|
||||||
"description": "LEGO Mindstorms EV3 for Microsoft MakeCode",
|
"description": "LEGO Mindstorms EV3 for Microsoft MakeCode",
|
||||||
"private": true,
|
"private": true,
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@ -39,8 +39,8 @@
|
|||||||
"semantic-ui-less": "^2.2.4"
|
"semantic-ui-less": "^2.2.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"pxt-common-packages": "0.8.1",
|
"pxt-common-packages": "0.9.1",
|
||||||
"pxt-core": "1.7.4"
|
"pxt-core": "1.8.10"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "node node_modules/pxt-core/built/pxt.js travis"
|
"test": "node node_modules/pxt-core/built/pxt.js travis"
|
||||||
|
Reference in New Issue
Block a user