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
|
||||
to the pre-existing custom USB HID function
|
||||
* 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
|
||||
* `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
|
||||
|
||||
|
@ -5,6 +5,6 @@ cd /mnt/ramdisk/prjs/ko
|
||||
#echo 3 > /proc/sys/kernel/printk
|
||||
insmod ./nbd.ko
|
||||
sleep 1
|
||||
./uf2d > /tmp/uf2d.log 2> /tmp/uf2derr.log
|
||||
./uf2d /dev/nbd1 > /tmp/uf2d.log 2> /tmp/uf2derr.log
|
||||
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);
|
||||
}
|
||||
|
||||
#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
|
||||
.mmap = Device1Mmap,
|
||||
.ioctl = Device1Ioctl
|
||||
};
|
||||
|
||||
|
||||
|
@ -288,7 +288,6 @@
|
||||
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/usb/composite.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_BUFFHD_STATIC_BUFFER 1
|
||||
#define FSG_NO_DEVICE_STRINGS 1
|
||||
#define FSG_NO_OTG 1
|
||||
#define FSG_NO_INTR_EP 1
|
||||
@ -318,8 +318,8 @@ struct fsg_dev;
|
||||
/* Data shared by all the FSG instances. */
|
||||
struct fsg_common {
|
||||
struct usb_gadget *gadget;
|
||||
struct fsg_dev *fsg, *new_fsg;
|
||||
wait_queue_head_t fsg_wait;
|
||||
struct fsg_dev *fsg;
|
||||
struct fsg_dev *prev_fsg;
|
||||
|
||||
/* filesem protects: backing files in use */
|
||||
struct rw_semaphore filesem;
|
||||
@ -348,6 +348,7 @@ struct fsg_common {
|
||||
enum fsg_state state; /* For exception handling */
|
||||
unsigned int exception_req_tag;
|
||||
|
||||
u8 config, new_config;
|
||||
enum data_direction data_dir;
|
||||
u32 data_size;
|
||||
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_length = le16_to_cpu(ctrl->wLength);
|
||||
|
||||
if (!fsg_is_set(fsg->common))
|
||||
if (!fsg->common->config)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
switch (ctrl->bRequest) {
|
||||
@ -613,12 +614,7 @@ static int fsg_setup(struct usb_function *f,
|
||||
return -EDOM;
|
||||
VDBG(fsg, "get max LUN\n");
|
||||
*(u8 *) req->buf = fsg->common->nluns - 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);
|
||||
return 1;
|
||||
}
|
||||
|
||||
VDBG(fsg,
|
||||
@ -709,7 +705,9 @@ static int do_read(struct fsg_common *common)
|
||||
u32 amount_left;
|
||||
loff_t file_offset, file_offset_tmp;
|
||||
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;
|
||||
|
||||
/* 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((loff_t) amount,
|
||||
curlun->file_length - file_offset);
|
||||
/*
|
||||
partial_page = file_offset & (PAGE_CACHE_SIZE - 1);
|
||||
if (partial_page > 0)
|
||||
amount = min(amount, (unsigned int) PAGE_CACHE_SIZE -
|
||||
partial_page);
|
||||
*/
|
||||
/* Wait for the next buffer to become available */
|
||||
bh = common->next_buffhd_to_fill;
|
||||
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;
|
||||
loff_t usb_offset, file_offset, file_offset_tmp;
|
||||
unsigned int amount;
|
||||
unsigned int partial_page;
|
||||
//unsigned int partial_page;
|
||||
ssize_t nwritten;
|
||||
int rc;
|
||||
|
||||
@ -904,10 +904,12 @@ static int do_write(struct fsg_common *common)
|
||||
amount = min(amount_left_to_req, FSG_BUFLEN);
|
||||
amount = min((loff_t) amount, curlun->file_length -
|
||||
usb_offset);
|
||||
/*
|
||||
partial_page = usb_offset & (PAGE_CACHE_SIZE - 1);
|
||||
if (partial_page > 0)
|
||||
amount = min(amount,
|
||||
(unsigned int) PAGE_CACHE_SIZE - partial_page);
|
||||
*/
|
||||
|
||||
if (amount == 0) {
|
||||
get_some_more = 0;
|
||||
@ -938,7 +940,6 @@ static int do_write(struct fsg_common *common)
|
||||
bh->outreq->length = amount;
|
||||
bh->bulk_out_intended_length = amount;
|
||||
bh->outreq->short_not_ok = 1;
|
||||
printk("write transfer %d\n", amount);
|
||||
START_TRANSFER_OR(common, bulk_out, bh->outreq,
|
||||
&bh->outreq_busy, &bh->state)
|
||||
/* Don't know what to do if
|
||||
@ -1015,14 +1016,10 @@ static int do_write(struct fsg_common *common)
|
||||
continue;
|
||||
}
|
||||
|
||||
printk("before sleep\n");
|
||||
|
||||
/* Wait for something to happen */
|
||||
rc = sleep_thread(common);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
printk("after sleep\n");
|
||||
}
|
||||
|
||||
return -EIO; /* No default reply */
|
||||
@ -2266,20 +2263,24 @@ static int alloc_request(struct fsg_common *common, struct usb_ep *ep,
|
||||
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)
|
||||
{
|
||||
const struct usb_endpoint_descriptor *d;
|
||||
struct fsg_dev *fsg;
|
||||
int i, rc = 0;
|
||||
int rc = 0;
|
||||
int i;
|
||||
const struct usb_endpoint_descriptor *d;
|
||||
|
||||
if (common->running)
|
||||
DBG(common, "reset interface\n");
|
||||
|
||||
reset:
|
||||
/* Deallocate the requests */
|
||||
if (common->fsg) {
|
||||
fsg = common->fsg;
|
||||
if (common->prev_fsg) {
|
||||
struct fsg_dev *fsg = common->prev_fsg;
|
||||
|
||||
for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
|
||||
struct fsg_buffhd *bh = &common->buffhds[i];
|
||||
@ -2304,53 +2305,88 @@ reset:
|
||||
fsg->bulk_out_enabled = 0;
|
||||
}
|
||||
|
||||
common->fsg = NULL;
|
||||
wake_up(&common->fsg_wait);
|
||||
common->prev_fsg = 0;
|
||||
}
|
||||
|
||||
common->running = 0;
|
||||
if (!new_fsg || rc)
|
||||
if (altsetting < 0 || rc != 0)
|
||||
return rc;
|
||||
|
||||
common->fsg = new_fsg;
|
||||
fsg = common->fsg;
|
||||
DBG(common, "set interface %d\n", altsetting);
|
||||
|
||||
/* Enable the endpoints */
|
||||
d = fsg_ep_desc(common->gadget,
|
||||
&fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc);
|
||||
rc = enable_endpoint(common, fsg->bulk_in, d);
|
||||
if (rc)
|
||||
goto reset;
|
||||
fsg->bulk_in_enabled = 1;
|
||||
if (fsg_is_set(common)) {
|
||||
struct fsg_dev *fsg = common->fsg;
|
||||
common->prev_fsg = common->fsg;
|
||||
|
||||
d = fsg_ep_desc(common->gadget,
|
||||
&fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc);
|
||||
rc = enable_endpoint(common, fsg->bulk_out, d);
|
||||
if (rc)
|
||||
goto reset;
|
||||
fsg->bulk_out_enabled = 1;
|
||||
common->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize);
|
||||
clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
|
||||
|
||||
/* Allocate the requests */
|
||||
for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
|
||||
struct fsg_buffhd *bh = &common->buffhds[i];
|
||||
|
||||
rc = alloc_request(common, fsg->bulk_in, &bh->inreq);
|
||||
/* Enable the endpoints */
|
||||
d = fsg_ep_desc(common->gadget,
|
||||
&fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc);
|
||||
rc = enable_endpoint(common, fsg->bulk_in, d);
|
||||
if (rc)
|
||||
goto reset;
|
||||
rc = alloc_request(common, fsg->bulk_out, &bh->outreq);
|
||||
fsg->bulk_in_enabled = 1;
|
||||
|
||||
d = fsg_ep_desc(common->gadget,
|
||||
&fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc);
|
||||
rc = enable_endpoint(common, fsg->bulk_out, d);
|
||||
if (rc)
|
||||
goto reset;
|
||||
bh->inreq->buf = bh->outreq->buf = bh->buf;
|
||||
bh->inreq->context = bh->outreq->context = bh;
|
||||
bh->inreq->complete = bulk_in_complete;
|
||||
bh->outreq->complete = bulk_out_complete;
|
||||
fsg->bulk_out_enabled = 1;
|
||||
common->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize);
|
||||
clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
|
||||
|
||||
/* Allocate the requests */
|
||||
for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
|
||||
struct fsg_buffhd *bh = &common->buffhds[i];
|
||||
|
||||
rc = alloc_request(common, fsg->bulk_in, &bh->inreq);
|
||||
if (rc)
|
||||
goto reset;
|
||||
rc = alloc_request(common, fsg->bulk_out, &bh->outreq);
|
||||
if (rc)
|
||||
goto reset;
|
||||
bh->inreq->buf = bh->outreq->buf = bh->buf;
|
||||
bh->inreq->context = bh->outreq->context = bh;
|
||||
bh->inreq->complete = bulk_in_complete;
|
||||
bh->outreq->complete = bulk_out_complete;
|
||||
}
|
||||
|
||||
common->running = 1;
|
||||
for (i = 0; i < common->nluns; ++i)
|
||||
common->luns[i].unit_attention_data = SS_RESET_OCCURRED;
|
||||
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);
|
||||
}
|
||||
|
||||
common->running = 1;
|
||||
for (i = 0; i < common->nluns; ++i)
|
||||
common->luns[i].unit_attention_data = SS_RESET_OCCURRED;
|
||||
/* 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)
|
||||
{
|
||||
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);
|
||||
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)
|
||||
{
|
||||
struct fsg_dev *fsg = fsg_from_func(f);
|
||||
fsg->common->new_fsg = NULL;
|
||||
raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
|
||||
fsg->common->prev_fsg = fsg->common->fsg;
|
||||
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)
|
||||
{
|
||||
siginfo_t info;
|
||||
int sig;
|
||||
int i;
|
||||
struct fsg_buffhd *bh;
|
||||
enum fsg_state old_state;
|
||||
u8 new_config;
|
||||
struct fsg_lun *curlun;
|
||||
unsigned int exception_req_tag;
|
||||
int rc;
|
||||
|
||||
/* Clear the existing signals. Anything but SIGUSR1 is converted
|
||||
* into a high-priority EXIT exception. */
|
||||
for (;;) {
|
||||
int sig =
|
||||
dequeue_signal_lock(current, ¤t->blocked, &info);
|
||||
sig = dequeue_signal_lock(current, ¤t->blocked, &info);
|
||||
if (!sig)
|
||||
break;
|
||||
if (sig != SIGUSR1) {
|
||||
@ -2400,7 +2463,7 @@ static void handle_exception(struct fsg_common *common)
|
||||
}
|
||||
|
||||
/* Cancel all the pending transfers */
|
||||
if (likely(common->fsg)) {
|
||||
if (fsg_is_set(common)) {
|
||||
for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
|
||||
bh = &common->buffhds[i];
|
||||
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_drain = &common->buffhds[0];
|
||||
exception_req_tag = common->exception_req_tag;
|
||||
new_config = common->new_config;
|
||||
old_state = common->state;
|
||||
|
||||
if (old_state == FSG_STATE_ABORT_BULK_OUT)
|
||||
@ -2489,13 +2553,24 @@ static void handle_exception(struct fsg_common *common)
|
||||
/* SS_RESET_OCCURRED; */
|
||||
break;
|
||||
|
||||
case FSG_STATE_CONFIG_CHANGE_DISABLE:
|
||||
shutdown_server();
|
||||
// fall-through
|
||||
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;
|
||||
|
||||
case FSG_STATE_EXIT:
|
||||
case FSG_STATE_TERMINATED:
|
||||
do_set_interface(common, NULL); /* Free resources */
|
||||
do_set_config(common, 0); /* Free resources */
|
||||
spin_lock_irq(&common->lock);
|
||||
common->state = FSG_STATE_TERMINATED; /* Stop the thread */
|
||||
spin_unlock_irq(&common->lock);
|
||||
@ -2669,7 +2744,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
|
||||
return ERR_PTR(-ENOMEM);
|
||||
common->free_storage_on_release = 1;
|
||||
} else {
|
||||
memset(common, 0, sizeof *common);
|
||||
memset(common, 0, sizeof common);
|
||||
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 */
|
||||
/* Buffers in buffhds are static -- no need for additional
|
||||
* allocation. */
|
||||
bh = common->buffhds;
|
||||
i = FSG_NUM_BUFFERS;
|
||||
goto buffhds_first_it;
|
||||
i = FSG_NUM_BUFFERS - 1;
|
||||
do {
|
||||
bh->next = bh + 1;
|
||||
++bh;
|
||||
buffhds_first_it:
|
||||
bh->buf = kmalloc(FSG_BUFLEN, GFP_KERNEL);
|
||||
if (unlikely(!bh->buf)) {
|
||||
rc = -ENOMEM;
|
||||
goto error_release;
|
||||
}
|
||||
} while (--i);
|
||||
} while (++bh, --i);
|
||||
bh->next = common->buffhds;
|
||||
|
||||
|
||||
@ -2813,7 +2882,6 @@ buffhds_first_it:
|
||||
goto error_release;
|
||||
}
|
||||
init_completion(&common->thread_notifier);
|
||||
init_waitqueue_head(&common->fsg_wait);
|
||||
#undef OR
|
||||
|
||||
|
||||
@ -2868,7 +2936,6 @@ static void fsg_common_release(struct kref *ref)
|
||||
container_of(ref, struct fsg_common, ref);
|
||||
unsigned i = common->nluns;
|
||||
struct fsg_lun *lun = common->luns;
|
||||
struct fsg_buffhd *bh;
|
||||
|
||||
/* If the thread isn't already dead, tell it to exit now */
|
||||
if (common->state != FSG_STATE_TERMINATED) {
|
||||
@ -2890,13 +2957,6 @@ static void fsg_common_release(struct kref *ref)
|
||||
}
|
||||
|
||||
kfree(common->luns);
|
||||
|
||||
i = FSG_NUM_BUFFERS;
|
||||
bh = common->buffhds;
|
||||
do {
|
||||
kfree(bh->buf);
|
||||
} while (++bh, --i);
|
||||
|
||||
if (common->free_storage_on_release)
|
||||
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)
|
||||
{
|
||||
struct fsg_dev *fsg = fsg_from_func(f);
|
||||
struct fsg_common *common = fsg->common;
|
||||
|
||||
DBG(fsg, "unbind\n");
|
||||
|
||||
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);
|
||||
|
||||
fsg_common_put(fsg->common);
|
||||
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 usb_gadget *gadget = c->cdev->gadget;
|
||||
int rc;
|
||||
int i;
|
||||
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 */
|
||||
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)) {
|
||||
/* Assume endpoint addresses are the same for both speeds */
|
||||
fsg_hs_bulk_in_desc.bEndpointAddress =
|
||||
@ -2974,8 +3018,9 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
|
||||
autoconf_fail:
|
||||
ERROR(fsg, "unable to autoconfigure all endpoints\n");
|
||||
rc = -ENOTSUPP;
|
||||
fsg_unbind(c, f);
|
||||
return -ENOTSUPP;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
@ -73,7 +73,6 @@
|
||||
#undef DUMP_MSGS
|
||||
#endif /* !DEBUG */
|
||||
|
||||
#define VERBOSE_DEBUG
|
||||
#ifdef VERBOSE_DEBUG
|
||||
#define VLDBG LDBG
|
||||
#else
|
||||
@ -335,6 +334,7 @@ enum fsg_state {
|
||||
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,
|
||||
|
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
|
||||
|
||||
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() {
|
||||
let cr = fs.readFileSync("cram.bin")
|
||||
if (cr.length > 10878976) {
|
||||
console.log("too big")
|
||||
if (bootnews.length > bootargs.length) {
|
||||
console.log("args too long")
|
||||
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
|
||||
if (img[off] != 0x45 || img[off + 1] != 0x3d) {
|
||||
console.log("bad magic: " + img[off] + " / " + img[off+1])
|
||||
@ -17,8 +39,8 @@ function build() {
|
||||
|
||||
cr.copy(img, off)
|
||||
|
||||
let kern = fs.readFileSync("piggy-patched.gzip")
|
||||
off = 0x0005540f
|
||||
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])
|
||||
|
@ -1,4 +1,9 @@
|
||||
#!/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
|
||||
|
@ -19,6 +19,9 @@
|
||||
#include <time.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#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
|
||||
typedef struct {
|
||||
uint32_t numBlocks;
|
||||
@ -634,81 +679,30 @@ typedef struct {
|
||||
uint8_t writtenMask[MAX_BLOCKS / 8 + 1];
|
||||
} 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() {
|
||||
if (!elfPath[0])
|
||||
if (!rbfPath[0])
|
||||
exit(0);
|
||||
|
||||
pid_t child = fork();
|
||||
if (child == 0)
|
||||
waitAndContinue();
|
||||
else
|
||||
exit(0); // causes parent to eject MSD etc
|
||||
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;
|
||||
}
|
||||
@ -747,6 +741,10 @@ void write_block(uint32_t block_no, uint8_t *data) {
|
||||
*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);
|
||||
@ -754,8 +752,8 @@ void write_block(uint32_t block_no, uint8_t *data) {
|
||||
write(fd, bl->data, bl->payloadSize);
|
||||
close(fd);
|
||||
|
||||
if (strlen(fn) > 4 && !strcmp(fn + strlen(fn) - 4, ".elf")) {
|
||||
strcpy(elfPath, fn);
|
||||
if (strlen(fn) > 4 && !strcmp(fn + strlen(fn) - 4, ".rbf")) {
|
||||
strcpy(rbfPath, fn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,9 @@
|
||||
|
||||
#include "uf2.h"
|
||||
|
||||
const char *dev_file = "/dev/nbd0";
|
||||
|
||||
|
||||
#define NUM_BLOCKS NUM_FAT_BLOCKS
|
||||
|
||||
uint64_t ntohll(uint64_t a) {
|
||||
@ -29,23 +32,30 @@ uint64_t ntohll(uint64_t a) {
|
||||
|
||||
void mylog(const char *fmt, ...) {
|
||||
va_list args;
|
||||
char *p;
|
||||
char *p, *p2;
|
||||
|
||||
va_start(args, fmt);
|
||||
vasprintf(&p, fmt, args);
|
||||
vprintf(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
int len = strlen(p) + 1;
|
||||
p[len - 1] = '\n';
|
||||
if (p[0] != '<')
|
||||
asprintf(&p2, "<6>%s\n", p);
|
||||
else
|
||||
asprintf(&p2, "%s\n", p);
|
||||
|
||||
int len = strlen(p2);
|
||||
|
||||
#ifdef X86
|
||||
write(2, p, len);
|
||||
write(2, p2, len);
|
||||
#else
|
||||
int fd = open("/dev/kmsg", O_WRONLY);
|
||||
write(fd, p, len);
|
||||
write(fd, p2, len);
|
||||
close(fd);
|
||||
#endif
|
||||
|
||||
free(p);
|
||||
free(p2);
|
||||
}
|
||||
|
||||
void readAll(int fd, void *dst, uint32_t length) {
|
||||
@ -89,8 +99,6 @@ void startclient() {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#define dev_file "/dev/nbd0"
|
||||
|
||||
void handleread(int off, int len) {
|
||||
uint8_t buf[512];
|
||||
LOG("read @%d len=%d", off, len);
|
||||
@ -189,11 +197,14 @@ void enableMSD(int enabled) {
|
||||
#endif
|
||||
}
|
||||
|
||||
int main() {
|
||||
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) {
|
||||
|
@ -37,7 +37,7 @@ void mylog(const char *fmt, ...);
|
||||
|
||||
#define FAIL(args...) \
|
||||
do { \
|
||||
mylog(args); \
|
||||
mylog("<4>" args); \
|
||||
exit(1); \
|
||||
} while (0)
|
||||
|
||||
|
@ -41,7 +41,8 @@ namespace pxt.editor {
|
||||
export function deployCoreAsync(resp: pxtc.CompileResult, isCli = false) {
|
||||
let w: Ev3Wrapper
|
||||
|
||||
let filename = resp.downloadFileBaseName
|
||||
let filename = resp.downloadFileBaseName || "pxt"
|
||||
filename = filename.replace(/^lego-/, "")
|
||||
|
||||
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,
|
||||
Function = 5,
|
||||
}
|
||||
declare namespace serial {
|
||||
}
|
||||
|
||||
// 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",
|
||||
"version": "0.0.0",
|
||||
"version": "0.0.1",
|
||||
"description": "LEGO Mindstorms EV3 for Microsoft MakeCode",
|
||||
"private": true,
|
||||
"keywords": [
|
||||
@ -39,8 +39,8 @@
|
||||
"semantic-ui-less": "^2.2.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"pxt-common-packages": "0.8.1",
|
||||
"pxt-core": "1.7.4"
|
||||
"pxt-common-packages": "0.9.1",
|
||||
"pxt-core": "1.8.10"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "node node_modules/pxt-core/built/pxt.js travis"
|
||||
|
Reference in New Issue
Block a user